source: trunk/dll/notify.c@ 1455

Last change on this file since 1455 was 1455, checked in by Steven Levine, 16 years ago

Blink thread LEDs while worker threads are working
Drop expermental code

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