]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkwindow-win32.c
win32: Don't remove the window from the handle table on destroy
[~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
757 static cairo_surface_t *
758 gdk_win32_window_resize_cairo_surface (GdkWindow       *window,
759                                        cairo_surface_t *surface,
760                                        gint             width,
761                                        gint             height)
762 {
763   /* XXX: Make Cairo surface use DC clip */
764   cairo_surface_destroy (surface);
765
766   return NULL;
767 }
768
769 static void
770 gdk_win32_window_destroy_foreign (GdkWindow *window)
771 {
772   /* It's somebody else's window, but in our hierarchy, so reparent it
773    * to the desktop, and then try to destroy it.
774    */
775   gdk_window_hide (window);
776   gdk_window_reparent (window, NULL, 0, 0);
777   
778   PostMessage (GDK_WINDOW_HWND (window), WM_CLOSE, 0, 0);
779 }
780
781 /* This function is called when the window really gone.
782  */
783 static void
784 gdk_win32_window_destroy_notify (GdkWindow *window)
785 {
786   g_return_if_fail (GDK_IS_WINDOW (window));
787
788   GDK_NOTE (EVENTS,
789             g_print ("gdk_window_destroy_notify: %p%s\n",
790                      GDK_WINDOW_HWND (window),
791                      (GDK_WINDOW_DESTROYED (window) ? " (destroyed)" : "")));
792
793   if (!GDK_WINDOW_DESTROYED (window))
794     {
795       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
796         g_warning ("window %p unexpectedly destroyed",
797                    GDK_WINDOW_HWND (window));
798
799       _gdk_window_destroy (window, TRUE);
800     }
801   
802   gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
803   g_object_unref (window);
804 }
805
806 static void
807 get_outer_rect (GdkWindow *window,
808                 gint       width,
809                 gint       height,
810                 RECT      *rect)
811 {
812   rect->left = rect->top = 0;
813   rect->right = width;
814   rect->bottom = height;
815       
816   _gdk_win32_adjust_client_rect (window, rect);
817 }
818
819 static void
820 adjust_for_gravity_hints (GdkWindow *window,
821                           RECT      *outer_rect,
822                           gint          *x,
823                           gint          *y)
824 {
825   GdkWindowImplWin32 *impl;
826
827   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
828
829   if (impl->hint_flags & GDK_HINT_WIN_GRAVITY)
830     {
831       gint orig_x = *x, orig_y = *y;
832
833       switch (impl->hints.win_gravity)
834         {
835         case GDK_GRAVITY_NORTH:
836         case GDK_GRAVITY_CENTER:
837         case GDK_GRAVITY_SOUTH:
838           *x -= (outer_rect->right - outer_rect->left) / 2;
839           *x += window->width / 2;
840           break;
841               
842         case GDK_GRAVITY_SOUTH_EAST:
843         case GDK_GRAVITY_EAST:
844         case GDK_GRAVITY_NORTH_EAST:
845           *x -= outer_rect->right - outer_rect->left;
846           *x += window->width;
847           break;
848
849         case GDK_GRAVITY_STATIC:
850           *x += outer_rect->left;
851           break;
852
853         default:
854           break;
855         }
856
857       switch (impl->hints.win_gravity)
858         {
859         case GDK_GRAVITY_WEST:
860         case GDK_GRAVITY_CENTER:
861         case GDK_GRAVITY_EAST:
862           *y -= (outer_rect->bottom - outer_rect->top) / 2;
863           *y += window->height / 2;
864           break;
865
866         case GDK_GRAVITY_SOUTH_WEST:
867         case GDK_GRAVITY_SOUTH:
868         case GDK_GRAVITY_SOUTH_EAST:
869           *y -= outer_rect->bottom - outer_rect->top;
870           *y += window->height;
871           break;
872
873         case GDK_GRAVITY_STATIC:
874           *y += outer_rect->top;
875           break;
876
877         default:
878           break;
879         }
880       GDK_NOTE (MISC,
881                 (orig_x != *x || orig_y != *y) ?
882                 g_print ("adjust_for_gravity_hints: x: %d->%d, y: %d->%d\n",
883                          orig_x, *x, orig_y, *y)
884                   : (void) 0);
885     }
886 }
887
888 static void
889 show_window_internal (GdkWindow *window,
890                       gboolean   already_mapped,
891                       gboolean   deiconify)
892 {
893   HWND old_active_window;
894   gboolean focus_on_map = FALSE;
895   DWORD exstyle;
896
897   if (window->destroyed)
898     return;
899
900   GDK_NOTE (MISC, g_print ("show_window_internal: %p: %s%s\n",
901                            GDK_WINDOW_HWND (window),
902                            _gdk_win32_window_state_to_string (window->state),
903                            (deiconify ? " deiconify" : "")));
904   
905   /* If asked to show (not deiconify) an withdrawn and iconified
906    * window, do that.
907    */
908   if (!deiconify &&
909       !already_mapped &&
910       (window->state & GDK_WINDOW_STATE_ICONIFIED))
911     {   
912       ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMINNOACTIVE);
913       return;
914     }
915   
916   /* If asked to just show an iconified window, do nothing. */
917   if (!deiconify && (window->state & GDK_WINDOW_STATE_ICONIFIED))
918     return;
919   
920   /* If asked to deiconify an already noniconified window, do
921    * nothing. (Especially, don't cause the window to rise and
922    * activate. There are different calls for that.)
923    */
924   if (deiconify && !(window->state & GDK_WINDOW_STATE_ICONIFIED))
925     return;
926   
927   /* If asked to show (but not raise) a window that is already
928    * visible, do nothing.
929    */
930   if (!deiconify && !already_mapped && IsWindowVisible (GDK_WINDOW_HWND (window)))
931     return;
932
933   /* Other cases */
934   
935   if (!already_mapped)
936     focus_on_map = window->focus_on_map;
937
938   exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
939
940   /* Use SetWindowPos to show transparent windows so automatic redraws
941    * in other windows can be suppressed.
942    */
943   if (exstyle & WS_EX_TRANSPARENT)
944     {
945       UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
946
947       if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP || !focus_on_map)
948         flags |= SWP_NOACTIVATE;
949
950       SetWindowPos (GDK_WINDOW_HWND (window), HWND_TOP, 0, 0, 0, 0, flags);
951
952       return;
953     }
954
955   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
956     {
957       gdk_window_fullscreen (window);
958     }
959   else if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
960     {
961       ShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
962     }
963   else if (window->state & GDK_WINDOW_STATE_ICONIFIED)
964     {
965       if (focus_on_map)
966         ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
967       else
968         ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNOACTIVATE);
969     }
970   else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP || !focus_on_map)
971     {
972       ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNOACTIVATE);
973     }
974   else
975     {
976       ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNORMAL);
977     }
978
979   /* Sync STATE_ABOVE to TOPMOST */
980   if (((window->state & GDK_WINDOW_STATE_ABOVE) &&
981        !(exstyle & WS_EX_TOPMOST)) ||
982       (!(window->state & GDK_WINDOW_STATE_ABOVE) &&
983        (exstyle & WS_EX_TOPMOST)))
984     {
985       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
986                                (window->state & GDK_WINDOW_STATE_ABOVE)?HWND_TOPMOST:HWND_NOTOPMOST,
987                                0, 0, 0, 0,
988                                SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
989     }
990 }
991
992 static void
993 gdk_win32_window_show (GdkWindow *window, 
994                        gboolean already_mapped)
995 {
996   show_window_internal (window, FALSE, FALSE);
997 }
998
999 static void
1000 gdk_win32_window_hide (GdkWindow *window)
1001 {
1002   if (window->destroyed)
1003     return;
1004
1005   GDK_NOTE (MISC, g_print ("gdk_win32_window_hide: %p: %s\n",
1006                            GDK_WINDOW_HWND (window),
1007                            _gdk_win32_window_state_to_string (window->state)));
1008   
1009   if (GDK_WINDOW_IS_MAPPED (window))
1010     gdk_synthesize_window_state (window,
1011                                  0,
1012                                  GDK_WINDOW_STATE_WITHDRAWN);
1013   
1014   _gdk_window_clear_update_area (window);
1015   
1016   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL)
1017     ShowOwnedPopups (GDK_WINDOW_HWND (window), FALSE);
1018   
1019   if (GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT)
1020     {
1021       SetWindowPos (GDK_WINDOW_HWND (window), HWND_BOTTOM,
1022                     0, 0, 0, 0,
1023                     SWP_HIDEWINDOW | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
1024     }
1025   else
1026     {
1027       ShowWindow (GDK_WINDOW_HWND (window), SW_HIDE);
1028     }
1029 }
1030
1031 static void
1032 gdk_win32_window_withdraw (GdkWindow *window)
1033 {
1034   if (window->destroyed)
1035     return;
1036
1037   GDK_NOTE (MISC, g_print ("gdk_win32_window_withdraw: %p: %s\n",
1038                            GDK_WINDOW_HWND (window),
1039                            _gdk_win32_window_state_to_string (window->state)));
1040
1041   gdk_window_hide (window);     /* ??? */
1042 }
1043
1044 static void
1045 gdk_win32_window_move (GdkWindow *window,
1046                        gint x, gint y)
1047 {
1048   GdkWindowImplWin32 *impl;
1049
1050   g_return_if_fail (GDK_IS_WINDOW (window));
1051
1052   if (GDK_WINDOW_DESTROYED (window))
1053     return;
1054
1055   GDK_NOTE (MISC, g_print ("gdk_win32_window_move: %p: %+d%+d\n",
1056                            GDK_WINDOW_HWND (window), x, y));
1057
1058   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1059
1060   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1061     return;
1062
1063   /* Don't check GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD.
1064    * Foreign windows (another app's windows) might be children of our
1065    * windows! Especially in the case of gtkplug/socket.
1066    */
1067   if (GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) != GetDesktopWindow ())
1068     {
1069       _gdk_window_move_resize_child (window, x, y, window->width, window->height);
1070     }
1071   else
1072     {
1073       RECT outer_rect;
1074
1075       get_outer_rect (window, window->width, window->height, &outer_rect);
1076
1077       adjust_for_gravity_hints (window, &outer_rect, &x, &y);
1078
1079       GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,0,0,"
1080                                "NOACTIVATE|NOSIZE|NOZORDER)\n",
1081                                GDK_WINDOW_HWND (window),
1082                                x - _gdk_offset_x, y - _gdk_offset_y));
1083
1084       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
1085                                x - _gdk_offset_x, y - _gdk_offset_y, 0, 0,
1086                                SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
1087     }
1088 }
1089
1090 static void
1091 gdk_win32_window_resize (GdkWindow *window,
1092                          gint width, gint height)
1093 {
1094   GdkWindowImplWin32 *impl;
1095
1096   g_return_if_fail (GDK_IS_WINDOW (window));
1097
1098   if (GDK_WINDOW_DESTROYED (window))
1099     return;
1100
1101   if (width < 1)
1102     width = 1;
1103   if (height < 1)
1104     height = 1;
1105
1106   GDK_NOTE (MISC, g_print ("gdk_win32_window_resize: %p: %dx%d\n",
1107                            GDK_WINDOW_HWND (window), width, height));
1108
1109   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1110
1111   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1112     return;
1113
1114   if (GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) != GetDesktopWindow ())
1115     {
1116       _gdk_window_move_resize_child (window, window->x, window->y, width, height);
1117     }
1118   else
1119     {
1120       RECT outer_rect;
1121
1122       get_outer_rect (window, width, height, &outer_rect);
1123
1124       GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,0,0,%ld,%ld,"
1125                                "NOACTIVATE|NOMOVE|NOZORDER)\n",
1126                                GDK_WINDOW_HWND (window),
1127                                outer_rect.right - outer_rect.left,
1128                                outer_rect.bottom - outer_rect.top));
1129
1130       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
1131                                0, 0,
1132                                outer_rect.right - outer_rect.left,
1133                                outer_rect.bottom - outer_rect.top,
1134                                SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER));
1135       window->resize_count += 1;
1136     }
1137 }
1138
1139 static void
1140 gdk_win32_window_move_resize_internal (GdkWindow *window,
1141                                        gint       x,
1142                                        gint       y,
1143                                        gint       width,
1144                                        gint       height)
1145 {
1146   GdkWindowImplWin32 *impl;
1147
1148   g_return_if_fail (GDK_IS_WINDOW (window));
1149
1150   if (GDK_WINDOW_DESTROYED (window))
1151     return;
1152
1153   if (width < 1)
1154     width = 1;
1155   if (height < 1)
1156     height = 1;
1157
1158   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1159
1160   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1161     return;
1162
1163   GDK_NOTE (MISC, g_print ("gdk_win32_window_move_resize: %p: %dx%d@%+d%+d\n",
1164                            GDK_WINDOW_HWND (window),
1165                            width, height, x, y));
1166
1167   if (GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) != GetDesktopWindow ())
1168     {
1169       _gdk_window_move_resize_child (window, x, y, width, height);
1170     }
1171   else
1172     {
1173       RECT outer_rect;
1174
1175       get_outer_rect (window, width, height, &outer_rect);
1176
1177       adjust_for_gravity_hints (window, &outer_rect, &x, &y);
1178
1179       GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%ld,%ld,"
1180                                "NOACTIVATE|NOZORDER)\n",
1181                                GDK_WINDOW_HWND (window),
1182                                x - _gdk_offset_x, y - _gdk_offset_y,
1183                                outer_rect.right - outer_rect.left,
1184                                outer_rect.bottom - outer_rect.top));
1185
1186       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
1187                                x - _gdk_offset_x, y - _gdk_offset_y,
1188                                outer_rect.right - outer_rect.left,
1189                                outer_rect.bottom - outer_rect.top,
1190                                SWP_NOACTIVATE | SWP_NOZORDER));
1191     }
1192 }
1193
1194 static void
1195 gdk_win32_window_move_resize (GdkWindow *window,
1196                               gboolean   with_move,
1197                               gint       x,
1198                               gint       y,
1199                               gint       width,
1200                               gint       height)
1201 {
1202   /* We ignore changes to the window being moved or resized by the 
1203      user, as we don't want to fight the user */
1204   if (GDK_WINDOW_HWND (window) == _modal_move_resize_window)
1205     return;
1206
1207   if (with_move && (width < 0 && height < 0))
1208     {
1209       gdk_win32_window_move (window, x, y);
1210     }
1211   else
1212     {
1213       if (with_move)
1214         {
1215           gdk_win32_window_move_resize_internal (window, x, y, width, height);
1216         }
1217       else
1218         {
1219           gdk_win32_window_resize (window, width, height);
1220         }
1221     }
1222 }
1223
1224 static gboolean
1225 gdk_win32_window_reparent (GdkWindow *window,
1226                            GdkWindow *new_parent,
1227                            gint       x,
1228                            gint       y)
1229 {
1230   GdkWindow *parent;
1231   GdkWindow *old_parent;
1232   GdkWindowImplWin32 *impl;
1233   gboolean was_toplevel;
1234   LONG style;
1235
1236   if (!new_parent)
1237     new_parent = _gdk_root;
1238
1239   old_parent = window->parent;
1240   parent = new_parent;
1241   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1242
1243   GDK_NOTE (MISC, g_print ("gdk_win32_window_reparent: %p: %p\n",
1244                            GDK_WINDOW_HWND (window),
1245                            GDK_WINDOW_HWND (new_parent)));
1246
1247   style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
1248
1249   was_toplevel = GetAncestor (GDK_WINDOW_HWND (window), GA_PARENT) == GetDesktopWindow ();
1250   if (was_toplevel && new_parent != _gdk_root)
1251     {
1252       /* Reparenting from top-level (child of desktop). Clear out
1253        * decorations.
1254        */
1255       style &= ~(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
1256       style |= WS_CHILD;
1257       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, style);
1258     }
1259   else if (new_parent == _gdk_root)
1260     {
1261       /* Reparenting to top-level. Add decorations. */
1262       style &= ~(WS_CHILD);
1263       style |= WS_OVERLAPPEDWINDOW;
1264       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, style);
1265     }
1266
1267   API_CALL (SetParent, (GDK_WINDOW_HWND (window),
1268                         GDK_WINDOW_HWND (new_parent)));
1269   
1270   API_CALL (MoveWindow, (GDK_WINDOW_HWND (window),
1271                          x, y, window->width, window->height, TRUE));
1272
1273   /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like
1274    * the root window
1275    */
1276   if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
1277     new_parent = _gdk_root;
1278   
1279   window->parent = new_parent;
1280
1281   /* Switch the window type as appropriate */
1282
1283   switch (GDK_WINDOW_TYPE (new_parent))
1284     {
1285     case GDK_WINDOW_ROOT:
1286       if (impl->toplevel_window_type != -1)
1287         GDK_WINDOW_TYPE (window) = impl->toplevel_window_type;
1288       else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1289         GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
1290       break;
1291
1292     case GDK_WINDOW_TOPLEVEL:
1293     case GDK_WINDOW_CHILD:
1294     case GDK_WINDOW_TEMP:
1295       if (WINDOW_IS_TOPLEVEL (window))
1296         {
1297           /* Save the original window type so we can restore it if the
1298            * window is reparented back to be a toplevel.
1299            */
1300           impl->toplevel_window_type = GDK_WINDOW_TYPE (window);
1301           GDK_WINDOW_TYPE (window) = GDK_WINDOW_CHILD;
1302         }
1303     }
1304
1305   if (old_parent)
1306     old_parent->children =
1307       g_list_remove (old_parent->children, window);
1308
1309   parent->children = g_list_prepend (parent->children, window);
1310
1311   return FALSE;
1312 }
1313
1314 static void
1315 gdk_win32_window_raise (GdkWindow *window)
1316 {
1317   if (!GDK_WINDOW_DESTROYED (window))
1318     {
1319       GDK_NOTE (MISC, g_print ("gdk_win32_window_raise: %p\n",
1320                                GDK_WINDOW_HWND (window)));
1321
1322       if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
1323         API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOPMOST,
1324                                  0, 0, 0, 0,
1325                                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
1326       else if (window->accept_focus)
1327         API_CALL (BringWindowToTop, (GDK_WINDOW_HWND (window)));
1328       else
1329         API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOP,
1330                                  0, 0, 0, 0,
1331                                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
1332     }
1333 }
1334
1335 static void
1336 gdk_win32_window_lower (GdkWindow *window)
1337 {
1338   if (!GDK_WINDOW_DESTROYED (window))
1339     {
1340       GDK_NOTE (MISC, g_print ("gdk_win32_window_lower: %p\n"
1341                                "... SetWindowPos(%p,HWND_BOTTOM,0,0,0,0,"
1342                                "NOACTIVATE|NOMOVE|NOSIZE)\n",
1343                                GDK_WINDOW_HWND (window),
1344                                GDK_WINDOW_HWND (window)));
1345
1346       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_BOTTOM,
1347                                0, 0, 0, 0,
1348                                SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
1349     }
1350 }
1351
1352 static void
1353 gdk_win32_window_set_urgency_hint (GdkWindow *window,
1354                              gboolean   urgent)
1355 {
1356   FLASHWINFO flashwinfo;
1357   typedef BOOL (*PFN_FlashWindowEx) (FLASHWINFO*);
1358   PFN_FlashWindowEx flashWindowEx = NULL;
1359
1360   g_return_if_fail (GDK_IS_WINDOW (window));
1361   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
1362   
1363   if (GDK_WINDOW_DESTROYED (window))
1364     return;
1365
1366   flashWindowEx = (PFN_FlashWindowEx) GetProcAddress (GetModuleHandle ("user32.dll"), "FlashWindowEx");
1367
1368   if (flashWindowEx)
1369     {
1370       flashwinfo.cbSize = sizeof (flashwinfo);
1371       flashwinfo.hwnd = GDK_WINDOW_HWND (window);
1372       if (urgent)
1373         flashwinfo.dwFlags = FLASHW_ALL | FLASHW_TIMER;
1374       else
1375         flashwinfo.dwFlags = FLASHW_STOP;
1376       flashwinfo.uCount = 0;
1377       flashwinfo.dwTimeout = 0;
1378       
1379       flashWindowEx (&flashwinfo);
1380     }
1381   else
1382     {
1383       FlashWindow (GDK_WINDOW_HWND (window), urgent);
1384     }
1385 }
1386
1387 static gboolean
1388 get_effective_window_decorations (GdkWindow       *window,
1389                                   GdkWMDecoration *decoration)
1390 {
1391   GdkWindowImplWin32 *impl;
1392
1393   impl = (GdkWindowImplWin32 *)window->impl;
1394
1395   if (gdk_window_get_decorations (window, decoration))
1396     return TRUE;
1397     
1398   if (window->window_type != GDK_WINDOW_TOPLEVEL) 
1399     {
1400       return FALSE;
1401     }
1402
1403   if ((impl->hint_flags & GDK_HINT_MIN_SIZE) &&
1404       (impl->hint_flags & GDK_HINT_MAX_SIZE) &&
1405       impl->hints.min_width == impl->hints.max_width &&
1406       impl->hints.min_height == impl->hints.max_height)
1407     {
1408       *decoration = GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MAXIMIZE;
1409
1410       if (impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1411           impl->type_hint == GDK_WINDOW_TYPE_HINT_MENU ||
1412           impl->type_hint == GDK_WINDOW_TYPE_HINT_TOOLBAR)
1413         {
1414           *decoration |= GDK_DECOR_MINIMIZE;
1415         }
1416       else if (impl->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN)
1417         {
1418           *decoration |= GDK_DECOR_MENU | GDK_DECOR_MINIMIZE;
1419         }
1420
1421       return TRUE;
1422     }
1423   else if (impl->hint_flags & GDK_HINT_MAX_SIZE)
1424     {
1425       *decoration = GDK_DECOR_ALL | GDK_DECOR_MAXIMIZE;
1426       if (impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1427           impl->type_hint == GDK_WINDOW_TYPE_HINT_MENU ||
1428           impl->type_hint == GDK_WINDOW_TYPE_HINT_TOOLBAR)
1429         {
1430           *decoration |= GDK_DECOR_MINIMIZE;
1431         }
1432
1433       return TRUE;
1434     }
1435   else
1436     {
1437       switch (impl->type_hint)
1438         {
1439         case GDK_WINDOW_TYPE_HINT_DIALOG:
1440           *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1441           return TRUE;
1442
1443         case GDK_WINDOW_TYPE_HINT_MENU:
1444           *decoration = (GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1445           return TRUE;
1446
1447         case GDK_WINDOW_TYPE_HINT_TOOLBAR:
1448         case GDK_WINDOW_TYPE_HINT_UTILITY:
1449           gdk_window_set_skip_taskbar_hint (window, TRUE);
1450           gdk_window_set_skip_pager_hint (window, TRUE);
1451           *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1452           return TRUE;
1453
1454         case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
1455           *decoration = (GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MENU |
1456                          GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1457           return TRUE;
1458           
1459         case GDK_WINDOW_TYPE_HINT_DOCK:
1460           return FALSE;
1461           
1462         case GDK_WINDOW_TYPE_HINT_DESKTOP:
1463           return FALSE;
1464
1465         default:
1466           /* Fall thru */
1467         case GDK_WINDOW_TYPE_HINT_NORMAL:
1468           *decoration = GDK_DECOR_ALL;
1469           return TRUE;
1470         }
1471     }
1472     
1473   return FALSE;
1474 }
1475
1476 static void
1477 gdk_win32_window_set_geometry_hints (GdkWindow         *window,
1478                                const GdkGeometry *geometry,
1479                                GdkWindowHints     geom_mask)
1480 {
1481   GdkWindowImplWin32 *impl;
1482
1483   g_return_if_fail (GDK_IS_WINDOW (window));
1484   
1485   if (GDK_WINDOW_DESTROYED (window))
1486     return;
1487
1488   GDK_NOTE (MISC, g_print ("gdk_window_set_geometry_hints: %p\n",
1489                            GDK_WINDOW_HWND (window)));
1490
1491   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1492
1493   impl->hint_flags = geom_mask;
1494   impl->hints = *geometry;
1495
1496   if (geom_mask & GDK_HINT_POS)
1497     ; /* even the X11 mplementation doesn't care */
1498
1499   if (geom_mask & GDK_HINT_MIN_SIZE)
1500     {
1501       GDK_NOTE (MISC, g_print ("... MIN_SIZE: %dx%d\n",
1502                                geometry->min_width, geometry->min_height));
1503     }
1504   
1505   if (geom_mask & GDK_HINT_MAX_SIZE)
1506     {
1507       GDK_NOTE (MISC, g_print ("... MAX_SIZE: %dx%d\n",
1508                                geometry->max_width, geometry->max_height));
1509     }
1510
1511   if (geom_mask & GDK_HINT_BASE_SIZE)
1512     {
1513       GDK_NOTE (MISC, g_print ("... BASE_SIZE: %dx%d\n",
1514                                geometry->base_width, geometry->base_height));
1515     }
1516   
1517   if (geom_mask & GDK_HINT_RESIZE_INC)
1518     {
1519       GDK_NOTE (MISC, g_print ("... RESIZE_INC: (%d,%d)\n",
1520                                geometry->width_inc, geometry->height_inc));
1521     }
1522   
1523   if (geom_mask & GDK_HINT_ASPECT)
1524     {
1525       GDK_NOTE (MISC, g_print ("... ASPECT: %g--%g\n",
1526                                geometry->min_aspect, geometry->max_aspect));
1527     }
1528
1529   if (geom_mask & GDK_HINT_WIN_GRAVITY)
1530     {
1531       GDK_NOTE (MISC, g_print ("... GRAVITY: %d\n", geometry->win_gravity));
1532     }
1533
1534   update_style_bits (window);
1535 }
1536
1537 static void
1538 gdk_win32_window_set_title (GdkWindow   *window,
1539                       const gchar *title)
1540 {
1541   wchar_t *wtitle;
1542
1543   g_return_if_fail (GDK_IS_WINDOW (window));
1544   g_return_if_fail (title != NULL);
1545
1546   if (GDK_WINDOW_DESTROYED (window))
1547     return;
1548
1549   /* Empty window titles not allowed, so set it to just a period. */
1550   if (!title[0])
1551     title = ".";
1552   
1553   GDK_NOTE (MISC, g_print ("gdk_window_set_title: %p: %s\n",
1554                            GDK_WINDOW_HWND (window), title));
1555   
1556   GDK_NOTE (MISC_OR_EVENTS, title = g_strdup_printf ("%p %s", GDK_WINDOW_HWND (window), title));
1557
1558   wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
1559   API_CALL (SetWindowTextW, (GDK_WINDOW_HWND (window), wtitle));
1560   g_free (wtitle);
1561
1562   GDK_NOTE (MISC_OR_EVENTS, g_free ((char *) title));
1563 }
1564
1565 static void
1566 gdk_win32_window_set_role (GdkWindow   *window,
1567                      const gchar *role)
1568 {
1569   g_return_if_fail (GDK_IS_WINDOW (window));
1570   
1571   GDK_NOTE (MISC, g_print ("gdk_window_set_role: %p: %s\n",
1572                            GDK_WINDOW_HWND (window),
1573                            (role ? role : "NULL")));
1574   /* XXX */
1575 }
1576
1577 static void
1578 gdk_win32_window_set_transient_for (GdkWindow *window, 
1579                               GdkWindow *parent)
1580 {
1581   HWND window_id, parent_id;
1582   GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1583   GdkWindowImplWin32 *parent_impl = NULL;
1584   GSList *item;
1585
1586   g_return_if_fail (GDK_IS_WINDOW (window));
1587
1588   window_id = GDK_WINDOW_HWND (window);
1589   parent_id = parent != NULL ? GDK_WINDOW_HWND (parent) : NULL;
1590
1591   GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %p: %p\n", window_id, parent_id));
1592
1593   if (GDK_WINDOW_DESTROYED (window) || (parent && GDK_WINDOW_DESTROYED (parent)))
1594     {
1595       if (GDK_WINDOW_DESTROYED (window))
1596         GDK_NOTE (MISC, g_print ("... destroyed!\n"));
1597       else
1598         GDK_NOTE (MISC, g_print ("... owner destroyed!\n"));
1599
1600       return;
1601     }
1602
1603   if (window->window_type == GDK_WINDOW_CHILD)
1604     {
1605       GDK_NOTE (MISC, g_print ("... a child window!\n"));
1606       return;
1607     }
1608
1609   if (parent == NULL)
1610     {
1611       GdkWindowImplWin32 *trans_impl = GDK_WINDOW_IMPL_WIN32 (window_impl->transient_owner->impl);
1612       if (trans_impl->transient_children != NULL)
1613         {
1614           item = g_slist_find (trans_impl->transient_children, window);
1615           item->data = NULL;
1616           trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
1617           trans_impl->num_transients--;
1618
1619           if (!trans_impl->num_transients)
1620             {
1621               trans_impl->transient_children = NULL;
1622             }
1623         }
1624       g_object_unref (G_OBJECT (window_impl->transient_owner));
1625       g_object_unref (G_OBJECT (window));
1626
1627       window_impl->transient_owner = NULL;
1628     }
1629   else
1630     {
1631       parent_impl = GDK_WINDOW_IMPL_WIN32 (parent->impl);
1632
1633       parent_impl->transient_children = g_slist_append (parent_impl->transient_children, window);
1634       g_object_ref (G_OBJECT (window));
1635       parent_impl->num_transients++;
1636       window_impl->transient_owner = parent;
1637       g_object_ref (G_OBJECT (parent));
1638     }
1639
1640   /* This changes the *owner* of the window, despite the misleading
1641    * name. (Owner and parent are unrelated concepts.) At least that's
1642    * what people who seem to know what they talk about say on
1643    * USENET. Search on Google.
1644    */
1645   SetLastError (0);
1646   if (SetWindowLongPtr (window_id, GWLP_HWNDPARENT, (LONG_PTR) parent_id) == 0 &&
1647       GetLastError () != 0)
1648     WIN32_API_FAILED ("SetWindowLongPtr");
1649 }
1650
1651 void
1652 _gdk_push_modal_window (GdkWindow *window)
1653 {
1654   modal_window_stack = g_slist_prepend (modal_window_stack,
1655                                         window);
1656 }
1657
1658 void
1659 _gdk_remove_modal_window (GdkWindow *window)
1660 {
1661   GSList *tmp;
1662
1663   g_return_if_fail (window != NULL);
1664
1665   /* It's possible to be NULL here if someone sets the modal hint of the window
1666    * to FALSE before a modal window stack has ever been created. */
1667   if (modal_window_stack == NULL)
1668     return;
1669
1670   /* Find the requested window in the stack and remove it.  Yeah, I realize this
1671    * means we're not a 'real stack', strictly speaking.  Sue me. :) */
1672   tmp = g_slist_find (modal_window_stack, window);
1673   if (tmp != NULL)
1674     {
1675       modal_window_stack = g_slist_delete_link (modal_window_stack, tmp);
1676     }
1677 }
1678
1679 GdkWindow *
1680 _gdk_modal_current (void)
1681 {
1682   if (modal_window_stack != NULL)
1683     {
1684       GSList *tmp = modal_window_stack;
1685
1686       while (tmp != NULL && !GDK_WINDOW_IS_MAPPED (GDK_WINDOW (tmp->data)))
1687         {
1688           tmp = g_slist_next (tmp);
1689         }
1690
1691       return tmp != NULL ? tmp->data : NULL;
1692     }
1693   else
1694     {
1695       return NULL;
1696     }
1697 }
1698
1699 static void
1700 gdk_win32_window_set_background (GdkWindow       *window,
1701                                  cairo_pattern_t *pattern)
1702 {
1703 }
1704
1705 static void
1706 gdk_win32_window_set_device_cursor (GdkWindow *window,
1707                                     GdkDevice *device,
1708                                     GdkCursor *cursor)
1709 {
1710   GdkWindowImplWin32 *impl;
1711   GdkWin32Cursor *cursor_private;
1712   HCURSOR hcursor;
1713   HCURSOR hprevcursor;
1714   
1715   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1716   cursor_private = (GdkWin32Cursor*) cursor;
1717   
1718   if (GDK_WINDOW_DESTROYED (window))
1719     return;
1720
1721   if (!cursor)
1722     hcursor = NULL;
1723   else
1724     hcursor = cursor_private->hcursor;
1725   
1726   GDK_NOTE (MISC, g_print ("gdk_win32_window_set_cursor: %p: %p\n",
1727                            GDK_WINDOW_HWND (window),
1728                            hcursor));
1729
1730   /* First get the old cursor, if any (we wait to free the old one
1731    * since it may be the current cursor set in the Win32 API right
1732    * now).
1733    */
1734   hprevcursor = impl->hcursor;
1735
1736   GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
1737
1738   if (hcursor == NULL)
1739     impl->hcursor = NULL;
1740   else
1741     {
1742       /* We must copy the cursor as it is OK to destroy the GdkCursor
1743        * while still in use for some window. See for instance
1744        * gimp_change_win_cursor() which calls gdk_window_set_cursor
1745        * (win, cursor), and immediately afterwards gdk_cursor_destroy
1746        * (cursor).
1747        */
1748       if ((impl->hcursor = CopyCursor (hcursor)) == NULL)
1749         WIN32_API_FAILED ("CopyCursor");
1750       GDK_NOTE (MISC, g_print ("... CopyCursor (%p) = %p\n",
1751                                hcursor, impl->hcursor));
1752     }
1753
1754   /* Destroy the previous cursor */
1755   if (hprevcursor != NULL)
1756     {
1757       GDK_NOTE (MISC, g_print ("... DestroyCursor (%p)\n", hprevcursor));
1758       API_CALL (DestroyCursor, (hprevcursor));
1759     }
1760 }
1761
1762 static void
1763 gdk_win32_window_get_geometry (GdkWindow *window,
1764                                gint      *x,
1765                                gint      *y,
1766                                gint      *width,
1767                                gint      *height)
1768 {
1769   if (!window)
1770     window = _gdk_root;
1771   
1772   if (!GDK_WINDOW_DESTROYED (window))
1773     {
1774       RECT rect;
1775
1776       API_CALL (GetClientRect, (GDK_WINDOW_HWND (window), &rect));
1777
1778       if (window != _gdk_root)
1779         {
1780           POINT pt;
1781           GdkWindow *parent = gdk_window_get_parent (window);
1782
1783           pt.x = rect.left;
1784           pt.y = rect.top;
1785           ClientToScreen (GDK_WINDOW_HWND (window), &pt);
1786           ScreenToClient (GDK_WINDOW_HWND (parent), &pt);
1787           rect.left = pt.x;
1788           rect.top = pt.y;
1789
1790           pt.x = rect.right;
1791           pt.y = rect.bottom;
1792           ClientToScreen (GDK_WINDOW_HWND (window), &pt);
1793           ScreenToClient (GDK_WINDOW_HWND (parent), &pt);
1794           rect.right = pt.x;
1795           rect.bottom = pt.y;
1796
1797           if (parent == _gdk_root)
1798             {
1799               rect.left += _gdk_offset_x;
1800               rect.top += _gdk_offset_y;
1801               rect.right += _gdk_offset_x;
1802               rect.bottom += _gdk_offset_y;
1803             }
1804         }
1805
1806       if (x)
1807         *x = rect.left;
1808       if (y)
1809         *y = rect.top;
1810       if (width)
1811         *width = rect.right - rect.left;
1812       if (height)
1813         *height = rect.bottom - rect.top;
1814
1815       GDK_NOTE (MISC, g_print ("gdk_win32_window_get_geometry: %p: %ldx%ldx%d@%+ld%+ld\n",
1816                                GDK_WINDOW_HWND (window),
1817                                rect.right - rect.left, rect.bottom - rect.top,
1818                                gdk_window_get_visual (window)->depth,
1819                                rect.left, rect.top));
1820     }
1821 }
1822
1823 static gint
1824 gdk_win32_window_get_root_coords (GdkWindow *window,
1825                                   gint       x,
1826                                   gint       y,
1827                                   gint      *root_x,
1828                                   gint      *root_y)
1829 {
1830   gint tx;
1831   gint ty;
1832   POINT pt;
1833
1834   pt.x = x;
1835   pt.y = y;
1836   ClientToScreen (GDK_WINDOW_HWND (window), &pt);
1837   tx = pt.x;
1838   ty = pt.y;
1839   
1840   if (root_x)
1841     *root_x = tx + _gdk_offset_x;
1842   if (root_y)
1843     *root_y = ty + _gdk_offset_y;
1844
1845   GDK_NOTE (MISC, g_print ("gdk_win32_window_get_root_coords: %p: %+d%+d %+d%+d\n",
1846                            GDK_WINDOW_HWND (window),
1847                            x, y,
1848                            tx + _gdk_offset_x, ty + _gdk_offset_y));
1849   return 1;
1850 }
1851
1852 static void
1853 gdk_win32_window_restack_under (GdkWindow *window,
1854                                 GList *native_siblings)
1855 {
1856         // ### TODO
1857 }
1858
1859 static void
1860 gdk_win32_window_restack_toplevel (GdkWindow *window,
1861                                    GdkWindow *sibling,
1862                                    gboolean   above)
1863 {
1864         // ### TODO
1865 }
1866
1867 static void
1868 gdk_win32_window_get_root_origin (GdkWindow *window,
1869                             gint      *x,
1870                             gint      *y)
1871 {
1872   GdkRectangle rect;
1873
1874   g_return_if_fail (GDK_IS_WINDOW (window));
1875
1876   gdk_window_get_frame_extents (window, &rect);
1877
1878   if (x)
1879     *x = rect.x;
1880
1881   if (y)
1882     *y = rect.y;
1883
1884   GDK_NOTE (MISC, g_print ("gdk_window_get_root_origin: %p: %+d%+d\n",
1885                            GDK_WINDOW_HWND (window), rect.x, rect.y));
1886 }
1887
1888 static void
1889 gdk_win32_window_get_frame_extents (GdkWindow    *window,
1890                               GdkRectangle *rect)
1891 {
1892   HWND hwnd;
1893   RECT r;
1894
1895   g_return_if_fail (GDK_IS_WINDOW (window));
1896   g_return_if_fail (rect != NULL);
1897
1898   rect->x = 0;
1899   rect->y = 0;
1900   rect->width = 1;
1901   rect->height = 1;
1902   
1903   if (GDK_WINDOW_DESTROYED (window))
1904     return;
1905
1906   /* FIXME: window is documented to be a toplevel GdkWindow, so is it really
1907    * necessary to walk its parent chain?
1908    */
1909   while (window->parent && window->parent->parent)
1910     window = window->parent;
1911
1912   hwnd = GDK_WINDOW_HWND (window);
1913   API_CALL (GetWindowRect, (hwnd, &r));
1914
1915   rect->x = r.left + _gdk_offset_x;
1916   rect->y = r.top + _gdk_offset_y;
1917   rect->width = r.right - r.left;
1918   rect->height = r.bottom - r.top;
1919
1920   GDK_NOTE (MISC, g_print ("gdk_window_get_frame_extents: %p: %ldx%ld@%+ld%+ld\n",
1921                            GDK_WINDOW_HWND (window),
1922                            r.right - r.left, r.bottom - r.top,
1923                            r.left, r.top));
1924 }
1925
1926 static gboolean
1927 gdk_window_win32_get_device_state (GdkWindow       *window,
1928                                    GdkDevice       *device,
1929                                    gint            *x,
1930                                    gint            *y,
1931                                    GdkModifierType *mask)
1932 {
1933   GdkWindow *child;
1934
1935   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
1936
1937   GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
1938                                               NULL, &child,
1939                                               NULL, NULL,
1940                                               x, y, mask);
1941   return (child != NULL);
1942 }
1943
1944 void
1945 _gdk_windowing_get_device_state (GdkDisplay       *display,
1946                                  GdkDevice        *device,
1947                                  GdkScreen       **screen,
1948                                  gint             *x,
1949                                  gint             *y,
1950                                  GdkModifierType  *mask)
1951 {
1952   g_return_if_fail (display == _gdk_display);
1953
1954   if (screen)
1955     *screen = _gdk_screen;
1956
1957   GDK_DEVICE_GET_CLASS (device)->query_state (device,
1958                                               gdk_screen_get_root_window (_gdk_screen),
1959                                               NULL, NULL,
1960                                               x, y,
1961                                               NULL, NULL,
1962                                               mask);
1963 }
1964
1965 void
1966 gdk_display_warp_device (GdkDisplay *display,
1967                          GdkDevice  *device,
1968                          GdkScreen  *screen,
1969                          gint        x,
1970                          gint        y)
1971 {
1972   g_return_if_fail (display == _gdk_display);
1973   g_return_if_fail (screen == _gdk_screen);
1974   g_return_if_fail (GDK_IS_DEVICE (device));
1975   g_return_if_fail (display == gdk_device_get_display (device));
1976
1977   GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
1978 }
1979
1980 GdkWindow*
1981 _gdk_windowing_window_at_device_position (GdkDisplay      *display,
1982                                           GdkDevice       *device,
1983                                           gint            *win_x,
1984                                           gint            *win_y,
1985                                           GdkModifierType *mask,
1986                                           gboolean         get_toplevel)
1987 {
1988   return GDK_DEVICE_GET_CLASS (device)->window_at_position (device, win_x, win_y, mask, get_toplevel);
1989 }
1990
1991 static GdkEventMask  
1992 gdk_win32_window_get_events (GdkWindow *window)
1993 {
1994   GdkWindowImplWin32 *impl;
1995
1996   if (GDK_WINDOW_DESTROYED (window))
1997     return 0;
1998
1999   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2000
2001   return impl->native_event_mask;
2002 }
2003
2004 static void          
2005 gdk_win32_window_set_events (GdkWindow   *window,
2006                              GdkEventMask event_mask)
2007 {
2008   GdkWindowImplWin32 *impl;
2009
2010   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2011
2012   /* gdk_window_new() always sets the GDK_STRUCTURE_MASK, so better
2013    * set it here, too. Not that I know or remember why it is
2014    * necessary, will have to test some day.
2015    */
2016   impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
2017 }
2018
2019 static void
2020 do_shape_combine_region (GdkWindow *window,
2021                          HRGN       hrgn,
2022                          gint       x, gint y)
2023 {
2024   RECT rect;
2025
2026   GetClientRect (GDK_WINDOW_HWND (window), &rect);
2027   _gdk_win32_adjust_client_rect (window, &rect);
2028
2029   OffsetRgn (hrgn, -rect.left, -rect.top);
2030   OffsetRgn (hrgn, x, y);
2031
2032   /* If this is a top-level window, add the title bar to the region */
2033   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL)
2034     {
2035       HRGN tmp = CreateRectRgn (0, 0, rect.right - rect.left, -rect.top);
2036       CombineRgn (hrgn, hrgn, tmp, RGN_OR);
2037       DeleteObject (tmp);
2038     }
2039   
2040   SetWindowRgn (GDK_WINDOW_HWND (window), hrgn, TRUE);
2041 }
2042
2043 static void
2044 gdk_win32_window_set_override_redirect (GdkWindow *window,
2045                                   gboolean   override_redirect)
2046 {
2047   g_return_if_fail (GDK_IS_WINDOW (window));
2048
2049   g_warning ("gdk_window_set_override_redirect not implemented");
2050 }
2051
2052 static void
2053 gdk_win32_window_set_accept_focus (GdkWindow *window,
2054                              gboolean accept_focus)
2055 {
2056   g_return_if_fail (GDK_IS_WINDOW (window));
2057
2058   accept_focus = accept_focus != FALSE;
2059
2060   if (window->accept_focus != accept_focus)
2061     window->accept_focus = accept_focus;
2062 }
2063
2064 static void
2065 gdk_win32_window_set_focus_on_map (GdkWindow *window,
2066                              gboolean focus_on_map)
2067 {
2068   g_return_if_fail (GDK_IS_WINDOW (window));
2069
2070   focus_on_map = focus_on_map != FALSE;
2071
2072   if (window->focus_on_map != focus_on_map)
2073     window->focus_on_map = focus_on_map;
2074 }
2075
2076 static void
2077 gdk_win32_window_set_icon_list (GdkWindow *window,
2078                           GList     *pixbufs)
2079 {
2080   GdkPixbuf *pixbuf, *big_pixbuf, *small_pixbuf;
2081   gint big_diff, small_diff;
2082   gint big_w, big_h, small_w, small_h;
2083   gint w, h;
2084   gint dw, dh, diff;
2085   HICON small_hicon, big_hicon;
2086   GdkWindowImplWin32 *impl;
2087   gint i, big_i, small_i;
2088
2089   g_return_if_fail (GDK_IS_WINDOW (window));
2090
2091   if (GDK_WINDOW_DESTROYED (window))
2092     return;
2093
2094   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2095
2096   /* ideal sizes for small and large icons */
2097   big_w = GetSystemMetrics (SM_CXICON);
2098   big_h = GetSystemMetrics (SM_CYICON);
2099   small_w = GetSystemMetrics (SM_CXSMICON);
2100   small_h = GetSystemMetrics (SM_CYSMICON);
2101
2102   /* find closest sized icons in the list */
2103   big_pixbuf = NULL;
2104   small_pixbuf = NULL;
2105   big_diff = 0;
2106   small_diff = 0;
2107   i = 0;
2108   while (pixbufs)
2109     {
2110       pixbuf = (GdkPixbuf*) pixbufs->data;
2111       w = gdk_pixbuf_get_width (pixbuf);
2112       h = gdk_pixbuf_get_height (pixbuf);
2113
2114       dw = ABS (w - big_w);
2115       dh = ABS (h - big_h);
2116       diff = dw*dw + dh*dh;
2117       if (big_pixbuf == NULL || diff < big_diff)
2118         {
2119           big_pixbuf = pixbuf;
2120           big_diff = diff;
2121           big_i = i;
2122         }
2123
2124       dw = ABS (w - small_w);
2125       dh = ABS (h - small_h);
2126       diff = dw*dw + dh*dh;
2127       if (small_pixbuf == NULL || diff < small_diff)
2128         {
2129           small_pixbuf = pixbuf;
2130           small_diff = diff;
2131           small_i = i;
2132         }
2133
2134       pixbufs = g_list_next (pixbufs);
2135       i++;
2136     }
2137
2138   /* Create the icons */
2139   big_hicon = _gdk_win32_pixbuf_to_hicon (big_pixbuf);
2140   small_hicon = _gdk_win32_pixbuf_to_hicon (small_pixbuf);
2141
2142   /* Set the icons */
2143   SendMessageW (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG,
2144                 (LPARAM)big_hicon);
2145   SendMessageW (GDK_WINDOW_HWND (window), WM_SETICON, ICON_SMALL,
2146                 (LPARAM)small_hicon);
2147
2148   /* Store the icons, destroying any previous icons */
2149   if (impl->hicon_big)
2150     GDI_CALL (DestroyIcon, (impl->hicon_big));
2151   impl->hicon_big = big_hicon;
2152   if (impl->hicon_small)
2153     GDI_CALL (DestroyIcon, (impl->hicon_small));
2154   impl->hicon_small = small_hicon;
2155 }
2156
2157 static void
2158 gdk_win32_window_set_icon_name (GdkWindow   *window, 
2159                           const gchar *name)
2160 {
2161   /* In case I manage to confuse this again (or somebody else does):
2162    * Please note that "icon name" here really *does* mean the name or
2163    * title of an window minimized as an icon on the desktop, or in the
2164    * taskbar. It has nothing to do with the freedesktop.org icon
2165    * naming stuff.
2166    */
2167
2168   g_return_if_fail (GDK_IS_WINDOW (window));
2169
2170   if (GDK_WINDOW_DESTROYED (window))
2171     return;
2172   
2173 #if 0
2174   /* This is not the correct thing to do. We should keep both the
2175    * "normal" window title, and the icon name. When the window is
2176    * minimized, call SetWindowText() with the icon name, and when the
2177    * window is restored, with the normal window title. Also, the name
2178    * is in UTF-8, so we should do the normal conversion to either wide
2179    * chars or system codepage, and use either the W or A version of
2180    * SetWindowText(), depending on Windows version.
2181    */
2182   API_CALL (SetWindowText, (GDK_WINDOW_HWND (window), name));
2183 #endif
2184 }
2185
2186 static GdkWindow *
2187 gdk_win32_window_get_group (GdkWindow *window)
2188 {
2189   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2190   g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL);
2191
2192   if (GDK_WINDOW_DESTROYED (window))
2193     return NULL;
2194   
2195   g_warning ("gdk_window_get_group not yet implemented");
2196
2197   return NULL;
2198 }
2199
2200 static void
2201 gdk_win32_window_set_group (GdkWindow *window, 
2202                       GdkWindow *leader)
2203 {
2204   g_return_if_fail (GDK_IS_WINDOW (window));
2205   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
2206   g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader));
2207
2208   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
2209     return;
2210   
2211   g_warning ("gdk_window_set_group not implemented");
2212 }
2213
2214 static void
2215 update_single_bit (LONG    *style,
2216                    gboolean all,
2217                    int      gdk_bit,
2218                    int      style_bit)
2219 {
2220   /* all controls the interpretation of gdk_bit -- if all is TRUE,
2221    * gdk_bit indicates whether style_bit is off; if all is FALSE, gdk
2222    * bit indicate whether style_bit is on
2223    */
2224   if ((!all && gdk_bit) || (all && !gdk_bit))
2225     *style |= style_bit;
2226   else
2227     *style &= ~style_bit;
2228 }
2229
2230 static void
2231 update_style_bits (GdkWindow *window)
2232 {
2233   GdkWindowImplWin32 *impl = (GdkWindowImplWin32 *)window->impl;
2234   GdkWMDecoration decorations;
2235   LONG old_style, new_style, old_exstyle, new_exstyle;
2236   gboolean all;
2237   RECT rect, before, after;
2238
2239   old_style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
2240   old_exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
2241
2242   GetClientRect (GDK_WINDOW_HWND (window), &before);
2243   after = before;
2244   AdjustWindowRectEx (&before, old_style, FALSE, old_exstyle);
2245
2246   new_style = old_style;
2247   new_exstyle = old_exstyle;
2248
2249   if (window->window_type == GDK_WINDOW_TEMP ||
2250       impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY)
2251     new_exstyle |= WS_EX_TOOLWINDOW;
2252   else
2253     new_exstyle &= ~WS_EX_TOOLWINDOW;
2254
2255   if (get_effective_window_decorations (window, &decorations))
2256     {
2257       all = (decorations & GDK_DECOR_ALL);
2258       update_single_bit (&new_style, all, decorations & GDK_DECOR_BORDER, WS_BORDER);
2259       update_single_bit (&new_style, all, decorations & GDK_DECOR_RESIZEH, WS_THICKFRAME);
2260       update_single_bit (&new_style, all, decorations & GDK_DECOR_TITLE, WS_CAPTION);
2261       update_single_bit (&new_style, all, decorations & GDK_DECOR_MENU, WS_SYSMENU);
2262       update_single_bit (&new_style, all, decorations & GDK_DECOR_MINIMIZE, WS_MINIMIZEBOX);
2263       update_single_bit (&new_style, all, decorations & GDK_DECOR_MAXIMIZE, WS_MAXIMIZEBOX);
2264     }
2265
2266   if (old_style == new_style && old_exstyle == new_exstyle )
2267     {
2268       GDK_NOTE (MISC, g_print ("update_style_bits: %p: no change\n",
2269                                GDK_WINDOW_HWND (window)));
2270       return;
2271     }
2272
2273   if (old_style != new_style)
2274     {
2275       GDK_NOTE (MISC, g_print ("update_style_bits: %p: STYLE: %s => %s\n",
2276                                GDK_WINDOW_HWND (window),
2277                                _gdk_win32_window_style_to_string (old_style),
2278                                _gdk_win32_window_style_to_string (new_style)));
2279       
2280       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, new_style);
2281     }
2282
2283   if (old_exstyle != new_exstyle)
2284     {
2285       GDK_NOTE (MISC, g_print ("update_style_bits: %p: EXSTYLE: %s => %s\n",
2286                                GDK_WINDOW_HWND (window),
2287                                _gdk_win32_window_exstyle_to_string (old_exstyle),
2288                                _gdk_win32_window_exstyle_to_string (new_exstyle)));
2289       
2290       SetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE, new_exstyle);
2291     }
2292
2293   AdjustWindowRectEx (&after, new_style, FALSE, new_exstyle);
2294
2295   GetWindowRect (GDK_WINDOW_HWND (window), &rect);
2296   rect.left += after.left - before.left;
2297   rect.top += after.top - before.top;
2298   rect.right += after.right - before.right;
2299   rect.bottom += after.bottom - before.bottom;
2300
2301   SetWindowPos (GDK_WINDOW_HWND (window), NULL,
2302                 rect.left, rect.top,
2303                 rect.right - rect.left, rect.bottom - rect.top,
2304                 SWP_FRAMECHANGED | SWP_NOACTIVATE | 
2305                 SWP_NOREPOSITION | SWP_NOZORDER);
2306
2307 }
2308
2309 static void
2310 update_single_system_menu_entry (HMENU    hmenu,
2311                                  gboolean all,
2312                                  int      gdk_bit,
2313                                  int      menu_entry)
2314 {
2315   /* all controls the interpretation of gdk_bit -- if all is TRUE,
2316    * gdk_bit indicates whether menu entry is disabled; if all is
2317    * FALSE, gdk bit indicate whether menu entry is enabled
2318    */
2319   if ((!all && gdk_bit) || (all && !gdk_bit))
2320     EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_ENABLED);
2321   else
2322     EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_GRAYED);
2323 }
2324
2325 static void
2326 update_system_menu (GdkWindow *window)
2327 {
2328   GdkWMFunction functions;
2329   BOOL all;
2330
2331   if (_gdk_window_get_functions (window, &functions))
2332     {
2333       HMENU hmenu = GetSystemMenu (GDK_WINDOW_HWND (window), FALSE);
2334
2335       all = (functions & GDK_FUNC_ALL);
2336       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_RESIZE, SC_SIZE);
2337       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MOVE, SC_MOVE);
2338       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MINIMIZE, SC_MINIMIZE);
2339       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MAXIMIZE, SC_MAXIMIZE);
2340       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_CLOSE, SC_CLOSE);
2341     }
2342 }
2343
2344 static GQuark
2345 get_decorations_quark ()
2346 {
2347   static GQuark quark = 0;
2348   
2349   if (!quark)
2350     quark = g_quark_from_static_string ("gdk-window-decorations");
2351   
2352   return quark;
2353 }
2354
2355 static void
2356 gdk_win32_window_set_decorations (GdkWindow      *window,
2357                             GdkWMDecoration decorations)
2358 {
2359   GdkWMDecoration* decorations_copy;
2360   
2361   g_return_if_fail (GDK_IS_WINDOW (window));
2362   
2363   GDK_NOTE (MISC, g_print ("gdk_window_set_decorations: %p: %s %s%s%s%s%s%s\n",
2364                            GDK_WINDOW_HWND (window),
2365                            (decorations & GDK_DECOR_ALL ? "clearing" : "setting"),
2366                            (decorations & GDK_DECOR_BORDER ? "BORDER " : ""),
2367                            (decorations & GDK_DECOR_RESIZEH ? "RESIZEH " : ""),
2368                            (decorations & GDK_DECOR_TITLE ? "TITLE " : ""),
2369                            (decorations & GDK_DECOR_MENU ? "MENU " : ""),
2370                            (decorations & GDK_DECOR_MINIMIZE ? "MINIMIZE " : ""),
2371                            (decorations & GDK_DECOR_MAXIMIZE ? "MAXIMIZE " : "")));
2372
2373   decorations_copy = g_malloc (sizeof (GdkWMDecoration));
2374   *decorations_copy = decorations;
2375   g_object_set_qdata_full (G_OBJECT (window), get_decorations_quark (), decorations_copy, g_free);
2376
2377   update_style_bits (window);
2378 }
2379
2380 static gboolean
2381 gdk_win32_window_get_decorations (GdkWindow       *window,
2382                             GdkWMDecoration *decorations)
2383 {
2384   GdkWMDecoration* decorations_set;
2385   
2386   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2387
2388   decorations_set = g_object_get_qdata (G_OBJECT (window), get_decorations_quark ());
2389   if (decorations_set)
2390     *decorations = *decorations_set;
2391
2392   return (decorations_set != NULL);
2393 }
2394
2395 static GQuark
2396 get_functions_quark ()
2397 {
2398   static GQuark quark = 0;
2399   
2400   if (!quark)
2401     quark = g_quark_from_static_string ("gdk-window-functions");
2402   
2403   return quark;
2404 }
2405
2406 static void
2407 gdk_win32_window_set_functions (GdkWindow    *window,
2408                           GdkWMFunction functions)
2409 {
2410   GdkWMFunction* functions_copy;
2411
2412   g_return_if_fail (GDK_IS_WINDOW (window));
2413   
2414   GDK_NOTE (MISC, g_print ("gdk_window_set_functions: %p: %s %s%s%s%s%s\n",
2415                            GDK_WINDOW_HWND (window),
2416                            (functions & GDK_FUNC_ALL ? "clearing" : "setting"),
2417                            (functions & GDK_FUNC_RESIZE ? "RESIZE " : ""),
2418                            (functions & GDK_FUNC_MOVE ? "MOVE " : ""),
2419                            (functions & GDK_FUNC_MINIMIZE ? "MINIMIZE " : ""),
2420                            (functions & GDK_FUNC_MAXIMIZE ? "MAXIMIZE " : ""),
2421                            (functions & GDK_FUNC_CLOSE ? "CLOSE " : "")));
2422
2423   functions_copy = g_malloc (sizeof (GdkWMFunction));
2424   *functions_copy = functions;
2425   g_object_set_qdata_full (G_OBJECT (window), get_functions_quark (), functions_copy, g_free);
2426
2427   update_system_menu (window);
2428 }
2429
2430 gboolean
2431 _gdk_window_get_functions (GdkWindow     *window,
2432                            GdkWMFunction *functions)
2433 {
2434   GdkWMDecoration* functions_set;
2435   
2436   functions_set = g_object_get_qdata (G_OBJECT (window), get_functions_quark ());
2437   if (functions_set)
2438     *functions = *functions_set;
2439
2440   return (functions_set != NULL);
2441 }
2442
2443 static gboolean 
2444 gdk_win32_window_set_static_gravities (GdkWindow *window,
2445                                  gboolean   use_static)
2446 {
2447   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2448
2449   return !use_static;
2450 }
2451
2452 static void
2453 gdk_win32_window_begin_resize_drag (GdkWindow     *window,
2454                               GdkWindowEdge  edge,
2455                               GdkDevice     *device,
2456                               gint           button,
2457                               gint           root_x,
2458                               gint           root_y,
2459                               guint32        timestamp)
2460 {
2461   WPARAM winedge;
2462   
2463   g_return_if_fail (GDK_IS_WINDOW (window));
2464   
2465   if (GDK_WINDOW_DESTROYED (window))
2466     return;
2467
2468   /* Tell Windows to start interactively resizing the window by pretending that
2469    * the left pointer button was clicked in the suitable edge or corner. This
2470    * will only work if the button is down when this function is called, and
2471    * will only work with button 1 (left), since Windows only allows window
2472    * dragging using the left mouse button.
2473    */
2474   if (button != 1)
2475     return;
2476   
2477   /* Must break the automatic grab that occured when the button was
2478    * pressed, otherwise it won't work.
2479    */
2480   gdk_display_pointer_ungrab (_gdk_display, 0);
2481
2482   switch (edge)
2483     {
2484     case GDK_WINDOW_EDGE_NORTH_WEST:
2485       winedge = HTTOPLEFT;
2486       break;
2487
2488     case GDK_WINDOW_EDGE_NORTH:
2489       winedge = HTTOP;
2490       break;
2491
2492     case GDK_WINDOW_EDGE_NORTH_EAST:
2493       winedge = HTTOPRIGHT;
2494       break;
2495
2496     case GDK_WINDOW_EDGE_WEST:
2497       winedge = HTLEFT;
2498       break;
2499
2500     case GDK_WINDOW_EDGE_EAST:
2501       winedge = HTRIGHT;
2502       break;
2503
2504     case GDK_WINDOW_EDGE_SOUTH_WEST:
2505       winedge = HTBOTTOMLEFT;
2506       break;
2507
2508     case GDK_WINDOW_EDGE_SOUTH:
2509       winedge = HTBOTTOM;
2510       break;
2511
2512     case GDK_WINDOW_EDGE_SOUTH_EAST:
2513     default:
2514       winedge = HTBOTTOMRIGHT;
2515       break;
2516     }
2517
2518   DefWindowProcW (GDK_WINDOW_HWND (window), WM_NCLBUTTONDOWN, winedge,
2519                   MAKELPARAM (root_x - _gdk_offset_x, root_y - _gdk_offset_y));
2520 }
2521
2522 static void
2523 gdk_win32_window_begin_move_drag (GdkWindow *window,
2524                             GdkDevice *device,
2525                             gint       button,
2526                             gint       root_x,
2527                             gint       root_y,
2528                             guint32    timestamp)
2529 {
2530   g_return_if_fail (GDK_IS_WINDOW (window));
2531   
2532   if (GDK_WINDOW_DESTROYED (window))
2533     return;
2534
2535   /* Tell Windows to start interactively moving the window by pretending that
2536    * the left pointer button was clicked in the titlebar. This will only work
2537    * if the button is down when this function is called, and will only work
2538    * with button 1 (left), since Windows only allows window dragging using the
2539    * left mouse button.
2540    */
2541   if (button != 1)
2542     return;
2543   
2544   /* Must break the automatic grab that occured when the button was pressed,
2545    * otherwise it won't work.
2546    */
2547   gdk_display_pointer_ungrab (_gdk_display, 0);
2548
2549   DefWindowProcW (GDK_WINDOW_HWND (window), WM_NCLBUTTONDOWN, HTCAPTION,
2550                   MAKELPARAM (root_x - _gdk_offset_x, root_y - _gdk_offset_y));
2551 }
2552
2553
2554 /*
2555  * Setting window states
2556  */
2557 static void
2558 gdk_win32_window_iconify (GdkWindow *window)
2559 {
2560   HWND old_active_window;
2561
2562   g_return_if_fail (GDK_IS_WINDOW (window));
2563
2564   if (GDK_WINDOW_DESTROYED (window))
2565     return;
2566
2567   GDK_NOTE (MISC, g_print ("gdk_window_iconify: %p: %s\n",
2568                            GDK_WINDOW_HWND (window),
2569                            _gdk_win32_window_state_to_string (window->state)));
2570
2571   if (GDK_WINDOW_IS_MAPPED (window))
2572     {
2573       old_active_window = GetActiveWindow ();
2574       ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
2575       if (old_active_window != GDK_WINDOW_HWND (window))
2576         SetActiveWindow (old_active_window);
2577     }
2578   else
2579     {
2580       gdk_synthesize_window_state (window,
2581                                    0,
2582                                    GDK_WINDOW_STATE_ICONIFIED);
2583     }
2584 }
2585
2586 static void
2587 gdk_win32_window_deiconify (GdkWindow *window)
2588 {
2589   g_return_if_fail (GDK_IS_WINDOW (window));
2590
2591   if (GDK_WINDOW_DESTROYED (window))
2592     return;
2593
2594   GDK_NOTE (MISC, g_print ("gdk_window_deiconify: %p: %s\n",
2595                            GDK_WINDOW_HWND (window),
2596                            _gdk_win32_window_state_to_string (window->state)));
2597
2598   if (GDK_WINDOW_IS_MAPPED (window))
2599     {  
2600       show_window_internal (window, GDK_WINDOW_IS_MAPPED (window), TRUE);
2601     }
2602   else
2603     {
2604       gdk_synthesize_window_state (window,
2605                                    GDK_WINDOW_STATE_ICONIFIED,
2606                                    0);
2607     }
2608 }
2609
2610 static void
2611 gdk_win32_window_stick (GdkWindow *window)
2612 {
2613   g_return_if_fail (GDK_IS_WINDOW (window));
2614
2615   if (GDK_WINDOW_DESTROYED (window))
2616     return;
2617
2618   /* FIXME: Do something? */
2619 }
2620
2621 static void
2622 gdk_win32_window_unstick (GdkWindow *window)
2623 {
2624   g_return_if_fail (GDK_IS_WINDOW (window));
2625
2626   if (GDK_WINDOW_DESTROYED (window))
2627     return;
2628
2629   /* FIXME: Do something? */
2630 }
2631
2632 static void
2633 gdk_win32_window_maximize (GdkWindow *window)
2634 {
2635   g_return_if_fail (GDK_IS_WINDOW (window));
2636
2637   if (GDK_WINDOW_DESTROYED (window))
2638     return;
2639
2640   GDK_NOTE (MISC, g_print ("gdk_window_maximize: %p: %s\n",
2641                            GDK_WINDOW_HWND (window),
2642                            _gdk_win32_window_state_to_string (window->state)));
2643
2644   if (GDK_WINDOW_IS_MAPPED (window))
2645     ShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
2646   else
2647     gdk_synthesize_window_state (window,
2648                                  0,
2649                                  GDK_WINDOW_STATE_MAXIMIZED);
2650 }
2651
2652 static void
2653 gdk_win32_window_unmaximize (GdkWindow *window)
2654 {
2655   g_return_if_fail (GDK_IS_WINDOW (window));
2656
2657   if (GDK_WINDOW_DESTROYED (window))
2658     return;
2659
2660   GDK_NOTE (MISC, g_print ("gdk_window_unmaximize: %p: %s\n",
2661                            GDK_WINDOW_HWND (window),
2662                            _gdk_win32_window_state_to_string (window->state)));
2663
2664   if (GDK_WINDOW_IS_MAPPED (window))
2665     ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
2666   else
2667     gdk_synthesize_window_state (window,
2668                                  GDK_WINDOW_STATE_MAXIMIZED,
2669                                  0);
2670 }
2671
2672 typedef struct _FullscreenInfo FullscreenInfo;
2673
2674 struct _FullscreenInfo
2675 {
2676   RECT  r;
2677   guint hint_flags;
2678   LONG  style;
2679 };
2680
2681 static void
2682 gdk_win32_window_fullscreen (GdkWindow *window)
2683 {
2684   gint x, y, width, height;
2685   FullscreenInfo *fi;
2686   HMONITOR monitor;
2687   MONITORINFO mi;
2688
2689   g_return_if_fail (GDK_IS_WINDOW (window));
2690
2691   fi = g_new (FullscreenInfo, 1);
2692
2693   if (!GetWindowRect (GDK_WINDOW_HWND (window), &(fi->r)))
2694     g_free (fi);
2695   else
2696     {
2697       GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2698
2699       monitor = MonitorFromWindow (GDK_WINDOW_HWND (window), MONITOR_DEFAULTTONEAREST);
2700       mi.cbSize = sizeof (mi);
2701       if (monitor && GetMonitorInfo (monitor, &mi))
2702         {
2703           x = mi.rcMonitor.left;
2704           y = mi.rcMonitor.top;
2705           width = mi.rcMonitor.right - x;
2706           height = mi.rcMonitor.bottom - y;
2707         }
2708       else
2709         {
2710           x = y = 0;
2711           width = GetSystemMetrics (SM_CXSCREEN);
2712           height = GetSystemMetrics (SM_CYSCREEN);
2713         }
2714
2715       /* remember for restoring */
2716       fi->hint_flags = impl->hint_flags;
2717       impl->hint_flags &= ~GDK_HINT_MAX_SIZE;
2718       g_object_set_data (G_OBJECT (window), "fullscreen-info", fi);
2719       fi->style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
2720
2721       /* Send state change before configure event */
2722       gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
2723
2724       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, 
2725                      (fi->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
2726
2727       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOP,
2728                                x, y, width, height,
2729                                SWP_NOCOPYBITS | SWP_SHOWWINDOW));
2730     }
2731 }
2732
2733 static void
2734 gdk_win32_window_unfullscreen (GdkWindow *window)
2735 {
2736   FullscreenInfo *fi;
2737
2738   g_return_if_fail (GDK_IS_WINDOW (window));
2739
2740   fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
2741   if (fi)
2742     {
2743       GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2744
2745       gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
2746
2747       impl->hint_flags = fi->hint_flags;
2748       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, fi->style);
2749       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_NOTOPMOST,
2750                                fi->r.left, fi->r.top,
2751                                fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
2752                                SWP_NOCOPYBITS | SWP_SHOWWINDOW));
2753       
2754       g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
2755       g_free (fi);
2756
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
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
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 }