1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2002,2005 Hans Breuer
3 * Copyright (C) 2003 Tor Lillqvist
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.
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.
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.
23 #include "gdkprivate-win32.h"
24 #include "gdkdisplayprivate.h"
25 #include "gdkwin32display.h"
26 #include "gdkwin32screen.h"
27 #include "gdkwin32window.h"
30 #define HAVE_MONITOR_INFO
32 #if defined(_MSC_VER) && (WINVER < 0x500) && (WINVER > 0x0400)
34 #elif defined(_MSC_VER) && (WINVER <= 0x0400)
35 #undef HAVE_MONITOR_INFO
39 _gdk_windowing_set_default_display (GdkDisplay *display)
41 g_assert (display == NULL || _gdk_display == display);
45 gdk_win32_display_get_next_serial (GdkDisplay *display)
50 #ifdef HAVE_MONITOR_INFO
52 count_monitor (HMONITOR hmonitor,
57 gint *n = (gint *) data;
65 enum_monitor (HMONITOR hmonitor,
70 /* The struct MONITORINFOEX definition is for some reason different
71 * in the winuser.h bundled with mingw64 from that in MSDN and the
72 * official 32-bit mingw (the MONITORINFO part is in a separate "mi"
73 * member). So to keep this easily compileable with either, repeat
74 * the MSDN definition it here.
76 typedef struct tagMONITORINFOEXA2 {
81 CHAR szDevice[CCHDEVICENAME];
84 MONITORINFOEXA2 monitor_info;
87 gint *index = (gint *) data;
88 GdkWin32Monitor *monitor;
90 g_assert (*index < _gdk_num_monitors);
92 monitor = _gdk_monitors + *index;
94 monitor_info.cbSize = sizeof (MONITORINFOEX);
95 GetMonitorInfoA (hmonitor, (MONITORINFO *) &monitor_info);
97 #ifndef MONITORINFOF_PRIMARY
98 #define MONITORINFOF_PRIMARY 1
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);
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;
111 if (monitor_info.dwFlags & MONITORINFOF_PRIMARY &&
114 /* Put primary monitor at index 0, just in case somebody needs
115 * to know which one is the primary.
117 GdkWin32Monitor temp = *monitor;
118 *monitor = _gdk_monitors[0];
119 _gdk_monitors[0] = temp;
126 #endif /* HAVE_MONITOR_INFO */
129 _gdk_monitor_init (void)
131 #ifdef HAVE_MONITOR_INFO
134 _gdk_num_monitors = 0;
136 EnumDisplayMonitors (NULL, NULL, count_monitor, (LPARAM) &_gdk_num_monitors);
138 _gdk_monitors = g_renew (GdkWin32Monitor, _gdk_monitors, _gdk_num_monitors);
141 EnumDisplayMonitors (NULL, NULL, enum_monitor, (LPARAM) &index);
143 _gdk_offset_x = G_MININT;
144 _gdk_offset_y = G_MININT;
146 /* Calculate offset */
147 for (i = 0; i < _gdk_num_monitors; i++)
149 _gdk_offset_x = MAX (_gdk_offset_x, -_gdk_monitors[i].rect.x);
150 _gdk_offset_y = MAX (_gdk_offset_y, -_gdk_monitors[i].rect.y);
152 GDK_NOTE (MISC, g_print ("Multi-monitor offset: (%d,%d)\n",
153 _gdk_offset_x, _gdk_offset_y));
155 /* Translate monitor coords into GDK coordinate space */
156 for (i = 0; i < _gdk_num_monitors; i++)
158 _gdk_monitors[i].rect.x += _gdk_offset_x;
159 _gdk_monitors[i].rect.y += _gdk_offset_y;
160 GDK_NOTE (MISC, g_print ("Monitor %d: %dx%d@%+d%+d\n",
161 i, _gdk_monitors[i].rect.width,
162 _gdk_monitors[i].rect.height,
163 _gdk_monitors[i].rect.x,
164 _gdk_monitors[i].rect.y));
169 _gdk_num_monitors = 1;
170 _gdk_monitors = g_renew (GdkWin32Monitor, _gdk_monitors, 1);
172 _gdk_monitors[0].name = g_strdup ("DISPLAY");
174 _gdk_monitors[0].width_mm = GetDeviceCaps (hDC, HORZSIZE);
175 _gdk_monitors[0].height_mm = GetDeviceCaps (hDC, VERTSIZE);
176 ReleaseDC (NULL, hDC);
177 _gdk_monitors[0].rect.x = 0;
178 _gdk_monitors[0].rect.y = 0;
179 _gdk_monitors[0].rect.width = GetSystemMetrics (SM_CXSCREEN);
180 _gdk_monitors[0].rect.height = GetSystemMetrics (SM_CYSCREEN);
187 _gdk_win32_display_open (const gchar *display_name)
189 GDK_NOTE (MISC, g_print ("gdk_display_open: %s\n", (display_name ? display_name : "NULL")));
191 if (display_name == NULL ||
192 g_ascii_strcasecmp (display_name,
193 gdk_display_get_name (_gdk_display)) == 0)
195 if (_gdk_display != NULL)
197 GDK_NOTE (MISC, g_print ("... return _gdk_display\n"));
203 GDK_NOTE (MISC, g_print ("... return NULL\n"));
207 _gdk_display = g_object_new (GDK_TYPE_WIN32_DISPLAY, NULL);
208 _gdk_screen = g_object_new (GDK_TYPE_WIN32_SCREEN, NULL);
210 _gdk_monitor_init ();
212 _gdk_windowing_window_init (_gdk_screen);
214 _gdk_input_init (_gdk_display);
217 /* Precalculate display name */
218 (void) gdk_display_get_name (_gdk_display);
220 g_signal_emit_by_name (gdk_display_manager_get (),
221 "display_opened", _gdk_display);
223 GDK_NOTE (MISC, g_print ("... _gdk_display now set up\n"));
228 struct _GdkWin32Display
233 struct _GdkWin32DisplayClass
235 GdkDisplayClass display_class;
238 G_DEFINE_TYPE (GdkWin32Display, gdk_win32_display, GDK_TYPE_DISPLAY)
241 gdk_win32_display_get_name (GdkDisplay *display)
243 HDESK hdesk = GetThreadDesktop (GetCurrentThreadId ());
246 HWINSTA hwinsta = GetProcessWindowStation ();
247 char *window_station_name;
251 static const char *display_name_cache = NULL;
252 typedef BOOL (WINAPI *PFN_ProcessIdToSessionId) (DWORD, DWORD *);
253 PFN_ProcessIdToSessionId processIdToSessionId;
255 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
257 if (display_name_cache != NULL)
258 return display_name_cache;
261 GetUserObjectInformation (hdesk, UOI_NAME, &dummy, 0, &n);
263 desktop_name = "Default";
267 desktop_name = g_alloca (n + 1);
268 memset (desktop_name, 0, n + 1);
270 if (!GetUserObjectInformation (hdesk, UOI_NAME, desktop_name, n, &n))
271 desktop_name = "Default";
275 GetUserObjectInformation (hwinsta, UOI_NAME, &dummy, 0, &n);
277 window_station_name = "WinSta0";
281 window_station_name = g_alloca (n + 1);
282 memset (window_station_name, 0, n + 1);
284 if (!GetUserObjectInformation (hwinsta, UOI_NAME, window_station_name, n, &n))
285 window_station_name = "WinSta0";
288 processIdToSessionId = (PFN_ProcessIdToSessionId) GetProcAddress (GetModuleHandle ("kernel32.dll"), "ProcessIdToSessionId");
289 if (!processIdToSessionId || !processIdToSessionId (GetCurrentProcessId (), &session_id))
292 display_name = g_strdup_printf ("%ld\\%s\\%s",
297 GDK_NOTE (MISC, g_print ("gdk_win32_display_get_name: %s\n", display_name));
299 display_name_cache = display_name;
301 return display_name_cache;
305 gdk_win32_display_get_n_screens (GdkDisplay *display)
307 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
313 gdk_win32_display_get_screen (GdkDisplay *display,
316 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
317 g_return_val_if_fail (screen_num == 0, NULL);
323 gdk_win32_display_get_default_screen (GdkDisplay *display)
325 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
331 gdk_win32_display_get_default_group (GdkDisplay *display)
333 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
335 g_warning ("gdk_display_get_default_group not yet implemented");
341 gdk_win32_display_supports_selection_notification (GdkDisplay *display)
343 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
348 static HWND _hwnd_next_viewer = NULL;
349 static int debug_indent = 0;
352 * maybe this should be integrated with the default message loop - or maybe not ;-)
354 static LRESULT CALLBACK
355 inner_clipboard_window_procedure (HWND hwnd,
362 case WM_DESTROY: /* remove us from chain */
364 ChangeClipboardChain (hwnd, _hwnd_next_viewer);
368 case WM_CHANGECBCHAIN:
370 HWND hwndRemove = (HWND) wparam; /* handle of window being removed */
371 HWND hwndNext = (HWND) lparam; /* handle of next window in chain */
373 if (hwndRemove == _hwnd_next_viewer)
374 _hwnd_next_viewer = hwndNext == hwnd ? NULL : hwndNext;
375 else if (_hwnd_next_viewer != NULL)
376 return SendMessage (_hwnd_next_viewer, message, wparam, lparam);
380 #ifdef WM_CLIPBOARDUPDATE
381 case WM_CLIPBOARDUPDATE:
383 case WM_DRAWCLIPBOARD:
387 #ifdef G_ENABLE_DEBUG
393 success = OpenClipboard (hwnd);
394 g_return_val_if_fail (success, 0);
395 hwndOwner = GetClipboardOwner ();
396 owner = gdk_win32_window_lookup_for_display (_gdk_display, hwndOwner);
398 owner = gdk_win32_window_foreign_new_for_display (_gdk_display, hwndOwner);
400 GDK_NOTE (DND, g_print (" drawclipboard owner: %p", hwndOwner));
402 #ifdef G_ENABLE_DEBUG
403 if (_gdk_debug_flags & GDK_DEBUG_DND)
405 while ((nFormat = EnumClipboardFormats (nFormat)) != 0)
406 g_print ("%s ", _gdk_win32_cf_to_string (nFormat));
410 GDK_NOTE (DND, g_print (" \n"));
413 event = gdk_event_new (GDK_OWNER_CHANGE);
414 event->owner_change.window = _gdk_root;
415 event->owner_change.owner = owner;
416 event->owner_change.reason = GDK_OWNER_CHANGE_NEW_OWNER;
417 event->owner_change.selection = GDK_SELECTION_CLIPBOARD;
418 event->owner_change.time = _gdk_win32_get_next_tick (0);
419 event->owner_change.selection_time = GDK_CURRENT_TIME;
420 _gdk_win32_append_event (event);
424 if (_hwnd_next_viewer != NULL)
425 return SendMessage (_hwnd_next_viewer, message, wparam, lparam);
427 /* clear error to avoid confusing SetClipboardViewer() return */
432 /* Otherwise call DefWindowProcW(). */
433 GDK_NOTE (EVENTS, g_print (" DefWindowProcW"));
434 return DefWindowProc (hwnd, message, wparam, lparam);
438 static LRESULT CALLBACK
439 _clipboard_window_procedure (HWND hwnd,
446 GDK_NOTE (EVENTS, g_print ("%s%*s%s %p",
447 (debug_indent > 0 ? "\n" : ""),
449 _gdk_win32_message_to_string (message), hwnd));
451 retval = inner_clipboard_window_procedure (hwnd, message, wparam, lparam);
454 GDK_NOTE (EVENTS, g_print (" => %I64d%s", (gint64) retval, (debug_indent == 0 ? "\n" : "")));
460 * Creates a hidden window and adds it to the clipboard chain
463 _gdk_win32_register_clipboard_notification (void)
465 WNDCLASS wclass = { 0, };
469 wclass.lpszClassName = "GdkClipboardNotification";
470 wclass.lpfnWndProc = _clipboard_window_procedure;
471 wclass.hInstance = _gdk_app_hmodule;
473 klass = RegisterClass (&wclass);
477 hwnd = CreateWindow (MAKEINTRESOURCE (klass),
479 0, 0, 0, 0, NULL, NULL,
480 _gdk_app_hmodule, NULL);
485 _hwnd_next_viewer = SetClipboardViewer (hwnd);
487 if (_hwnd_next_viewer == NULL && GetLastError() != 0)
490 /* FIXME: http://msdn.microsoft.com/en-us/library/ms649033(v=VS.85).aspx */
491 /* This is only supported by Vista, and not yet by mingw64 */
492 /* if (AddClipboardFormatListener (hwnd) == FALSE) */
498 g_critical ("Failed to install clipboard viewer");
499 UnregisterClass (MAKEINTRESOURCE (klass), _gdk_app_hmodule);
504 gdk_win32_display_request_selection_notification (GdkDisplay *display,
508 static HWND hwndViewer = NULL;
509 gboolean ret = FALSE;
512 g_print ("gdk_display_request_selection_notification (..., %s)",
513 gdk_atom_name (selection)));
515 if (selection == GDK_SELECTION_CLIPBOARD ||
516 selection == GDK_SELECTION_PRIMARY)
520 hwndViewer = _gdk_win32_register_clipboard_notification ();
521 GDK_NOTE (DND, g_print (" registered"));
523 ret = (hwndViewer != NULL);
527 GDK_NOTE (DND, g_print (" unsupported"));
531 GDK_NOTE (DND, g_print (" -> %s\n", ret ? "TRUE" : "FALSE"));
536 gdk_win32_display_supports_clipboard_persistence (GdkDisplay *display)
542 gdk_win32_display_store_clipboard (GdkDisplay *display,
543 GdkWindow *clipboard_window,
545 const GdkAtom *targets,
551 gdk_win32_display_supports_shapes (GdkDisplay *display)
553 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
559 gdk_win32_display_supports_input_shapes (GdkDisplay *display)
561 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
563 /* Not yet implemented. See comment in
564 * gdk_window_input_shape_combine_mask().
571 gdk_win32_display_supports_composite (GdkDisplay *display)
577 gdk_win32_display_beep (GdkDisplay *display)
579 g_return_if_fail (display == gdk_display_get_default());
580 if (!MessageBeep (-1))
585 gdk_win32_display_flush (GdkDisplay * display)
587 g_return_if_fail (display == _gdk_display);
594 gdk_win32_display_sync (GdkDisplay * display)
596 g_return_if_fail (display == _gdk_display);
602 gdk_win32_display_dispose (GObject *object)
607 gdk_win32_display_finalize (GObject *object)
612 gdk_win32_display_init(GdkWin32Display *display)
617 gdk_win32_display_before_process_all_updates (GdkDisplay *display)
622 gdk_win32_display_after_process_all_updates (GdkDisplay *display)
627 gdk_win32_display_notify_startup_complete (GdkDisplay *display,
628 const gchar *startup_id)
633 gdk_win32_display_event_data_copy (GdkDisplay *display,
640 gdk_win32_display_event_data_free (GdkDisplay *display,
646 gdk_win32_display_push_error_trap (GdkDisplay *display)
651 gdk_win32_display_pop_error_trap (GdkDisplay *display,
657 gdk_win32_display_class_init (GdkWin32DisplayClass *klass)
659 GObjectClass *object_class = G_OBJECT_CLASS (klass);
660 GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (klass);
662 object_class->dispose = gdk_win32_display_dispose;
663 object_class->finalize = gdk_win32_display_finalize;
665 display_class->window_type = GDK_TYPE_WIN32_WINDOW;
667 display_class->get_name = gdk_win32_display_get_name;
668 display_class->get_n_screens = gdk_win32_display_get_n_screens;
669 display_class->get_screen = gdk_win32_display_get_screen;
670 display_class->get_default_screen = gdk_win32_display_get_default_screen;
671 display_class->beep = gdk_win32_display_beep;
672 display_class->sync = gdk_win32_display_sync;
673 display_class->flush = gdk_win32_display_flush;
674 display_class->has_pending = _gdk_win32_display_has_pending;
675 display_class->queue_events = _gdk_win32_display_queue_events;
676 display_class->get_default_group = gdk_win32_display_get_default_group;
678 display_class->supports_selection_notification = gdk_win32_display_supports_selection_notification;
679 display_class->request_selection_notification = gdk_win32_display_request_selection_notification;
680 display_class->supports_clipboard_persistence = gdk_win32_display_supports_clipboard_persistence;
681 display_class->store_clipboard = gdk_win32_display_store_clipboard;
682 display_class->supports_shapes = gdk_win32_display_supports_shapes;
683 display_class->supports_input_shapes = gdk_win32_display_supports_input_shapes;
684 display_class->supports_composite = gdk_win32_display_supports_composite;
686 display_class->list_devices = _gdk_win32_display_list_devices;
687 //? display_class->get_app_launch_context = _gdk_win32_display_get_app_launch_context;
688 display_class->get_cursor_for_type = _gdk_win32_display_get_cursor_for_type;
689 display_class->get_cursor_for_name = _gdk_win32_display_get_cursor_for_name;
690 display_class->get_cursor_for_pixbuf = _gdk_win32_display_get_cursor_for_pixbuf;
691 display_class->get_default_cursor_size = _gdk_win32_display_get_default_cursor_size;
692 display_class->get_maximal_cursor_size = _gdk_win32_display_get_maximal_cursor_size;
693 display_class->supports_cursor_alpha = _gdk_win32_display_supports_cursor_alpha;
694 display_class->supports_cursor_color = _gdk_win32_display_supports_cursor_color;
696 display_class->before_process_all_updates = gdk_win32_display_before_process_all_updates;
697 display_class->after_process_all_updates = gdk_win32_display_after_process_all_updates;
698 display_class->get_next_serial = gdk_win32_display_get_next_serial;
699 display_class->notify_startup_complete = gdk_win32_display_notify_startup_complete;
700 display_class->event_data_copy = gdk_win32_display_event_data_copy;
701 display_class->event_data_free = gdk_win32_display_event_data_free;
702 display_class->create_window_impl = _gdk_win32_display_create_window_impl;
704 display_class->get_keymap = _gdk_win32_display_get_keymap;
705 display_class->push_error_trap = gdk_win32_display_push_error_trap;
706 display_class->pop_error_trap = gdk_win32_display_pop_error_trap;
707 display_class->get_selection_owner = _gdk_win32_display_get_selection_owner;
708 display_class->set_selection_owner = _gdk_win32_display_set_selection_owner;
709 display_class->send_selection_notify = _gdk_win32_display_send_selection_notify;
710 display_class->get_selection_property = _gdk_win32_display_get_selection_property;
711 display_class->convert_selection = _gdk_win32_display_convert_selection;
712 display_class->text_property_to_utf8_list = _gdk_win32_display_text_property_to_utf8_list;
713 display_class->utf8_to_string_target = _gdk_win32_display_utf8_to_string_target;