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