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