source: trunk/dll/notify.c@ 1669

Last change on this file since 1669 was 1669, checked in by Gregg Young, 13 years ago

Add support for changing PresParams in the notify status window. (Ticket 443)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/***********************************************************************
2
3 $Id: notify.c 1669 2012-08-13 01:21:26Z gyoung $
4
5 Thread notes window and popup notifications over status line
6
7 Copyright (c) 1993-98 M. Kimes
8 Copyright (c) 2006, 2010 Steven H.Levine
9
10 17 Jul 06 SHL Use Win_Error
11 22 Jul 06 SHL Check more run time errors
12 30 Mar 07 GKY Remove GetPString for window class names
13 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
14 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
15 16 Apr 08 SHL Comment and clean up logic
16 10 Dec 08 SHL Integrate exception handler support
17 11 Jan 09 GKY Replace font names in the string file with global set at compile in init.c
18 07 Feb 09 GKY Allow user to turn off alert and/or error beeps in settings notebook.
19 07 Feb 09 GKY Eliminate Win_Error2 by moving function names to PCSZs used in Win_Error
20 13 Jul 09 SHL Sync with renames
21 16 Jul 09 SHL Stop leaking hptrIcon
22 17 Jan 10 GKY Changes to get working with Watcom 1.9 Beta (1/16/10). Mostly cast CHAR CONSTANT * as CHAR *.
23 12 Aug 12 GKY Add support for changing PresParams in the notify status window
24
25***********************************************************************/
26
27#include <stdlib.h>
28#include <string.h>
29#include <ctype.h>
30#include <stddef.h> // _threadid
31
32#define INCL_DOS
33#define INCL_WIN
34#define INCL_GPI
35#define INCL_LONGLONG // dircnrs.h
36
37#include "fm3dll.h"
38#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
39#include "collect.h" // Data declaration(s)
40#include "grep.h" // Data declaration(s)
41#include "notebook.h" // Data declaration(s)
42#include "init.h" // Data declaration(s)
43#include "fm3dlg.h"
44#include "fm3str.h"
45#include "errutil.h" // Dos_Error...
46#include "strutil.h" // GetPString
47#include "notify.h"
48#include "presparm.h" // SetPresParams
49#include "mainwnd.h" // Data declaration(s)
50#include "wrappers.h" // xmalloc
51#include "misc.h" // PostMsg
52#include "fortify.h"
53#include "excputil.h" // xbeginthread
54
55#pragma data_seg(DATA1)
56
57// Data definitions
58static PSZ pszSrcFile = __FILE__;
59static volatile HWND hwndNotify; // 16 Apr 08 SHL
60static volatile PCSZ pszCachedNote; // 16 Jul 09 SHL
61
62#pragma data_seg(GLOBAL1)
63BOOL fThreadNotes;
64
65static VOID StartNotes(PCSZ pszNote);
66
67/**
68 * Notification message window procedure
69 * Displays timed message over status line
70 */
71
72MRESULT EXPENTRY NotifyWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
73{
74 static ULONG showing = 0;
75
76 switch (msg) {
77 case WM_CREATE:
78 showing++;
79 {
80 MRESULT rc = PFNWPStatic(hwnd, msg, mp1, mp2);
81
82 if (!WinStartTimer(WinQueryAnchorBlock(hwnd), hwnd, ID_NOTIFY_TIMER, 5000)) {
83 Win_Error(hwnd, hwnd, pszSrcFile, __LINE__, "WinStartTimer");
84 WinDestroyWindow(hwnd);
85 }
86 else {
87 if (hwndMain) {
88 if (hwndStatus)
89 WinShowWindow(hwndStatus, FALSE);
90 if (hwndStatus2)
91 WinShowWindow(hwndStatus2, FALSE);
92 }
93 PostMsg(hwnd, UM_SETUP, MPVOID, MPVOID);
94 }
95 return rc;
96 }
97
98 case UM_SETUP:
99 WinSetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER | SWP_SHOW);
100 WinInvalidateRect(hwnd, NULL, FALSE);
101 return 0;
102
103 case WM_SETFOCUS:
104 if (mp2)
105 PostMsg(hwnd, UM_REPLACEFOCUS, mp1, MPVOID);
106 break;
107
108 case UM_REPLACEFOCUS:
109 if (mp1)
110 WinSetFocus(HWND_DESKTOP, (HWND) mp1);
111 PostMsg(hwnd, UM_SETUP, MPVOID, MPVOID);
112 return 0;
113
114 case WM_PAINT:
115 {
116 SWP swp;
117 POINTL ptl;
118
119 MRESULT mr = PFNWPStatic(hwnd, msg, mp1, mp2);
120 HPS hps = WinGetPS(hwnd);
121 if (hps) {
122 if (WinQueryWindowPos(hwnd, &swp)) {
123 ptl.x = 0;
124 ptl.y = 0;
125 GpiMove(hps, &ptl);
126 GpiSetColor(hps, CLR_RED);
127 ptl.x = swp.cx - 1;
128 ptl.y = swp.cy - 1;
129 GpiBox(hps, DRO_OUTLINE, &ptl, 2, 2);
130 }
131 WinReleasePS(hwnd);
132 }
133 return mr;
134 }
135
136 case WM_BUTTON1DOWN:
137 case WM_BUTTON2DOWN:
138 case WM_BUTTON3DOWN:
139 case WM_TIMER:
140 case WM_CLOSE:
141 WinStopTimer(WinQueryAnchorBlock(hwnd), hwnd, ID_NOTIFY_TIMER);
142 WinDestroyWindow(hwnd);
143 return 0;
144
145 case WM_DESTROY:
146 showing--;
147 if (!showing && hwndMain) {
148 if (hwndStatus)
149 WinShowWindow(hwndStatus, TRUE);
150 if (hwndStatus2)
151 WinShowWindow(hwndStatus2, TRUE);
152 }
153 break;
154 }
155 return PFNWPStatic(hwnd, msg, mp1, mp2);
156}
157
158/**
159 * Process UM_NOTIFY message to display timed message over status line
160 */
161
162HWND DoNotify(PCSZ str)
163{
164 char *p;
165 HWND hwnd = (HWND)0, hwndP;
166 LONG x, y, cx, cy;
167 SWP swp, swpS, swpS2;
168 static USHORT id = NOTE_FRAME;
169
170 if (str && *str) {
171 // figure out what size the window should be and where it should be
172 hwndP = hwndMain ? WinQueryWindow(hwndMain, QW_PARENT) : HWND_DESKTOP;
173 WinQueryWindowPos(hwndP, &swp);
174 if (hwndStatus)
175 WinQueryWindowPos(hwndStatus, &swpS);
176 if (hwndStatus2)
177 WinQueryWindowPos(hwndStatus2, &swpS2);
178 x = hwndMain ? (hwndStatus ? swpS.x - 1 :
179 WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER)) : 0;
180 y = hwndMain ? (hwndStatus ? swpS.y - 1 :
181 WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER)) : 0;
182 if (hwndMain && hwndStatus) {
183 if (hwndStatus2)
184 cx = swpS2.cx + swpS.cx + 8;
185 else
186 cx = swpS.cx + 6;
187 }
188 else
189 cx = (swp.cx - ((x * 2) + 4));
190 cy = hwndMain ? (hwndStatus ? swpS.cy + 2 : 28) : 28;
191
192 // pretty-up the note by putting on a leading space
193 if (*str != ' ') {
194 p = xmalloc(strlen(str) + 2, pszSrcFile, __LINE__);
195 if (!p)
196 p = (PSZ)str;
197 else {
198 strcpy(p + 1, str);
199 *p = ' ';
200 }
201 }
202 else
203 p = (PSZ)str;
204
205 hwnd = WinCreateWindow(hwndP,
206 (CHAR *) WC_ERRORWND,
207 p,
208 SS_TEXT | DT_LEFT | DT_VCENTER | WS_VISIBLE,
209 x, y, cx, cy, hwndP, HWND_TOP, id++, NULL, NULL);
210 if (!hwnd)
211 Win_Error(hwndP, hwndP, pszSrcFile, __LINE__,
212 PCSZ_WINCREATEWINDOW);
213
214 if (p != str)
215 free(p);
216 if (id > NOTE_MAX)
217 id = NOTE_FRAME; // Wrap
218 }
219
220 AddNote(str); // Add thread notes window
221
222 return hwnd;
223}
224
225/**
226 * Display timed notification window over status line
227 */
228
229HWND Notify(PCSZ str)
230{
231 return (HWND)WinSendMsg(MainObjectHwnd, UM_NOTIFY, MPFROMP(str), MPVOID);
232}
233
234/**
235 * Notify on error
236 * Format message and pass to Notify
237 */
238
239VOID NotifyError(PCSZ filename, APIRET status)
240{
241 CHAR errortext[512];
242
243 if (!filename)
244 return;
245
246 sprintf(errortext, GetPString(IDS_ERRORACCESSTEXT), status, filename);
247 if (toupper(*filename) > 'B') {
248 if (status == 21)
249 strcat(errortext, GetPString(IDS_EMPTYREMOVETEXT));
250 else if (status == 27)
251 strcat(errortext, GetPString(IDS_CDMUSICTEXT));
252 else if (status == 19)
253 strcat(errortext, GetPString(IDS_WRITEPROTECTTEXT));
254 else if (status == 108)
255 strcat(errortext, GetPString(IDS_DRIVELOCKEDTEXT));
256 }
257 else {
258 if (status == 21)
259 strcat(errortext, GetPString(IDS_EMPTYFLOPPYTEXT));
260 else if (status == 27)
261 strcat(errortext, GetPString(IDS_UNFORMATEDTEXT));
262 else if (status == 107)
263 sprintf(&errortext[strlen(errortext)],
264 GetPString(IDS_PHANTOMTEXT), toupper(*filename));
265 else if (status == 19)
266 strcat(errortext, GetPString(IDS_DISKWRITEPROTEXTTEXT));
267 else if (status == 108)
268 strcat(errortext, GetPString(IDS_DISKLOCKEDTEXT));
269 }
270 if (!fErrorBeepOff) {
271 DosBeep(250, 10);
272 DosBeep(500, 10);
273 DosBeep(250, 10);
274 DosBeep(500, 10);
275 }
276 Notify(errortext);
277}
278
279/**
280 * Thread notes window dialog procedure
281 */
282
283MRESULT EXPENTRY NoteWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
284{
285 static HPOINTER hptrIcon;
286
287 switch (msg) {
288 case WM_INITDLG:
289 if (hwndNotify != (HWND)0) {
290 // Already have notes dialog - pass message on
291 if (mp2) {
292 AddNote((PCSZ)mp2); // 16 Jul 09 SHL was direct LM_INSERTITEM
293 xfree((PSZ)mp2, pszSrcFile, __LINE__);
294 }
295 WinDismissDlg(hwnd, 0);
296 break;
297 }
298 hwndNotify = hwnd;
299 {
300 USHORT ids[] = {NOTE_FRAME, NOTE_LISTBOX, 0};
301 UINT x;
302 CHAR s[24];
303
304 for (x = 0; ids[x]; x++) {
305 sprintf(s, "%s%i", PCSZ_NOTIFYWND,ids[x]);
306 RestorePresParams(WinWindowFromID(hwnd, ids[x]), s);
307 }
308 }
309 // Remember showing for restart
310 fThreadNotes = TRUE;
311 PrfWriteProfileData(fmprof,
312 FM3Str,
313 "ThreadNotes",
314 &fThreadNotes,
315 sizeof(BOOL));
316 fThreadNotes = FALSE; // Optimize shutdown
317
318 // 16 Jul 09 SHL Added
319 if (pszCachedNote) {
320 PCSZ p = pszCachedNote;
321 pszCachedNote = NULL;
322 AddNote(p);
323 xfree((PSZ)p, pszSrcFile, __LINE__);
324 }
325
326 if (mp2) {
327 AddNote((PCSZ)mp2); // 16 Jul 09 SHL was direct LM_INSERTITEM
328 xfree((PSZ)mp2, pszSrcFile, __LINE__);
329 }
330
331 // Grab focus
332 PostMsg(hwnd,
333 UM_FOCUSME,
334 MPFROMLONG(WinQueryActiveWindow(HWND_DESKTOP)),
335 MPVOID);
336
337 hptrIcon = WinLoadPointer(HWND_DESKTOP, FM3ModHandle, NOTE_FRAME);
338 if (hptrIcon)
339 WinDefDlgProc(hwnd, WM_SETICON, MPFROMLONG(hptrIcon), MPFROMLONG(0L));
340 break;
341
342 case UM_FOCUSME:
343 {
344 ULONG size = sizeof(SWP),
345 fl = SWP_ZORDER | SWP_FOCUSDEACTIVATE | SWP_SHOW;
346 SWP swp;
347
348 if (PrfQueryProfileData(fmprof,
349 FM3Str, "NoteWndSwp", (PVOID) & swp, &size)) {
350 if (swp.fl & (SWP_HIDE | SWP_MINIMIZE)) {
351 fl |= SWP_MINIMIZE;
352 fl &= (~SWP_SHOW);
353 }
354 else
355 fl |= (SWP_MOVE | SWP_SIZE);
356 }
357 WinSetWindowPos(hwnd, HWND_BOTTOM, swp.x, swp.y, swp.cx, swp.cy, fl);
358 if (fl & SWP_MINIMIZE) {
359 WinSetWindowUShort(hwnd, QWS_XRESTORE, (USHORT) swp.x);
360 WinSetWindowUShort(hwnd, QWS_CXRESTORE, (USHORT) swp.cx);
361 WinSetWindowUShort(hwnd, QWS_YRESTORE, (USHORT) swp.y);
362 WinSetWindowUShort(hwnd, QWS_CYRESTORE, (USHORT) swp.cy);
363 }
364 }
365 if (mp1)
366 WinSetActiveWindow(HWND_DESKTOP, (HWND) mp1);
367 return 0;
368
369 case UM_STRETCH:
370 {
371 SWP swp;
372 LONG titl, szbx, szby;
373
374 WinQueryWindowPos(hwnd, &swp);
375 if (!(swp.fl & (SWP_MINIMIZE | SWP_HIDE))) {
376 szbx = SysVal(SV_CXSIZEBORDER);
377 szby = SysVal(SV_CYSIZEBORDER);
378 titl = SysVal(SV_CYTITLEBAR);
379 WinSetWindowPos(WinWindowFromID(hwnd, NOTE_LISTBOX),
380 HWND_TOP,
381 szbx,
382 szby,
383 swp.cx - (szbx * 2L),
384 (swp.cy - titl) - (szby * 2L), SWP_MOVE | SWP_SIZE);
385 }
386 if (!(swp.fl & SWP_MAXIMIZE)) {
387 if (swp.fl & (SWP_MINIMIZE | SWP_HIDE)) {
388 swp.x = WinQueryWindowUShort(hwnd, QWS_XRESTORE);
389 swp.y = WinQueryWindowUShort(hwnd, QWS_YRESTORE);
390 swp.cx = WinQueryWindowUShort(hwnd, QWS_CXRESTORE);
391 swp.cy = WinQueryWindowUShort(hwnd, QWS_CYRESTORE);
392 }
393 PrfWriteProfileData(fmprof,
394 FM3Str, "NoteWndSwp", (PVOID) & swp, sizeof(SWP));
395 }
396 }
397 return 0;
398
399 case WM_ADJUSTWINDOWPOS:
400 PostMsg(hwnd, UM_STRETCH, MPVOID, MPVOID);
401 break;
402
403 case UM_CONTAINER_FILLED:
404 {
405 SHORT y;
406 SHORT x = (SHORT)WinSendDlgItemMsg(hwnd,
407 NOTE_LISTBOX,
408 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
409 if (x > 60) {
410 for (y = 0; y < x - 50; y++) {
411 WinSendDlgItemMsg(hwnd,
412 NOTE_LISTBOX,
413 LM_DELETEITEM, MPFROMSHORT(y), MPVOID);
414 }
415 }
416 }
417 return 0;
418
419 case UM_NOTIFY:
420 {
421 SHORT x = (SHORT) WinSendDlgItemMsg(hwnd,
422 NOTE_LISTBOX,
423 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
424 if (x > 0)
425 WinSendDlgItemMsg(hwnd,
426 NOTE_LISTBOX,
427 LM_SETTOPINDEX, MPFROMSHORT(x), MPVOID);
428 }
429 return 0;
430
431 case UM_SHOWME:
432 WinSetWindowPos(hwnd,
433 HWND_TOP,
434 0,
435 0,
436 0, 0, SWP_SHOW | SWP_RESTORE | SWP_ZORDER | SWP_ACTIVATE);
437 return 0;
438
439 case WM_COMMAND:
440 return 0;
441
442 case WM_CLOSE:
443 if (pszCachedNote)
444 Runtime_Error(pszSrcFile, __LINE__, "pszCachedNote %p unexpected", pszCachedNote);
445 else {
446 // Cache last item for next open
447 SHORT ndx = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
448 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
449 if (ndx != LIT_NONE) {
450 SHORT len;
451 ndx--;
452 len = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
453 LM_QUERYITEMTEXTLENGTH,
454 MPFROMSHORT(ndx), MPVOID);
455 if (len != LIT_ERROR) {
456 PSZ p;
457 len++;
458 p = xmalloc(len, pszSrcFile, __LINE__);
459 if (p) {
460 SHORT len2 = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
461 LM_QUERYITEMTEXT,
462 MPFROM2SHORT(ndx, len), MPFROMP(p));
463 len--;
464 if (len2 != len) {
465 DbgMsg(pszSrcFile, __LINE__, "len %u unexpected - should be %u", len2, len); // 18 Jul 08 SHL fixme to be Runtime_Error
466 xfree((PSZ)p, pszSrcFile, __LINE__);
467 }
468 else
469 pszCachedNote = p;
470 }
471 }
472 }
473 }
474 WinDismissDlg(hwnd, 0);
475 return 0;
476
477 case WM_DESTROY:
478 if (hwndNotify == hwnd) {
479 USHORT ids[] = {NOTE_FRAME, NOTE_LISTBOX, 0};
480 UINT x;
481 CHAR s[24];
482
483 for (x = 0; ids[x]; x++) {
484 sprintf(s, "%s%i", PCSZ_NOTIFYWND,ids[x]);
485 SavePresParams(WinWindowFromID(hwnd, ids[x]), s);
486 }
487 fThreadNotes = FALSE; // Remember not open
488 PrfWriteProfileData(fmprof,
489 FM3Str, "ThreadNotes", &fThreadNotes, sizeof(BOOL));
490 hwndNotify = (HWND)0;
491 }
492 if (hptrIcon) {
493 WinDestroyPointer(hptrIcon);
494 hptrIcon = (HPOINTER)0; // 16 Jul 09 SHL
495 }
496 if (!PostMsg((HWND)0, WM_QUIT, MPVOID, MPVOID))
497 WinSendMsg((HWND)0, WM_QUIT, MPVOID, MPVOID);
498 break;
499 }
500 return WinDefDlgProc(hwnd, msg, mp1, mp2);
501}
502
503/**
504 * Thread notes dialog window thread
505 */
506
507static VOID NoteThread(VOID *args)
508{
509 HAB hab = WinInitialize(0);
510# ifdef FORTIFY
511 Fortify_EnterScope();
512# endif
513 if (hab) {
514 HMQ hmq = WinCreateMsgQueue(hab, 0);
515 if (hmq) {
516 if (!hwndNotify)
517 WinDlgBox(HWND_DESKTOP,
518 HWND_DESKTOP,
519 NoteWndProc, FM3ModHandle, NOTE_FRAME, args);
520 WinDestroyMsgQueue(hmq);
521 }
522 WinTerminate(hab);
523 }
524# ifdef FORTIFY
525 Fortify_LeaveScope();
526# endif
527}
528
529/**
530 * Start thread notes dialog window thread
531 */
532
533static VOID StartNotes(PCSZ note)
534{
535 if (!hwndNotify) {
536 if (xbeginthread(NoteThread,
537 65536,
538 (VOID*)note,
539 pszSrcFile,
540 __LINE__) != -1)
541 {
542 USHORT i;
543 for (i = 0; !hwndNotify && i < 10; i++)
544 DosSleep(10);
545 if (!hwndNotify)
546 Runtime_Error(pszSrcFile, __LINE__, "Can not create Notify window");
547 }
548 }
549}
550
551/**
552 * Add note to thread notes window or popup status window
553 * Open window if was open and first messages after restart
554 * Cache last note until window opened
555 */
556
557VOID AddNote(PCSZ note)
558{
559 PSZ s;
560 PCSZ p;
561 BOOL once = FALSE;
562
563 // Cache last note until window opened
564 // 16 Jul 09 SHL fixme to avoid FORTIFY complaints
565 if (!fThreadNotes && !hwndNotify && note) {
566 p = note + strspn(note, " \t"); // Skip leading white
567 if (*p) {
568 if (pszCachedNote)
569 xfree((PSZ)pszCachedNote, pszSrcFile, __LINE__);
570 pszCachedNote = xstrdup(p, pszSrcFile, __LINE__);
571 }
572 return;
573 }
574
575 if ((fThreadNotes || hwndNotify) && note) {
576 p = note + strspn(note, " \t"); // Skip leading white
577 if (*p) {
578 // If have cached note, output it first
579 if (pszCachedNote) {
580 PCSZ psz = pszCachedNote;
581 pszCachedNote = NULL;
582 AddNote(psz);
583 free((VOID*)psz);
584 }
585 if (!hwndNotify) {
586 fThreadNotes = FALSE; // 16 Jul 09 SHL fixme to be gone?
587 StartNotes(NULL);
588 }
589 if (hwndNotify) {
590 s = xmalloc(strlen(p) + 14, pszSrcFile, __LINE__);
591 if (s) {
592 sprintf(s, "%08lx %s", _threadid, p);
593 while (!once) {
594 if ((SHORT) WinSendDlgItemMsg(hwndNotify,
595 NOTE_LISTBOX,
596 LM_INSERTITEM,
597 MPFROM2SHORT(LIT_END, 0),
598 MPFROMP(s)) >= 0) {
599 PostMsg(hwndNotify, UM_NOTIFY, MPVOID, MPVOID);
600 break;
601 }
602 PostMsg(hwndNotify, UM_CONTAINER_FILLED, MPVOID, MPVOID);
603 once = TRUE;
604 }
605 free(s);
606 }
607 }
608 }
609 }
610}
611
612/**
613 * Close thread notes window
614 */
615
616VOID EndNote(VOID)
617{
618 if (hwndNotify)
619 if (!PostMsg(hwndNotify, WM_CLOSE, MPVOID, MPVOID))
620 WinSendMsg(hwndNotify, WM_CLOSE, MPVOID, MPVOID);
621}
622
623/**
624 * Pop up thread notes window
625 */
626
627VOID ShowNote(VOID)
628{
629 if (!hwndNotify)
630 StartNotes(NULL);
631 if (hwndNotify)
632 PostMsg(hwndNotify, UM_SHOWME, MPVOID, MPVOID);
633}
634
635/**
636 * Hide thread notes window
637 */
638
639VOID HideNote(VOID)
640{
641 if (hwndNotify)
642 WinSetWindowPos(hwndNotify,
643 HWND_BOTTOM,
644 0,
645 0, 0, 0, SWP_MINIMIZE | SWP_ZORDER | SWP_FOCUSDEACTIVATE);
646}
647
648#pragma alloc_text(NOTIFY,Notify,NotifyWndProc,StartNotify,NotifyError)
649#pragma alloc_text(NOTIFY2,AddNote,NoteThread,NoteWndProc)
650#pragma alloc_text(NOTIFY3,StartNotes,EndNote,HideNote,ShowNote)
Note: See TracBrowser for help on using the repository browser.