]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkwindow-win32.c
win32: Record the native event mask in use
[~andy/gtk] / gdk / win32 / gdkwindow-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2004 Tor Lillqvist
4  * Copyright (C) 2001-2011 Hans Breuer
5  * Copyright (C) 2007-2009 Cody Russell
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 #include "config.h"
31 #include <stdlib.h>
32
33 #include "gdk.h"
34 #include "gdkwindowimpl.h"
35 #include "gdkprivate-win32.h"
36 #include "gdkdeviceprivate.h"
37 #include "gdkdevicemanager-win32.h"
38 #include "gdkenumtypes.h"
39 #include "gdkwin32.h"
40 #include "gdkdisplayprivate.h"
41 #include "gdkvisualprivate.h"
42 #include "gdkwin32window.h"
43
44 #include <cairo-win32.h>
45
46 static void gdk_window_impl_win32_init       (GdkWindowImplWin32      *window);
47 static void gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass);
48 static void gdk_window_impl_win32_finalize   (GObject                 *object);
49
50 static gpointer parent_class = NULL;
51 static GSList *modal_window_stack = NULL;
52
53 static const cairo_user_data_key_t gdk_win32_cairo_key;
54
55 static void     update_style_bits         (GdkWindow         *window);
56 static gboolean _gdk_window_get_functions (GdkWindow         *window,
57                                            GdkWMFunction     *functions);
58
59 #define WINDOW_IS_TOPLEVEL(window)                 \
60   (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
61    GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
62    GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
63
64 GdkScreen *
65 GDK_WINDOW_SCREEN (GObject *win)
66 {
67   return _gdk_screen;
68 }
69
70 struct _GdkWin32Window {
71   GdkWindow parent;
72 };
73
74 struct _GdkWin32WindowClass {
75   GdkWindowClass parent_class;
76 };
77
78 G_DEFINE_TYPE (GdkWin32Window, gdk_win32_window, GDK_TYPE_WINDOW)
79
80 static void
81 gdk_win32_window_class_init (GdkWin32WindowClass *window_class)
82 {
83 }
84
85 static void
86 gdk_win32_window_init (GdkWin32Window *window)
87 {
88 }
89
90
91 G_DEFINE_TYPE (GdkWindowImplWin32, gdk_window_impl_win32, GDK_TYPE_WINDOW_IMPL)
92
93 GType
94 _gdk_window_impl_win32_get_type (void)
95 {
96   static GType object_type = 0;
97
98   if (!object_type)
99     {
100       const GTypeInfo object_info =
101       {
102         sizeof (GdkWindowImplWin32Class),
103         (GBaseInitFunc) NULL,
104         (GBaseFinalizeFunc) NULL,
105         (GClassInitFunc) gdk_window_impl_win32_class_init,
106         NULL,           /* class_finalize */
107         NULL,           /* class_data */
108         sizeof (GdkWindowImplWin32),
109         0,              /* n_preallocs */
110         (GInstanceInitFunc) gdk_window_impl_win32_init,
111       };
112
113       object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL,
114                                             "GdkWindowImplWin32",
115                                             &object_info, 0);
116     }
117   
118   return object_type;
119 }
120
121 static void
122 gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
123 {
124   impl->toplevel_window_type = -1;
125   impl->hcursor = NULL;
126   impl->hicon_big = NULL;
127   impl->hicon_small = NULL;
128   impl->hint_flags = 0;
129   impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
130   impl->extension_events_selected = FALSE;
131   impl->transient_owner = NULL;
132   impl->transient_children = NULL;
133   impl->num_transients = 0;
134   impl->changing_state = FALSE;
135 }
136
137 static void
138 gdk_window_impl_win32_finalize (GObject *object)
139 {
140   GdkWindow *wrapper;
141   GdkWindowImplWin32 *window_impl;
142   
143   g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (object));
144
145   window_impl = GDK_WINDOW_IMPL_WIN32 (object);
146   
147   wrapper = window_impl->wrapper;
148
149   if (!GDK_WINDOW_DESTROYED (wrapper))
150     {
151       gdk_win32_handle_table_remove (window_impl->handle);
152     }
153
154   if (window_impl->hcursor != NULL)
155     {
156       if (GetCursor () == window_impl->hcursor)
157         SetCursor (NULL);
158
159       GDI_CALL (DestroyCursor, (window_impl->hcursor));
160       window_impl->hcursor = NULL;
161     }
162
163   if (window_impl->hicon_big != NULL)
164     {
165       GDI_CALL (DestroyIcon, (window_impl->hicon_big));
166       window_impl->hicon_big = NULL;
167     }
168
169   if (window_impl->hicon_small != NULL)
170     {
171       GDI_CALL (DestroyIcon, (window_impl->hicon_small));
172       window_impl->hicon_small = NULL;
173     }
174
175   G_OBJECT_CLASS (parent_class)->finalize (object);
176 }
177
178 void
179 _gdk_win32_adjust_client_rect (GdkWindow *window,
180                                RECT      *rect)
181 {
182   LONG style, exstyle;
183
184   style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
185   exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
186   API_CALL (AdjustWindowRectEx, (rect, style, FALSE, exstyle));
187 }
188
189 void
190 _gdk_root_window_size_init (void)
191 {
192   GdkWindow *window;
193   GdkRectangle rect;
194   int i;
195
196   window = GDK_WINDOW (_gdk_root);
197   rect = _gdk_monitors[0].rect;
198   for (i = 1; i < _gdk_num_monitors; i++)
199     gdk_rectangle_union (&rect, &_gdk_monitors[i].rect, &rect);
200
201   window->width = rect.width;
202   window->height = rect.height;
203 }
204
205 void
206 _gdk_windowing_window_init (GdkScreen *screen)
207 {
208   GdkWindow *window;
209   GdkWindowImplWin32 *impl_win32;
210
211   g_assert (_gdk_root == NULL);
212   
213   _gdk_root = _gdk_display_create_window (_gdk_display);
214
215   window = (GdkWindow *)_gdk_root;
216   window->impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WIN32, NULL);
217   impl_win32 = GDK_WINDOW_IMPL_WIN32 (window->impl);
218   impl_win32->wrapper = window;
219
220   window->impl_window = window;
221   window->visual = gdk_screen_get_system_visual (screen);
222
223   window->window_type = GDK_WINDOW_ROOT;
224   window->depth = gdk_visual_get_system ()->depth;
225
226   _gdk_root_window_size_init ();
227
228   window->x = 0;
229   window->y = 0;
230   window->abs_x = 0;
231   window->abs_y = 0;
232   /* width and height already initialised in _gdk_root_window_size_init() */
233   window->viewable = TRUE;
234
235   gdk_win32_handle_table_insert ((HANDLE *) &impl_win32->handle, _gdk_root);
236
237   GDK_NOTE (MISC, g_print ("_gdk_root=%p\n", GDK_WINDOW_HWND (_gdk_root)));
238 }
239
240 static const gchar *
241 get_default_title (void)
242 {
243   const char *title;
244   title = g_get_application_name ();
245   if (!title)
246     title = g_get_prgname ();
247
248   return title;
249 }
250
251 /* RegisterGdkClass
252  *   is a wrapper function for RegisterWindowClassEx.
253  *   It creates at least one unique class for every 
254  *   GdkWindowType. If support for single window-specific icons
255  *   is ever needed (e.g Dialog specific), every such window should
256  *   get its own class
257  */
258 static ATOM
259 RegisterGdkClass (GdkWindowType wtype, GdkWindowTypeHint wtype_hint)
260 {
261   static ATOM klassTOPLEVEL   = 0;
262   static ATOM klassCHILD      = 0;
263   static ATOM klassTEMP       = 0;
264   static ATOM klassTEMPSHADOW = 0;
265   static HICON hAppIcon = NULL;
266   static HICON hAppIconSm = NULL;
267   static WNDCLASSEXW wcl; 
268   ATOM klass = 0;
269
270   wcl.cbSize = sizeof (WNDCLASSEX);
271   wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
272                   * on WM_SIZE and WM_MOVE. Flicker, Performance!
273                   */
274   wcl.lpfnWndProc = _gdk_win32_window_procedure;
275   wcl.cbClsExtra = 0;
276   wcl.cbWndExtra = 0;
277   wcl.hInstance = _gdk_app_hmodule;
278   wcl.hIcon = 0;
279   wcl.hIconSm = 0;
280
281   /* initialize once! */
282   if (0 == hAppIcon && 0 == hAppIconSm)
283     {
284       gchar sLoc [MAX_PATH+1];
285
286       if (0 != GetModuleFileName (_gdk_app_hmodule, sLoc, MAX_PATH))
287         {
288           ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
289
290           if (0 == hAppIcon && 0 == hAppIconSm)
291             {
292               if (0 != GetModuleFileName (_gdk_dll_hinstance, sLoc, MAX_PATH))
293                 {
294                   ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
295                 }
296             }
297         }
298
299       if (0 == hAppIcon && 0 == hAppIconSm)
300         {
301           hAppIcon = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
302                                 GetSystemMetrics (SM_CXICON),
303                                 GetSystemMetrics (SM_CYICON), 0);
304           hAppIconSm = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
305                                   GetSystemMetrics (SM_CXSMICON),
306                                   GetSystemMetrics (SM_CYSMICON), 0);
307         }
308     }
309
310   if (0 == hAppIcon)
311     hAppIcon = hAppIconSm;
312   else if (0 == hAppIconSm)
313     hAppIconSm = hAppIcon;
314
315   wcl.lpszMenuName = NULL;
316
317   /* initialize once per class */
318   /*
319    * HB: Setting the background brush leads to flicker, because we
320    * don't get asked how to clear the background. This is not what
321    * we want, at least not for input_only windows ...
322    */
323 #define ONCE_PER_CLASS() \
324   wcl.hIcon = CopyIcon (hAppIcon); \
325   wcl.hIconSm = CopyIcon (hAppIconSm); \
326   wcl.hbrBackground = NULL; \
327   wcl.hCursor = LoadCursor (NULL, IDC_ARROW); 
328   
329   switch (wtype)
330     {
331     case GDK_WINDOW_TOPLEVEL:
332       if (0 == klassTOPLEVEL)
333         {
334           wcl.lpszClassName = L"gdkWindowToplevel";
335           
336           ONCE_PER_CLASS ();
337           klassTOPLEVEL = RegisterClassExW (&wcl);
338         }
339       klass = klassTOPLEVEL;
340       break;
341       
342     case GDK_WINDOW_CHILD:
343       if (0 == klassCHILD)
344         {
345           wcl.lpszClassName = L"gdkWindowChild";
346           
347           wcl.style |= CS_PARENTDC; /* MSDN: ... enhances system performance. */
348           ONCE_PER_CLASS ();
349           klassCHILD = RegisterClassExW (&wcl);
350         }
351       klass = klassCHILD;
352       break;
353       
354     case GDK_WINDOW_TEMP:
355       if ((wtype_hint == GDK_WINDOW_TYPE_HINT_MENU) ||
356           (wtype_hint == GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU) ||
357           (wtype_hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU) ||
358           (wtype_hint == GDK_WINDOW_TYPE_HINT_TOOLTIP))
359         {
360           if (klassTEMPSHADOW == 0)
361             {
362               wcl.lpszClassName = L"gdkWindowTempShadow";
363               wcl.style |= CS_SAVEBITS;
364               if (LOBYTE (g_win32_get_windows_version()) > 0x05 ||
365                   LOWORD (g_win32_get_windows_version()) == 0x0105)
366                 {
367                   /* Windows XP (5.1) or above */
368                   wcl.style |= 0x00020000; /* CS_DROPSHADOW */
369                 }
370               ONCE_PER_CLASS ();
371               klassTEMPSHADOW = RegisterClassExW (&wcl);
372             }
373
374           klass = klassTEMPSHADOW;
375         }
376        else
377         {
378           if (klassTEMP == 0)
379             {
380               wcl.lpszClassName = L"gdkWindowTemp";
381               wcl.style |= CS_SAVEBITS;
382               ONCE_PER_CLASS ();
383               klassTEMP = RegisterClassExW (&wcl);
384             }
385
386           klass = klassTEMP;
387         }
388       break;
389       
390     default:
391       g_assert_not_reached ();
392       break;
393     }
394   
395   if (klass == 0)
396     {
397       WIN32_API_FAILED ("RegisterClassExW");
398       g_error ("That is a fatal error");
399     }
400   return klass;
401 }
402
403 /*
404  * Create native windows.
405  *
406  * With the default Gdk the created windows are mostly toplevel windows.
407  *
408  * Placement of the window is derived from the passed in window,
409  * except for toplevel window where OS/Window Manager placement
410  * is used.
411  *
412  * The visual parameter, is based on GDK_WA_VISUAL if set already.
413  * From attributes the only things used is: colormap, title, 
414  * wmclass and type_hint. [1]. We are checking redundant information
415  * and complain if that changes, which would break this implementation
416  * again.
417  *
418  * [1] http://mail.gnome.org/archives/gtk-devel-list/2010-August/msg00214.html
419  */
420 void
421 _gdk_win32_display_create_window_impl (GdkDisplay    *display,
422                                        GdkWindow     *window,
423                                        GdkWindow     *real_parent,
424                                        GdkScreen     *screen,
425                                        GdkEventMask   event_mask,
426                                        GdkWindowAttr *attributes,
427                                        gint           attributes_mask)
428 {
429   HWND hwndNew;
430   HANDLE hparent;
431   ATOM klass = 0;
432   DWORD dwStyle = 0, dwExStyle;
433   RECT rect;
434   GdkWindowImplWin32 *impl;
435   const gchar *title;
436   wchar_t *wtitle;
437   gint window_width, window_height;
438   gint offset_x = 0, offset_y = 0;
439   gint x, y;
440   /* check consistency of redundant information */
441   guint remaining_mask = attributes_mask;
442
443   GDK_NOTE (MISC,
444             g_print ("_gdk_window_impl_new: %s %s\n",
445                      (window->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" :
446                       (window->window_type == GDK_WINDOW_CHILD ? "CHILD" :
447                        (window->window_type == GDK_WINDOW_TEMP ? "TEMP" :
448                         "???"))),
449                      (attributes->wclass == GDK_INPUT_OUTPUT ? "" : "input-only"))
450                            );
451
452   /* to ensure to not miss important information some additional check against
453    * attributes which may silently work on X11 */
454   if ((attributes_mask & GDK_WA_X) != 0)
455     {
456       g_assert (attributes->x == window->x);
457       remaining_mask &= ~GDK_WA_X;
458     }
459   if ((attributes_mask & GDK_WA_Y) != 0)
460     {
461       g_assert (attributes->y == window->y);
462       remaining_mask &= ~GDK_WA_Y;
463     }
464   if ((attributes_mask & GDK_WA_NOREDIR) != 0)
465     remaining_mask &= ~GDK_WA_NOREDIR;
466
467   if ((remaining_mask & ~(GDK_WA_WMCLASS|GDK_WA_VISUAL|GDK_WA_CURSOR|GDK_WA_TITLE|GDK_WA_TYPE_HINT)) != 0)
468     g_warning ("_gdk_window_impl_new: uexpected attribute 0x%X",
469                remaining_mask & ~(GDK_WA_WMCLASS|GDK_WA_VISUAL|GDK_WA_CURSOR|GDK_WA_TITLE|GDK_WA_TYPE_HINT));
470
471   hparent = GDK_WINDOW_HWND (real_parent);
472
473   impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WIN32, NULL);
474   impl->wrapper = GDK_WINDOW (window);
475   window->impl = GDK_WINDOW_IMPL (impl);
476
477   if (attributes_mask & GDK_WA_VISUAL)
478     g_assert (gdk_screen_get_system_visual (screen) == attributes->visual);
479
480   impl->extension_events_selected = FALSE;
481
482   /* wclass is not any longer set always, but if is ... */
483   if ((attributes_mask & GDK_WA_WMCLASS) == GDK_WA_WMCLASS)
484     g_assert ((attributes->wclass == GDK_INPUT_OUTPUT) == !window->input_only);
485
486   if (!window->input_only)
487     {
488       dwExStyle = 0;
489     }
490   else
491     {
492       /* I very much doubt using WS_EX_TRANSPARENT actually
493        * corresponds to how X11 InputOnly windows work, but it appears
494        * to work well enough for the actual use cases in gtk.
495        */
496       dwExStyle = WS_EX_TRANSPARENT;
497       GDK_NOTE (MISC, g_print ("... GDK_INPUT_ONLY\n"));
498     }
499
500   switch (window->window_type)
501     {
502     case GDK_WINDOW_TOPLEVEL:
503       if (GDK_WINDOW_TYPE (window->parent) != GDK_WINDOW_ROOT)
504         {
505           /* The common code warns for this case. */
506           hparent = GetDesktopWindow ();
507         }
508       /* Children of foreign windows aren't toplevel windows */
509       if (GDK_WINDOW_TYPE (real_parent) == GDK_WINDOW_FOREIGN)
510         {
511           dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN;
512         }
513       else
514         {
515           if (window->window_type == GDK_WINDOW_TOPLEVEL)
516             dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
517           else
518             dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN;
519
520           offset_x = _gdk_offset_x;
521           offset_y = _gdk_offset_y;
522         }
523       break;
524
525     case GDK_WINDOW_CHILD:
526       dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
527       break;
528
529     case GDK_WINDOW_TEMP:
530       /* A temp window is not necessarily a top level window */
531       dwStyle = (_gdk_root == real_parent ? WS_POPUP : WS_CHILDWINDOW);
532       dwStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
533       dwExStyle |= WS_EX_TOOLWINDOW;
534       offset_x = _gdk_offset_x;
535       offset_y = _gdk_offset_y;
536       break;
537
538     default:
539       g_assert_not_reached ();
540     }
541
542   if (window->window_type != GDK_WINDOW_CHILD)
543     {
544       rect.left = window->x;
545       rect.top = window->y;
546       rect.right = window->width;
547       rect.bottom = window->height;
548
549       AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
550
551       /* non child windows are placed by the OS/window manager */
552       x = y = CW_USEDEFAULT;
553
554       window_width = rect.right - rect.left;
555       window_height = rect.bottom - rect.top;
556     }
557   else
558     {
559       /* adjust position relative to real_parent */
560       window_width = window->width;
561       window_height = window->height;
562       /* use given position for initial placement, native coordinates */
563       x = window->x + window->parent->abs_x - offset_x;
564       y = window->y + window->parent->abs_y - offset_y;
565     }
566
567   if (attributes_mask & GDK_WA_TITLE)
568     title = attributes->title;
569   else
570     title = get_default_title ();
571   if (!title || !*title)
572     title = "";
573
574   impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
575       
576   if (attributes_mask & GDK_WA_TYPE_HINT)
577     gdk_window_set_type_hint (window, attributes->type_hint);
578
579   if (impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY)
580     dwExStyle |= WS_EX_TOOLWINDOW;
581
582   klass = RegisterGdkClass (window->window_type, impl->type_hint);
583
584   wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
585   
586   hwndNew = CreateWindowExW (dwExStyle,
587                              MAKEINTRESOURCEW (klass),
588                              wtitle,
589                              dwStyle,
590                              x,
591                              y,
592                              window_width, window_height,
593                              hparent,
594                              NULL,
595                              _gdk_app_hmodule,
596                              window);
597   if (GDK_WINDOW_HWND (window) != hwndNew)
598     {
599       g_warning ("gdk_window_new: gdk_event_translate::WM_CREATE (%p, %p) HWND mismatch.",
600                  GDK_WINDOW_HWND (window),
601                  hwndNew);
602
603       /* HB: IHMO due to a race condition the handle was increased by
604        * one, which causes much trouble. Because I can't find the 
605        * real bug, try to workaround it ...
606        * To reproduce: compile with MSVC 5, DEBUG=1
607        */
608 # if 0
609       gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
610       GDK_WINDOW_HWND (window) = hwndNew;
611       gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
612 # else
613       /* the old behaviour, but with warning */
614       impl->handle = hwndNew;
615 # endif
616
617     }
618
619   g_object_ref (window);
620   gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
621
622   GDK_NOTE (MISC, g_print ("... \"%s\" %dx%d@%+d%+d %p = %p\n",
623                            title,
624                            window_width, window_height,
625                            window->x - offset_x,
626                            window->y - offset_y, 
627                            hparent,
628                            GDK_WINDOW_HWND (window)));
629
630   /* Add window handle to title */
631   GDK_NOTE (MISC_OR_EVENTS, gdk_window_set_title (window, title));
632
633   g_free (wtitle);
634
635   if (impl->handle == NULL)
636     {
637       WIN32_API_FAILED ("CreateWindowExW");
638       g_object_unref (window);
639       return;
640     }
641
642 //  if (!from_set_skip_taskbar_hint && window->window_type == GDK_WINDOW_TEMP)
643 //    gdk_window_set_skip_taskbar_hint (window, TRUE);
644
645   if (attributes_mask & GDK_WA_CURSOR)
646     gdk_window_set_cursor (window, attributes->cursor);
647 }
648
649 GdkWindow *
650 gdk_win32_window_foreign_new_for_display (GdkDisplay      *display,
651                                           HWND             anid)
652 {
653   GdkWindow *window;
654   GdkWindowImplWin32 *impl;
655
656   HANDLE parent;
657   RECT rect;
658   POINT point;
659
660   g_return_val_if_fail (display == _gdk_display, NULL);
661
662   if ((window = gdk_win32_window_lookup_for_display (display, anid)) != NULL)
663     return g_object_ref (window);
664
665   window = _gdk_display_create_window (display);
666   window->visual = gdk_screen_get_system_visual (_gdk_screen);
667   window->impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WIN32, NULL);
668   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
669   impl->wrapper = window;
670   parent = GetParent (anid);
671   
672   window->parent = gdk_win32_handle_table_lookup (parent);
673   if (!window->parent || GDK_WINDOW_TYPE (window->parent) == GDK_WINDOW_FOREIGN)
674     window->parent = _gdk_root;
675   
676   window->parent->children = g_list_prepend (window->parent->children, window);
677
678   GetClientRect ((HWND) anid, &rect);
679   point.x = rect.left;
680   point.y = rect.right;
681   ClientToScreen ((HWND) anid, &point);
682   if (parent != GetDesktopWindow ())
683     ScreenToClient (parent, &point);
684   window->x = point.x;
685   window->y = point.y;
686   window->width = rect.right - rect.left;
687   window->height = rect.bottom - rect.top;
688   window->window_type = GDK_WINDOW_FOREIGN;
689   window->destroyed = FALSE;
690   window->event_mask = GDK_ALL_EVENTS_MASK; /* XXX */
691   if (IsWindowVisible ((HWND) anid))
692     window->state &= (~GDK_WINDOW_STATE_WITHDRAWN);
693   else
694     window->state |= GDK_WINDOW_STATE_WITHDRAWN;
695   if (GetWindowLong ((HWND)anid, GWL_EXSTYLE) & WS_EX_TOPMOST)
696     window->state |= GDK_WINDOW_STATE_ABOVE;
697   else
698     window->state &= (~GDK_WINDOW_STATE_ABOVE);
699   window->state &= (~GDK_WINDOW_STATE_BELOW);
700   window->viewable = TRUE;
701
702   window->depth = gdk_visual_get_system ()->depth;
703
704   g_object_ref (window);
705   gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
706
707   GDK_NOTE (MISC, g_print ("gdk_win32_window_foreign_new_for_display: %p: %s@%+d%+d\n",
708                            (HWND) anid,
709                            _gdk_win32_window_description (window),
710                            window->x, window->y));
711
712   return window;
713 }
714
715 static void
716 gdk_win32_window_destroy (GdkWindow *window,
717                           gboolean   recursing,
718                           gboolean   foreign_destroy)
719 {
720   GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
721   GSList *tmp;
722
723   g_return_if_fail (GDK_IS_WINDOW (window));
724   
725   GDK_NOTE (MISC, g_print ("gdk_win32_window_destroy: %p\n",
726                            GDK_WINDOW_HWND (window)));
727
728   /* Remove ourself from the modal stack */
729   _gdk_remove_modal_window (window);
730
731   /* Remove all our transient children */
732   tmp = window_impl->transient_children;
733   while (tmp != NULL)
734     {
735       GdkWindow *child = tmp->data;
736       GdkWindowImplWin32 *child_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW (child)->impl);
737
738       child_impl->transient_owner = NULL;
739       tmp = g_slist_next (tmp);
740     }
741   g_slist_free (window_impl->transient_children);
742   window_impl->transient_children = NULL;
743
744   /* Remove ourself from our transient owner */
745   if (window_impl->transient_owner != NULL)
746     {
747       gdk_window_set_transient_for (window, NULL);
748     }
749
750   if (!recursing && !foreign_destroy)
751     {
752       window->destroyed = TRUE;
753       DestroyWindow (GDK_WINDOW_HWND (window));
754     }
755
756   gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
757 }
758
759 static cairo_surface_t *
760 gdk_win32_window_resize_cairo_surface (GdkWindow       *window,
761                                        cairo_surface_t *surface,
762                                        gint             width,
763                                        gint             height)
764 {
765   /* XXX: Make Cairo surface use DC clip */
766   cairo_surface_destroy (surface);
767
768   return NULL;
769 }
770
771 static void
772 gdk_win32_window_destroy_foreign (GdkWindow *window)
773 {
774   /* It's somebody else's window, but in our hierarchy, so reparent it
775    * to the desktop, and then try to destroy it.
776    */
777   gdk_window_hide (window);
778   gdk_window_reparent (window, NULL, 0, 0);
779   
780   PostMessage (GDK_WINDOW_HWND (window), WM_CLOSE, 0, 0);
781 }
782
783 /* This function is called when the window really gone.
784  */
785 static void
786 gdk_win32_window_destroy_notify (GdkWindow *window)
787 {
788   g_return_if_fail (GDK_IS_WINDOW (window));
789
790   GDK_NOTE (EVENTS,
791             g_print ("gdk_window_destroy_notify: %p%s\n",
792                      GDK_WINDOW_HWND (window),
793                      (GDK_WINDOW_DESTROYED (window) ? " (destroyed)" : "")));
794
795   if (!GDK_WINDOW_DESTROYED (window))
796     {
797       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
798         g_warning ("window %p unexpectedly destroyed",
799                    GDK_WINDOW_HWND (window));
800
801       _gdk_window_destroy (window, TRUE);
802     }
803   
804   gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
805   g_object_unref (window);
806 }
807
808 static void
809 get_outer_rect (GdkWindow *window,
810                 gint       width,
811                 gint       height,
812                 RECT      *rect)
813 {
814   rect->left = rect->top = 0;
815   rect->right = width;
816   rect->bottom = height;
817       
818   _gdk_win32_adjust_client_rect (window, rect);
819 }
820
821 static void
822 adjust_for_gravity_hints (GdkWindow *window,
823                           RECT      *outer_rect,
824                           gint          *x,
825                           gint          *y)
826 {
827   GdkWindowImplWin32 *impl;
828
829   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
830
831   if (impl->hint_flags & GDK_HINT_WIN_GRAVITY)
832     {
833       gint orig_x = *x, orig_y = *y;
834
835       switch (impl->hints.win_gravity)
836         {
837         case GDK_GRAVITY_NORTH:
838         case GDK_GRAVITY_CENTER:
839         case GDK_GRAVITY_SOUTH:
840           *x -= (outer_rect->right - outer_rect->left) / 2;
841           *x += window->width / 2;
842           break;
843               
844         case GDK_GRAVITY_SOUTH_EAST:
845         case GDK_GRAVITY_EAST:
846         case GDK_GRAVITY_NORTH_EAST:
847           *x -= outer_rect->right - outer_rect->left;
848           *x += window->width;
849           break;
850
851         case GDK_GRAVITY_STATIC:
852           *x += outer_rect->left;
853           break;
854
855         default:
856           break;
857         }
858
859       switch (impl->hints.win_gravity)
860         {
861         case GDK_GRAVITY_WEST:
862         case GDK_GRAVITY_CENTER:
863         case GDK_GRAVITY_EAST:
864           *y -= (outer_rect->bottom - outer_rect->top) / 2;
865           *y += window->height / 2;
866           break;
867
868         case GDK_GRAVITY_SOUTH_WEST:
869         case GDK_GRAVITY_SOUTH:
870         case GDK_GRAVITY_SOUTH_EAST:
871           *y -= outer_rect->bottom - outer_rect->top;
872           *y += window->height;
873           break;
874
875         case GDK_GRAVITY_STATIC:
876           *y += outer_rect->top;
877           break;
878
879         default:
880           break;
881         }
882       GDK_NOTE (MISC,
883                 (orig_x != *x || orig_y != *y) ?
884                 g_print ("adjust_for_gravity_hints: x: %d->%d, y: %d->%d\n",
885                          orig_x, *x, orig_y, *y)
886                   : (void) 0);
887     }
888 }
889
890 static void
891 show_window_internal (GdkWindow *window,
892                       gboolean   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   GdkWindowImplWin32 *impl;
2032
2033   if (GDK_WINDOW_DESTROYED (window))
2034     return 0;
2035
2036   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2037
2038   return impl->native_event_mask;
2039 }
2040
2041 static void          
2042 gdk_win32_window_set_events (GdkWindow   *window,
2043                              GdkEventMask event_mask)
2044 {
2045   GdkWindowImplWin32 *impl;
2046
2047   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2048
2049   /* gdk_window_new() always sets the GDK_STRUCTURE_MASK, so better
2050    * set it here, too. Not that I know or remember why it is
2051    * necessary, will have to test some day.
2052    */
2053   impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
2054 }
2055
2056 static void
2057 do_shape_combine_region (GdkWindow *window,
2058                          HRGN       hrgn,
2059                          gint       x, gint y)
2060 {
2061   RECT rect;
2062
2063   GetClientRect (GDK_WINDOW_HWND (window), &rect);
2064   _gdk_win32_adjust_client_rect (window, &rect);
2065
2066   OffsetRgn (hrgn, -rect.left, -rect.top);
2067   OffsetRgn (hrgn, x, y);
2068
2069   /* If this is a top-level window, add the title bar to the region */
2070   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL)
2071     {
2072       HRGN tmp = CreateRectRgn (0, 0, rect.right - rect.left, -rect.top);
2073       CombineRgn (hrgn, hrgn, tmp, RGN_OR);
2074       DeleteObject (tmp);
2075     }
2076   
2077   SetWindowRgn (GDK_WINDOW_HWND (window), hrgn, TRUE);
2078 }
2079
2080 static void
2081 gdk_win32_window_set_override_redirect (GdkWindow *window,
2082                                   gboolean   override_redirect)
2083 {
2084   g_return_if_fail (GDK_IS_WINDOW (window));
2085
2086   g_warning ("gdk_window_set_override_redirect not implemented");
2087 }
2088
2089 static void
2090 gdk_win32_window_set_accept_focus (GdkWindow *window,
2091                              gboolean accept_focus)
2092 {
2093   g_return_if_fail (GDK_IS_WINDOW (window));
2094
2095   accept_focus = accept_focus != FALSE;
2096
2097   if (window->accept_focus != accept_focus)
2098     window->accept_focus = accept_focus;
2099 }
2100
2101 static void
2102 gdk_win32_window_set_focus_on_map (GdkWindow *window,
2103                              gboolean focus_on_map)
2104 {
2105   g_return_if_fail (GDK_IS_WINDOW (window));
2106
2107   focus_on_map = focus_on_map != FALSE;
2108
2109   if (window->focus_on_map != focus_on_map)
2110     window->focus_on_map = focus_on_map;
2111 }
2112
2113 static void
2114 gdk_win32_window_set_icon_list (GdkWindow *window,
2115                           GList     *pixbufs)
2116 {
2117   GdkPixbuf *pixbuf, *big_pixbuf, *small_pixbuf;
2118   gint big_diff, small_diff;
2119   gint big_w, big_h, small_w, small_h;
2120   gint w, h;
2121   gint dw, dh, diff;
2122   HICON small_hicon, big_hicon;
2123   GdkWindowImplWin32 *impl;
2124   gint i, big_i, small_i;
2125
2126   g_return_if_fail (GDK_IS_WINDOW (window));
2127
2128   if (GDK_WINDOW_DESTROYED (window))
2129     return;
2130
2131   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2132
2133   /* ideal sizes for small and large icons */
2134   big_w = GetSystemMetrics (SM_CXICON);
2135   big_h = GetSystemMetrics (SM_CYICON);
2136   small_w = GetSystemMetrics (SM_CXSMICON);
2137   small_h = GetSystemMetrics (SM_CYSMICON);
2138
2139   /* find closest sized icons in the list */
2140   big_pixbuf = NULL;
2141   small_pixbuf = NULL;
2142   big_diff = 0;
2143   small_diff = 0;
2144   i = 0;
2145   while (pixbufs)
2146     {
2147       pixbuf = (GdkPixbuf*) pixbufs->data;
2148       w = gdk_pixbuf_get_width (pixbuf);
2149       h = gdk_pixbuf_get_height (pixbuf);
2150
2151       dw = ABS (w - big_w);
2152       dh = ABS (h - big_h);
2153       diff = dw*dw + dh*dh;
2154       if (big_pixbuf == NULL || diff < big_diff)
2155         {
2156           big_pixbuf = pixbuf;
2157           big_diff = diff;
2158           big_i = i;
2159         }
2160
2161       dw = ABS (w - small_w);
2162       dh = ABS (h - small_h);
2163       diff = dw*dw + dh*dh;
2164       if (small_pixbuf == NULL || diff < small_diff)
2165         {
2166           small_pixbuf = pixbuf;
2167           small_diff = diff;
2168           small_i = i;
2169         }
2170
2171       pixbufs = g_list_next (pixbufs);
2172       i++;
2173     }
2174
2175   /* Create the icons */
2176   big_hicon = _gdk_win32_pixbuf_to_hicon (big_pixbuf);
2177   small_hicon = _gdk_win32_pixbuf_to_hicon (small_pixbuf);
2178
2179   /* Set the icons */
2180   SendMessageW (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG,
2181                 (LPARAM)big_hicon);
2182   SendMessageW (GDK_WINDOW_HWND (window), WM_SETICON, ICON_SMALL,
2183                 (LPARAM)small_hicon);
2184
2185   /* Store the icons, destroying any previous icons */
2186   if (impl->hicon_big)
2187     GDI_CALL (DestroyIcon, (impl->hicon_big));
2188   impl->hicon_big = big_hicon;
2189   if (impl->hicon_small)
2190     GDI_CALL (DestroyIcon, (impl->hicon_small));
2191   impl->hicon_small = small_hicon;
2192 }
2193
2194 static void
2195 gdk_win32_window_set_icon_name (GdkWindow   *window, 
2196                           const gchar *name)
2197 {
2198   /* In case I manage to confuse this again (or somebody else does):
2199    * Please note that "icon name" here really *does* mean the name or
2200    * title of an window minimized as an icon on the desktop, or in the
2201    * taskbar. It has nothing to do with the freedesktop.org icon
2202    * naming stuff.
2203    */
2204
2205   g_return_if_fail (GDK_IS_WINDOW (window));
2206
2207   if (GDK_WINDOW_DESTROYED (window))
2208     return;
2209   
2210 #if 0
2211   /* This is not the correct thing to do. We should keep both the
2212    * "normal" window title, and the icon name. When the window is
2213    * minimized, call SetWindowText() with the icon name, and when the
2214    * window is restored, with the normal window title. Also, the name
2215    * is in UTF-8, so we should do the normal conversion to either wide
2216    * chars or system codepage, and use either the W or A version of
2217    * SetWindowText(), depending on Windows version.
2218    */
2219   API_CALL (SetWindowText, (GDK_WINDOW_HWND (window), name));
2220 #endif
2221 }
2222
2223 static GdkWindow *
2224 gdk_win32_window_get_group (GdkWindow *window)
2225 {
2226   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2227   g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL);
2228
2229   if (GDK_WINDOW_DESTROYED (window))
2230     return NULL;
2231   
2232   g_warning ("gdk_window_get_group not yet implemented");
2233
2234   return NULL;
2235 }
2236
2237 static void
2238 gdk_win32_window_set_group (GdkWindow *window, 
2239                       GdkWindow *leader)
2240 {
2241   g_return_if_fail (GDK_IS_WINDOW (window));
2242   g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD);
2243   g_return_if_fail (leader == NULL || GDK_IS_WINDOW (leader));
2244
2245   if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
2246     return;
2247   
2248   g_warning ("gdk_window_set_group not implemented");
2249 }
2250
2251 static void
2252 update_single_bit (LONG    *style,
2253                    gboolean all,
2254                    int      gdk_bit,
2255                    int      style_bit)
2256 {
2257   /* all controls the interpretation of gdk_bit -- if all is TRUE,
2258    * gdk_bit indicates whether style_bit is off; if all is FALSE, gdk
2259    * bit indicate whether style_bit is on
2260    */
2261   if ((!all && gdk_bit) || (all && !gdk_bit))
2262     *style |= style_bit;
2263   else
2264     *style &= ~style_bit;
2265 }
2266
2267 static void
2268 update_style_bits (GdkWindow *window)
2269 {
2270   GdkWindowImplWin32 *impl = (GdkWindowImplWin32 *)window->impl;
2271   GdkWMDecoration decorations;
2272   LONG old_style, new_style, old_exstyle, new_exstyle;
2273   gboolean all;
2274   RECT rect, before, after;
2275
2276   old_style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
2277   old_exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
2278
2279   GetClientRect (GDK_WINDOW_HWND (window), &before);
2280   after = before;
2281   AdjustWindowRectEx (&before, old_style, FALSE, old_exstyle);
2282
2283   new_style = old_style;
2284   new_exstyle = old_exstyle;
2285
2286   if (window->window_type == GDK_WINDOW_TEMP ||
2287       impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY)
2288     new_exstyle |= WS_EX_TOOLWINDOW;
2289   else
2290     new_exstyle &= ~WS_EX_TOOLWINDOW;
2291
2292   if (get_effective_window_decorations (window, &decorations))
2293     {
2294       all = (decorations & GDK_DECOR_ALL);
2295       update_single_bit (&new_style, all, decorations & GDK_DECOR_BORDER, WS_BORDER);
2296       update_single_bit (&new_style, all, decorations & GDK_DECOR_RESIZEH, WS_THICKFRAME);
2297       update_single_bit (&new_style, all, decorations & GDK_DECOR_TITLE, WS_CAPTION);
2298       update_single_bit (&new_style, all, decorations & GDK_DECOR_MENU, WS_SYSMENU);
2299       update_single_bit (&new_style, all, decorations & GDK_DECOR_MINIMIZE, WS_MINIMIZEBOX);
2300       update_single_bit (&new_style, all, decorations & GDK_DECOR_MAXIMIZE, WS_MAXIMIZEBOX);
2301     }
2302
2303   if (old_style == new_style && old_exstyle == new_exstyle )
2304     {
2305       GDK_NOTE (MISC, g_print ("update_style_bits: %p: no change\n",
2306                                GDK_WINDOW_HWND (window)));
2307       return;
2308     }
2309
2310   if (old_style != new_style)
2311     {
2312       GDK_NOTE (MISC, g_print ("update_style_bits: %p: STYLE: %s => %s\n",
2313                                GDK_WINDOW_HWND (window),
2314                                _gdk_win32_window_style_to_string (old_style),
2315                                _gdk_win32_window_style_to_string (new_style)));
2316       
2317       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, new_style);
2318     }
2319
2320   if (old_exstyle != new_exstyle)
2321     {
2322       GDK_NOTE (MISC, g_print ("update_style_bits: %p: EXSTYLE: %s => %s\n",
2323                                GDK_WINDOW_HWND (window),
2324                                _gdk_win32_window_exstyle_to_string (old_exstyle),
2325                                _gdk_win32_window_exstyle_to_string (new_exstyle)));
2326       
2327       SetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE, new_exstyle);
2328     }
2329
2330   AdjustWindowRectEx (&after, new_style, FALSE, new_exstyle);
2331
2332   GetWindowRect (GDK_WINDOW_HWND (window), &rect);
2333   rect.left += after.left - before.left;
2334   rect.top += after.top - before.top;
2335   rect.right += after.right - before.right;
2336   rect.bottom += after.bottom - before.bottom;
2337
2338   SetWindowPos (GDK_WINDOW_HWND (window), NULL,
2339                 rect.left, rect.top,
2340                 rect.right - rect.left, rect.bottom - rect.top,
2341                 SWP_FRAMECHANGED | SWP_NOACTIVATE | 
2342                 SWP_NOREPOSITION | SWP_NOZORDER);
2343
2344 }
2345
2346 static void
2347 update_single_system_menu_entry (HMENU    hmenu,
2348                                  gboolean all,
2349                                  int      gdk_bit,
2350                                  int      menu_entry)
2351 {
2352   /* all controls the interpretation of gdk_bit -- if all is TRUE,
2353    * gdk_bit indicates whether menu entry is disabled; if all is
2354    * FALSE, gdk bit indicate whether menu entry is enabled
2355    */
2356   if ((!all && gdk_bit) || (all && !gdk_bit))
2357     EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_ENABLED);
2358   else
2359     EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_GRAYED);
2360 }
2361
2362 static void
2363 update_system_menu (GdkWindow *window)
2364 {
2365   GdkWMFunction functions;
2366   BOOL all;
2367
2368   if (_gdk_window_get_functions (window, &functions))
2369     {
2370       HMENU hmenu = GetSystemMenu (GDK_WINDOW_HWND (window), FALSE);
2371
2372       all = (functions & GDK_FUNC_ALL);
2373       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_RESIZE, SC_SIZE);
2374       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MOVE, SC_MOVE);
2375       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MINIMIZE, SC_MINIMIZE);
2376       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MAXIMIZE, SC_MAXIMIZE);
2377       update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_CLOSE, SC_CLOSE);
2378     }
2379 }
2380
2381 static GQuark
2382 get_decorations_quark ()
2383 {
2384   static GQuark quark = 0;
2385   
2386   if (!quark)
2387     quark = g_quark_from_static_string ("gdk-window-decorations");
2388   
2389   return quark;
2390 }
2391
2392 static void
2393 gdk_win32_window_set_decorations (GdkWindow      *window,
2394                             GdkWMDecoration decorations)
2395 {
2396   GdkWMDecoration* decorations_copy;
2397   
2398   g_return_if_fail (GDK_IS_WINDOW (window));
2399   
2400   GDK_NOTE (MISC, g_print ("gdk_window_set_decorations: %p: %s %s%s%s%s%s%s\n",
2401                            GDK_WINDOW_HWND (window),
2402                            (decorations & GDK_DECOR_ALL ? "clearing" : "setting"),
2403                            (decorations & GDK_DECOR_BORDER ? "BORDER " : ""),
2404                            (decorations & GDK_DECOR_RESIZEH ? "RESIZEH " : ""),
2405                            (decorations & GDK_DECOR_TITLE ? "TITLE " : ""),
2406                            (decorations & GDK_DECOR_MENU ? "MENU " : ""),
2407                            (decorations & GDK_DECOR_MINIMIZE ? "MINIMIZE " : ""),
2408                            (decorations & GDK_DECOR_MAXIMIZE ? "MAXIMIZE " : "")));
2409
2410   decorations_copy = g_malloc (sizeof (GdkWMDecoration));
2411   *decorations_copy = decorations;
2412   g_object_set_qdata_full (G_OBJECT (window), get_decorations_quark (), decorations_copy, g_free);
2413
2414   update_style_bits (window);
2415 }
2416
2417 static gboolean
2418 gdk_win32_window_get_decorations (GdkWindow       *window,
2419                             GdkWMDecoration *decorations)
2420 {
2421   GdkWMDecoration* decorations_set;
2422   
2423   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2424
2425   decorations_set = g_object_get_qdata (G_OBJECT (window), get_decorations_quark ());
2426   if (decorations_set)
2427     *decorations = *decorations_set;
2428
2429   return (decorations_set != NULL);
2430 }
2431
2432 static GQuark
2433 get_functions_quark ()
2434 {
2435   static GQuark quark = 0;
2436   
2437   if (!quark)
2438     quark = g_quark_from_static_string ("gdk-window-functions");
2439   
2440   return quark;
2441 }
2442
2443 static void
2444 gdk_win32_window_set_functions (GdkWindow    *window,
2445                           GdkWMFunction functions)
2446 {
2447   GdkWMFunction* functions_copy;
2448
2449   g_return_if_fail (GDK_IS_WINDOW (window));
2450   
2451   GDK_NOTE (MISC, g_print ("gdk_window_set_functions: %p: %s %s%s%s%s%s\n",
2452                            GDK_WINDOW_HWND (window),
2453                            (functions & GDK_FUNC_ALL ? "clearing" : "setting"),
2454                            (functions & GDK_FUNC_RESIZE ? "RESIZE " : ""),
2455                            (functions & GDK_FUNC_MOVE ? "MOVE " : ""),
2456                            (functions & GDK_FUNC_MINIMIZE ? "MINIMIZE " : ""),
2457                            (functions & GDK_FUNC_MAXIMIZE ? "MAXIMIZE " : ""),
2458                            (functions & GDK_FUNC_CLOSE ? "CLOSE " : "")));
2459
2460   functions_copy = g_malloc (sizeof (GdkWMFunction));
2461   *functions_copy = functions;
2462   g_object_set_qdata_full (G_OBJECT (window), get_functions_quark (), functions_copy, g_free);
2463
2464   update_system_menu (window);
2465 }
2466
2467 gboolean
2468 _gdk_window_get_functions (GdkWindow     *window,
2469                            GdkWMFunction *functions)
2470 {
2471   GdkWMDecoration* functions_set;
2472   
2473   functions_set = g_object_get_qdata (G_OBJECT (window), get_functions_quark ());
2474   if (functions_set)
2475     *functions = *functions_set;
2476
2477   return (functions_set != NULL);
2478 }
2479
2480 static gboolean 
2481 gdk_win32_window_set_static_gravities (GdkWindow *window,
2482                                  gboolean   use_static)
2483 {
2484   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
2485
2486   return !use_static;
2487 }
2488
2489 static void
2490 gdk_win32_window_begin_resize_drag (GdkWindow     *window,
2491                               GdkWindowEdge  edge,
2492                               GdkDevice     *device,
2493                               gint           button,
2494                               gint           root_x,
2495                               gint           root_y,
2496                               guint32        timestamp)
2497 {
2498   WPARAM winedge;
2499   
2500   g_return_if_fail (GDK_IS_WINDOW (window));
2501   
2502   if (GDK_WINDOW_DESTROYED (window))
2503     return;
2504
2505   /* Tell Windows to start interactively resizing the window by pretending that
2506    * the left pointer button was clicked in the suitable edge or corner. This
2507    * will only work if the button is down when this function is called, and
2508    * will only work with button 1 (left), since Windows only allows window
2509    * dragging using the left mouse button.
2510    */
2511   if (button != 1)
2512     return;
2513   
2514   /* Must break the automatic grab that occured when the button was
2515    * pressed, otherwise it won't work.
2516    */
2517   gdk_display_pointer_ungrab (_gdk_display, 0);
2518
2519   switch (edge)
2520     {
2521     case GDK_WINDOW_EDGE_NORTH_WEST:
2522       winedge = HTTOPLEFT;
2523       break;
2524
2525     case GDK_WINDOW_EDGE_NORTH:
2526       winedge = HTTOP;
2527       break;
2528
2529     case GDK_WINDOW_EDGE_NORTH_EAST:
2530       winedge = HTTOPRIGHT;
2531       break;
2532
2533     case GDK_WINDOW_EDGE_WEST:
2534       winedge = HTLEFT;
2535       break;
2536
2537     case GDK_WINDOW_EDGE_EAST:
2538       winedge = HTRIGHT;
2539       break;
2540
2541     case GDK_WINDOW_EDGE_SOUTH_WEST:
2542       winedge = HTBOTTOMLEFT;
2543       break;
2544
2545     case GDK_WINDOW_EDGE_SOUTH:
2546       winedge = HTBOTTOM;
2547       break;
2548
2549     case GDK_WINDOW_EDGE_SOUTH_EAST:
2550     default:
2551       winedge = HTBOTTOMRIGHT;
2552       break;
2553     }
2554
2555   DefWindowProcW (GDK_WINDOW_HWND (window), WM_NCLBUTTONDOWN, winedge,
2556                   MAKELPARAM (root_x - _gdk_offset_x, root_y - _gdk_offset_y));
2557 }
2558
2559 static void
2560 gdk_win32_window_begin_move_drag (GdkWindow *window,
2561                             GdkDevice *device,
2562                             gint       button,
2563                             gint       root_x,
2564                             gint       root_y,
2565                             guint32    timestamp)
2566 {
2567   g_return_if_fail (GDK_IS_WINDOW (window));
2568   
2569   if (GDK_WINDOW_DESTROYED (window))
2570     return;
2571
2572   /* Tell Windows to start interactively moving the window by pretending that
2573    * the left pointer button was clicked in the titlebar. This will only work
2574    * if the button is down when this function is called, and will only work
2575    * with button 1 (left), since Windows only allows window dragging using the
2576    * left mouse button.
2577    */
2578   if (button != 1)
2579     return;
2580   
2581   /* Must break the automatic grab that occured when the button was pressed,
2582    * otherwise it won't work.
2583    */
2584   gdk_display_pointer_ungrab (_gdk_display, 0);
2585
2586   DefWindowProcW (GDK_WINDOW_HWND (window), WM_NCLBUTTONDOWN, HTCAPTION,
2587                   MAKELPARAM (root_x - _gdk_offset_x, root_y - _gdk_offset_y));
2588 }
2589
2590
2591 /*
2592  * Setting window states
2593  */
2594 static void
2595 gdk_win32_window_iconify (GdkWindow *window)
2596 {
2597   HWND old_active_window;
2598
2599   g_return_if_fail (GDK_IS_WINDOW (window));
2600
2601   if (GDK_WINDOW_DESTROYED (window))
2602     return;
2603
2604   GDK_NOTE (MISC, g_print ("gdk_window_iconify: %p: %s\n",
2605                            GDK_WINDOW_HWND (window),
2606                            _gdk_win32_window_state_to_string (window->state)));
2607
2608   if (GDK_WINDOW_IS_MAPPED (window))
2609     {
2610       old_active_window = GetActiveWindow ();
2611       ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
2612       if (old_active_window != GDK_WINDOW_HWND (window))
2613         SetActiveWindow (old_active_window);
2614     }
2615   else
2616     {
2617       gdk_synthesize_window_state (window,
2618                                    0,
2619                                    GDK_WINDOW_STATE_ICONIFIED);
2620     }
2621 }
2622
2623 static void
2624 gdk_win32_window_deiconify (GdkWindow *window)
2625 {
2626   g_return_if_fail (GDK_IS_WINDOW (window));
2627
2628   if (GDK_WINDOW_DESTROYED (window))
2629     return;
2630
2631   GDK_NOTE (MISC, g_print ("gdk_window_deiconify: %p: %s\n",
2632                            GDK_WINDOW_HWND (window),
2633                            _gdk_win32_window_state_to_string (window->state)));
2634
2635   if (GDK_WINDOW_IS_MAPPED (window))
2636     {  
2637       show_window_internal (window, FALSE, TRUE);
2638     }
2639   else
2640     {
2641       gdk_synthesize_window_state (window,
2642                                    GDK_WINDOW_STATE_ICONIFIED,
2643                                    0);
2644     }
2645 }
2646
2647 static void
2648 gdk_win32_window_stick (GdkWindow *window)
2649 {
2650   g_return_if_fail (GDK_IS_WINDOW (window));
2651
2652   if (GDK_WINDOW_DESTROYED (window))
2653     return;
2654
2655   /* FIXME: Do something? */
2656 }
2657
2658 static void
2659 gdk_win32_window_unstick (GdkWindow *window)
2660 {
2661   g_return_if_fail (GDK_IS_WINDOW (window));
2662
2663   if (GDK_WINDOW_DESTROYED (window))
2664     return;
2665
2666   /* FIXME: Do something? */
2667 }
2668
2669 static void
2670 gdk_win32_window_maximize (GdkWindow *window)
2671 {
2672   g_return_if_fail (GDK_IS_WINDOW (window));
2673
2674   if (GDK_WINDOW_DESTROYED (window))
2675     return;
2676
2677   GDK_NOTE (MISC, g_print ("gdk_window_maximize: %p: %s\n",
2678                            GDK_WINDOW_HWND (window),
2679                            _gdk_win32_window_state_to_string (window->state)));
2680
2681   if (GDK_WINDOW_IS_MAPPED (window))
2682     ShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
2683   else
2684     gdk_synthesize_window_state (window,
2685                                  0,
2686                                  GDK_WINDOW_STATE_MAXIMIZED);
2687 }
2688
2689 static void
2690 gdk_win32_window_unmaximize (GdkWindow *window)
2691 {
2692   g_return_if_fail (GDK_IS_WINDOW (window));
2693
2694   if (GDK_WINDOW_DESTROYED (window))
2695     return;
2696
2697   GDK_NOTE (MISC, g_print ("gdk_window_unmaximize: %p: %s\n",
2698                            GDK_WINDOW_HWND (window),
2699                            _gdk_win32_window_state_to_string (window->state)));
2700
2701   if (GDK_WINDOW_IS_MAPPED (window))
2702     ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
2703   else
2704     gdk_synthesize_window_state (window,
2705                                  GDK_WINDOW_STATE_MAXIMIZED,
2706                                  0);
2707 }
2708
2709 typedef struct _FullscreenInfo FullscreenInfo;
2710
2711 struct _FullscreenInfo
2712 {
2713   RECT  r;
2714   guint hint_flags;
2715   LONG  style;
2716 };
2717
2718 static void
2719 gdk_win32_window_fullscreen (GdkWindow *window)
2720 {
2721   gint x, y, width, height;
2722   FullscreenInfo *fi;
2723   HMONITOR monitor;
2724   MONITORINFO mi;
2725
2726   g_return_if_fail (GDK_IS_WINDOW (window));
2727
2728   fi = g_new (FullscreenInfo, 1);
2729
2730   if (!GetWindowRect (GDK_WINDOW_HWND (window), &(fi->r)))
2731     g_free (fi);
2732   else
2733     {
2734       GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2735
2736       monitor = MonitorFromWindow (GDK_WINDOW_HWND (window), MONITOR_DEFAULTTONEAREST);
2737       mi.cbSize = sizeof (mi);
2738       if (monitor && GetMonitorInfo (monitor, &mi))
2739         {
2740           x = mi.rcMonitor.left;
2741           y = mi.rcMonitor.top;
2742           width = mi.rcMonitor.right - x;
2743           height = mi.rcMonitor.bottom - y;
2744         }
2745       else
2746         {
2747           x = y = 0;
2748           width = GetSystemMetrics (SM_CXSCREEN);
2749           height = GetSystemMetrics (SM_CYSCREEN);
2750         }
2751
2752       /* remember for restoring */
2753       fi->hint_flags = impl->hint_flags;
2754       impl->hint_flags &= ~GDK_HINT_MAX_SIZE;
2755       g_object_set_data (G_OBJECT (window), "fullscreen-info", fi);
2756       fi->style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
2757
2758       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, 
2759                      (fi->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
2760
2761       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOP,
2762                                x, y, width, height,
2763                                SWP_NOCOPYBITS | SWP_SHOWWINDOW));
2764
2765       gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
2766     }
2767 }
2768
2769 static void
2770 gdk_win32_window_unfullscreen (GdkWindow *window)
2771 {
2772   FullscreenInfo *fi;
2773
2774   g_return_if_fail (GDK_IS_WINDOW (window));
2775
2776   fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
2777   if (fi)
2778     {
2779       GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2780
2781       impl->hint_flags = fi->hint_flags;
2782       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, fi->style);
2783       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_NOTOPMOST,
2784                                fi->r.left, fi->r.top,
2785                                fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
2786                                SWP_NOCOPYBITS | SWP_SHOWWINDOW));
2787       
2788       g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
2789       g_free (fi);
2790
2791       gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
2792     }
2793 }
2794
2795 static void
2796 gdk_win32_window_set_keep_above (GdkWindow *window,
2797                            gboolean   setting)
2798 {
2799   g_return_if_fail (GDK_IS_WINDOW (window));
2800
2801   if (GDK_WINDOW_DESTROYED (window))
2802     return;
2803
2804   GDK_NOTE (MISC, g_print ("gdk_window_set_keep_above: %p: %s\n",
2805                            GDK_WINDOW_HWND (window),
2806                            setting ? "YES" : "NO"));
2807
2808   if (GDK_WINDOW_IS_MAPPED (window))
2809     {
2810       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
2811                                setting ? HWND_TOPMOST : HWND_NOTOPMOST,
2812                                0, 0, 0, 0,
2813                                SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
2814     }
2815   else
2816     gdk_synthesize_window_state (window,
2817                                  setting ? GDK_WINDOW_STATE_BELOW : GDK_WINDOW_STATE_ABOVE,
2818                                  setting ? GDK_WINDOW_STATE_ABOVE : 0);
2819 }
2820
2821 static void
2822 gdk_win32_window_set_keep_below (GdkWindow *window,
2823                            gboolean   setting)
2824 {
2825   g_return_if_fail (GDK_IS_WINDOW (window));
2826
2827   if (GDK_WINDOW_DESTROYED (window))
2828     return;
2829
2830   GDK_NOTE (MISC, g_print ("gdk_window_set_keep_below: %p: %s\n",
2831                            GDK_WINDOW_HWND (window),
2832                            setting ? "YES" : "NO"));
2833
2834   if (GDK_WINDOW_IS_MAPPED (window))
2835     {
2836       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
2837                                setting ? HWND_BOTTOM : HWND_NOTOPMOST,
2838                                0, 0, 0, 0,
2839                                SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
2840     }
2841   else
2842     gdk_synthesize_window_state (window,
2843                                  setting ? GDK_WINDOW_STATE_ABOVE : GDK_WINDOW_STATE_BELOW,
2844                                  setting ? GDK_WINDOW_STATE_BELOW : 0);
2845 }
2846
2847 static void
2848 gdk_win32_window_focus (GdkWindow *window,
2849                         guint32    timestamp)
2850 {
2851   g_return_if_fail (GDK_IS_WINDOW (window));
2852
2853   if (GDK_WINDOW_DESTROYED (window))
2854     return;
2855   
2856   GDK_NOTE (MISC, g_print ("gdk_window_focus: %p: %s\n",
2857                            GDK_WINDOW_HWND (window),
2858                            _gdk_win32_window_state_to_string (window->state)));
2859
2860   if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
2861     ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMAXIMIZED);
2862   else
2863     ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNORMAL);
2864   SetFocus (GDK_WINDOW_HWND (window));
2865 }
2866
2867 static void
2868 gdk_win32_window_set_modal_hint (GdkWindow *window,
2869                            gboolean   modal)
2870 {
2871   g_return_if_fail (GDK_IS_WINDOW (window));
2872   
2873   if (GDK_WINDOW_DESTROYED (window))
2874     return;
2875
2876   GDK_NOTE (MISC, g_print ("gdk_window_set_modal_hint: %p: %s\n",
2877                            GDK_WINDOW_HWND (window),
2878                            modal ? "YES" : "NO"));
2879
2880   if (modal == window->modal_hint)
2881     return;
2882
2883   window->modal_hint = modal;
2884
2885 #if 0
2886   /* Not sure about this one.. -- Cody */
2887   if (GDK_WINDOW_IS_MAPPED (window))
2888     API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), 
2889                              modal ? HWND_TOPMOST : HWND_NOTOPMOST,
2890                              0, 0, 0, 0,
2891                              SWP_NOMOVE | SWP_NOSIZE));
2892 #else
2893
2894   if (modal)
2895     {
2896       _gdk_push_modal_window (window);
2897       gdk_window_raise (window);
2898     }
2899   else
2900     {
2901       _gdk_remove_modal_window (window);
2902     }
2903
2904 #endif
2905 }
2906
2907 static void
2908 gdk_win32_window_set_skip_taskbar_hint (GdkWindow *window,
2909                                   gboolean   skips_taskbar)
2910 {
2911   static GdkWindow *owner = NULL;
2912   //GdkWindowAttr wa;
2913
2914   g_return_if_fail (GDK_IS_WINDOW (window));
2915
2916   GDK_NOTE (MISC, g_print ("gdk_window_set_skip_taskbar_hint: %p: %s, doing nothing\n",
2917                            GDK_WINDOW_HWND (window),
2918                            skips_taskbar ? "YES" : "NO"));
2919
2920   // ### TODO: Need to figure out what to do here.
2921   return;
2922
2923   if (skips_taskbar)
2924     {
2925 #if 0
2926       if (owner == NULL)
2927                 {
2928                   wa.window_type = GDK_WINDOW_TEMP;
2929                   wa.wclass = GDK_INPUT_OUTPUT;
2930                   wa.width = wa.height = 1;
2931                   wa.event_mask = 0;
2932                   owner = gdk_window_new_internal (NULL, &wa, 0, TRUE);
2933                 }
2934 #endif
2935
2936       SetWindowLongPtr (GDK_WINDOW_HWND (window), GWLP_HWNDPARENT, (LONG_PTR) GDK_WINDOW_HWND (owner));
2937
2938 #if 0 /* Should we also turn off the minimize and maximize buttons? */
2939       SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE,
2940                      GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE) & ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU));
2941      
2942       SetWindowPos (GDK_WINDOW_HWND (window), NULL,
2943                     0, 0, 0, 0,
2944                     SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
2945                     SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
2946 #endif
2947     }
2948   else
2949     {
2950       SetWindowLongPtr (GDK_WINDOW_HWND (window), GWLP_HWNDPARENT, 0);
2951     }
2952 }
2953
2954 static void
2955 gdk_win32_window_set_skip_pager_hint (GdkWindow *window,
2956                                 gboolean   skips_pager)
2957 {
2958   g_return_if_fail (GDK_IS_WINDOW (window));
2959
2960   GDK_NOTE (MISC, g_print ("gdk_window_set_skip_pager_hint: %p: %s, doing nothing\n",
2961                            GDK_WINDOW_HWND (window),
2962                            skips_pager ? "YES" : "NO"));
2963 }
2964
2965 static void
2966 gdk_win32_window_set_type_hint (GdkWindow        *window,
2967                           GdkWindowTypeHint hint)
2968 {
2969   g_return_if_fail (GDK_IS_WINDOW (window));
2970   
2971   if (GDK_WINDOW_DESTROYED (window))
2972     return;
2973
2974   GDK_NOTE (MISC,
2975             G_STMT_START{
2976               static GEnumClass *class = NULL;
2977               if (!class)
2978                 class = g_type_class_ref (GDK_TYPE_WINDOW_TYPE_HINT);
2979               g_print ("gdk_window_set_type_hint: %p: %s\n",
2980                        GDK_WINDOW_HWND (window),
2981                        g_enum_get_value (class, hint)->value_name);
2982             }G_STMT_END);
2983
2984   ((GdkWindowImplWin32 *)window->impl)->type_hint = hint;
2985
2986   update_style_bits (window);
2987 }
2988
2989 static GdkWindowTypeHint
2990 gdk_win32_window_get_type_hint (GdkWindow *window)
2991 {
2992   g_return_val_if_fail (GDK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
2993   
2994   if (GDK_WINDOW_DESTROYED (window))
2995     return GDK_WINDOW_TYPE_HINT_NORMAL;
2996
2997   return GDK_WINDOW_IMPL_WIN32 (window->impl)->type_hint;
2998 }
2999
3000 static HRGN
3001 cairo_region_to_hrgn (const cairo_region_t *region,
3002                       gint                  x_origin,
3003                       gint                  y_origin)
3004 {
3005   HRGN hrgn;
3006   RGNDATA *rgndata;
3007   RECT *rect;
3008   cairo_rectangle_int_t r;
3009   const int nrects = cairo_region_num_rectangles (region);
3010   guint nbytes =
3011     sizeof (RGNDATAHEADER) + (sizeof (RECT) * nrects);
3012   int i;
3013
3014   rgndata = g_malloc (nbytes);
3015   rgndata->rdh.dwSize = sizeof (RGNDATAHEADER);
3016   rgndata->rdh.iType = RDH_RECTANGLES;
3017   rgndata->rdh.nCount = rgndata->rdh.nRgnSize = 0;
3018   SetRect (&rgndata->rdh.rcBound,
3019            G_MAXLONG, G_MAXLONG, G_MINLONG, G_MINLONG);
3020
3021   for (i = 0; i < nrects; i++)
3022     {
3023       rect = ((RECT *) rgndata->Buffer) + rgndata->rdh.nCount++;
3024       
3025       cairo_region_get_rectangle (region, i, &r);
3026       rect->left = r.x + x_origin;
3027       rect->right = rect->left + r.width;
3028       rect->top = r.y + y_origin;
3029       rect->bottom = rect->top + r.height;
3030
3031       if (rect->left < rgndata->rdh.rcBound.left)
3032         rgndata->rdh.rcBound.left = rect->left;
3033       if (rect->right > rgndata->rdh.rcBound.right)
3034         rgndata->rdh.rcBound.right = rect->right;
3035       if (rect->top < rgndata->rdh.rcBound.top)
3036         rgndata->rdh.rcBound.top = rect->top;
3037       if (rect->bottom > rgndata->rdh.rcBound.bottom)
3038         rgndata->rdh.rcBound.bottom = rect->bottom;
3039     }
3040   if ((hrgn = ExtCreateRegion (NULL, nbytes, rgndata)) == NULL)
3041     WIN32_API_FAILED ("ExtCreateRegion");
3042
3043   g_free (rgndata);
3044
3045   return (hrgn);
3046 }
3047
3048 static void
3049 gdk_win32_window_shape_combine_region (GdkWindow       *window,
3050                                        const cairo_region_t *shape_region,
3051                                        gint             offset_x,
3052                                        gint             offset_y)
3053 {
3054   if (GDK_WINDOW_DESTROYED (window))
3055     return;
3056
3057   if (!shape_region)
3058     {
3059       GDK_NOTE (MISC, g_print ("gdk_win32_window_shape_combine_region: %p: none\n",
3060                                GDK_WINDOW_HWND (window)));
3061       SetWindowRgn (GDK_WINDOW_HWND (window), NULL, TRUE);
3062     }
3063   else
3064     {
3065       HRGN hrgn;
3066
3067       hrgn = cairo_region_to_hrgn (shape_region, 0, 0);
3068       
3069       GDK_NOTE (MISC, g_print ("gdk_win32_window_shape_combine_region: %p: %p\n",
3070                                GDK_WINDOW_HWND (window),
3071                                hrgn));
3072
3073       do_shape_combine_region (window, hrgn, offset_x, offset_y);
3074     }
3075 }
3076
3077 GdkWindow *
3078 gdk_win32_window_lookup_for_display (GdkDisplay *display,
3079                                      HWND        anid)
3080 {
3081   g_return_val_if_fail (display == _gdk_display, NULL);
3082
3083   return (GdkWindow*) gdk_win32_handle_table_lookup (anid);
3084 }
3085
3086 static void
3087 gdk_win32_window_enable_synchronized_configure (GdkWindow *window)
3088 {
3089   /* nothing - no window manager to cooperate with */
3090 }
3091
3092 static void
3093 gdk_win32_window_configure_finished (GdkWindow *window)
3094 {
3095   /* nothing - no window manager to cooperate with */
3096 }
3097
3098 static void
3099 gdk_win32_window_set_opacity (GdkWindow *window,
3100                         gdouble    opacity)
3101 {
3102   LONG exstyle;
3103   typedef BOOL (*PFN_SetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
3104   PFN_SetLayeredWindowAttributes setLayeredWindowAttributes = NULL;
3105
3106   g_return_if_fail (GDK_IS_WINDOW (window));
3107   g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
3108
3109   if (GDK_WINDOW_DESTROYED (window))
3110     return;
3111
3112   if (opacity < 0)
3113     opacity = 0;
3114   else if (opacity > 1)
3115     opacity = 1;
3116
3117   exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
3118
3119   if (!(exstyle & WS_EX_LAYERED))
3120     API_CALL (SetWindowLong, (GDK_WINDOW_HWND (window),
3121                               GWL_EXSTYLE,
3122                               exstyle | WS_EX_LAYERED));
3123
3124   setLayeredWindowAttributes = 
3125     (PFN_SetLayeredWindowAttributes)GetProcAddress (GetModuleHandle ("user32.dll"), "SetLayeredWindowAttributes");
3126
3127   if (setLayeredWindowAttributes)
3128     {
3129       API_CALL (setLayeredWindowAttributes, (GDK_WINDOW_HWND (window),
3130                                              0,
3131                                              opacity * 0xff,
3132                                              LWA_ALPHA));
3133     }
3134 }
3135
3136 static cairo_region_t *
3137 gdk_win32_window_get_shape (GdkWindow *window)
3138 {
3139   HRGN hrgn = CreateRectRgn (0, 0, 0, 0);
3140   int  type = GetWindowRgn (GDK_WINDOW_HWND (window), hrgn);
3141
3142   if (type == SIMPLEREGION || type == COMPLEXREGION)
3143     {
3144       cairo_region_t *region = _gdk_win32_hrgn_to_region (hrgn);
3145
3146       DeleteObject (hrgn);
3147       return region;
3148     }
3149
3150   return NULL;
3151 }
3152
3153 static gboolean
3154 _gdk_win32_window_queue_antiexpose (GdkWindow *window,
3155                                     cairo_region_t *area)
3156 {
3157   HRGN hrgn = cairo_region_to_hrgn (area, 0, 0);
3158
3159   GDK_NOTE (EVENTS, g_print ("_gdk_windowing_window_queue_antiexpose: ValidateRgn %p %s\n",
3160                              GDK_WINDOW_HWND (window),
3161                              _gdk_win32_cairo_region_to_string (area)));
3162
3163   ValidateRgn (GDK_WINDOW_HWND (window), hrgn);
3164
3165   DeleteObject (hrgn);
3166
3167   return FALSE;
3168 }
3169
3170 /* Gets called from gdwindow.c(do_move_region_bits_on_impl)
3171  * and got tested with testgtk::big_window. Given the previous,
3172  * untested implementation this one looks much too simple ;)
3173  */
3174 static void
3175 _gdk_win32_window_translate (GdkWindow *window,
3176                              cairo_region_t *area, /* In impl window coords */
3177                              gint       dx,
3178                              gint       dy)
3179 {
3180   GdkRectangle extents;
3181   RECT rect;
3182
3183   cairo_region_get_extents (area, &extents);
3184   rect.left = extents.x - dx;
3185   rect.top = extents.y - dy;
3186   rect.right = rect.left + extents.width;
3187   rect.bottom = rect.top + extents.height;
3188
3189   API_CALL (ScrollWindowEx, (GDK_WINDOW_HWND (window), 
3190                              dx, dy, &rect, 
3191                              NULL, NULL, NULL, 
3192                              SW_INVALIDATE));
3193
3194 }
3195
3196 static void
3197 gdk_win32_input_shape_combine_region (GdkWindow *window,
3198                                       const cairo_region_t *shape_region,
3199                                       gint offset_x,
3200                                       gint offset_y)
3201 {
3202   if (GDK_WINDOW_DESTROYED (window))
3203     return;
3204   /* CHECK: are these really supposed to be the same? */
3205   gdk_win32_window_shape_combine_region (window, shape_region, offset_x, offset_y);
3206 }
3207
3208 static void
3209 gdk_win32_window_process_updates_recurse (GdkWindow *window,
3210                                                cairo_region_t *region)
3211 {
3212   _gdk_window_process_updates_recurse (window, region);
3213 }
3214
3215 gboolean
3216 gdk_win32_window_is_win32 (GdkWindow *window)
3217 {
3218   return GDK_WINDOW_IS_WIN32 (window);
3219 }
3220
3221 /**
3222  * _gdk_win32_acquire_dc
3223  * @impl: a Win32 #GdkWindowImplWin32 implementation
3224  * 
3225  * Gets a DC with the given drawable selected into it.
3226  *
3227  * Return value: The DC, on success. Otherwise
3228  *  %NULL. If this function succeeded
3229  *  _gdk_win32_impl_release_dc()  must be called
3230  *  release the DC when you are done using it.
3231  **/
3232 static HDC 
3233 _gdk_win32_impl_acquire_dc (GdkWindowImplWin32 *impl)
3234 {
3235   if (GDK_IS_WINDOW_IMPL_WIN32 (impl) &&
3236       GDK_WINDOW_DESTROYED (impl->wrapper))
3237     return NULL;
3238
3239   if (!impl->hdc)
3240     {
3241       impl->hdc = GetDC (impl->handle);
3242       if (!impl->hdc)
3243         WIN32_GDI_FAILED ("GetDC");
3244     }
3245
3246   if (impl->hdc)
3247     {
3248       impl->hdc_count++;
3249       return impl->hdc;
3250     }
3251   else
3252     {
3253       return NULL;
3254     }
3255 }
3256
3257 /**
3258  * _gdk_win32_impl_release_dc
3259  * @impl: a Win32 #GdkWindowImplWin32 implementation
3260  * 
3261  * Releases the reference count for the DC
3262  * from _gdk_win32_impl_acquire_dc()
3263  **/
3264 static void
3265 _gdk_win32_impl_release_dc (GdkWindowImplWin32 *impl)
3266 {
3267   g_return_if_fail (impl->hdc_count > 0);
3268
3269   impl->hdc_count--;
3270   if (impl->hdc_count == 0)
3271     {
3272       if (impl->saved_dc_bitmap)
3273         {
3274           GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
3275           impl->saved_dc_bitmap = NULL;
3276         }
3277       
3278       if (impl->hdc)
3279         {
3280           GDI_CALL (ReleaseDC, (impl->handle, impl->hdc));
3281           impl->hdc = NULL;
3282         }
3283     }
3284 }
3285
3286 static void
3287 gdk_win32_cairo_surface_destroy (void *data)
3288 {
3289   GdkWindowImplWin32 *impl = data;
3290
3291   _gdk_win32_impl_release_dc (impl);
3292   impl->cairo_surface = NULL;
3293 }
3294
3295 static cairo_surface_t *
3296 gdk_win32_ref_cairo_surface (GdkWindow *window)
3297 {
3298   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
3299
3300   if (GDK_IS_WINDOW_IMPL_WIN32 (impl) &&
3301       GDK_WINDOW_DESTROYED (impl->wrapper))
3302     return NULL;
3303
3304   if (!impl->cairo_surface)
3305     {
3306       HDC hdc = _gdk_win32_impl_acquire_dc (impl);
3307       if (!hdc)
3308         return NULL;
3309
3310       impl->cairo_surface = cairo_win32_surface_create (hdc);
3311
3312       cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
3313                                    impl, gdk_win32_cairo_surface_destroy);
3314     }
3315   else
3316     cairo_surface_reference (impl->cairo_surface);
3317
3318   return impl->cairo_surface;
3319 }
3320
3321 static void
3322 gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
3323 {
3324   GObjectClass *object_class = G_OBJECT_CLASS (klass);
3325   GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
3326
3327   parent_class = g_type_class_peek_parent (klass);
3328
3329   object_class->finalize = gdk_window_impl_win32_finalize;
3330   
3331   impl_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
3332
3333   impl_class->show = gdk_win32_window_show;
3334   impl_class->hide = gdk_win32_window_hide;
3335   impl_class->withdraw = gdk_win32_window_withdraw;
3336   impl_class->set_events = gdk_win32_window_set_events;
3337   impl_class->get_events = gdk_win32_window_get_events;
3338   impl_class->raise = gdk_win32_window_raise;
3339   impl_class->lower = gdk_win32_window_lower;
3340   impl_class->restack_under = gdk_win32_window_restack_under;
3341   impl_class->restack_toplevel = gdk_win32_window_restack_toplevel;
3342   impl_class->move_resize = gdk_win32_window_move_resize;
3343   impl_class->set_background = gdk_win32_window_set_background;
3344   impl_class->reparent = gdk_win32_window_reparent;
3345   impl_class->set_device_cursor = gdk_win32_window_set_device_cursor;
3346   impl_class->get_geometry = gdk_win32_window_get_geometry;
3347   impl_class->get_device_state = gdk_window_win32_get_device_state;
3348   impl_class->get_root_coords = gdk_win32_window_get_root_coords;
3349
3350   impl_class->shape_combine_region = gdk_win32_window_shape_combine_region;
3351   impl_class->input_shape_combine_region = gdk_win32_input_shape_combine_region;
3352   impl_class->set_static_gravities = gdk_win32_window_set_static_gravities;
3353   impl_class->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
3354   impl_class->translate = _gdk_win32_window_translate;
3355   impl_class->destroy = gdk_win32_window_destroy;
3356   impl_class->destroy_foreign = gdk_win32_window_destroy_foreign;
3357   impl_class->resize_cairo_surface = gdk_win32_window_resize_cairo_surface;
3358   impl_class->get_shape = gdk_win32_window_get_shape;
3359   //FIXME?: impl_class->get_input_shape = gdk_win32_window_get_input_shape;
3360
3361   //impl_class->beep = gdk_x11_window_beep;
3362
3363   impl_class->focus = gdk_win32_window_focus;
3364   impl_class->set_type_hint = gdk_win32_window_set_type_hint;
3365   impl_class->get_type_hint = gdk_win32_window_get_type_hint;
3366   impl_class->set_modal_hint = gdk_win32_window_set_modal_hint;
3367   impl_class->set_skip_taskbar_hint = gdk_win32_window_set_skip_taskbar_hint;
3368   impl_class->set_skip_pager_hint = gdk_win32_window_set_skip_pager_hint;
3369   impl_class->set_urgency_hint = gdk_win32_window_set_urgency_hint;
3370   impl_class->set_geometry_hints = gdk_win32_window_set_geometry_hints;
3371   impl_class->set_title = gdk_win32_window_set_title;
3372   impl_class->set_role = gdk_win32_window_set_role;
3373   //impl_class->set_startup_id = gdk_x11_window_set_startup_id;
3374   impl_class->set_transient_for = gdk_win32_window_set_transient_for;
3375   impl_class->get_root_origin = gdk_win32_window_get_root_origin;
3376   impl_class->get_frame_extents = gdk_win32_window_get_frame_extents;
3377   impl_class->set_override_redirect = gdk_win32_window_set_override_redirect;
3378   impl_class->set_accept_focus = gdk_win32_window_set_accept_focus;
3379   impl_class->set_focus_on_map = gdk_win32_window_set_focus_on_map;
3380   impl_class->set_icon_list = gdk_win32_window_set_icon_list;
3381   impl_class->set_icon_name = gdk_win32_window_set_icon_name;
3382   impl_class->iconify = gdk_win32_window_iconify;
3383   impl_class->deiconify = gdk_win32_window_deiconify;
3384   impl_class->stick = gdk_win32_window_stick;
3385   impl_class->unstick = gdk_win32_window_unstick;
3386   impl_class->maximize = gdk_win32_window_maximize;
3387   impl_class->unmaximize = gdk_win32_window_unmaximize;
3388   impl_class->fullscreen = gdk_win32_window_fullscreen;
3389   impl_class->unfullscreen = gdk_win32_window_unfullscreen;
3390   impl_class->set_keep_above = gdk_win32_window_set_keep_above;
3391   impl_class->set_keep_below = gdk_win32_window_set_keep_below;
3392   impl_class->get_group = gdk_win32_window_get_group;
3393   impl_class->set_group = gdk_win32_window_set_group;
3394   impl_class->set_decorations = gdk_win32_window_set_decorations;
3395   impl_class->get_decorations = gdk_win32_window_get_decorations;
3396   impl_class->set_functions = gdk_win32_window_set_functions;
3397
3398   impl_class->begin_resize_drag = gdk_win32_window_begin_resize_drag;
3399   impl_class->begin_move_drag = gdk_win32_window_begin_move_drag;
3400   impl_class->enable_synchronized_configure = gdk_win32_window_enable_synchronized_configure;
3401   impl_class->configure_finished = gdk_win32_window_configure_finished;
3402   impl_class->set_opacity = gdk_win32_window_set_opacity;
3403   //impl_class->set_composited = gdk_win32_window_set_composited;
3404   impl_class->destroy_notify = gdk_win32_window_destroy_notify;
3405   impl_class->get_drag_protocol = _gdk_win32_window_get_drag_protocol;
3406   impl_class->register_dnd = _gdk_win32_window_register_dnd;
3407   impl_class->drag_begin = _gdk_win32_window_drag_begin;
3408   impl_class->process_updates_recurse = gdk_win32_window_process_updates_recurse;
3409   //? impl_class->sync_rendering = _gdk_win32_window_sync_rendering;
3410   impl_class->simulate_key = _gdk_win32_window_simulate_key;
3411   impl_class->simulate_button = _gdk_win32_window_simulate_button;
3412   impl_class->get_property = _gdk_win32_window_get_property;
3413   impl_class->change_property = _gdk_win32_window_change_property;
3414   impl_class->delete_property = _gdk_win32_window_delete_property;
3415 }
3416
3417 HGDIOBJ
3418 gdk_win32_window_get_handle (GdkWindow *window)
3419 {
3420   /* Try to ensure the window has a native window */
3421   if (!_gdk_window_has_impl (window))
3422     gdk_window_ensure_native (window);
3423
3424   if (!GDK_WINDOW_IS_WIN32 (window))
3425     {
3426       g_warning (G_STRLOC " window is not a native Win32 window");
3427       return NULL;
3428     }
3429
3430   return GDK_WINDOW_HWND (window);
3431 }