1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-2004 Tor Lillqvist
4 * Copyright (C) 2001-2011 Hans Breuer
5 * Copyright (C) 2007-2009 Cody Russell
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /*
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26 */
27
28 #include "config.h"
29 #include <stdlib.h>
30
31 #include "gdk.h"
32 #include "gdksurfaceprivate.h"
33 #include "gdktoplevelprivate.h"
34 #include "gdkpopupprivate.h"
35 #include "gdkdragsurfaceprivate.h"
36 #include "gdkprivate-win32.h"
37 #include "gdkdeviceprivate.h"
38 #include "gdkdevicemanager-win32.h"
39 #include "gdkenumtypes.h"
40 #include "gdkwin32.h"
41 #include "gdkdisplayprivate.h"
42 #include "gdkframeclockidleprivate.h"
43 #include "gdkmonitorprivate.h"
44 #include "gdkwin32surface.h"
45 #include "gdkwin32cursor.h"
46 #include "gdkinput-winpointer.h"
47 #include "gdkglcontext-win32.h"
48 #include "gdkdisplay-win32.h"
49 #include "gdkdevice-win32.h"
50 #include "gdkcairocontext-win32.h"
51
52 #include <cairo-win32.h>
53 #include <dwmapi.h>
54 #include <math.h>
55
56 static void gdk_surface_win32_finalize (GObject *object);
57 static void compute_toplevel_size (GdkSurface *surface,
58 gboolean update_geometry,
59 int *width,
60 int *height);
61
62 static gpointer parent_class = NULL;
63 static GSList *modal_window_stack = NULL;
64
65 typedef struct _FullscreenInfo FullscreenInfo;
66
67 struct _FullscreenInfo
68 {
69 RECT r;
70 guint hint_flags;
71 LONG style;
72 };
73
74 struct _AeroSnapEdgeRegion
75 {
76 /* The rectangle along the edge of the desktop
77 * that allows application of the snap transformation.
78 */
79 GdkRectangle edge;
80
81 /* A subregion of the "edge". When the pointer hits
82 * this region, the transformation is revealed.
83 * Usually it is 1-pixel thick and is located at the
84 * very edge of the screen. When there's a toolbar
85 * at that edge, the "trigger" and the "edge" regions
86 * are extended to cover that toolbar.
87 */
88 GdkRectangle trigger;
89 };
90
91 typedef struct _AeroSnapEdgeRegion AeroSnapEdgeRegion;
92
93 /* Size of the regions at the edges of the desktop where
94 * snapping can take place (in pixels)
95 */
96 #define AEROSNAP_REGION_THICKNESS (20)
97 /* Size of the subregions that actually trigger the snapping prompt
98 * (in pixels).
99 */
100 #define AEROSNAP_REGION_TRIGGER_THICKNESS (1)
101
102 /* The gap between the snap indicator and the edge of the work area
103 * (in pixels).
104 */
105 #define AEROSNAP_INDICATOR_EDGE_GAP (10)
106
107 /* Width of the outline of the snap indicator
108 * (in pixels).
109 */
110 #define AEROSNAP_INDICATOR_LINE_WIDTH (3.0)
111
112 /* Corner radius of the snap indicator.
113 */
114 #define AEROSNAP_INDICATOR_CORNER_RADIUS (3.0)
115
116 /* The time it takes for snap indicator to expand/shrink
117 * from current window size to future position of the
118 * snapped window (in microseconds).
119 */
120 #define AEROSNAP_INDICATOR_ANIMATION_DURATION (200 * 1000)
121
122 /* Opacity if the snap indicator. */
123 #define AEROSNAP_INDICATOR_OPACITY (0.5)
124
125 /* The interval between snap indicator redraws (in milliseconds).
126 * 16 is ~ 1/60 of a second, for ~60 FPS.
127 */
128 #define AEROSNAP_INDICATOR_ANIMATION_TICK (16)
129
130 static void gdk_win32_impl_frame_clock_after_paint (GdkFrameClock *clock,
131 GdkSurface *surface);
132
133 G_DEFINE_TYPE (GdkWin32Surface, gdk_win32_surface, GDK_TYPE_SURFACE)
134
135 GType gdk_win32_toplevel_get_type (void) G_GNUC_CONST;
136 GType gdk_win32_popup_get_type (void) G_GNUC_CONST;
137 GType gdk_win32_drag_surface_get_type (void) G_GNUC_CONST;
138
139 #define GDK_TYPE_WIN32_TOPLEVEL (gdk_win32_toplevel_get_type ())
140 #define GDK_TYPE_WIN32_POPUP (gdk_win32_popup_get_type ())
141 #define GDK_TYPE_WIN32_DRAG_SURFACE (gdk_win32_drag_surface_get_type ())
142
143 static void
gdk_win32_surface_init(GdkWin32Surface * impl)144 gdk_win32_surface_init (GdkWin32Surface *impl)
145 {
146 impl->hicon_big = NULL;
147 impl->hicon_small = NULL;
148 impl->hint_flags = 0;
149 impl->transient_owner = NULL;
150 impl->transient_children = NULL;
151 impl->num_transients = 0;
152 impl->changing_state = FALSE;
153 impl->surface_scale = 1;
154 }
155
156
157 static void
gdk_surface_win32_dispose(GObject * object)158 gdk_surface_win32_dispose (GObject *object)
159 {
160 GdkWin32Surface *surface;
161
162 g_return_if_fail (GDK_IS_WIN32_SURFACE (object));
163
164 surface = GDK_WIN32_SURFACE (object);
165
166 g_clear_object (&surface->cursor);
167
168 G_OBJECT_CLASS (parent_class)->dispose (object);
169 }
170
171
172 static void
gdk_surface_win32_finalize(GObject * object)173 gdk_surface_win32_finalize (GObject *object)
174 {
175 GdkWin32Surface *surface;
176
177 g_return_if_fail (GDK_IS_WIN32_SURFACE (object));
178
179 surface = GDK_WIN32_SURFACE (object);
180
181 if (!GDK_SURFACE_DESTROYED (surface))
182 {
183 gdk_win32_handle_table_remove (surface->handle);
184 }
185
186 g_clear_pointer (&surface->snap_stash, g_free);
187 g_clear_pointer (&surface->snap_stash_int, g_free);
188
189 if (surface->hicon_big != NULL)
190 {
191 GDI_CALL (DestroyIcon, (surface->hicon_big));
192 surface->hicon_big = NULL;
193 }
194
195 if (surface->hicon_small != NULL)
196 {
197 GDI_CALL (DestroyIcon, (surface->hicon_small));
198 surface->hicon_small = NULL;
199 }
200
201 if (surface->cache_surface)
202 {
203 cairo_surface_destroy (surface->cache_surface);
204 surface->cache_surface = NULL;
205 }
206
207 _gdk_win32_surface_unregister_dnd (GDK_SURFACE (surface));
208
209 g_assert (surface->transient_owner == NULL);
210 g_assert (surface->transient_children == NULL);
211
212 G_OBJECT_CLASS (parent_class)->finalize (object);
213 }
214
215 void
_gdk_win32_get_window_client_area_rect(GdkSurface * window,int scale,RECT * rect)216 _gdk_win32_get_window_client_area_rect (GdkSurface *window,
217 int scale,
218 RECT *rect)
219 {
220 int x, y, width, height;
221
222 gdk_surface_get_geometry (window, &x, &y, NULL, NULL);
223 width = gdk_surface_get_width (window);
224 height = gdk_surface_get_height (window);
225 rect->left = x * scale;
226 rect->top = y * scale;
227 rect->right = rect->left + width * scale;
228 rect->bottom = rect->top + height * scale;
229 }
230
231 static void
gdk_win32_impl_frame_clock_after_paint(GdkFrameClock * clock,GdkSurface * surface)232 gdk_win32_impl_frame_clock_after_paint (GdkFrameClock *clock,
233 GdkSurface *surface)
234 {
235 DWM_TIMING_INFO timing_info;
236 LARGE_INTEGER tick_frequency;
237 GdkFrameTimings *timings;
238
239 timings = gdk_frame_clock_get_timings (clock, gdk_frame_clock_get_frame_counter (clock));
240
241 if (timings)
242 {
243 timings->refresh_interval = 16667; /* default to 1/60th of a second */
244 timings->presentation_time = 0;
245
246 if (QueryPerformanceFrequency (&tick_frequency))
247 {
248 HRESULT hr;
249
250 timing_info.cbSize = sizeof (timing_info);
251 hr = DwmGetCompositionTimingInfo (NULL, &timing_info);
252
253 if (SUCCEEDED (hr))
254 {
255 timings->refresh_interval = timing_info.qpcRefreshPeriod * (double)G_USEC_PER_SEC / tick_frequency.QuadPart;
256 timings->presentation_time = timing_info.qpcCompose * (double)G_USEC_PER_SEC / tick_frequency.QuadPart;
257 }
258 }
259
260 timings->complete = TRUE;
261 }
262 }
263
264 void
_gdk_win32_adjust_client_rect(GdkSurface * window,RECT * rect)265 _gdk_win32_adjust_client_rect (GdkSurface *window,
266 RECT *rect)
267 {
268 LONG style, exstyle;
269
270 style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
271 exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
272 API_CALL (AdjustWindowRectEx, (rect, style, FALSE, exstyle));
273 }
274
275 gboolean
_gdk_win32_surface_enable_transparency(GdkSurface * window)276 _gdk_win32_surface_enable_transparency (GdkSurface *window)
277 {
278 DWM_BLURBEHIND blur_behind;
279 HRGN empty_region;
280 HRESULT call_result;
281 HWND thiswindow;
282
283 if (window == NULL || GDK_SURFACE_HWND (window) == NULL)
284 return FALSE;
285
286 if (!gdk_display_is_composited (gdk_surface_get_display (window)))
287 return FALSE;
288
289 thiswindow = GDK_SURFACE_HWND (window);
290
291 empty_region = CreateRectRgn (0, 0, -1, -1);
292
293 if (empty_region == NULL)
294 return FALSE;
295
296 memset (&blur_behind, 0, sizeof (blur_behind));
297 blur_behind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
298 blur_behind.hRgnBlur = empty_region;
299 blur_behind.fEnable = TRUE;
300 call_result = DwmEnableBlurBehindWindow (thiswindow, &blur_behind);
301
302 if (!SUCCEEDED (call_result))
303 g_warning ("%s: %s (%p) failed: %" G_GINT32_MODIFIER "x",
304 G_STRLOC, "DwmEnableBlurBehindWindow", thiswindow, (guint32) call_result);
305
306 DeleteObject (empty_region);
307
308 return SUCCEEDED (call_result);
309 }
310
311 static const char *
get_default_title(void)312 get_default_title (void)
313 {
314 const char *title;
315 title = g_get_application_name ();
316 if (!title)
317 title = g_get_prgname ();
318
319 return title;
320 }
321
322 /* RegisterGdkClass
323 * is a wrapper function for RegisterWindowClassEx.
324 * It creates at least one unique class for every
325 * GdkSurfaceType. If support for single window-specific icons
326 * is ever needed (e.g Dialog specific), every such window should
327 * get its own class
328 */
329 static ATOM
RegisterGdkClass(GdkSurfaceType wtype)330 RegisterGdkClass (GdkSurfaceType wtype)
331 {
332 static ATOM klassTOPLEVEL = 0;
333 static ATOM klassTEMP = 0;
334 static HICON hAppIcon = NULL;
335 static HICON hAppIconSm = NULL;
336 static WNDCLASSEXW wcl;
337 ATOM klass = 0;
338
339 wcl.cbSize = sizeof (WNDCLASSEX);
340 wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
341 * on WM_SIZE and WM_MOVE. Flicker, Performance!
342 */
343 wcl.lpfnWndProc = _gdk_win32_surface_procedure;
344 wcl.cbClsExtra = 0;
345 wcl.cbWndExtra = 0;
346 wcl.hInstance = _gdk_dll_hinstance;
347 wcl.hIcon = 0;
348 wcl.hIconSm = 0;
349
350 /* initialize once! */
351 if (0 == hAppIcon && 0 == hAppIconSm)
352 {
353 char sLoc [MAX_PATH+1];
354
355 // try to load first icon of executable program
356 if (0 != GetModuleFileName (NULL, sLoc, MAX_PATH))
357 {
358 ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
359
360 if (0 == hAppIcon && 0 == hAppIconSm)
361 {
362 // fallback : load icon from GTK DLL
363 if (0 != GetModuleFileName (_gdk_dll_hinstance, sLoc, MAX_PATH))
364 {
365 ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
366 }
367 }
368 }
369
370 if (0 == hAppIcon && 0 == hAppIconSm)
371 {
372 hAppIcon = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
373 GetSystemMetrics (SM_CXICON),
374 GetSystemMetrics (SM_CYICON), 0);
375 hAppIconSm = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
376 GetSystemMetrics (SM_CXSMICON),
377 GetSystemMetrics (SM_CYSMICON), 0);
378 }
379 }
380
381 if (0 == hAppIcon)
382 hAppIcon = hAppIconSm;
383 else if (0 == hAppIconSm)
384 hAppIconSm = hAppIcon;
385
386 wcl.lpszMenuName = NULL;
387
388 /* initialize once per class */
389 /*
390 * HB: Setting the background brush leads to flicker, because we
391 * don't get asked how to clear the background. This is not what
392 * we want, at least not for input_only windows ...
393 */
394 #define ONCE_PER_CLASS() \
395 wcl.hIcon = CopyIcon (hAppIcon); \
396 wcl.hIconSm = CopyIcon (hAppIconSm); \
397 wcl.hbrBackground = NULL; \
398 wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
399
400 /* MSDN: CS_OWNDC is needed for OpenGL contexts */
401 wcl.style |= CS_OWNDC;
402
403 switch (wtype)
404 {
405 case GDK_SURFACE_TOPLEVEL:
406 case GDK_SURFACE_POPUP:
407 if (0 == klassTOPLEVEL)
408 {
409 wcl.lpszClassName = L"gdkSurfaceToplevel";
410
411 ONCE_PER_CLASS ();
412 klassTOPLEVEL = RegisterClassExW (&wcl);
413 }
414 klass = klassTOPLEVEL;
415 break;
416
417 case GDK_SURFACE_TEMP:
418 if (klassTEMP == 0)
419 {
420 wcl.lpszClassName = L"gdkSurfaceTemp";
421 wcl.style |= CS_SAVEBITS;
422 ONCE_PER_CLASS ();
423 klassTEMP = RegisterClassExW (&wcl);
424 }
425
426 klass = klassTEMP;
427
428 break;
429
430 default:
431 g_assert_not_reached ();
432 break;
433 }
434
435 if (klass == 0)
436 {
437 WIN32_API_FAILED ("RegisterClassExW");
438 g_error ("That is a fatal error");
439 }
440 return klass;
441 }
442
443 /*
444 * Create native windows.
445 *
446 * With the default Gdk the created windows are mostly toplevel windows.
447 *
448 * Placement of the window is derived from the passed in window,
449 * except for toplevel window where OS/Window Manager placement
450 * is used.
451 *
452 * [1] http://mail.gnome.org/archives/gtk-devel-list/2010-August/msg00214.html
453 */
454 GdkSurface *
_gdk_win32_display_create_surface(GdkDisplay * display,GdkSurfaceType surface_type,GdkSurface * parent,int x,int y,int width,int height)455 _gdk_win32_display_create_surface (GdkDisplay *display,
456 GdkSurfaceType surface_type,
457 GdkSurface *parent,
458 int x,
459 int y,
460 int width,
461 int height)
462 {
463 HWND hwndNew;
464 HANDLE owner;
465 ATOM klass = 0;
466 DWORD dwStyle = 0, dwExStyle;
467 RECT rect;
468 GdkWin32Surface *impl;
469 GdkWin32Display *display_win32;
470 GdkSurface *surface;
471 const char *title;
472 wchar_t *wtitle;
473 int window_width, window_height;
474 int window_x, window_y;
475 int offset_x = 0, offset_y = 0;
476 int real_x = 0, real_y = 0;
477 GdkFrameClock *frame_clock;
478
479 g_return_val_if_fail (display == _gdk_display, NULL);
480
481 GDK_NOTE (MISC,
482 g_print ("_gdk_surface_new: %s\n", (surface_type == GDK_SURFACE_TOPLEVEL ? "TOPLEVEL" :
483 (surface_type == GDK_SURFACE_TEMP ? "TEMP" :
484 (surface_type == GDK_SURFACE_TEMP ? "POPUP" : "???")))));
485
486 display_win32 = GDK_WIN32_DISPLAY (display);
487
488 if (parent)
489 frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
490 else
491 frame_clock = _gdk_frame_clock_idle_new ();
492
493 switch (surface_type)
494 {
495 case GDK_SURFACE_TOPLEVEL:
496 impl = g_object_new (GDK_TYPE_WIN32_TOPLEVEL,
497 "display", display,
498 "frame-clock", frame_clock,
499 NULL);
500 break;
501 case GDK_SURFACE_POPUP:
502 impl = g_object_new (GDK_TYPE_WIN32_POPUP,
503 "parent", parent,
504 "display", display,
505 "frame-clock", frame_clock,
506 NULL);
507 break;
508 case GDK_SURFACE_TEMP:
509 impl = g_object_new (GDK_TYPE_WIN32_DRAG_SURFACE,
510 "display", display,
511 "frame-clock", frame_clock,
512 NULL);
513 break;
514 default:
515 g_assert_not_reached ();
516 break;
517 }
518
519 surface = GDK_SURFACE (impl);
520 surface->x = x;
521 surface->y = y;
522 surface->width = width;
523 surface->height = height;
524
525 impl->surface_scale = gdk_win32_display_get_monitor_scale_factor (display_win32, NULL, NULL);
526
527 dwExStyle = 0;
528 owner = NULL;
529
530 offset_x = _gdk_offset_x;
531 offset_y = _gdk_offset_y;
532 /* MSDN: We need WS_CLIPCHILDREN and WS_CLIPSIBLINGS for GL Context Creation */
533 dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
534
535 switch (surface_type)
536 {
537 case GDK_SURFACE_TOPLEVEL:
538 dwStyle |= WS_OVERLAPPEDWINDOW;
539 break;
540
541 case GDK_SURFACE_TEMP:
542 dwExStyle |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
543 /* fall through */
544 case GDK_SURFACE_POPUP:
545 dwStyle |= WS_POPUP;
546
547 /* Only popup and temp windows are fit to use the Owner Window mechanism */
548 if (parent != NULL)
549 owner = GDK_SURFACE_HWND (parent);
550 break;
551
552 default:
553 g_assert_not_reached ();
554 }
555
556 rect.left = x * impl->surface_scale;
557 rect.top = y * impl->surface_scale;
558 rect.right = rect.left + width * impl->surface_scale;
559 rect.bottom = rect.top + height * impl->surface_scale;
560
561 AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
562
563 real_x = (x - offset_x) * impl->surface_scale;
564 real_y = (y - offset_y) * impl->surface_scale;
565
566 if (surface_type == GDK_SURFACE_TOPLEVEL)
567 {
568 /* We initially place it at default so that we can get the
569 default window positioning if we want */
570 window_x = window_y = CW_USEDEFAULT;
571 }
572 else
573 {
574 /* TEMP: Put these where requested */
575 window_x = real_x;
576 window_y = real_y;
577 }
578
579 window_width = rect.right - rect.left;
580 window_height = rect.bottom - rect.top;
581
582 title = get_default_title ();
583 if (!title || !*title)
584 title = "";
585
586 klass = RegisterGdkClass (surface_type);
587
588 wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
589
590 hwndNew = CreateWindowExW (dwExStyle,
591 MAKEINTRESOURCEW (klass),
592 wtitle,
593 dwStyle,
594 window_x, window_y,
595 window_width, window_height,
596 owner,
597 NULL,
598 _gdk_dll_hinstance,
599 surface);
600 impl->handle = hwndNew;
601
602 GetWindowRect (hwndNew, &rect);
603 impl->initial_x = rect.left;
604 impl->initial_y = rect.top;
605
606 /* Now we know the initial position, move to actually specified position */
607 if (real_x != window_x || real_y != window_y)
608 {
609 API_CALL (SetWindowPos, (hwndNew,
610 SWP_NOZORDER_SPECIFIED,
611 real_x, real_y, 0, 0,
612 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
613 }
614
615 g_object_ref (impl);
616 /* Take note: we're inserting a pointer into a heap-allocated
617 * object (impl). Inserting a pointer to a stack variable
618 * will break the logic, since stack variables are short-lived.
619 * We insert a pointer to the handle instead of the handle itself
620 * probably because we need to hash them differently depending
621 * on the bitness of the OS. That pointer is still unique,
622 * so this works out in the end.
623 */
624 gdk_win32_handle_table_insert (&GDK_SURFACE_HWND (impl), impl);
625
626 GDK_NOTE (MISC, g_print ("... \"%s\" %dx%d@%+d%+d %p = %p\n",
627 title,
628 window_width, window_height,
629 surface->x - offset_x,
630 surface->y - offset_y,
631 owner,
632 hwndNew));
633
634 g_free (wtitle);
635
636 if (impl->handle == NULL)
637 {
638 WIN32_API_FAILED ("CreateWindowExW");
639 g_object_unref (impl);
640 return NULL;
641 }
642
643 if (display_win32->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER)
644 gdk_winpointer_initialize_surface (surface);
645
646 _gdk_win32_surface_enable_transparency (surface);
647 _gdk_win32_surface_register_dnd (surface);
648 _gdk_win32_surface_update_style_bits (surface);
649
650 g_signal_connect (frame_clock,
651 "after-paint",
652 G_CALLBACK (gdk_win32_impl_frame_clock_after_paint),
653 impl);
654
655 g_object_unref (frame_clock);
656 impl->hdc = GetDC (impl->handle);
657
658 return surface;
659 }
660
661 static void
662 gdk_win32_surface_set_transient_for (GdkSurface *window,
663 GdkSurface *parent);
664
665 static void
gdk_win32_surface_destroy(GdkSurface * window,gboolean foreign_destroy)666 gdk_win32_surface_destroy (GdkSurface *window,
667 gboolean foreign_destroy)
668 {
669 GdkWin32Surface *surface = GDK_WIN32_SURFACE (window);
670
671 g_return_if_fail (GDK_IS_SURFACE (window));
672
673 GDK_NOTE (MISC, g_print ("gdk_win32_surface_destroy: %p\n",
674 GDK_SURFACE_HWND (window)));
675
676 /* Remove ourself from the modal stack */
677 _gdk_remove_modal_window (window);
678
679 g_signal_handlers_disconnect_by_func (gdk_surface_get_frame_clock (window),
680 gdk_win32_impl_frame_clock_after_paint,
681 window);
682
683 /* Remove all our transient children */
684 while (surface->transient_children != NULL)
685 {
686 GdkSurface *child = surface->transient_children->data;
687 gdk_win32_surface_set_transient_for (child, NULL);
688 }
689
690 #ifdef GDK_WIN32_ENABLE_EGL
691 GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_surface_get_display (window));
692
693 /* Get rid of any EGLSurfaces that we might have created */
694 if (surface->egl_surface != EGL_NO_SURFACE)
695 {
696 eglDestroySurface (display->egl_disp, surface->egl_surface);
697 surface->egl_surface = EGL_NO_SURFACE;
698 }
699 if (surface->egl_dummy_surface != EGL_NO_SURFACE)
700 {
701 eglDestroySurface (display->egl_disp, surface->egl_dummy_surface);
702 surface->egl_dummy_surface = EGL_NO_SURFACE;
703 }
704 #endif
705
706 /* Remove ourself from our transient owner */
707 if (surface->transient_owner != NULL)
708 {
709 gdk_win32_surface_set_transient_for (window, NULL);
710 }
711
712 if (!foreign_destroy)
713 {
714 window->destroyed = TRUE;
715 DestroyWindow (GDK_SURFACE_HWND (window));
716 }
717 }
718
719 /* This function is called when the window really gone.
720 */
721 static void
gdk_win32_surface_destroy_notify(GdkSurface * window)722 gdk_win32_surface_destroy_notify (GdkSurface *window)
723 {
724 g_return_if_fail (GDK_IS_SURFACE (window));
725
726 GDK_NOTE (EVENTS,
727 g_print ("gdk_surface_destroy_notify: %p%s\n",
728 GDK_SURFACE_HWND (window),
729 (GDK_SURFACE_DESTROYED (window) ? " (destroyed)" : "")));
730
731 if (!GDK_SURFACE_DESTROYED (window))
732 {
733 g_warning ("window %p unexpectedly destroyed",
734 GDK_SURFACE_HWND (window));
735
736 _gdk_surface_destroy (window, TRUE);
737 }
738
739 gdk_win32_handle_table_remove (GDK_SURFACE_HWND (window));
740 g_object_unref (window);
741 }
742
743 static void
get_outer_rect(GdkSurface * window,int width,int height,RECT * rect)744 get_outer_rect (GdkSurface *window,
745 int width,
746 int height,
747 RECT *rect)
748 {
749 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
750
751 rect->left = rect->top = 0;
752 rect->right = width * impl->surface_scale;
753 rect->bottom = height * impl->surface_scale;
754
755 _gdk_win32_adjust_client_rect (window, rect);
756 }
757
758 static void
759 gdk_win32_surface_fullscreen (GdkSurface *window);
760
761 static void
show_window_internal(GdkSurface * window,gboolean already_mapped,gboolean unminimize)762 show_window_internal (GdkSurface *window,
763 gboolean already_mapped,
764 gboolean unminimize)
765 {
766 GdkWin32Surface *surface;
767 DWORD exstyle;
768
769 if (window->destroyed)
770 return;
771
772 GDK_NOTE (MISC, g_print ("show_window_internal: %p: %s%s\n",
773 GDK_SURFACE_HWND (window),
774 _gdk_win32_surface_state_to_string (window->state),
775 (unminimize ? " unminimize" : "")));
776
777 /* If asked to show (not unminimize) a withdrawn and iconified
778 * window, do that.
779 */
780 if (!unminimize &&
781 !already_mapped &&
782 (window->state & GDK_TOPLEVEL_STATE_MINIMIZED))
783 {
784 GtkShowWindow (window, SW_SHOWMINNOACTIVE);
785 return;
786 }
787
788 /* If asked to just show an iconified window, do nothing. */
789 if (!unminimize && (window->state & GDK_TOPLEVEL_STATE_MINIMIZED))
790 return;
791
792 /* If asked to unminimize an already noniconified window, do
793 * nothing. (Especially, don't cause the window to rise and
794 * activate. There are different calls for that.)
795 */
796 if (unminimize && !(window->state & GDK_TOPLEVEL_STATE_MINIMIZED))
797 return;
798
799 /* If asked to show (but not raise) a window that is already
800 * visible, do nothing.
801 */
802 if (!unminimize && !already_mapped && IsWindowVisible (GDK_SURFACE_HWND (window)))
803 return;
804
805 /* Other cases */
806
807 exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
808
809 /* Use SetWindowPos to show transparent windows so automatic redraws
810 * in other windows can be suppressed.
811 */
812 if (exstyle & WS_EX_TRANSPARENT)
813 {
814 UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
815
816 if (GDK_IS_DRAG_SURFACE (window))
817 flags |= SWP_NOACTIVATE;
818
819 SetWindowPos (GDK_SURFACE_HWND (window),
820 SWP_NOZORDER_SPECIFIED, 0, 0, 0, 0, flags);
821
822 return;
823 }
824
825 /* For initial map of "normal" windows we want to emulate WM window
826 * positioning behaviour, which means:
827 * + default to the initial CW_USEDEFAULT placement,
828 * no matter if the user moved the window before showing it.
829 * + Certain window types and hints have more elaborate positioning
830 * schemes.
831 */
832 surface = GDK_WIN32_SURFACE (window);
833 if (!already_mapped &&
834 GDK_IS_TOPLEVEL (window))
835 {
836 gboolean center = FALSE;
837 RECT window_rect, center_on_rect;
838 int x, y;
839
840 x = surface->initial_x;
841 y = surface->initial_y;
842
843 if (FALSE)
844 {
845 HMONITOR monitor;
846 MONITORINFO mi;
847
848 monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
849 mi.cbSize = sizeof (mi);
850 if (monitor && GetMonitorInfo (monitor, &mi))
851 center_on_rect = mi.rcMonitor;
852 else
853 {
854 center_on_rect.left = 0;
855 center_on_rect.top = 0;
856 center_on_rect.right = GetSystemMetrics (SM_CXSCREEN);
857 center_on_rect.bottom = GetSystemMetrics (SM_CYSCREEN);
858 }
859 center = TRUE;
860 }
861 else if (surface->transient_owner != NULL &&
862 GDK_SURFACE_IS_MAPPED (surface->transient_owner))
863 {
864 GdkSurface *owner = surface->transient_owner;
865 /* Center on transient parent */
866 center_on_rect.left = (owner->x - _gdk_offset_x) * surface->surface_scale;
867 center_on_rect.top = (owner->y - _gdk_offset_y) * surface->surface_scale;
868 center_on_rect.right = center_on_rect.left + owner->width * surface->surface_scale;
869 center_on_rect.bottom = center_on_rect.top + owner->height * surface->surface_scale;
870
871 _gdk_win32_adjust_client_rect (GDK_SURFACE (owner), ¢er_on_rect);
872 center = TRUE;
873 }
874
875 if (center)
876 {
877 window_rect.left = 0;
878 window_rect.top = 0;
879 window_rect.right = window->width * surface->surface_scale;
880 window_rect.bottom = window->height * surface->surface_scale;
881 _gdk_win32_adjust_client_rect (window, &window_rect);
882
883 x = center_on_rect.left + ((center_on_rect.right - center_on_rect.left) - (window_rect.right - window_rect.left)) / 2;
884 y = center_on_rect.top + ((center_on_rect.bottom - center_on_rect.top) - (window_rect.bottom - window_rect.top)) / 2;
885 }
886
887 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
888 SWP_NOZORDER_SPECIFIED,
889 x, y, 0, 0,
890 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
891 }
892
893 if (!already_mapped && GDK_IS_TOPLEVEL (window))
894 {
895 /* Ensure new windows are fully onscreen */
896 RECT window_rect;
897 HMONITOR monitor;
898 MONITORINFO mi;
899 int x, y;
900
901 GetWindowRect (GDK_SURFACE_HWND (window), &window_rect);
902
903 monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
904 mi.cbSize = sizeof (mi);
905 if (monitor && GetMonitorInfo (monitor, &mi))
906 {
907 x = window_rect.left;
908 y = window_rect.top;
909
910 if (window_rect.right > mi.rcWork.right)
911 {
912 window_rect.left -= (window_rect.right - mi.rcWork.right);
913 window_rect.right -= (window_rect.right - mi.rcWork.right);
914 }
915
916 if (window_rect.bottom > mi.rcWork.bottom)
917 {
918 window_rect.top -= (window_rect.bottom - mi.rcWork.bottom);
919 window_rect.bottom -= (window_rect.bottom - mi.rcWork.bottom);
920 }
921
922 if (window_rect.left < mi.rcWork.left)
923 {
924 window_rect.right += (mi.rcWork.left - window_rect.left);
925 window_rect.left += (mi.rcWork.left - window_rect.left);
926 }
927
928 if (window_rect.top < mi.rcWork.top)
929 {
930 window_rect.bottom += (mi.rcWork.top - window_rect.top);
931 window_rect.top += (mi.rcWork.top - window_rect.top);
932 }
933
934 if (x != window_rect.left || y != window_rect.top)
935 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
936 SWP_NOZORDER_SPECIFIED,
937 window_rect.left, window_rect.top, 0, 0,
938 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
939 }
940 }
941
942
943 if (window->state & GDK_TOPLEVEL_STATE_FULLSCREEN)
944 {
945 gdk_win32_surface_fullscreen (window);
946 }
947 else if (window->state & GDK_TOPLEVEL_STATE_MAXIMIZED)
948 {
949 GtkShowWindow (window, SW_MAXIMIZE);
950 }
951 else if (window->state & GDK_TOPLEVEL_STATE_MINIMIZED)
952 {
953 GtkShowWindow (window, SW_RESTORE);
954 }
955 else if (GDK_IS_DRAG_SURFACE (window))
956 {
957 if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
958 GtkShowWindow (window, SW_SHOWNOACTIVATE);
959 else
960 GtkShowWindow (window, SW_SHOWNA);
961 }
962 else if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
963 {
964 GtkShowWindow (window, SW_SHOWNORMAL);
965 }
966 else
967 {
968 GtkShowWindow (window, SW_SHOW);
969 }
970
971 /* Sync STATE_ABOVE to TOPMOST */
972 if (!GDK_IS_DRAG_SURFACE (window) &&
973 (((window->state & GDK_TOPLEVEL_STATE_ABOVE) &&
974 !(exstyle & WS_EX_TOPMOST)) ||
975 (!(window->state & GDK_TOPLEVEL_STATE_ABOVE) &&
976 (exstyle & WS_EX_TOPMOST))))
977 {
978 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
979 (window->state & GDK_TOPLEVEL_STATE_ABOVE)?HWND_TOPMOST:HWND_NOTOPMOST,
980 0, 0, 0, 0,
981 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
982 }
983 }
984
985 void
gdk_win32_surface_show(GdkSurface * window,gboolean already_mapped)986 gdk_win32_surface_show (GdkSurface *window,
987 gboolean already_mapped)
988 {
989 show_window_internal (window, FALSE, FALSE);
990 }
991
992 static void
gdk_win32_surface_hide(GdkSurface * window)993 gdk_win32_surface_hide (GdkSurface *window)
994 {
995 if (window->destroyed)
996 return;
997
998 GDK_NOTE (MISC, g_print ("gdk_win32_surface_hide: %p: %s\n",
999 GDK_SURFACE_HWND (window),
1000 _gdk_win32_surface_state_to_string (window->state)));
1001
1002 if (GDK_SURFACE_IS_MAPPED (window))
1003 gdk_surface_set_is_mapped (window, FALSE);
1004
1005 _gdk_surface_clear_update_area (window);
1006
1007 if (GDK_IS_TOPLEVEL (window))
1008 ShowOwnedPopups (GDK_SURFACE_HWND (window), FALSE);
1009
1010 /* Use SetWindowPos to hide transparent windows so automatic redraws
1011 * in other windows can be suppressed.
1012 */
1013 if (GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT)
1014 {
1015 SetWindowPos (GDK_SURFACE_HWND (window), SWP_NOZORDER_SPECIFIED,
1016 0, 0, 0, 0,
1017 SWP_HIDEWINDOW | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
1018 }
1019 else
1020 {
1021 GtkShowWindow (window, SW_HIDE);
1022 }
1023 }
1024
1025 static void
gdk_win32_surface_do_move(GdkSurface * window,int x,int y)1026 gdk_win32_surface_do_move (GdkSurface *window,
1027 int x, int y)
1028 {
1029 RECT outer_rect;
1030 GdkWin32Surface *impl;
1031
1032 g_return_if_fail (GDK_IS_SURFACE (window));
1033
1034 if (GDK_SURFACE_DESTROYED (window))
1035 return;
1036
1037 GDK_NOTE (MISC, g_print ("gdk_win32_surface_move: %p: %+d%+d\n",
1038 GDK_SURFACE_HWND (window), x, y));
1039
1040 if (window->state & GDK_TOPLEVEL_STATE_FULLSCREEN)
1041 return;
1042
1043 impl = GDK_WIN32_SURFACE (window);
1044 get_outer_rect (window, window->width, window->height, &outer_rect);
1045
1046 GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,0,0,"
1047 "NOACTIVATE|NOSIZE|NOZORDER)\n",
1048 GDK_SURFACE_HWND (window),
1049 (x - _gdk_offset_x) * impl->surface_scale,
1050 (y - _gdk_offset_y) * impl->surface_scale));
1051
1052 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
1053 SWP_NOZORDER_SPECIFIED,
1054 (x - _gdk_offset_x) * impl->surface_scale,
1055 (y - _gdk_offset_y) * impl->surface_scale,
1056 0, 0,
1057 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
1058 }
1059
1060 void
gdk_win32_surface_resize(GdkSurface * window,int width,int height)1061 gdk_win32_surface_resize (GdkSurface *window,
1062 int width, int height)
1063 {
1064 RECT outer_rect;
1065
1066 g_return_if_fail (GDK_IS_SURFACE (window));
1067
1068 if (GDK_SURFACE_DESTROYED (window))
1069 return;
1070
1071 if (width < 1)
1072 width = 1;
1073 if (height < 1)
1074 height = 1;
1075
1076 GDK_NOTE (MISC, g_print ("gdk_win32_surface_resize: %p: %dx%d\n",
1077 GDK_SURFACE_HWND (window), width, height));
1078
1079 if (window->state & GDK_TOPLEVEL_STATE_FULLSCREEN)
1080 return;
1081
1082 get_outer_rect (window, width, height, &outer_rect);
1083
1084 GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,0,0,%ld,%ld,"
1085 "NOACTIVATE|NOMOVE|NOZORDER)\n",
1086 GDK_SURFACE_HWND (window),
1087 outer_rect.right - outer_rect.left,
1088 outer_rect.bottom - outer_rect.top));
1089
1090 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
1091 SWP_NOZORDER_SPECIFIED,
1092 0, 0,
1093 outer_rect.right - outer_rect.left,
1094 outer_rect.bottom - outer_rect.top,
1095 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER));
1096 window->resize_count += 1;
1097
1098 gdk_surface_request_layout (window);
1099 }
1100
1101 static void
gdk_win32_surface_do_move_resize(GdkSurface * window,int x,int y,int width,int height)1102 gdk_win32_surface_do_move_resize (GdkSurface *window,
1103 int x,
1104 int y,
1105 int width,
1106 int height)
1107 {
1108 RECT outer_rect;
1109 GdkWin32Surface *impl;
1110
1111 g_return_if_fail (GDK_IS_SURFACE (window));
1112
1113 if (GDK_SURFACE_DESTROYED (window))
1114 return;
1115
1116 if (width < 1)
1117 width = 1;
1118 if (height < 1)
1119 height = 1;
1120
1121 if (window->state & GDK_TOPLEVEL_STATE_FULLSCREEN)
1122 return;
1123
1124 GDK_NOTE (MISC, g_print ("gdk_win32_surface_move_resize: %p: %dx%d@%+d%+d\n",
1125 GDK_SURFACE_HWND (window),
1126 width, height, x, y));
1127
1128 impl = GDK_WIN32_SURFACE (window);
1129
1130 get_outer_rect (window, width, height, &outer_rect);
1131
1132 GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%ld,%ld,"
1133 "NOACTIVATE|NOZORDER)\n",
1134 GDK_SURFACE_HWND (window),
1135 (x - _gdk_offset_x) * impl->surface_scale,
1136 (y - _gdk_offset_y) * impl->surface_scale,
1137 outer_rect.right - outer_rect.left,
1138 outer_rect.bottom - outer_rect.top));
1139
1140 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
1141 SWP_NOZORDER_SPECIFIED,
1142 (x - _gdk_offset_x) * impl->surface_scale,
1143 (y - _gdk_offset_y) * impl->surface_scale,
1144 outer_rect.right - outer_rect.left,
1145 outer_rect.bottom - outer_rect.top,
1146 SWP_NOACTIVATE | SWP_NOZORDER));
1147 }
1148
1149 static void
gdk_win32_surface_move_resize_internal(GdkSurface * window,gboolean with_move,int x,int y,int width,int height)1150 gdk_win32_surface_move_resize_internal (GdkSurface *window,
1151 gboolean with_move,
1152 int x,
1153 int y,
1154 int width,
1155 int height)
1156 {
1157 GdkWin32Surface *surface = GDK_WIN32_SURFACE (window);
1158
1159 /* We ignore changes to the window being moved or resized by the
1160 user, as we don't want to fight the user */
1161 if (GDK_SURFACE_HWND (window) == _modal_move_resize_window)
1162 goto out;
1163
1164 if (with_move && (width < 0 && height < 0))
1165 {
1166 gdk_win32_surface_do_move (window, x, y);
1167 }
1168 else
1169 {
1170 _gdk_win32_surface_invalidate_egl_framebuffer (window);
1171
1172 if (with_move)
1173 {
1174 gdk_win32_surface_do_move_resize (window, x, y, width, height);
1175 }
1176 else
1177 {
1178 gdk_win32_surface_resize (window, width, height);
1179 }
1180 }
1181
1182 out:
1183 gdk_surface_request_layout (window);
1184 }
1185
1186 void
gdk_win32_surface_move_resize(GdkSurface * window,int x,int y,int width,int height)1187 gdk_win32_surface_move_resize (GdkSurface *window,
1188 int x,
1189 int y,
1190 int width,
1191 int height)
1192 {
1193 gdk_win32_surface_move_resize_internal (window, TRUE, x, y, width, height);
1194 }
1195
1196 void
gdk_win32_surface_move(GdkSurface * surface,int x,int y)1197 gdk_win32_surface_move (GdkSurface *surface,
1198 int x,
1199 int y)
1200 {
1201 gdk_win32_surface_move_resize_internal (surface, TRUE, x, y, -1, -1);
1202 }
1203
1204 static void gdk_win32_surface_set_shadow_width (GdkSurface *window,
1205 int left,
1206 int right,
1207 int top,
1208 int bottom);
1209
1210 static void
gdk_win32_surface_layout_popup(GdkSurface * surface,int width,int height,GdkPopupLayout * layout)1211 gdk_win32_surface_layout_popup (GdkSurface *surface,
1212 int width,
1213 int height,
1214 GdkPopupLayout *layout)
1215 {
1216 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
1217 GdkMonitor *monitor;
1218 GdkRectangle bounds;
1219 GdkRectangle final_rect;
1220 int x, y;
1221 int shadow_left, shadow_right, shadow_top, shadow_bottom;
1222
1223 monitor = gdk_surface_get_layout_monitor (surface, layout,
1224 gdk_win32_monitor_get_workarea);
1225 gdk_win32_monitor_get_workarea (monitor, &bounds);
1226
1227 gdk_popup_layout_get_shadow_width (layout,
1228 &shadow_left,
1229 &shadow_right,
1230 &shadow_top,
1231 &shadow_bottom);
1232
1233 gdk_win32_surface_set_shadow_width (surface,
1234 shadow_left,
1235 shadow_right,
1236 shadow_top,
1237 shadow_bottom);
1238
1239 gdk_surface_layout_popup_helper (surface,
1240 width,
1241 height,
1242 shadow_left,
1243 shadow_right,
1244 shadow_top,
1245 shadow_bottom,
1246 monitor,
1247 &bounds,
1248 layout,
1249 &final_rect);
1250
1251 gdk_surface_get_origin (surface->parent, &x, &y);
1252 x += final_rect.x;
1253 y += final_rect.y;
1254
1255 if (final_rect.width != surface->width ||
1256 final_rect.height != surface->height)
1257 {
1258 gdk_win32_surface_move_resize (surface,
1259 x,
1260 y,
1261 final_rect.width,
1262 final_rect.height);
1263 }
1264 else
1265 gdk_win32_surface_move (surface, x, y);
1266 }
1267
1268 static void
maybe_notify_mapped(GdkSurface * surface)1269 maybe_notify_mapped (GdkSurface *surface)
1270 {
1271 if (surface->destroyed)
1272 return;
1273
1274 if (!GDK_SURFACE_IS_MAPPED (surface))
1275 {
1276 gdk_surface_set_is_mapped (surface, TRUE);
1277 gdk_surface_invalidate_rect (surface, NULL);
1278 }
1279 }
1280
1281 static void
show_popup(GdkSurface * surface)1282 show_popup (GdkSurface *surface)
1283 {
1284 gdk_win32_surface_raise (surface);
1285 maybe_notify_mapped (surface);
1286 show_window_internal (surface, FALSE, FALSE);
1287 gdk_surface_invalidate_rect (surface, NULL);
1288 }
1289
1290 static void
show_grabbing_popup(GdkSeat * seat,GdkSurface * surface,gpointer user_data)1291 show_grabbing_popup (GdkSeat *seat,
1292 GdkSurface *surface,
1293 gpointer user_data)
1294 {
1295 show_popup (surface);
1296 }
1297
1298 static gboolean
gdk_win32_surface_present_popup(GdkSurface * surface,int width,int height,GdkPopupLayout * layout)1299 gdk_win32_surface_present_popup (GdkSurface *surface,
1300 int width,
1301 int height,
1302 GdkPopupLayout *layout)
1303 {
1304 gdk_win32_surface_layout_popup (surface, width, height, layout);
1305
1306 if (GDK_SURFACE_IS_MAPPED (surface))
1307 return TRUE;
1308
1309 if (surface->autohide)
1310 {
1311 gdk_seat_grab (gdk_display_get_default_seat (surface->display),
1312 surface,
1313 GDK_SEAT_CAPABILITY_ALL,
1314 TRUE,
1315 NULL, NULL,
1316 show_grabbing_popup, NULL);
1317 }
1318 else
1319 {
1320 show_popup (surface);
1321 }
1322
1323 return GDK_SURFACE_IS_MAPPED (surface);
1324 }
1325
1326 void
gdk_win32_surface_raise(GdkSurface * window)1327 gdk_win32_surface_raise (GdkSurface *window)
1328 {
1329 if (!GDK_SURFACE_DESTROYED (window))
1330 {
1331 GDK_NOTE (MISC, g_print ("gdk_win32_surface_raise: %p\n",
1332 GDK_SURFACE_HWND (window)));
1333
1334 if (GDK_IS_DRAG_SURFACE (window))
1335 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOPMOST,
1336 0, 0, 0, 0,
1337 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER));
1338
1339 else if (GDK_IS_POPUP (window))
1340 ShowWindow (GDK_SURFACE_HWND (window), SW_SHOWNOACTIVATE);
1341 else
1342 /* Do not wrap this in an API_CALL macro as SetForegroundWindow might
1343 * fail when for example dragging a window belonging to a different
1344 * application at the time of a gtk_window_present() call due to focus
1345 * stealing prevention. */
1346 SetForegroundWindow (GDK_SURFACE_HWND (window));
1347 }
1348 }
1349
1350 void
gdk_win32_surface_set_urgency_hint(GdkSurface * window,gboolean urgent)1351 gdk_win32_surface_set_urgency_hint (GdkSurface *window,
1352 gboolean urgent)
1353 {
1354 FLASHWINFO flashwinfo;
1355 typedef BOOL (WINAPI *PFN_FlashWindowEx) (FLASHWINFO*);
1356 PFN_FlashWindowEx flashWindowEx = NULL;
1357
1358 g_return_if_fail (GDK_IS_SURFACE (window));
1359
1360 if (GDK_SURFACE_DESTROYED (window))
1361 return;
1362
1363 flashWindowEx = (PFN_FlashWindowEx) GetProcAddress (GetModuleHandle ("user32.dll"), "FlashWindowEx");
1364
1365 if (flashWindowEx)
1366 {
1367 flashwinfo.cbSize = sizeof (flashwinfo);
1368 flashwinfo.hwnd = GDK_SURFACE_HWND (window);
1369 if (urgent)
1370 flashwinfo.dwFlags = FLASHW_ALL | FLASHW_TIMER;
1371 else
1372 flashwinfo.dwFlags = FLASHW_STOP;
1373 flashwinfo.uCount = 0;
1374 flashwinfo.dwTimeout = 0;
1375
1376 flashWindowEx (&flashwinfo);
1377 }
1378 else
1379 {
1380 FlashWindow (GDK_SURFACE_HWND (window), urgent);
1381 }
1382 }
1383
1384 static gboolean
get_effective_window_decorations(GdkSurface * window,GdkWMDecoration * decoration)1385 get_effective_window_decorations (GdkSurface *window,
1386 GdkWMDecoration *decoration)
1387 {
1388 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
1389
1390 *decoration = 0;
1391
1392 if (!GDK_IS_TOPLEVEL (window))
1393 return FALSE;
1394
1395 /* we want to apply the "no decorations", if decorations are disabled */
1396 if (!GDK_WIN32_SURFACE (window)->decorate_all)
1397 return TRUE;
1398
1399 if ((impl->hint_flags & GDK_HINT_MIN_SIZE) &&
1400 (impl->hint_flags & GDK_HINT_MAX_SIZE) &&
1401 impl->hints.min_width == impl->hints.max_width &&
1402 impl->hints.min_height == impl->hints.max_height)
1403 {
1404 *decoration = GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MAXIMIZE;
1405
1406 *decoration |= GDK_DECOR_MINIMIZE;
1407
1408 return TRUE;
1409 }
1410 else if (impl->hint_flags & GDK_HINT_MAX_SIZE)
1411 {
1412 *decoration = GDK_DECOR_ALL | GDK_DECOR_MAXIMIZE;
1413 *decoration |= GDK_DECOR_MINIMIZE;
1414
1415 return TRUE;
1416 }
1417 else
1418 {
1419 *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
1420 return TRUE;
1421 }
1422
1423 return FALSE;
1424 }
1425
1426 static void
gdk_win32_surface_set_geometry_hints(GdkSurface * window,const GdkGeometry * geometry,GdkSurfaceHints geom_mask)1427 gdk_win32_surface_set_geometry_hints (GdkSurface *window,
1428 const GdkGeometry *geometry,
1429 GdkSurfaceHints geom_mask)
1430 {
1431 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
1432 FullscreenInfo *fi;
1433
1434 g_return_if_fail (GDK_IS_SURFACE (window));
1435
1436 if (GDK_SURFACE_DESTROYED (window))
1437 return;
1438
1439 GDK_NOTE (MISC, g_print ("gdk_surface_set_geometry_hints: %p\n",
1440 GDK_SURFACE_HWND (window)));
1441
1442 fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
1443 if (fi)
1444 fi->hint_flags = geom_mask;
1445 else
1446 impl->hint_flags = geom_mask;
1447 impl->hints = *geometry;
1448
1449 if (geom_mask & GDK_HINT_MIN_SIZE)
1450 {
1451 GDK_NOTE (MISC, g_print ("... MIN_SIZE: %dx%d\n",
1452 geometry->min_width, geometry->min_height));
1453 }
1454
1455 if (geom_mask & GDK_HINT_MAX_SIZE)
1456 {
1457 GDK_NOTE (MISC, g_print ("... MAX_SIZE: %dx%d\n",
1458 geometry->max_width, geometry->max_height));
1459 }
1460
1461 _gdk_win32_surface_update_style_bits (window);
1462 }
1463
1464 static void
gdk_win32_surface_set_title(GdkSurface * window,const char * title)1465 gdk_win32_surface_set_title (GdkSurface *window,
1466 const char *title)
1467 {
1468 wchar_t *wtitle;
1469
1470 g_return_if_fail (GDK_IS_SURFACE (window));
1471 g_return_if_fail (title != NULL);
1472
1473 if (GDK_SURFACE_DESTROYED (window))
1474 return;
1475
1476 /* Empty window titles not allowed, so set it to just a period. */
1477 if (!title[0])
1478 title = ".";
1479
1480 GDK_NOTE (MISC, g_print ("gdk_surface_set_title: %p: %s\n",
1481 GDK_SURFACE_HWND (window), title));
1482
1483 GDK_NOTE (MISC_OR_EVENTS, title = g_strdup_printf ("%p %s", GDK_SURFACE_HWND (window), title));
1484
1485 wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
1486 API_CALL (SetWindowTextW, (GDK_SURFACE_HWND (window), wtitle));
1487 g_free (wtitle);
1488
1489 GDK_NOTE (MISC_OR_EVENTS, g_free ((char *) title));
1490 }
1491
1492 static void
gdk_win32_surface_set_transient_for(GdkSurface * window,GdkSurface * parent)1493 gdk_win32_surface_set_transient_for (GdkSurface *window,
1494 GdkSurface *parent)
1495 {
1496 HWND window_id, parent_id;
1497 LONG_PTR old_ptr;
1498 DWORD w32_error;
1499 GdkWin32Surface *surface = GDK_WIN32_SURFACE (window);
1500 GdkWin32Surface *parent_impl = NULL;
1501 GSList *item;
1502
1503 g_return_if_fail (GDK_IS_SURFACE (window));
1504
1505 window_id = GDK_SURFACE_HWND (window);
1506 parent_id = parent != NULL ? GDK_SURFACE_HWND (parent) : NULL;
1507
1508 GDK_NOTE (MISC, g_print ("gdk_surface_set_transient_for: %p: %p\n", window_id, parent_id));
1509
1510 if (GDK_SURFACE_DESTROYED (window) || (parent && GDK_SURFACE_DESTROYED (parent)))
1511 {
1512 if (GDK_SURFACE_DESTROYED (window))
1513 GDK_NOTE (MISC, g_print ("... destroyed!\n"));
1514 else
1515 GDK_NOTE (MISC, g_print ("... owner destroyed!\n"));
1516
1517 return;
1518 }
1519
1520 if (surface->transient_owner == parent)
1521 return;
1522
1523 if (GDK_IS_SURFACE (surface->transient_owner))
1524 {
1525 GdkWin32Surface *trans_impl = GDK_WIN32_SURFACE (surface->transient_owner);
1526 item = g_slist_find (trans_impl->transient_children, window);
1527 item->data = NULL;
1528 trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
1529 trans_impl->num_transients--;
1530
1531 if (!trans_impl->num_transients)
1532 {
1533 trans_impl->transient_children = NULL;
1534 }
1535
1536 g_object_unref (G_OBJECT (surface->transient_owner));
1537 g_object_unref (G_OBJECT (window));
1538
1539 surface->transient_owner = NULL;
1540 }
1541
1542 if (parent)
1543 {
1544 parent_impl = GDK_WIN32_SURFACE (parent);
1545
1546 parent_impl->transient_children = g_slist_append (parent_impl->transient_children, window);
1547 g_object_ref (G_OBJECT (window));
1548 parent_impl->num_transients++;
1549 surface->transient_owner = parent;
1550 g_object_ref (G_OBJECT (parent));
1551 }
1552
1553 SetLastError (0);
1554 old_ptr = GetWindowLongPtr (window_id, GWLP_HWNDPARENT);
1555 w32_error = GetLastError ();
1556
1557 /* Don't re-set GWLP_HWNDPARENT to the same value */
1558 if ((HWND) old_ptr == parent_id && w32_error == NO_ERROR)
1559 return;
1560
1561 /* Don't return if it failed, try SetWindowLongPtr() anyway */
1562 if (old_ptr == 0 && w32_error != NO_ERROR)
1563 WIN32_API_FAILED ("GetWindowLongPtr");
1564
1565 /* This changes the *owner* of the window, despite the misleading
1566 * name. (Owner and parent are unrelated concepts.) At least that's
1567 * what people who seem to know what they talk about say on
1568 * USENET. Search on Google.
1569 */
1570 SetLastError (0);
1571 old_ptr = SetWindowLongPtr (window_id, GWLP_HWNDPARENT, (LONG_PTR) parent_id);
1572 w32_error = GetLastError ();
1573
1574 if (old_ptr == 0 && w32_error != NO_ERROR)
1575 WIN32_API_FAILED ("SetWindowLongPtr");
1576 }
1577
1578 void
_gdk_push_modal_window(GdkSurface * window)1579 _gdk_push_modal_window (GdkSurface *window)
1580 {
1581 modal_window_stack = g_slist_prepend (modal_window_stack, window);
1582 }
1583
1584 void
_gdk_remove_modal_window(GdkSurface * window)1585 _gdk_remove_modal_window (GdkSurface *window)
1586 {
1587 GSList *tmp;
1588
1589 g_return_if_fail (window != NULL);
1590
1591 /* It's possible to be NULL here if someone sets the modal hint of the window
1592 * to FALSE before a modal window stack has ever been created. */
1593 if (modal_window_stack == NULL)
1594 return;
1595
1596 /* Find the requested window in the stack and remove it. Yeah, I realize this
1597 * means we're not a 'real stack', strictly speaking. Sue me. :) */
1598 tmp = g_slist_find (modal_window_stack, window);
1599 if (tmp != NULL)
1600 {
1601 modal_window_stack = g_slist_delete_link (modal_window_stack, tmp);
1602 }
1603 }
1604
1605 gboolean
_gdk_modal_blocked(GdkSurface * window)1606 _gdk_modal_blocked (GdkSurface *window)
1607 {
1608 GSList *l;
1609 gboolean found_any = FALSE;
1610
1611 for (l = modal_window_stack; l != NULL; l = l->next)
1612 {
1613 GdkSurface *modal = l->data;
1614
1615 if (modal == window)
1616 return FALSE;
1617
1618 if (GDK_SURFACE_IS_MAPPED (modal))
1619 found_any = TRUE;
1620 }
1621
1622 return found_any;
1623 }
1624
1625 GdkSurface *
_gdk_modal_current(void)1626 _gdk_modal_current (void)
1627 {
1628 GSList *l;
1629
1630 for (l = modal_window_stack; l != NULL; l = l->next)
1631 {
1632 GdkSurface *modal = l->data;
1633
1634 if (GDK_SURFACE_IS_MAPPED (modal))
1635 return modal;
1636 }
1637
1638 return NULL;
1639 }
1640
1641 static void
gdk_win32_surface_get_geometry(GdkSurface * window,int * x,int * y,int * width,int * height)1642 gdk_win32_surface_get_geometry (GdkSurface *window,
1643 int *x,
1644 int *y,
1645 int *width,
1646 int *height)
1647 {
1648 if (!GDK_SURFACE_DESTROYED (window))
1649 {
1650 RECT rect;
1651 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
1652
1653 if (GDK_IS_TOPLEVEL (window) && impl->drag_move_resize_context.native_move_resize_pending)
1654 rect = impl->next_layout.configured_rect;
1655 else
1656 {
1657 POINT pt;
1658 GdkSurface *parent;
1659
1660 if (GDK_IS_TOPLEVEL (window))
1661 parent = NULL;
1662 else if (GDK_IS_POPUP (window))
1663 parent = gdk_popup_get_parent (GDK_POPUP (window));
1664 else
1665 parent = NULL;
1666
1667 API_CALL (GetClientRect, (GDK_SURFACE_HWND (window), &rect));
1668
1669 pt.x = rect.left;
1670 pt.y = rect.top;
1671 ClientToScreen (GDK_SURFACE_HWND (window), &pt);
1672 if (parent)
1673 ScreenToClient (GDK_SURFACE_HWND (parent), &pt);
1674
1675 rect.left = pt.x;
1676 rect.top = pt.y;
1677
1678 pt.x = rect.right;
1679 pt.y = rect.bottom;
1680 ClientToScreen (GDK_SURFACE_HWND (window), &pt);
1681 if (parent)
1682 ScreenToClient (GDK_SURFACE_HWND (parent), &pt);
1683
1684 rect.right = pt.x;
1685 rect.bottom = pt.y;
1686
1687 if (parent == NULL)
1688 {
1689 rect.left += _gdk_offset_x * impl->surface_scale;
1690 rect.top += _gdk_offset_y * impl->surface_scale;
1691 rect.right += _gdk_offset_x * impl->surface_scale;
1692 rect.bottom += _gdk_offset_y * impl->surface_scale;
1693 }
1694 }
1695
1696 if (x)
1697 *x = rect.left / impl->surface_scale;
1698 if (y)
1699 *y = rect.top / impl->surface_scale;
1700 if (width)
1701 *width = (rect.right - rect.left) / impl->surface_scale;
1702 if (height)
1703 *height = (rect.bottom - rect.top) / impl->surface_scale;
1704
1705 GDK_NOTE (MISC, g_print ("gdk_win32_surface_get_geometry: %p: %ldx%ld@%+ld%+ld\n",
1706 GDK_SURFACE_HWND (window),
1707 (rect.right - rect.left) / impl->surface_scale,
1708 (rect.bottom - rect.top) / impl->surface_scale,
1709 rect.left, rect.top));
1710 }
1711 }
1712
1713 static void
gdk_win32_surface_get_root_coords(GdkSurface * window,int x,int y,int * root_x,int * root_y)1714 gdk_win32_surface_get_root_coords (GdkSurface *window,
1715 int x,
1716 int y,
1717 int *root_x,
1718 int *root_y)
1719 {
1720 int tx;
1721 int ty;
1722 POINT pt;
1723 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
1724
1725 pt.x = x * impl->surface_scale;
1726 pt.y = y * impl->surface_scale;
1727 ClientToScreen (GDK_SURFACE_HWND (window), &pt);
1728 tx = pt.x;
1729 ty = pt.y;
1730
1731 if (root_x)
1732 *root_x = (tx + _gdk_offset_x) / impl->surface_scale;
1733 if (root_y)
1734 *root_y = (ty + _gdk_offset_y) / impl->surface_scale;
1735
1736 GDK_NOTE (MISC, g_print ("gdk_win32_surface_get_root_coords: %p: %+d%+d %+d%+d\n",
1737 GDK_SURFACE_HWND (window),
1738 x * impl->surface_scale,
1739 y * impl->surface_scale,
1740 (tx + _gdk_offset_x) / impl->surface_scale,
1741 (ty + _gdk_offset_y) / impl->surface_scale));
1742 }
1743
1744 static gboolean
gdk_surface_win32_get_device_state(GdkSurface * window,GdkDevice * device,double * x,double * y,GdkModifierType * mask)1745 gdk_surface_win32_get_device_state (GdkSurface *window,
1746 GdkDevice *device,
1747 double *x,
1748 double *y,
1749 GdkModifierType *mask)
1750 {
1751 _gdk_device_win32_query_state (device, window, NULL, x, y, mask);
1752
1753 return *x >= 0 && *y >= 0 && *x < window->width && *y < window->height;
1754
1755 }
1756
1757 static void
update_single_bit(LONG * style,gboolean all,int gdk_bit,int style_bit)1758 update_single_bit (LONG *style,
1759 gboolean all,
1760 int gdk_bit,
1761 int style_bit)
1762 {
1763 /* all controls the interpretation of gdk_bit -- if all is TRUE,
1764 * gdk_bit indicates whether style_bit is off; if all is FALSE, gdk
1765 * bit indicate whether style_bit is on
1766 */
1767 if ((!all && gdk_bit) || (all && !gdk_bit))
1768 *style |= style_bit;
1769 else
1770 *style &= ~style_bit;
1771 }
1772
1773 /*
1774 * Returns TRUE if window has no decorations.
1775 * Usually it means CSD windows, because GTK
1776 * calls gdk_surface_set_decorations (window, 0);
1777 */
1778 gboolean
_gdk_win32_surface_lacks_wm_decorations(GdkSurface * window)1779 _gdk_win32_surface_lacks_wm_decorations (GdkSurface *window)
1780 {
1781 GdkWin32Surface *impl;
1782 LONG style;
1783 gboolean has_any_decorations;
1784
1785 if (GDK_SURFACE_DESTROYED (window))
1786 return FALSE;
1787
1788 impl = GDK_WIN32_SURFACE (window);
1789
1790 /* This is because GTK calls gdk_surface_set_decorations (window, 0),
1791 * even though GdkWMDecoration docs indicate that 0 does NOT mean
1792 * "no decorations".
1793 */
1794 if (!impl->decorate_all)
1795 return TRUE;
1796
1797 if (GDK_SURFACE_HWND (window) == 0)
1798 return FALSE;
1799
1800 style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
1801
1802 if (style == 0)
1803 {
1804 DWORD w32_error = GetLastError ();
1805
1806 GDK_NOTE (MISC, g_print ("Failed to get style of window %p (handle %p): %lu\n",
1807 window, GDK_SURFACE_HWND (window), w32_error));
1808 return FALSE;
1809 }
1810
1811 /* Keep this in sync with _gdk_win32_surface_update_style_bits() */
1812 /* We don't check what get_effective_window_decorations()
1813 * has to say, because it gives suggestions based on
1814 * various hints, while we want *actual* decorations,
1815 * or their absence.
1816 */
1817 has_any_decorations = FALSE;
1818
1819 if (style & (WS_BORDER | WS_THICKFRAME | WS_CAPTION |
1820 WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX))
1821 has_any_decorations = TRUE;
1822 else
1823 GDK_NOTE (MISC, g_print ("Window %p (handle %p): has no decorations (style %lx)\n",
1824 window, GDK_SURFACE_HWND (window), style));
1825
1826 return !has_any_decorations;
1827 }
1828
1829 void
_gdk_win32_surface_update_style_bits(GdkSurface * window)1830 _gdk_win32_surface_update_style_bits (GdkSurface *window)
1831 {
1832 GdkWin32Surface *impl = (GdkWin32Surface *)window;
1833 GdkWMDecoration decorations;
1834 LONG old_style, new_style, old_exstyle, new_exstyle;
1835 gboolean all;
1836 RECT rect, before, after;
1837 gboolean was_topmost;
1838 gboolean will_be_topmost;
1839 gboolean was_layered;
1840 gboolean will_be_layered;
1841 HWND insert_after;
1842 UINT flags;
1843
1844 if (window->state & GDK_TOPLEVEL_STATE_FULLSCREEN)
1845 return;
1846
1847 old_style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
1848 old_exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
1849
1850 GetClientRect (GDK_SURFACE_HWND (window), &before);
1851 after = before;
1852 AdjustWindowRectEx (&before, old_style, FALSE, old_exstyle);
1853
1854 was_topmost = (old_exstyle & WS_EX_TOPMOST) ? TRUE : FALSE;
1855 was_layered = (old_exstyle & WS_EX_LAYERED) ? TRUE : FALSE;
1856 will_be_topmost = was_topmost;
1857 will_be_layered = was_layered;
1858
1859 old_exstyle &= ~WS_EX_TOPMOST;
1860
1861 new_style = old_style;
1862 new_exstyle = old_exstyle;
1863
1864 if (GDK_IS_DRAG_SURFACE (window))
1865 {
1866 new_exstyle |= WS_EX_TOOLWINDOW;
1867
1868 /* WS_EX_LAYERED | WS_EX_TRANSPARENT makes the drag surface behave
1869 * in pointer input passthrough mode, so it doesn't interfere with
1870 * the drag and drop operation.
1871 */
1872 new_exstyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
1873 will_be_topmost = TRUE;
1874 will_be_layered = TRUE;
1875 }
1876 else
1877 {
1878 new_exstyle &= ~WS_EX_TOOLWINDOW;
1879 }
1880
1881 if (get_effective_window_decorations (window, &decorations))
1882 {
1883 all = (decorations & GDK_DECOR_ALL);
1884
1885 /* Keep this in sync with the test in _gdk_win32_surface_lacks_wm_decorations() */
1886 update_single_bit (&new_style, all, decorations & GDK_DECOR_BORDER, WS_BORDER);
1887 update_single_bit (&new_style, all, decorations & GDK_DECOR_RESIZEH, WS_THICKFRAME);
1888 update_single_bit (&new_style, all, decorations & GDK_DECOR_TITLE, WS_CAPTION);
1889 update_single_bit (&new_style, all, decorations & GDK_DECOR_MENU, WS_SYSMENU);
1890 update_single_bit (&new_style, all, decorations & GDK_DECOR_MINIMIZE, WS_MINIMIZEBOX);
1891 update_single_bit (&new_style, all, decorations & GDK_DECOR_MAXIMIZE, WS_MAXIMIZEBOX);
1892 }
1893
1894 if (old_style == new_style && old_exstyle == new_exstyle )
1895 {
1896 GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: no change\n",
1897 GDK_SURFACE_HWND (window)));
1898 return;
1899 }
1900
1901 if (old_style != new_style)
1902 {
1903 GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: STYLE: %s => %s\n",
1904 GDK_SURFACE_HWND (window),
1905 _gdk_win32_surface_style_to_string (old_style),
1906 _gdk_win32_surface_style_to_string (new_style)));
1907
1908 SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE, new_style);
1909 }
1910
1911 if (old_exstyle != new_exstyle)
1912 {
1913 GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: EXSTYLE: %s => %s\n",
1914 GDK_SURFACE_HWND (window),
1915 _gdk_win32_surface_exstyle_to_string (old_exstyle),
1916 _gdk_win32_surface_exstyle_to_string (new_exstyle)));
1917
1918 SetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE, new_exstyle);
1919
1920 if (!was_layered && will_be_layered)
1921 {
1922 /* We have to call SetLayeredWindowAttributes when setting the
1923 * WS_EX_LAYERED style anew, otherwise the window won't show up
1924 */
1925 API_CALL (SetLayeredWindowAttributes, (GDK_SURFACE_HWND (window), 0, 255, LWA_ALPHA));
1926 }
1927 }
1928
1929 AdjustWindowRectEx (&after, new_style, FALSE, new_exstyle);
1930
1931 GetWindowRect (GDK_SURFACE_HWND (window), &rect);
1932 rect.left += after.left - before.left;
1933 rect.top += after.top - before.top;
1934 rect.right += after.right - before.right;
1935 rect.bottom += after.bottom - before.bottom;
1936
1937 flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOREPOSITION;
1938
1939 if (will_be_topmost && !was_topmost)
1940 {
1941 insert_after = HWND_TOPMOST;
1942 }
1943 else if (was_topmost && !will_be_topmost)
1944 {
1945 insert_after = HWND_NOTOPMOST;
1946 }
1947 else
1948 {
1949 flags |= SWP_NOZORDER;
1950 insert_after = SWP_NOZORDER_SPECIFIED;
1951 }
1952
1953 SetWindowPos (GDK_SURFACE_HWND (window), insert_after,
1954 rect.left, rect.top,
1955 rect.right - rect.left, rect.bottom - rect.top,
1956 flags);
1957 }
1958
1959 #if defined(MORE_AEROSNAP_DEBUGGING)
1960 static void
log_region(char * prefix,AeroSnapEdgeRegion * region)1961 log_region (char *prefix, AeroSnapEdgeRegion *region)
1962 {
1963 GDK_NOTE (MISC, g_print ("Region %s:\n"
1964 "edge %d x %d @ %d x %d\n"
1965 "trig %d x %d @ %d x %d\n",
1966 prefix,
1967 region->edge.width,
1968 region->edge.height,
1969 region->edge.x,
1970 region->edge.y,
1971 region->trigger.width,
1972 region->trigger.height,
1973 region->trigger.x,
1974 region->trigger.y));
1975 }
1976 #endif
1977
1978 static void
calculate_aerosnap_regions(GdkW32DragMoveResizeContext * context)1979 calculate_aerosnap_regions (GdkW32DragMoveResizeContext *context)
1980 {
1981 GdkDisplay *display;
1982 GListModel *monitors;
1983 int monitor_idx, other_monitor_idx;
1984 GdkWin32Surface *impl = GDK_WIN32_SURFACE (context->window);
1985 #if defined(MORE_AEROSNAP_DEBUGGING)
1986 int i;
1987 #endif
1988
1989 display = gdk_surface_get_display (context->window);
1990 monitors = gdk_display_get_monitors (display);
1991
1992 #define _M_UP 0
1993 #define _M_DOWN 1
1994 #define _M_LEFT 2
1995 #define _M_RIGHT 3
1996
1997 for (monitor_idx = 0; monitor_idx < g_list_model_get_n_items (monitors); monitor_idx++)
1998 {
1999 GdkRectangle wa;
2000 GdkRectangle geometry;
2001 AeroSnapEdgeRegion snap_region;
2002 gboolean move_edge[4] = { TRUE, FALSE, TRUE, TRUE };
2003 gboolean resize_edge[2] = { TRUE, TRUE };
2004 int diff;
2005 int thickness, trigger_thickness;
2006 GdkMonitor *monitor;
2007
2008 monitor = g_list_model_get_item (monitors, monitor_idx);
2009 g_object_unref (monitor);
2010 gdk_win32_monitor_get_workarea (monitor, &wa);
2011 gdk_monitor_get_geometry (monitor, &geometry);
2012
2013 for (other_monitor_idx = 0;
2014 other_monitor_idx < g_list_model_get_n_items (monitors) &&
2015 (move_edge[_M_UP] || move_edge[_M_LEFT] ||
2016 move_edge[_M_RIGHT] || resize_edge[_M_DOWN]);
2017 other_monitor_idx++)
2018 {
2019 GdkRectangle other_wa;
2020 GdkMonitor *other_monitor;
2021
2022 if (other_monitor_idx == monitor_idx)
2023 continue;
2024
2025 other_monitor = g_list_model_get_item (monitors, other_monitor_idx);
2026 g_object_unref (other_monitor);
2027 gdk_win32_monitor_get_workarea (other_monitor, &other_wa);
2028
2029 /* An edge triggers AeroSnap only if there are no
2030 * monitors beyond that edge.
2031 * Even if there's another monitor, but it does not cover
2032 * the whole edge (it's smaller or is not aligned to
2033 * the corner of current monitor), that edge is still
2034 * removed from the trigger list.
2035 */
2036 if (other_wa.x >= wa.x + wa.width)
2037 move_edge[_M_RIGHT] = FALSE;
2038
2039 if (other_wa.x + other_wa.width <= wa.x)
2040 move_edge[_M_LEFT] = FALSE;
2041
2042 if (other_wa.y + other_wa.height <= wa.y)
2043 {
2044 move_edge[_M_UP] = FALSE;
2045 resize_edge[_M_UP] = FALSE;
2046 }
2047
2048 if (other_wa.y >= wa.y + wa.height)
2049 {
2050 /* no move_edge for the bottom edge, just resize_edge */
2051 resize_edge[_M_DOWN] = FALSE;
2052 }
2053 }
2054
2055 thickness = AEROSNAP_REGION_THICKNESS * impl->surface_scale;
2056 trigger_thickness = AEROSNAP_REGION_TRIGGER_THICKNESS * impl->surface_scale;
2057
2058 snap_region.edge = wa;
2059 snap_region.trigger = wa;
2060 snap_region.edge.height = thickness;
2061 snap_region.trigger.height = trigger_thickness;
2062
2063 /* Extend both regions into toolbar space.
2064 * When there's no toolbar, diff == 0.
2065 */
2066 diff = wa.y - geometry.y;
2067 snap_region.edge.height += diff;
2068 snap_region.edge.y -= diff;
2069 snap_region.trigger.height += diff;
2070 snap_region.trigger.y -= diff;
2071
2072 if (move_edge[_M_UP])
2073 g_array_append_val (context->maximize_regions, snap_region);
2074
2075 if (resize_edge[_M_UP])
2076 g_array_append_val (context->fullup_regions, snap_region);
2077
2078 snap_region.edge = wa;
2079 snap_region.trigger = wa;
2080 snap_region.edge.width = thickness;
2081 snap_region.trigger.width = trigger_thickness;
2082
2083 diff = wa.x - geometry.x;
2084 snap_region.edge.width += diff;
2085 snap_region.edge.x -= diff;
2086 snap_region.trigger.width += diff;
2087 snap_region.trigger.x -= diff;
2088
2089 if (move_edge[_M_LEFT])
2090 g_array_append_val (context->halfleft_regions, snap_region);
2091
2092 snap_region.edge = wa;
2093 snap_region.trigger = wa;
2094 snap_region.edge.x += wa.width - thickness;
2095 snap_region.edge.width = thickness;
2096 snap_region.trigger.x += wa.width - trigger_thickness;
2097 snap_region.trigger.width = trigger_thickness;
2098
2099 diff = (geometry.x + geometry.width) - (wa.x + wa.width);
2100 snap_region.edge.width += diff;
2101 snap_region.trigger.width += diff;
2102
2103 if (move_edge[_M_RIGHT])
2104 g_array_append_val (context->halfright_regions, snap_region);
2105
2106 snap_region.edge = wa;
2107 snap_region.trigger = wa;
2108 snap_region.edge.y += wa.height - thickness;
2109 snap_region.edge.height = thickness;
2110 snap_region.trigger.y += wa.height - trigger_thickness;
2111 snap_region.trigger.height = trigger_thickness;
2112
2113 diff = (geometry.y + geometry.height) - (wa.y + wa.height);
2114 snap_region.edge.height += diff;
2115 snap_region.trigger.height += diff;
2116
2117 if (resize_edge[_M_DOWN])
2118 g_array_append_val (context->fullup_regions, snap_region);
2119 }
2120
2121 #undef _M_UP
2122 #undef _M_DOWN
2123 #undef _M_LEFT
2124 #undef _M_RIGHT
2125
2126 #if defined(MORE_AEROSNAP_DEBUGGING)
2127 for (i = 0; i < context->maximize_regions->len; i++)
2128 log_region ("maximize", &g_array_index (context->maximize_regions, AeroSnapEdgeRegion, i));
2129
2130 for (i = 0; i < context->halfleft_regions->len; i++)
2131 log_region ("halfleft", &g_array_index (context->halfleft_regions, AeroSnapEdgeRegion, i));
2132
2133 for (i = 0; i < context->halfright_regions->len; i++)
2134 log_region ("halfright", &g_array_index (context->halfright_regions, AeroSnapEdgeRegion, i));
2135
2136 for (i = 0; i < context->fullup_regions->len; i++)
2137 log_region ("fullup", &g_array_index (context->fullup_regions, AeroSnapEdgeRegion, i));
2138 #endif
2139 }
2140
2141 static void
discard_snapinfo(GdkSurface * window)2142 discard_snapinfo (GdkSurface *window)
2143 {
2144 GdkWin32Surface *impl;
2145
2146 impl = GDK_WIN32_SURFACE (window);
2147
2148 impl->snap_state = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
2149
2150 if (impl->snap_stash == NULL)
2151 return;
2152
2153 g_clear_pointer (&impl->snap_stash, g_free);
2154 g_clear_pointer (&impl->snap_stash_int, g_free);
2155 }
2156
2157 static void
unsnap(GdkSurface * window,GdkMonitor * monitor)2158 unsnap (GdkSurface *window,
2159 GdkMonitor *monitor)
2160 {
2161 GdkWin32Surface *impl;
2162 GdkRectangle rect;
2163
2164 impl = GDK_WIN32_SURFACE (window);
2165
2166 impl->snap_state = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
2167
2168 if (impl->snap_stash == NULL)
2169 return;
2170
2171 gdk_win32_monitor_get_workarea (monitor, &rect);
2172
2173 GDK_NOTE (MISC, g_print ("Monitor work area %d x %d @ %d : %d\n", rect.width, rect.height, rect.x, rect.y));
2174
2175 if (rect.width >= impl->snap_stash_int->width &&
2176 rect.height >= impl->snap_stash_int->height)
2177 {
2178 /* If the window fits into new work area without resizing it,
2179 * place it into new work area without resizing it.
2180 */
2181 double left, right, up, down, hratio, vratio;
2182 double hscale, vscale;
2183 double new_left, new_up;
2184
2185 left = impl->snap_stash->x;
2186 right = 1.0 - (impl->snap_stash->x + impl->snap_stash->width);
2187 up = impl->snap_stash->y;
2188 down = 1.0 - (impl->snap_stash->y + impl->snap_stash->height);
2189 hscale = 1.0;
2190
2191 if (right > 0.001)
2192 {
2193 hratio = left / right;
2194 hscale = hratio / (1.0 + hratio);
2195 }
2196
2197 new_left = (double) (rect.width - impl->snap_stash_int->width) * hscale;
2198
2199 vscale = 1.0;
2200
2201 if (down > 0.001)
2202 {
2203 vratio = up / down;
2204 vscale = vratio / (1.0 + vratio);
2205 }
2206
2207 new_up = (double) (rect.height - impl->snap_stash_int->height) * vscale;
2208
2209 rect.x = round (rect.x + new_left);
2210 rect.y = round (rect.y + new_up);
2211 rect.width = impl->snap_stash_int->width;
2212 rect.height = impl->snap_stash_int->height;
2213 }
2214 else
2215 {
2216 /* Calculate actual unsnapped window size based on its
2217 * old relative size. Same for position.
2218 */
2219 rect.x += round (rect.width * impl->snap_stash->x);
2220 rect.y += round (rect.height * impl->snap_stash->y);
2221 rect.width = round (rect.width * impl->snap_stash->width);
2222 rect.height = round (rect.height * impl->snap_stash->height);
2223 }
2224
2225 GDK_NOTE (MISC, g_print ("Unsnapped window size %d x %d @ %d : %d\n", rect.width, rect.height, rect.x, rect.y));
2226
2227 gdk_win32_surface_move_resize (window, rect.x, rect.y,
2228 rect.width, rect.height);
2229
2230 g_clear_pointer (&impl->snap_stash, g_free);
2231 g_clear_pointer (&impl->snap_stash_int, g_free);
2232 }
2233
2234 static void
stash_window(GdkSurface * window,GdkWin32Surface * impl)2235 stash_window (GdkSurface *window,
2236 GdkWin32Surface *impl)
2237 {
2238 int x, y;
2239 int width, wwidth;
2240 int height, wheight;
2241 WINDOWPLACEMENT placement;
2242 HMONITOR hmonitor;
2243 MONITORINFO hmonitor_info;
2244
2245 placement.length = sizeof(WINDOWPLACEMENT);
2246
2247 /* Use W32 API to get unmaximized window size, which GDK doesn't remember */
2248 if (!GetWindowPlacement (GDK_SURFACE_HWND (window), &placement))
2249 return;
2250
2251 /* MSDN is very vague, but in practice rcNormalPosition is the same as GetWindowRect(),
2252 * only with adjustments for toolbars (which creates rather weird coordinate space issues).
2253 * We need to get monitor info and apply workarea vs monitorarea diff to turn
2254 * these into screen coordinates proper.
2255 */
2256 hmonitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
2257 hmonitor_info.cbSize = sizeof (hmonitor_info);
2258
2259 if (!GetMonitorInfoA (hmonitor, &hmonitor_info))
2260 return;
2261
2262 if (impl->snap_stash == NULL)
2263 impl->snap_stash = g_new0 (GdkRectangleDouble, 1);
2264
2265 if (impl->snap_stash_int == NULL)
2266 impl->snap_stash_int = g_new0 (GdkRectangle, 1);
2267
2268 GDK_NOTE (MISC, g_print ("monitor work area %ld x %ld @ %ld : %ld\n",
2269 (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left) / impl->surface_scale,
2270 (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top) / impl->surface_scale,
2271 hmonitor_info.rcWork.left,
2272 hmonitor_info.rcWork.top));
2273 GDK_NOTE (MISC, g_print ("monitor area %ld x %ld @ %ld : %ld\n",
2274 (hmonitor_info.rcMonitor.right - hmonitor_info.rcMonitor.left) / impl->surface_scale,
2275 (hmonitor_info.rcMonitor.bottom - hmonitor_info.rcMonitor.top) / impl->surface_scale,
2276 hmonitor_info.rcMonitor.left,
2277 hmonitor_info.rcMonitor.top));
2278 GDK_NOTE (MISC, g_print ("window work place %ld x %ld @ %ld : %ld\n",
2279 (placement.rcNormalPosition.right - placement.rcNormalPosition.left) / impl->surface_scale,
2280 (placement.rcNormalPosition.bottom - placement.rcNormalPosition.top) / impl->surface_scale,
2281 placement.rcNormalPosition.left,
2282 placement.rcNormalPosition.top));
2283
2284 width = (placement.rcNormalPosition.right - placement.rcNormalPosition.left) / impl->surface_scale;
2285 height = (placement.rcNormalPosition.bottom - placement.rcNormalPosition.top) / impl->surface_scale;
2286 x = (placement.rcNormalPosition.left - hmonitor_info.rcMonitor.left) / impl->surface_scale;
2287 y = (placement.rcNormalPosition.top - hmonitor_info.rcMonitor.top) / impl->surface_scale;
2288
2289 wwidth = (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left) / impl->surface_scale;
2290 wheight = (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top) / impl->surface_scale;
2291
2292 impl->snap_stash->x = (double) (x) / (double) (wwidth);
2293 impl->snap_stash->y = (double) (y) / (double) (wheight);
2294 impl->snap_stash->width = (double) width / (double) (wwidth);
2295 impl->snap_stash->height = (double) height / (double) (wheight);
2296
2297 impl->snap_stash_int->x = x;
2298 impl->snap_stash_int->y = y;
2299 impl->snap_stash_int->width = width;
2300 impl->snap_stash_int->height = height;
2301
2302 GDK_NOTE (MISC, g_print ("Stashed window %d x %d @ %d : %d as %f x %f @ %f : %f\n",
2303 width, height, x, y,
2304 impl->snap_stash->width, impl->snap_stash->height, impl->snap_stash->x, impl->snap_stash->y));
2305 }
2306
2307 static void
snap_up(GdkSurface * window)2308 snap_up (GdkSurface *window)
2309 {
2310 SHORT maxysize;
2311 int x, y;
2312 int width, height;
2313 GdkWin32Surface *impl;
2314
2315 impl = GDK_WIN32_SURFACE (window);
2316
2317 impl->snap_state = GDK_WIN32_AEROSNAP_STATE_FULLUP;
2318
2319 stash_window (window, impl);
2320
2321 maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->surface_scale;
2322 x = y = 0;
2323 width = gdk_surface_get_width (window);
2324
2325 y = 0;
2326 height = maxysize;
2327
2328 x = x - impl->shadow.left;
2329 y = y - impl->shadow.top;
2330 width += impl->shadow_x;
2331 height += impl->shadow_y;
2332
2333 /* XXX: FIXME, AeroSnap snap_up() not really working well,
2334 *
2335 * * The snap_up() puts the window at the top left corner.
2336 * * Without the following call, the height maximizes but we see a spew of
2337 * "GdkToplevelSize: geometry size (x,y) exceeds bounds" warnings
2338 */
2339 compute_toplevel_size (window, TRUE, &width, &height);
2340
2341 gdk_win32_surface_move_resize (window, x, y, width, height);
2342 }
2343
2344 static void
snap_left(GdkSurface * window,GdkMonitor * monitor,GdkMonitor * snap_monitor)2345 snap_left (GdkSurface *window,
2346 GdkMonitor *monitor,
2347 GdkMonitor *snap_monitor)
2348 {
2349 GdkRectangle rect;
2350 GdkWin32Surface *impl;
2351
2352 impl = GDK_WIN32_SURFACE (window);
2353
2354 impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
2355
2356 gdk_win32_monitor_get_workarea (snap_monitor, &rect);
2357
2358 stash_window (window, impl);
2359
2360 rect.width = rect.width / 2;
2361
2362 rect.x = rect.x - impl->shadow.left;
2363 rect.y = rect.y - impl->shadow.top;
2364 rect.width = rect.width + impl->shadow_x;
2365 rect.height = rect.height + impl->shadow_y;
2366
2367 gdk_win32_surface_move_resize (window,
2368 rect.x, rect.y,
2369 rect.width, rect.height);
2370 }
2371
2372 static void
snap_right(GdkSurface * window,GdkMonitor * monitor,GdkMonitor * snap_monitor)2373 snap_right (GdkSurface *window,
2374 GdkMonitor *monitor,
2375 GdkMonitor *snap_monitor)
2376 {
2377 GdkRectangle rect;
2378 GdkWin32Surface *impl;
2379
2380 impl = GDK_WIN32_SURFACE (window);
2381
2382 impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
2383
2384 gdk_win32_monitor_get_workarea (snap_monitor, &rect);
2385
2386 stash_window (window, impl);
2387
2388 rect.width = rect.width / 2;
2389 rect.x += rect.width;
2390
2391 rect.x = rect.x - impl->shadow.left;
2392 rect.y = rect.y - impl->shadow.top;
2393 rect.width = rect.width + impl->shadow_x;
2394 rect.height = rect.height + impl->shadow_y;
2395
2396 gdk_win32_surface_move_resize (window,
2397 rect.x, rect.y,
2398 rect.width, rect.height);
2399 }
2400
2401 static void
2402 gdk_win32_surface_maximize (GdkSurface *window);
2403 static void
2404 gdk_win32_surface_unmaximize (GdkSurface *window);
2405 static void
2406 gdk_win32_surface_minimize (GdkSurface *window);
2407
2408 void
_gdk_win32_surface_handle_aerosnap(GdkSurface * window,GdkWin32AeroSnapCombo combo)2409 _gdk_win32_surface_handle_aerosnap (GdkSurface *window,
2410 GdkWin32AeroSnapCombo combo)
2411 {
2412 GdkWin32Surface *impl;
2413 GdkDisplay *display;
2414 GListModel *monitors;
2415 int n_monitors;
2416 GdkToplevelState surface_state = gdk_toplevel_get_state (GDK_TOPLEVEL (window));
2417 gboolean minimized = surface_state & GDK_TOPLEVEL_STATE_MINIMIZED;
2418 gboolean maximized = surface_state & GDK_TOPLEVEL_STATE_MAXIMIZED;
2419 gboolean halfsnapped;
2420 GdkMonitor *monitor;
2421
2422 impl = GDK_WIN32_SURFACE (window);
2423 display = gdk_surface_get_display (window);
2424 monitors = gdk_display_get_monitors (display);
2425 n_monitors = g_list_model_get_n_items (monitors);
2426 monitor = gdk_display_get_monitor_at_surface (display, window);
2427
2428 if (minimized && maximized)
2429 minimized = FALSE;
2430
2431 halfsnapped = (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
2432 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
2433 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP);
2434
2435 switch (combo)
2436 {
2437 case GDK_WIN32_AEROSNAP_COMBO_NOTHING:
2438 /* Do nothing */
2439 break;
2440 case GDK_WIN32_AEROSNAP_COMBO_UP:
2441 if (!maximized)
2442 {
2443 unsnap (window, monitor);
2444 gdk_win32_surface_maximize (window);
2445 }
2446 break;
2447 case GDK_WIN32_AEROSNAP_COMBO_DOWN:
2448 case GDK_WIN32_AEROSNAP_COMBO_SHIFTDOWN:
2449 if (maximized)
2450 {
2451 gdk_win32_surface_unmaximize (window);
2452 unsnap (window, monitor);
2453 }
2454 else if (halfsnapped)
2455 unsnap (window, monitor);
2456 else if (!minimized)
2457 gdk_win32_surface_minimize (window);
2458 break;
2459 case GDK_WIN32_AEROSNAP_COMBO_LEFT:
2460 if (maximized)
2461 gdk_win32_surface_unmaximize (window);
2462
2463 if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED ||
2464 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP)
2465 {
2466 unsnap (window, monitor);
2467 snap_left (window, monitor, monitor);
2468 }
2469 else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT)
2470 {
2471 GdkMonitor *other;
2472
2473 unsnap (window, monitor);
2474 if (gdk_win32_display_get_primary_monitor (monitor->display) == monitor)
2475 other = g_object_ref (monitor);
2476 else
2477 other = g_list_model_get_item (monitors, n_monitors - 1);
2478 snap_right (window, monitor, other);
2479 g_object_unref (other);
2480 }
2481 else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT)
2482 {
2483 unsnap (window, monitor);
2484 }
2485 break;
2486 case GDK_WIN32_AEROSNAP_COMBO_RIGHT:
2487 if (maximized)
2488 gdk_win32_surface_unmaximize (window);
2489
2490 if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED ||
2491 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP)
2492 {
2493 unsnap (window, monitor);
2494 snap_right (window, monitor, monitor);
2495 }
2496 else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT)
2497 {
2498 unsnap (window, monitor);
2499 }
2500 else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT)
2501 {
2502 GdkMonitor *other;
2503 int i;
2504
2505 unsnap (window, monitor);
2506 for (i = 0; i < n_monitors; i++)
2507 {
2508 other = g_list_model_get_item (monitors, i);
2509 g_object_unref (other);
2510 if (monitor == other)
2511 break;
2512 }
2513
2514 other = g_list_model_get_item (monitors, (i + 1) % n_monitors);
2515 snap_left (window, monitor, other);
2516 g_object_unref (other);
2517 }
2518 break;
2519 case GDK_WIN32_AEROSNAP_COMBO_SHIFTUP:
2520 if (!maximized &&
2521 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED)
2522 {
2523 snap_up (window);
2524 }
2525 break;
2526 case GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT:
2527 case GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT:
2528 /* No implementation needed at the moment */
2529 break;
2530 }
2531 }
2532
2533 static void
apply_snap(GdkSurface * window,GdkWin32AeroSnapState snap)2534 apply_snap (GdkSurface *window,
2535 GdkWin32AeroSnapState snap)
2536 {
2537 GdkMonitor *monitor;
2538 GdkDisplay *display;
2539
2540 display = gdk_surface_get_display (window);
2541 monitor = gdk_display_get_monitor_at_surface (display, window);
2542
2543 switch (snap)
2544 {
2545 case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
2546 break;
2547 case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
2548 unsnap (window, monitor);
2549 gdk_win32_surface_maximize (window);
2550 break;
2551 case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
2552 unsnap (window, monitor);
2553 snap_left (window, monitor, monitor);
2554 break;
2555 case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
2556 unsnap (window, monitor);
2557 snap_right (window, monitor, monitor);
2558 break;
2559 case GDK_WIN32_AEROSNAP_STATE_FULLUP:
2560 snap_up (window);
2561 break;
2562 }
2563 }
2564
2565 /* Registers a dumb window class. This window
2566 * has DefWindowProc() for a window procedure and
2567 * does not do anything that GdkSurface-bound HWNDs do.
2568 */
2569 static ATOM
RegisterGdkDumbClass()2570 RegisterGdkDumbClass ()
2571 {
2572 static ATOM klassDUMB = 0;
2573 static WNDCLASSEXW wcl;
2574 ATOM klass = 0;
2575
2576 wcl.cbSize = sizeof (WNDCLASSEX);
2577 wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
2578 * on WM_SIZE and WM_MOVE. Flicker, Performance!
2579 */
2580 wcl.lpfnWndProc = DefWindowProcW;
2581 wcl.cbClsExtra = 0;
2582 wcl.cbWndExtra = 0;
2583 wcl.hInstance = _gdk_dll_hinstance;
2584 wcl.hIcon = 0;
2585 wcl.hIconSm = 0;
2586 wcl.lpszMenuName = NULL;
2587 wcl.hbrBackground = NULL;
2588 wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
2589 wcl.style |= CS_OWNDC;
2590 wcl.lpszClassName = L"gdkSurfaceDumb";
2591
2592 if (klassDUMB == 0)
2593 klassDUMB = RegisterClassExW (&wcl);
2594
2595 klass = klassDUMB;
2596
2597 if (klass == 0)
2598 {
2599 WIN32_API_FAILED ("RegisterClassExW");
2600 g_error ("That is a fatal error");
2601 }
2602
2603 return klass;
2604 }
2605
2606 static gboolean
ensure_snap_indicator_exists(GdkW32DragMoveResizeContext * context)2607 ensure_snap_indicator_exists (GdkW32DragMoveResizeContext *context)
2608 {
2609 if (context->shape_indicator == NULL)
2610 {
2611 HWND handle;
2612 ATOM klass;
2613 klass = RegisterGdkDumbClass ();
2614
2615 handle = CreateWindowExW (WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE,
2616 MAKEINTRESOURCEW (klass),
2617 L"",
2618 WS_POPUP,
2619 0,
2620 0,
2621 0, 0,
2622 NULL,
2623 NULL,
2624 _gdk_dll_hinstance,
2625 NULL);
2626
2627 context->shape_indicator = handle;
2628 }
2629
2630 return context->shape_indicator != NULL;
2631 }
2632
2633 static gboolean
ensure_snap_indicator_surface(GdkW32DragMoveResizeContext * context,int width,int height,guint scale)2634 ensure_snap_indicator_surface (GdkW32DragMoveResizeContext *context,
2635 int width,
2636 int height,
2637 guint scale)
2638 {
2639 if (context->indicator_surface != NULL &&
2640 (context->indicator_surface_width < width ||
2641 context->indicator_surface_height < height))
2642 {
2643 cairo_surface_destroy (context->indicator_surface);
2644 context->indicator_surface = NULL;
2645 }
2646
2647 if (context->indicator_surface == NULL)
2648 context->indicator_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
2649 width * scale,
2650 height * scale);
2651
2652 if (cairo_surface_status (context->indicator_surface) != CAIRO_STATUS_SUCCESS)
2653 {
2654 cairo_surface_destroy (context->indicator_surface);
2655 context->indicator_surface = NULL;
2656
2657 return FALSE;
2658 }
2659
2660 return TRUE;
2661 }
2662
2663 /* Indicator is drawn with some inward offset, so that it does
2664 * not hug screen edges.
2665 */
2666 static void
adjust_indicator_rectangle(GdkRectangle * rect,gboolean inward)2667 adjust_indicator_rectangle (GdkRectangle *rect,
2668 gboolean inward)
2669 {
2670 double inverter;
2671 const int gap = AEROSNAP_INDICATOR_EDGE_GAP;
2672 #if defined(MORE_AEROSNAP_DEBUGGING)
2673 GdkRectangle cache = *rect;
2674 #endif
2675
2676 if (inward)
2677 inverter = 1.0;
2678 else
2679 inverter = -1.0;
2680
2681 rect->x += (gap * inverter);
2682 rect->y += (gap * inverter);
2683 rect->width -= (gap * 2 * inverter);
2684 rect->height -= (gap * 2 * inverter);
2685
2686 #if defined(MORE_AEROSNAP_DEBUGGING)
2687 GDK_NOTE (MISC, g_print ("Adjusted %d x %d @ %d : %d -> %d x %d @ %d : %d\n",
2688 cache.width, cache.height, cache.x, cache.y,
2689 rect->width, rect->height, rect->x, rect->y));
2690 #endif
2691 }
2692
2693 static void
rounded_rectangle(cairo_t * cr,int x,int y,int width,int height,double radius,double line_width,GdkRGBA * fill,GdkRGBA * outline)2694 rounded_rectangle (cairo_t *cr,
2695 int x,
2696 int y,
2697 int width,
2698 int height,
2699 double radius,
2700 double line_width,
2701 GdkRGBA *fill,
2702 GdkRGBA *outline)
2703 {
2704 double degrees = M_PI / 180.0;
2705
2706 if (fill == NULL && outline == NULL)
2707 return;
2708
2709 cairo_save (cr);
2710 cairo_new_sub_path (cr);
2711 cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
2712 cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
2713 cairo_arc (cr, (x + radius), y + height - radius, radius, 90 * degrees, 180 * degrees);
2714 cairo_arc (cr, (x + radius), (y + radius), radius, 180 * degrees, 270 * degrees);
2715 cairo_close_path (cr);
2716
2717 if (fill)
2718 {
2719 cairo_set_source_rgba (cr, fill->red, fill->green, fill->blue, fill->alpha);
2720
2721 if (outline)
2722 cairo_fill_preserve (cr);
2723 else
2724 cairo_fill (cr);
2725 }
2726
2727 if (outline)
2728 {
2729 cairo_set_source_rgba (cr, outline->red, outline->green, outline->blue, outline->alpha);
2730 cairo_set_line_width (cr, line_width);
2731 cairo_stroke (cr);
2732 }
2733
2734 cairo_restore (cr);
2735 }
2736
2737 /* Translates linear animation scale into some kind of curve */
2738 static double
curve(double val)2739 curve (double val)
2740 {
2741 /* TODO: try different curves. For now it's just linear */
2742 return val;
2743 }
2744
2745 static gboolean
draw_indicator(GdkW32DragMoveResizeContext * context,gint64 timestamp)2746 draw_indicator (GdkW32DragMoveResizeContext *context,
2747 gint64 timestamp)
2748 {
2749 cairo_t *cr;
2750 GdkRGBA outline = {0, 0, 1.0, 1.0};
2751 GdkRGBA fill = {0, 0, 1.0, 0.8};
2752 GdkRectangle current_rect;
2753 gint64 current_time = g_get_monotonic_time ();
2754 double animation_progress;
2755 gboolean last_draw;
2756 double line_width;
2757 double corner_radius;
2758 gint64 animation_duration;
2759 GdkWin32Surface *impl = GDK_WIN32_SURFACE (context->window);
2760
2761 line_width = AEROSNAP_INDICATOR_LINE_WIDTH * impl->surface_scale;
2762 corner_radius = AEROSNAP_INDICATOR_CORNER_RADIUS;
2763 animation_duration = AEROSNAP_INDICATOR_ANIMATION_DURATION;
2764 last_draw = FALSE;
2765
2766 if (timestamp == 0 &&
2767 current_time - context->indicator_start_time > animation_duration)
2768 {
2769 timestamp = context->indicator_start_time + animation_duration;
2770 last_draw = TRUE;
2771 }
2772
2773 if (timestamp != 0)
2774 current_time = timestamp;
2775
2776 animation_progress = (double) (current_time - context->indicator_start_time) / animation_duration;
2777
2778 if (animation_progress > 1.0)
2779 animation_progress = 1.0;
2780
2781 if (animation_progress < 0)
2782 animation_progress = 0;
2783
2784 animation_progress = curve (animation_progress);
2785
2786 current_rect = context->indicator_start;
2787 current_rect.x += (context->indicator_target.x - context->indicator_start.x) * animation_progress;
2788 current_rect.y += (context->indicator_target.y - context->indicator_start.y) * animation_progress;
2789 current_rect.width += (context->indicator_target.width - context->indicator_start.width) * animation_progress;
2790 current_rect.height += (context->indicator_target.height - context->indicator_start.height) * animation_progress;
2791
2792 if (context->op == GDK_WIN32_DRAGOP_RESIZE && last_draw)
2793 {
2794 switch (context->edge)
2795 {
2796 case GDK_SURFACE_EDGE_NORTH_WEST:
2797 current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
2798 current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
2799 break;
2800 case GDK_SURFACE_EDGE_NORTH:
2801 current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
2802 break;
2803 case GDK_SURFACE_EDGE_WEST:
2804 current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
2805 break;
2806 case GDK_SURFACE_EDGE_SOUTH_WEST:
2807 current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
2808 current_rect.y = context->indicator_target.y;
2809 break;
2810 case GDK_SURFACE_EDGE_NORTH_EAST:
2811 current_rect.x = context->indicator_target.x;
2812 current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
2813 break;
2814 case GDK_SURFACE_EDGE_SOUTH_EAST:
2815 current_rect.x = context->indicator_target.x;
2816 current_rect.y = context->indicator_target.y;
2817 break;
2818 case GDK_SURFACE_EDGE_SOUTH:
2819 current_rect.y = context->indicator_target.y;
2820 break;
2821 case GDK_SURFACE_EDGE_EAST:
2822 current_rect.x = context->indicator_target.x;
2823 break;
2824 }
2825 }
2826
2827 cr = cairo_create (context->indicator_surface);
2828 rounded_rectangle (cr,
2829 (current_rect.x - context->indicator_window_rect.x) * impl->surface_scale,
2830 (current_rect.y - context->indicator_window_rect.y) * impl->surface_scale,
2831 current_rect.width * impl->surface_scale,
2832 current_rect.height * impl->surface_scale,
2833 corner_radius,
2834 line_width,
2835 &fill, &outline);
2836 cairo_destroy (cr);
2837
2838 #if defined(MORE_AEROSNAP_DEBUGGING)
2839 GDK_NOTE (MISC, g_print ("Indicator is %d x %d @ %d : %d; current time is %" G_GINT64_FORMAT "\n",
2840 current_rect.width, current_rect.height,
2841 current_rect.x - context->indicator_window_rect.x,
2842 current_rect.y - context->indicator_window_rect.y,
2843 current_time));
2844 #endif
2845
2846 return last_draw;
2847 }
2848
2849 static gboolean
redraw_indicator(gpointer user_data)2850 redraw_indicator (gpointer user_data)
2851 {
2852 GdkW32DragMoveResizeContext *context = user_data;
2853 POINT window_position;
2854 SIZE window_size;
2855 BLENDFUNCTION blender;
2856 HDC hdc;
2857 POINT source_point = { 0, 0 };
2858 gboolean last_draw;
2859 double indicator_opacity;
2860 GdkWin32Surface *impl;
2861 gboolean do_source_remove = FALSE;
2862
2863 indicator_opacity = AEROSNAP_INDICATOR_OPACITY;
2864
2865 if (GDK_SURFACE_DESTROYED (context->window) ||
2866 !ensure_snap_indicator_exists (context))
2867 {
2868 do_source_remove = TRUE;
2869 }
2870
2871 impl = GDK_WIN32_SURFACE (context->window);
2872
2873 if (!ensure_snap_indicator_surface (context,
2874 context->indicator_window_rect.width,
2875 context->indicator_window_rect.height,
2876 impl->surface_scale))
2877 {
2878 do_source_remove = TRUE;
2879 }
2880
2881 if (do_source_remove)
2882 {
2883 context->timer = 0;
2884 return G_SOURCE_REMOVE;
2885 }
2886
2887 last_draw = draw_indicator (context, context->draw_timestamp);
2888
2889 window_position.x = (context->indicator_window_rect.x - _gdk_offset_x) * impl->surface_scale;
2890 window_position.y = (context->indicator_window_rect.y - _gdk_offset_y) * impl->surface_scale;
2891 window_size.cx = context->indicator_window_rect.width * impl->surface_scale;
2892 window_size.cy = context->indicator_window_rect.height * impl->surface_scale;
2893
2894 blender.BlendOp = AC_SRC_OVER;
2895 blender.BlendFlags = 0;
2896 blender.AlphaFormat = AC_SRC_ALPHA;
2897 blender.SourceConstantAlpha = 255 * indicator_opacity;
2898
2899 hdc = cairo_win32_surface_get_dc (context->indicator_surface);
2900
2901 API_CALL (SetWindowPos, (context->shape_indicator,
2902 GDK_SURFACE_HWND (context->window),
2903 0, 0, 0, 0,
2904 SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_NOACTIVATE));
2905
2906 #if defined(MORE_AEROSNAP_DEBUGGING)
2907 GDK_NOTE (MISC, g_print ("Indicator window position is %ld x %ld @ %ld : %ld\n",
2908 window_size.cx, window_size.cy,
2909 window_position.x, window_position.y));
2910 #endif
2911
2912 API_CALL (UpdateLayeredWindow, (context->shape_indicator, NULL,
2913 &window_position, &window_size,
2914 hdc, &source_point,
2915 0, &blender, ULW_ALPHA));
2916
2917 if (last_draw)
2918 context->timer = 0;
2919
2920 return last_draw ? G_SOURCE_REMOVE : G_SOURCE_CONTINUE;
2921 }
2922
2923 static GdkRectangle
unity_of_rects(GdkRectangle a,GdkRectangle b)2924 unity_of_rects (GdkRectangle a,
2925 GdkRectangle b)
2926 {
2927 GdkRectangle u = b;
2928
2929 if (a.x < u.x)
2930 {
2931 u.width += u.x - a.x;
2932 u.x = a.x;
2933 }
2934
2935 if (a.y < u.y)
2936 {
2937 u.height += (u.y - a.y);
2938 u.y = a.y;
2939 }
2940
2941 if (a.x + a.width > u.x + u.width)
2942 u.width += (a.x + a.width) - (u.x + u.width);
2943
2944 if (a.y + a.height > u.y + u.height)
2945 u.height += (a.y + a.height) - (u.y + u.height);
2946
2947 #if defined(MORE_AEROSNAP_DEBUGGING)
2948 GDK_NOTE (MISC, g_print ("Unified 2 rects into %d x %d @ %d : %d\n",
2949 u.width, u.height, u.x, u.y));
2950 #endif
2951
2952 return u;
2953 }
2954
2955 static void
start_indicator_drawing(GdkW32DragMoveResizeContext * context,GdkRectangle from,GdkRectangle to,guint scale)2956 start_indicator_drawing (GdkW32DragMoveResizeContext *context,
2957 GdkRectangle from,
2958 GdkRectangle to,
2959 guint scale)
2960 {
2961 GdkRectangle to_adjusted, from_adjusted, from_or_to;
2962 gint64 indicator_animation_tick = AEROSNAP_INDICATOR_ANIMATION_TICK;
2963
2964 GDK_NOTE (MISC, g_print ("Start drawing snap indicator %d x %d @ %d : %d -> %d x %d @ %d : %d\n",
2965 from.width * scale, from.height * scale, from.x, from.y, to.width * scale, to.height * scale, to.x, to.y));
2966
2967 if (GDK_SURFACE_DESTROYED (context->window))
2968 return;
2969
2970 if (!ensure_snap_indicator_exists (context))
2971 return;
2972
2973 from_or_to = unity_of_rects (from, to);
2974
2975 if (!ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height, scale))
2976 return;
2977
2978 to_adjusted = to;
2979 adjust_indicator_rectangle (&to_adjusted, TRUE);
2980
2981 from_adjusted = from;
2982 adjust_indicator_rectangle (&from_adjusted, TRUE);
2983
2984 context->draw_timestamp = 0;
2985 context->indicator_start = from_adjusted;
2986 context->indicator_target = to_adjusted;
2987 context->indicator_window_rect = from_or_to;
2988 context->indicator_start_time = g_get_monotonic_time ();
2989
2990 if (context->timer)
2991 {
2992 g_source_remove (context->timer);
2993 context->timer = 0;
2994 }
2995
2996 context->timer = g_timeout_add_full (G_PRIORITY_DEFAULT,
2997 indicator_animation_tick,
2998 redraw_indicator,
2999 context,
3000 NULL);
3001 }
3002
3003 static void
update_fullup_indicator(GdkSurface * window,GdkW32DragMoveResizeContext * context)3004 update_fullup_indicator (GdkSurface *window,
3005 GdkW32DragMoveResizeContext *context)
3006 {
3007 SHORT maxysize;
3008 GdkRectangle from, to;
3009 GdkRectangle to_adjusted, from_adjusted, from_or_to;
3010 GdkWin32Surface *impl;
3011
3012 GDK_NOTE (MISC, g_print ("Update fullup indicator\n"));
3013
3014 if (GDK_SURFACE_DESTROYED (context->window))
3015 return;
3016
3017 if (context->shape_indicator == NULL)
3018 return;
3019
3020 impl = GDK_WIN32_SURFACE (window);
3021 maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN);
3022 to.x = to.y = 0;
3023 to.width = gdk_surface_get_width (window);
3024 to.height = gdk_surface_get_height (window);
3025
3026 to.y = 0;
3027 to.height = maxysize;
3028 from = context->indicator_target;
3029
3030 if (context->timer == 0)
3031 {
3032 from_adjusted = from;
3033 adjust_indicator_rectangle (&from_adjusted, FALSE);
3034
3035 GDK_NOTE (MISC, g_print ("Restart fullup animation from %d x %d @ %d : %d -> %d x %d @ %d x %d\n",
3036 context->indicator_target.width, context->indicator_target.height,
3037 context->indicator_target.x, context->indicator_target.y,
3038 to.width, to.height, to.x, to.y));
3039 start_indicator_drawing (context, from_adjusted, to, impl->surface_scale);
3040
3041 return;
3042 }
3043
3044 from_or_to = unity_of_rects (from, to);
3045
3046 to_adjusted = to;
3047 adjust_indicator_rectangle (&to_adjusted, TRUE);
3048
3049 GDK_NOTE (MISC, g_print ("Retarget fullup animation %d x %d @ %d : %d -> %d x %d @ %d x %d\n",
3050 context->indicator_target.width, context->indicator_target.height,
3051 context->indicator_target.x, context->indicator_target.y,
3052 to_adjusted.width, to_adjusted.height, to_adjusted.x, to_adjusted.y));
3053
3054 context->indicator_target = to_adjusted;
3055 context->indicator_window_rect = from_or_to;
3056
3057 ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height, impl->surface_scale);
3058 }
3059
3060 static GdkMonitor *
get_monitor_at_point(GdkDisplay * display,int x,int y)3061 get_monitor_at_point (GdkDisplay *display,
3062 int x,
3063 int y)
3064 {
3065 GListModel *monitors;
3066 GdkMonitor *nearest = NULL;
3067 int nearest_dist = G_MAXINT;
3068 guint i;
3069
3070 monitors = gdk_display_get_monitors (display);
3071 for (i = 0; i < g_list_model_get_n_items (monitors); i++)
3072 {
3073 GdkMonitor *monitor;
3074 GdkRectangle geometry;
3075 int dist_x, dist_y, dist;
3076
3077 monitor = g_list_model_get_item (monitors, i);
3078 gdk_monitor_get_geometry (monitor, &geometry);
3079
3080 if (x < geometry.x)
3081 dist_x = geometry.x - x;
3082 else if (geometry.x + geometry.width <= x)
3083 dist_x = x - (geometry.x + geometry.width) + 1;
3084 else
3085 dist_x = 0;
3086
3087 if (y < geometry.y)
3088 dist_y = geometry.y - y;
3089 else if (geometry.y + geometry.height <= y)
3090 dist_y = y - (geometry.y + geometry.height) + 1;
3091 else
3092 dist_y = 0;
3093
3094 dist = dist_x + dist_y;
3095 if (dist < nearest_dist)
3096 {
3097 nearest_dist = dist;
3098 nearest = monitor;
3099 }
3100
3101 if (x < geometry.x)
3102 dist_x = geometry.x - x;
3103 else if (geometry.x + geometry.width <= x)
3104 dist_x = x - (geometry.x + geometry.width) + 1;
3105 else
3106 dist_x = 0;
3107
3108 if (y < geometry.y)
3109 dist_y = geometry.y - y;
3110 else if (geometry.y + geometry.height <= y)
3111 dist_y = y - (geometry.y + geometry.height) + 1;
3112 else
3113 dist_y = 0;
3114
3115 dist = dist_x + dist_y;
3116 if (dist < nearest_dist)
3117 {
3118 nearest_dist = dist;
3119 nearest = monitor;
3120 }
3121
3122 g_object_unref (monitor);
3123
3124 if (nearest_dist == 0)
3125 break;
3126 }
3127
3128 return nearest;
3129 }
3130
3131 static void
start_indicator(GdkSurface * window,GdkW32DragMoveResizeContext * context,int x,int y,GdkWin32AeroSnapState state)3132 start_indicator (GdkSurface *window,
3133 GdkW32DragMoveResizeContext *context,
3134 int x,
3135 int y,
3136 GdkWin32AeroSnapState state)
3137 {
3138 GdkMonitor *monitor;
3139 GdkRectangle workarea;
3140 SHORT maxysize;
3141 GdkRectangle start_size, end_size;
3142 GdkDisplay *display;
3143 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
3144
3145 display = gdk_surface_get_display (window);
3146 monitor = get_monitor_at_point (display, x, y);
3147 gdk_win32_monitor_get_workarea (monitor, &workarea);
3148
3149 maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->surface_scale;
3150 start_size.x = start_size.y = 0;
3151 start_size.width = gdk_surface_get_width (window);
3152 start_size.height = gdk_surface_get_height (window);
3153
3154 end_size = start_size;
3155
3156 switch (state)
3157 {
3158 case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
3159 return;
3160 case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
3161 end_size.x = workarea.x;
3162 end_size.y = workarea.y;
3163 end_size.width = workarea.width;
3164 end_size.height = workarea.height;
3165 break;
3166 case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
3167 end_size.x = workarea.x;
3168 end_size.y = workarea.y;
3169 end_size.width = workarea.width / 2;
3170 end_size.height = workarea.height;
3171 break;
3172 case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
3173 end_size.x = (workarea.x + workarea.width / 2);
3174 end_size.y = workarea.y;
3175 end_size.width = workarea.width / 2;
3176 end_size.height = workarea.height;
3177 break;
3178 case GDK_WIN32_AEROSNAP_STATE_FULLUP:
3179 end_size.y = 0;
3180 end_size.height = maxysize;
3181 break;
3182 }
3183
3184 start_indicator_drawing (context, start_size, end_size, impl->surface_scale);
3185 }
3186
3187 static void
stop_indicator(GdkSurface * window,GdkW32DragMoveResizeContext * context)3188 stop_indicator (GdkSurface *window,
3189 GdkW32DragMoveResizeContext *context)
3190 {
3191 GDK_NOTE (MISC, g_print ("Stop drawing snap indicator\n"));
3192
3193 if (context->timer)
3194 {
3195 g_source_remove (context->timer);
3196 context->timer = 0;
3197 }
3198
3199 API_CALL (SetWindowPos, (context->shape_indicator,
3200 SWP_NOZORDER_SPECIFIED,
3201 0, 0, 0, 0,
3202 SWP_NOZORDER | SWP_NOMOVE |
3203 SWP_NOSIZE | SWP_NOREDRAW | SWP_HIDEWINDOW | SWP_NOACTIVATE));
3204 }
3205
3206 static int
point_in_aerosnap_region(int x,int y,AeroSnapEdgeRegion * region)3207 point_in_aerosnap_region (int x,
3208 int y,
3209 AeroSnapEdgeRegion *region)
3210 {
3211 int edge, trigger;
3212
3213 edge = (x >= region->edge.x &&
3214 y >= region->edge.y &&
3215 x <= region->edge.x + region->edge.width &&
3216 y <= region->edge.y + region->edge.height) ? 1 : 0;
3217 trigger = (x >= region->trigger.x &&
3218 y >= region->trigger.y &&
3219 x <= region->trigger.x + region->trigger.width &&
3220 y <= region->trigger.y + region->trigger.height) ? 1 : 0;
3221 return edge + trigger;
3222 }
3223
3224 static void
handle_aerosnap_move_resize(GdkSurface * window,GdkW32DragMoveResizeContext * context,int x,int y)3225 handle_aerosnap_move_resize (GdkSurface *window,
3226 GdkW32DragMoveResizeContext *context,
3227 int x,
3228 int y)
3229 {
3230 int i;
3231 AeroSnapEdgeRegion *reg;
3232 int maximize = 0;
3233 int halfleft = 0;
3234 int halfright = 0;
3235 int fullup = 0;
3236 gboolean fullup_edge = FALSE;
3237
3238 if (context->op == GDK_WIN32_DRAGOP_RESIZE)
3239 switch (context->edge)
3240 {
3241 case GDK_SURFACE_EDGE_NORTH_WEST:
3242 case GDK_SURFACE_EDGE_NORTH_EAST:
3243 case GDK_SURFACE_EDGE_WEST:
3244 case GDK_SURFACE_EDGE_EAST:
3245 case GDK_SURFACE_EDGE_SOUTH_WEST:
3246 case GDK_SURFACE_EDGE_SOUTH_EAST:
3247 break;
3248 case GDK_SURFACE_EDGE_SOUTH:
3249 case GDK_SURFACE_EDGE_NORTH:
3250 fullup_edge = TRUE;
3251 break;
3252 }
3253
3254 for (i = 0; i < context->maximize_regions->len && maximize == 0; i++)
3255 {
3256 reg = &g_array_index (context->maximize_regions, AeroSnapEdgeRegion, i);
3257 maximize = point_in_aerosnap_region (x, y, reg);
3258 }
3259
3260 for (i = 0; i < context->halfleft_regions->len && halfleft == 0; i++)
3261 {
3262 reg = &g_array_index (context->halfleft_regions, AeroSnapEdgeRegion, i);
3263 halfleft = point_in_aerosnap_region (x, y, reg);
3264 }
3265
3266 for (i = 0; i < context->halfright_regions->len && halfright == 0; i++)
3267 {
3268 reg = &g_array_index (context->halfright_regions, AeroSnapEdgeRegion, i);
3269 halfright = point_in_aerosnap_region (x, y, reg);
3270 }
3271
3272 for (i = 0; i < context->fullup_regions->len && fullup == 0; i++)
3273 {
3274 reg = &g_array_index (context->fullup_regions, AeroSnapEdgeRegion, i);
3275 fullup = point_in_aerosnap_region (x, y, reg);
3276 }
3277
3278 #if defined(MORE_AEROSNAP_DEBUGGING)
3279 GDK_NOTE (MISC, g_print ("AeroSnap: point %d : %d - max: %d, left %d, right %d, up %d\n",
3280 x, y, maximize, halfleft, halfright, fullup));
3281 #endif
3282
3283 if (!context->revealed)
3284 {
3285 if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize == 2)
3286 {
3287 context->revealed = TRUE;
3288 context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
3289 start_indicator (window, context, x, y, context->current_snap);
3290 }
3291 else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft == 2)
3292 {
3293 context->revealed = TRUE;
3294 context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
3295 start_indicator (window, context, x, y, context->current_snap);
3296 }
3297 else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright == 2)
3298 {
3299 context->revealed = TRUE;
3300 context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
3301 start_indicator (window, context, x, y, context->current_snap);
3302 }
3303 else if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup == 2 && fullup_edge)
3304 {
3305 context->revealed = TRUE;
3306 context->current_snap = GDK_WIN32_AEROSNAP_STATE_FULLUP;
3307 start_indicator (window, context, x, y, context->current_snap);
3308 }
3309
3310 return;
3311 }
3312
3313 switch (context->current_snap)
3314 {
3315 case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
3316 if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup > 0)
3317 {
3318 context->current_snap = GDK_WIN32_AEROSNAP_STATE_FULLUP;
3319 start_indicator (window, context, x, y, context->current_snap);
3320 }
3321 break;
3322 case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
3323 if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
3324 break;
3325 if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
3326 {
3327 context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
3328 start_indicator (window, context, x, y, context->current_snap);
3329 }
3330 else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
3331 {
3332 context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
3333 start_indicator (window, context, x, y, context->current_snap);
3334 }
3335 else
3336 {
3337 context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
3338 stop_indicator (window, context);
3339 context->revealed = FALSE;
3340 }
3341 break;
3342 case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
3343 if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
3344 break;
3345 if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
3346 {
3347 context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
3348 start_indicator (window, context, x, y, context->current_snap);
3349 }
3350 else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
3351 {
3352 context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
3353 start_indicator (window, context, x, y, context->current_snap);
3354 }
3355 else
3356 {
3357 context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
3358 stop_indicator (window, context);
3359 context->revealed = FALSE;
3360 }
3361 break;
3362 case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
3363 if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
3364 break;
3365 if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
3366 {
3367 context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
3368 start_indicator (window, context, x, y, context->current_snap);
3369 }
3370 else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
3371 {
3372 context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
3373 start_indicator (window, context, x, y, context->current_snap);
3374 }
3375 else
3376 {
3377 context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
3378 stop_indicator (window, context);
3379 context->revealed = FALSE;
3380 }
3381 break;
3382 case GDK_WIN32_AEROSNAP_STATE_FULLUP:
3383 if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup > 0 && fullup_edge)
3384 {
3385 update_fullup_indicator (window, context);
3386 break;
3387 }
3388
3389 context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
3390 stop_indicator (window, context);
3391 break;
3392 }
3393 }
3394
3395
3396 static const char *
get_cursor_name_from_op(GdkW32WindowDragOp op,GdkSurfaceEdge edge)3397 get_cursor_name_from_op (GdkW32WindowDragOp op,
3398 GdkSurfaceEdge edge)
3399 {
3400 switch (op)
3401 {
3402 case GDK_WIN32_DRAGOP_MOVE:
3403 return "move";
3404 case GDK_WIN32_DRAGOP_RESIZE:
3405 switch (edge)
3406 {
3407 case GDK_SURFACE_EDGE_NORTH_WEST:
3408 return "nw-resize";
3409 case GDK_SURFACE_EDGE_NORTH:
3410 return "n-resize";
3411 case GDK_SURFACE_EDGE_NORTH_EAST:
3412 return "ne-resize";
3413 case GDK_SURFACE_EDGE_WEST:
3414 return "w-resize";
3415 case GDK_SURFACE_EDGE_EAST:
3416 return "e-resize";
3417 case GDK_SURFACE_EDGE_SOUTH_WEST:
3418 return "sw-resize";
3419 case GDK_SURFACE_EDGE_SOUTH:
3420 return "s-resize";
3421 case GDK_SURFACE_EDGE_SOUTH_EAST:
3422 return "se-resize";
3423 }
3424 /* default: warn about unhandled enum values,
3425 * fallthrough to GDK_WIN32_DRAGOP_NONE case
3426 */
3427 case GDK_WIN32_DRAGOP_COUNT:
3428 g_assert_not_reached ();
3429 case GDK_WIN32_DRAGOP_NONE:
3430 return "default";
3431 /* default: warn about unhandled enum values */
3432 }
3433
3434 g_assert_not_reached ();
3435
3436 return NULL;
3437 }
3438
3439 static void
setup_drag_move_resize_context(GdkSurface * window,GdkW32DragMoveResizeContext * context,GdkW32WindowDragOp op,GdkSurfaceEdge edge,GdkDevice * device,int button,double x,double y,guint32 timestamp)3440 setup_drag_move_resize_context (GdkSurface *window,
3441 GdkW32DragMoveResizeContext *context,
3442 GdkW32WindowDragOp op,
3443 GdkSurfaceEdge edge,
3444 GdkDevice *device,
3445 int button,
3446 double x,
3447 double y,
3448 guint32 timestamp)
3449 {
3450 RECT rect;
3451 const char *cursor_name;
3452 GdkSurface *pointer_window;
3453 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
3454 gboolean maximized = gdk_toplevel_get_state (GDK_TOPLEVEL (window)) & GDK_TOPLEVEL_STATE_MAXIMIZED;
3455 int root_x, root_y;
3456
3457 gdk_win32_surface_get_root_coords (window, x, y, &root_x, &root_y);
3458
3459 /* Before we drag, we need to undo any maximization or snapping.
3460 * AeroSnap behaviour:
3461 * If snapped halfleft/halfright:
3462 * horizontal resize:
3463 * resize
3464 * don't unsnap
3465 * keep stashed unsnapped size intact
3466 * vertical resize:
3467 * resize
3468 * unsnap to new size (merge cached unsnapped state with current
3469 * snapped state in such a way that the gripped edge
3470 * does not move)
3471 * diagonal resize:
3472 * difficult to test (first move is usually either purely
3473 * horizontal or purely vertical, in which
3474 * case the above behaviour applies)
3475 * If snapped up:
3476 * horizontal resize:
3477 * resize
3478 * don't unsnap
3479 * apply new width and x position to unsnapped cache,
3480 * so that unsnapped window only regains its height
3481 * and y position, but inherits x and width from
3482 * the fullup snapped state
3483 * vertical resize:
3484 * unsnap to new size (merge cached unsnapped state with current
3485 * snapped state in such a way that the gripped edge
3486 * does not move)
3487 *
3488 * This implementation behaviour:
3489 * If snapped halfleft/halfright/fullup:
3490 * any resize:
3491 * unsnap to current size, discard cached pre-snap state
3492 *
3493 * TODO: make this implementation behave as AeroSnap on resizes?
3494 * There's also the case where
3495 * a halfleft/halfright window isn't unsnapped when it's
3496 * being moved horizontally, but it's more difficult to implement.
3497 */
3498 if (op == GDK_WIN32_DRAGOP_RESIZE &&
3499 (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
3500 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
3501 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP))
3502 {
3503 discard_snapinfo (window);
3504 }
3505 else if (maximized ||
3506 (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
3507 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
3508 impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP))
3509 {
3510 GdkMonitor *monitor;
3511 int wx, wy, wwidth, wheight;
3512 int swx, swy, swwidth, swheight;
3513 gboolean pointer_outside_of_window;
3514 int offsetx, offsety;
3515 gboolean left_half;
3516 GdkDisplay *display;
3517
3518 display = gdk_surface_get_display (window);
3519 monitor = gdk_display_get_monitor_at_surface (display, window);
3520 gdk_surface_get_geometry (window, &wx, &wy, &wwidth, &wheight);
3521
3522 swx = wx;
3523 swy = wy;
3524 swwidth = wwidth;
3525 swheight = wheight;
3526
3527 /* Subtract window shadow. We don't want pointer to go outside of
3528 * the visible window during drag-move. For drag-resize it's OK.
3529 * Don't take shadow into account if the window is maximized -
3530 * maximized windows don't have shadows.
3531 */
3532 if (op == GDK_WIN32_DRAGOP_MOVE && !maximized)
3533 {
3534 swx += impl->shadow.left / impl->surface_scale;
3535 swy += impl->shadow.top / impl->surface_scale;
3536 swwidth -= impl->shadow_x;
3537 swheight -= impl->shadow_y;
3538 }
3539
3540 pointer_outside_of_window = root_x < swx || root_x > swx + swwidth ||
3541 root_y < swy || root_y > swy + swheight;
3542 /* Calculate the offset of the pointer relative to the window */
3543 offsetx = root_x - swx;
3544 offsety = root_y - swy;
3545
3546 /* Figure out in which half of the window the pointer is.
3547 * The code currently only concerns itself with horizontal
3548 * dimension (left/right halves).
3549 * There's no upper/lower half, because usually window
3550 * is dragged by its upper half anyway. If that changes, adjust
3551 * accordingly.
3552 */
3553 left_half = (offsetx < swwidth / 2);
3554
3555 /* Inverse the offset for it to be from the right edge */
3556 if (!left_half)
3557 offsetx = swwidth - offsetx;
3558
3559 GDK_NOTE (MISC, g_print ("Pointer at %d : %d, this is %d : %d relative to the window's %s\n",
3560 root_x, root_y, offsetx, offsety,
3561 left_half ? "left half" : "right half"));
3562
3563 /* Move window in such a way that on unmaximization/unsnapping the pointer
3564 * is still pointing at the appropriate half of the window,
3565 * with the same offset from the left or right edge. If the new
3566 * window size is too small, and adding that offset puts the pointer
3567 * into the other half or even beyond, move the pointer to the middle.
3568 */
3569 if (!pointer_outside_of_window && maximized)
3570 {
3571 WINDOWPLACEMENT placement;
3572 int unmax_width, unmax_height;
3573 int shadow_unmax_width, shadow_unmax_height;
3574
3575 placement.length = sizeof (placement);
3576 API_CALL (GetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
3577
3578 GDK_NOTE (MISC, g_print ("W32 WM unmaximized window placement is %ld x %ld @ %ld : %ld\n",
3579 placement.rcNormalPosition.right - placement.rcNormalPosition.left,
3580 placement.rcNormalPosition.bottom - placement.rcNormalPosition.top,
3581 placement.rcNormalPosition.left + _gdk_offset_x * impl->surface_scale,
3582 placement.rcNormalPosition.top + _gdk_offset_y * impl->surface_scale));
3583
3584 unmax_width = placement.rcNormalPosition.right - placement.rcNormalPosition.left;
3585 unmax_height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top;
3586
3587 shadow_unmax_width = unmax_width - impl->shadow_x * impl->surface_scale;
3588 shadow_unmax_height = unmax_height - impl->shadow_y * impl->surface_scale;
3589
3590 if (offsetx * impl->surface_scale < (shadow_unmax_width / 2) &&
3591 offsety * impl->surface_scale < (shadow_unmax_height / 2))
3592 {
3593 placement.rcNormalPosition.top = (root_y - offsety + impl->shadow.top - _gdk_offset_y) * impl->surface_scale;
3594 placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
3595
3596 if (left_half)
3597 {
3598 placement.rcNormalPosition.left = (root_x - offsetx + impl->shadow.left - _gdk_offset_x) * impl->surface_scale;
3599 placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
3600 }
3601 else
3602 {
3603 placement.rcNormalPosition.right = (root_x + offsetx + impl->shadow.right - _gdk_offset_x) * impl->surface_scale;
3604 placement.rcNormalPosition.left = placement.rcNormalPosition.right - unmax_width;
3605 }
3606 }
3607 else
3608 {
3609 placement.rcNormalPosition.left = (root_x * impl->surface_scale) -
3610 (unmax_width / 2) -
3611 (_gdk_offset_x * impl->surface_scale);
3612
3613 if (offsety * impl->surface_scale < shadow_unmax_height / 2)
3614 placement.rcNormalPosition.top = (root_y - offsety + impl->shadow.top - _gdk_offset_y) * impl->surface_scale;
3615 else
3616 placement.rcNormalPosition.top = (root_y * impl->surface_scale) -
3617 (unmax_height / 2) -
3618 (_gdk_offset_y * impl->surface_scale);
3619
3620 placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
3621 placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
3622 }
3623
3624 GDK_NOTE (MISC, g_print ("Unmaximized window will be at %ld : %ld\n",
3625 placement.rcNormalPosition.left + _gdk_offset_x * impl->surface_scale,
3626 placement.rcNormalPosition.top + _gdk_offset_y * impl->surface_scale));
3627
3628 API_CALL (SetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
3629 }
3630 else if (!pointer_outside_of_window && impl->snap_stash_int)
3631 {
3632 GdkRectangle new_pos;
3633 GdkRectangle snew_pos;
3634
3635 new_pos.width = impl->snap_stash_int->width;
3636 new_pos.height = impl->snap_stash_int->height;
3637 snew_pos = new_pos;
3638
3639 if (op == GDK_WIN32_DRAGOP_MOVE)
3640 {
3641 snew_pos.width -= impl->shadow_x;
3642 snew_pos.height -= impl->shadow_y;
3643 }
3644
3645 if (offsetx < snew_pos.width / 2 && offsety < snew_pos.height / 2)
3646 {
3647 new_pos.y = root_y - offsety + impl->shadow.top / impl->surface_scale;
3648
3649 if (left_half)
3650 new_pos.x = root_x - offsetx + impl->shadow.left / impl->surface_scale;
3651 else
3652 new_pos.x = root_x + offsetx + impl->shadow.left / impl->surface_scale - new_pos.width;
3653 }
3654 else
3655 {
3656 new_pos.x = root_x - new_pos.width / 2;
3657 new_pos.y = root_y - new_pos.height / 2;
3658 }
3659
3660 GDK_NOTE (MISC, g_print ("Unsnapped window to %d : %d\n",
3661 new_pos.x, new_pos.y));
3662 discard_snapinfo (window);
3663 gdk_win32_surface_move_resize (window, new_pos.x, new_pos.y,
3664 new_pos.width, new_pos.height);
3665 }
3666
3667
3668 if (maximized)
3669 gdk_win32_surface_unmaximize (window);
3670 else
3671 unsnap (window, monitor);
3672
3673 if (pointer_outside_of_window)
3674 {
3675 /* Pointer outside of the window, move pointer into window */
3676 GDK_NOTE (MISC, g_print ("Pointer at %d : %d is outside of %d x %d @ %d : %d, move it to %d : %d\n",
3677 root_x, root_y, wwidth, wheight, wx, wy, wx + wwidth / 2, wy + wheight / 2));
3678 root_x = wx + wwidth / 2;
3679 /* This is Gnome behaviour. Windows WM would put the pointer
3680 * in the middle of the titlebar, but GDK doesn't know where
3681 * the titlebar is, if any.
3682 */
3683 root_y = wy + wheight / 2;
3684 SetCursorPos (root_x - _gdk_offset_x, root_y - _gdk_offset_y);
3685 }
3686 }
3687
3688 _gdk_win32_get_window_rect (window, &rect);
3689
3690 cursor_name = get_cursor_name_from_op (op, edge);
3691
3692 context->cursor = gdk_cursor_new_from_name (cursor_name, NULL);
3693
3694 pointer_window = window;
3695
3696 /* Note: This triggers a WM_CAPTURECHANGED, which will trigger
3697 * gdk_win32_surface_end_move_resize_drag(), which will end
3698 * our op before it even begins, but only if context->op is not NONE.
3699 * This is why we first do the grab, *then* set the op.
3700 */
3701 gdk_device_grab (device, pointer_window,
3702 FALSE,
3703 GDK_ALL_EVENTS_MASK,
3704 context->cursor,
3705 timestamp);
3706
3707 context->window = g_object_ref (window);
3708 context->op = op;
3709 context->edge = edge;
3710 context->device = device;
3711 context->button = button;
3712 context->start_root_x = root_x;
3713 context->start_root_y = root_y;
3714 context->timestamp = timestamp;
3715 context->start_rect = rect;
3716
3717 context->shape_indicator = NULL;
3718 context->revealed = FALSE;
3719 context->halfleft_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
3720 context->halfright_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
3721 context->maximize_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
3722 context->fullup_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
3723
3724 calculate_aerosnap_regions (context);
3725
3726 GDK_NOTE (EVENTS,
3727 g_print ("begin drag moveresize: window %p, toplevel %p, "
3728 "op %u, edge %d, device %p, "
3729 "button %d, coord %d:%d, time %u\n",
3730 pointer_window, window,
3731 context->op, context->edge, context->device,
3732 context->button, context->start_root_x,
3733 context->start_root_y, context->timestamp));
3734 }
3735
3736 void
gdk_win32_surface_end_move_resize_drag(GdkSurface * window)3737 gdk_win32_surface_end_move_resize_drag (GdkSurface *window)
3738 {
3739 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
3740 GdkW32DragMoveResizeContext *context = &impl->drag_move_resize_context;
3741
3742 if (context->op == GDK_WIN32_DRAGOP_RESIZE)
3743 _gdk_win32_surface_invalidate_egl_framebuffer (window);
3744
3745 context->op = GDK_WIN32_DRAGOP_NONE;
3746
3747 gdk_device_ungrab (context->device, GDK_CURRENT_TIME);
3748
3749 g_clear_object (&context->cursor);
3750
3751 context->revealed = FALSE;
3752
3753 if (context->timer)
3754 {
3755 g_source_remove (context->timer);
3756 context->timer = 0;
3757 }
3758
3759 g_clear_object (&context->window);
3760
3761 if (context->indicator_surface)
3762 {
3763 cairo_surface_destroy (context->indicator_surface);
3764 context->indicator_surface = NULL;
3765 }
3766
3767 if (context->shape_indicator)
3768 {
3769 stop_indicator (window, context);
3770 DestroyWindow (context->shape_indicator);
3771 context->shape_indicator = NULL;
3772 }
3773
3774 g_clear_pointer (&context->halfleft_regions, g_array_unref);
3775 g_clear_pointer (&context->halfright_regions, g_array_unref);
3776 g_clear_pointer (&context->maximize_regions, g_array_unref);
3777 g_clear_pointer (&context->fullup_regions, g_array_unref);
3778
3779 GDK_NOTE (EVENTS,
3780 g_print ("end drag moveresize: window %p, toplevel %p,"
3781 "op %u, edge %d, device %p, "
3782 "button %d, coord %d:%d, time %u\n",
3783 window, window,
3784 context->op, context->edge, context->device,
3785 context->button, context->start_root_x,
3786 context->start_root_y, context->timestamp));
3787
3788 if (context->current_snap != GDK_WIN32_AEROSNAP_STATE_UNDETERMINED)
3789 apply_snap (window, context->current_snap);
3790
3791 context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
3792 }
3793
3794 static void
gdk_win32_get_window_size_and_position_from_client_rect(GdkSurface * window,RECT * window_rect,SIZE * window_size,POINT * window_position)3795 gdk_win32_get_window_size_and_position_from_client_rect (GdkSurface *window,
3796 RECT *window_rect,
3797 SIZE *window_size,
3798 POINT *window_position)
3799 {
3800 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
3801
3802 /* Turn client area into window area */
3803 _gdk_win32_adjust_client_rect (window, window_rect);
3804
3805 /* Convert GDK screen coordinates to W32 desktop coordinates */
3806 window_rect->left -= _gdk_offset_x * impl->surface_scale;
3807 window_rect->right -= _gdk_offset_x * impl->surface_scale;
3808 window_rect->top -= _gdk_offset_y * impl->surface_scale;
3809 window_rect->bottom -= _gdk_offset_y * impl->surface_scale;
3810
3811 window_position->x = window_rect->left;
3812 window_position->y = window_rect->top;
3813 window_size->cx = window_rect->right - window_rect->left;
3814 window_size->cy = window_rect->bottom - window_rect->top;
3815 }
3816
3817 void
gdk_win32_surface_do_move_resize_drag(GdkSurface * window,int x,int y)3818 gdk_win32_surface_do_move_resize_drag (GdkSurface *window,
3819 int x,
3820 int y)
3821 {
3822 RECT rect;
3823 RECT new_rect;
3824 int diffy, diffx;
3825 MINMAXINFO mmi;
3826 GdkWin32Surface *impl;
3827 GdkW32DragMoveResizeContext *context;
3828 int width;
3829 int height;
3830
3831 impl = GDK_WIN32_SURFACE (window);
3832 context = &impl->drag_move_resize_context;
3833
3834 if (!_gdk_win32_get_window_rect (window, &rect))
3835 return;
3836
3837 new_rect = context->start_rect;
3838 diffx = (x - context->start_root_x) * impl->surface_scale;
3839 diffy = (y - context->start_root_y) * impl->surface_scale;
3840
3841 switch (context->op)
3842 {
3843 case GDK_WIN32_DRAGOP_RESIZE:
3844
3845 switch (context->edge)
3846 {
3847 case GDK_SURFACE_EDGE_NORTH_WEST:
3848 new_rect.left += diffx;
3849 new_rect.top += diffy;
3850 break;
3851
3852 case GDK_SURFACE_EDGE_NORTH:
3853 new_rect.top += diffy;
3854 break;
3855
3856 case GDK_SURFACE_EDGE_NORTH_EAST:
3857 new_rect.right += diffx;
3858 new_rect.top += diffy;
3859 break;
3860
3861 case GDK_SURFACE_EDGE_WEST:
3862 new_rect.left += diffx;
3863 break;
3864
3865 case GDK_SURFACE_EDGE_EAST:
3866 new_rect.right += diffx;
3867 break;
3868
3869 case GDK_SURFACE_EDGE_SOUTH_WEST:
3870 new_rect.left += diffx;
3871 new_rect.bottom += diffy;
3872 break;
3873
3874 case GDK_SURFACE_EDGE_SOUTH:
3875 new_rect.bottom += diffy;
3876 break;
3877
3878 case GDK_SURFACE_EDGE_SOUTH_EAST:
3879 default:
3880 new_rect.right += diffx;
3881 new_rect.bottom += diffy;
3882 break;
3883 }
3884
3885 /* When handling WM_GETMINMAXINFO, mmi is already populated
3886 * by W32 WM and we apply our stuff on top of that.
3887 * Here it isn't, so we should at least clear it.
3888 */
3889 memset (&mmi, 0, sizeof (mmi));
3890
3891 if (!_gdk_win32_surface_fill_min_max_info (window, &mmi))
3892 break;
3893
3894 width = new_rect.right - new_rect.left;
3895 height = new_rect.bottom - new_rect.top;
3896
3897 if (width > mmi.ptMaxTrackSize.x)
3898 {
3899 switch (context->edge)
3900 {
3901 case GDK_SURFACE_EDGE_NORTH_WEST:
3902 case GDK_SURFACE_EDGE_WEST:
3903 case GDK_SURFACE_EDGE_SOUTH_WEST:
3904 new_rect.left = new_rect.right - mmi.ptMaxTrackSize.x;
3905 break;
3906
3907 case GDK_SURFACE_EDGE_NORTH_EAST:
3908 case GDK_SURFACE_EDGE_EAST:
3909 case GDK_SURFACE_EDGE_SOUTH_EAST:
3910 default:
3911 new_rect.right = new_rect.left + mmi.ptMaxTrackSize.x;
3912 break;
3913 }
3914 }
3915 else if (width < mmi.ptMinTrackSize.x)
3916 {
3917 switch (context->edge)
3918 {
3919 case GDK_SURFACE_EDGE_NORTH_WEST:
3920 case GDK_SURFACE_EDGE_WEST:
3921 case GDK_SURFACE_EDGE_SOUTH_WEST:
3922 new_rect.left = new_rect.right - mmi.ptMinTrackSize.x;
3923 break;
3924
3925 case GDK_SURFACE_EDGE_NORTH_EAST:
3926 case GDK_SURFACE_EDGE_EAST:
3927 case GDK_SURFACE_EDGE_SOUTH_EAST:
3928 default:
3929 new_rect.right = new_rect.left + mmi.ptMinTrackSize.x;
3930 break;
3931 }
3932 }
3933
3934 if (height > mmi.ptMaxTrackSize.y)
3935 {
3936 switch (context->edge)
3937 {
3938 case GDK_SURFACE_EDGE_NORTH_WEST:
3939 case GDK_SURFACE_EDGE_NORTH:
3940 case GDK_SURFACE_EDGE_NORTH_EAST:
3941 new_rect.top = new_rect.bottom - mmi.ptMaxTrackSize.y;
3942
3943 case GDK_SURFACE_EDGE_SOUTH_WEST:
3944 case GDK_SURFACE_EDGE_SOUTH:
3945 case GDK_SURFACE_EDGE_SOUTH_EAST:
3946 default:
3947 new_rect.bottom = new_rect.top + mmi.ptMaxTrackSize.y;
3948 break;
3949 }
3950 }
3951 else if (height < mmi.ptMinTrackSize.y)
3952 {
3953 switch (context->edge)
3954 {
3955 case GDK_SURFACE_EDGE_NORTH_WEST:
3956 case GDK_SURFACE_EDGE_NORTH:
3957 case GDK_SURFACE_EDGE_NORTH_EAST:
3958 new_rect.top = new_rect.bottom - mmi.ptMinTrackSize.y;
3959
3960 case GDK_SURFACE_EDGE_SOUTH_WEST:
3961 case GDK_SURFACE_EDGE_SOUTH:
3962 case GDK_SURFACE_EDGE_SOUTH_EAST:
3963 default:
3964 new_rect.bottom = new_rect.top + mmi.ptMinTrackSize.y;
3965 break;
3966 }
3967 }
3968
3969 break;
3970 case GDK_WIN32_DRAGOP_MOVE:
3971 new_rect.left += diffx;
3972 new_rect.top += diffy;
3973 new_rect.right += diffx;
3974 new_rect.bottom += diffy;
3975 break;
3976 default:
3977 break;
3978 }
3979
3980 if (context->op == GDK_WIN32_DRAGOP_RESIZE &&
3981 (rect.left != new_rect.left ||
3982 rect.right != new_rect.right ||
3983 rect.top != new_rect.top ||
3984 rect.bottom != new_rect.bottom))
3985 {
3986 if (GDK_IS_TOPLEVEL (window))
3987 {
3988 int scale = impl->surface_scale;
3989
3990 impl->next_layout.configured_rect = new_rect;
3991 impl->next_layout.configured_width = (new_rect.right - new_rect.left + scale - 1) / scale;
3992 impl->next_layout.configured_height = (new_rect.bottom - new_rect.top + scale - 1) / scale;
3993 }
3994
3995 context->native_move_resize_pending = TRUE;
3996 }
3997 else if (context->op == GDK_WIN32_DRAGOP_MOVE &&
3998 (rect.left != new_rect.left ||
3999 rect.top != new_rect.top))
4000 {
4001 SIZE window_size;
4002 POINT window_position;
4003
4004 context->native_move_resize_pending = FALSE;
4005
4006 gdk_surface_request_layout (window);
4007
4008 gdk_win32_get_window_size_and_position_from_client_rect (window,
4009 &new_rect,
4010 &window_size,
4011 &window_position);
4012
4013 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
4014 SWP_NOZORDER_SPECIFIED,
4015 window_position.x, window_position.y,
4016 0, 0,
4017 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE));
4018 }
4019
4020 if (context->op == GDK_WIN32_DRAGOP_RESIZE ||
4021 context->op == GDK_WIN32_DRAGOP_MOVE)
4022 handle_aerosnap_move_resize (window, context, x, y);
4023
4024 gdk_surface_request_layout (window);
4025 }
4026
4027 static void
gdk_win32_toplevel_begin_resize(GdkToplevel * toplevel,GdkSurfaceEdge edge,GdkDevice * device,int button,double x,double y,guint32 timestamp)4028 gdk_win32_toplevel_begin_resize (GdkToplevel *toplevel,
4029 GdkSurfaceEdge edge,
4030 GdkDevice *device,
4031 int button,
4032 double x,
4033 double y,
4034 guint32 timestamp)
4035 {
4036 GdkSurface *window = GDK_SURFACE (toplevel);
4037 GdkWin32Surface *impl;
4038
4039 if (GDK_SURFACE_DESTROYED (window) ||
4040 IsIconic (GDK_SURFACE_HWND (window)))
4041 return;
4042
4043 /* Tell Windows to start interactively resizing the window by pretending that
4044 * the left pointer button was clicked in the suitable edge or corner. This
4045 * will only work if the button is down when this function is called, and
4046 * will only work with button 1 (left), since Windows only allows window
4047 * dragging using the left mouse button.
4048 */
4049
4050 if (button != 1)
4051 return;
4052
4053 impl = GDK_WIN32_SURFACE (window);
4054
4055 if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
4056 gdk_win32_surface_end_move_resize_drag (window);
4057
4058 setup_drag_move_resize_context (window, &impl->drag_move_resize_context,
4059 GDK_WIN32_DRAGOP_RESIZE, edge, device,
4060 button, x, y, timestamp);
4061 }
4062
4063 static void
gdk_win32_toplevel_begin_move(GdkToplevel * toplevel,GdkDevice * device,int button,double x,double y,guint32 timestamp)4064 gdk_win32_toplevel_begin_move (GdkToplevel *toplevel,
4065 GdkDevice *device,
4066 int button,
4067 double x,
4068 double y,
4069 guint32 timestamp)
4070 {
4071 GdkSurface *window = GDK_SURFACE (toplevel);
4072 GdkWin32Surface *impl;
4073
4074 if (GDK_SURFACE_DESTROYED (window) ||
4075 IsIconic (GDK_SURFACE_HWND (window)))
4076 return;
4077
4078 /* Tell Windows to start interactively moving the window by pretending that
4079 * the left pointer button was clicked in the titlebar. This will only work
4080 * if the button is down when this function is called, and will only work
4081 * with button 1 (left), since Windows only allows window dragging using the
4082 * left mouse button.
4083 */
4084 if (button != 1)
4085 return;
4086
4087 impl = GDK_WIN32_SURFACE (window);
4088
4089 if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
4090 gdk_win32_surface_end_move_resize_drag (window);
4091
4092 setup_drag_move_resize_context (window, &impl->drag_move_resize_context,
4093 GDK_WIN32_DRAGOP_MOVE, GDK_SURFACE_EDGE_NORTH_WEST,
4094 device, button, x, y, timestamp);
4095 }
4096
4097
4098 /*
4099 * Setting window states
4100 */
4101 static void
gdk_win32_surface_minimize(GdkSurface * window)4102 gdk_win32_surface_minimize (GdkSurface *window)
4103 {
4104 HWND old_active_window;
4105
4106 g_return_if_fail (GDK_IS_SURFACE (window));
4107
4108 if (GDK_SURFACE_DESTROYED (window))
4109 return;
4110
4111 GDK_NOTE (MISC, g_print ("gdk_surface_minimize: %p: %s\n",
4112 GDK_SURFACE_HWND (window),
4113 _gdk_win32_surface_state_to_string (window->state)));
4114
4115 if (GDK_SURFACE_IS_MAPPED (window))
4116 {
4117 old_active_window = GetActiveWindow ();
4118 GtkShowWindow (window, SW_MINIMIZE);
4119 if (old_active_window != GDK_SURFACE_HWND (window))
4120 SetActiveWindow (old_active_window);
4121 }
4122 else
4123 {
4124 gdk_synthesize_surface_state (window,
4125 0,
4126 GDK_TOPLEVEL_STATE_MINIMIZED);
4127 }
4128 }
4129
4130 static void
gdk_win32_surface_maximize(GdkSurface * window)4131 gdk_win32_surface_maximize (GdkSurface *window)
4132 {
4133 GdkWin32Surface *impl;
4134
4135 g_return_if_fail (GDK_IS_SURFACE (window));
4136
4137 if (GDK_SURFACE_DESTROYED (window))
4138 return;
4139
4140 GDK_NOTE (MISC, g_print ("gdk_surface_maximize: %p: %s\n",
4141 GDK_SURFACE_HWND (window),
4142 _gdk_win32_surface_state_to_string (window->state)));
4143
4144 impl = GDK_WIN32_SURFACE (window);
4145
4146 if (GDK_SURFACE_IS_MAPPED (window))
4147 GtkShowWindow (window, SW_MAXIMIZE);
4148 else
4149 gdk_synthesize_surface_state (window,
4150 0,
4151 GDK_TOPLEVEL_STATE_MAXIMIZED);
4152 }
4153
4154 static void
gdk_win32_surface_unmaximize(GdkSurface * window)4155 gdk_win32_surface_unmaximize (GdkSurface *window)
4156 {
4157 g_return_if_fail (GDK_IS_SURFACE (window));
4158
4159 if (GDK_SURFACE_DESTROYED (window))
4160 return;
4161
4162 GDK_NOTE (MISC, g_print ("gdk_surface_unmaximize: %p: %s\n",
4163 GDK_SURFACE_HWND (window),
4164 _gdk_win32_surface_state_to_string (window->state)));
4165
4166 _gdk_win32_surface_invalidate_egl_framebuffer (window);
4167
4168 if (GDK_SURFACE_IS_MAPPED (window))
4169 GtkShowWindow (window, SW_RESTORE);
4170 else
4171 gdk_synthesize_surface_state (window,
4172 GDK_TOPLEVEL_STATE_MAXIMIZED,
4173 0);
4174 }
4175
4176 static void
gdk_win32_surface_fullscreen(GdkSurface * window)4177 gdk_win32_surface_fullscreen (GdkSurface *window)
4178 {
4179 int x, y, width, height;
4180 FullscreenInfo *fi;
4181 HMONITOR monitor;
4182 MONITORINFO mi;
4183
4184 g_return_if_fail (GDK_IS_SURFACE (window));
4185
4186 fi = g_new (FullscreenInfo, 1);
4187
4188 if (!GetWindowRect (GDK_SURFACE_HWND (window), &(fi->r)))
4189 g_free (fi);
4190 else
4191 {
4192 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
4193
4194 monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
4195 mi.cbSize = sizeof (mi);
4196 if (monitor && GetMonitorInfo (monitor, &mi))
4197 {
4198 x = mi.rcMonitor.left;
4199 y = mi.rcMonitor.top;
4200 width = mi.rcMonitor.right - x;
4201 height = mi.rcMonitor.bottom - y;
4202 }
4203 else
4204 {
4205 x = y = 0;
4206 width = GetSystemMetrics (SM_CXSCREEN);
4207 height = GetSystemMetrics (SM_CYSCREEN);
4208 }
4209
4210 /* remember for restoring */
4211 fi->hint_flags = impl->hint_flags;
4212 impl->hint_flags &= ~GDK_HINT_MAX_SIZE;
4213 g_object_set_data (G_OBJECT (window), "fullscreen-info", fi);
4214 fi->style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
4215
4216 /* Send state change before configure event */
4217 gdk_synthesize_surface_state (window, 0, GDK_TOPLEVEL_STATE_FULLSCREEN);
4218
4219 SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE,
4220 (fi->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
4221
4222 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
4223 x, y, width, height,
4224 SWP_NOCOPYBITS | SWP_SHOWWINDOW));
4225 }
4226 }
4227
4228 static void
gdk_win32_surface_unfullscreen(GdkSurface * window)4229 gdk_win32_surface_unfullscreen (GdkSurface *window)
4230 {
4231 FullscreenInfo *fi;
4232
4233 g_return_if_fail (GDK_IS_SURFACE (window));
4234
4235 fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
4236 if (fi)
4237 {
4238 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
4239
4240 gdk_synthesize_surface_state (window, GDK_TOPLEVEL_STATE_FULLSCREEN, 0);
4241
4242 impl->hint_flags = fi->hint_flags;
4243 SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE, fi->style);
4244 _gdk_win32_surface_invalidate_egl_framebuffer (window);
4245 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_NOTOPMOST,
4246 fi->r.left, fi->r.top,
4247 fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
4248 SWP_NOCOPYBITS | SWP_SHOWWINDOW));
4249
4250 g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
4251 g_free (fi);
4252 _gdk_win32_surface_update_style_bits (window);
4253 }
4254 }
4255
4256 static void
gdk_win32_surface_focus(GdkSurface * window,guint32 timestamp)4257 gdk_win32_surface_focus (GdkSurface *window,
4258 guint32 timestamp)
4259 {
4260 g_return_if_fail (GDK_IS_SURFACE (window));
4261
4262 if (GDK_SURFACE_DESTROYED (window))
4263 return;
4264
4265 GDK_NOTE (MISC, g_print ("gdk_surface_focus: %p: %s\n",
4266 GDK_SURFACE_HWND (window),
4267 _gdk_win32_surface_state_to_string (window->state)));
4268
4269 if (window->state & GDK_TOPLEVEL_STATE_MAXIMIZED)
4270 GtkShowWindow (window, SW_SHOWMAXIMIZED);
4271 else if (window->state & GDK_TOPLEVEL_STATE_MINIMIZED)
4272 GtkShowWindow (window, SW_RESTORE);
4273 else if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
4274 GtkShowWindow (window, SW_SHOWNORMAL);
4275 else
4276 GtkShowWindow (window, SW_SHOW);
4277
4278 SetFocus (GDK_SURFACE_HWND (window));
4279 }
4280
4281 GdkSurface *
gdk_win32_surface_lookup_for_display(GdkDisplay * display,HWND anid)4282 gdk_win32_surface_lookup_for_display (GdkDisplay *display,
4283 HWND anid)
4284 {
4285 g_return_val_if_fail (display == gdk_display_get_default (), NULL);
4286
4287 return (GdkSurface*) gdk_win32_handle_table_lookup (anid);
4288 }
4289
4290 gboolean
gdk_win32_surface_is_win32(GdkSurface * window)4291 gdk_win32_surface_is_win32 (GdkSurface *window)
4292 {
4293 return GDK_IS_WIN32_SURFACE (window);
4294 }
4295
4296 static gboolean
gdk_win32_surface_show_window_menu(GdkSurface * surface,GdkEvent * event)4297 gdk_win32_surface_show_window_menu (GdkSurface *surface,
4298 GdkEvent *event)
4299 {
4300 double event_x, event_y;
4301 int x, y;
4302 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
4303 GdkEventType event_type = gdk_event_get_event_type (event);
4304
4305 switch ((int) event_type)
4306 {
4307 case GDK_BUTTON_PRESS:
4308 case GDK_BUTTON_RELEASE:
4309 case GDK_TOUCH_BEGIN:
4310 case GDK_TOUCH_END:
4311 break;
4312 default:
4313 return FALSE;
4314 }
4315
4316 gdk_event_get_position (event, &event_x, &event_y);
4317 gdk_win32_surface_get_root_coords (surface, event_x, event_y, &x, &y);
4318
4319 SendMessage (GDK_SURFACE_HWND (surface),
4320 WM_SYSMENU,
4321 0,
4322 MAKELPARAM (x * impl->surface_scale, y * impl->surface_scale));
4323
4324 return TRUE;
4325 }
4326
4327 HWND
gdk_win32_surface_get_impl_hwnd(GdkSurface * window)4328 gdk_win32_surface_get_impl_hwnd (GdkSurface *window)
4329 {
4330 if (GDK_IS_WIN32_SURFACE (window))
4331 return GDK_SURFACE_HWND (window);
4332 return NULL;
4333 }
4334
4335 BOOL WINAPI
GtkShowWindow(GdkSurface * window,int cmd_show)4336 GtkShowWindow (GdkSurface *window,
4337 int cmd_show)
4338 {
4339 cairo_t *cr;
4340 cairo_surface_t *surface;
4341 RECT window_rect;
4342 HDC hdc;
4343 POINT window_position;
4344 SIZE window_size;
4345 POINT source_point;
4346 BLENDFUNCTION blender;
4347
4348 HWND hwnd = GDK_SURFACE_HWND (window);
4349 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
4350
4351 switch (cmd_show)
4352 {
4353 case SW_FORCEMINIMIZE:
4354 case SW_HIDE:
4355 case SW_MINIMIZE:
4356 break;
4357 case SW_MAXIMIZE:
4358 case SW_RESTORE:
4359 case SW_SHOW:
4360 case SW_SHOWDEFAULT:
4361 case SW_SHOWMINIMIZED:
4362 case SW_SHOWMINNOACTIVE:
4363 case SW_SHOWNA:
4364 case SW_SHOWNOACTIVATE:
4365 case SW_SHOWNORMAL:
4366 if (IsWindowVisible (hwnd))
4367 break;
4368
4369 /* Window was hidden, will be shown. Erase it, GDK will repaint soon,
4370 * but not soon enough, so it's possible to see old content before
4371 * the next redraw, unless we erase the window first.
4372 */
4373 GetWindowRect (hwnd, &window_rect);
4374 source_point.x = source_point.y = 0;
4375
4376 window_position.x = window_rect.left;
4377 window_position.y = window_rect.top;
4378 window_size.cx = window_rect.right - window_rect.left;
4379 window_size.cy = window_rect.bottom - window_rect.top;
4380
4381 blender.BlendOp = AC_SRC_OVER;
4382 blender.BlendFlags = 0;
4383 blender.AlphaFormat = AC_SRC_ALPHA;
4384 blender.SourceConstantAlpha = 255;
4385
4386 /* Create a surface of appropriate size and clear it */
4387 surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
4388 window_size.cx,
4389 window_size.cy);
4390 cairo_surface_set_device_scale (surface, impl->surface_scale, impl->surface_scale);
4391 cr = cairo_create (surface);
4392 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
4393 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
4394 cairo_paint (cr);
4395 cairo_destroy (cr);
4396 cairo_surface_flush (surface);
4397 hdc = cairo_win32_surface_get_dc (surface);
4398
4399 /* No API_CALL() wrapper, don't check for errors */
4400 UpdateLayeredWindow (hwnd, NULL,
4401 &window_position, &window_size,
4402 hdc, &source_point,
4403 0, &blender, ULW_ALPHA);
4404
4405 cairo_surface_destroy (surface);
4406
4407 break;
4408 }
4409
4410 /* Ensure that maximized window size is corrected later on */
4411 if (cmd_show == SW_MAXIMIZE)
4412 impl->maximizing = TRUE;
4413
4414 return ShowWindow (hwnd, cmd_show);
4415 }
4416
4417 static void
gdk_win32_surface_set_shadow_width(GdkSurface * window,int left,int right,int top,int bottom)4418 gdk_win32_surface_set_shadow_width (GdkSurface *window,
4419 int left,
4420 int right,
4421 int top,
4422 int bottom)
4423 {
4424 GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
4425
4426 if (GDK_SURFACE_DESTROYED (window))
4427 return;
4428
4429 GDK_NOTE (MISC, g_print ("gdk_win32_surface_set_shadow_width: window %p, "
4430 "left %d, top %d, right %d, bottom %d\n",
4431 window, left, top, right, bottom));
4432
4433 impl->zero_shadow = left == 0 && right == 0 && top == 0 && bottom == 0;
4434
4435 if (impl->zero_shadow)
4436 return;
4437
4438 impl->shadow.left = left * impl->surface_scale;;
4439 impl->shadow.right = right * impl->surface_scale;
4440 impl->shadow.top = top * impl->surface_scale;;
4441 impl->shadow.bottom = bottom * impl->surface_scale;
4442 impl->shadow_x = left + right;
4443 impl->shadow_y = top + bottom;
4444 }
4445
4446
4447 int
_gdk_win32_surface_get_scale_factor(GdkSurface * surface)4448 _gdk_win32_surface_get_scale_factor (GdkSurface *surface)
4449 {
4450 GdkDisplay *display;
4451 GdkWin32Surface *impl;
4452 GdkWin32Display *win32_display;
4453
4454 if (GDK_SURFACE_DESTROYED (surface))
4455 return 1;
4456
4457 g_return_val_if_fail (surface != NULL, 1);
4458
4459 display = gdk_surface_get_display (surface);
4460 impl = GDK_WIN32_SURFACE (surface);
4461
4462 win32_display = GDK_WIN32_DISPLAY (display);
4463
4464 if (win32_display->dpi_aware_type != PROCESS_DPI_UNAWARE)
4465 {
4466 if (win32_display->has_fixed_scale)
4467 impl->surface_scale = win32_display->surface_scale;
4468 else
4469 impl->surface_scale = gdk_win32_display_get_monitor_scale_factor (win32_display,
4470 surface,
4471 NULL);
4472
4473 return impl->surface_scale;
4474 }
4475 else
4476 {
4477 if (win32_display->has_fixed_scale)
4478 {
4479 static gsize hidpi_msg_displayed = 0;
4480
4481 if (g_once_init_enter (&hidpi_msg_displayed))
4482 {
4483 g_message ("Note: GDK_SCALE is ignored as HiDPI awareness is disabled.");
4484 g_once_init_leave (&hidpi_msg_displayed, 1);
4485 }
4486 }
4487
4488 /* Application is not DPI aware, don't bother */
4489 return 1;
4490 }
4491 }
4492
4493 static void
gdk_win32_surface_set_input_region(GdkSurface * window,cairo_region_t * input_region)4494 gdk_win32_surface_set_input_region (GdkSurface *window,
4495 cairo_region_t *input_region)
4496 {
4497 /* Partial input shape support is implemented by handling the
4498 * NC_NCHITTEST message
4499 */
4500 }
4501
4502 static void
compute_toplevel_size(GdkSurface * surface,gboolean update_geometry,int * width,int * height)4503 compute_toplevel_size (GdkSurface *surface,
4504 gboolean update_geometry,
4505 int *width,
4506 int *height)
4507 {
4508 GdkDisplay *display = gdk_surface_get_display (surface);
4509 GdkMonitor *monitor;
4510 GdkToplevelSize size;
4511 int bounds_width, bounds_height;
4512 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
4513
4514 monitor = gdk_display_get_monitor_at_surface (display, surface);
4515 if (monitor)
4516 {
4517 GdkRectangle workarea;
4518
4519 gdk_win32_monitor_get_workarea (monitor, &workarea);
4520 bounds_width = workarea.width;
4521 bounds_height = workarea.height;
4522 }
4523 else
4524 {
4525 bounds_width = G_MAXINT;
4526 bounds_height = G_MAXINT;
4527 }
4528
4529 gdk_toplevel_size_init (&size, bounds_width, bounds_height);
4530 gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size);
4531 g_warn_if_fail (size.width > 0);
4532 g_warn_if_fail (size.height > 0);
4533 *width = size.width;
4534 *height = size.height;
4535
4536 if (size.shadow.is_valid)
4537 {
4538 gdk_win32_surface_set_shadow_width (surface,
4539 size.shadow.left,
4540 size.shadow.right,
4541 size.shadow.top,
4542 size.shadow.bottom);
4543 }
4544
4545 if (update_geometry)
4546 {
4547 GdkGeometry geometry;
4548 GdkSurfaceHints mask;
4549 GdkToplevelLayout *layout = impl->toplevel_layout;
4550
4551 if (gdk_toplevel_layout_get_resizable (layout))
4552 {
4553 geometry.min_width = size.min_width;
4554 geometry.min_height = size.min_height;
4555 mask = GDK_HINT_MIN_SIZE;
4556 }
4557 else
4558 {
4559 geometry.max_width = geometry.min_width = *width;
4560 geometry.max_height = geometry.min_height = *height;
4561 mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
4562 }
4563 gdk_win32_surface_set_geometry_hints (surface, &geometry, mask);
4564 gdk_surface_constrain_size (&geometry, mask, *width, *height, width, height);
4565 }
4566 }
4567
4568 static void
_gdk_win32_surface_request_layout(GdkSurface * surface)4569 _gdk_win32_surface_request_layout (GdkSurface *surface)
4570 {
4571 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
4572 int scale = impl->surface_scale;
4573 RECT rect;
4574
4575 if (impl->drag_move_resize_context.native_move_resize_pending)
4576 {
4577 surface->width = impl->next_layout.configured_width;
4578 surface->height = impl->next_layout.configured_height;
4579 }
4580 else
4581 {
4582 _gdk_win32_get_window_rect (surface, &rect);
4583
4584 impl->next_layout.configured_width = (rect.right - rect.left + scale - 1) / scale;
4585 impl->next_layout.configured_height = (rect.bottom - rect.top + scale - 1) / scale;
4586
4587 if (GDK_IS_TOPLEVEL (surface))
4588 {
4589 surface->x = rect.left / scale;
4590 surface->y = rect.top / scale;
4591 }
4592 else if (GDK_IS_POPUP (surface))
4593 {
4594 gdk_win32_surface_get_geometry (surface,
4595 &surface->x, &surface->y,
4596 NULL, NULL);
4597 }
4598 }
4599 }
4600
4601 static gboolean
_gdk_win32_surface_compute_size(GdkSurface * surface)4602 _gdk_win32_surface_compute_size (GdkSurface *surface)
4603 {
4604 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
4605 int width, height;
4606
4607 if (GDK_IS_TOPLEVEL (surface))
4608 compute_toplevel_size (surface, TRUE, &width, &height);
4609
4610 if (!impl->drag_move_resize_context.native_move_resize_pending)
4611 {
4612 surface->width = impl->next_layout.configured_width;
4613 surface->height = impl->next_layout.configured_height;
4614
4615 _gdk_surface_update_size (surface);
4616 }
4617
4618 return FALSE;
4619 }
4620
4621 static void
gdk_win32_surface_class_init(GdkWin32SurfaceClass * klass)4622 gdk_win32_surface_class_init (GdkWin32SurfaceClass *klass)
4623 {
4624 GObjectClass *object_class = G_OBJECT_CLASS (klass);
4625 GdkSurfaceClass *impl_class = GDK_SURFACE_CLASS (klass);
4626
4627 parent_class = g_type_class_peek_parent (klass);
4628
4629 object_class->dispose = gdk_surface_win32_dispose;
4630 object_class->finalize = gdk_surface_win32_finalize;
4631
4632 impl_class->hide = gdk_win32_surface_hide;
4633 impl_class->get_geometry = gdk_win32_surface_get_geometry;
4634 impl_class->get_device_state = gdk_surface_win32_get_device_state;
4635 impl_class->get_root_coords = gdk_win32_surface_get_root_coords;
4636
4637 impl_class->set_input_region = gdk_win32_surface_set_input_region;
4638 impl_class->destroy = gdk_win32_surface_destroy;
4639
4640 //impl_class->beep = gdk_x11_surface_beep;
4641
4642 impl_class->destroy_notify = gdk_win32_surface_destroy_notify;
4643 impl_class->drag_begin = _gdk_win32_surface_drag_begin;
4644 impl_class->get_scale_factor = _gdk_win32_surface_get_scale_factor;
4645 impl_class->request_layout = _gdk_win32_surface_request_layout;
4646 impl_class->compute_size = _gdk_win32_surface_compute_size;
4647 }
4648
4649 HGDIOBJ
gdk_win32_surface_get_handle(GdkSurface * window)4650 gdk_win32_surface_get_handle (GdkSurface *window)
4651 {
4652 if (!GDK_IS_WIN32_SURFACE (window))
4653 {
4654 g_warning (G_STRLOC " window is not a native Win32 window");
4655 return NULL;
4656 }
4657
4658 return GDK_SURFACE_HWND (window);
4659 }
4660
4661 #define LAST_PROP 1
4662
4663 typedef struct
4664 {
4665 GdkWin32Surface parent_instance;
4666 } GdkWin32Popup;
4667
4668 typedef struct
4669 {
4670 GdkWin32SurfaceClass parent_class;
4671 } GdkWin32PopupClass;
4672
4673 static void gdk_win32_popup_iface_init (GdkPopupInterface *iface);
4674
G_DEFINE_TYPE_WITH_CODE(GdkWin32Popup,gdk_win32_popup,GDK_TYPE_WIN32_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,gdk_win32_popup_iface_init))4675 G_DEFINE_TYPE_WITH_CODE (GdkWin32Popup, gdk_win32_popup, GDK_TYPE_WIN32_SURFACE,
4676 G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,
4677 gdk_win32_popup_iface_init))
4678
4679 static void
4680 gdk_win32_popup_init (GdkWin32Popup *popup)
4681 {
4682 }
4683
4684 static void
gdk_win32_popup_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)4685 gdk_win32_popup_get_property (GObject *object,
4686 guint prop_id,
4687 GValue *value,
4688 GParamSpec *pspec)
4689 {
4690 GdkSurface *surface = GDK_SURFACE (object);
4691
4692 switch (prop_id)
4693 {
4694 case LAST_PROP + GDK_POPUP_PROP_PARENT:
4695 g_value_set_object (value, surface->parent);
4696 break;
4697
4698 case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
4699 g_value_set_boolean (value, surface->autohide);
4700 break;
4701
4702 default:
4703 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4704 break;
4705 }
4706 }
4707
4708 static void
gdk_win32_popup_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)4709 gdk_win32_popup_set_property (GObject *object,
4710 guint prop_id,
4711 const GValue *value,
4712 GParamSpec *pspec)
4713 {
4714 GdkSurface *surface = GDK_SURFACE (object);
4715
4716 switch (prop_id)
4717 {
4718 case LAST_PROP + GDK_POPUP_PROP_PARENT:
4719 surface->parent = g_value_dup_object (value);
4720 if (surface->parent != NULL)
4721 surface->parent->children = g_list_prepend (surface->parent->children, surface);
4722 break;
4723
4724 case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
4725 surface->autohide = g_value_get_boolean (value);
4726 break;
4727
4728 default:
4729 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4730 break;
4731 }
4732 }
4733
4734 static void
gdk_win32_popup_class_init(GdkWin32PopupClass * class)4735 gdk_win32_popup_class_init (GdkWin32PopupClass *class)
4736 {
4737 GObjectClass *object_class = G_OBJECT_CLASS (class);
4738
4739 object_class->get_property = gdk_win32_popup_get_property;
4740 object_class->set_property = gdk_win32_popup_set_property;
4741
4742 gdk_popup_install_properties (object_class, 1);
4743 }
4744
4745 static gboolean
gdk_win32_popup_present(GdkPopup * popup,int width,int height,GdkPopupLayout * layout)4746 gdk_win32_popup_present (GdkPopup *popup,
4747 int width,
4748 int height,
4749 GdkPopupLayout *layout)
4750 {
4751 return gdk_win32_surface_present_popup (GDK_SURFACE (popup), width, height, layout);
4752 }
4753
4754 static GdkGravity
gdk_win32_popup_get_surface_anchor(GdkPopup * popup)4755 gdk_win32_popup_get_surface_anchor (GdkPopup *popup)
4756 {
4757 return GDK_SURFACE (popup)->popup.surface_anchor;
4758 }
4759
4760 static GdkGravity
gdk_win32_popup_get_rect_anchor(GdkPopup * popup)4761 gdk_win32_popup_get_rect_anchor (GdkPopup *popup)
4762 {
4763 return GDK_SURFACE (popup)->popup.rect_anchor;
4764 }
4765
4766 static int
gdk_win32_popup_get_position_x(GdkPopup * popup)4767 gdk_win32_popup_get_position_x (GdkPopup *popup)
4768 {
4769 return GDK_SURFACE (popup)->x;
4770 }
4771
4772 static int
gdk_win32_popup_get_position_y(GdkPopup * popup)4773 gdk_win32_popup_get_position_y (GdkPopup *popup)
4774 {
4775 return GDK_SURFACE (popup)->y;
4776 }
4777
4778 static void
gdk_win32_popup_iface_init(GdkPopupInterface * iface)4779 gdk_win32_popup_iface_init (GdkPopupInterface *iface)
4780 {
4781 iface->present = gdk_win32_popup_present;
4782 iface->get_surface_anchor = gdk_win32_popup_get_surface_anchor;
4783 iface->get_rect_anchor = gdk_win32_popup_get_rect_anchor;
4784 iface->get_position_x = gdk_win32_popup_get_position_x;
4785 iface->get_position_y = gdk_win32_popup_get_position_y;
4786 }
4787
4788
4789 typedef struct
4790 {
4791 GdkWin32Surface parent_instance;
4792 } GdkWin32Toplevel;
4793
4794 typedef struct
4795 {
4796 GdkWin32SurfaceClass parent_class;
4797 } GdkWin32ToplevelClass;
4798
4799 static void gdk_win32_toplevel_iface_init (GdkToplevelInterface *iface);
4800
G_DEFINE_TYPE_WITH_CODE(GdkWin32Toplevel,gdk_win32_toplevel,GDK_TYPE_WIN32_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,gdk_win32_toplevel_iface_init))4801 G_DEFINE_TYPE_WITH_CODE (GdkWin32Toplevel, gdk_win32_toplevel, GDK_TYPE_WIN32_SURFACE,
4802 G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,
4803 gdk_win32_toplevel_iface_init))
4804
4805 static void
4806 gdk_win32_toplevel_init (GdkWin32Toplevel *toplevel)
4807 {
4808 }
4809
4810 static void
gdk_win32_toplevel_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)4811 gdk_win32_toplevel_set_property (GObject *object,
4812 guint prop_id,
4813 const GValue *value,
4814 GParamSpec *pspec)
4815 {
4816 GdkSurface *surface = GDK_SURFACE (object);
4817
4818 switch (prop_id)
4819 {
4820 case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
4821 gdk_win32_surface_set_title (surface, g_value_get_string (value));
4822 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4823 break;
4824
4825 case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
4826 break;
4827
4828 case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
4829 gdk_win32_surface_set_transient_for (surface, g_value_get_object (value));
4830 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4831 break;
4832
4833 case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
4834 GDK_SURFACE (surface)->modal_hint = g_value_get_boolean (value);
4835
4836 if (GDK_SURFACE (surface)->modal_hint)
4837 {
4838 SetCapture (GDK_SURFACE_HWND (surface));
4839 _gdk_push_modal_window (surface);
4840 }
4841
4842 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4843 break;
4844
4845 case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
4846 break;
4847
4848 case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
4849 GDK_WIN32_SURFACE (surface)->decorate_all = g_value_get_boolean (value);
4850 _gdk_win32_surface_update_style_bits (surface);
4851 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4852 break;
4853
4854 case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
4855 break;
4856
4857 case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
4858 surface->fullscreen_mode = g_value_get_enum (value);
4859 g_object_notify_by_pspec (G_OBJECT (surface), pspec);
4860 break;
4861
4862 case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
4863 break;
4864
4865 default:
4866 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4867 break;
4868 }
4869 }
4870
4871 static void
gdk_win32_toplevel_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)4872 gdk_win32_toplevel_get_property (GObject *object,
4873 guint prop_id,
4874 GValue *value,
4875 GParamSpec *pspec)
4876 {
4877 GdkSurface *surface = GDK_SURFACE (object);
4878
4879 switch (prop_id)
4880 {
4881 case LAST_PROP + GDK_TOPLEVEL_PROP_STATE:
4882 g_value_set_flags (value, surface->state);
4883 break;
4884
4885 case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
4886 break;
4887
4888 case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
4889 break;
4890
4891 case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
4892 g_value_set_object (value, surface->transient_for);
4893 break;
4894
4895 case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
4896 g_value_set_boolean (value, GDK_SURFACE (surface)->modal_hint);
4897 break;
4898
4899 case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
4900 g_value_set_pointer (value, NULL);
4901 break;
4902
4903 case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
4904 g_value_set_boolean (value, GDK_WIN32_SURFACE (surface)->decorate_all);
4905 break;
4906
4907 case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
4908 break;
4909
4910 case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
4911 g_value_set_enum (value, surface->fullscreen_mode);
4912 break;
4913
4914 case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
4915 g_value_set_boolean (value, surface->shortcuts_inhibited);
4916 break;
4917
4918 default:
4919 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4920 break;
4921 }
4922 }
4923
4924 static void
gdk_win32_toplevel_class_init(GdkWin32ToplevelClass * class)4925 gdk_win32_toplevel_class_init (GdkWin32ToplevelClass *class)
4926 {
4927 GObjectClass *object_class = G_OBJECT_CLASS (class);
4928
4929 object_class->get_property = gdk_win32_toplevel_get_property;
4930 object_class->set_property = gdk_win32_toplevel_set_property;
4931
4932 gdk_toplevel_install_properties (object_class, 1);
4933 }
4934
4935 static void
gdk_win32_toplevel_present(GdkToplevel * toplevel,GdkToplevelLayout * layout)4936 gdk_win32_toplevel_present (GdkToplevel *toplevel,
4937 GdkToplevelLayout *layout)
4938 {
4939 GdkSurface *surface = GDK_SURFACE (toplevel);
4940 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
4941 int width, height;
4942 gboolean maximize;
4943 gboolean fullscreen;
4944
4945 g_clear_pointer (&impl->toplevel_layout, gdk_toplevel_layout_unref);
4946 impl->toplevel_layout = gdk_toplevel_layout_copy (layout);
4947 compute_toplevel_size (surface, FALSE, &width, &height);
4948 gdk_win32_surface_resize (surface, width, height);
4949
4950 if (gdk_toplevel_layout_get_maximized (layout, &maximize))
4951 {
4952 if (maximize)
4953 gdk_win32_surface_maximize (surface);
4954 else
4955 gdk_win32_surface_unmaximize (surface);
4956 }
4957
4958 if (gdk_toplevel_layout_get_fullscreen (layout, &fullscreen))
4959 {
4960 if (fullscreen)
4961 gdk_win32_surface_fullscreen (surface);
4962 else
4963 gdk_win32_surface_unfullscreen (surface);
4964 }
4965
4966 gdk_win32_surface_show (surface, FALSE);
4967 maybe_notify_mapped (surface);
4968 }
4969
4970 static gboolean
gdk_win32_toplevel_minimize(GdkToplevel * toplevel)4971 gdk_win32_toplevel_minimize (GdkToplevel *toplevel)
4972 {
4973 gdk_win32_surface_minimize (GDK_SURFACE (toplevel));
4974
4975 return TRUE;
4976 }
4977
4978 static gboolean
gdk_win32_toplevel_lower(GdkToplevel * toplevel)4979 gdk_win32_toplevel_lower (GdkToplevel *toplevel)
4980 {
4981 return FALSE;
4982 }
4983
4984 static void
gdk_win32_toplevel_focus(GdkToplevel * toplevel,guint32 timestamp)4985 gdk_win32_toplevel_focus (GdkToplevel *toplevel,
4986 guint32 timestamp)
4987 {
4988 gdk_win32_surface_focus (GDK_SURFACE (toplevel), timestamp);
4989 }
4990
4991 static gboolean
gdk_win32_toplevel_show_window_menu(GdkToplevel * toplevel,GdkEvent * event)4992 gdk_win32_toplevel_show_window_menu (GdkToplevel *toplevel,
4993 GdkEvent *event)
4994 {
4995 return gdk_win32_surface_show_window_menu (GDK_SURFACE (toplevel), event);
4996 }
4997
4998 static gboolean
gdk_win32_toplevel_supports_edge_constraints(GdkToplevel * toplevel)4999 gdk_win32_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
5000 {
5001 return FALSE;
5002 }
5003
5004 static void
gdk_win32_toplevel_iface_init(GdkToplevelInterface * iface)5005 gdk_win32_toplevel_iface_init (GdkToplevelInterface *iface)
5006 {
5007 iface->present = gdk_win32_toplevel_present;
5008 iface->minimize = gdk_win32_toplevel_minimize;
5009 iface->lower = gdk_win32_toplevel_lower;
5010 iface->focus = gdk_win32_toplevel_focus;
5011 iface->show_window_menu = gdk_win32_toplevel_show_window_menu;
5012 iface->supports_edge_constraints = gdk_win32_toplevel_supports_edge_constraints;
5013 iface->begin_resize = gdk_win32_toplevel_begin_resize;
5014 iface->begin_move = gdk_win32_toplevel_begin_move;
5015 }
5016
5017 typedef struct
5018 {
5019 GdkWin32Surface parent_instance;
5020 } GdkWin32DragSurface;
5021
5022 typedef struct
5023 {
5024 GdkWin32SurfaceClass parent_class;
5025 } GdkWin32DragSurfaceClass;
5026
5027 static void gdk_win32_drag_surface_iface_init (GdkDragSurfaceInterface *iface);
5028
G_DEFINE_TYPE_WITH_CODE(GdkWin32DragSurface,gdk_win32_drag_surface,GDK_TYPE_WIN32_SURFACE,G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE,gdk_win32_drag_surface_iface_init))5029 G_DEFINE_TYPE_WITH_CODE (GdkWin32DragSurface, gdk_win32_drag_surface, GDK_TYPE_WIN32_SURFACE,
5030 G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE,
5031 gdk_win32_drag_surface_iface_init))
5032
5033 static void
5034 gdk_win32_drag_surface_init (GdkWin32DragSurface *surface)
5035 {
5036 }
5037
5038 static void
gdk_win32_drag_surface_class_init(GdkWin32DragSurfaceClass * class)5039 gdk_win32_drag_surface_class_init (GdkWin32DragSurfaceClass *class)
5040 {
5041 }
5042
5043 static gboolean
gdk_win32_drag_surface_present(GdkDragSurface * drag_surface,int width,int height)5044 gdk_win32_drag_surface_present (GdkDragSurface *drag_surface,
5045 int width,
5046 int height)
5047 {
5048 GdkSurface *surface = GDK_SURFACE (drag_surface);
5049
5050 gdk_win32_surface_resize (surface, width, height);
5051 gdk_win32_surface_show (surface, FALSE);
5052 maybe_notify_mapped (surface);
5053
5054 return TRUE;
5055 }
5056
5057 static void
gdk_win32_drag_surface_iface_init(GdkDragSurfaceInterface * iface)5058 gdk_win32_drag_surface_iface_init (GdkDragSurfaceInterface *iface)
5059 {
5060 iface->present = gdk_win32_drag_surface_present;
5061 }
5062
5063 #ifdef GDK_WIN32_ENABLE_EGL
5064 EGLSurface
gdk_win32_surface_get_egl_surface(GdkSurface * surface,EGLConfig config,gboolean is_dummy)5065 gdk_win32_surface_get_egl_surface (GdkSurface *surface,
5066 EGLConfig config,
5067 gboolean is_dummy)
5068 {
5069 GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface));
5070 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
5071
5072 if (is_dummy)
5073 {
5074 if (impl->egl_dummy_surface == EGL_NO_SURFACE)
5075 {
5076 EGLint attribs[] = {EGL_WIDTH, 1, EGL_WIDTH, 1, EGL_NONE};
5077 impl->egl_dummy_surface = eglCreatePbufferSurface (display->egl_disp,
5078 config,
5079 attribs);
5080 }
5081 return impl->egl_dummy_surface;
5082 }
5083 else
5084 {
5085 if (impl->egl_surface == EGL_NO_SURFACE)
5086 impl->egl_surface = eglCreateWindowSurface (display->egl_disp,
5087 config,
5088 GDK_SURFACE_HWND (surface),
5089 NULL);
5090
5091 return impl->egl_surface;
5092 }
5093
5094 }
5095 #endif
5096
5097 static void
gdk_win32_surface_get_queued_window_rect(GdkSurface * surface,int scale,RECT * return_window_rect)5098 gdk_win32_surface_get_queued_window_rect (GdkSurface *surface,
5099 int scale,
5100 RECT *return_window_rect)
5101 {
5102 RECT window_rect;
5103 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
5104
5105 _gdk_win32_get_window_client_area_rect (surface, scale, &window_rect);
5106
5107 /* Turn client area into window area */
5108 _gdk_win32_adjust_client_rect (surface, &window_rect);
5109
5110 /* Convert GDK screen coordinates to W32 desktop coordinates */
5111 window_rect.left -= _gdk_offset_x * impl->surface_scale;
5112 window_rect.right -= _gdk_offset_x * impl->surface_scale;
5113 window_rect.top -= _gdk_offset_y * impl->surface_scale;
5114 window_rect.bottom -= _gdk_offset_y * impl->surface_scale;
5115
5116 *return_window_rect = window_rect;
5117 }
5118
5119 static void
gdk_win32_surface_apply_queued_move_resize(GdkSurface * surface,RECT window_rect)5120 gdk_win32_surface_apply_queued_move_resize (GdkSurface *surface,
5121 RECT window_rect)
5122 {
5123 if (!IsIconic (GDK_SURFACE_HWND (surface)))
5124 {
5125 GDK_NOTE (EVENTS, g_print ("Setting window position ... "));
5126
5127 API_CALL (SetWindowPos, (GDK_SURFACE_HWND (surface),
5128 SWP_NOZORDER_SPECIFIED,
5129 window_rect.left, window_rect.top,
5130 window_rect.right - window_rect.left,
5131 window_rect.bottom - window_rect.top,
5132 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW));
5133
5134 GDK_NOTE (EVENTS, g_print (" ... set window position\n"));
5135
5136 return;
5137 }
5138
5139 /* Don't move iconic windows */
5140 /* TODO: use SetWindowPlacement() to change non-minimized window position */
5141 }
5142
5143 RECT
gdk_win32_surface_handle_queued_move_resize(GdkDrawContext * draw_context)5144 gdk_win32_surface_handle_queued_move_resize (GdkDrawContext *draw_context)
5145 {
5146 GdkSurface *surface;
5147 GdkWin32Surface *impl;
5148 int scale;
5149 RECT queued_window_rect;
5150
5151 surface = gdk_draw_context_get_surface (draw_context);
5152 impl = GDK_WIN32_SURFACE (surface);
5153 scale = gdk_surface_get_scale_factor (surface);
5154
5155 gdk_win32_surface_get_queued_window_rect (surface, scale, &queued_window_rect);
5156
5157 /* Apply queued resizes for non-double-buffered windows
5158 * before painting them (we paint on the window DC directly,
5159 * it must have the right size).
5160 * Due to some poorly-undetstood issue delayed
5161 * resizing of double-buffered windows can produce weird
5162 * artefacts, so these are also resized before we paint.
5163 */
5164 if (impl->drag_move_resize_context.native_move_resize_pending)
5165 {
5166 impl->drag_move_resize_context.native_move_resize_pending = FALSE;
5167 gdk_win32_surface_apply_queued_move_resize (surface, queued_window_rect);
5168 }
5169
5170 return queued_window_rect;
5171 }
5172
5173 void
_gdk_win32_surface_invalidate_egl_framebuffer(GdkSurface * surface)5174 _gdk_win32_surface_invalidate_egl_framebuffer (GdkSurface *surface)
5175 {
5176 /* If we are using ANGLE, we need to force redraw of the whole Window and its child windows
5177 * as we need to re-acquire the EGL surfaces that we rendered to upload to Cairo explicitly,
5178 * using gdk_window_invalidate_rect (), when we maximize or restore or use aerosnap
5179 */
5180 #ifdef GDK_WIN32_ENABLE_EGL
5181 if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context))
5182 {
5183 GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
5184
5185 impl->egl_force_redraw_all = TRUE;
5186 }
5187 #endif
5188 }
5189