]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdisplay-win32.c
Cache the display name. There is only one GdkDisplay on Win32, and
[~andy/gtk] / gdk / win32 / gdkdisplay-win32.c
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 #ifdef HAVE_MONITOR_INFO
34 typedef BOOL (WINAPI *t_EnumDisplayMonitors)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
35 typedef BOOL (WINAPI *t_GetMonitorInfoA)(HMONITOR, LPMONITORINFO);
36
37 static t_EnumDisplayMonitors p_EnumDisplayMonitors = NULL;
38 static t_GetMonitorInfoA p_GetMonitorInfoA = NULL;
39 #endif
40
41 void
42 _gdk_windowing_set_default_display (GdkDisplay *display)
43 {
44   g_assert (_gdk_display == display);
45 }
46
47 #ifdef HAVE_MONITOR_INFO
48 static BOOL CALLBACK
49 count_monitor (HMONITOR hmonitor,
50                HDC      hdc,
51                LPRECT   rect,
52                LPARAM   data)
53 {
54   gint *n = (gint *) data;
55
56   (*n)++;
57
58   return TRUE;
59 }
60
61 static BOOL CALLBACK
62 enum_monitor (HMONITOR hmonitor,
63               HDC      hdc,
64               LPRECT   rect,
65               LPARAM   data)
66 {
67   MONITORINFOEX monitor_info;
68
69   gint *index = (gint *) data;
70   GdkRectangle *monitor;
71
72   g_assert (*index < _gdk_num_monitors);
73
74   monitor = _gdk_monitors + *index;
75
76   monitor_info.cbSize = sizeof (MONITORINFOEX);
77   (*p_GetMonitorInfoA) (hmonitor, (MONITORINFO *) &monitor_info);
78
79 #ifndef MONITORINFOF_PRIMARY
80 #define MONITORINFOF_PRIMARY 1
81 #endif
82
83   monitor->x = monitor_info.rcMonitor.left;
84   monitor->y = monitor_info.rcMonitor.top;
85   monitor->width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left;
86   monitor->height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top;
87
88   if (monitor_info.dwFlags & MONITORINFOF_PRIMARY &&
89       *index != 0)
90     {
91       /* Put primary monitor at index 0, just in case somebody needs
92        * to know which one is the primary.
93        */
94       GdkRectangle temp = *monitor;
95       *monitor = _gdk_monitors[0];
96       _gdk_monitors[0] = temp;
97     }
98
99   (*index)++;
100
101   return TRUE;
102 }
103 #endif /* HAVE_MONITOR_INFO */
104
105 void
106 _gdk_monitor_init (void)
107 {
108 #ifdef HAVE_MONITOR_INFO
109   static HMODULE user32 = NULL;
110
111   if (user32 == NULL)
112     {
113       user32 = GetModuleHandle ("user32.dll");
114
115       g_assert (user32 != NULL);
116
117       p_EnumDisplayMonitors = (t_EnumDisplayMonitors) GetProcAddress (user32, "EnumDisplayMonitors");
118       p_GetMonitorInfoA = (t_GetMonitorInfoA) GetProcAddress (user32, "GetMonitorInfoA");
119     }
120
121   if (p_EnumDisplayMonitors != NULL && p_GetMonitorInfoA != NULL)
122     {
123       gint i, index;
124
125       _gdk_num_monitors = 0;
126
127       (*p_EnumDisplayMonitors) (NULL, NULL, count_monitor, (LPARAM) &_gdk_num_monitors);
128
129       _gdk_monitors = g_renew (GdkRectangle, _gdk_monitors, _gdk_num_monitors);
130
131       index = 0;
132       (*p_EnumDisplayMonitors) (NULL, NULL, enum_monitor, (LPARAM) &index);
133
134       _gdk_offset_x = G_MININT;
135       _gdk_offset_y = G_MININT;
136
137       /* Calculate offset */
138       for (i = 0; i < _gdk_num_monitors; i++)
139         {
140           _gdk_offset_x = MAX (_gdk_offset_x, -_gdk_monitors[i].x);
141           _gdk_offset_y = MAX (_gdk_offset_y, -_gdk_monitors[i].y);
142         }
143       GDK_NOTE (MISC, g_print ("Multi-monitor offset: (%d,%d)\n",
144                                _gdk_offset_x, _gdk_offset_y));
145
146       /* Translate monitor coords into GDK coordinate space */
147       for (i = 0; i < _gdk_num_monitors; i++)
148         {
149           _gdk_monitors[i].x += _gdk_offset_x;
150           _gdk_monitors[i].y += _gdk_offset_y;
151           GDK_NOTE (MISC, g_print ("Monitor %d: %dx%d@%+d%+d\n",
152                                    i, _gdk_monitors[i].width,
153                                    _gdk_monitors[i].height,
154                                    _gdk_monitors[i].x, _gdk_monitors[i].y));
155         }
156     }
157   else
158 #endif /* HAVE_MONITOR_INFO */
159     {
160       unsigned int width, height;
161
162       _gdk_num_monitors = 1;
163       _gdk_monitors = g_renew (GdkRectangle, _gdk_monitors, 1);
164
165       width = GetSystemMetrics (SM_CXSCREEN);
166       height = GetSystemMetrics (SM_CYSCREEN);
167
168       _gdk_monitors[0].x = 0;
169       _gdk_monitors[0].y = 0;
170       _gdk_monitors[0].width = width;
171       _gdk_monitors[0].height = height;
172       _gdk_offset_x = 0;
173       _gdk_offset_y = 0;
174     }
175
176 }
177
178 /*
179  * Dynamic version of ProcessIdToSessionId() form Terminal Service.
180  * It is only returning something else than 0 when running under
181  * Terminal Service, available since NT4 SP4 and not for win9x
182  */
183 static guint
184 get_session_id (void)
185 {
186   typedef BOOL (WINAPI *t_ProcessIdToSessionId) (DWORD, DWORD*);
187   static t_ProcessIdToSessionId p_ProcessIdToSessionId = NULL;
188   static HMODULE kernel32 = NULL;
189   DWORD id = 0;
190
191   if (kernel32 == NULL)
192     {
193       kernel32 = GetModuleHandle ("kernel32.dll");
194
195       g_assert (kernel32 != NULL);
196
197       p_ProcessIdToSessionId = (t_ProcessIdToSessionId) GetProcAddress (kernel32, "ProcessIdToSessionId");
198    }
199   if (p_ProcessIdToSessionId)
200       p_ProcessIdToSessionId (GetCurrentProcessId (), &id); /* got it (or not ;) */
201
202   return id;
203 }
204
205 GdkDisplay *
206 gdk_display_open (const gchar *display_name)
207 {
208   GDK_NOTE (MISC, g_print ("gdk_display_open: %s\n", (display_name ? display_name : "NULL")));
209
210   if (display_name == NULL ||
211       g_ascii_strcasecmp (display_name,
212                           gdk_display_get_name (_gdk_display)) == 0)
213     {
214       if (_gdk_display != NULL)
215         {
216           GDK_NOTE (MISC, g_print ("... return _gdk_display\n"));
217           return _gdk_display;
218         }
219     }
220   else
221     {
222       GDK_NOTE (MISC, g_print ("... return NULL\n"));
223       return NULL;
224     }
225
226   _gdk_display = g_object_new (GDK_TYPE_DISPLAY, NULL);
227   _gdk_screen = g_object_new (GDK_TYPE_SCREEN, NULL);
228
229   _gdk_monitor_init ();
230   _gdk_visual_init ();
231   gdk_screen_set_default_colormap (_gdk_screen,
232                                    gdk_screen_get_system_colormap (_gdk_screen));
233   _gdk_windowing_window_init ();
234   _gdk_windowing_image_init ();
235   _gdk_events_init ();
236   _gdk_input_init (_gdk_display);
237   _gdk_dnd_init ();
238
239   /* Precalculate display name */
240   (void) gdk_display_get_name (_gdk_display);
241
242   g_signal_emit_by_name (gdk_display_manager_get (),
243                          "display_opened", _gdk_display);
244
245   GDK_NOTE (MISC, g_print ("... _gdk_display now set up\n"));
246
247   return _gdk_display;
248 }
249
250 G_CONST_RETURN gchar *
251 gdk_display_get_name (GdkDisplay *display)
252 {
253   HDESK hdesk = GetThreadDesktop (GetCurrentThreadId ());
254   char dummy;
255   char *desktop_name;
256   HWINSTA hwinsta = GetProcessWindowStation ();
257   char *window_station_name;
258   DWORD n;
259   char *display_name;
260   static const char *display_name_cache = NULL;
261
262   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
263   
264   if (display_name_cache != NULL)
265     return display_name_cache;
266
267   n = 0;
268   GetUserObjectInformation (hdesk, UOI_NAME, &dummy, 0, &n);
269   if (n == 0)
270     desktop_name = "Default";
271   else
272     {
273       n++;
274       desktop_name = g_alloca (n + 1);
275       memset (desktop_name, 0, n + 1);
276
277       if (!GetUserObjectInformation (hdesk, UOI_NAME, desktop_name, n, &n))
278         desktop_name = "Default";
279     }
280
281   n = 0;
282   GetUserObjectInformation (hwinsta, UOI_NAME, &dummy, 0, &n);
283   if (n == 0)
284     window_station_name = "WinSta0";
285   else
286     {
287       n++;
288       window_station_name = g_alloca (n + 1);
289       memset (window_station_name, 0, n + 1);
290
291       if (!GetUserObjectInformation (hwinsta, UOI_NAME, window_station_name, n, &n))
292         window_station_name = "WinSta0";
293     }
294
295   display_name = g_strdup_printf ("%d\\%s\\%s",
296                                   get_session_id (), window_station_name,
297                                   desktop_name);
298
299   GDK_NOTE (MISC, g_print ("gdk_display_get_name: %s\n", display_name));
300
301   display_name_cache = display_name;
302
303   return display_name_cache;
304 }
305
306 gint
307 gdk_display_get_n_screens (GdkDisplay *display)
308 {
309   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
310   
311   return 1;
312 }
313
314 GdkScreen *
315 gdk_display_get_screen (GdkDisplay *display,
316                         gint        screen_num)
317 {
318   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
319   g_return_val_if_fail (screen_num != 0, NULL);
320
321   return _gdk_screen;
322 }
323
324 GdkScreen *
325 gdk_display_get_default_screen (GdkDisplay *display)
326 {
327   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
328
329   return _gdk_screen;
330 }
331
332 GdkWindow *
333 gdk_display_get_default_group (GdkDisplay *display)
334 {
335   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
336
337   g_warning ("gdk_display_get_default_group not yet implemented");
338
339   return NULL;
340 }
341
342 gboolean 
343 gdk_display_supports_selection_notification (GdkDisplay *display)
344 {
345   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
346
347   return TRUE;
348 }
349
350 static HWND _hwnd_next_viewer = NULL;
351
352 /*
353  * maybe this should be integrated with the default message loop - or maybe not ;-)
354  */
355 static LRESULT CALLBACK
356 _win32_on_clipboard_change (HWND   hwnd,
357                             UINT   message,
358                             WPARAM wparam,
359                             LPARAM lparam)
360 {
361   switch (message)
362     {
363     case WM_DESTROY : /* remove us from chain */
364       {
365         ChangeClipboardChain (hwnd, _hwnd_next_viewer);
366         return 0; 
367       }
368     case WM_CHANGECBCHAIN :
369       {
370         HWND hwndRemove = (HWND) wparam; /* handle of window being removed */
371         HWND hwndNext   = (HWND) lparam; /* handle of next window in chain */
372         if (hwndRemove == _hwnd_next_viewer)
373           _hwnd_next_viewer = hwndNext == hwnd ? NULL : hwndNext;
374         return 0;
375       }
376     case WM_DRAWCLIPBOARD :
377       {
378         /* Create the appropriate gdk events */
379
380 #ifdef G_ENABLE_DEBUG
381         if ((_gdk_debug_flags & GDK_DEBUG_DND) &&
382             OpenClipboard (hwnd))
383           {
384             HWND hwndOwner = GetClipboardOwner ();
385             UINT nFormat = 0;
386             
387             g_print ("WM_DRAWCLIPBOARD: owner:%p formats: ", hwndOwner);
388             for (; 0 != (nFormat = EnumClipboardFormats (nFormat));)
389               {
390                 g_print ("%s ", _gdk_win32_cf_to_string (nFormat));
391               }
392             g_print ("\n");
393             CloseClipboard ();
394           }
395 #endif
396         /* XXX: generate the apropriate GdkEventOwnerChange ... */
397
398         /* don't break the chain */
399         return PostMessage (_hwnd_next_viewer, message, wparam, lparam);
400       }
401     default :
402       return DefWindowProc (hwnd, message, wparam, lparam);
403     }
404 }
405
406 /*
407  * Creates a hidden window and adds it to the clipboard chain
408  */
409 HWND
410 _gdk_win32_register_clipboard_notification (void)
411 {
412   WNDCLASS wclass;
413   HWND     hwnd;
414   ATOM     klass;
415
416   memset (&wclass, 0, sizeof(WNDCLASS));
417   wclass.lpszClassName = "GdkClipboardNotification";
418   wclass.lpfnWndProc   = _win32_on_clipboard_change;
419   wclass.hInstance     = _gdk_app_hmodule;
420
421   klass = RegisterClass (&wclass);
422   if (!klass)
423     return NULL;
424
425   hwnd = CreateWindow (MAKEINTRESOURCE(klass),
426                        NULL, WS_POPUP,
427                        0, 0, 0, 0, NULL, NULL,
428                        _gdk_app_hmodule, NULL);
429   if (!hwnd)
430     {
431       UnregisterClass (MAKEINTRESOURCE(klass), _gdk_app_hmodule);
432       return NULL;
433     }
434   _hwnd_next_viewer = SetClipboardViewer (hwnd);
435   return hwnd;
436 }
437
438 /*
439  * The whole function would only make sense if the gdk/win32 clipboard
440  * model is rewritten to do delayed rendering. Currently this is only
441  * testcode and as noted in
442  * http://mail.gnome.org/archives/gtk-devel-list/2004-May/msg00113.html
443  * probably not worth bothering ;)
444  */
445 gboolean 
446 gdk_display_request_selection_notification (GdkDisplay *display,
447                                             GdkAtom     selection)
448
449 {
450   static HWND hwndViewer = NULL;
451   gboolean ret = FALSE;
452
453   GDK_NOTE (DND, 
454             g_print ("gdk_display_request_selection_notification (..., %s)",
455                      gdk_atom_name (selection)));
456
457   if (GDK_SELECTION_CLIPBOARD == selection)
458     {
459       if (!hwndViewer)
460         {
461           hwndViewer = _gdk_win32_register_clipboard_notification ();
462           GDK_NOTE (DND, g_print (" registered"));
463         }
464       ret = (hwndViewer != NULL);
465     }
466   else if (GDK_SELECTION_PRIMARY == selection)
467     {
468       /* seems to work by default ? */
469       GDK_NOTE (DND, g_print (" by default"));
470       ret = TRUE;
471     }
472   GDK_NOTE (DND, g_print (" -> %s\n", ret ? "TRUE" : "FALSE"));
473   return ret;
474 }
475
476 gboolean
477 gdk_display_supports_clipboard_persistence (GdkDisplay *display)
478 {
479   return FALSE;
480 }
481
482 void
483 gdk_display_store_clipboard (GdkDisplay *display,
484                              GdkWindow  *clipboard_window,
485                              guint32     time_,
486                              GdkAtom    *targets,
487                              gint        n_targets)
488 {
489   /* XXX: implement it (or maybe not as long as we don't support delayed rendering?) */
490 }