source: trunk/dll/notify.c@ 1570

Last change on this file since 1570 was 1521, checked in by Gregg Young, 15 years ago

Minor code clean up mostly remming or removal of DbgMsgs; comments

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