[gtk+] GDK W32: custom (non-WM) drag-move and drag-resize code
- From: Руслан Ижбулатов <ruslanizhb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] GDK W32: custom (non-WM) drag-move and drag-resize code
- Date: Wed, 2 Mar 2016 21:40:14 +0000 (UTC)
commit e03946bd285d860fc9011a2fbb5363c2a176aaab
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date: Sat Feb 6 12:06:41 2016 +0000
GDK W32: custom (non-WM) drag-move and drag-resize code
Normally works only on CSD windows, non-CSD windows continue
to use WM modal loop for drag-resizing and drag-moving. However,
if it is activated on non-CSD windows, it does work.
Has the advantage of being completely immune to AeroSnap.
AeroSnap only worked partially on CSD windows, with the only part
that worked being "don't let users drag window titlebar outside of
the desktop". Now AeroSnap doesn't work on windows moved by
this code at all, which is good, since they currently don't work
well with it due to the way shadows are drawn.
It's possible to also re-implement AeroSnap (or something similar),
but that is a story for another commit.
This code was originally intended to fix the problem of window
size and window contents desynchronization, but failed to achieve
that result in the end. Nevertheless, it serves as a foundation for
other changes to the way window resizing works.
https://bugzilla.gnome.org/show_bug.cgi?id=761629
gdk/win32/gdkevents-win32.c | 223 +++++++++++++++----------
gdk/win32/gdkprivate-win32.h | 12 ++
gdk/win32/gdkwindow-win32.c | 388 +++++++++++++++++++++++++++++++++++-------
gdk/win32/gdkwindow-win32.h | 49 ++++++
4 files changed, 523 insertions(+), 149 deletions(-)
---
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index b6a0b61..da21e9f 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -1408,8 +1408,14 @@ doesnt_want_char (gint mask,
return !(mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK));
}
-void
-_gdk_win32_emit_configure_event (GdkWindow *window)
+/* Acquires actual client area size of the underlying native window.
+ * Rectangle is in GDK screen coordinates (_gdk_offset_* is added).
+ * Returns FALSE if configure events should be inhibited,
+ * TRUE otherwise.
+ */
+gboolean
+_gdk_win32_get_window_rect (GdkWindow *window,
+ RECT *rect)
{
GdkWindowImplWin32 *window_impl;
RECT client_rect;
@@ -1417,8 +1423,6 @@ _gdk_win32_emit_configure_event (GdkWindow *window)
HWND hwnd;
window_impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
- if (window_impl->inhibit_configure)
- return;
hwnd = GDK_WINDOW_HWND (window);
@@ -1434,11 +1438,23 @@ _gdk_win32_emit_configure_event (GdkWindow *window)
point.y += _gdk_offset_y;
}
- window->width = client_rect.right - client_rect.left;
- window->height = client_rect.bottom - client_rect.top;
+ rect->left = point.x;
+ rect->top = point.y;
+ rect->right = point.x + client_rect.right - client_rect.left;
+ rect->bottom = point.y + client_rect.bottom - client_rect.top;
+
+ return !window_impl->inhibit_configure;
+}
+
+void
+_gdk_win32_do_emit_configure_event (GdkWindow *window,
+ RECT rect)
+{
+ window->width = rect.right - rect.left;
+ window->height = rect.bottom - rect.top;
- window->x = point.x;
- window->y = point.y;
+ window->x = rect.left;
+ window->y = rect.top;
_gdk_window_update_size (window);
@@ -1448,16 +1464,27 @@ _gdk_win32_emit_configure_event (GdkWindow *window)
event->configure.window = window;
- event->configure.width = client_rect.right - client_rect.left;
- event->configure.height = client_rect.bottom - client_rect.top;
+ event->configure.width = rect.right - rect.left;
+ event->configure.height = rect.bottom - rect.top;
- event->configure.x = point.x;
- event->configure.y = point.y;
+ event->configure.x = rect.left;
+ event->configure.y = rect.top;
_gdk_win32_append_event (event);
}
}
+void
+_gdk_win32_emit_configure_event (GdkWindow *window)
+{
+ RECT rect;
+
+ if (!_gdk_win32_get_window_rect (window, &rect))
+ return;
+
+ _gdk_win32_do_emit_configure_event (window, rect);
+}
+
cairo_region_t *
_gdk_win32_hrgn_to_region (HRGN hrgn)
{
@@ -1874,6 +1901,76 @@ ensure_stacking_on_activate_app (MSG *msg,
}
}
+gboolean
+_gdk_win32_window_fill_min_max_info (GdkWindow *window,
+ MINMAXINFO *mmi)
+{
+ GdkWindowImplWin32 *impl;
+ RECT rect;
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return FALSE;
+
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ if (impl->hint_flags & GDK_HINT_MIN_SIZE)
+ {
+ rect.left = rect.top = 0;
+ rect.right = impl->hints.min_width;
+ rect.bottom = impl->hints.min_height;
+
+ _gdk_win32_adjust_client_rect (window, &rect);
+
+ mmi->ptMinTrackSize.x = rect.right - rect.left;
+ mmi->ptMinTrackSize.y = rect.bottom - rect.top;
+ }
+
+ if (impl->hint_flags & GDK_HINT_MAX_SIZE)
+ {
+ int maxw, maxh;
+
+ rect.left = rect.top = 0;
+ rect.right = impl->hints.max_width;
+ rect.bottom = impl->hints.max_height;
+
+ _gdk_win32_adjust_client_rect (window, &rect);
+
+ /* at least on win9x we have the 16 bit trouble */
+ maxw = rect.right - rect.left;
+ maxh = rect.bottom - rect.top;
+ mmi->ptMaxTrackSize.x = maxw > 0 && maxw < G_MAXSHORT ? maxw : G_MAXSHORT;
+ mmi->ptMaxTrackSize.y = maxh > 0 && maxh < G_MAXSHORT ? maxh : G_MAXSHORT;
+ }
+ else
+ {
+ HMONITOR nearest_monitor;
+ MONITORINFO nearest_info;
+
+ nearest_monitor = MonitorFromWindow (GDK_WINDOW_HWND (window), MONITOR_DEFAULTTONEAREST);
+ nearest_info.cbSize = sizeof (nearest_info);
+
+ if (GetMonitorInfoA (nearest_monitor, &nearest_info))
+ {
+ /* MSDN says that we must specify maximized window
+ * size as if it was located on the primary monitor.
+ * However, we still need to account for a taskbar
+ * that might or might not be on the nearest monitor where
+ * window will actually end up.
+ * "0" here is the top-left corner of the primary monitor.
+ */
+ mmi->ptMaxPosition.x = 0 + (nearest_info.rcWork.left - nearest_info.rcMonitor.left);
+ mmi->ptMaxPosition.y = 0 + (nearest_info.rcWork.top - nearest_info.rcMonitor.top);
+ mmi->ptMaxSize.x = nearest_info.rcWork.right - nearest_info.rcWork.left;
+ mmi->ptMaxSize.y = nearest_info.rcWork.bottom - nearest_info.rcWork.top;
+ }
+
+ mmi->ptMaxTrackSize.x = GetSystemMetrics (SM_CXMAXTRACK);
+ mmi->ptMaxTrackSize.y = GetSystemMetrics (SM_CYMAXTRACK);
+ }
+
+ return TRUE;
+}
+
#define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
GDK_BUTTON2_MASK | \
GDK_BUTTON3_MASK | \
@@ -1887,7 +1984,6 @@ gdk_event_translate (MSG *msg,
RECT rect, *drag, orig_drag;
POINT point;
MINMAXINFO *mmi;
- LONG style;
HWND hwnd;
GdkCursor *cursor;
BYTE key_state[256];
@@ -2469,7 +2565,13 @@ gdk_event_translate (MSG *msg,
current_root_x = msg->pt.x + _gdk_offset_x;
current_root_y = msg->pt.y + _gdk_offset_y;
- if (!_gdk_input_ignore_core)
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+ {
+ gdk_win32_window_do_move_resize_drag (window, current_root_x, current_root_y);
+ }
+ else if (!_gdk_input_ignore_core)
{
event = gdk_event_new (GDK_MOTION_NOTIFY);
event->motion.window = window;
@@ -2775,6 +2877,11 @@ gdk_event_translate (MSG *msg,
_modal_move_resize_window = NULL;
_gdk_win32_end_modal_call ();
}
+
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+ gdk_win32_window_end_move_resize_drag (window);
break;
case WM_WINDOWPOSCHANGING:
@@ -3130,11 +3237,8 @@ gdk_event_translate (MSG *msg,
break;
case WM_GETMINMAXINFO:
- if (GDK_WINDOW_DESTROYED (window))
- break;
-
- impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
mmi = (MINMAXINFO*) msg->lParam;
+
GDK_NOTE (EVENTS, g_print (" (mintrack:%ldx%ld maxtrack:%ldx%ld "
"maxpos:%+ld%+ld maxsize:%ldx%ld)",
mmi->ptMinTrackSize.x, mmi->ptMinTrackSize.y,
@@ -3142,79 +3246,20 @@ gdk_event_translate (MSG *msg,
mmi->ptMaxPosition.x, mmi->ptMaxPosition.y,
mmi->ptMaxSize.x, mmi->ptMaxSize.y));
- style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
-
- if (impl->hint_flags & GDK_HINT_MIN_SIZE)
- {
- rect.left = rect.top = 0;
- rect.right = impl->hints.min_width;
- rect.bottom = impl->hints.min_height;
-
- _gdk_win32_adjust_client_rect (window, &rect);
-
- mmi->ptMinTrackSize.x = rect.right - rect.left;
- mmi->ptMinTrackSize.y = rect.bottom - rect.top;
- }
-
- if (impl->hint_flags & GDK_HINT_MAX_SIZE)
- {
- int maxw, maxh;
-
- rect.left = rect.top = 0;
- rect.right = impl->hints.max_width;
- rect.bottom = impl->hints.max_height;
-
- _gdk_win32_adjust_client_rect (window, &rect);
-
- /* at least on win9x we have the 16 bit trouble */
- maxw = rect.right - rect.left;
- maxh = rect.bottom - rect.top;
- mmi->ptMaxTrackSize.x = maxw > 0 && maxw < G_MAXSHORT ? maxw : G_MAXSHORT;
- mmi->ptMaxTrackSize.y = maxh > 0 && maxh < G_MAXSHORT ? maxh : G_MAXSHORT;
- }
- /* Assume that these styles are incompatible with CSD,
- * so there's no reason for us to override the defaults.
- */
- else if ((style & (WS_BORDER | WS_THICKFRAME)) == 0)
- {
- HMONITOR nearest_monitor;
- MONITORINFO nearest_info;
-
- nearest_monitor = MonitorFromWindow (GDK_WINDOW_HWND (window), MONITOR_DEFAULTTONEAREST);
- nearest_info.cbSize = sizeof (nearest_info);
-
- if (GetMonitorInfoA (nearest_monitor, &nearest_info))
- {
- /* MSDN says that we must specify maximized window
- * size as if it was located on the primary monitor.
- * However, we still need to account for a taskbar
- * that might or might not be on the nearest monitor where
- * window will actually end up.
- * "0" here is the top-left corner of the primary monitor.
- */
- mmi->ptMaxPosition.x = 0 + (nearest_info.rcWork.left - nearest_info.rcMonitor.left);
- mmi->ptMaxPosition.y = 0 + (nearest_info.rcWork.top - nearest_info.rcMonitor.top);
- mmi->ptMaxSize.x = nearest_info.rcWork.right - nearest_info.rcWork.left;
- mmi->ptMaxSize.y = nearest_info.rcWork.bottom - nearest_info.rcWork.top;
- }
-
- mmi->ptMaxTrackSize.x = GetSystemMetrics (SM_CXMAXTRACK);
- mmi->ptMaxTrackSize.y = GetSystemMetrics (SM_CYMAXTRACK);
- }
+ if (_gdk_win32_window_fill_min_max_info (window, mmi))
+ {
+ /* Don't call DefWindowProcW() */
+ GDK_NOTE (EVENTS,
+ g_print (" (handled, mintrack:%ldx%ld maxtrack:%ldx%ld "
+ "maxpos:%+ld%+ld maxsize:%ldx%ld)",
+ mmi->ptMinTrackSize.x, mmi->ptMinTrackSize.y,
+ mmi->ptMaxTrackSize.x, mmi->ptMaxTrackSize.y,
+ mmi->ptMaxPosition.x, mmi->ptMaxPosition.y,
+ mmi->ptMaxSize.x, mmi->ptMaxSize.y));
- if (impl->hint_flags & (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE))
- {
- /* Don't call DefWindowProcW() */
- GDK_NOTE (EVENTS, g_print (" (handled, mintrack:%ldx%ld maxtrack:%ldx%ld "
- "maxpos:%+ld%+ld maxsize:%ldx%ld)",
- mmi->ptMinTrackSize.x, mmi->ptMinTrackSize.y,
- mmi->ptMaxTrackSize.x, mmi->ptMaxTrackSize.y,
- mmi->ptMaxPosition.x, mmi->ptMaxPosition.y,
- mmi->ptMaxSize.x, mmi->ptMaxSize.y));
- return_val = TRUE;
- }
+ return_val = TRUE;
+ }
- return_val = TRUE;
break;
case WM_CLOSE:
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index f590ff7..ba79a1b 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -521,8 +521,20 @@ gchar *_gdk_win32_display_manager_get_atom_name (GdkDisplayManager *manager,
void _gdk_win32_append_event (GdkEvent *event);
void _gdk_win32_emit_configure_event (GdkWindow *window);
+
guint32 _gdk_win32_keymap_get_decimal_mark (void);
+gboolean _gdk_win32_get_window_rect (GdkWindow *window,
+ RECT *rect);
+void _gdk_win32_do_emit_configure_event (GdkWindow *window,
+ RECT rect);
+void gdk_win32_window_do_move_resize_drag (GdkWindow *window,
+ gint x,
+ gint y);
+void gdk_win32_window_end_move_resize_drag (GdkWindow *window);
+gboolean _gdk_win32_window_fill_min_max_info (GdkWindow *window,
+ MINMAXINFO *mmi);
+
/* Initialization */
void _gdk_win32_windowing_init (void);
void _gdk_dnd_init (void);
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index bd64753..513a3bf 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -184,6 +184,50 @@ gdk_window_impl_win32_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+static void
+gdk_win32_window_end_paint (GdkWindow *window)
+{
+ GdkWindowImplWin32 *impl;
+ RECT window_rect;
+ gint x, y;
+
+ if (window == NULL || GDK_WINDOW_DESTROYED (window))
+ return;
+
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ if (!impl->drag_move_resize_context.native_move_resize_pending)
+ return;
+
+ impl->drag_move_resize_context.native_move_resize_pending = FALSE;
+
+ gdk_window_get_position (window, &x, &y);
+ window_rect.left = x;
+ window_rect.top = y;
+ window_rect.right = window_rect.left + gdk_window_get_width (window);
+ window_rect.bottom = window_rect.top + gdk_window_get_height (window);
+
+ /* Turn client area into window area */
+ _gdk_win32_adjust_client_rect (window, &window_rect);
+
+ /* Convert GDK screen coordinates to W32 desktop coordinates */
+ window_rect.left -= _gdk_offset_x;
+ window_rect.right -= _gdk_offset_x;
+ window_rect.top -= _gdk_offset_y;
+ window_rect.bottom -= _gdk_offset_y;
+
+ GDK_NOTE (EVENTS, g_print ("Setting window position ... "));
+
+ API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ window_rect.left, window_rect.top,
+ window_rect.right - window_rect.left,
+ window_rect.bottom - window_rect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW));
+
+ GDK_NOTE (EVENTS, g_print (" ... set window position\n"));
+}
+
void
_gdk_win32_adjust_client_rect (GdkWindow *window,
RECT *rect)
@@ -2639,86 +2683,308 @@ _gdk_window_get_functions (GdkWindow *window,
}
static void
-gdk_win32_window_begin_resize_drag (GdkWindow *window,
- GdkWindowEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
+setup_drag_move_resize_context (GdkWindow *window,
+ GdkW32DragMoveResizeContext *context,
+ GdkW32WindowDragOp op,
+ GdkWindowEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
{
- WPARAM winedge;
+ RECT rect;
- g_return_if_fail (GDK_IS_WINDOW (window));
+ _gdk_win32_get_window_rect (window, &rect);
- if (GDK_WINDOW_DESTROYED (window))
- return;
+ context->op = op;
+ context->edge = edge;
+ context->device = device;
+ context->button = button;
+ context->start_root_x = root_x;
+ context->start_root_y = root_y;
+ context->timestamp = timestamp;
+ context->start_rect = rect;
- /* Tell Windows to start interactively resizing the window by pretending that
- * the left pointer button was clicked in the suitable edge or corner. This
- * will only work if the button is down when this function is called, and
- * will only work with button 1 (left), since Windows only allows window
- * dragging using the left mouse button.
- */
- if (button != 1)
+ GDK_NOTE (EVENTS,
+ g_print ("begin drag moveresize: "
+ "op %u, edge %d, device %p, "
+ "button %d, coord %d:%d, time %u\n",
+ context->op, context->edge, context->device,
+ context->button, context->start_root_x,
+ context->start_root_y, context->timestamp));
+}
+
+void
+gdk_win32_window_end_move_resize_drag (GdkWindow *window)
+{
+ GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+ GdkW32DragMoveResizeContext *context = &impl->drag_move_resize_context;
+
+ context->op = GDK_WIN32_DRAGOP_NONE;
+ GDK_NOTE (EVENTS,
+ g_print ("end drag moveresize: "
+ "op %u, edge %d, device %p, "
+ "button %d, coord %d:%d, time %u\n",
+ context->op, context->edge, context->device,
+ context->button, context->start_root_x,
+ context->start_root_y, context->timestamp));
+}
+
+void
+gdk_win32_window_do_move_resize_drag (GdkWindow *window,
+ gint x,
+ gint y)
+{
+ RECT rect;
+ RECT new_rect;
+ gint diffy, diffx;
+ MINMAXINFO mmi;
+ GdkWindowImplWin32 *impl;
+ GdkW32DragMoveResizeContext *context;
+ gint width;
+ gint height;
+
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+ context = &impl->drag_move_resize_context;
+
+ if (!_gdk_win32_get_window_rect (window, &rect))
return;
- /* Must break the automatic grab that occured when the button was
- * pressed, otherwise it won't work.
- */
- gdk_device_ungrab (device, 0);
+ new_rect = context->start_rect;
+ diffx = x - context->start_root_x;
+ diffy = y - context->start_root_y;
- switch (edge)
+ switch (context->op)
{
- case GDK_WINDOW_EDGE_NORTH_WEST:
- winedge = HTTOPLEFT;
- break;
+ case GDK_WIN32_DRAGOP_RESIZE:
+ switch (context->edge)
+ {
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ new_rect.left += diffx;
+ new_rect.top += diffy;
+ break;
+
+ case GDK_WINDOW_EDGE_NORTH:
+ new_rect.top += diffy;
+ break;
+
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ new_rect.right += diffx;
+ new_rect.top += diffy;
+ break;
+
+ case GDK_WINDOW_EDGE_WEST:
+ new_rect.left += diffx;
+ break;
+
+ case GDK_WINDOW_EDGE_EAST:
+ new_rect.right += diffx;
+ break;
+
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ new_rect.left += diffx;
+ new_rect.bottom += diffy;
+ break;
+
+ case GDK_WINDOW_EDGE_SOUTH:
+ new_rect.bottom += diffy;
+ break;
+
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ default:
+ new_rect.right += diffx;
+ new_rect.bottom += diffy;
+ break;
+ }
- case GDK_WINDOW_EDGE_NORTH:
- winedge = HTTOP;
- break;
+ /* When handling WM_GETMINMAXINFO, mmi is already populated
+ * by W32 WM and we apply our stuff on top of that.
+ * Here it isn't, so we should at least clear it.
+ */
+ memset (&mmi, 0, sizeof (mmi));
- case GDK_WINDOW_EDGE_NORTH_EAST:
- winedge = HTTOPRIGHT;
- break;
+ if (!_gdk_win32_window_fill_min_max_info (window, &mmi))
+ break;
- case GDK_WINDOW_EDGE_WEST:
- winedge = HTLEFT;
- break;
+ width = new_rect.right - new_rect.left;
+ height = new_rect.bottom - new_rect.top;
- case GDK_WINDOW_EDGE_EAST:
- winedge = HTRIGHT;
- break;
+ if (width > mmi.ptMaxTrackSize.x)
+ {
+ switch (context->edge)
+ {
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ case GDK_WINDOW_EDGE_WEST:
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ new_rect.left = new_rect.right - mmi.ptMaxTrackSize.x;
+ break;
+
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ case GDK_WINDOW_EDGE_EAST:
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ default:
+ new_rect.right = new_rect.left + mmi.ptMaxTrackSize.x;
+ break;
+ }
+ }
+ else if (width < mmi.ptMinTrackSize.x)
+ {
+ switch (context->edge)
+ {
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ case GDK_WINDOW_EDGE_WEST:
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ new_rect.left = new_rect.right - mmi.ptMinTrackSize.x;
+ break;
+
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ case GDK_WINDOW_EDGE_EAST:
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ default:
+ new_rect.right = new_rect.left + mmi.ptMinTrackSize.x;
+ break;
+ }
+ }
- case GDK_WINDOW_EDGE_SOUTH_WEST:
- winedge = HTBOTTOMLEFT;
- break;
+ if (height > mmi.ptMaxTrackSize.y)
+ {
+ switch (context->edge)
+ {
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ case GDK_WINDOW_EDGE_NORTH:
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ new_rect.top = new_rect.bottom - mmi.ptMaxTrackSize.y;
+
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ case GDK_WINDOW_EDGE_SOUTH:
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ default:
+ new_rect.bottom = new_rect.top + mmi.ptMaxTrackSize.y;
+ break;
+ }
+ }
+ else if (height < mmi.ptMinTrackSize.y)
+ {
+ switch (context->edge)
+ {
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ case GDK_WINDOW_EDGE_NORTH:
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ new_rect.top = new_rect.bottom - mmi.ptMinTrackSize.y;
+
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ case GDK_WINDOW_EDGE_SOUTH:
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ default:
+ new_rect.bottom = new_rect.top + mmi.ptMinTrackSize.y;
+ break;
+ }
+ }
- case GDK_WINDOW_EDGE_SOUTH:
- winedge = HTBOTTOM;
break;
-
- case GDK_WINDOW_EDGE_SOUTH_EAST:
+ case GDK_WIN32_DRAGOP_MOVE:
+ new_rect.left += diffx;
+ new_rect.top += diffy;
+ new_rect.right += diffx;
+ new_rect.bottom += diffy;
+ break;
default:
- winedge = HTBOTTOMRIGHT;
break;
}
- DefWindowProcW (GDK_WINDOW_HWND (window), WM_NCLBUTTONDOWN, winedge,
- MAKELPARAM (root_x - _gdk_offset_x, root_y - _gdk_offset_y));
+ if (context->op == GDK_WIN32_DRAGOP_RESIZE &&
+ (rect.left != new_rect.left ||
+ rect.right != new_rect.right ||
+ rect.top != new_rect.top ||
+ rect.bottom != new_rect.bottom))
+ {
+ context->native_move_resize_pending = TRUE;
+ _gdk_win32_do_emit_configure_event (window, new_rect);
+ }
+ else if (context->op == GDK_WIN32_DRAGOP_MOVE &&
+ (rect.left != new_rect.left ||
+ rect.top != new_rect.top))
+ {
+ POINT window_position;
+
+ context->native_move_resize_pending = FALSE;
+
+ _gdk_win32_do_emit_configure_event (window, new_rect);
+
+ /* Turn client area into window area */
+ _gdk_win32_adjust_client_rect (window, &new_rect);
+
+ /* Convert GDK screen coordinates to W32 desktop coordinates */
+ new_rect.left -= _gdk_offset_x;
+ new_rect.right -= _gdk_offset_x;
+ new_rect.top -= _gdk_offset_y;
+ new_rect.bottom -= _gdk_offset_y;
+
+ window_position.x = new_rect.left;
+ window_position.y = new_rect.top;
+
+ /* Move immediately, no need to wait for redraw */
+ API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ window_position.x, window_position.y,
+ 0, 0,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE));
+ }
+}
+
+static void
+gdk_win32_window_begin_resize_drag (GdkWindow *window,
+ GdkWindowEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkWindowImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ if (GDK_WINDOW_DESTROYED (window) ||
+ GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
+ IsIconic (GDK_WINDOW_HWND (window)))
+ return;
+
+ /* Tell Windows to start interactively resizing the window by pretending that
+ * the left pointer button was clicked in the suitable edge or corner. This
+ * will only work if the button is down when this function is called, and
+ * will only work with button 1 (left), since Windows only allows window
+ * dragging using the left mouse button.
+ */
+ if (button != 1)
+ return;
+
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+ gdk_win32_window_end_move_resize_drag (window);
+
+ setup_drag_move_resize_context (window, &impl->drag_move_resize_context,
+ GDK_WIN32_DRAGOP_RESIZE, edge, device,
+ button, root_x, root_y, timestamp);
}
static void
gdk_win32_window_begin_move_drag (GdkWindow *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
{
+ GdkWindowImplWin32 *impl;
+
g_return_if_fail (GDK_IS_WINDOW (window));
- if (GDK_WINDOW_DESTROYED (window))
+ if (GDK_WINDOW_DESTROYED (window) ||
+ GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
+ IsIconic (GDK_WINDOW_HWND (window)))
return;
/* Tell Windows to start interactively moving the window by pretending that
@@ -2730,13 +2996,14 @@ gdk_win32_window_begin_move_drag (GdkWindow *window,
if (button != 1)
return;
- /* Must break the automatic grab that occured when the button was pressed,
- * otherwise it won't work.
- */
- gdk_device_ungrab (device, 0);
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+ gdk_win32_window_end_move_resize_drag (window);
- DefWindowProcW (GDK_WINDOW_HWND (window), WM_NCLBUTTONDOWN, HTCAPTION,
- MAKELPARAM (root_x - _gdk_offset_x, root_y - _gdk_offset_y));
+ setup_drag_move_resize_context (window, &impl->drag_move_resize_context,
+ GDK_WIN32_DRAGOP_MOVE, GDK_WINDOW_EDGE_NORTH_WEST,
+ device, button, root_x, root_y, timestamp);
}
@@ -3447,6 +3714,7 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
impl_class->destroy_foreign = gdk_win32_window_destroy_foreign;
impl_class->get_shape = gdk_win32_window_get_shape;
//FIXME?: impl_class->get_input_shape = gdk_win32_window_get_input_shape;
+ impl_class->end_paint = gdk_win32_window_end_paint;
//impl_class->beep = gdk_x11_window_beep;
diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h
index 8f17ead..b7389f1 100644
--- a/gdk/win32/gdkwindow-win32.h
+++ b/gdk/win32/gdkwindow-win32.h
@@ -46,6 +46,53 @@ 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 _GdkW32WindowDragOp
+{
+ GDK_WIN32_DRAGOP_NONE = 0,
+ GDK_WIN32_DRAGOP_RESIZE,
+ GDK_WIN32_DRAGOP_MOVE,
+ GDK_WIN32_DRAGOP_COUNT
+};
+
+typedef enum _GdkW32WindowDragOp GdkW32WindowDragOp;
+
+struct _GdkW32DragMoveResizeContext
+{
+ /* The kind of drag-operation going on. */
+ GdkW32WindowDragOp op;
+
+ /* The edge that was grabbed for resizing. Not used for moving. */
+ GdkWindowEdge edge;
+
+ /* Not used */
+ GdkDevice *device;
+
+ /* Not used */
+ gint button;
+
+ /* Initial cursor position when the operation began.
+ * Current cursor position is subtracted from it to find how far
+ * to move window border(s).
+ */
+ gint start_root_x;
+ gint start_root_y;
+
+ /* Initial window rectangle (position and size).
+ * The window is resized/moved relative to this (see start_root_*).
+ */
+ RECT start_rect;
+
+ /* Not used */
+ guint32 timestamp;
+
+ /* TRUE if during the next redraw we should call SetWindowPos() to push
+ * the window size and poistion to the native window.
+ */
+ gboolean native_move_resize_pending;
+};
+
+typedef struct _GdkW32DragMoveResizeContext GdkW32DragMoveResizeContext;
+
struct _GdkWindowImplWin32
{
GdkWindowImpl parent_instance;
@@ -83,6 +130,8 @@ struct _GdkWindowImplWin32
HDC hdc;
int hdc_count;
HBITMAP saved_dc_bitmap; /* Original bitmap for dc */
+
+ GdkW32DragMoveResizeContext drag_move_resize_context;
};
struct _GdkWindowImplWin32Class
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]