]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkwindow-win32.c
win32: Ignore client requested window move/size during SIZEMOVE
[~andy/gtk] / gdk / win32 / gdkwindow-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2004 Tor Lillqvist
4  * Copyright (C) 2001-2011 Hans Breuer
5  * Copyright (C) 2007-2009 Cody Russell
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 #include "config.h"
31 #include <stdlib.h>
32
33 #include "gdk.h"
34 #include "gdkwindowimpl.h"
35 #include "gdkprivate-win32.h"
36 #include "gdkdeviceprivate.h"
37 #include "gdkdevicemanager-win32.h"
38 #include "gdkenumtypes.h"
39 #include "gdkwin32.h"
40 #include "gdkdisplayprivate.h"
41 #include "gdkvisualprivate.h"
42 #include "gdkwin32window.h"
43
44 #include <cairo-win32.h>
45
46 static void gdk_window_impl_win32_init       (GdkWindowImplWin32      *window);
47 static void gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass);
48 static void gdk_window_impl_win32_finalize   (GObject                 *object);
49
50 static gpointer parent_class = NULL;
51 static GSList *modal_window_stack = NULL;
52
53 static const cairo_user_data_key_t gdk_win32_cairo_key;
54
55 static void     update_style_bits         (GdkWindow         *window);
56 static gboolean _gdk_window_get_functions (GdkWindow         *window,
57                                            GdkWMFunction     *functions);
58
59 #define WINDOW_IS_TOPLEVEL(window)                 \
60   (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
61    GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
62    GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
63
64 GdkScreen *
65 GDK_WINDOW_SCREEN (GObject *win)
66 {
67   return _gdk_screen;
68 }
69
70 struct _GdkWin32Window {
71   GdkWindow parent;
72 };
73
74 struct _GdkWin32WindowClass {
75   GdkWindowClass parent_class;
76 };
77
78 G_DEFINE_TYPE (GdkWin32Window, gdk_win32_window, GDK_TYPE_WINDOW)
79
80 static void
81 gdk_win32_window_class_init (GdkWin32WindowClass *window_class)
82 {
83 }
84
85 static void
86 gdk_win32_window_init (GdkWin32Window *window)
87 {
88 }
89
90
91 G_DEFINE_TYPE (GdkWindowImplWin32, gdk_window_impl_win32, GDK_TYPE_WINDOW_IMPL)
92
93 GType
94 _gdk_window_impl_win32_get_type (void)
95 {
96   static GType object_type = 0;
97
98   if (!object_type)
99     {
100       const GTypeInfo object_info =
101       {
102         sizeof (GdkWindowImplWin32Class),
103         (GBaseInitFunc) NULL,
104         (GBaseFinalizeFunc) NULL,
105         (GClassInitFunc) gdk_window_impl_win32_class_init,
106         NULL,           /* class_finalize */
107         NULL,           /* class_data */
108         sizeof (GdkWindowImplWin32),
109         0,              /* n_preallocs */
110         (GInstanceInitFunc) gdk_window_impl_win32_init,
111       };
112
113       object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL,
114                                             "GdkWindowImplWin32",
115                                             &object_info, 0);
116     }
117   
118   return object_type;
119 }
120
121 static void
122 gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
123 {
124   impl->toplevel_window_type = -1;
125   impl->hcursor = NULL;
126   impl->hicon_big = NULL;
127   impl->hicon_small = NULL;
128   impl->hint_flags = 0;
129   impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
130   impl->extension_events_selected = FALSE;
131   impl->transient_owner = NULL;
132   impl->transient_children = NULL;
133   impl->num_transients = 0;
134   impl->changing_state = FALSE;
135 }
136
137 static void
138 gdk_window_impl_win32_finalize (GObject *object)
139 {
140   GdkWindow *wrapper;
141   GdkWindowImplWin32 *window_impl;
142   
143   g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (object));
144
145   window_impl = GDK_WINDOW_IMPL_WIN32 (object);
146   
147   wrapper = window_impl->wrapper;
148
149   if (!GDK_WINDOW_DESTROYED (wrapper))
150     {
151       gdk_win32_handle_table_remove (window_impl->handle);
152     }
153
154   if (window_impl->hcursor != NULL)
155     {
156       if (GetCursor () == window_impl->hcursor)
157         SetCursor (NULL);
158
159       GDI_CALL (DestroyCursor, (window_impl->hcursor));
160       window_impl->hcursor = NULL;
161     }
162
163   if (window_impl->hicon_big != NULL)
164     {
165       GDI_CALL (DestroyIcon, (window_impl->hicon_big));
166       window_impl->hicon_big = NULL;
167     }
168
169   if (window_impl->hicon_small != NULL)
170     {
171       GDI_CALL (DestroyIcon, (window_impl->hicon_small));
172       window_impl->hicon_small = NULL;
173     }
174
175   G_OBJECT_CLASS (parent_class)->finalize (object);
176 }
177
178 void
179 _gdk_win32_adjust_client_rect (GdkWindow *window,
180                                RECT      *rect)
181 {
182   LONG style, exstyle;
183
184   style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
185   exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
186   API_CALL (AdjustWindowRectEx, (rect, style, FALSE, exstyle));
187 }
188
189 void
190 _gdk_root_window_size_init (void)
191 {
192   GdkWindow *window;
193   GdkRectangle rect;
194   int i;
195
196   window = GDK_WINDOW (_gdk_root);
197   rect = _gdk_monitors[0].rect;
198   for (i = 1; i < _gdk_num_monitors; i++)
199     gdk_rectangle_union (&rect, &_gdk_monitors[i].rect, &rect);
200
201   window->width = rect.width;
202   window->height = rect.height;
203 }
204
205 void
206 _gdk_windowing_window_init (GdkScreen *screen)
207 {
208   GdkWindow *window;
209   GdkWindowImplWin32 *impl_win32;
210
211   g_assert (_gdk_root == NULL);
212   
213   _gdk_root = _gdk_display_create_window (_gdk_display);
214
215   window = (GdkWindow *)_gdk_root;
216   window->impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WIN32, NULL);
217   impl_win32 = GDK_WINDOW_IMPL_WIN32 (window->impl);
218   impl_win32->wrapper = window;
219
220   window->impl_window = window;
221   window->visual = gdk_screen_get_system_visual (screen);
222
223   window->window_type = GDK_WINDOW_ROOT;
224   window->depth = gdk_visual_get_system ()->depth;
225
226   _gdk_root_window_size_init ();
227
228   window->x = 0;
229   window->y = 0;
230   window->abs_x = 0;
231   window->abs_y = 0;
232   /* width and height already initialised in _gdk_root_window_size_init() */
233   window->viewable = TRUE;
234
235   gdk_win32_handle_table_insert ((HANDLE *) &impl_win32->handle, _gdk_root);
236
237   GDK_NOTE (MISC, g_print ("_gdk_root=%p\n", GDK_WINDOW_HWND (_gdk_root)));
238 }
239
240 static const gchar *
241 get_default_title (void)
242 {
243   const char *title;
244   title = g_get_application_name ();
245   if (!title)
246     title = g_get_prgname ();
247
248   return title;
249 }
250
251 /* RegisterGdkClass
252  *   is a wrapper function for RegisterWindowClassEx.
253  *   It creates at least one unique class for every 
254  *   GdkWindowType. If support for single window-specific icons
255  *   is ever needed (e.g Dialog specific), every such window should
256  *   get its own class
257  */
258 static ATOM
259 RegisterGdkClass (GdkWindowType wtype, GdkWindowTypeHint wtype_hint)
260 {
261   static ATOM klassTOPLEVEL   = 0;
262   static ATOM klassCHILD      = 0;
263   static ATOM klassTEMP       = 0;
264   static ATOM klassTEMPSHADOW = 0;
265   static HICON hAppIcon = NULL;
266   static HICON hAppIconSm = NULL;
267   static WNDCLASSEXW wcl; 
268   ATOM klass = 0;
269
270   wcl.cbSize = sizeof (WNDCLASSEX);
271   wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
272                   * on WM_SIZE and WM_MOVE. Flicker, Performance!
273                   */
274   wcl.lpfnWndProc = _gdk_win32_window_procedure;
275   wcl.cbClsExtra = 0;
276   wcl.cbWndExtra = 0;
277   wcl.hInstance = _gdk_app_hmodule;
278   wcl.hIcon = 0;
279   wcl.hIconSm = 0;
280
281   /* initialize once! */
282   if (0 == hAppIcon && 0 == hAppIconSm)
283     {
284       gchar sLoc [MAX_PATH+1];
285
286       if (0 != GetModuleFileName (_gdk_app_hmodule, sLoc, MAX_PATH))
287         {
288           ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
289
290           if (0 == hAppIcon && 0 == hAppIconSm)
291             {
292               if (0 != GetModuleFileName (_gdk_dll_hinstance, sLoc, MAX_PATH))
293                 {
294                   ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
295                 }
296             }
297         }
298
299       if (0 == hAppIcon && 0 == hAppIconSm)
300         {
301           hAppIcon = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
302                                 GetSystemMetrics (SM_CXICON),
303                                 GetSystemMetrics (SM_CYICON), 0);
304           hAppIconSm = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
305                                   GetSystemMetrics (SM_CXSMICON),
306                                   GetSystemMetrics (SM_CYSMICON), 0);
307         }
308     }
309
310   if (0 == hAppIcon)
311     hAppIcon = hAppIconSm;
312   else if (0 == hAppIconSm)
313     hAppIconSm = hAppIcon;
314
315   wcl.lpszMenuName = NULL;
316
317   /* initialize once per class */
318   /*
319    * HB: Setting the background brush leads to flicker, because we
320    * don't get asked how to clear the background. This is not what
321    * we want, at least not for input_only windows ...
322    */
323 #define ONCE_PER_CLASS() \
324   wcl.hIcon = CopyIcon (hAppIcon); \
325   wcl.hIconSm = CopyIcon (hAppIconSm); \
326   wcl.hbrBackground = NULL; \
327   wcl.hCursor = LoadCursor (NULL, IDC_ARROW); 
328   
329   switch (wtype)
330     {
331     case GDK_WINDOW_TOPLEVEL:
332       if (0 == klassTOPLEVEL)
333         {
334           wcl.lpszClassName = L"gdkWindowToplevel";
335           
336           ONCE_PER_CLASS ();
337           klassTOPLEVEL = RegisterClassExW (&wcl);
338         }
339       klass = klassTOPLEVEL;
340       break;
341       
342     case GDK_WINDOW_CHILD:
343       if (0 == klassCHILD)
344         {
345           wcl.lpszClassName = L"gdkWindowChild";
346           
347           wcl.style |= CS_PARENTDC; /* MSDN: ... enhances system performance. */
348           ONCE_PER_CLASS ();
349           klassCHILD = RegisterClassExW (&wcl);
350         }
351       klass = klassCHILD;
352       break;
353       
354     case GDK_WINDOW_TEMP:
355       if ((wtype_hint == GDK_WINDOW_TYPE_HINT_MENU) ||
356           (wtype_hint == GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU) ||
357           (wtype_hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU) ||
358           (wtype_hint == GDK_WINDOW_TYPE_HINT_TOOLTIP))
359         {
360           if (klassTEMPSHADOW == 0)
361             {
362               wcl.lpszClassName = L"gdkWindowTempShadow";
363               wcl.style |= CS_SAVEBITS;
364               if (LOBYTE (g_win32_get_windows_version()) > 0x05 ||
365                   LOWORD (g_win32_get_windows_version()) == 0x0105)
366                 {
367                   /* Windows XP (5.1) or above */
368                   wcl.style |= 0x00020000; /* CS_DROPSHADOW */
369                 }
370               ONCE_PER_CLASS ();
371               klassTEMPSHADOW = RegisterClassExW (&wcl);
372             }
373
374           klass = klassTEMPSHADOW;
375         }
376        else
377         {
378           if (klassTEMP == 0)
379             {
380               wcl.lpszClassName = L"gdkWindowTemp";
381               wcl.style |= CS_SAVEBITS;
382               ONCE_PER_CLASS ();
383               klassTEMP = RegisterClassExW (&wcl);
384             }
385
386           klass = klassTEMP;
387         }
388       break;
389       
390     default:
391       g_assert_not_reached ();
392       break;
393     }
394   
395   if (klass == 0)
396     {
397       WIN32_API_FAILED ("RegisterClassExW");
398       g_error ("That is a fatal error");
399     }
400   return klass;
401 }
402
403 /*
404  * Create native windows.
405  *
406  * With the default Gdk the created windows are mostly toplevel windows.
407  *
408  * Placement of the window is derived from the passed in window,
409  * except for toplevel window where OS/Window Manager placement
410  * is used.
411  *
412  * The visual parameter, is based on GDK_WA_VISUAL if set already.
413  * From attributes the only things used is: colormap, title, 
414  * wmclass and type_hint. [1]. We are checking redundant information
415  * and complain if that changes, which would break this implementation
416  * again.
417  *
418  * [1] http://mail.gnome.org/archives/gtk-devel-list/2010-August/msg00214.html
419  */
420 void
421 _gdk_win32_display_create_window_impl (GdkDisplay    *display,
422                                        GdkWindow     *window,
423                                        GdkWindow     *real_parent,
424                                        GdkScreen     *screen,
425                                        GdkEventMask   event_mask,
426                                        GdkWindowAttr *attributes,
427                                        gint           attributes_mask)
428 {
429   HWND hwndNew;
430   HANDLE hparent;
431   ATOM klass = 0;
432   DWORD dwStyle = 0, dwExStyle;
433   RECT rect;
434   GdkWindowImplWin32 *impl;
435   const gchar *title;
436   wchar_t *wtitle;
437   gint window_width, window_height;
438   gint offset_x = 0, offset_y = 0;
439   gint x, y;
440   /* check consistency of redundant information */
441   guint remaining_mask = attributes_mask;
442
443   GDK_NOTE (MISC,
444             g_print ("_gdk_window_impl_new: %s %s\n",
445                      (window->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" :
446                       (window->window_type == GDK_WINDOW_CHILD ? "CHILD" :
447                        (window->window_type == GDK_WINDOW_TEMP ? "TEMP" :
448                         "???"))),
449                      (attributes->wclass == GDK_INPUT_OUTPUT ? "" : "input-only"))
450                            );
451
452   /* to ensure to not miss important information some additional check against
453    * attributes which may silently work on X11 */
454   if ((attributes_mask & GDK_WA_X) != 0)
455     {
456       g_assert (attributes->x == window->x);
457       remaining_mask &= ~GDK_WA_X;
458     }
459   if ((attributes_mask & GDK_WA_Y) != 0)
460     {
461       g_assert (attributes->y == window->y);
462       remaining_mask &= ~GDK_WA_Y;
463     }
464   if ((attributes_mask & GDK_WA_NOREDIR) != 0)
465     remaining_mask &= ~GDK_WA_NOREDIR;
466
467   if ((remaining_mask & ~(GDK_WA_WMCLASS|GDK_WA_VISUAL|GDK_WA_CURSOR|GDK_WA_TITLE|GDK_WA_TYPE_HINT)) != 0)
468     g_warning ("_gdk_window_impl_new: uexpected attribute 0x%X",
469                remaining_mask & ~(GDK_WA_WMCLASS|GDK_WA_VISUAL|GDK_WA_CURSOR|GDK_WA_TITLE|GDK_WA_TYPE_HINT));
470
471   hparent = GDK_WINDOW_HWND (real_parent);
472
473   impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WIN32, NULL);
474   impl->wrapper = GDK_WINDOW (window);
475   window->impl = GDK_WINDOW_IMPL (impl);
476
477   if (attributes_mask & GDK_WA_VISUAL)
478     g_assert (gdk_screen_get_system_visual (screen) == attributes->visual);
479
480   impl->extension_events_selected = FALSE;
481
482   /* wclass is not any longer set always, but if is ... */
483   if ((attributes_mask & GDK_WA_WMCLASS) == GDK_WA_WMCLASS)
484     g_assert ((attributes->wclass == GDK_INPUT_OUTPUT) == !window->input_only);
485
486   if (!window->input_only)
487     {
488       dwExStyle = 0;
489     }
490   else
491     {
492       /* I very much doubt using WS_EX_TRANSPARENT actually
493        * corresponds to how X11 InputOnly windows work, but it appears
494        * to work well enough for the actual use cases in gtk.
495        */
496       dwExStyle = WS_EX_TRANSPARENT;
497       GDK_NOTE (MISC, g_print ("... GDK_INPUT_ONLY\n"));
498     }
499
500   switch (window->window_type)
501     {
502     case GDK_WINDOW_TOPLEVEL:
503       if (GDK_WINDOW_TYPE (window->parent) != GDK_WINDOW_ROOT)
504         {
505           /* The common code warns for this case. */
506           hparent = GetDesktopWindow ();
507         }
508       /* Children of foreign windows aren't toplevel windows */
509       if (GDK_WINDOW_TYPE (real_parent) == GDK_WINDOW_FOREIGN)
510         {
511           dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN;
512         }
513       else
514         {
515           if (window->window_type == GDK_WINDOW_TOPLEVEL)
516             dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
517           else
518             dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN;
519
520           offset_x = _gdk_offset_x;
521           offset_y = _gdk_offset_y;
522         }
523       break;
524
525     case GDK_WINDOW_CHILD:
526       dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
527       break;
528
529     case GDK_WINDOW_TEMP:
530       /* A temp window is not necessarily a top level window */
531       dwStyle = (_gdk_root == real_parent ? WS_POPUP : WS_CHILDWINDOW);
532       dwStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
533       dwExStyle |= WS_EX_TOOLWINDOW;
534       offset_x = _gdk_offset_x;
535       offset_y = _gdk_offset_y;
536       break;
537
538     default:
539       g_assert_not_reached ();
540     }
541
542   if (window->window_type != GDK_WINDOW_CHILD)
543     {
544       rect.left = window->x;
545       rect.top = window->y;
546       rect.right = window->width;
547       rect.bottom = window->height;
548
549       AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
550
551       /* non child windows are placed by the OS/window manager */
552       x = y = CW_USEDEFAULT;
553
554       window_width = rect.right - rect.left;
555       window_height = rect.bottom - rect.top;
556     }
557   else
558     {
559       /* adjust position relative to real_parent */
560       window_width = window->width;
561       window_height = window->height;
562       /* use given position for initial placement, native coordinates */
563       x = window->x + window->parent->abs_x - offset_x;
564       y = window->y + window->parent->abs_y - offset_y;
565     }
566
567   if (attributes_mask & GDK_WA_TITLE)
568     title = attributes->title;
569   else
570     title = get_default_title ();
571   if (!title || !*title)
572     title = "";
573
574   impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
575       
576   if (attributes_mask & GDK_WA_TYPE_HINT)
577     gdk_window_set_type_hint (window, attributes->type_hint);
578
579   if (impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY)
580     dwExStyle |= WS_EX_TOOLWINDOW;
581
582   klass = RegisterGdkClass (window->window_type, impl->type_hint);
583
584   wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
585   
586   hwndNew = CreateWindowExW (dwExStyle,
587                              MAKEINTRESOURCEW (klass),
588                              wtitle,
589                              dwStyle,
590                              x,
591                              y,
592                              window_width, window_height,
593                              hparent,
594                              NULL,
595                              _gdk_app_hmodule,
596                              window);
597   if (GDK_WINDOW_HWND (window) != hwndNew)
598     {
599       g_warning ("gdk_window_new: gdk_event_translate::WM_CREATE (%p, %p) HWND mismatch.",
600                  GDK_WINDOW_HWND (window),
601                  hwndNew);
602
603       /* HB: IHMO due to a race condition the handle was increased by
604        * one, which causes much trouble. Because I can't find the 
605        * real bug, try to workaround it ...
606        * To reproduce: compile with MSVC 5, DEBUG=1
607        */
608 # if 0
609       gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
610       GDK_WINDOW_HWND (window) = hwndNew;
611       gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
612 # else
613       /* the old behaviour, but with warning */
614       impl->handle = hwndNew;
615 # endif
616
617     }
618
619   g_object_ref (window);
620   gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
621
622   GDK_NOTE (MISC, g_print ("... \"%s\" %dx%d@%+d%+d %p = %p\n",
623                            title,
624                            window_width, window_height,
625                            window->x - offset_x,
626                            window->y - offset_y, 
627                            hparent,
628                            GDK_WINDOW_HWND (window)));
629
630   /* Add window handle to title */
631   GDK_NOTE (MISC_OR_EVENTS, gdk_window_set_title (window, title));
632
633   g_free (wtitle);
634
635   if (impl->handle == NULL)
636     {
637       WIN32_API_FAILED ("CreateWindowExW");
638       g_object_unref (window);
639       return;
640     }
641
642 //  if (!from_set_skip_taskbar_hint && window->window_type == GDK_WINDOW_TEMP)
643 //    gdk_window_set_skip_taskbar_hint (window, TRUE);
644
645   if (attributes_mask & GDK_WA_CURSOR)
646     gdk_window_set_cursor (window, attributes->cursor);
647 }
648
649 GdkWindow *
650 gdk_win32_window_foreign_new_for_display (GdkDisplay      *display,
651                                           HWND             anid)
652 {
653   GdkWindow *window;
654   GdkWindowImplWin32 *impl;
655
656   HANDLE parent;
657   RECT rect;
658   POINT point;
659
660   g_return_val_if_fail (display == _gdk_display, NULL);
661
662   if ((window = gdk_win32_window_lookup_for_display (display, anid)) != NULL)
663     return g_object_ref (window);
664
665   window = _gdk_display_create_window (display);
666   window->visual = gdk_screen_get_system_visual (_gdk_screen);
667   window->impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WIN32, NULL);
668   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
669   impl->wrapper = window;
670   parent = GetParent (anid);
671   
672   window->parent = gdk_win32_handle_table_lookup (parent);
673   if (!window->parent || GDK_WINDOW_TYPE (window->parent) == GDK_WINDOW_FOREIGN)
674     window->parent = _gdk_root;
675   
676   window->parent->children = g_list_prepend (window->parent->children, window);
677
678   GetClientRect ((HWND) anid, &rect);
679   point.x = rect.left;
680   point.y = rect.right;
681   ClientToScreen ((HWND) anid, &point);
682   if (parent != GetDesktopWindow ())
683     ScreenToClient (parent, &point);
684   window->x = point.x;
685   window->y = point.y;
686   window->width = rect.right - rect.left;
687   window->height = rect.bottom - rect.top;
688   window->window_type = GDK_WINDOW_FOREIGN;
689   window->destroyed = FALSE;
690   window->event_mask = GDK_ALL_EVENTS_MASK; /* XXX */
691   if (IsWindowVisible ((HWND) anid))
692     window->state &= (~GDK_WINDOW_STATE_WITHDRAWN);
693   else
694     window->state |= GDK_WINDOW_STATE_WITHDRAWN;
695   if (GetWindowLong ((HWND)anid, GWL_EXSTYLE) & WS_EX_TOPMOST)
696     window->state |= GDK_WINDOW_STATE_ABOVE;
697   else
698     window->state &= (~GDK_WINDOW_STATE_ABOVE);
699   window->state &= (~GDK_WINDOW_STATE_BELOW);
700   window->viewable = TRUE;
701
702   window->depth = gdk_visual_get_system ()->depth;
703
704   g_object_ref (window);
705   gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
706
707   GDK_NOTE (MISC, g_print ("gdk_win32_window_foreign_new_for_display: %p: %s@%+d%+d\n",
708                            (HWND) anid,
709                            _gdk_win32_window_description (window),
710                            window->x, window->y));
711
712   return window;
713 }
714
715 static void
716 gdk_win32_window_destroy (GdkWindow *window,
717                           gboolean   recursing,
718                           gboolean   foreign_destroy)
719 {
720   GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
721   GSList *tmp;
722
723   g_return_if_fail (GDK_IS_WINDOW (window));
724   
725   GDK_NOTE (MISC, g_print ("gdk_win32_window_destroy: %p\n",
726                            GDK_WINDOW_HWND (window)));
727
728   /* Remove ourself from the modal stack */
729   _gdk_remove_modal_window (window);
730
731   /* Remove all our transient children */
732   tmp = window_impl->transient_children;
733   while (tmp != NULL)
734     {
735       GdkWindow *child = tmp->data;
736       GdkWindowImplWin32 *child_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW (child)->impl);
737
738       child_impl->transient_owner = NULL;
739       tmp = g_slist_next (tmp);
740     }
741   g_slist_free (window_impl->transient_children);
742   window_impl->transient_children = NULL;
743
744   /* Remove ourself from our transient owner */
745   if (window_impl->transient_owner != NULL)
746     {
747       gdk_window_set_transient_for (window, NULL);
748     }
749
750   if (!recursing && !foreign_destroy)
751     {
752       window->destroyed = TRUE;
753       DestroyWindow (GDK_WINDOW_HWND (window));
754     }
755
756   gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
757 }
758
759 static cairo_surface_t *
760 gdk_win32_window_resize_cairo_surface (GdkWindow       *window,
761                                        cairo_surface_t *surface,
762                                        gint             width,
763                                        gint             height)
764 {
765   /* XXX: Make Cairo surface use DC clip */
766   cairo_surface_destroy (surface);
767
768   return NULL;
769 }
770
771 static void
772 gdk_win32_window_destroy_foreign (GdkWindow *window)
773 {
774   /* It's somebody else's window, but in our hierarchy, so reparent it
775    * to the desktop, and then try to destroy it.
776    */
777   gdk_window_hide (window);
778   gdk_window_reparent (window, NULL, 0, 0);
779   
780   PostMessage (GDK_WINDOW_HWND (window), WM_CLOSE, 0, 0);
781 }
782
783 /* This function is called when the window really gone.
784  */
785 static void
786 gdk_win32_window_destroy_notify (GdkWindow *window)
787 {
788   g_return_if_fail (GDK_IS_WINDOW (window));
789
790   GDK_NOTE (EVENTS,
791             g_print ("gdk_window_destroy_notify: %p%s\n",
792                      GDK_WINDOW_HWND (window),
793                      (GDK_WINDOW_DESTROYED (window) ? " (destroyed)" : "")));
794
795   if (!GDK_WINDOW_DESTROYED (window))
796     {
797       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
798         g_warning ("window %p unexpectedly destroyed",
799                    GDK_WINDOW_HWND (window));
800
801       _gdk_window_destroy (window, TRUE);
802     }
803   
804   gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
805   g_object_unref (window);
806 }
807
808 static void
809 get_outer_rect (GdkWindow *window,
810                 gint       width,
811                 gint       height,
812                 RECT      *rect)
813 {
814   rect->left = rect->top = 0;
815   rect->right = width;
816   rect->bottom = height;
817       
818   _gdk_win32_adjust_client_rect (window, rect);
819 }
820
821 static void
822 adjust_for_gravity_hints (GdkWindow *window,
823                           RECT      *outer_rect,
824                           gint          *x,
825                           gint          *y)
826 {
827   GdkWindowImplWin32 *impl;
828
829   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
830
831   if (impl->hint_flags & GDK_HINT_WIN_GRAVITY)
832     {
833       gint orig_x = *x, orig_y = *y;
834
835       switch (impl->hints.win_gravity)
836         {
837         case GDK_GRAVITY_NORTH:
838         case GDK_GRAVITY_CENTER:
839         case GDK_GRAVITY_SOUTH:
840           *x -= (outer_rect->right - outer_rect->left) / 2;
841           *x += window->width / 2;
842           break;
843               
844         case GDK_GRAVITY_SOUTH_EAST:
845         case GDK_GRAVITY_EAST:
846         case GDK_GRAVITY_NORTH_EAST:
847           *x -= outer_rect->right - outer_rect->left;
848           *x += window->width;
849           break;
850
851         case GDK_GRAVITY_STATIC:
852           *x += outer_rect->left;
853           break;
854
855         default:
856           break;
857         }
858
859       switch (impl->hints.win_gravity)
860         {
861         case GDK_GRAVITY_WEST:
862         case GDK_GRAVITY_CENTER:
863         case GDK_GRAVITY_EAST:
864           *y -= (outer_rect->bottom - outer_rect->top) / 2;
865           *y += window->height / 2;
866           break;
867
868         case GDK_GRAVITY_SOUTH_WEST:
869         case GDK_GRAVITY_SOUTH:
870         case GDK_GRAVITY_SOUTH_EAST:
871           *y -= outer_rect->bottom - outer_rect->top;
872           *y += window->height;
873           break;
874
875         case GDK_GRAVITY_STATIC:
876           *y += outer_rect->top;
877           break;
878
879         default:
880           break;
881         }
882       GDK_NOTE (MISC,
883                 (orig_x != *x || orig_y != *y) ?
884                 g_print ("adjust_for_gravity_hints: x: %d->%d, y: %d->%d\n",
885                          orig_x, *x, orig_y, *y)
886                   : (void) 0);
887     }
888 }
889
890 static void
891 show_window_internal (GdkWindow *window,
892                       gboolean   already_mapped,
893                       gboolean   deiconify)
894 {
895   HWND old_active_window;
896   gboolean focus_on_map = FALSE;
897   DWORD exstyle;
898   HWND top;
899
900   if (window->destroyed)
901     return;
902
903   GDK_NOTE (MISC, g_print ("show_window_internal: %p: %s%s\n",
904                            GDK_WINDOW_HWND (window),
905                            _gdk_win32_window_state_to_string (window->state),
906                            (deiconify ? " deiconify" : "")));
907   
908   /* If asked to show (not deiconify) an withdrawn and iconified
909    * window, do that.
910    */
911   if (!deiconify &&
912       !already_mapped &&
913       (window->state & GDK_WINDOW_STATE_ICONIFIED))
914     {   
915       ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMINNOACTIVE);
916       return;
917     }
918   
919   /* If asked to just show an iconified window, do nothing. */
920   if (!deiconify && (window->state & GDK_WINDOW_STATE_ICONIFIED))
921     return;
922   
923   /* If asked to deiconify an already noniconified window, do
924    * nothing. (Especially, don't cause the window to rise and
925    * activate. There are different calls for that.)
926    */
927   if (deiconify && !(window->state & GDK_WINDOW_STATE_ICONIFIED))
928     return;
929   
930   /* If asked to show (but not raise) a window that is already
931    * visible, do nothing.
932    */
933   if (!deiconify && !already_mapped && IsWindowVisible (GDK_WINDOW_HWND (window)))
934     return;
935
936   /* Other cases */
937   
938   if (!already_mapped)
939     focus_on_map = window->focus_on_map;
940
941   exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
942
943   if (window->state & GDK_WINDOW_STATE_BELOW)
944     exstyle &= (~WS_EX_TOPMOST);
945
946   if (window->state & GDK_WINDOW_STATE_ABOVE)
947     exstyle |= WS_EX_TOPMOST;
948
949   if (exstyle & WS_EX_TOPMOST)
950     top = HWND_TOPMOST;
951   else
952     top = HWND_TOP;
953
954   /* Use SetWindowPos to show transparent windows so automatic redraws
955    * in other windows can be suppressed.
956    */
957   if (exstyle & WS_EX_TRANSPARENT)
958     {
959       UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
960
961       if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP || !focus_on_map)
962         flags |= SWP_NOACTIVATE;
963
964       SetWindowPos (GDK_WINDOW_HWND (window), top, 0, 0, 0, 0, flags);
965
966       return;
967     }
968
969   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
970     {
971       gdk_window_fullscreen (window);
972     }
973   else if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
974     {
975       ShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
976     }
977   else if (window->state & GDK_WINDOW_STATE_ICONIFIED)
978     {
979       if (focus_on_map)
980         ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
981       else
982         ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNOACTIVATE);
983     }
984   else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP || !focus_on_map)
985     {
986       ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNOACTIVATE);
987     }
988   else
989     {
990       ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNORMAL);
991     }
992 }
993
994 static void
995 gdk_win32_window_show (GdkWindow *window, 
996                        gboolean already_mapped)
997 {
998   show_window_internal (window, FALSE, FALSE);
999 }
1000
1001 static void
1002 gdk_win32_window_hide (GdkWindow *window)
1003 {
1004   if (window->destroyed)
1005     return;
1006
1007   GDK_NOTE (MISC, g_print ("gdk_win32_window_hide: %p: %s\n",
1008                            GDK_WINDOW_HWND (window),
1009                            _gdk_win32_window_state_to_string (window->state)));
1010   
1011   if (GDK_WINDOW_IS_MAPPED (window))
1012     gdk_synthesize_window_state (window,
1013                                  0,
1014                                  GDK_WINDOW_STATE_WITHDRAWN);
1015   
1016   _gdk_window_clear_update_area (window);
1017   
1018   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL)
1019     ShowOwnedPopups (GDK_WINDOW_HWND (window), FALSE);
1020   
1021   if (GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT)
1022     {
1023       SetWindowPos (GDK_WINDOW_HWND (window), HWND_BOTTOM,
1024                     0, 0, 0, 0,
1025                     SWP_HIDEWINDOW | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
1026     }
1027   else
1028     {
1029       ShowWindow (GDK_WINDOW_HWND (window), SW_HIDE);
1030     }
1031 }
1032
1033 static void
1034 gdk_win32_window_withdraw (GdkWindow *window)
1035 {
1036   if (window->destroyed)
1037     return;
1038
1039   GDK_NOTE (MISC, g_print ("gdk_win32_window_withdraw: %p: %s\n",
1040                            GDK_WINDOW_HWND (window),
1041                            _gdk_win32_window_state_to_string (window->state)));
1042
1043   gdk_window_hide (window);     /* ??? */
1044 }
1045
1046 static void
1047 gdk_win32_window_move (GdkWindow *window,
1048                        gint x, gint y)
1049 {
1050   GdkWindowImplWin32 *impl;
1051
1052   g_return_if_fail (GDK_IS_WINDOW (window));
1053
1054   if (GDK_WINDOW_DESTROYED (window))
1055     return;
1056
1057   GDK_NOTE (MISC, g_print ("gdk_win32_window_move: %p: %+d%+d\n",
1058                            GDK_WINDOW_HWND (window), x, y));
1059
1060   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1061
1062   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1063     return;
1064
1065   /* Don't check GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD.
1066    * Foreign windows (another app's windows) might be children of our
1067    * windows! Especially in the case of gtkplug/socket.
1068    */
1069   if (GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) != GetDesktopWindow ())
1070     {
1071       _gdk_window_move_resize_child (window, x, y, window->width, window->height);
1072     }
1073   else
1074     {
1075       RECT outer_rect;
1076
1077       get_outer_rect (window, window->width, window->height, &outer_rect);
1078
1079       adjust_for_gravity_hints (window, &outer_rect, &x, &y);
1080
1081       GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,0,0,"
1082                                "NOACTIVATE|NOSIZE|NOZORDER)\n",
1083                                GDK_WINDOW_HWND (window),
1084                                x - _gdk_offset_x, y - _gdk_offset_y));
1085
1086       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
1087                                x - _gdk_offset_x, y - _gdk_offset_y, 0, 0,
1088                                SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
1089     }
1090 }
1091
1092 static void
1093 gdk_win32_window_resize (GdkWindow *window,
1094                          gint width, gint height)
1095 {
1096   GdkWindowImplWin32 *impl;
1097
1098   g_return_if_fail (GDK_IS_WINDOW (window));
1099
1100   if (GDK_WINDOW_DESTROYED (window))
1101     return;
1102
1103   if (width < 1)
1104     width = 1;
1105   if (height < 1)
1106     height = 1;
1107
1108   GDK_NOTE (MISC, g_print ("gdk_win32_window_resize: %p: %dx%d\n",
1109                            GDK_WINDOW_HWND (window), width, height));
1110
1111   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1112
1113   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1114     return;
1115
1116   if (GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) != GetDesktopWindow ())
1117     {
1118       _gdk_window_move_resize_child (window, window->x, window->y, width, height);
1119     }
1120   else
1121     {
1122       RECT outer_rect;
1123
1124       get_outer_rect (window, width, height, &outer_rect);
1125
1126       GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,0,0,%ld,%ld,"
1127                                "NOACTIVATE|NOMOVE|NOZORDER)\n",
1128                                GDK_WINDOW_HWND (window),
1129                                outer_rect.right - outer_rect.left,
1130                                outer_rect.bottom - outer_rect.top));
1131
1132       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
1133                                0, 0,
1134                                outer_rect.right - outer_rect.left,
1135                                outer_rect.bottom - outer_rect.top,
1136                                SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER));
1137       window->resize_count += 1;
1138     }
1139 }
1140
1141 static void
1142 gdk_win32_window_move_resize_internal (GdkWindow *window,
1143                                        gint       x,
1144                                        gint       y,
1145                                        gint       width,
1146                                        gint       height)
1147 {
1148   GdkWindowImplWin32 *impl;
1149
1150   g_return_if_fail (GDK_IS_WINDOW (window));
1151
1152   if (GDK_WINDOW_DESTROYED (window))
1153     return;
1154
1155   if (width < 1)
1156     width = 1;
1157   if (height < 1)
1158     height = 1;
1159
1160   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1161
1162   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1163     return;
1164
1165   GDK_NOTE (MISC, g_print ("gdk_win32_window_move_resize: %p: %dx%d@%+d%+d\n",
1166                            GDK_WINDOW_HWND (window),
1167                            width, height, x, y));
1168
1169   if (GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) != GetDesktopWindow ())
1170     {
1171       _gdk_window_move_resize_child (window, x, y, width, height);
1172     }
1173   else
1174     {
1175       RECT outer_rect;
1176
1177       get_outer_rect (window, width, height, &outer_rect);
1178
1179       adjust_for_gravity_hints (window, &outer_rect, &x, &y);
1180
1181       GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%ld,%ld,"
1182                                "NOACTIVATE|NOZORDER)\n",
1183                                GDK_WINDOW_HWND (window),
1184                                x - _gdk_offset_x, y - _gdk_offset_y,
1185                                outer_rect.right - outer_rect.left,
1186                                outer_rect.bottom - outer_rect.top));
1187
1188       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
1189                                x - _gdk_offset_x, y - _gdk_offset_y,
1190                                outer_rect.right - outer_rect.left,
1191                                outer_rect.bottom - outer_rect.top,
1192                                SWP_NOACTIVATE | SWP_NOZORDER));
1193     }
1194 }
1195
1196 static void
1197 gdk_win32_window_move_resize (GdkWindow *window,
1198                               gboolean   with_move,
1199                               gint       x,
1200                               gint       y,
1201                               gint       width,
1202                               gint       height)
1203 {
1204   /* We ignore changes to the window being moved or resized by the 
1205      user, as we don't want to fight the user */
1206   if (GDK_WINDOW_HWND (window) == _modal_move_resize_window)
1207     return;
1208
1209   if (with_move && (width < 0 && height < 0))
1210     {
1211       gdk_win32_window_move (window, x, y);
1212     }
1213   else
1214     {
1215       if (with_move)
1216         {
1217           gdk_win32_window_move_resize_internal (window, x, y, width, height);
1218         }
1219       else
1220         {
1221           gdk_win32_window_resize (window, width, height);
1222         }
1223     }
1224 }
1225
1226 static gboolean
1227 gdk_win32_window_reparent (GdkWindow *window,
1228                            GdkWindow *new_parent,
1229                            gint       x,
1230                            gint       y)
1231 {
1232   GdkWindow *parent;
1233   GdkWindow *old_parent;
1234   GdkWindowImplWin32 *impl;
1235   gboolean was_toplevel;
1236   LONG style;
1237
1238   if (!new_parent)
1239     new_parent = _gdk_root;
1240
1241   old_parent = window->parent;
1242   parent = new_parent;
1243   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1244
1245   GDK_NOTE (MISC, g_print ("gdk_win32_window_reparent: %p: %p\n",
1246                            GDK_WINDOW_HWND (window),
1247                            GDK_WINDOW_HWND (new_parent)));
1248
1249   style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
1250
1251   was_toplevel = GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) == GetDesktopWindow ();
1252   if (was_toplevel && new_parent != _gdk_root)
1253     {
1254       /* Reparenting from top-level (child of desktop). Clear out
1255        * decorations.
1256        */
1257       style &= ~(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
1258       style |= WS_CHILD;
1259       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, style);
1260     }
1261   else if (new_parent == _gdk_root)
1262     {
1263       /* Reparenting to top-level. Add decorations. */
1264       style &= ~(WS_CHILD);
1265       style |= WS_OVERLAPPEDWINDOW;
1266       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, style);
1267     }
1268
1269   API_CALL (SetParent, (GDK_WINDOW_HWND (window),
1270                         GDK_WINDOW_HWND (new_parent)));
1271   
1272   API_CALL (MoveWindow, (GDK_WINDOW_HWND (window),
1273                          x, y, window->width, window->height, TRUE));
1274
1275   /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like
1276    * the root window
1277    */
1278   if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
1279     new_parent = _gdk_root;
1280   
1281   window->parent = new_parent;
1282
1283   /* Switch the window type as appropriate */
1284
1285   switch (GDK_WINDOW_TYPE (new_parent))
1286     {
1287     case GDK_WINDOW_ROOT:
1288       if (impl->toplevel_window_type != -1)
1289         GDK_WINDOW_TYPE (window) = impl->toplevel_window_type;
1290       else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1291         GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
1292       break;
1293
1294     case GDK_WINDOW_TOPLEVEL:
1295     case GDK_WINDOW_CHILD:
1296     case GDK_WINDOW_TEMP:
1297       if (WINDOW_IS_TOPLEVEL (window))
1298         {
1299           /* Save the original window type so we can restore it if the
1300            * window is reparented back to be a toplevel.
1301            */
1302           impl->toplevel_window_type = GDK_WINDOW_TYPE (window);
1303           GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD;
1304         }
1305     }
1306
1307   if (old_parent)
1308     old_parent->children =
1309       g_list_remove (old_parent->children, window);
1310
1311   parent->children = g_list_prepend (parent->children, window);
1312
1313   return FALSE;
1314 }
1315
1316 static void
1317 gdk_win32_window_raise (GdkWindow *window)
1318 {
1319   if (!GDK_WINDOW_DESTROYED (window))
1320     {
1321       GDK_NOTE (MISC, g_print ("gdk_win32_window_raise: %p\n",
1322                                GDK_WINDOW_HWND (window)));
1323
1324       if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
1325         API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOPMOST,
1326                                  0, 0, 0, 0,
1327                                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
1328       else if (window->accept_focus)
1329         API_CALL (BringWindowToTop, (GDK_WINDOW_HWND (window)));
1330       else
1331         API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOP,
1332                                  0, 0, 0, 0,
1333                                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
1334     }
1335 }
1336
1337 static void
1338 gdk_win32_window_lower (GdkWindow *window)
1339 {
1340   if (!GDK_WINDOW_DESTROYED (window))
1341     {
1342       GDK_NOTE (MISC, g_print ("gdk_win32_window_lower: %p\n"
1343                                "... SetWindowPos(%p,HWND_BOTTOM,0,0,0,0,"
1344                                "NOACTIVATE|NOMOVE|NOSIZE)\n",
1345                                GDK_WINDOW_HWND (window),
1346                                GDK_WINDOW_HWND (window)));
1347
1348       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_BOTTOM,
1349                                0, 0, 0, 0,
1350                                SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
1351     }
1352 }
1353
1354 static void
1355 gdk_win32_window_set_urgency_hint (GdkWindow *window,
1356                              gboolean   urgent)
1357 {
1358   FLASHWINFO flashwinfo;
1359   typedef BOOL (*PFN_FlashWindowEx) (FLASHWINFO*);
1360   PFN_FlashWindowEx flashWindowEx = NULL;
1361
1362   g_return_if_fail (GDK_IS_WINDOW (window));
1363   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
1364   
1365   if (GDK_WINDOW_DESTROYED (window))
1366     return;
1367
1368   flashWindowEx = (PFN_FlashWindowEx) GetProcAddress (GetModuleHandle ("user32.dll"), "FlashWindowEx");
1369
1370   if (flashWindowEx)
1371     {
1372       flashwinfo.cbSize = sizeof (flashwinfo);
1373       flashwinfo.hwnd = GDK_WINDOW_HWND (window);
1374       if (urgent)
1375         flashwinfo.dwFlags = FLASHW_ALL | FLASHW_TIMER;
1376       else
1377         flashwinfo.dwFlags = FLASHW_STOP;
1378       flashwinfo.uCount = 0;
1379       flashwinfo.dwTimeout = 0;
1380       
1381       flashWindowEx (&flashwinfo);
1382     }
1383   else
1384     {
1385       FlashWindow (GDK_WINDOW_HWND (window), urgent);
1386     }
1387 }
1388
1389 static gboolean
1390 get_effective_window_decorations (GdkWindow       *window,
1391                                   GdkWMDecoration *decoration)
1392 {
1393   GdkWindowImplWin32 *impl;
1394
1395   impl = (GdkWindowImplWin32 *)window->impl;
1396
1397   if (gdk_window_get_decorations (window, decoration))
1398     return TRUE;
1399     
1400   if (window->window_type != GDK_WINDOW_TOPLEVEL) 
1401     {
1402       return FALSE;
1403     }
1404
1405   if ((impl->hint_flags & GDK_HINT_MIN_SIZE) &&
1406       (impl->hint_flags & GDK_HINT_MAX_SIZE) &&
1407       impl->hints.min_width == impl->hints.max_width &&
1408       impl->hints.min_height == impl->hints.max_height)
1409     {
1410       *decoration = GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MAXIMIZE;
1411
1412       if (impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1413           impl->type_hint == GDK_WINDOW_TYPE_HINT_MENU ||
1414           impl->type_hint == GDK_WINDOW_TYPE_HINT_TOOLBAR)
1415         {
1416           *decoration |= GDK_DECOR_MINIMIZE;
1417         }
1418       else if (impl->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN)
1419         {
1420           *decoration |= GDK_DECOR_MENU | GDK_DECOR_MINIMIZE;
1421         }
1422
1423       return TRUE;
1424     }
1425   else if (impl->hint_flags & GDK_HINT_MAX_SIZE)
1426     {
1427       *decoration = GDK_DECOR_ALL | GDK_DECOR_MAXIMIZE;
1428       if (impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1429           impl->type_hint == GDK_WINDOW_TYPE_HINT_MENU ||
1430           impl->type_hint == GDK_WINDOW_TYPE_HINT_TOOLBAR)
1431         {
1432           *decoration |= GDK_DECOR_MINIMIZE;
1433         }
1434
1435       return TRUE;
1436     }
1437   else
1438     {
1439       switch (impl->type_hint)
1440         {
1441         case GDK_WINDOW_TYPE_HINT_DIALOG:
1442           *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1443           return TRUE;
1444
1445         case GDK_WINDOW_TYPE_HINT_MENU:
1446           *decoration = (GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1447           return TRUE;
1448
1449         case GDK_WINDOW_TYPE_HINT_TOOLBAR:
1450         case GDK_WINDOW_TYPE_HINT_UTILITY:
1451           gdk_window_set_skip_taskbar_hint (window, TRUE);
1452           gdk_window_set_skip_pager_hint (window, TRUE);
1453           *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1454           return TRUE;
1455
1456         case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
1457           *decoration = (GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MENU |
1458                          GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1459           return TRUE;
1460           
1461         case GDK_WINDOW_TYPE_HINT_DOCK:
1462           return FALSE;
1463           
1464         case GDK_WINDOW_TYPE_HINT_DESKTOP:
1465           return FALSE;
1466
1467         default:
1468           /* Fall thru */
1469         case GDK_WINDOW_TYPE_HINT_NORMAL:
1470           *decoration = GDK_DECOR_ALL;
1471           return TRUE;
1472         }
1473     }
1474     
1475   return FALSE;
1476 }
1477
1478 static void
1479 gdk_win32_window_set_geometry_hints (GdkWindow         *window,
1480                                const GdkGeometry *geometry,
1481                                GdkWindowHints     geom_mask)
1482 {
1483   GdkWindowImplWin32 *impl;
1484
1485   g_return_if_fail (GDK_IS_WINDOW (window));
1486   
1487   if (GDK_WINDOW_DESTROYED (window))
1488     return;
1489
1490   GDK_NOTE (MISC, g_print ("gdk_window_set_geometry_hints: %p\n",
1491                            GDK_WINDOW_HWND (window)));
1492
1493   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1494
1495   impl->hint_flags = geom_mask;
1496   impl->hints = *geometry;
1497
1498   if (geom_mask & GDK_HINT_POS)
1499     ; /* even the X11 mplementation doesn't care */
1500
1501   if (geom_mask & GDK_HINT_MIN_SIZE)
1502     {
1503       GDK_NOTE (MISC, g_print ("... MIN_SIZE: %dx%d\n",
1504                                geometry->min_width, geometry->min_height));
1505     }
1506   
1507   if (geom_mask & GDK_HINT_MAX_SIZE)
1508     {
1509       GDK_NOTE (MISC, g_print ("... MAX_SIZE: %dx%d\n",
1510                                geometry->max_width, geometry->max_height));
1511     }
1512
1513   if (geom_mask & GDK_HINT_BASE_SIZE)
1514     {
1515       GDK_NOTE (MISC, g_print ("... BASE_SIZE: %dx%d\n",
1516                                geometry->base_width, geometry->base_height));
1517     }
1518   
1519   if (geom_mask & GDK_HINT_RESIZE_INC)
1520     {
1521       GDK_NOTE (MISC, g_print ("... RESIZE_INC: (%d,%d)\n",
1522                                geometry->width_inc, geometry->height_inc));
1523     }
1524   
1525   if (geom_mask & GDK_HINT_ASPECT)
1526     {
1527       GDK_NOTE (MISC, g_print ("... ASPECT: %g--%g\n",
1528                                geometry->min_aspect, geometry->max_aspect));
1529     }
1530
1531   if (geom_mask & GDK_HINT_WIN_GRAVITY)
1532     {
1533       GDK_NOTE (MISC, g_print ("... GRAVITY: %d\n", geometry->win_gravity));
1534     }
1535
1536   update_style_bits (window);
1537 }
1538
1539 static void
1540 gdk_win32_window_set_title (GdkWindow   *window,
1541                       const gchar *title)
1542 {
1543   wchar_t *wtitle;
1544
1545   g_return_if_fail (GDK_IS_WINDOW (window));
1546   g_return_if_fail (title != NULL);
1547
1548   if (GDK_WINDOW_DESTROYED (window))
1549     return;
1550
1551   /* Empty window titles not allowed, so set it to just a period. */
1552   if (!title[0])
1553     title = ".";
1554   
1555   GDK_NOTE (MISC, g_print ("gdk_window_set_title: %p: %s\n",
1556                            GDK_WINDOW_HWND (window), title));
1557   
1558   GDK_NOTE (MISC_OR_EVENTS, title = g_strdup_printf ("%p %s", GDK_WINDOW_HWND (window), title));
1559
1560   wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
1561   API_CALL (SetWindowTextW, (GDK_WINDOW_HWND (window), wtitle));
1562   g_free (wtitle);
1563
1564   GDK_NOTE (MISC_OR_EVENTS, g_free ((char *) title));
1565 }
1566
1567 static void
1568 gdk_win32_window_set_role (GdkWindow   *window,
1569                      const gchar *role)
1570 {
1571   g_return_if_fail (GDK_IS_WINDOW (window));
1572   
1573   GDK_NOTE (MISC, g_print ("gdk_window_set_role: %p: %s\n",
1574                            GDK_WINDOW_HWND (window),
1575                            (role ? role : "NULL")));
1576   /* XXX */
1577 }
1578
1579 static void
1580 gdk_win32_window_set_transient_for (GdkWindow *window, 
1581                               GdkWindow *parent)
1582 {
1583   HWND window_id, parent_id;
1584   GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1585   GdkWindowImplWin32 *parent_impl = NULL;
1586   GSList *item;
1587
1588   g_return_if_fail (GDK_IS_WINDOW (window));
1589
1590   window_id = GDK_WINDOW_HWND (window);
1591   parent_id = parent != NULL ? GDK_WINDOW_HWND (parent) : NULL;
1592
1593   GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %p: %p\n", window_id, parent_id));
1594
1595   if (GDK_WINDOW_DESTROYED (window) || (parent && GDK_WINDOW_DESTROYED (parent)))
1596     {
1597       if (GDK_WINDOW_DESTROYED (window))
1598         GDK_NOTE (MISC, g_print ("... destroyed!\n"));
1599       else
1600         GDK_NOTE (MISC, g_print ("... owner destroyed!\n"));
1601
1602       return;
1603     }
1604
1605   if (window->window_type == GDK_WINDOW_CHILD)
1606     {
1607       GDK_NOTE (MISC, g_print ("... a child window!\n"));
1608       return;
1609     }
1610
1611   if (parent == NULL)
1612     {
1613       GdkWindowImplWin32 *trans_impl = GDK_WINDOW_IMPL_WIN32 (window_impl->transient_owner->impl);
1614       if (trans_impl->transient_children != NULL)
1615         {
1616           item = g_slist_find (trans_impl->transient_children, window);
1617           item->data = NULL;
1618           trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
1619           trans_impl->num_transients--;
1620
1621           if (!trans_impl->num_transients)
1622             {
1623               trans_impl->transient_children = NULL;
1624             }
1625         }
1626       g_object_unref (G_OBJECT (window_impl->transient_owner));
1627       g_object_unref (G_OBJECT (window));
1628
1629       window_impl->transient_owner = NULL;
1630     }
1631   else
1632     {
1633       parent_impl = GDK_WINDOW_IMPL_WIN32 (parent->impl);
1634
1635       parent_impl->transient_children = g_slist_append (parent_impl->transient_children, window);
1636       g_object_ref (G_OBJECT (window));
1637       parent_impl->num_transients++;
1638       window_impl->transient_owner = parent;
1639       g_object_ref (G_OBJECT (parent));
1640     }
1641
1642   /* This changes the *owner* of the window, despite the misleading
1643    * name. (Owner and parent are unrelated concepts.) At least that's
1644    * what people who seem to know what they talk about say on
1645    * USENET. Search on Google.
1646    */
1647   SetLastError (0);
1648   if (SetWindowLongPtr (window_id, GWLP_HWNDPARENT, (LONG_PTR) parent_id) == 0 &&
1649       GetLastError () != 0)
1650     WIN32_API_FAILED ("SetWindowLongPtr");
1651 }
1652
1653 void
1654 _gdk_push_modal_window (GdkWindow *window)
1655 {
1656   modal_window_stack = g_slist_prepend (modal_window_stack,
1657                                         window);
1658 }
1659
1660 void
1661 _gdk_remove_modal_window (GdkWindow *window)
1662 {
1663   GSList *tmp;
1664
1665   g_return_if_fail (window != NULL);
1666
1667   /* It's possible to be NULL here if someone sets the modal hint of the window
1668    * to FALSE before a modal window stack has ever been created. */
1669   if (modal_window_stack == NULL)
1670     return;
1671
1672   /* Find the requested window in the stack and remove it.  Yeah, I realize this
1673    * means we're not a 'real stack', strictly speaking.  Sue me. :) */
1674   tmp = g_slist_find (modal_window_stack, window);
1675   if (tmp != NULL)
1676     {
1677       modal_window_stack = g_slist_delete_link (modal_window_stack, tmp);
1678     }
1679 }
1680
1681 GdkWindow *
1682 _gdk_modal_current (void)
1683 {
1684   if (modal_window_stack != NULL)
1685     {
1686       GSList *tmp = modal_window_stack;
1687
1688       while (tmp != NULL && !GDK_WINDOW_IS_MAPPED (GDK_WINDOW (tmp->data)))
1689         {
1690           tmp = g_slist_next (tmp);
1691         }
1692
1693       return tmp != NULL ? tmp->data : NULL;
1694     }
1695   else
1696     {
1697       return NULL;
1698     }
1699 }
1700
1701 static void
1702 gdk_win32_window_set_background (GdkWindow       *window,
1703                                  cairo_pattern_t *pattern)
1704 {
1705 }
1706
1707 static void
1708 gdk_win32_window_set_device_cursor (GdkWindow *window,
1709                                     GdkDevice *device,
1710                                     GdkCursor *cursor)
1711 {
1712   GdkWindowImplWin32 *impl;
1713   GdkWin32Cursor *cursor_private;
1714   HCURSOR hcursor;
1715   HCURSOR hprevcursor;
1716   
1717   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1718   cursor_private = (GdkWin32Cursor*) cursor;
1719   
1720   if (GDK_WINDOW_DESTROYED (window))
1721     return;
1722
1723   if (!cursor)
1724     hcursor = NULL;
1725   else
1726     hcursor = cursor_private->hcursor;
1727   
1728   GDK_NOTE (MISC, g_print ("gdk_win32_window_set_cursor: %p: %p\n",
1729                            GDK_WINDOW_HWND (window),
1730                            hcursor));
1731
1732   /* First get the old cursor, if any (we wait to free the old one
1733    * since it may be the current cursor set in the Win32 API right
1734    * now).
1735    */
1736   hprevcursor = impl->hcursor;
1737
1738   GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
1739
1740   if (hcursor == NULL)
1741     impl->hcursor = NULL;
1742   else
1743     {
1744       /* We must copy the cursor as it is OK to destroy the GdkCursor
1745        * while still in use for some window. See for instance
1746        * gimp_change_win_cursor() which calls gdk_window_set_cursor
1747        * (win, cursor), and immediately afterwards gdk_cursor_destroy
1748        * (cursor).
1749        */
1750       if ((impl->hcursor = CopyCursor (hcursor)) == NULL)
1751         WIN32_API_FAILED ("CopyCursor");
1752       GDK_NOTE (MISC, g_print ("... CopyCursor (%p) = %p\n",
1753                                hcursor, impl->hcursor));
1754     }
1755
1756   /* Destroy the previous cursor */
1757   if (hprevcursor != NULL)
1758     {
1759       GDK_NOTE (MISC, g_print ("... DestroyCursor (%p)\n", hprevcursor));
1760       API_CALL (DestroyCursor, (hprevcursor));
1761     }
1762 }
1763
1764 static void
1765 gdk_win32_window_get_geometry (GdkWindow *window,
1766                                gint      *x,
1767                                gint      *y,
1768                                gint      *width,
1769                                gint      *height)
1770 {
1771   if (!window)
1772     window = _gdk_root;
1773   
1774   if (!GDK_WINDOW_DESTROYED (window))
1775     {
1776       RECT rect;
1777
1778       API_CALL (GetClientRect, (GDK_WINDOW_HWND (window), &rect));
1779
1780       if (window != _gdk_root)
1781         {
1782           POINT pt;
1783           GdkWindow *parent = gdk_window_get_parent (window);
1784
1785           pt.x = rect.left;
1786           pt.y = rect.top;
1787           ClientToScreen (GDK_WINDOW_HWND (window), &pt);
1788           ScreenToClient (GDK_WINDOW_HWND (parent), &pt);
1789           rect.left = pt.x;
1790           rect.top = pt.y;
1791
1792           pt.x = rect.right;
1793           pt.y = rect.bottom;
1794           ClientToScreen (GDK_WINDOW_HWND (window), &pt);
1795           ScreenToClient (GDK_WINDOW_HWND (parent), &pt);
1796           rect.right = pt.x;
1797           rect.bottom = pt.y;
1798
1799           if (parent == _gdk_root)
1800             {
1801               rect.left += _gdk_offset_x;
1802               rect.top += _gdk_offset_y;
1803               rect.right += _gdk_offset_x;
1804               rect.bottom += _gdk_offset_y;
1805             }
1806         }
1807
1808       if (x)
1809         *x = rect.left;
1810       if (y)
1811         *y = rect.top;
1812       if (width)
1813         *width = rect.right - rect.left;
1814       if (height)
1815         *height = rect.bottom - rect.top;
1816
1817       GDK_NOTE (MISC, g_print ("gdk_win32_window_get_geometry: %p: %ldx%ldx%d@%+ld%+ld\n",
1818                                GDK_WINDOW_HWND (window),
1819                                rect.right - rect.left, rect.bottom - rect.top,
1820                                gdk_window_get_visual (window)->depth,
1821                                rect.left, rect.top));
1822     }
1823 }
1824
1825 static gint
1826 gdk_win32_window_get_root_coords (GdkWindow *window,
1827                                   gint       x,
1828                                   gint       y,
1829                                   gint      *root_x,
1830                                   gint      *root_y)
1831 {
1832   gint tx;
1833   gint ty;
1834   POINT pt;
1835
1836   pt.x = x;
1837   pt.y = y;
1838   ClientToScreen (GDK_WINDOW_HWND (window), &pt);
1839   tx = pt.x;
1840   ty = pt.y;
1841   
1842   if (root_x)
1843     *root_x = tx + _gdk_offset_x;
1844   if (root_y)
1845     *root_y = ty + _gdk_offset_y;
1846
1847   GDK_NOTE (MISC, g_print ("gdk_win32_window_get_root_coords: %p: %+d%+d %+d%+d\n",
1848                            GDK_WINDOW_HWND (window),
1849                            x, y,
1850                            tx + _gdk_offset_x, ty + _gdk_offset_y));
1851   return 1;
1852 }
1853
1854 static void
1855 gdk_win32_window_restack_under (GdkWindow *window,
1856                                 GList *native_siblings)
1857 {
1858         // ### TODO
1859 }
1860
1861 static void
1862 gdk_win32_window_restack_toplevel (GdkWindow *window,
1863                                    GdkWindow *sibling,
1864                                    gboolean   above)
1865 {
1866         // ### TODO
1867 }
1868
1869 static void
1870 gdk_win32_window_get_root_origin (GdkWindow *window,
1871                             gint      *x,
1872                             gint      *y)
1873 {
1874   GdkRectangle rect;
1875
1876   g_return_if_fail (GDK_IS_WINDOW (window));
1877
1878   gdk_window_get_frame_extents (window, &rect);
1879
1880   if (x)
1881     *x = rect.x;
1882
1883   if (y)
1884     *y = rect.y;
1885
1886   GDK_NOTE (MISC, g_print ("gdk_window_get_root_origin: %p: %+d%+d\n",
1887                            GDK_WINDOW_HWND (window), rect.x, rect.y));
1888 }
1889
1890 static void
1891 gdk_win32_window_get_frame_extents (GdkWindow    *window,
1892                               GdkRectangle *rect)
1893 {
1894   HWND hwnd;
1895   RECT r;
1896
1897   g_return_if_fail (GDK_IS_WINDOW (window));
1898   g_return_if_fail (rect != NULL);
1899
1900   rect->x = 0;
1901   rect->y = 0;
1902   rect->width = 1;
1903   rect->height = 1;
1904   
1905   if (GDK_WINDOW_DESTROYED (window))
1906     return;
1907
1908   /* FIXME: window is documented to be a toplevel GdkWindow, so is it really
1909    * necessary to walk its parent chain?
1910    */
1911   while (window->parent && window->parent->parent)
1912     window = window->parent;
1913
1914   hwnd = GDK_WINDOW_HWND (window);
1915   API_CALL (GetWindowRect, (hwnd, &r));
1916
1917   rect->x = r.left + _gdk_offset_x;
1918   rect->y = r.top + _gdk_offset_y;
1919   rect->width = r.right - r.left;
1920   rect->height = r.bottom - r.top;
1921
1922   GDK_NOTE (MISC, g_print ("gdk_window_get_frame_extents: %p: %ldx%ld@%+ld%+ld\n",
1923                            GDK_WINDOW_HWND (window),
1924                            r.right - r.left, r.bottom - r.top,
1925                            r.left, r.top));
1926 }
1927
1928 static gboolean
1929 gdk_window_win32_get_device_state (GdkWindow       *window,
1930                                    GdkDevice       *device,
1931                                    gint            *x,
1932                                    gint            *y,
1933                                    GdkModifierType *mask)
1934 {
1935   GdkWindow *child;
1936
1937   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
1938
1939   GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
1940                                               NULL, &child,
1941                                               NULL, NULL,
1942                                               x, y, mask);
1943   return (child != NULL);
1944 }
1945
1946 void
1947 _gdk_windowing_get_device_state (GdkDisplay       *display,
1948                                  GdkDevice        *device,
1949                                  GdkScreen       **screen,
1950                                  gint             *x,
1951                                  gint             *y,
1952                                  GdkModifierType  *mask)
1953 {
1954   g_return_if_fail (display == _gdk_display);
1955
1956   if (screen)
1957     *screen = _gdk_screen;
1958
1959   GDK_DEVICE_GET_CLASS (device)->query_state (device,
1960                                               gdk_screen_get_root_window (_gdk_screen),
1961                                               NULL, NULL,
1962                                               x, y,
1963                                               NULL, NULL,
1964                                               mask);
1965 }
1966
1967 void
1968 gdk_display_warp_device (GdkDisplay *display,
1969                          GdkDevice  *device,
1970                          GdkScreen  *screen,
1971                          gint        x,
1972                          gint        y)
1973 {
1974   g_return_if_fail (display == _gdk_display);
1975   g_return_if_fail (screen == _gdk_screen);
1976   g_return_if_fail (GDK_IS_DEVICE (device));
1977   g_return_if_fail (display == gdk_device_get_display (device));
1978
1979   GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
1980 }
1981
1982 GdkWindow*
1983 _gdk_windowing_window_at_device_position (GdkDisplay      *display,
1984                                           GdkDevice       *device,
1985                                           gint            *win_x,
1986                                           gint            *win_y,
1987                                           GdkModifierType *mask,
1988                                           gboolean         get_toplevel)
1989 {
1990   return GDK_DEVICE_GET_CLASS (device)->window_at_position (device, win_x, win_y, mask, get_toplevel);
1991 }
1992
1993 static GdkEventMask  
1994 gdk_win32_window_get_events (GdkWindow *window)
1995 {
1996   GdkWindowImplWin32 *impl;
1997
1998   if (GDK_WINDOW_DESTROYED (window))
1999     return 0;
2000
2001   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2002
2003   return impl->native_event_mask;
2004 }
2005
2006 static void          
2007 gdk_win32_window_set_events (GdkWindow   *window,
2008                              GdkEventMask event_mask)
2009 {
2010   GdkWindowImplWin32 *impl;
2011
2012   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2013
2014   /* gdk_window_new() always sets the GDK_STRUCTURE_MASK, so better
2015    * set it here, too. Not that I know or remember why it is
2016    * necessary, will have to test some day.
2017    */
2018   impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
2019 }
2020
2021 static void
2022 do_shape_combine_region (GdkWindow *window,
2023                          HRGN       hrgn,
2024                          gint       x, gint y)
2025 {
2026   RECT rect;
2027
2028   GetClientRect (GDK_WINDOW_HWND (window), &rect);
2029   _gdk_win32_adjust_client_rect (window, &rect);
2030
2031   OffsetRgn (hrgn, -rect.left, -rect.top);
2032   OffsetRgn (hrgn, x, y);
2033
2034   /* If this is a top-level window, add the title bar to the region */
2035   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL)
2036     {
2037       HRGN tmp = CreateRectRgn (0, 0, rect.right - rect.left, -rect.top);
2038       CombineRgn (hrgn, hrgn, tmp, RGN_OR);
2039       DeleteObject (tmp);
2040     }
2041   
2042   SetWindowRgn (GDK_WINDOW_HWND (window), hrgn, TRUE);
2043 }
2044
2045 static void
2046 gdk_win32_window_set_override_redirect (GdkWindow *window,
2047                                   gboolean   override_redirect)
2048 {
2049   g_return_if_fail (GDK_IS_WINDOW (window));
2050
2051   g_warning ("gdk_window_set_override_redirect not implemented");
2052 }
2053
2054 static void
2055 gdk_win32_window_set_accept_focus (GdkWindow *window,
2056                              gboolean accept_focus)
2057 {
2058   g_return_if_fail (GDK_IS_WINDOW (window));
2059
2060   accept_focus = accept_focus != FALSE;
2061
2062   if (window->accept_focus != accept_focus)
2063     window->accept_focus = accept_focus;
2064 }
2065
2066 static void
2067 gdk_win32_window_set_focus_on_map (GdkWindow *window,
2068                              gboolean focus_on_map)
2069 {
2070   g_return_if_fail (GDK_IS_WINDOW (window));
2071
2072   focus_on_map = focus_on_map != FALSE;
2073
2074   if (window->focus_on_map != focus_on_map)
2075     window->focus_on_map = focus_on_map;
2076 }
2077
2078 static void
2079 gdk_win32_window_set_icon_list (GdkWindow *window,
2080                           GList     *pixbufs)
2081 {
2082   GdkPixbuf *pixbuf, *big_pixbuf, *small_pixbuf;
2083   gint big_diff, small_diff;
2084   gint big_w, big_h, small_w, small_h;
2085   gint w, h;
2086   gint dw, dh, diff;
2087   HICON small_hicon, big_hicon;
2088   GdkWindowImplWin32 *impl;
2089   gint i, big_i, small_i;
2090
2091   g_return_if_fail (GDK_IS_WINDOW (window));
2092
2093   if (GDK_WINDOW_DESTROYED (window))
2094     return;
2095
2096   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2097
2098   /* ideal sizes for small and large icons */
2099   big_w = GetSystemMetrics (SM_CXICON);
2100   big_h = GetSystemMetrics (SM_CYICON);
2101   small_w = GetSystemMetrics (SM_CXSMICON);
2102   small_h = GetSystemMetrics (SM_CYSMICON);
2103
2104   /* find closest sized icons in the list */
2105   big_pixbuf = NULL;
2106   small_pixbuf = NULL;
2107   big_diff = 0;
2108   small_diff = 0;
2109   i = 0;
2110   while (pixbufs)
2111     {
2112       pixbuf = (GdkPixbuf*) pixbufs->data;
2113       w = gdk_pixbuf_get_width (pixbuf);
2114       h = gdk_pixbuf_get_height (pixbuf);
2115
2116       dw = ABS (w - big_w);
2117       dh = ABS (h - big_h);
2118       diff = dw*dw + dh*dh;
2119       if (big_pixbuf == NULL || diff < big_diff)
2120         {
2121           big_pixbuf = pixbuf;
2122           big_diff = diff;
2123           big_i = i;
2124         }
2125
2126       dw = ABS (w - small_w);
2127       dh = ABS (h - small_h);
2128       diff = dw*dw + dh*dh;
2129       if (small_pixbuf == NULL || diff < small_diff)
2130         {
2131           small_pixbuf = pixbuf;
2132           small_diff = diff;
2133           small_i = i;
2134         }
2135
2136       pixbufs = g_list_next (pixbufs);
2137       i++;
2138     }
2139
2140   /* Create the icons */
2141   big_hicon = _gdk_win32_pixbuf_to_hicon (big_pixbuf);
2142   small_hicon = _gdk_win32_pixbuf_to_hicon (small_pixbuf);
2143
2144   /* Set the icons */
2145   SendMessageW (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG,
2146                 (LPARAM)big_hicon);
2147   SendMessageW (GDK_WINDOW_HWND (window), WM_SETICON, ICON_SMALL,
2148                 (LPARAM)small_hicon);
2149
2150   /* Store the icons, destroying any previous icons */
2151   if (impl->hicon_big)
2152     GDI_CALL (DestroyIcon, (impl->hicon_big));
2153   impl->hicon_big = big_hicon;
2154   if (impl->hicon_small)
2155     GDI_CALL (DestroyIcon, (impl->hicon_small));
2156   impl->hicon_small = small_hicon;
2157 }
2158
2159 static void
2160 gdk_win32_window_set_icon_name (GdkWindow   *window, 
2161                           const gchar *name)
2162 {
2163   /* In case I manage to confuse this again (or somebody else does):
2164    * Please note that "icon name" here really *does* mean the name or
2165    * title of an window minimized as an icon on the desktop, or in the
2166    * taskbar. It has nothing to do with the freedesktop.org icon
2167    * naming stuff.
2168    */
2169
2170   g_return_if_fail (GDK_IS_WINDOW (window));
2171
2172   if (GDK_WINDOW_DESTROYED (window))
2173     return;
2174   
2175 #if 0
2176   /* This is not the correct thing to do. We should keep both the
2177    * "normal" window title, and the icon name. When the window is
2178    * minimized, call SetWindowText() with the icon name, and when the
2179    * window is restored, with the normal window title. Also, the name
2180    * is in UTF-8, so we should do the normal conversion to either wide
2181    * chars or system codepage, and use either the W or A version of
2182    * SetWindowText(), depending on Windows version.
2183    */
2184   API_CALL (SetWindowText, (GDK_WINDOW_HWND (window), name));
2185 #endif
2186 }
2187
2188 static GdkWindow *
2189 gdk_win32_window_get_group (GdkWindow *window)
2190 {
2191   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2192   g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL);
2193
2194   if (GDK_WINDOW_DESTROYED (window))
2195     return NULL;
2196   
2197   g_warning ("gdk_window_get_group not yet implemented");
2198
2199   return NULL;
2200 }
2201
2202 static void
2203 gdk_win32_window_set_group (GdkWindow *window, 
2204                       GdkWindow *leader)
2205 {
2206   g_return_if_fail (GDK_IS_WINDOW (window));
2207   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
2208   g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader));
2209
2210   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
2211     return;
2212   
2213   g_warning ("gdk_window_set_group not implemented");
2214 }
2215
2216 static void
2217 update_single_bit (LONG    *style,
2218                    gboolean all,
2219                    int      gdk_bit,
2220                    int      style_bit)
2221 {
2222   /* all controls the interpretation of gdk_bit -- if all is TRUE,
2223    * gdk_bit indicates whether style_bit is off; if all is FALSE, gdk
2224    * bit indicate whether style_bit is on
2225    */
2226   if ((!all && gdk_bit) || (all && !gdk_bit))
2227     *style |= style_bit;
2228   else
2229     *style &= ~style_bit;
2230 }
2231
2232 static void
2233 update_style_bits (GdkWindow *window)
2234 {
2235   GdkWindowImplWin32 *impl = (GdkWindowImplWin32 *)window->impl;
2236   GdkWMDecoration decorations;
2237   LONG old_style, new_style, old_exstyle, new_exstyle;
2238   gboolean all;
2239   RECT rect, before, after;
2240
2241   old_style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
2242   old_exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
2243
2244   GetClientRect (GDK_WINDOW_HWND (window), &before);
2245   after = before;
2246   AdjustWindowRectEx (&before, old_style, FALSE, old_exstyle);
2247
2248   new_style = old_style;
2249   new_exstyle = old_exstyle;
2250
2251   if (window->window_type == GDK_WINDOW_TEMP ||
2252       impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY)
2253     new_exstyle |= WS_EX_TOOLWINDOW;
2254   else
2255     new_exstyle &= ~WS_EX_TOOLWINDOW;
2256
2257   if (get_effective_window_decorations (window, &decorations))
2258     {
2259       all = (decorations & GDK_DECOR_ALL);
2260       update_single_bit (&new_style, all, decorations & GDK_DECOR_BORDER, WS_BORDER);
2261       update_single_bit (&new_style, all, decorations & GDK_DECOR_RESIZEH, WS_THICKFRAME);
2262       update_single_bit (&new_style, all, decorations & GDK_DECOR_TITLE, WS_CAPTION);
2263       update_single_bit (&new_style, all, decorations & GDK_DECOR_MENU, WS_SYSMENU);
2264       update_single_bit (&new_style, all, decorations & GDK_DECOR_MINIMIZE, WS_MINIMIZEBOX);
2265       update_single_bit (&new_style, all, decorations & GDK_DECOR_MAXIMIZE, WS_MAXIMIZEBOX);
2266     }
2267
2268   if (old_style == new_style && old_exstyle == new_exstyle )
2269     {
2270       GDK_NOTE (MISC, g_print ("update_style_bits: %p: no change\n",
2271                                GDK_WINDOW_HWND (window)));
2272       return;
2273     }
2274
2275   if (old_style != new_style)
2276     {
2277       GDK_NOTE (MISC, g_print ("update_style_bits: %p: STYLE: %s => %s\n",
2278                                GDK_WINDOW_HWND (window),
2279                                _gdk_win32_window_style_to_string (old_style),
2280                                _gdk_win32_window_style_to_string (new_style)));
2281       
2282       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, new_style);
2283     }
2284
2285   if (old_exstyle != new_exstyle)
2286     {
2287       GDK_NOTE (MISC, g_print ("update_style_bits: %p: EXSTYLE: %s => %s\n",
2288                                GDK_WINDOW_HWND (window),
2289                                _gdk_win32_window_exstyle_to_string (old_exstyle),
2290                                _gdk_win32_window_exstyle_to_string (new_exstyle)));
2291       
2292       SetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE, new_exstyle);
2293     }
2294
2295   AdjustWindowRectEx (&after, new_style, FALSE, new_exstyle);
2296
2297   GetWindowRect (GDK_WINDOW_HWND (window), &rect);
2298   rect.left += after.left - before.left;
2299   rect.top += after.top - before.top;
2300   rect.right += after.right - before.right;
2301   rect.bottom += after.bottom - before.bottom;
2302
2303   SetWindowPos (GDK_WINDOW_HWND (window), NULL,
2304                 rect.left, rect.top,
2305                 rect.right - rect.left, rect.bottom - rect.top,
2306                 SWP_FRAMECHANGED | SWP_NOACTIVATE | 
2307                 SWP_NOREPOSITION | SWP_NOZORDER);
2308
2309 }
2310
2311 static void
2312 update_single_system_menu_entry (HMENU    hmenu,
2313                                  gboolean all,
2314                                  int      gdk_bit,
2315                                  int      menu_entry)
2316 {
2317   /* all controls the interpretation of gdk_bit -- if all is TRUE,
2318    * gdk_bit indicates whether menu entry is disabled; if all is
2319    * FALSE, gdk bit indicate whether menu entry is enabled
2320    */
2321   if ((!all && gdk_bit) || (all && !gdk_bit))
2322     EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_ENABLED);
2323   else
2324     EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_GRAYED);
2325 }
2326
2327 static void
2328 update_system_menu (GdkWindow *window)
2329 {
2330   GdkWMFunction functions;
2331   BOOL all;
2332
2333   if (_gdk_window_get_functions (window, &functions))
2334     {
2335       HMENU hmenu = GetSystemMenu (GDK_WINDOW_HWND (window), FALSE);
2336
2337       all = (functions & GDK_FUNC_ALL);
2338       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_RESIZE, SC_SIZE);
2339       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MOVE, SC_MOVE);
2340       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MINIMIZE, SC_MINIMIZE);
2341       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MAXIMIZE, SC_MAXIMIZE);
2342       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_CLOSE, SC_CLOSE);
2343     }
2344 }
2345
2346 static GQuark
2347 get_decorations_quark ()
2348 {
2349   static GQuark quark = 0;
2350   
2351   if (!quark)
2352     quark = g_quark_from_static_string ("gdk-window-decorations");
2353   
2354   return quark;
2355 }
2356
2357 static void
2358 gdk_win32_window_set_decorations (GdkWindow      *window,
2359                             GdkWMDecoration decorations)
2360 {
2361   GdkWMDecoration* decorations_copy;
2362   
2363   g_return_if_fail (GDK_IS_WINDOW (window));
2364   
2365   GDK_NOTE (MISC, g_print ("gdk_window_set_decorations: %p: %s %s%s%s%s%s%s\n",
2366                            GDK_WINDOW_HWND (window),
2367                            (decorations & GDK_DECOR_ALL ? "clearing" : "setting"),
2368                            (decorations & GDK_DECOR_BORDER ? "BORDER " : ""),
2369                            (decorations & GDK_DECOR_RESIZEH ? "RESIZEH " : ""),
2370                            (decorations & GDK_DECOR_TITLE ? "TITLE " : ""),
2371                            (decorations & GDK_DECOR_MENU ? "MENU " : ""),
2372                            (decorations & GDK_DECOR_MINIMIZE ? "MINIMIZE " : ""),
2373                            (decorations & GDK_DECOR_MAXIMIZE ? "MAXIMIZE " : "")));
2374
2375   decorations_copy = g_malloc (sizeof (GdkWMDecoration));
2376   *decorations_copy = decorations;
2377   g_object_set_qdata_full (G_OBJECT (window), get_decorations_quark (), decorations_copy, g_free);
2378
2379   update_style_bits (window);
2380 }
2381
2382 static gboolean
2383 gdk_win32_window_get_decorations (GdkWindow       *window,
2384                             GdkWMDecoration *decorations)
2385 {
2386   GdkWMDecoration* decorations_set;
2387   
2388   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2389
2390   decorations_set = g_object_get_qdata (G_OBJECT (window), get_decorations_quark ());
2391   if (decorations_set)
2392     *decorations = *decorations_set;
2393
2394   return (decorations_set != NULL);
2395 }
2396
2397 static GQuark
2398 get_functions_quark ()
2399 {
2400   static GQuark quark = 0;
2401   
2402   if (!quark)
2403     quark = g_quark_from_static_string ("gdk-window-functions");
2404   
2405   return quark;
2406 }
2407
2408 static void
2409 gdk_win32_window_set_functions (GdkWindow    *window,
2410                           GdkWMFunction functions)
2411 {
2412   GdkWMFunction* functions_copy;
2413
2414   g_return_if_fail (GDK_IS_WINDOW (window));
2415   
2416   GDK_NOTE (MISC, g_print ("gdk_window_set_functions: %p: %s %s%s%s%s%s\n",
2417                            GDK_WINDOW_HWND (window),
2418                            (functions & GDK_FUNC_ALL ? "clearing" : "setting"),
2419                            (functions & GDK_FUNC_RESIZE ? "RESIZE " : ""),
2420                            (functions & GDK_FUNC_MOVE ? "MOVE " : ""),
2421                            (functions & GDK_FUNC_MINIMIZE ? "MINIMIZE " : ""),
2422                            (functions & GDK_FUNC_MAXIMIZE ? "MAXIMIZE " : ""),
2423                            (functions & GDK_FUNC_CLOSE ? "CLOSE " : "")));
2424
2425   functions_copy = g_malloc (sizeof (GdkWMFunction));
2426   *functions_copy = functions;
2427   g_object_set_qdata_full (G_OBJECT (window), get_functions_quark (), functions_copy, g_free);
2428
2429   update_system_menu (window);
2430 }
2431
2432 gboolean
2433 _gdk_window_get_functions (GdkWindow     *window,
2434                            GdkWMFunction *functions)
2435 {
2436   GdkWMDecoration* functions_set;
2437   
2438   functions_set = g_object_get_qdata (G_OBJECT (window), get_functions_quark ());
2439   if (functions_set)
2440     *functions = *functions_set;
2441
2442   return (functions_set != NULL);
2443 }
2444
2445 static gboolean 
2446 gdk_win32_window_set_static_gravities (GdkWindow *window,
2447                                  gboolean   use_static)
2448 {
2449   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2450
2451   return !use_static;
2452 }
2453
2454 static void
2455 gdk_win32_window_begin_resize_drag (GdkWindow     *window,
2456                               GdkWindowEdge  edge,
2457                               GdkDevice     *device,
2458                               gint           button,
2459                               gint           root_x,
2460                               gint           root_y,
2461                               guint32        timestamp)
2462 {
2463   WPARAM winedge;
2464   
2465   g_return_if_fail (GDK_IS_WINDOW (window));
2466   
2467   if (GDK_WINDOW_DESTROYED (window))
2468     return;
2469
2470   /* Tell Windows to start interactively resizing the window by pretending that
2471    * the left pointer button was clicked in the suitable edge or corner. This
2472    * will only work if the button is down when this function is called, and
2473    * will only work with button 1 (left), since Windows only allows window
2474    * dragging using the left mouse button.
2475    */
2476   if (button != 1)
2477     return;
2478   
2479   /* Must break the automatic grab that occured when the button was
2480    * pressed, otherwise it won't work.
2481    */
2482   gdk_display_pointer_ungrab (_gdk_display, 0);
2483
2484   switch (edge)
2485     {
2486     case GDK_WINDOW_EDGE_NORTH_WEST:
2487       winedge = HTTOPLEFT;
2488       break;
2489
2490     case GDK_WINDOW_EDGE_NORTH:
2491       winedge = HTTOP;
2492       break;
2493
2494     case GDK_WINDOW_EDGE_NORTH_EAST:
2495       winedge = HTTOPRIGHT;
2496       break;
2497
2498     case GDK_WINDOW_EDGE_WEST:
2499       winedge = HTLEFT;
2500       break;
2501
2502     case GDK_WINDOW_EDGE_EAST:
2503       winedge = HTRIGHT;
2504       break;
2505
2506     case GDK_WINDOW_EDGE_SOUTH_WEST:
2507       winedge = HTBOTTOMLEFT;
2508       break;
2509
2510     case GDK_WINDOW_EDGE_SOUTH:
2511       winedge = HTBOTTOM;
2512       break;
2513
2514     case GDK_WINDOW_EDGE_SOUTH_EAST:
2515     default:
2516       winedge = HTBOTTOMRIGHT;
2517       break;
2518     }
2519
2520   DefWindowProcW (GDK_WINDOW_HWND (window), WM_NCLBUTTONDOWN, winedge,
2521                   MAKELPARAM (root_x - _gdk_offset_x, root_y - _gdk_offset_y));
2522 }
2523
2524 static void
2525 gdk_win32_window_begin_move_drag (GdkWindow *window,
2526                             GdkDevice *device,
2527                             gint       button,
2528                             gint       root_x,
2529                             gint       root_y,
2530                             guint32    timestamp)
2531 {
2532   g_return_if_fail (GDK_IS_WINDOW (window));
2533   
2534   if (GDK_WINDOW_DESTROYED (window))
2535     return;
2536
2537   /* Tell Windows to start interactively moving the window by pretending that
2538    * the left pointer button was clicked in the titlebar. This will only work
2539    * if the button is down when this function is called, and will only work
2540    * with button 1 (left), since Windows only allows window dragging using the
2541    * left mouse button.
2542    */
2543   if (button != 1)
2544     return;
2545   
2546   /* Must break the automatic grab that occured when the button was pressed,
2547    * otherwise it won't work.
2548    */
2549   gdk_display_pointer_ungrab (_gdk_display, 0);
2550
2551   DefWindowProcW (GDK_WINDOW_HWND (window), WM_NCLBUTTONDOWN, HTCAPTION,
2552                   MAKELPARAM (root_x - _gdk_offset_x, root_y - _gdk_offset_y));
2553 }
2554
2555
2556 /*
2557  * Setting window states
2558  */
2559 static void
2560 gdk_win32_window_iconify (GdkWindow *window)
2561 {
2562   HWND old_active_window;
2563
2564   g_return_if_fail (GDK_IS_WINDOW (window));
2565
2566   if (GDK_WINDOW_DESTROYED (window))
2567     return;
2568
2569   GDK_NOTE (MISC, g_print ("gdk_window_iconify: %p: %s\n",
2570                            GDK_WINDOW_HWND (window),
2571                            _gdk_win32_window_state_to_string (window->state)));
2572
2573   if (GDK_WINDOW_IS_MAPPED (window))
2574     {
2575       old_active_window = GetActiveWindow ();
2576       ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
2577       if (old_active_window != GDK_WINDOW_HWND (window))
2578         SetActiveWindow (old_active_window);
2579     }
2580   else
2581     {
2582       gdk_synthesize_window_state (window,
2583                                    0,
2584                                    GDK_WINDOW_STATE_ICONIFIED);
2585     }
2586 }
2587
2588 static void
2589 gdk_win32_window_deiconify (GdkWindow *window)
2590 {
2591   g_return_if_fail (GDK_IS_WINDOW (window));
2592
2593   if (GDK_WINDOW_DESTROYED (window))
2594     return;
2595
2596   GDK_NOTE (MISC, g_print ("gdk_window_deiconify: %p: %s\n",
2597                            GDK_WINDOW_HWND (window),
2598                            _gdk_win32_window_state_to_string (window->state)));
2599
2600   if (GDK_WINDOW_IS_MAPPED (window))
2601     {  
2602       show_window_internal (window, GDK_WINDOW_IS_MAPPED (window), TRUE);
2603     }
2604   else
2605     {
2606       gdk_synthesize_window_state (window,
2607                                    GDK_WINDOW_STATE_ICONIFIED,
2608                                    0);
2609     }
2610 }
2611
2612 static void
2613 gdk_win32_window_stick (GdkWindow *window)
2614 {
2615   g_return_if_fail (GDK_IS_WINDOW (window));
2616
2617   if (GDK_WINDOW_DESTROYED (window))
2618     return;
2619
2620   /* FIXME: Do something? */
2621 }
2622
2623 static void
2624 gdk_win32_window_unstick (GdkWindow *window)
2625 {
2626   g_return_if_fail (GDK_IS_WINDOW (window));
2627
2628   if (GDK_WINDOW_DESTROYED (window))
2629     return;
2630
2631   /* FIXME: Do something? */
2632 }
2633
2634 static void
2635 gdk_win32_window_maximize (GdkWindow *window)
2636 {
2637   g_return_if_fail (GDK_IS_WINDOW (window));
2638
2639   if (GDK_WINDOW_DESTROYED (window))
2640     return;
2641
2642   GDK_NOTE (MISC, g_print ("gdk_window_maximize: %p: %s\n",
2643                            GDK_WINDOW_HWND (window),
2644                            _gdk_win32_window_state_to_string (window->state)));
2645
2646   if (GDK_WINDOW_IS_MAPPED (window))
2647     ShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
2648   else
2649     gdk_synthesize_window_state (window,
2650                                  0,
2651                                  GDK_WINDOW_STATE_MAXIMIZED);
2652 }
2653
2654 static void
2655 gdk_win32_window_unmaximize (GdkWindow *window)
2656 {
2657   g_return_if_fail (GDK_IS_WINDOW (window));
2658
2659   if (GDK_WINDOW_DESTROYED (window))
2660     return;
2661
2662   GDK_NOTE (MISC, g_print ("gdk_window_unmaximize: %p: %s\n",
2663                            GDK_WINDOW_HWND (window),
2664                            _gdk_win32_window_state_to_string (window->state)));
2665
2666   if (GDK_WINDOW_IS_MAPPED (window))
2667     ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
2668   else
2669     gdk_synthesize_window_state (window,
2670                                  GDK_WINDOW_STATE_MAXIMIZED,
2671                                  0);
2672 }
2673
2674 typedef struct _FullscreenInfo FullscreenInfo;
2675
2676 struct _FullscreenInfo
2677 {
2678   RECT  r;
2679   guint hint_flags;
2680   LONG  style;
2681 };
2682
2683 static void
2684 gdk_win32_window_fullscreen (GdkWindow *window)
2685 {
2686   gint x, y, width, height;
2687   FullscreenInfo *fi;
2688   HMONITOR monitor;
2689   MONITORINFO mi;
2690
2691   g_return_if_fail (GDK_IS_WINDOW (window));
2692
2693   fi = g_new (FullscreenInfo, 1);
2694
2695   if (!GetWindowRect (GDK_WINDOW_HWND (window), &(fi->r)))
2696     g_free (fi);
2697   else
2698     {
2699       GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2700
2701       monitor = MonitorFromWindow (GDK_WINDOW_HWND (window), MONITOR_DEFAULTTONEAREST);
2702       mi.cbSize = sizeof (mi);
2703       if (monitor && GetMonitorInfo (monitor, &mi))
2704         {
2705           x = mi.rcMonitor.left;
2706           y = mi.rcMonitor.top;
2707           width = mi.rcMonitor.right - x;
2708           height = mi.rcMonitor.bottom - y;
2709         }
2710       else
2711         {
2712           x = y = 0;
2713           width = GetSystemMetrics (SM_CXSCREEN);
2714           height = GetSystemMetrics (SM_CYSCREEN);
2715         }
2716
2717       /* remember for restoring */
2718       fi->hint_flags = impl->hint_flags;
2719       impl->hint_flags &= ~GDK_HINT_MAX_SIZE;
2720       g_object_set_data (G_OBJECT (window), "fullscreen-info", fi);
2721       fi->style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
2722
2723       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, 
2724                      (fi->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
2725
2726       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOP,
2727                                x, y, width, height,
2728                                SWP_NOCOPYBITS | SWP_SHOWWINDOW));
2729
2730       gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
2731     }
2732 }
2733
2734 static void
2735 gdk_win32_window_unfullscreen (GdkWindow *window)
2736 {
2737   FullscreenInfo *fi;
2738
2739   g_return_if_fail (GDK_IS_WINDOW (window));
2740
2741   fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
2742   if (fi)
2743     {
2744       GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2745
2746       impl->hint_flags = fi->hint_flags;
2747       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, fi->style);
2748       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_NOTOPMOST,
2749                                fi->r.left, fi->r.top,
2750                                fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
2751                                SWP_NOCOPYBITS | SWP_SHOWWINDOW));
2752       
2753       g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
2754       g_free (fi);
2755
2756       gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
2757     }
2758 }
2759
2760 static void
2761 gdk_win32_window_set_keep_above (GdkWindow *window,
2762                            gboolean   setting)
2763 {
2764   g_return_if_fail (GDK_IS_WINDOW (window));
2765
2766   if (GDK_WINDOW_DESTROYED (window))
2767     return;
2768
2769   GDK_NOTE (MISC, g_print ("gdk_window_set_keep_above: %p: %s\n",
2770                            GDK_WINDOW_HWND (window),
2771                            setting ? "YES" : "NO"));
2772
2773   if (GDK_WINDOW_IS_MAPPED (window))
2774     {
2775       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
2776                                setting ? HWND_TOPMOST : HWND_NOTOPMOST,
2777                                0, 0, 0, 0,
2778                                SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
2779     }
2780   else
2781     gdk_synthesize_window_state (window,
2782                                  setting ? GDK_WINDOW_STATE_BELOW : GDK_WINDOW_STATE_ABOVE,
2783                                  setting ? GDK_WINDOW_STATE_ABOVE : 0);
2784 }
2785
2786 static void
2787 gdk_win32_window_set_keep_below (GdkWindow *window,
2788                            gboolean   setting)
2789 {
2790   g_return_if_fail (GDK_IS_WINDOW (window));
2791
2792   if (GDK_WINDOW_DESTROYED (window))
2793     return;
2794
2795   GDK_NOTE (MISC, g_print ("gdk_window_set_keep_below: %p: %s\n",
2796                            GDK_WINDOW_HWND (window),
2797                            setting ? "YES" : "NO"));
2798
2799   if (GDK_WINDOW_IS_MAPPED (window))
2800     {
2801       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
2802                                setting ? HWND_BOTTOM : HWND_NOTOPMOST,
2803                                0, 0, 0, 0,
2804                                SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
2805     }
2806   else
2807     gdk_synthesize_window_state (window,
2808                                  setting ? GDK_WINDOW_STATE_ABOVE : GDK_WINDOW_STATE_BELOW,
2809                                  setting ? GDK_WINDOW_STATE_BELOW : 0);
2810 }
2811
2812 static void
2813 gdk_win32_window_focus (GdkWindow *window,
2814                         guint32    timestamp)
2815 {
2816   g_return_if_fail (GDK_IS_WINDOW (window));
2817
2818   if (GDK_WINDOW_DESTROYED (window))
2819     return;
2820   
2821   GDK_NOTE (MISC, g_print ("gdk_window_focus: %p: %s\n",
2822                            GDK_WINDOW_HWND (window),
2823                            _gdk_win32_window_state_to_string (window->state)));
2824
2825   if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
2826     ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMAXIMIZED);
2827   else
2828     ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNORMAL);
2829   SetFocus (GDK_WINDOW_HWND (window));
2830 }
2831
2832 static void
2833 gdk_win32_window_set_modal_hint (GdkWindow *window,
2834                            gboolean   modal)
2835 {
2836   g_return_if_fail (GDK_IS_WINDOW (window));
2837   
2838   if (GDK_WINDOW_DESTROYED (window))
2839     return;
2840
2841   GDK_NOTE (MISC, g_print ("gdk_window_set_modal_hint: %p: %s\n",
2842                            GDK_WINDOW_HWND (window),
2843                            modal ? "YES" : "NO"));
2844
2845   if (modal == window->modal_hint)
2846     return;
2847
2848   window->modal_hint = modal;
2849
2850 #if 0
2851   /* Not sure about this one.. -- Cody */
2852   if (GDK_WINDOW_IS_MAPPED (window))
2853     API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), 
2854                              modal ? HWND_TOPMOST : HWND_NOTOPMOST,
2855                              0, 0, 0, 0,
2856                              SWP_NOMOVE | SWP_NOSIZE));
2857 #else
2858
2859   if (modal)
2860     {
2861       _gdk_push_modal_window (window);
2862       gdk_window_raise (window);
2863     }
2864   else
2865     {
2866       _gdk_remove_modal_window (window);
2867     }
2868
2869 #endif
2870 }
2871
2872 static void
2873 gdk_win32_window_set_skip_taskbar_hint (GdkWindow *window,
2874                                   gboolean   skips_taskbar)
2875 {
2876   static GdkWindow *owner = NULL;
2877   //GdkWindowAttr wa;
2878
2879   g_return_if_fail (GDK_IS_WINDOW (window));
2880
2881   GDK_NOTE (MISC, g_print ("gdk_window_set_skip_taskbar_hint: %p: %s, doing nothing\n",
2882                            GDK_WINDOW_HWND (window),
2883                            skips_taskbar ? "YES" : "NO"));
2884
2885   // ### TODO: Need to figure out what to do here.
2886   return;
2887
2888   if (skips_taskbar)
2889     {
2890 #if 0
2891       if (owner == NULL)
2892                 {
2893                   wa.window_type = GDK_WINDOW_TEMP;
2894                   wa.wclass = GDK_INPUT_OUTPUT;
2895                   wa.width = wa.height = 1;
2896                   wa.event_mask = 0;
2897                   owner = gdk_window_new_internal (NULL, &wa, 0, TRUE);
2898                 }
2899 #endif
2900
2901       SetWindowLongPtr (GDK_WINDOW_HWND (window), GWLP_HWNDPARENT, (LONG_PTR) GDK_WINDOW_HWND (owner));
2902
2903 #if 0 /* Should we also turn off the minimize and maximize buttons? */
2904       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE,
2905                      GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE) & ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU));
2906      
2907       SetWindowPos (GDK_WINDOW_HWND (window), NULL,
2908                     0, 0, 0, 0,
2909                     SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
2910                     SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
2911 #endif
2912     }
2913   else
2914     {
2915       SetWindowLongPtr (GDK_WINDOW_HWND (window), GWLP_HWNDPARENT, 0);
2916     }
2917 }
2918
2919 static void
2920 gdk_win32_window_set_skip_pager_hint (GdkWindow *window,
2921                                 gboolean   skips_pager)
2922 {
2923   g_return_if_fail (GDK_IS_WINDOW (window));
2924
2925   GDK_NOTE (MISC, g_print ("gdk_window_set_skip_pager_hint: %p: %s, doing nothing\n",
2926                            GDK_WINDOW_HWND (window),
2927                            skips_pager ? "YES" : "NO"));
2928 }
2929
2930 static void
2931 gdk_win32_window_set_type_hint (GdkWindow        *window,
2932                           GdkWindowTypeHint hint)
2933 {
2934   g_return_if_fail (GDK_IS_WINDOW (window));
2935   
2936   if (GDK_WINDOW_DESTROYED (window))
2937     return;
2938
2939   GDK_NOTE (MISC,
2940             G_STMT_START{
2941               static GEnumClass *class = NULL;
2942               if (!class)
2943                 class = g_type_class_ref (GDK_TYPE_WINDOW_TYPE_HINT);
2944               g_print ("gdk_window_set_type_hint: %p: %s\n",
2945                        GDK_WINDOW_HWND (window),
2946                        g_enum_get_value (class, hint)->value_name);
2947             }G_STMT_END);
2948
2949   ((GdkWindowImplWin32 *)window->impl)->type_hint = hint;
2950
2951   update_style_bits (window);
2952 }
2953
2954 static GdkWindowTypeHint
2955 gdk_win32_window_get_type_hint (GdkWindow *window)
2956 {
2957   g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
2958   
2959   if (GDK_WINDOW_DESTROYED (window))
2960     return GDK_WINDOW_TYPE_HINT_NORMAL;
2961
2962   return GDK_WINDOW_IMPL_WIN32 (window->impl)->type_hint;
2963 }
2964
2965 static HRGN
2966 cairo_region_to_hrgn (const cairo_region_t *region,
2967                       gint                  x_origin,
2968                       gint                  y_origin)
2969 {
2970   HRGN hrgn;
2971   RGNDATA *rgndata;
2972   RECT *rect;
2973   cairo_rectangle_int_t r;
2974   const int nrects = cairo_region_num_rectangles (region);
2975   guint nbytes =
2976     sizeof (RGNDATAHEADER) + (sizeof (RECT) * nrects);
2977   int i;
2978
2979   rgndata = g_malloc (nbytes);
2980   rgndata->rdh.dwSize = sizeof (RGNDATAHEADER);
2981   rgndata->rdh.iType = RDH_RECTANGLES;
2982   rgndata->rdh.nCount = rgndata->rdh.nRgnSize = 0;
2983   SetRect (&rgndata->rdh.rcBound,
2984            G_MAXLONG, G_MAXLONG, G_MINLONG, G_MINLONG);
2985
2986   for (i = 0; i < nrects; i++)
2987     {
2988       rect = ((RECT *) rgndata->Buffer) + rgndata->rdh.nCount++;
2989       
2990       cairo_region_get_rectangle (region, i, &r);
2991       rect->left = r.x + x_origin;
2992       rect->right = rect->left + r.width;
2993       rect->top = r.y + y_origin;
2994       rect->bottom = rect->top + r.height;
2995
2996       if (rect->left < rgndata->rdh.rcBound.left)
2997         rgndata->rdh.rcBound.left = rect->left;
2998       if (rect->right > rgndata->rdh.rcBound.right)
2999         rgndata->rdh.rcBound.right = rect->right;
3000       if (rect->top < rgndata->rdh.rcBound.top)
3001         rgndata->rdh.rcBound.top = rect->top;
3002       if (rect->bottom > rgndata->rdh.rcBound.bottom)
3003         rgndata->rdh.rcBound.bottom = rect->bottom;
3004     }
3005   if ((hrgn = ExtCreateRegion (NULL, nbytes, rgndata)) == NULL)
3006     WIN32_API_FAILED ("ExtCreateRegion");
3007
3008   g_free (rgndata);
3009
3010   return (hrgn);
3011 }
3012
3013 static void
3014 gdk_win32_window_shape_combine_region (GdkWindow       *window,
3015                                        const cairo_region_t *shape_region,
3016                                        gint             offset_x,
3017                                        gint             offset_y)
3018 {
3019   if (GDK_WINDOW_DESTROYED (window))
3020     return;
3021
3022   if (!shape_region)
3023     {
3024       GDK_NOTE (MISC, g_print ("gdk_win32_window_shape_combine_region: %p: none\n",
3025                                GDK_WINDOW_HWND (window)));
3026       SetWindowRgn (GDK_WINDOW_HWND (window), NULL, TRUE);
3027     }
3028   else
3029     {
3030       HRGN hrgn;
3031
3032       hrgn = cairo_region_to_hrgn (shape_region, 0, 0);
3033       
3034       GDK_NOTE (MISC, g_print ("gdk_win32_window_shape_combine_region: %p: %p\n",
3035                                GDK_WINDOW_HWND (window),
3036                                hrgn));
3037
3038       do_shape_combine_region (window, hrgn, offset_x, offset_y);
3039     }
3040 }
3041
3042 GdkWindow *
3043 gdk_win32_window_lookup_for_display (GdkDisplay *display,
3044                                      HWND        anid)
3045 {
3046   g_return_val_if_fail (display == _gdk_display, NULL);
3047
3048   return (GdkWindow*) gdk_win32_handle_table_lookup (anid);
3049 }
3050
3051 static void
3052 gdk_win32_window_enable_synchronized_configure (GdkWindow *window)
3053 {
3054   /* nothing - no window manager to cooperate with */
3055 }
3056
3057 static void
3058 gdk_win32_window_configure_finished (GdkWindow *window)
3059 {
3060   /* nothing - no window manager to cooperate with */
3061 }
3062
3063 static void
3064 gdk_win32_window_set_opacity (GdkWindow *window,
3065                         gdouble    opacity)
3066 {
3067   LONG exstyle;
3068   typedef BOOL (*PFN_SetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
3069   PFN_SetLayeredWindowAttributes setLayeredWindowAttributes = NULL;
3070
3071   g_return_if_fail (GDK_IS_WINDOW (window));
3072   g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
3073
3074   if (GDK_WINDOW_DESTROYED (window))
3075     return;
3076
3077   if (opacity < 0)
3078     opacity = 0;
3079   else if (opacity > 1)
3080     opacity = 1;
3081
3082   exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
3083
3084   if (!(exstyle & WS_EX_LAYERED))
3085     API_CALL (SetWindowLong, (GDK_WINDOW_HWND (window),
3086                               GWL_EXSTYLE,
3087                               exstyle | WS_EX_LAYERED));
3088
3089   setLayeredWindowAttributes = 
3090     (PFN_SetLayeredWindowAttributes)GetProcAddress (GetModuleHandle ("user32.dll"), "SetLayeredWindowAttributes");
3091
3092   if (setLayeredWindowAttributes)
3093     {
3094       API_CALL (setLayeredWindowAttributes, (GDK_WINDOW_HWND (window),
3095                                              0,
3096                                              opacity * 0xff,
3097                                              LWA_ALPHA));
3098     }
3099 }
3100
3101 static cairo_region_t *
3102 gdk_win32_window_get_shape (GdkWindow *window)
3103 {
3104   HRGN hrgn = CreateRectRgn (0, 0, 0, 0);
3105   int  type = GetWindowRgn (GDK_WINDOW_HWND (window), hrgn);
3106
3107   if (type == SIMPLEREGION || type == COMPLEXREGION)
3108     {
3109       cairo_region_t *region = _gdk_win32_hrgn_to_region (hrgn);
3110
3111       DeleteObject (hrgn);
3112       return region;
3113     }
3114
3115   return NULL;
3116 }
3117
3118 static gboolean
3119 _gdk_win32_window_queue_antiexpose (GdkWindow *window,
3120                                     cairo_region_t *area)
3121 {
3122   HRGN hrgn = cairo_region_to_hrgn (area, 0, 0);
3123
3124   GDK_NOTE (EVENTS, g_print ("_gdk_windowing_window_queue_antiexpose: ValidateRgn %p %s\n",
3125                              GDK_WINDOW_HWND (window),
3126                              _gdk_win32_cairo_region_to_string (area)));
3127
3128   ValidateRgn (GDK_WINDOW_HWND (window), hrgn);
3129
3130   DeleteObject (hrgn);
3131
3132   return FALSE;
3133 }
3134
3135 /* Gets called from gdwindow.c(do_move_region_bits_on_impl)
3136  * and got tested with testgtk::big_window. Given the previous,
3137  * untested implementation this one looks much too simple ;)
3138  */
3139 static void
3140 _gdk_win32_window_translate (GdkWindow *window,
3141                              cairo_region_t *area, /* In impl window coords */
3142                              gint       dx,
3143                              gint       dy)
3144 {
3145   GdkRectangle extents;
3146   RECT rect;
3147
3148   cairo_region_get_extents (area, &extents);
3149   rect.left = extents.x - dx;
3150   rect.top = extents.y - dy;
3151   rect.right = rect.left + extents.width;
3152   rect.bottom = rect.top + extents.height;
3153
3154   API_CALL (ScrollWindowEx, (GDK_WINDOW_HWND (window), 
3155                              dx, dy, &rect, 
3156                              NULL, NULL, NULL, 
3157                              SW_INVALIDATE));
3158
3159 }
3160
3161 static void
3162 gdk_win32_input_shape_combine_region (GdkWindow *window,
3163                                       const cairo_region_t *shape_region,
3164                                       gint offset_x,
3165                                       gint offset_y)
3166 {
3167   if (GDK_WINDOW_DESTROYED (window))
3168     return;
3169   /* CHECK: are these really supposed to be the same? */
3170   gdk_win32_window_shape_combine_region (window, shape_region, offset_x, offset_y);
3171 }
3172
3173 static void
3174 gdk_win32_window_process_updates_recurse (GdkWindow *window,
3175                                                cairo_region_t *region)
3176 {
3177   _gdk_window_process_updates_recurse (window, region);
3178 }
3179
3180 gboolean
3181 gdk_win32_window_is_win32 (GdkWindow *window)
3182 {
3183   return GDK_WINDOW_IS_WIN32 (window);
3184 }
3185
3186 /**
3187  * _gdk_win32_acquire_dc
3188  * @impl: a Win32 #GdkWindowImplWin32 implementation
3189  * 
3190  * Gets a DC with the given drawable selected into it.
3191  *
3192  * Return value: The DC, on success. Otherwise
3193  *  %NULL. If this function succeeded
3194  *  _gdk_win32_impl_release_dc()  must be called
3195  *  release the DC when you are done using it.
3196  **/
3197 static HDC 
3198 _gdk_win32_impl_acquire_dc (GdkWindowImplWin32 *impl)
3199 {
3200   if (GDK_IS_WINDOW_IMPL_WIN32 (impl) &&
3201       GDK_WINDOW_DESTROYED (impl->wrapper))
3202     return NULL;
3203
3204   if (!impl->hdc)
3205     {
3206       impl->hdc = GetDC (impl->handle);
3207       if (!impl->hdc)
3208         WIN32_GDI_FAILED ("GetDC");
3209     }
3210
3211   if (impl->hdc)
3212     {
3213       impl->hdc_count++;
3214       return impl->hdc;
3215     }
3216   else
3217     {
3218       return NULL;
3219     }
3220 }
3221
3222 /**
3223  * _gdk_win32_impl_release_dc
3224  * @impl: a Win32 #GdkWindowImplWin32 implementation
3225  * 
3226  * Releases the reference count for the DC
3227  * from _gdk_win32_impl_acquire_dc()
3228  **/
3229 static void
3230 _gdk_win32_impl_release_dc (GdkWindowImplWin32 *impl)
3231 {
3232   g_return_if_fail (impl->hdc_count > 0);
3233
3234   impl->hdc_count--;
3235   if (impl->hdc_count == 0)
3236     {
3237       if (impl->saved_dc_bitmap)
3238         {
3239           GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
3240           impl->saved_dc_bitmap = NULL;
3241         }
3242       
3243       if (impl->hdc)
3244         {
3245           GDI_CALL (ReleaseDC, (impl->handle, impl->hdc));
3246           impl->hdc = NULL;
3247         }
3248     }
3249 }
3250
3251 static void
3252 gdk_win32_cairo_surface_destroy (void *data)
3253 {
3254   GdkWindowImplWin32 *impl = data;
3255
3256   _gdk_win32_impl_release_dc (impl);
3257   impl->cairo_surface = NULL;
3258 }
3259
3260 static cairo_surface_t *
3261 gdk_win32_ref_cairo_surface (GdkWindow *window)
3262 {
3263   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
3264
3265   if (GDK_IS_WINDOW_IMPL_WIN32 (impl) &&
3266       GDK_WINDOW_DESTROYED (impl->wrapper))
3267     return NULL;
3268
3269   if (!impl->cairo_surface)
3270     {
3271       HDC hdc = _gdk_win32_impl_acquire_dc (impl);
3272       if (!hdc)
3273         return NULL;
3274
3275       impl->cairo_surface = cairo_win32_surface_create (hdc);
3276
3277       cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
3278                                    impl, gdk_win32_cairo_surface_destroy);
3279     }
3280   else
3281     cairo_surface_reference (impl->cairo_surface);
3282
3283   return impl->cairo_surface;
3284 }
3285
3286 static void
3287 gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
3288 {
3289   GObjectClass *object_class = G_OBJECT_CLASS (klass);
3290   GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
3291
3292   parent_class = g_type_class_peek_parent (klass);
3293
3294   object_class->finalize = gdk_window_impl_win32_finalize;
3295   
3296   impl_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
3297
3298   impl_class->show = gdk_win32_window_show;
3299   impl_class->hide = gdk_win32_window_hide;
3300   impl_class->withdraw = gdk_win32_window_withdraw;
3301   impl_class->set_events = gdk_win32_window_set_events;
3302   impl_class->get_events = gdk_win32_window_get_events;
3303   impl_class->raise = gdk_win32_window_raise;
3304   impl_class->lower = gdk_win32_window_lower;
3305   impl_class->restack_under = gdk_win32_window_restack_under;
3306   impl_class->restack_toplevel = gdk_win32_window_restack_toplevel;
3307   impl_class->move_resize = gdk_win32_window_move_resize;
3308   impl_class->set_background = gdk_win32_window_set_background;
3309   impl_class->reparent = gdk_win32_window_reparent;
3310   impl_class->set_device_cursor = gdk_win32_window_set_device_cursor;
3311   impl_class->get_geometry = gdk_win32_window_get_geometry;
3312   impl_class->get_device_state = gdk_window_win32_get_device_state;
3313   impl_class->get_root_coords = gdk_win32_window_get_root_coords;
3314
3315   impl_class->shape_combine_region = gdk_win32_window_shape_combine_region;
3316   impl_class->input_shape_combine_region = gdk_win32_input_shape_combine_region;
3317   impl_class->set_static_gravities = gdk_win32_window_set_static_gravities;
3318   impl_class->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
3319   impl_class->translate = _gdk_win32_window_translate;
3320   impl_class->destroy = gdk_win32_window_destroy;
3321   impl_class->destroy_foreign = gdk_win32_window_destroy_foreign;
3322   impl_class->resize_cairo_surface = gdk_win32_window_resize_cairo_surface;
3323   impl_class->get_shape = gdk_win32_window_get_shape;
3324   //FIXME?: impl_class->get_input_shape = gdk_win32_window_get_input_shape;
3325
3326   //impl_class->beep = gdk_x11_window_beep;
3327
3328   impl_class->focus = gdk_win32_window_focus;
3329   impl_class->set_type_hint = gdk_win32_window_set_type_hint;
3330   impl_class->get_type_hint = gdk_win32_window_get_type_hint;
3331   impl_class->set_modal_hint = gdk_win32_window_set_modal_hint;
3332   impl_class->set_skip_taskbar_hint = gdk_win32_window_set_skip_taskbar_hint;
3333   impl_class->set_skip_pager_hint = gdk_win32_window_set_skip_pager_hint;
3334   impl_class->set_urgency_hint = gdk_win32_window_set_urgency_hint;
3335   impl_class->set_geometry_hints = gdk_win32_window_set_geometry_hints;
3336   impl_class->set_title = gdk_win32_window_set_title;
3337   impl_class->set_role = gdk_win32_window_set_role;
3338   //impl_class->set_startup_id = gdk_x11_window_set_startup_id;
3339   impl_class->set_transient_for = gdk_win32_window_set_transient_for;
3340   impl_class->get_root_origin = gdk_win32_window_get_root_origin;
3341   impl_class->get_frame_extents = gdk_win32_window_get_frame_extents;
3342   impl_class->set_override_redirect = gdk_win32_window_set_override_redirect;
3343   impl_class->set_accept_focus = gdk_win32_window_set_accept_focus;
3344   impl_class->set_focus_on_map = gdk_win32_window_set_focus_on_map;
3345   impl_class->set_icon_list = gdk_win32_window_set_icon_list;
3346   impl_class->set_icon_name = gdk_win32_window_set_icon_name;
3347   impl_class->iconify = gdk_win32_window_iconify;
3348   impl_class->deiconify = gdk_win32_window_deiconify;
3349   impl_class->stick = gdk_win32_window_stick;
3350   impl_class->unstick = gdk_win32_window_unstick;
3351   impl_class->maximize = gdk_win32_window_maximize;
3352   impl_class->unmaximize = gdk_win32_window_unmaximize;
3353   impl_class->fullscreen = gdk_win32_window_fullscreen;
3354   impl_class->unfullscreen = gdk_win32_window_unfullscreen;
3355   impl_class->set_keep_above = gdk_win32_window_set_keep_above;
3356   impl_class->set_keep_below = gdk_win32_window_set_keep_below;
3357   impl_class->get_group = gdk_win32_window_get_group;
3358   impl_class->set_group = gdk_win32_window_set_group;
3359   impl_class->set_decorations = gdk_win32_window_set_decorations;
3360   impl_class->get_decorations = gdk_win32_window_get_decorations;
3361   impl_class->set_functions = gdk_win32_window_set_functions;
3362
3363   impl_class->begin_resize_drag = gdk_win32_window_begin_resize_drag;
3364   impl_class->begin_move_drag = gdk_win32_window_begin_move_drag;
3365   impl_class->enable_synchronized_configure = gdk_win32_window_enable_synchronized_configure;
3366   impl_class->configure_finished = gdk_win32_window_configure_finished;
3367   impl_class->set_opacity = gdk_win32_window_set_opacity;
3368   //impl_class->set_composited = gdk_win32_window_set_composited;
3369   impl_class->destroy_notify = gdk_win32_window_destroy_notify;
3370   impl_class->get_drag_protocol = _gdk_win32_window_get_drag_protocol;
3371   impl_class->register_dnd = _gdk_win32_window_register_dnd;
3372   impl_class->drag_begin = _gdk_win32_window_drag_begin;
3373   impl_class->process_updates_recurse = gdk_win32_window_process_updates_recurse;
3374   //? impl_class->sync_rendering = _gdk_win32_window_sync_rendering;
3375   impl_class->simulate_key = _gdk_win32_window_simulate_key;
3376   impl_class->simulate_button = _gdk_win32_window_simulate_button;
3377   impl_class->get_property = _gdk_win32_window_get_property;
3378   impl_class->change_property = _gdk_win32_window_change_property;
3379   impl_class->delete_property = _gdk_win32_window_delete_property;
3380 }
3381
3382 HGDIOBJ
3383 gdk_win32_window_get_handle (GdkWindow *window)
3384 {
3385   /* Try to ensure the window has a native window */
3386   if (!_gdk_window_has_impl (window))
3387     gdk_window_ensure_native (window);
3388
3389   if (!GDK_WINDOW_IS_WIN32 (window))
3390     {
3391       g_warning (G_STRLOC " window is not a native Win32 window");
3392       return NULL;
3393     }
3394
3395   return GDK_WINDOW_HWND (window);
3396 }