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