forked from AuroraMiddleware/gtk
GDK W32: Re-implement AeroSnap for CSD windows
It works exactly like AeroSnap. Except for shift+win+left/right, which is left for AeroSnap to handle (AeroSnap takes action before we get the message, so there's no way for us to override it). The only thing that doesn't work is shift+win+left/right on a maximized window, for reasons unknown at the moment. This only implements winkey+stuff behaviour of AeroSnap, not the drag-to-the-edge-and-something-funny-happens one. https://bugzilla.gnome.org/show_bug.cgi?id=763013
This commit is contained in:
parent
27a1b50bc6
commit
0ce217cf94
@ -2288,6 +2288,48 @@ gdk_event_translate (MSG *msg,
|
||||
if (GDK_WINDOW_DESTROYED (window))
|
||||
break;
|
||||
|
||||
if (msg->message == WM_KEYUP &&
|
||||
!GDK_WINDOW_DESTROYED (gdk_window_get_toplevel (window)) &&
|
||||
_gdk_win32_window_lacks_wm_decorations (gdk_window_get_toplevel (window)) && /* For CSD only */
|
||||
((GetKeyState (VK_LWIN) & 0x8000) ||
|
||||
(GetKeyState (VK_RWIN) & 0x8000)))
|
||||
{
|
||||
GdkWin32AeroSnapCombo combo = GDK_WIN32_AEROSNAP_COMBO_NOTHING;
|
||||
gboolean lshiftdown = GetKeyState (VK_LSHIFT) & 0x8000;
|
||||
gboolean rshiftdown = GetKeyState (VK_RSHIFT) & 0x8000;
|
||||
gboolean oneshiftdown = (lshiftdown || rshiftdown) && !(lshiftdown && rshiftdown);
|
||||
|
||||
switch (msg->wParam)
|
||||
{
|
||||
case VK_UP:
|
||||
combo = GDK_WIN32_AEROSNAP_COMBO_UP;
|
||||
break;
|
||||
case VK_DOWN:
|
||||
combo = GDK_WIN32_AEROSNAP_COMBO_DOWN;
|
||||
break;
|
||||
case VK_LEFT:
|
||||
combo = GDK_WIN32_AEROSNAP_COMBO_LEFT;
|
||||
break;
|
||||
case VK_RIGHT:
|
||||
combo = GDK_WIN32_AEROSNAP_COMBO_RIGHT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (oneshiftdown && combo != GDK_WIN32_AEROSNAP_COMBO_NOTHING)
|
||||
combo += 4;
|
||||
|
||||
/* These are the only combos that Windows WM does handle for us */
|
||||
if (combo == GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT ||
|
||||
combo == GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT)
|
||||
combo = GDK_WIN32_AEROSNAP_COMBO_NOTHING;
|
||||
|
||||
if (combo != GDK_WIN32_AEROSNAP_COMBO_NOTHING)
|
||||
{
|
||||
_gdk_win32_window_handle_aerosnap (gdk_window_get_toplevel (window), combo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
event = gdk_event_new ((msg->message == WM_KEYDOWN ||
|
||||
msg->message == WM_SYSKEYDOWN) ?
|
||||
GDK_KEY_PRESS : GDK_KEY_RELEASE);
|
||||
|
@ -536,6 +536,9 @@ void _gdk_win32_emit_configure_event (GdkWindow *window);
|
||||
|
||||
guint32 _gdk_win32_keymap_get_decimal_mark (void);
|
||||
|
||||
void _gdk_win32_window_handle_aerosnap (GdkWindow *window,
|
||||
GdkWin32AeroSnapCombo combo);
|
||||
|
||||
gboolean _gdk_win32_get_window_rect (GdkWindow *window,
|
||||
RECT *rect);
|
||||
void _gdk_win32_do_emit_configure_event (GdkWindow *window,
|
||||
|
@ -42,6 +42,8 @@
|
||||
|
||||
#include <cairo-win32.h>
|
||||
#include <dwmapi.h>
|
||||
#include <math.h>
|
||||
#include "fallback-c89.c"
|
||||
|
||||
static void gdk_window_impl_win32_init (GdkWindowImplWin32 *window);
|
||||
static void gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass);
|
||||
@ -2919,6 +2921,277 @@ _gdk_window_get_functions (GdkWindow *window,
|
||||
return (functions_set != NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
unsnap (GdkWindow *window,
|
||||
GdkScreen *screen,
|
||||
gint monitor)
|
||||
{
|
||||
GdkWindowImplWin32 *impl;
|
||||
GdkRectangle rect;
|
||||
|
||||
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
|
||||
|
||||
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
|
||||
|
||||
if (impl->snap_stash == NULL)
|
||||
return;
|
||||
|
||||
gdk_screen_get_monitor_workarea (screen, monitor, &rect);
|
||||
|
||||
GDK_NOTE (MISC, g_print ("Monitor work area %d x %d @ %d : %d\n", rect.width, rect.height, rect.x, rect.y));
|
||||
|
||||
/* Calculate actual unsnapped window size based on its
|
||||
* old relative size. Same for position.
|
||||
*/
|
||||
rect.x += round (rect.width * impl->snap_stash->x);
|
||||
rect.y += round (rect.height * impl->snap_stash->y);
|
||||
rect.width = round (rect.width * impl->snap_stash->width);
|
||||
rect.height = round (rect.height * impl->snap_stash->height);
|
||||
|
||||
GDK_NOTE (MISC, g_print ("Unsnapped window size %d x %d @ %d : %d\n", rect.width, rect.height, rect.x, rect.y));
|
||||
|
||||
gdk_window_move_resize (window, rect.x, rect.y,
|
||||
rect.width, rect.height);
|
||||
|
||||
g_clear_pointer (&impl->snap_stash, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
stash_window (GdkWindow *window,
|
||||
GdkWindowImplWin32 *impl,
|
||||
GdkScreen *screen,
|
||||
gint monitor)
|
||||
{
|
||||
gint x, y;
|
||||
gint width;
|
||||
gint height;
|
||||
WINDOWPLACEMENT placement;
|
||||
HMONITOR hmonitor;
|
||||
MONITORINFO hmonitor_info;
|
||||
|
||||
placement.length = sizeof(WINDOWPLACEMENT);
|
||||
|
||||
/* Use W32 API to get unmaximized window size, which GDK doesn't remember */
|
||||
if (!GetWindowPlacement (GDK_WINDOW_HWND (window), &placement))
|
||||
return;
|
||||
|
||||
/* MSDN is very vague, but in practice rcNormalPosition is the same as GetWindowRect(),
|
||||
* only with adjustments for toolbars (which creates rather weird coodinate space issues).
|
||||
* We need to get monitor info and apply workarea vs monitorarea diff to turn
|
||||
* these into screen coordinates proper.
|
||||
*/
|
||||
hmonitor = MonitorFromWindow (GDK_WINDOW_HWND (window), MONITOR_DEFAULTTONEAREST);
|
||||
hmonitor_info.cbSize = sizeof (hmonitor_info);
|
||||
|
||||
if (!GetMonitorInfoA (hmonitor, &hmonitor_info))
|
||||
return;
|
||||
|
||||
if (impl->snap_stash == NULL)
|
||||
impl->snap_stash = g_new0 (GdkRectangleDouble, 1);
|
||||
|
||||
GDK_NOTE (MISC, g_print ("monitor work area %ld x %ld @ %ld : %ld\n",
|
||||
hmonitor_info.rcWork.right - hmonitor_info.rcWork.left,
|
||||
hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top,
|
||||
hmonitor_info.rcWork.left,
|
||||
hmonitor_info.rcWork.top));
|
||||
GDK_NOTE (MISC, g_print ("monitor area %ld x %ld @ %ld : %ld\n",
|
||||
hmonitor_info.rcMonitor.right - hmonitor_info.rcMonitor.left,
|
||||
hmonitor_info.rcMonitor.bottom - hmonitor_info.rcMonitor.top,
|
||||
hmonitor_info.rcMonitor.left,
|
||||
hmonitor_info.rcMonitor.top));
|
||||
GDK_NOTE (MISC, g_print ("window work place %ld x %ld @ %ld : %ld\n",
|
||||
placement.rcNormalPosition.right - placement.rcNormalPosition.left,
|
||||
placement.rcNormalPosition.bottom - placement.rcNormalPosition.top,
|
||||
placement.rcNormalPosition.left,
|
||||
placement.rcNormalPosition.top));
|
||||
|
||||
width = placement.rcNormalPosition.right - placement.rcNormalPosition.left;
|
||||
height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top;
|
||||
x = placement.rcNormalPosition.left - hmonitor_info.rcMonitor.left;
|
||||
y = placement.rcNormalPosition.top - hmonitor_info.rcMonitor.top;
|
||||
|
||||
impl->snap_stash->x = (gdouble) (x) / (gdouble) (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left);
|
||||
impl->snap_stash->y = (gdouble) (y) / (gdouble) (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top);
|
||||
impl->snap_stash->width = (gdouble) width / (gdouble) (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left);
|
||||
impl->snap_stash->height = (gdouble) height / (gdouble) (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top);
|
||||
|
||||
GDK_NOTE (MISC, g_print ("Stashed window %d x %d @ %d : %d as %f x %f @ %f : %f\n",
|
||||
width, height, x, y,
|
||||
impl->snap_stash->width, impl->snap_stash->height, impl->snap_stash->x, impl->snap_stash->y));
|
||||
}
|
||||
|
||||
static void
|
||||
snap_up (GdkWindow *window,
|
||||
GdkScreen *screen,
|
||||
gint monitor)
|
||||
{
|
||||
SHORT maxysize;
|
||||
gint x, y;
|
||||
gint width;
|
||||
GdkWindowImplWin32 *impl;
|
||||
|
||||
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
|
||||
|
||||
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_FULLUP;
|
||||
|
||||
maxysize = GetSystemMetrics (SM_CYMAXTRACK);
|
||||
gdk_window_get_position (window, &x, &y);
|
||||
width = gdk_window_get_width (window);
|
||||
|
||||
stash_window (window, impl, screen, monitor);
|
||||
|
||||
gdk_window_move_resize (window, x, 0, width, maxysize);
|
||||
}
|
||||
|
||||
static void
|
||||
snap_left (GdkWindow *window,
|
||||
GdkScreen *screen,
|
||||
gint monitor,
|
||||
gint snap_monitor)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
GdkWindowImplWin32 *impl;
|
||||
|
||||
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
|
||||
|
||||
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
|
||||
|
||||
gdk_screen_get_monitor_workarea (screen, snap_monitor, &rect);
|
||||
|
||||
stash_window (window, impl, screen, monitor);
|
||||
|
||||
rect.width = rect.width / 2;
|
||||
|
||||
gdk_window_move_resize (window, rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
|
||||
static void
|
||||
snap_right (GdkWindow *window,
|
||||
GdkScreen *screen,
|
||||
gint monitor,
|
||||
gint snap_monitor)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
GdkWindowImplWin32 *impl;
|
||||
|
||||
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
|
||||
|
||||
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
|
||||
|
||||
gdk_screen_get_monitor_workarea (screen, snap_monitor, &rect);
|
||||
|
||||
stash_window (window, impl, screen, monitor);
|
||||
|
||||
rect.width /= 2;
|
||||
rect.x += rect.width;
|
||||
|
||||
gdk_window_move_resize (window, rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_win32_window_handle_aerosnap (GdkWindow *window,
|
||||
GdkWin32AeroSnapCombo combo)
|
||||
{
|
||||
GdkWindowImplWin32 *impl;
|
||||
GdkDisplay *display;
|
||||
GdkScreen *screen;
|
||||
gint n_monitors, monitor;
|
||||
GdkWindowState window_state = gdk_window_get_state (window);
|
||||
gboolean minimized = window_state & GDK_WINDOW_STATE_ICONIFIED;
|
||||
gboolean maximized = window_state & GDK_WINDOW_STATE_MAXIMIZED;
|
||||
gboolean halfsnapped;
|
||||
|
||||
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
|
||||
display = gdk_window_get_display (window);
|
||||
screen = gdk_display_get_default_screen (display);
|
||||
n_monitors = gdk_screen_get_n_monitors (screen);
|
||||
monitor = gdk_screen_get_monitor_at_window (screen, window);
|
||||
|
||||
if (minimized && maximized)
|
||||
minimized = FALSE;
|
||||
|
||||
halfsnapped = (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
|
||||
impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
|
||||
impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP);
|
||||
|
||||
switch (combo)
|
||||
{
|
||||
case GDK_WIN32_AEROSNAP_COMBO_NOTHING:
|
||||
/* Do nothing */
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_COMBO_UP:
|
||||
if (!maximized)
|
||||
{
|
||||
unsnap (window, screen, monitor);
|
||||
gdk_window_maximize (window);
|
||||
}
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_COMBO_DOWN:
|
||||
case GDK_WIN32_AEROSNAP_COMBO_SHIFTDOWN:
|
||||
if (maximized)
|
||||
{
|
||||
gdk_window_unmaximize (window);
|
||||
unsnap (window, screen, monitor);
|
||||
}
|
||||
else if (halfsnapped)
|
||||
unsnap (window, screen, monitor);
|
||||
else if (!minimized)
|
||||
gdk_window_iconify (window);
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_COMBO_LEFT:
|
||||
if (maximized)
|
||||
gdk_window_unmaximize (window);
|
||||
|
||||
if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED ||
|
||||
impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP)
|
||||
{
|
||||
unsnap (window, screen, monitor);
|
||||
snap_left (window, screen, monitor, monitor);
|
||||
}
|
||||
else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT)
|
||||
{
|
||||
unsnap (window, screen, monitor);
|
||||
snap_right (window, screen, monitor, monitor - 1 >= 0 ? monitor - 1 : n_monitors - 1);
|
||||
}
|
||||
else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT)
|
||||
{
|
||||
unsnap (window, screen, monitor);
|
||||
}
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_COMBO_RIGHT:
|
||||
if (maximized)
|
||||
gdk_window_unmaximize (window);
|
||||
|
||||
if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED ||
|
||||
impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP)
|
||||
{
|
||||
unsnap (window, screen, monitor);
|
||||
snap_right (window, screen, monitor, monitor);
|
||||
}
|
||||
else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT)
|
||||
{
|
||||
unsnap (window, screen, monitor);
|
||||
}
|
||||
else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT)
|
||||
{
|
||||
unsnap (window, screen, monitor);
|
||||
snap_left (window, screen, monitor, monitor + 1 < n_monitors ? monitor + 1 : 0);
|
||||
}
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_COMBO_SHIFTUP:
|
||||
if (!maximized &&
|
||||
impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED)
|
||||
{
|
||||
snap_up (window, screen, monitor);
|
||||
}
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT:
|
||||
case GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT:
|
||||
/* No implementation needed at the moment */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
get_cursor_name_from_op (GdkW32WindowDragOp op,
|
||||
GdkWindowEdge edge)
|
||||
|
@ -46,6 +46,44 @@ typedef struct _GdkWindowImplWin32Class GdkWindowImplWin32Class;
|
||||
#define GDK_IS_WINDOW_IMPL_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_WIN32))
|
||||
#define GDK_WINDOW_IMPL_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_WIN32, GdkWindowImplWin32Class))
|
||||
|
||||
enum _GdkWin32AeroSnapCombo
|
||||
{
|
||||
GDK_WIN32_AEROSNAP_COMBO_NOTHING = 0,
|
||||
GDK_WIN32_AEROSNAP_COMBO_UP,
|
||||
GDK_WIN32_AEROSNAP_COMBO_DOWN,
|
||||
GDK_WIN32_AEROSNAP_COMBO_LEFT,
|
||||
GDK_WIN32_AEROSNAP_COMBO_RIGHT,
|
||||
/* Same order as non-shift variants. We use it to do things like:
|
||||
* AEROSNAP_UP + 4 = AEROSNAP_SHIFTUP
|
||||
*/
|
||||
GDK_WIN32_AEROSNAP_COMBO_SHIFTUP,
|
||||
GDK_WIN32_AEROSNAP_COMBO_SHIFTDOWN,
|
||||
GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT,
|
||||
GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT
|
||||
};
|
||||
|
||||
typedef enum _GdkWin32AeroSnapCombo GdkWin32AeroSnapCombo;
|
||||
|
||||
enum _GdkWin32AeroSnapState
|
||||
{
|
||||
GDK_WIN32_AEROSNAP_STATE_UNDETERMINED = 0,
|
||||
GDK_WIN32_AEROSNAP_STATE_HALFLEFT,
|
||||
GDK_WIN32_AEROSNAP_STATE_HALFRIGHT,
|
||||
GDK_WIN32_AEROSNAP_STATE_FULLUP,
|
||||
};
|
||||
|
||||
typedef enum _GdkWin32AeroSnapState GdkWin32AeroSnapState;
|
||||
|
||||
struct _GdkRectangleDouble
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble width;
|
||||
gdouble height;
|
||||
};
|
||||
|
||||
typedef struct _GdkRectangleDouble GdkRectangleDouble;
|
||||
|
||||
enum _GdkW32WindowDragOp
|
||||
{
|
||||
GDK_WIN32_DRAGOP_NONE = 0,
|
||||
@ -173,6 +211,19 @@ struct _GdkWindowImplWin32
|
||||
|
||||
GdkW32DragMoveResizeContext drag_move_resize_context;
|
||||
|
||||
/* Remembers where the window was snapped.
|
||||
* Some snap operations change their meaning if
|
||||
* the window is already snapped.
|
||||
*/
|
||||
GdkWin32AeroSnapState snap_state;
|
||||
|
||||
/* Remembers window position before it was snapped.
|
||||
* This is used to unsnap it.
|
||||
* Position and size are percentages of the workarea
|
||||
* of the monitor on which the window was before it was snapped.
|
||||
*/
|
||||
GdkRectangleDouble *snap_stash;
|
||||
|
||||
/* Decorations set by gdk_window_set_decorations() or NULL if unset */
|
||||
GdkWMDecoration* decorations;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user