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