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