source: trunk/dll/notify.c@ 1654

Last change on this file since 1654 was 1654, checked in by Gregg Young, 14 years ago

Add support for changing PresParams in the notify status window.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.5 KB
Line 
1/***********************************************************************
2
3 $Id: notify.c 1654 2012-01-08 18:16:08Z 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 08 Jan 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 RestorePresParams(hwnd, PCSZ_NOTIFYWND);
102 return 0;
103
104 case WM_SETFOCUS:
105 if (mp2)
106 PostMsg(hwnd, UM_REPLACEFOCUS, mp1, MPVOID);
107 break;
108
109 case UM_REPLACEFOCUS:
110 if (mp1)
111 WinSetFocus(HWND_DESKTOP, (HWND) mp1);
112 PostMsg(hwnd, UM_SETUP, MPVOID, MPVOID);
113 return 0;
114
115 case WM_PRESPARAMCHANGED:
116 PresParamChanged(hwnd, PCSZ_NOTIFYWND, mp1, mp2);
117 break;
118
119 case WM_PAINT:
120 {
121 SWP swp;
122 POINTL ptl;
123
124 MRESULT mr = PFNWPStatic(hwnd, msg, mp1, mp2);
125 HPS hps = WinGetPS(hwnd);
126 if (hps) {
127 if (WinQueryWindowPos(hwnd, &swp)) {
128 ptl.x = 0;
129 ptl.y = 0;
130 GpiMove(hps, &ptl);
131 GpiSetColor(hps, CLR_RED);
132 ptl.x = swp.cx - 1;
133 ptl.y = swp.cy - 1;
134 GpiBox(hps, DRO_OUTLINE, &ptl, 2, 2);
135 }
136 WinReleasePS(hwnd);
137 }
138 return mr;
139 }
140
141 case WM_BUTTON1DOWN:
142 case WM_BUTTON2DOWN:
143 case WM_BUTTON3DOWN:
144 case WM_TIMER:
145 case WM_CLOSE:
146 WinStopTimer(WinQueryAnchorBlock(hwnd), hwnd, ID_NOTIFY_TIMER);
147 WinDestroyWindow(hwnd);
148 return 0;
149
150 case WM_DESTROY:
151 showing--;
152 if (!showing && hwndMain) {
153 if (hwndStatus)
154 WinShowWindow(hwndStatus, TRUE);
155 if (hwndStatus2)
156 WinShowWindow(hwndStatus2, TRUE);
157 }
158 break;
159 }
160 return PFNWPStatic(hwnd, msg, mp1, mp2);
161}
162
163/**
164 * Process UM_NOTIFY message to display timed message over status line
165 */
166
167HWND DoNotify(PCSZ str)
168{
169 char *p;
170 HWND hwnd = (HWND)0, hwndP;
171 LONG x, y, cx, cy;
172 SWP swp, swpS, swpS2;
173 static USHORT id = NOTE_FRAME;
174
175 if (str && *str) {
176 // figure out what size the window should be and where it should be
177 hwndP = hwndMain ? WinQueryWindow(hwndMain, QW_PARENT) : HWND_DESKTOP;
178 WinQueryWindowPos(hwndP, &swp);
179 if (hwndStatus)
180 WinQueryWindowPos(hwndStatus, &swpS);
181 if (hwndStatus2)
182 WinQueryWindowPos(hwndStatus2, &swpS2);
183 x = hwndMain ? (hwndStatus ? swpS.x - 1 :
184 WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER)) : 0;
185 y = hwndMain ? (hwndStatus ? swpS.y - 1 :
186 WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER)) : 0;
187 if (hwndMain && hwndStatus) {
188 if (hwndStatus2)
189 cx = swpS2.cx + swpS.cx + 8;
190 else
191 cx = swpS.cx + 6;
192 }
193 else
194 cx = (swp.cx - ((x * 2) + 4));
195 cy = hwndMain ? (hwndStatus ? swpS.cy + 2 : 28) : 28;
196
197 // pretty-up the note by putting on a leading space
198 if (*str != ' ') {
199 p = xmalloc(strlen(str) + 2, pszSrcFile, __LINE__);
200 if (!p)
201 p = (PSZ)str;
202 else {
203 strcpy(p + 1, str);
204 *p = ' ';
205 }
206 }
207 else
208 p = (PSZ)str;
209
210 hwnd = WinCreateWindow(hwndP,
211 (CHAR *) WC_ERRORWND,
212 p,
213 SS_TEXT | DT_LEFT | DT_VCENTER | WS_VISIBLE,
214 x, y, cx, cy, hwndP, HWND_TOP, id++, NULL, NULL);
215 if (!hwnd)
216 Win_Error(hwndP, hwndP, pszSrcFile, __LINE__,
217 PCSZ_WINCREATEWINDOW);
218
219 if (p != str)
220 free(p);
221 if (id > NOTE_MAX)
222 id = NOTE_FRAME; // Wrap
223 }
224
225 AddNote(str); // Add thread notes window
226
227 return hwnd;
228}
229
230/**
231 * Display timed notification window over status line
232 */
233
234HWND Notify(PCSZ str)
235{
236 return (HWND)WinSendMsg(MainObjectHwnd, UM_NOTIFY, MPFROMP(str), MPVOID);
237}
238
239/**
240 * Notify on error
241 * Format message and pass to Notify
242 */
243
244VOID NotifyError(PCSZ filename, APIRET status)
245{
246 CHAR errortext[512];
247
248 if (!filename)
249 return;
250
251 sprintf(errortext, GetPString(IDS_ERRORACCESSTEXT), status, filename);
252 if (toupper(*filename) > 'B') {
253 if (status == 21)
254 strcat(errortext, GetPString(IDS_EMPTYREMOVETEXT));
255 else if (status == 27)
256 strcat(errortext, GetPString(IDS_CDMUSICTEXT));
257 else if (status == 19)
258 strcat(errortext, GetPString(IDS_WRITEPROTECTTEXT));
259 else if (status == 108)
260 strcat(errortext, GetPString(IDS_DRIVELOCKEDTEXT));
261 }
262 else {
263 if (status == 21)
264 strcat(errortext, GetPString(IDS_EMPTYFLOPPYTEXT));
265 else if (status == 27)
266 strcat(errortext, GetPString(IDS_UNFORMATEDTEXT));
267 else if (status == 107)
268 sprintf(&errortext[strlen(errortext)],
269 GetPString(IDS_PHANTOMTEXT), toupper(*filename));
270 else if (status == 19)
271 strcat(errortext, GetPString(IDS_DISKWRITEPROTEXTTEXT));
272 else if (status == 108)
273 strcat(errortext, GetPString(IDS_DISKLOCKEDTEXT));
274 }
275 if (!fErrorBeepOff) {
276 DosBeep(250, 10);
277 DosBeep(500, 10);
278 DosBeep(250, 10);
279 DosBeep(500, 10);
280 }
281 Notify(errortext);
282}
283
284/**
285 * Thread notes window dialog procedure
286 */
287
288MRESULT EXPENTRY NoteWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
289{
290 static HPOINTER hptrIcon;
291
292 switch (msg) {
293 case WM_INITDLG:
294 if (hwndNotify != (HWND)0) {
295 // Already have notes dialog - pass message on
296 if (mp2) {
297 AddNote((PCSZ)mp2); // 16 Jul 09 SHL was direct LM_INSERTITEM
298 xfree((PSZ)mp2, pszSrcFile, __LINE__);
299 }
300 WinDismissDlg(hwnd, 0);
301 break;
302 }
303 hwndNotify = hwnd;
304 // Remember showing for restart
305 fThreadNotes = TRUE;
306 PrfWriteProfileData(fmprof,
307 FM3Str,
308 "ThreadNotes",
309 &fThreadNotes,
310 sizeof(BOOL));
311 fThreadNotes = FALSE; // Optimize shutdown
312
313 // 16 Jul 09 SHL Added
314 if (pszCachedNote) {
315 PCSZ p = pszCachedNote;
316 pszCachedNote = NULL;
317 AddNote(p);
318 xfree((PSZ)p, pszSrcFile, __LINE__);
319 }
320
321 if (mp2) {
322 AddNote((PCSZ)mp2); // 16 Jul 09 SHL was direct LM_INSERTITEM
323 xfree((PSZ)mp2, pszSrcFile, __LINE__);
324 }
325
326 // Grab focus
327 PostMsg(hwnd,
328 UM_FOCUSME,
329 MPFROMLONG(WinQueryActiveWindow(HWND_DESKTOP)),
330 MPVOID);
331
332 hptrIcon = WinLoadPointer(HWND_DESKTOP, FM3ModHandle, NOTE_FRAME);
333 if (hptrIcon)
334 WinDefDlgProc(hwnd, WM_SETICON, MPFROMLONG(hptrIcon), MPFROMLONG(0L));
335 break;
336
337 case UM_FOCUSME:
338 {
339 ULONG size = sizeof(SWP),
340 fl = SWP_ZORDER | SWP_FOCUSDEACTIVATE | SWP_SHOW;
341 SWP swp;
342
343 if (PrfQueryProfileData(fmprof,
344 FM3Str, "NoteWndSwp", (PVOID) & swp, &size)) {
345 if (swp.fl & (SWP_HIDE | SWP_MINIMIZE)) {
346 fl |= SWP_MINIMIZE;
347 fl &= (~SWP_SHOW);
348 }
349 else
350 fl |= (SWP_MOVE | SWP_SIZE);
351 }
352 WinSetWindowPos(hwnd, HWND_BOTTOM, swp.x, swp.y, swp.cx, swp.cy, fl);
353 if (fl & SWP_MINIMIZE) {
354 WinSetWindowUShort(hwnd, QWS_XRESTORE, (USHORT) swp.x);
355 WinSetWindowUShort(hwnd, QWS_CXRESTORE, (USHORT) swp.cx);
356 WinSetWindowUShort(hwnd, QWS_YRESTORE, (USHORT) swp.y);
357 WinSetWindowUShort(hwnd, QWS_CYRESTORE, (USHORT) swp.cy);
358 }
359 }
360 if (mp1)
361 WinSetActiveWindow(HWND_DESKTOP, (HWND) mp1);
362 return 0;
363
364 case UM_STRETCH:
365 {
366 SWP swp;
367 LONG titl, szbx, szby;
368
369 WinQueryWindowPos(hwnd, &swp);
370 if (!(swp.fl & (SWP_MINIMIZE | SWP_HIDE))) {
371 szbx = SysVal(SV_CXSIZEBORDER);
372 szby = SysVal(SV_CYSIZEBORDER);
373 titl = SysVal(SV_CYTITLEBAR);
374 WinSetWindowPos(WinWindowFromID(hwnd, NOTE_LISTBOX),
375 HWND_TOP,
376 szbx,
377 szby,
378 swp.cx - (szbx * 2L),
379 (swp.cy - titl) - (szby * 2L), SWP_MOVE | SWP_SIZE);
380 }
381 if (!(swp.fl & SWP_MAXIMIZE)) {
382 if (swp.fl & (SWP_MINIMIZE | SWP_HIDE)) {
383 swp.x = WinQueryWindowUShort(hwnd, QWS_XRESTORE);
384 swp.y = WinQueryWindowUShort(hwnd, QWS_YRESTORE);
385 swp.cx = WinQueryWindowUShort(hwnd, QWS_CXRESTORE);
386 swp.cy = WinQueryWindowUShort(hwnd, QWS_CYRESTORE);
387 }
388 PrfWriteProfileData(fmprof,
389 FM3Str, "NoteWndSwp", (PVOID) & swp, sizeof(SWP));
390 }
391 }
392 return 0;
393
394 case WM_ADJUSTWINDOWPOS:
395 PostMsg(hwnd, UM_STRETCH, MPVOID, MPVOID);
396 break;
397
398 case UM_CONTAINER_FILLED:
399 {
400 SHORT y;
401 SHORT x = (SHORT)WinSendDlgItemMsg(hwnd,
402 NOTE_LISTBOX,
403 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
404 if (x > 60) {
405 for (y = 0; y < x - 50; y++) {
406 WinSendDlgItemMsg(hwnd,
407 NOTE_LISTBOX,
408 LM_DELETEITEM, MPFROMSHORT(y), MPVOID);
409 }
410 }
411 }
412 return 0;
413
414 case UM_NOTIFY:
415 {
416 SHORT x = (SHORT) WinSendDlgItemMsg(hwnd,
417 NOTE_LISTBOX,
418 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
419 if (x > 0)
420 WinSendDlgItemMsg(hwnd,
421 NOTE_LISTBOX,
422 LM_SETTOPINDEX, MPFROMSHORT(x), MPVOID);
423 }
424 return 0;
425
426 case UM_SHOWME:
427 WinSetWindowPos(hwnd,
428 HWND_TOP,
429 0,
430 0,
431 0, 0, SWP_SHOW | SWP_RESTORE | SWP_ZORDER | SWP_ACTIVATE);
432 return 0;
433
434 case WM_COMMAND:
435 return 0;
436
437 case WM_CLOSE:
438 if (pszCachedNote)
439 Runtime_Error(pszSrcFile, __LINE__, "pszCachedNote %p unexpected", pszCachedNote);
440 else {
441 // Cache last item for next open
442 SHORT ndx = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
443 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
444 if (ndx != LIT_NONE) {
445 SHORT len;
446 ndx--;
447 len = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
448 LM_QUERYITEMTEXTLENGTH,
449 MPFROMSHORT(ndx), MPVOID);
450 if (len != LIT_ERROR) {
451 PSZ p;
452 len++;
453 p = xmalloc(len, pszSrcFile, __LINE__);
454 if (p) {
455 SHORT len2 = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
456 LM_QUERYITEMTEXT,
457 MPFROM2SHORT(ndx, len), MPFROMP(p));
458 len--;
459 if (len2 != len) {
460 DbgMsg(pszSrcFile, __LINE__, "len %u unexpected - should be %u", len2, len); // 18 Jul 08 SHL fixme to be Runtime_Error
461 xfree((PSZ)p, pszSrcFile, __LINE__);
462 }
463 else
464 pszCachedNote = p;
465 }
466 }
467 }
468 }
469 WinDismissDlg(hwnd, 0);
470 return 0;
471
472 case WM_DESTROY:
473 if (hwndNotify == hwnd) {
474 fThreadNotes = FALSE; // Remember not open
475 PrfWriteProfileData(fmprof,
476 FM3Str, "ThreadNotes", &fThreadNotes, sizeof(BOOL));
477 hwndNotify = (HWND)0;
478 }
479 if (hptrIcon) {
480 WinDestroyPointer(hptrIcon);
481 hptrIcon = (HPOINTER)0; // 16 Jul 09 SHL
482 }
483 if (!PostMsg((HWND)0, WM_QUIT, MPVOID, MPVOID))
484 WinSendMsg((HWND)0, WM_QUIT, MPVOID, MPVOID);
485 break;
486 }
487 return WinDefDlgProc(hwnd, msg, mp1, mp2);
488}
489
490/**
491 * Thread notes dialog window thread
492 */
493
494static VOID NoteThread(VOID *args)
495{
496 HAB hab = WinInitialize(0);
497# ifdef FORTIFY
498 Fortify_EnterScope();
499# endif
500 if (hab) {
501 HMQ hmq = WinCreateMsgQueue(hab, 0);
502 if (hmq) {
503 if (!hwndNotify)
504 WinDlgBox(HWND_DESKTOP,
505 HWND_DESKTOP,
506 NoteWndProc, FM3ModHandle, NOTE_FRAME, args);
507 WinDestroyMsgQueue(hmq);
508 }
509 WinTerminate(hab);
510 }
511# ifdef FORTIFY
512 Fortify_LeaveScope();
513# endif
514}
515
516/**
517 * Start thread notes dialog window thread
518 */
519
520static VOID StartNotes(PCSZ note)
521{
522 if (!hwndNotify) {
523 if (xbeginthread(NoteThread,
524 65536,
525 (VOID*)note,
526 pszSrcFile,
527 __LINE__) != -1)
528 {
529 USHORT i;
530 for (i = 0; !hwndNotify && i < 10; i++)
531 DosSleep(10);
532 if (!hwndNotify)
533 Runtime_Error(pszSrcFile, __LINE__, "Can not create Notify window");
534 }
535 }
536}
537
538/**
539 * Add note to thread notes window or popup status window
540 * Open window if was open and first messages after restart
541 * Cache last note until window opened
542 */
543
544VOID AddNote(PCSZ note)
545{
546 PSZ s;
547 PCSZ p;
548 BOOL once = FALSE;
549
550 // Cache last note until window opened
551 // 16 Jul 09 SHL fixme to avoid FORTIFY complaints
552 if (!fThreadNotes && !hwndNotify && note) {
553 p = note + strspn(note, " \t"); // Skip leading white
554 if (*p) {
555 if (pszCachedNote)
556 xfree((PSZ)pszCachedNote, pszSrcFile, __LINE__);
557 pszCachedNote = xstrdup(p, pszSrcFile, __LINE__);
558 }
559 return;
560 }
561
562 if ((fThreadNotes || hwndNotify) && note) {
563 p = note + strspn(note, " \t"); // Skip leading white
564 if (*p) {
565 // If have cached note, output it first
566 if (pszCachedNote) {
567 PCSZ psz = pszCachedNote;
568 pszCachedNote = NULL;
569 AddNote(psz);
570 free((VOID*)psz);
571 }
572 if (!hwndNotify) {
573 fThreadNotes = FALSE; // 16 Jul 09 SHL fixme to be gone?
574 StartNotes(NULL);
575 }
576 if (hwndNotify) {
577 s = xmalloc(strlen(p) + 14, pszSrcFile, __LINE__);
578 if (s) {
579 sprintf(s, "%08lx %s", _threadid, p);
580 while (!once) {
581 if ((SHORT) WinSendDlgItemMsg(hwndNotify,
582 NOTE_LISTBOX,
583 LM_INSERTITEM,
584 MPFROM2SHORT(LIT_END, 0),
585 MPFROMP(s)) >= 0) {
586 PostMsg(hwndNotify, UM_NOTIFY, MPVOID, MPVOID);
587 break;
588 }
589 PostMsg(hwndNotify, UM_CONTAINER_FILLED, MPVOID, MPVOID);
590 once = TRUE;
591 }
592 free(s);
593 }
594 }
595 }
596 }
597}
598
599/**
600 * Close thread notes window
601 */
602
603VOID EndNote(VOID)
604{
605 if (hwndNotify)
606 if (!PostMsg(hwndNotify, WM_CLOSE, MPVOID, MPVOID))
607 WinSendMsg(hwndNotify, WM_CLOSE, MPVOID, MPVOID);
608}
609
610/**
611 * Pop up thread notes window
612 */
613
614VOID ShowNote(VOID)
615{
616 if (!hwndNotify)
617 StartNotes(NULL);
618 if (hwndNotify)
619 PostMsg(hwndNotify, UM_SHOWME, MPVOID, MPVOID);
620}
621
622/**
623 * Hide thread notes window
624 */
625
626VOID HideNote(VOID)
627{
628 if (hwndNotify)
629 WinSetWindowPos(hwndNotify,
630 HWND_BOTTOM,
631 0,
632 0, 0, 0, SWP_MINIMIZE | SWP_ZORDER | SWP_FOCUSDEACTIVATE);
633}
634
635#pragma alloc_text(NOTIFY,Notify,NotifyWndProc,StartNotify,NotifyError)
636#pragma alloc_text(NOTIFY2,AddNote,NoteThread,NoteWndProc)
637#pragma alloc_text(NOTIFY3,StartNotes,EndNote,HideNote,ShowNote)
Note: See TracBrowser for help on using the repository browser.