]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdisplay-win32.c
Report whole of (primary) monitor, including any taskbars. Excluding the
[~andy/gtk] / gdk / win32 / gdkdisplay-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 2002 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 GdkDisplay *
106 gdk_display_open (const gchar *display_name)
107 {
108   HMODULE user32;
109
110   if (_gdk_display != NULL)
111     return NULL; /* single display only */
112
113   _gdk_display = g_object_new (GDK_TYPE_DISPLAY, NULL);
114   _gdk_screen = g_object_new (GDK_TYPE_SCREEN, NULL);
115
116 #ifdef HAVE_MONITOR_INFO
117   user32 = GetModuleHandle ("user32.dll");
118   g_assert (user32 != NULL);
119
120   p_EnumDisplayMonitors = (t_EnumDisplayMonitors) GetProcAddress (user32, "EnumDisplayMonitors");
121   p_GetMonitorInfoA = (t_GetMonitorInfoA) GetProcAddress (user32, "GetMonitorInfoA");
122
123   if (p_EnumDisplayMonitors != NULL && p_GetMonitorInfoA != NULL)
124     {
125       gint i, index;
126
127       _gdk_num_monitors = 0;
128
129       (*p_EnumDisplayMonitors) (NULL, NULL, count_monitor, (LPARAM) &_gdk_num_monitors);
130
131       _gdk_monitors = g_new (GdkRectangle, _gdk_num_monitors);
132       index = 0;
133       (*p_EnumDisplayMonitors) (NULL, NULL, enum_monitor, (LPARAM) &index);
134 #if 1
135       _gdk_offset_x = G_MININT;
136       _gdk_offset_y = G_MININT;
137
138       /* Calculate offset */
139       for (i = 0; i < _gdk_num_monitors; i++)
140         {
141           _gdk_offset_x = MAX (_gdk_offset_x, -_gdk_monitors[i].x);
142           _gdk_offset_y = MAX (_gdk_offset_y, -_gdk_monitors[i].y);
143         }
144       GDK_NOTE (MISC, g_print ("Multi-monitor offset: (%d,%d)\n",
145                                _gdk_offset_x, _gdk_offset_y));
146
147       /* Translate monitor coords into GDK coordinate space */
148       for (i = 0; i < _gdk_num_monitors; i++)
149         {
150           _gdk_monitors[i].x += _gdk_offset_x;
151           _gdk_monitors[i].y += _gdk_offset_y;
152           GDK_NOTE (MISC, g_print ("Monitor %d: %dx%d@+%d+%d\n",
153                                    i, _gdk_monitors[i].width,
154                                    _gdk_monitors[i].height,
155                                    _gdk_monitors[i].x, _gdk_monitors[i].y));
156         }
157 #endif
158     }
159   else
160 #endif /* HAVE_MONITOR_INFO */
161     {
162       unsigned int width, height;
163
164       _gdk_num_monitors = 1;
165       _gdk_monitors = g_new (GdkRectangle, 1);
166
167       width = GetSystemMetrics (SM_CXSCREEN);
168       height = GetSystemMetrics (SM_CYSCREEN);
169
170       _gdk_monitors[0].x = 0;
171       _gdk_monitors[0].y = 0;
172       _gdk_monitors[0].width = width;
173       _gdk_monitors[0].height = height;
174       _gdk_offset_x = 0;
175       _gdk_offset_y = 0;
176     }
177
178   _gdk_visual_init ();
179   gdk_screen_set_default_colormap (_gdk_screen,
180                                    gdk_screen_get_system_colormap (_gdk_screen));
181   _gdk_windowing_window_init ();
182   _gdk_windowing_image_init ();
183   _gdk_events_init ();
184   _gdk_input_init (_gdk_display);
185   _gdk_dnd_init ();
186
187   g_signal_emit_by_name (gdk_display_manager_get (),
188                          "display_opened", _gdk_display);
189
190   return _gdk_display;
191 }
192
193 G_CONST_RETURN gchar *
194 gdk_display_get_name (GdkDisplay *display)
195 {
196   return gdk_get_display_arg_name ();
197 }
198
199 gint
200 gdk_display_get_n_screens (GdkDisplay *display)
201 {
202   return 1;
203 }
204
205 GdkScreen *
206 gdk_display_get_screen (GdkDisplay *display,
207                         gint        screen_num)
208 {
209   return _gdk_screen;
210 }
211
212 GdkScreen *
213 gdk_display_get_default_screen (GdkDisplay *display)
214 {
215   return _gdk_screen;
216 }
217
218 GdkWindow *
219 gdk_display_get_default_group (GdkDisplay *display)
220 {
221   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
222
223   g_warning ("gdk_display_get_default_group not yet implemented");
224
225   return NULL;
226 }
227
228 gboolean 
229 gdk_display_supports_selection_notification (GdkDisplay *display)
230 {
231   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
232
233   return TRUE;
234 }
235
236 static HWND _hwnd_next_viewer = NULL;
237
238 /*
239  * maybe this should be integrated with the default message loop - or maybe not ;-)
240  */
241 static LRESULT CALLBACK
242 _win32_on_clipboard_change (HWND   hwnd,
243                             UINT   message,
244                             WPARAM wparam,
245                             LPARAM lparam)
246 {
247   switch (message)
248     {
249     case WM_DESTROY : /* remove us from chain */
250       {
251         ChangeClipboardChain (hwnd, _hwnd_next_viewer);
252         return 0; 
253       }
254     case WM_CHANGECBCHAIN :
255       {
256         HWND hwndRemove = (HWND) wparam; /* handle of window being removed */
257         HWND hwndNext   = (HWND) lparam; /* handle of next window in chain */
258         if (hwndRemove == _hwnd_next_viewer)
259           _hwnd_next_viewer = hwndNext == hwnd ? NULL : hwndNext;
260         return 0;
261       }
262     case WM_DRAWCLIPBOARD :
263       {
264         /* create the appropriate gdk events */
265         HWND hwndOwner = GetClipboardOwner ();
266         UINT nFormat = 0;
267         int n = 0;
268
269         if (OpenClipboard (hwnd))
270           { 
271             for (; 0 != (nFormat = EnumClipboardFormats (nFormat)); )
272               {
273                 char sFormat[80];
274                 if (GetClipboardFormatName (nFormat, sFormat, 80) > 0)
275                   g_print ("%s ", sFormat);
276                 n++; /* do something useful ? */
277               }
278             GDK_NOTE (DND, 
279                       g_print ("WM_DRAWCLIPBOARD :  formats %d owner %#lx\n", n, hwndOwner));
280
281             CloseClipboard ();
282           }
283         /* XXX: generate the apropriate GdkEventOwnerChange ... */
284
285         /* don't break the chain */
286         return PostMessage (_hwnd_next_viewer, message, wparam, lparam);
287       }
288     default :
289       return DefWindowProc (hwnd, message, wparam, lparam);
290     }
291 }
292
293 /*
294  * Creates a hidden window and adds it to the clipboard chain
295  */
296 HWND
297 _gdk_win32_register_clipboard_notification (void)
298 {
299   WNDCLASS wclass;
300   HWND     hwnd;
301   ATOM     klass;
302
303   memset (&wclass, 0, sizeof(WNDCLASS));
304   wclass.lpszClassName = "GdkClipboardNotification";
305   wclass.lpfnWndProc   = _win32_on_clipboard_change;
306   wclass.hInstance     = _gdk_app_hmodule;
307
308   klass = RegisterClass (&wclass);
309   if (!klass)
310     return NULL;
311
312   hwnd = CreateWindow (MAKEINTRESOURCE(klass),
313                        NULL, WS_POPUP,
314                        0, 0, 0, 0, NULL, NULL,
315                        _gdk_app_hmodule, NULL);
316   if (!hwnd)
317     {
318       UnregisterClass (MAKEINTRESOURCE(klass), _gdk_app_hmodule);
319       return NULL;
320     }
321   _hwnd_next_viewer = SetClipboardViewer (hwnd);
322   return hwnd;
323 }
324
325 /*
326  * The whole function would only make sense if the gdk/win32 clipboard
327  * model is rewritten to do delayed rendering. Currently this is only
328  * testcode and as noted in
329  * http://mail.gnome.org/archives/gtk-devel-list/2004-May/msg00113.html
330  * probably not worth bothering ;)
331  */
332 gboolean 
333 gdk_display_request_selection_notification (GdkDisplay *display,
334                                             GdkAtom     selection)
335
336 {
337   static HWND hwndViewer = NULL;
338   gboolean ret = FALSE;
339
340   GDK_NOTE (DND, 
341             g_print ("gdk_display_request_selection_notification (..., %s)",
342                      gdk_atom_name (selection)));
343
344   if (GDK_SELECTION_CLIPBOARD == selection)
345     {
346       if (!hwndViewer)
347         {
348           hwndViewer = _gdk_win32_register_clipboard_notification ();
349           GDK_NOTE (DND, g_print (" registered"));
350         }
351       ret = (hwndViewer != NULL);
352     }
353   else if (GDK_SELECTION_PRIMARY == selection)
354     {
355       /* seems to work by default ? */
356       GDK_NOTE (DND, g_print (" by default"));
357       ret = TRUE;
358     }
359   GDK_NOTE (DND, g_print (" -> %s\n", ret ? "TRUE" : "FALSE"));
360   return ret;
361 }