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