1/*
2 *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
3 *
4 *Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 *"Software"), to deal in the Software without restriction, including
7 *without limitation the rights to use, copy, modify, merge, publish,
8 *distribute, sublicense, and/or sell copies of the Software, and to
9 *permit persons to whom the Software is furnished to do so, subject to
10 *the following conditions:
11 *
12 *The above copyright notice and this permission notice shall be
13 *included in all copies or substantial portions of the Software.
14 *
15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 *Except as contained in this notice, the name of Harold L Hunt II
24 *shall not be used in advertising or otherwise to promote the sale, use
25 *or other dealings in this Software without prior written authorization
26 *from Harold L Hunt II.
27 *
28 * Authors:	Harold L Hunt II
29 *              Earle F. Philhower III
30 */
31
32#ifdef HAVE_XWIN_CONFIG_H
33#include <xwin-config.h>
34#endif
35#include "win.h"
36#ifdef __CYGWIN__
37#include <sys/cygwin.h>
38#endif
39#include <shellapi.h>
40#include "winprefs.h"
41
42
43/*
44 * References to external globals
45 */
46
47#ifdef XWIN_CLIPBOARD
48extern Bool			g_fClipboardStarted;
49#endif
50/*
51 * Local function prototypes
52 */
53
54static wBOOL CALLBACK
55winExitDlgProc (HWND hDialog, UINT message,
56		WPARAM wParam, LPARAM lParam);
57
58static wBOOL CALLBACK
59winChangeDepthDlgProc (HWND hDialog, UINT message,
60		       WPARAM wParam, LPARAM lParam);
61
62static wBOOL CALLBACK
63winAboutDlgProc (HWND hDialog, UINT message,
64		 WPARAM wParam, LPARAM lParam);
65
66
67static void
68winDrawURLWindow (LPARAM lParam);
69
70static LRESULT CALLBACK
71winURLWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
72
73static void
74winOverrideURLButton (HWND hdlg, int id);
75
76static void
77winUnoverrideURLButton (HWND hdlg, int id);
78
79
80/*
81 * Owner-draw a button as a URL
82 */
83
84static void
85winDrawURLWindow (LPARAM lParam)
86{
87  DRAWITEMSTRUCT *draw;
88  char str[256];
89  RECT rect;
90  HFONT font;
91  COLORREF crText;
92
93  draw = (DRAWITEMSTRUCT *) lParam;
94  GetWindowText (draw->hwndItem, str, sizeof(str));
95  str[255] = 0;
96  GetClientRect (draw->hwndItem, &rect);
97
98  /* Color the button depending upon its state */
99  if (draw->itemState & ODS_SELECTED)
100    crText = RGB(128+64,0,0);
101  else if (draw->itemState & ODS_FOCUS)
102    crText = RGB(0,128+64,0);
103  else
104    crText = RGB(0,0,128+64);
105  SetTextColor (draw->hDC, crText);
106
107  /* Create font 8 high, standard dialog font */
108  font = CreateFont (-8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
109		     0, 0, 0, 0, 0, "MS Sans Serif");
110  if (!font)
111    {
112      ErrorF ("winDrawURLWindow: Unable to create URL font, bailing.\n");
113      return;
114    }
115  /* Draw it */
116  SetBkMode (draw->hDC, OPAQUE);
117  SelectObject (draw->hDC, font);
118  DrawText (draw->hDC, str, strlen (str),&rect,DT_CENTER | DT_VCENTER);
119  /* Delete the created font, replace it with stock font */
120  DeleteObject (SelectObject (draw->hDC, GetStockObject (ANSI_VAR_FONT)));
121}
122
123
124/*
125 * WndProc for overridden buttons
126 */
127
128static LRESULT CALLBACK
129winURLWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
130{
131  WNDPROC origCB = NULL;
132  HCURSOR cursor;
133
134  /* If it's a SetCursor message, tell it to the hand */
135  if (msg==WM_SETCURSOR) {
136    cursor = LoadCursor (NULL, IDC_HAND);
137    if (cursor)
138      SetCursor (cursor);
139    return TRUE;
140  }
141  origCB = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
142  /* Otherwise fall through to original WndProc */
143  if (origCB)
144    return CallWindowProc (origCB, hwnd, msg, wParam, lParam);
145  else
146    return FALSE;
147}
148
149
150/*
151 * Register and unregister the custom WndProc
152 */
153
154static void
155winOverrideURLButton (HWND hwnd, int id)
156{
157  WNDPROC origCB;
158  origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id),
159                                     GWLP_WNDPROC, (LONG_PTR)winURLWndProc);
160  SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_USERDATA, (LONG_PTR)origCB);
161}
162
163static void
164winUnoverrideURLButton (HWND hwnd, int id)
165{
166  WNDPROC origCB;
167  origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id),
168                                     GWLP_USERDATA, 0);
169  if (origCB)
170    SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_WNDPROC, (LONG_PTR)origCB);
171}
172
173
174/*
175 * Center a dialog window in the desktop window
176 * and set small and large icons to X icons.
177 */
178
179static void
180winInitDialog (HWND hwndDlg)
181{
182  HWND hwndDesk;
183  RECT rc, rcDlg, rcDesk;
184  HICON hIcon, hIconSmall;
185
186  hwndDesk = GetParent (hwndDlg);
187  if (!hwndDesk || IsIconic (hwndDesk))
188    hwndDesk = GetDesktopWindow ();
189
190  /* Remove minimize and maximize buttons */
191  SetWindowLongPtr(hwndDlg, GWL_STYLE,
192                   GetWindowLongPtr(hwndDlg, GWL_STYLE)
193                   & ~(WS_MAXIMIZEBOX | WS_MINIMIZEBOX));
194
195  /* Set Window not to show in the task bar */
196  SetWindowLongPtr(hwndDlg, GWL_EXSTYLE,
197                   GetWindowLongPtr(hwndDlg, GWL_EXSTYLE) & ~WS_EX_APPWINDOW );
198
199  /* Center dialog window in the screen. Not done for multi-monitor systems, where
200   * it is likely to end up split across the screens. In that case, it appears
201   * near the Tray icon.
202   */
203  if (GetSystemMetrics(SM_CMONITORS)>1) {
204    /* Still need to refresh the frame change. */
205    SetWindowPos (hwndDlg, HWND_TOPMOST, 0,0,0,0,
206		SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
207  } else {
208    GetWindowRect (hwndDesk, &rcDesk);
209    GetWindowRect (hwndDlg, &rcDlg);
210    CopyRect (&rc, &rcDesk);
211
212    OffsetRect (&rcDlg, -rcDlg.left, -rcDlg.top);
213    OffsetRect (&rc, -rc.left, -rc.top);
214    OffsetRect (&rc, -rcDlg.right, -rcDlg.bottom);
215
216    SetWindowPos (hwndDlg,
217		HWND_TOPMOST,
218		rcDesk.left + (rc.right / 2),
219		rcDesk.top + (rc.bottom / 2),
220		0, 0,
221		SWP_NOSIZE | SWP_FRAMECHANGED);
222  }
223
224#ifdef XWIN_MULTIWINDOW
225  if (g_hIconX) hIcon=g_hIconX;
226  else
227#endif
228  hIcon = LoadIcon (g_hInstance, MAKEINTRESOURCE(IDI_XWIN));
229
230#ifdef XWIN_MULTIWINDOW
231  if (g_hSmallIconX) hIconSmall=g_hSmallIconX;
232  else
233#endif
234  hIconSmall = LoadImage (g_hInstance,
235                        MAKEINTRESOURCE(IDI_XWIN), IMAGE_ICON,
236                        GetSystemMetrics(SM_CXSMICON),
237                        GetSystemMetrics(SM_CYSMICON),
238                        LR_SHARED);
239
240  PostMessage (hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
241  PostMessage (hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall);
242}
243
244
245/*
246 * Display the Exit dialog box
247 */
248
249void
250winDisplayExitDialog (winPrivScreenPtr pScreenPriv)
251{
252  int i;
253  int liveClients = 0;
254
255  /* Count up running clients (clients[0] is serverClient) */
256  for (i = 1; i < currentMaxClients; i++)
257    if (clients[i] != NullClient)
258      liveClients++;
259#if defined(XWIN_MULTIWINDOW)
260  /* Count down server internal clients */
261  if (pScreenPriv->pScreenInfo->fMultiWindow)
262    liveClients -= 2; /* multiwindow window manager & XMsgProc  */
263#endif
264#if defined(XWIN_CLIPBOARD)
265  if (g_fClipboardStarted)
266    liveClients--; /* clipboard manager */
267#endif
268
269  /* A user reported that this sometimes drops below zero. just eye-candy. */
270  if (liveClients < 0)
271    liveClients = 0;
272
273  /* Don't show the exit confirmation dialog if SilentExit & no clients,
274     or ForceExit, is enabled */
275  if ((pref.fSilentExit && liveClients <= 0) || pref.fForceExit)
276    {
277      if (g_hDlgExit != NULL)
278	{
279	  DestroyWindow (g_hDlgExit);
280	  g_hDlgExit = NULL;
281	}
282      PostMessage (pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0);
283      return;
284    }
285
286  pScreenPriv->iConnectedClients = liveClients;
287
288  /* Check if dialog already exists */
289  if (g_hDlgExit != NULL)
290    {
291      /* Dialog box already exists, display it */
292      ShowWindow (g_hDlgExit, SW_SHOWDEFAULT);
293
294      /* User has lost the dialog.  Show them where it is. */
295      SetForegroundWindow (g_hDlgExit);
296
297      return;
298    }
299
300  /* Create dialog box */
301  g_hDlgExit = CreateDialogParam (g_hInstance,
302				  "EXIT_DIALOG",
303				  pScreenPriv->hwndScreen,
304				  winExitDlgProc,
305				  (int) pScreenPriv);
306
307  /* Show the dialog box */
308  ShowWindow (g_hDlgExit, SW_SHOW);
309
310  /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */
311  SetForegroundWindow (g_hDlgExit);
312
313  /* Set focus to the Cancel button */
314  PostMessage (g_hDlgExit, WM_NEXTDLGCTL,
315	       (WPARAM)GetDlgItem (g_hDlgExit, IDCANCEL), TRUE);
316}
317
318#define CONNECTED_CLIENTS_FORMAT	"There %s currently %d client%s connected."
319
320
321/*
322 * Exit dialog window procedure
323 */
324
325static wBOOL CALLBACK
326winExitDlgProc (HWND hDialog, UINT message,
327		WPARAM wParam, LPARAM lParam)
328{
329  static winPrivScreenPtr	s_pScreenPriv = NULL;
330
331  /* Branch on message type */
332  switch (message)
333    {
334    case WM_INITDIALOG:
335      {
336	char			*pszConnectedClients;
337
338	/* Store pointers to private structures for future use */
339	s_pScreenPriv = (winPrivScreenPtr) lParam;
340
341	winInitDialog (hDialog);
342
343	/* Format the connected clients string */
344	if (asprintf (&pszConnectedClients, CONNECTED_CLIENTS_FORMAT,
345           (s_pScreenPriv->iConnectedClients == 1) ? "is" : "are",
346            s_pScreenPriv->iConnectedClients,
347           (s_pScreenPriv->iConnectedClients == 1) ? "" : "s") == -1)
348	    return TRUE;
349
350
351
352	/* Set the number of connected clients */
353	SetWindowText (GetDlgItem (hDialog, IDC_CLIENTS_CONNECTED),
354		       pszConnectedClients);
355	free(pszConnectedClients);
356      }
357      return TRUE;
358
359    case WM_COMMAND:
360      switch (LOWORD (wParam))
361	{
362	case IDOK:
363	  /* Send message to call the GiveUp function */
364	  PostMessage (s_pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0);
365	  DestroyWindow (g_hDlgExit);
366	  g_hDlgExit = NULL;
367
368	  /* Fix to make sure keyboard focus isn't trapped */
369	  PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0);
370	  return TRUE;
371
372	case IDCANCEL:
373	  DestroyWindow (g_hDlgExit);
374	  g_hDlgExit = NULL;
375
376	  /* Fix to make sure keyboard focus isn't trapped */
377	  PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0);
378	  return TRUE;
379	}
380      break;
381
382    case WM_MOUSEMOVE:
383    case WM_NCMOUSEMOVE:
384      /* Show the cursor if it is hidden */
385      if (g_fSoftwareCursor && !g_fCursor)
386	{
387	  g_fCursor = TRUE;
388	  ShowCursor (TRUE);
389	}
390      return TRUE;
391
392    case WM_CLOSE:
393      DestroyWindow (g_hDlgExit);
394      g_hDlgExit = NULL;
395
396      /* Fix to make sure keyboard focus isn't trapped */
397      PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0);
398      return TRUE;
399    }
400
401  return FALSE;
402}
403
404
405/*
406 * Display the Depth Change dialog box
407 */
408
409void
410winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv)
411{
412  /* Check if dialog already exists */
413  if (g_hDlgDepthChange != NULL)
414    {
415      /* Dialog box already exists, display it */
416      ShowWindow (g_hDlgDepthChange, SW_SHOWDEFAULT);
417
418      /* User has lost the dialog.  Show them where it is. */
419      SetForegroundWindow (g_hDlgDepthChange);
420
421      return;
422    }
423
424  /*
425   * Display a notification to the user that the visual
426   * will not be displayed until the Windows display depth
427   * is restored to the original value.
428   */
429  g_hDlgDepthChange = CreateDialogParam (g_hInstance,
430					 "DEPTH_CHANGE_BOX",
431					 pScreenPriv->hwndScreen,
432					 winChangeDepthDlgProc,
433					 (int) pScreenPriv);
434  /* Show the dialog box */
435  ShowWindow (g_hDlgDepthChange, SW_SHOW);
436
437  ErrorF ("winDisplayDepthChangeDialog - DialogBox returned: %d\n",
438	  (int) g_hDlgDepthChange);
439  ErrorF ("winDisplayDepthChangeDialog - GetLastError: %d\n",
440	  (int) GetLastError ());
441
442  /* Minimize the display window */
443  ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE);
444}
445
446
447/*
448 * Process messages for the dialog that is displayed for
449 * disruptive screen depth changes.
450 */
451
452static wBOOL CALLBACK
453winChangeDepthDlgProc (HWND hwndDialog, UINT message,
454		       WPARAM wParam, LPARAM lParam)
455{
456  static winPrivScreenPtr	s_pScreenPriv = NULL;
457  static winScreenInfo		*s_pScreenInfo = NULL;
458  static ScreenPtr		s_pScreen = NULL;
459
460#if CYGDEBUG
461  winDebug ("winChangeDepthDlgProc\n");
462#endif
463
464  /* Branch on message type */
465  switch (message)
466    {
467    case WM_INITDIALOG:
468#if CYGDEBUG
469      winDebug ("winChangeDepthDlgProc - WM_INITDIALOG\n");
470#endif
471
472      /* Store pointers to private structures for future use */
473      s_pScreenPriv = (winPrivScreenPtr) lParam;
474      s_pScreenInfo = s_pScreenPriv->pScreenInfo;
475      s_pScreen = s_pScreenInfo->pScreen;
476
477#if CYGDEBUG
478      winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - s_pScreenPriv: %08x, "
479	      "s_pScreenInfo: %08x, s_pScreen: %08x\n",
480	      s_pScreenPriv, s_pScreenInfo, s_pScreen);
481#endif
482
483#if CYGDEBUG
484      winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - orig bpp: %d, "
485	      "current bpp: %d\n",
486	      s_pScreenInfo->dwBPP,
487              GetDeviceCaps(s_pScreenPriv->hdcScreen, BITSPIXEL));
488#endif
489
490      winInitDialog( hwndDialog );
491
492      return TRUE;
493
494    case WM_DISPLAYCHANGE:
495#if CYGDEBUG
496      winDebug ("winChangeDepthDlgProc - WM_DISPLAYCHANGE - orig bpp: %d, "
497	      "new bpp: %d\n",
498	      s_pScreenInfo->dwBPP,
499              GetDeviceCaps(s_pScreenPriv->hdcScreen, BITSPIXEL));
500#endif
501
502      /* Dismiss the dialog if the display returns to the original depth */
503      if (GetDeviceCaps(s_pScreenPriv->hdcScreen, BITSPIXEL) == s_pScreenInfo->dwBPP)
504	{
505	  ErrorF ("winChangeDelthDlgProc - wParam == s_pScreenInfo->dwBPP\n");
506
507	  /* Depth has been restored, dismiss dialog */
508	  DestroyWindow (g_hDlgDepthChange);
509	  g_hDlgDepthChange = NULL;
510
511	  /* Flag that we have a valid screen depth */
512	  s_pScreenPriv->fBadDepth = FALSE;
513	}
514      return TRUE;
515
516    case WM_COMMAND:
517      switch (LOWORD (wParam))
518	{
519	case IDOK:
520	case IDCANCEL:
521	  ErrorF ("winChangeDepthDlgProc - WM_COMMAND - IDOK or IDCANCEL\n");
522
523	  /*
524	   * User dismissed the dialog, hide it until the
525	   * display mode is restored.
526	   */
527	  ShowWindow (g_hDlgDepthChange, SW_HIDE);
528	  return TRUE;
529	}
530      break;
531
532    case WM_CLOSE:
533      ErrorF ("winChangeDepthDlgProc - WM_CLOSE\n");
534
535      DestroyWindow (g_hDlgAbout);
536      g_hDlgAbout = NULL;
537
538      /* Fix to make sure keyboard focus isn't trapped */
539      PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0);
540      return TRUE;
541    }
542
543  return FALSE;
544}
545
546
547/*
548 * Display the About dialog box
549 */
550
551void
552winDisplayAboutDialog (winPrivScreenPtr pScreenPriv)
553{
554  /* Check if dialog already exists */
555  if (g_hDlgAbout != NULL)
556    {
557      /* Dialog box already exists, display it */
558      ShowWindow (g_hDlgAbout, SW_SHOWDEFAULT);
559
560      /* User has lost the dialog.  Show them where it is. */
561      SetForegroundWindow (g_hDlgAbout);
562
563      return;
564    }
565
566  /*
567   * Display the about box
568   */
569  g_hDlgAbout = CreateDialogParam (g_hInstance,
570				   "ABOUT_BOX",
571				   pScreenPriv->hwndScreen,
572				   winAboutDlgProc,
573				   (int) pScreenPriv);
574
575  /* Show the dialog box */
576  ShowWindow (g_hDlgAbout, SW_SHOW);
577
578  /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */
579  SetForegroundWindow (g_hDlgAbout);
580
581  /* Set focus to the OK button */
582  PostMessage (g_hDlgAbout, WM_NEXTDLGCTL,
583	       (WPARAM)GetDlgItem (g_hDlgAbout, IDOK), TRUE);
584}
585
586
587/*
588 * Process messages for the about dialog.
589 */
590
591static wBOOL CALLBACK
592winAboutDlgProc (HWND hwndDialog, UINT message,
593		 WPARAM wParam, LPARAM lParam)
594{
595  static winPrivScreenPtr	s_pScreenPriv = NULL;
596  static winScreenInfo		*s_pScreenInfo = NULL;
597  static ScreenPtr		s_pScreen = NULL;
598
599#if CYGDEBUG
600  winDebug ("winAboutDlgProc\n");
601#endif
602
603  /* Branch on message type */
604  switch (message)
605    {
606    case WM_INITDIALOG:
607#if CYGDEBUG
608      winDebug ("winAboutDlgProc - WM_INITDIALOG\n");
609#endif
610
611      /* Store pointers to private structures for future use */
612      s_pScreenPriv = (winPrivScreenPtr) lParam;
613      s_pScreenInfo = s_pScreenPriv->pScreenInfo;
614      s_pScreen = s_pScreenInfo->pScreen;
615
616      winInitDialog (hwndDialog);
617
618      /* Override the URL buttons */
619      winOverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG);
620      winOverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE);
621      winOverrideURLButton (hwndDialog, ID_ABOUT_UG);
622      winOverrideURLButton (hwndDialog, ID_ABOUT_FAQ);
623
624      return TRUE;
625
626    case WM_DRAWITEM:
627      /* Draw the URL buttons as needed */
628      winDrawURLWindow (lParam);
629      return TRUE;
630
631    case WM_MOUSEMOVE:
632    case WM_NCMOUSEMOVE:
633      /* Show the cursor if it is hidden */
634      if (g_fSoftwareCursor && !g_fCursor)
635	{
636	  g_fCursor = TRUE;
637	  ShowCursor (TRUE);
638	}
639      return TRUE;
640
641    case WM_COMMAND:
642      switch (LOWORD (wParam))
643	{
644	case IDOK:
645	case IDCANCEL:
646	  ErrorF ("winAboutDlgProc - WM_COMMAND - IDOK or IDCANCEL\n");
647
648	  DestroyWindow (g_hDlgAbout);
649	  g_hDlgAbout = NULL;
650
651	  /* Fix to make sure keyboard focus isn't trapped */
652	  PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0);
653
654	  /* Restore window procedures for URL buttons */
655	  winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG);
656	  winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE);
657	  winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG);
658	  winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ);
659
660	  return TRUE;
661
662	case ID_ABOUT_CHANGELOG:
663	  {
664	    int iReturn;
665#ifdef __CYGWIN__
666	    const char *	pszCygPath = "/usr/X11R6/share/doc/"
667	      "xorg-x11-xwin/changelog.html";
668	    char		pszWinPath[MAX_PATH + 1];
669
670	    /* Convert the POSIX path to a Win32 path */
671	    cygwin_conv_to_win32_path (pszCygPath, pszWinPath);
672#else
673	    const char *	pszWinPath = "http://x.cygwin.com/"
674		    "devel/server/changelog.html";
675#endif
676
677	    iReturn = (int)ShellExecute (NULL,
678                                    "open",
679                                    pszWinPath,
680                                    NULL,
681                                    NULL,
682                                    SW_MAXIMIZE);
683	    if (iReturn < 32)
684	      {
685		ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_CHANGELOG - "
686			"ShellExecute failed: %d\n",
687			iReturn);
688	      }
689	  }
690	  return TRUE;
691
692	case ID_ABOUT_WEBSITE:
693	  {
694	    const char *	pszPath = __VENDORDWEBSUPPORT__;
695	    int			iReturn;
696
697	    iReturn = (int)ShellExecute (NULL,
698                                    "open",
699                                    pszPath,
700                                    NULL,
701                                    NULL,
702                                    SW_MAXIMIZE);
703	    if (iReturn < 32)
704	      {
705		ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_WEBSITE - "
706			"ShellExecute failed: %d\n",
707			iReturn);
708	      }
709	  }
710	  return TRUE;
711
712	case ID_ABOUT_UG:
713	  {
714	    const char *	pszPath = "http://x.cygwin.com/docs/ug/";
715	    int			iReturn;
716
717	    iReturn = (int)ShellExecute (NULL,
718                                    "open",
719                                    pszPath,
720                                    NULL,
721                                    NULL,
722                                    SW_MAXIMIZE);
723	    if (iReturn < 32)
724	      {
725		ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_UG - "
726			"ShellExecute failed: %d\n",
727			iReturn);
728	      }
729	  }
730	  return TRUE;
731
732	case ID_ABOUT_FAQ:
733	  {
734	    const char *	pszPath = "http://x.cygwin.com/docs/faq/";
735	    int			iReturn;
736
737	    iReturn = (int)ShellExecute (NULL,
738                                    "open",
739                                    pszPath,
740                                    NULL,
741                                    NULL,
742                                    SW_MAXIMIZE);
743	    if (iReturn < 32)
744	      {
745		ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_FAQ - "
746			"ShellExecute failed: %d\n",
747			iReturn);
748	      }
749	  }
750	  return TRUE;
751	}
752      break;
753
754    case WM_CLOSE:
755      ErrorF ("winAboutDlgProc - WM_CLOSE\n");
756
757      DestroyWindow (g_hDlgAbout);
758      g_hDlgAbout = NULL;
759
760      /* Fix to make sure keyboard focus isn't trapped */
761      PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0);
762
763      /* Restore window procedures for URL buttons */
764      winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG);
765      winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE);
766      winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG);
767      winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ);
768
769      return TRUE;
770    }
771
772  return FALSE;
773}
774