source: trunk/dll/notify.c@ 1444

Last change on this file since 1444 was 1444, checked in by Gregg Young, 16 years ago

Rework of drivebar to rescan all drives and refresh media buttons and menu items grey out inappropriate menu items. Streamline Tree scan code and use semaphores to serialize access. Add NOEASUPPORT and LOCALHD driveflag; .LONGNAME usage fixes; (Tickets 377-386)

  • 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 1444 2009-07-22 23:24:23Z gyoung $
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, "ThreadNotes", &fThreadNotes, sizeof(BOOL));
310 fThreadNotes = FALSE; // Optimize
311
312 // 16 Jul 09 SHL Added
313 if (pszCachedNote) {
314 PCSZ p = pszCachedNote;
315 pszCachedNote = NULL;
316 AddNote(p);
317 xfree((PSZ)p, pszSrcFile, __LINE__);
318 }
319
320 if (mp2) {
321 AddNote((PCSZ)mp2); // 16 Jul 09 SHL was direct LM_INSERTITEM
322 xfree((PSZ)mp2, pszSrcFile, __LINE__);
323 }
324
325 // Grab focus
326 PostMsg(hwnd,
327 UM_FOCUSME,
328 MPFROMLONG(WinQueryActiveWindow(HWND_DESKTOP)),
329 MPVOID);
330
331 hptrIcon = WinLoadPointer(HWND_DESKTOP, FM3ModHandle, NOTE_FRAME);
332 if (hptrIcon)
333 WinDefDlgProc(hwnd, WM_SETICON, MPFROMLONG(hptrIcon), MPFROMLONG(0L));
334 break;
335
336 case UM_FOCUSME:
337 {
338 ULONG size = sizeof(SWP),
339 fl = SWP_ZORDER | SWP_FOCUSDEACTIVATE | SWP_SHOW;
340 SWP swp;
341
342 if (PrfQueryProfileData(fmprof,
343 FM3Str, "NoteWndSwp", (PVOID) & swp, &size)) {
344 if (swp.fl & (SWP_HIDE | SWP_MINIMIZE)) {
345 fl |= SWP_MINIMIZE;
346 fl &= (~SWP_SHOW);
347 }
348 else
349 fl |= (SWP_MOVE | SWP_SIZE);
350 }
351 WinSetWindowPos(hwnd, HWND_BOTTOM, swp.x, swp.y, swp.cx, swp.cy, fl);
352 if (fl & SWP_MINIMIZE) {
353 WinSetWindowUShort(hwnd, QWS_XRESTORE, (USHORT) swp.x);
354 WinSetWindowUShort(hwnd, QWS_CXRESTORE, (USHORT) swp.cx);
355 WinSetWindowUShort(hwnd, QWS_YRESTORE, (USHORT) swp.y);
356 WinSetWindowUShort(hwnd, QWS_CYRESTORE, (USHORT) swp.cy);
357 }
358 }
359 if (mp1)
360 WinSetActiveWindow(HWND_DESKTOP, (HWND) mp1);
361 return 0;
362
363 case UM_STRETCH:
364 {
365 SWP swp;
366 LONG titl, szbx, szby;
367
368 WinQueryWindowPos(hwnd, &swp);
369 if (!(swp.fl & (SWP_MINIMIZE | SWP_HIDE))) {
370 szbx = SysVal(SV_CXSIZEBORDER);
371 szby = SysVal(SV_CYSIZEBORDER);
372 titl = SysVal(SV_CYTITLEBAR);
373 WinSetWindowPos(WinWindowFromID(hwnd, NOTE_LISTBOX),
374 HWND_TOP,
375 szbx,
376 szby,
377 swp.cx - (szbx * 2L),
378 (swp.cy - titl) - (szby * 2L), SWP_MOVE | SWP_SIZE);
379 }
380 if (!(swp.fl & SWP_MAXIMIZE)) {
381 if (swp.fl & (SWP_MINIMIZE | SWP_HIDE)) {
382 swp.x = WinQueryWindowUShort(hwnd, QWS_XRESTORE);
383 swp.y = WinQueryWindowUShort(hwnd, QWS_YRESTORE);
384 swp.cx = WinQueryWindowUShort(hwnd, QWS_CXRESTORE);
385 swp.cy = WinQueryWindowUShort(hwnd, QWS_CYRESTORE);
386 }
387 PrfWriteProfileData(fmprof,
388 FM3Str, "NoteWndSwp", (PVOID) & swp, sizeof(SWP));
389 }
390 }
391 return 0;
392
393 case WM_ADJUSTWINDOWPOS:
394 PostMsg(hwnd, UM_STRETCH, MPVOID, MPVOID);
395 break;
396
397 case UM_CONTAINER_FILLED:
398 {
399 SHORT y;
400 SHORT x = (SHORT)WinSendDlgItemMsg(hwnd,
401 NOTE_LISTBOX,
402 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
403 if (x > 60) {
404 for (y = 0; y < x - 50; y++) {
405 WinSendDlgItemMsg(hwnd,
406 NOTE_LISTBOX,
407 LM_DELETEITEM, MPFROMSHORT(y), MPVOID);
408 }
409 }
410 }
411 return 0;
412
413 case UM_NOTIFY:
414 {
415 SHORT x = (SHORT) WinSendDlgItemMsg(hwnd,
416 NOTE_LISTBOX,
417 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
418 if (x > 0)
419 WinSendDlgItemMsg(hwnd,
420 NOTE_LISTBOX,
421 LM_SETTOPINDEX, MPFROMSHORT(x), MPVOID);
422 }
423 return 0;
424
425 case UM_SHOWME:
426 WinSetWindowPos(hwnd,
427 HWND_TOP,
428 0,
429 0,
430 0, 0, SWP_SHOW | SWP_RESTORE | SWP_ZORDER | SWP_ACTIVATE);
431 return 0;
432
433 case WM_COMMAND:
434 return 0;
435
436 case WM_CLOSE:
437 if (pszCachedNote)
438 DbgMsg(pszSrcFile, __LINE__, "pszCachedNote %p unexpected", pszCachedNote); // 18 Jul 08 SHL fixme to be Runtime_Error
439 else {
440 // Cache last item for next open
441 SHORT ndx = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
442 LM_QUERYITEMCOUNT, MPVOID, MPVOID);
443 if (ndx != LIT_NONE) {
444 SHORT len;
445 ndx--;
446 len = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
447 LM_QUERYITEMTEXTLENGTH,
448 MPFROMSHORT(ndx), MPVOID);
449 if (len != LIT_ERROR) {
450 PSZ p;
451 len++;
452 p = xmalloc(len, pszSrcFile, __LINE__);
453 if (p) {
454 SHORT len2 = (SHORT)WinSendDlgItemMsg(hwnd, NOTE_LISTBOX,
455 LM_QUERYITEMTEXT,
456 MPFROM2SHORT(ndx, len), MPFROMP(p));
457 len--;
458 if (len2 != len) {
459 DbgMsg(pszSrcFile, __LINE__, "len %u unexpected - should be %u", len2, len); // 18 Jul 08 SHL fixme to be Runtime_Error
460 xfree((PSZ)p, pszSrcFile, __LINE__);
461 }
462 else
463 pszCachedNote = p;
464 }
465 }
466 }
467 }
468 WinDismissDlg(hwnd, 0);
469 return 0;
470
471 case WM_DESTROY:
472 if (hwndNotify == hwnd) {
473 // Remember not open
474 fThreadNotes = FALSE;
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.