1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2002,2005 Hans Breuer
3 * Copyright (C) 2003 Tor Lillqvist
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21 #include "config.h"
22 #include "gdk.h"
23 #include "gdkprivate-win32.h"
24
25 #define HAVE_MONITOR_INFO
26
27 #if defined(_MSC_VER) && (WINVER < 0x500) && (WINVER > 0x0400)
28 #include <multimon.h>
29 #elif defined(_MSC_VER) && (WINVER <= 0x0400)
30 #undef HAVE_MONITOR_INFO
31 #endif
32
33 void
_gdk_windowing_set_default_display(GdkDisplay * display)34 _gdk_windowing_set_default_display (GdkDisplay *display)
35 {
36 g_assert (display == NULL || _gdk_display == display);
37 }
38
39 gulong
_gdk_windowing_window_get_next_serial(GdkDisplay * display)40 _gdk_windowing_window_get_next_serial (GdkDisplay *display)
41 {
42 return 0;
43 }
44
45 #ifdef HAVE_MONITOR_INFO
46 static BOOL CALLBACK
count_monitor(HMONITOR hmonitor,HDC hdc,LPRECT rect,LPARAM data)47 count_monitor (HMONITOR hmonitor,
48 HDC hdc,
49 LPRECT rect,
50 LPARAM data)
51 {
52 gint *n = (gint *) data;
53
54 (*n)++;
55
56 return TRUE;
57 }
58
59 static BOOL CALLBACK
enum_monitor(HMONITOR hmonitor,HDC hdc,LPRECT rect,LPARAM data)60 enum_monitor (HMONITOR hmonitor,
61 HDC hdc,
62 LPRECT rect,
63 LPARAM data)
64 {
65 /* The struct MONITORINFOEX definition is for some reason different
66 * in the winuser.h bundled with mingw64 from that in MSDN and the
67 * official 32-bit mingw (the MONITORINFO part is in a separate "mi"
68 * member). So to keep this easily compileable with either, repeat
69 * the MSDN definition it here.
70 */
71 typedef struct tagMONITORINFOEXA2 {
72 DWORD cbSize;
73 RECT rcMonitor;
74 RECT rcWork;
75 DWORD dwFlags;
76 CHAR szDevice[CCHDEVICENAME];
77 } MONITORINFOEXA2;
78
79 MONITORINFOEXA2 monitor_info;
80 HDC hDC;
81
82 gint *index = (gint *) data;
83 GdkWin32Monitor *monitor;
84
85 if (*index >= _gdk_num_monitors)
86 {
87 (*index) += 1;
88
89 return TRUE;
90 }
91
92 monitor = _gdk_monitors + *index;
93
94 monitor_info.cbSize = sizeof (MONITORINFOEX);
95 GetMonitorInfoA (hmonitor, (MONITORINFO *) &monitor_info);
96
97 #ifndef MONITORINFOF_PRIMARY
98 #define MONITORINFOF_PRIMARY 1
99 #endif
100
101 monitor->name = g_strdup (monitor_info.szDevice);
102 hDC = CreateDCA ("DISPLAY", monitor_info.szDevice, NULL, NULL);
103 monitor->width_mm = GetDeviceCaps (hDC, HORZSIZE);
104 monitor->height_mm = GetDeviceCaps (hDC, VERTSIZE);
105 DeleteDC (hDC);
106 monitor->rect.x = monitor_info.rcMonitor.left;
107 monitor->rect.y = monitor_info.rcMonitor.top;
108 monitor->rect.width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left;
109 monitor->rect.height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top;
110
111 if (monitor_info.dwFlags & MONITORINFOF_PRIMARY &&
112 *index != 0)
113 {
114 /* Put primary monitor at index 0, just in case somebody needs
115 * to know which one is the primary.
116 */
117 GdkWin32Monitor temp = *monitor;
118 *monitor = _gdk_monitors[0];
119 _gdk_monitors[0] = temp;
120 }
121
122 (*index)++;
123
124 return TRUE;
125 }
126 #endif /* HAVE_MONITOR_INFO */
127
128 void
_gdk_monitor_init(void)129 _gdk_monitor_init (void)
130 {
131 #ifdef HAVE_MONITOR_INFO
132 gint i, index;
133
134 /* In case something happens between monitor counting and monitor
135 * enumeration, repeat until the count matches up.
136 * enum_monitor is coded to ignore any monitors past _gdk_num_monitors.
137 */
138 do
139 {
140 _gdk_num_monitors = 0;
141
142 EnumDisplayMonitors (NULL, NULL, count_monitor, (LPARAM) &_gdk_num_monitors);
143
144 _gdk_monitors = g_renew (GdkWin32Monitor, _gdk_monitors, _gdk_num_monitors);
145
146 index = 0;
147 EnumDisplayMonitors (NULL, NULL, enum_monitor, (LPARAM) &index);
148 } while (index != _gdk_num_monitors);
149
150 _gdk_offset_x = G_MININT;
151 _gdk_offset_y = G_MININT;
152
153 /* Calculate offset */
154 for (i = 0; i < _gdk_num_monitors; i++)
155 {
156 _gdk_offset_x = MAX (_gdk_offset_x, -_gdk_monitors[i].rect.x);
157 _gdk_offset_y = MAX (_gdk_offset_y, -_gdk_monitors[i].rect.y);
158 }
159 GDK_NOTE (MISC, g_print ("Multi-monitor offset: (%d,%d)\n",
160 _gdk_offset_x, _gdk_offset_y));
161
162 /* Translate monitor coords into GDK coordinate space */
163 for (i = 0; i < _gdk_num_monitors; i++)
164 {
165 _gdk_monitors[i].rect.x += _gdk_offset_x;
166 _gdk_monitors[i].rect.y += _gdk_offset_y;
167 GDK_NOTE (MISC, g_print ("Monitor %d: %dx%d@%+d%+d\n",
168 i, _gdk_monitors[i].rect.width,
169 _gdk_monitors[i].rect.height,
170 _gdk_monitors[i].rect.x,
171 _gdk_monitors[i].rect.y));
172 }
173 #else
174 HDC hDC;
175
176 _gdk_num_monitors = 1;
177 _gdk_monitors = g_renew (GdkWin32Monitor, _gdk_monitors, 1);
178
179 _gdk_monitors[0].name = g_strdup ("DISPLAY");
180 hDC = GetDC (NULL);
181 _gdk_monitors[0].width_mm = GetDeviceCaps (hDC, HORZSIZE);
182 _gdk_monitors[0].height_mm = GetDeviceCaps (hDC, VERTSIZE);
183 ReleaseDC (NULL, hDC);
184 _gdk_monitors[0].rect.x = 0;
185 _gdk_monitors[0].rect.y = 0;
186 _gdk_monitors[0].rect.width = GetSystemMetrics (SM_CXSCREEN);
187 _gdk_monitors[0].rect.height = GetSystemMetrics (SM_CYSCREEN);
188 _gdk_offset_x = 0;
189 _gdk_offset_y = 0;
190 #endif
191 }
192
193 GdkDisplay *
gdk_display_open(const gchar * display_name)194 gdk_display_open (const gchar *display_name)
195 {
196 GDK_NOTE (MISC, g_print ("gdk_display_open: %s\n", (display_name ? display_name : "NULL")));
197
198 if (display_name == NULL ||
199 g_ascii_strcasecmp (display_name,
200 gdk_display_get_name (_gdk_display)) == 0)
201 {
202 if (_gdk_display != NULL)
203 {
204 GDK_NOTE (MISC, g_print ("... return _gdk_display\n"));
205 return _gdk_display;
206 }
207 }
208 else
209 {
210 GDK_NOTE (MISC, g_print ("... return NULL\n"));
211 return NULL;
212 }
213
214 _gdk_display = g_object_new (GDK_TYPE_DISPLAY, NULL);
215 _gdk_screen = g_object_new (GDK_TYPE_SCREEN, NULL);
216
217 _gdk_monitor_init ();
218 _gdk_visual_init ();
219 gdk_screen_set_default_colormap (_gdk_screen,
220 gdk_screen_get_system_colormap (_gdk_screen));
221 _gdk_windowing_window_init (_gdk_screen);
222 _gdk_windowing_image_init ();
223 _gdk_events_init ();
224 _gdk_input_init (_gdk_display);
225 _gdk_dnd_init ();
226
227 /* Precalculate display name */
228 (void) gdk_display_get_name (_gdk_display);
229
230 g_signal_emit_by_name (gdk_display_manager_get (),
231 "display_opened", _gdk_display);
232
233 GDK_NOTE (MISC, g_print ("... _gdk_display now set up\n"));
234
235 return _gdk_display;
236 }
237
238 const gchar *
gdk_display_get_name(GdkDisplay * display)239 gdk_display_get_name (GdkDisplay *display)
240 {
241 HDESK hdesk = GetThreadDesktop (GetCurrentThreadId ());
242 char dummy;
243 char *desktop_name;
244 HWINSTA hwinsta = GetProcessWindowStation ();
245 char *window_station_name;
246 DWORD n;
247 DWORD session_id;
248 char *display_name;
249 static const char *display_name_cache = NULL;
250 typedef BOOL (WINAPI *PFN_ProcessIdToSessionId) (DWORD, DWORD *);
251 PFN_ProcessIdToSessionId processIdToSessionId;
252
253 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
254
255 if (display_name_cache != NULL)
256 return display_name_cache;
257
258 n = 0;
259 GetUserObjectInformation (hdesk, UOI_NAME, &dummy, 0, &n);
260 if (n == 0)
261 desktop_name = "Default";
262 else
263 {
264 n++;
265 desktop_name = g_alloca (n + 1);
266 memset (desktop_name, 0, n + 1);
267
268 if (!GetUserObjectInformation (hdesk, UOI_NAME, desktop_name, n, &n))
269 desktop_name = "Default";
270 }
271
272 n = 0;
273 GetUserObjectInformation (hwinsta, UOI_NAME, &dummy, 0, &n);
274 if (n == 0)
275 window_station_name = "WinSta0";
276 else
277 {
278 n++;
279 window_station_name = g_alloca (n + 1);
280 memset (window_station_name, 0, n + 1);
281
282 if (!GetUserObjectInformation (hwinsta, UOI_NAME, window_station_name, n, &n))
283 window_station_name = "WinSta0";
284 }
285
286 processIdToSessionId = (PFN_ProcessIdToSessionId) GetProcAddress (GetModuleHandle ("kernel32.dll"), "ProcessIdToSessionId");
287 if (!processIdToSessionId || !processIdToSessionId (GetCurrentProcessId (), &session_id))
288 session_id = 0;
289
290 display_name = g_strdup_printf ("%ld\\%s\\%s",
291 session_id,
292 window_station_name,
293 desktop_name);
294
295 GDK_NOTE (MISC, g_print ("gdk_display_get_name: %s\n", display_name));
296
297 display_name_cache = display_name;
298
299 return display_name_cache;
300 }
301
302 gint
gdk_display_get_n_screens(GdkDisplay * display)303 gdk_display_get_n_screens (GdkDisplay *display)
304 {
305 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
306
307 return 1;
308 }
309
310 GdkScreen *
gdk_display_get_screen(GdkDisplay * display,gint screen_num)311 gdk_display_get_screen (GdkDisplay *display,
312 gint screen_num)
313 {
314 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
315 g_return_val_if_fail (screen_num == 0, NULL);
316
317 return _gdk_screen;
318 }
319
320 GdkScreen *
gdk_display_get_default_screen(GdkDisplay * display)321 gdk_display_get_default_screen (GdkDisplay *display)
322 {
323 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
324
325 return _gdk_screen;
326 }
327
328 GdkWindow *
gdk_display_get_default_group(GdkDisplay * display)329 gdk_display_get_default_group (GdkDisplay *display)
330 {
331 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
332
333 g_warning ("gdk_display_get_default_group not yet implemented");
334
335 return NULL;
336 }
337
338 gboolean
gdk_display_supports_selection_notification(GdkDisplay * display)339 gdk_display_supports_selection_notification (GdkDisplay *display)
340 {
341 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
342
343 return TRUE;
344 }
345
346 static HWND _hwnd_next_viewer = NULL;
347 static int debug_indent = 0;
348
349 /*
350 * maybe this should be integrated with the default message loop - or maybe not ;-)
351 */
352 static LRESULT CALLBACK
inner_clipboard_window_procedure(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)353 inner_clipboard_window_procedure (HWND hwnd,
354 UINT message,
355 WPARAM wparam,
356 LPARAM lparam)
357 {
358 switch (message)
359 {
360 case WM_DESTROY: /* remove us from chain */
361 {
362 ChangeClipboardChain (hwnd, _hwnd_next_viewer);
363 PostQuitMessage (0);
364 return 0;
365 }
366 case WM_CHANGECBCHAIN:
367 {
368 HWND hwndRemove = (HWND) wparam; /* handle of window being removed */
369 HWND hwndNext = (HWND) lparam; /* handle of next window in chain */
370
371 if (hwndRemove == _hwnd_next_viewer)
372 _hwnd_next_viewer = hwndNext == hwnd ? NULL : hwndNext;
373 else if (_hwnd_next_viewer != NULL)
374 return SendMessage (_hwnd_next_viewer, message, wparam, lparam);
375
376 return 0;
377 }
378 #ifdef WM_CLIPBOARDUPDATE
379 case WM_CLIPBOARDUPDATE:
380 #endif
381 case WM_DRAWCLIPBOARD:
382 {
383 int success;
384 HWND hwndOwner;
385 #ifdef G_ENABLE_DEBUG
386 UINT nFormat = 0;
387 #endif
388 GdkEvent *event;
389 GdkWindow *owner;
390
391 success = OpenClipboard (hwnd);
392 g_return_val_if_fail (success, 0);
393 hwndOwner = GetClipboardOwner ();
394 owner = gdk_win32_window_lookup_for_display (_gdk_display, hwndOwner);
395 if (owner == NULL)
396 owner = gdk_win32_window_foreign_new_for_display (_gdk_display, hwndOwner);
397
398 GDK_NOTE (DND, g_print (" drawclipboard owner: %p", hwndOwner));
399
400 #ifdef G_ENABLE_DEBUG
401 if (_gdk_debug_flags & GDK_DEBUG_DND)
402 {
403 while ((nFormat = EnumClipboardFormats (nFormat)) != 0)
404 g_print ("%s ", _gdk_win32_cf_to_string (nFormat));
405 }
406 #endif
407
408 GDK_NOTE (DND, g_print (" \n"));
409
410
411 event = gdk_event_new (GDK_OWNER_CHANGE);
412 event->owner_change.window = _gdk_root;
413 event->owner_change.owner = owner;
414 event->owner_change.reason = GDK_OWNER_CHANGE_NEW_OWNER;
415 event->owner_change.selection = GDK_SELECTION_CLIPBOARD;
416 event->owner_change.time = _gdk_win32_get_next_tick (0);
417 event->owner_change.selection_time = GDK_CURRENT_TIME;
418 _gdk_win32_append_event (event);
419
420 CloseClipboard ();
421
422 if (_hwnd_next_viewer != NULL)
423 return SendMessage (_hwnd_next_viewer, message, wparam, lparam);
424
425 /* clear error to avoid confusing SetClipboardViewer() return */
426 SetLastError (0);
427 return 0;
428 }
429 default:
430 /* Otherwise call DefWindowProcW(). */
431 GDK_NOTE (EVENTS, g_print (" DefWindowProcW"));
432 return DefWindowProc (hwnd, message, wparam, lparam);
433 }
434 }
435
436 static LRESULT CALLBACK
_clipboard_window_procedure(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)437 _clipboard_window_procedure (HWND hwnd,
438 UINT message,
439 WPARAM wparam,
440 LPARAM lparam)
441 {
442 LRESULT retval;
443
444 GDK_NOTE (EVENTS, g_print ("%s%*s%s %p",
445 (debug_indent > 0 ? "\n" : ""),
446 debug_indent, "",
447 _gdk_win32_message_to_string (message), hwnd));
448 debug_indent += 2;
449 retval = inner_clipboard_window_procedure (hwnd, message, wparam, lparam);
450 debug_indent -= 2;
451
452 GDK_NOTE (EVENTS, g_print (" => %I64d%s", (gint64) retval, (debug_indent == 0 ? "\n" : "")));
453
454 return retval;
455 }
456
457 /*
458 * Creates a hidden window and adds it to the clipboard chain
459 */
460 static HWND
_gdk_win32_register_clipboard_notification(void)461 _gdk_win32_register_clipboard_notification (void)
462 {
463 WNDCLASS wclass = { 0, };
464 HWND hwnd;
465 ATOM klass;
466
467 wclass.lpszClassName = "GdkClipboardNotification";
468 wclass.lpfnWndProc = _clipboard_window_procedure;
469 wclass.hInstance = _gdk_app_hmodule;
470
471 klass = RegisterClass (&wclass);
472 if (!klass)
473 return NULL;
474
475 hwnd = CreateWindow (MAKEINTRESOURCE (klass),
476 NULL, WS_POPUP,
477 0, 0, 0, 0, NULL, NULL,
478 _gdk_app_hmodule, NULL);
479 if (!hwnd)
480 goto failed;
481
482 SetLastError (0);
483 _hwnd_next_viewer = SetClipboardViewer (hwnd);
484
485 if (_hwnd_next_viewer == NULL && GetLastError() != 0)
486 goto failed;
487
488 /* FIXME: http://msdn.microsoft.com/en-us/library/ms649033(v=VS.85).aspx */
489 /* This is only supported by Vista, and not yet by mingw64 */
490 /* if (AddClipboardFormatListener (hwnd) == FALSE) */
491 /* goto failed; */
492
493 return hwnd;
494
495 failed:
496 g_critical ("Failed to install clipboard viewer");
497 UnregisterClass (MAKEINTRESOURCE (klass), _gdk_app_hmodule);
498 return NULL;
499 }
500
501 gboolean
gdk_display_request_selection_notification(GdkDisplay * display,GdkAtom selection)502 gdk_display_request_selection_notification (GdkDisplay *display,
503 GdkAtom selection)
504
505 {
506 static HWND hwndViewer = NULL;
507 gboolean ret = FALSE;
508
509 GDK_NOTE (DND,
510 g_print ("gdk_display_request_selection_notification (..., %s)",
511 gdk_atom_name (selection)));
512
513 if (selection == GDK_SELECTION_CLIPBOARD ||
514 selection == GDK_SELECTION_PRIMARY)
515 {
516 if (!hwndViewer)
517 {
518 hwndViewer = _gdk_win32_register_clipboard_notification ();
519 GDK_NOTE (DND, g_print (" registered"));
520 }
521 ret = (hwndViewer != NULL);
522 }
523 else
524 {
525 GDK_NOTE (DND, g_print (" unsupported"));
526 ret = FALSE;
527 }
528
529 GDK_NOTE (DND, g_print (" -> %s\n", ret ? "TRUE" : "FALSE"));
530 return ret;
531 }
532
533 gboolean
gdk_display_supports_clipboard_persistence(GdkDisplay * display)534 gdk_display_supports_clipboard_persistence (GdkDisplay *display)
535 {
536 return FALSE;
537 }
538
539 void
gdk_display_store_clipboard(GdkDisplay * display,GdkWindow * clipboard_window,guint32 time_,const GdkAtom * targets,gint n_targets)540 gdk_display_store_clipboard (GdkDisplay *display,
541 GdkWindow *clipboard_window,
542 guint32 time_,
543 const GdkAtom *targets,
544 gint n_targets)
545 {
546 }
547
548 gboolean
gdk_display_supports_shapes(GdkDisplay * display)549 gdk_display_supports_shapes (GdkDisplay *display)
550 {
551 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
552
553 return TRUE;
554 }
555
556 gboolean
gdk_display_supports_input_shapes(GdkDisplay * display)557 gdk_display_supports_input_shapes (GdkDisplay *display)
558 {
559 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
560
561 /* Not yet implemented. See comment in
562 * gdk_window_input_shape_combine_mask().
563 */
564
565 return FALSE;
566 }
567
568 gboolean
gdk_display_supports_composite(GdkDisplay * display)569 gdk_display_supports_composite (GdkDisplay *display)
570 {
571 return FALSE;
572 }
573