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