--- /dev/null
+diff -Nuard metacity-2.6.3.orig/README metacity-2.6.3/README
+--- metacity-2.6.3.orig/README 2003-09-08 21:42:02.000000000 +0200
++++ metacity-2.6.3/README 2003-12-03 21:24:03.603521208 +0100
+@@ -370,12 +370,11 @@
+ http://pobox.com/~hp/free-software-ui.html
+ http://pobox.com/~hp/features.html
+
+-Q: Why no wireframe move/resize?
++Q: Why does wireframe move/resize suck?
+
+-A: It's implemented in a patch that will be merged for GNOME 2.6
+- and is already in some vendor packages.
++A: You can turn it on with the reduced_resources setting.
+
+- But: Because it has low usability, and is a pain
++ But: it has low usability, and is a pain
+ to implement, and there's no reason opaque move/resize should be a
+ problem on any setup that can run a modern desktop worth a darn to
+ begin with.
+diff -Nuard metacity-2.6.3.orig/src/display.c metacity-2.6.3/src/display.c
+--- metacity-2.6.3.orig/src/display.c 2003-10-13 22:15:40.000000000 +0200
++++ metacity-2.6.3/src/display.c 2003-12-03 21:24:03.606520752 +0100
+@@ -35,6 +35,7 @@
+ #include "resizepopup.h"
+ #include "workspace.h"
+ #include "bell.h"
++#include "effects.h"
+ #include <X11/Xatom.h>
+ #include <X11/cursorfont.h>
+ #ifdef HAVE_SOLARIS_XINERAMA
+@@ -1219,7 +1220,8 @@
+ * goes to the frame.
+ */
+ frame_was_receiver = TRUE;
+- meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event\n");
++ meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n",
++ window->desc);
+ }
+
+ #ifdef HAVE_XSYNC
+@@ -1231,6 +1233,7 @@
+
+ if (display->grab_op != META_GRAB_OP_NONE &&
+ display->grab_window != NULL &&
++ event->xany.serial > display->grab_start_serial &&
+ grab_op_is_mouse (display->grab_op))
+ meta_window_handle_mouse_grab_op_event (display->grab_window, event);
+ }
+@@ -1296,7 +1299,8 @@
+ case ButtonPress:
+ if ((window &&
+ grab_op_is_mouse (display->grab_op) &&
+- display->grab_button != (int) event->xbutton.button &&
++ display->grab_button != (int) event->xbutton.button &&
++ event->xany.serial > display->grab_start_serial &&
+ display->grab_window == window) ||
+ grab_op_is_keyboard (display->grab_op))
+ {
+@@ -1455,16 +1459,19 @@
+ break;
+ case ButtonRelease:
+ if (display->grab_window == window &&
++ event->xany.serial > display->grab_start_serial &&
+ grab_op_is_mouse (display->grab_op))
+ meta_window_handle_mouse_grab_op_event (window, event);
+ break;
+ case MotionNotify:
+ if (display->grab_window == window &&
++ event->xany.serial > display->grab_start_serial &&
+ grab_op_is_mouse (display->grab_op))
+ meta_window_handle_mouse_grab_op_event (window, event);
+ break;
+ case EnterNotify:
+ if (display->grab_window == window &&
++ event->xany.serial > display->grab_start_serial &&
+ grab_op_is_mouse (display->grab_op))
+ meta_window_handle_mouse_grab_op_event (window, event);
+ /* do this even if window->has_focus to avoid races */
+@@ -1528,6 +1535,7 @@
+ break;
+ case LeaveNotify:
+ if (display->grab_window == window &&
++ event->xany.serial > display->grab_start_serial &&
+ grab_op_is_mouse (display->grab_op))
+ meta_window_handle_mouse_grab_op_event (window, event);
+ else if (window != NULL)
+@@ -2806,8 +2814,9 @@
+ Window grab_xwindow;
+
+ meta_topic (META_DEBUG_WINDOW_OPS,
+- "Doing grab op %d on window %s button %d pointer already grabbed: %d\n",
+- op, window ? window->desc : "none", button, pointer_already_grabbed);
++ "Doing grab op %d on window %s button %d pointer already grabbed: %d pointer pos %d,%d\n",
++ op, window ? window->desc : "none", button, pointer_already_grabbed,
++ root_x, root_y);
+
+ if (display->grab_op != META_GRAB_OP_NONE)
+ {
+@@ -2817,6 +2826,9 @@
+ return FALSE;
+ }
+
++ /* We'll ignore any events < this serial. */
++ display->grab_start_serial = XNextRequest (display->xdisplay);
++
+ /* FIXME:
+ * If we have no MetaWindow we do our best
+ * and try to do the grab on the RootWindow.
+@@ -2832,7 +2844,7 @@
+
+ if (pointer_already_grabbed)
+ display->grab_have_pointer = TRUE;
+-
++
+ meta_display_set_grab_op_cursor (display, screen, op, FALSE, grab_xwindow,
+ timestamp);
+
+@@ -2869,8 +2881,8 @@
+ display->grab_xwindow = grab_xwindow;
+ display->grab_button = button;
+ display->grab_mask = modmask;
+- display->grab_initial_root_x = root_x;
+- display->grab_initial_root_y = root_y;
++ display->grab_anchor_root_x = root_x;
++ display->grab_anchor_root_y = root_y;
+ display->grab_latest_motion_x = root_x;
+ display->grab_latest_motion_y = root_y;
+ display->grab_last_moveresize_time.tv_sec = 0;
+@@ -2879,6 +2891,7 @@
+ #ifdef HAVE_XSYNC
+ display->grab_update_alarm = None;
+ #endif
++ display->grab_was_cancelled = FALSE;
+
+ if (display->grab_window)
+ {
+@@ -2886,9 +2899,34 @@
+ meta_window_get_position (display->grab_window,
+ &display->grab_initial_window_pos.x,
+ &display->grab_initial_window_pos.y);
++ display->grab_anchor_window_pos = display->grab_initial_window_pos;
+
++ display->grab_wireframe_active =
++ meta_prefs_get_reduced_resources () &&
++ (meta_grab_op_is_resizing (display->grab_op) ||
++ meta_grab_op_is_moving (display->grab_op));
++
++ if (display->grab_wireframe_active)
++ {
++ /* FIXME we should really display the outer frame rect,
++ * but that complicates all the move/resize code since
++ * it works in terms of window rect.
++ */
++ display->grab_wireframe_rect = window->rect;
++ if (window->frame)
++ {
++ display->grab_wireframe_rect.x += window->frame->rect.x;
++ display->grab_wireframe_rect.y += window->frame->rect.y;
++ }
++
++ meta_window_calc_showing (display->grab_window);
++ meta_effects_begin_wireframe (display->grab_window->screen,
++ &display->grab_wireframe_rect);
++ }
++
+ #ifdef HAVE_XSYNC
+- if (meta_grab_op_is_resizing (display->grab_op) &&
++ if (!display->grab_wireframe_active &&
++ meta_grab_op_is_resizing (display->grab_op) &&
+ display->grab_window->update_counter != None)
+ {
+ XSyncAlarmAttributes values;
+@@ -3018,6 +3056,21 @@
+ display->grab_update_alarm);
+ }
+ #endif /* HAVE_XSYNC */
++
++ if (display->grab_wireframe_active)
++ {
++ display->grab_wireframe_active = FALSE;
++ meta_effects_end_wireframe (display->grab_window->screen,
++ &display->grab_wireframe_rect);
++ if (!display->grab_was_cancelled)
++ meta_window_move_resize (display->grab_window,
++ TRUE,
++ display->grab_wireframe_rect.x,
++ display->grab_wireframe_rect.y,
++ display->grab_wireframe_rect.width,
++ display->grab_wireframe_rect.height);
++ meta_window_calc_showing (display->grab_window);
++ }
+
+ display->grab_window = NULL;
+ display->grab_screen = NULL;
+diff -Nuard metacity-2.6.3.orig/src/display.h metacity-2.6.3/src/display.h
+--- metacity-2.6.3.orig/src/display.h 2003-10-13 22:15:40.000000000 +0200
++++ metacity-2.6.3/src/display.h 2003-12-03 21:24:03.607520600 +0100
+@@ -225,19 +225,24 @@
+ MetaScreen *grab_screen;
+ MetaWindow *grab_window;
+ Window grab_xwindow;
++ gulong grab_start_serial;
+ int grab_button;
+- int grab_initial_root_x;
+- int grab_initial_root_y;
++ int grab_anchor_root_x;
++ int grab_anchor_root_y;
++ MetaRectangle grab_anchor_window_pos;
+ int grab_latest_motion_x;
+ int grab_latest_motion_y;
+ gulong grab_mask;
+ guint grab_have_pointer : 1;
+ guint grab_have_keyboard : 1;
++ guint grab_wireframe_active : 1;
++ guint grab_was_cancelled : 1;
++ MetaRectangle grab_wireframe_rect;
+ MetaRectangle grab_initial_window_pos;
+ MetaResizePopup *grab_resize_popup;
+ GTimeVal grab_last_moveresize_time;
+ Time grab_motion_notify_time;
+-
++
+ /* we use property updates as sentinels for certain window focus events
+ * to avoid some race conditions on EnterNotify events
+ */
+diff -Nuard metacity-2.6.3.orig/src/effects.c metacity-2.6.3/src/effects.c
+--- metacity-2.6.3.orig/src/effects.c 2002-10-19 00:46:37.000000000 +0200
++++ metacity-2.6.3/src/effects.c 2003-12-03 21:24:03.608520448 +0100
+@@ -409,5 +409,108 @@
+ XFlush (context->screen->display->xdisplay);
+ }
+
++void
++meta_effects_begin_wireframe (MetaScreen *screen,
++ const MetaRectangle *rect)
++{
++ /* Grab the X server to avoid screen dirt */
++ meta_display_grab (screen->display);
++ meta_ui_push_delay_exposes (screen->ui);
++
++ meta_effects_update_wireframe (screen, NULL, rect);
++}
++
++static void
++draw_xor_rect (MetaScreen *screen,
++ const MetaRectangle *rect)
++{
++ /* The lines in the center can't overlap the rectangle or each
++ * other, or the XOR gets reversed. So we have to draw things
++ * a bit oddly.
++ */
++ XSegment segments[8];
++ int i;
++
++#define LINE_WIDTH META_WIREFRAME_XOR_LINE_WIDTH
++
++ XDrawRectangle (screen->display->xdisplay,
++ screen->xroot,
++ screen->root_xor_gc,
++ rect->x, rect->y,
++ rect->width, rect->height);
++
++ /* Don't put lines inside small rectangles where they won't fit */
++ if (rect->width < (LINE_WIDTH * 4) ||
++ rect->height < (LINE_WIDTH * 4))
++ return;
++
++ /* Two vertical lines at 1/3 and 2/3 */
++ segments[0].x1 = rect->x + rect->width / 3;
++ segments[0].y1 = rect->y + LINE_WIDTH / 2 + LINE_WIDTH % 2;
++ segments[0].x2 = segments[0].x1;
++ segments[0].y2 = rect->y + rect->height - LINE_WIDTH / 2;
+
++ segments[1] = segments[0];
++ segments[1].x1 = rect->x + (rect->width / 3) * 2;
++ segments[1].x2 = segments[1].x1;
++
++ /* Now make two horizontal lines at 1/3 and 2/3, but not
++ * overlapping the verticals
++ */
++
++ segments[2].x1 = rect->x + LINE_WIDTH / 2 + LINE_WIDTH % 2;
++ segments[2].x2 = segments[0].x1 - LINE_WIDTH / 2;
++ segments[2].y1 = rect->y + rect->height / 3;
++ segments[2].y2 = segments[2].y1;
++
++ segments[3] = segments[2];
++ segments[3].x1 = segments[2].x2 + LINE_WIDTH;
++ segments[3].x2 = segments[1].x1 - LINE_WIDTH / 2;
++
++ segments[4] = segments[3];
++ segments[4].x1 = segments[3].x2 + LINE_WIDTH;
++ segments[4].x2 = rect->x + rect->width - LINE_WIDTH / 2;
++
++ /* Second horizontal line is just like the first, but
++ * shifted down
++ */
++ i = 5;
++ while (i < 8)
++ {
++ segments[i] = segments[i - 3];
++ segments[i].y1 = rect->y + (rect->height / 3) * 2;
++ segments[i].y2 = segments[i].y1;
++ ++i;
++ }
++
++ XDrawSegments (screen->display->xdisplay,
++ screen->xroot,
++ screen->root_xor_gc,
++ segments,
++ G_N_ELEMENTS (segments));
++}
++
++void
++meta_effects_update_wireframe (MetaScreen *screen,
++ const MetaRectangle *old_rect,
++ const MetaRectangle *new_rect)
++{
++ if (old_rect)
++ draw_xor_rect (screen, old_rect);
++
++ if (new_rect)
++ draw_xor_rect (screen, new_rect);
++
++ XFlush (screen->display->xdisplay);
++}
++
++void
++meta_effects_end_wireframe (MetaScreen *screen,
++ const MetaRectangle *old_rect)
++{
++ meta_effects_update_wireframe (screen, old_rect, NULL);
++
++ meta_display_ungrab (screen->display);
++ meta_ui_pop_delay_exposes (screen->ui);
++}
+
+diff -Nuard metacity-2.6.3.orig/src/effects.h metacity-2.6.3/src/effects.h
+--- metacity-2.6.3.orig/src/effects.h 2002-09-30 05:49:22.000000000 +0200
++++ metacity-2.6.3/src/effects.h 2003-12-03 21:24:03.608520448 +0100
+@@ -41,4 +41,12 @@
+ double seconds_duration,
+ MetaBoxAnimType anim_type);
+
++void meta_effects_begin_wireframe (MetaScreen *screen,
++ const MetaRectangle *rect);
++void meta_effects_update_wireframe (MetaScreen *screen,
++ const MetaRectangle *old_rect,
++ const MetaRectangle *new_rect);
++void meta_effects_end_wireframe (MetaScreen *screen,
++ const MetaRectangle *old_rect);
++
+ #endif /* META_EFFECTS_H */
+diff -Nuard metacity-2.6.3.orig/src/frames.c metacity-2.6.3/src/frames.c
+--- metacity-2.6.3.orig/src/frames.c 2003-08-16 18:32:10.000000000 +0200
++++ metacity-2.6.3/src/frames.c 2003-12-03 21:24:03.610520144 +0100
+@@ -2110,6 +2110,13 @@
+ void
+ meta_frames_push_delay_exposes (MetaFrames *frames)
+ {
++ if (frames->expose_delay_count == 0)
++ {
++ /* Make sure we've repainted things */
++ gdk_window_process_all_updates ();
++ XFlush (gdk_display);
++ }
++
+ frames->expose_delay_count += 1;
+ }
+
+diff -Nuard metacity-2.6.3.orig/src/keybindings.c metacity-2.6.3/src/keybindings.c
+--- metacity-2.6.3.orig/src/keybindings.c 2003-09-29 18:55:25.000000000 +0200
++++ metacity-2.6.3/src/keybindings.c 2003-12-03 21:24:03.613519688 +0100
+@@ -27,6 +27,7 @@
+ #include "frame.h"
+ #include "place.h"
+ #include "prefs.h"
++#include "effects.h"
+
+ #include <X11/keysym.h>
+ #include <string.h>
+@@ -1693,10 +1694,24 @@
+ if (is_modifier (display, event->xkey.keycode))
+ return TRUE;
+
+- meta_window_get_position (window, &x, &y);
++ if (display->grab_wireframe_active)
++ {
++ x = display->grab_wireframe_rect.x;
++ y = display->grab_wireframe_rect.y;
++ }
++ else
++ {
++ meta_window_get_position (window, &x, &y);
++ }
+
++ /* FIXME in wireframe mode the edge snapping is all fucked up
++ * since the edge-find routines use window->rect. Window
++ * constraints are also broken with wireframe.
++ */
+ smart_snap = (event->xkey.state & ShiftMask) != 0;
+-
++ if (display->grab_wireframe_active)
++ smart_snap = FALSE;
++
+ #define SMALL_INCREMENT 1
+ #define NORMAL_INCREMENT 10
+
+@@ -1709,13 +1724,18 @@
+
+ if (keysym == XK_Escape)
+ {
+- /* End move and restore to original position */
++ /* End resize and restore to original state.
++ * The move_resize is only needed when !wireframe
++ * since in wireframe we always moveresize at the end
++ * of the grab only.
++ */
+ meta_window_move_resize (display->grab_window,
+ TRUE,
+ display->grab_initial_window_pos.x,
+ display->grab_initial_window_pos.y,
+ display->grab_initial_window_pos.width,
+ display->grab_initial_window_pos.height);
++ display->grab_was_cancelled = TRUE;
+ }
+
+ /* When moving by increments, we still snap to edges if the move
+@@ -1729,11 +1749,14 @@
+ case XK_KP_Prior:
+ case XK_Up:
+ case XK_KP_Up:
+- edge = meta_window_find_next_horizontal_edge (window, FALSE);
+ y -= incr;
+-
+- if (smart_snap || ((edge > y) && ABS (edge - y) < incr))
+- y = edge;
++
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_horizontal_edge (window, FALSE);
++ if (smart_snap || ((edge > y) && ABS (edge - y) < incr))
++ y = edge;
++ }
+
+ handled = TRUE;
+ break;
+@@ -1741,11 +1764,14 @@
+ case XK_KP_Next:
+ case XK_Down:
+ case XK_KP_Down:
+- edge = meta_window_find_next_horizontal_edge (window, TRUE);
+ y += incr;
+
+- if (smart_snap || ((edge < y) && ABS (edge - y) < incr))
+- y = edge;
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_horizontal_edge (window, TRUE);
++ if (smart_snap || ((edge < y) && ABS (edge - y) < incr))
++ y = edge;
++ }
+
+ handled = TRUE;
+ break;
+@@ -1757,11 +1783,14 @@
+ case XK_KP_End:
+ case XK_Left:
+ case XK_KP_Left:
+- edge = meta_window_find_next_vertical_edge (window, FALSE);
+ x -= incr;
+-
+- if (smart_snap || ((edge > x) && ABS (edge - x) < incr))
+- x = edge;
++
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_vertical_edge (window, FALSE);
++ if (smart_snap || ((edge > x) && ABS (edge - x) < incr))
++ x = edge;
++ }
+
+ handled = TRUE;
+ break;
+@@ -1769,18 +1798,43 @@
+ case XK_KP_Next:
+ case XK_Right:
+ case XK_KP_Right:
+- edge = meta_window_find_next_vertical_edge (window, TRUE);
+ x += incr;
+- if (smart_snap || ((edge < x) && ABS (edge - x) < incr))
+- x = edge;
++
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_vertical_edge (window, TRUE);
++ if (smart_snap || ((edge < x) && ABS (edge - x) < incr))
++ x = edge;
++ }
++
+ handled = TRUE;
+ break;
+ }
+
+ if (handled)
+ {
+- meta_window_move (window, TRUE, x, y);
+- meta_window_warp_pointer (window, display->grab_op);
++ meta_topic (META_DEBUG_KEYBINDINGS,
++ "Computed new window location %d,%d due to keypress\n",
++ x, y);
++ if (display->grab_wireframe_active)
++ {
++ MetaRectangle new_xor;
++
++ new_xor = display->grab_wireframe_rect;
++ new_xor.x = x;
++ new_xor.y = y;
++
++ meta_effects_update_wireframe (window->screen,
++ &display->grab_wireframe_rect,
++ &new_xor);
++ display->grab_wireframe_rect = new_xor;
++ }
++ else
++ {
++ meta_window_move (window, TRUE, x, y);
++ }
++
++ meta_window_update_keyboard_move (window);
+ }
+
+ return handled;
+@@ -1815,13 +1869,18 @@
+
+ if (keysym == XK_Escape)
+ {
+- /* End resize and restore to original state */
++ /* End resize and restore to original state.
++ * The move_resize is only needed when !wireframe
++ * since in wireframe we always moveresize at the end
++ * of the grab only.
++ */
+ meta_window_move_resize (display->grab_window,
+ TRUE,
+ display->grab_initial_window_pos.x,
+ display->grab_initial_window_pos.y,
+ display->grab_initial_window_pos.width,
+ display->grab_initial_window_pos.height);
++ display->grab_was_cancelled = TRUE;
+
+ return FALSE;
+ }
+@@ -1931,20 +1990,38 @@
+
+ if (handled)
+ {
+- meta_window_update_resize_grab_op (window, TRUE);
++ meta_window_update_keyboard_resize (window, TRUE);
+ return TRUE;
+- }
++ }
+
+- meta_window_get_position (window, &orig_x, &orig_y);
+- x = orig_x;
+- y = orig_y;
+- width = window->rect.width;
+- height = window->rect.height;
++ if (display->grab_wireframe_active)
++ {
++ x = display->grab_wireframe_rect.x;
++ y = display->grab_wireframe_rect.y;
++ orig_x = x;
++ orig_y = y;
++ width = display->grab_wireframe_rect.width;
++ height = display->grab_wireframe_rect.height;
++ }
++ else
++ {
++ meta_window_get_position (window, &orig_x, &orig_y);
++ x = orig_x;
++ y = orig_y;
++ width = window->rect.width;
++ height = window->rect.height;
++ }
+
+ gravity = meta_resize_gravity_from_grab_op (display->grab_op);
+-
+- smart_snap = (event->xkey.state & ShiftMask) != 0;
+
++ /* FIXME in wireframe mode the edge snapping is all fucked up
++ * since the edge-find routines use window->rect. Window
++ * constraints are also broken with wireframe.
++ */
++ smart_snap = (event->xkey.state & ShiftMask) != 0;
++ if (display->grab_wireframe_active)
++ smart_snap = FALSE;
++
+ #define SMALL_INCREMENT 1
+ #define NORMAL_INCREMENT 10
+
+@@ -1994,12 +2071,16 @@
+ case NorthWestGravity:
+ case NorthEastGravity:
+ /* Move bottom edge up */
+- edge = meta_window_find_next_horizontal_edge (window, TRUE);
+ height -= height_inc;
+
+- if (smart_snap || ((edge > (y+height)) &&
+- ABS (edge - (y+height)) < height_inc))
+- height = edge - y;
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_horizontal_edge (window, TRUE);
++
++ if (smart_snap || ((edge > (y+height)) &&
++ ABS (edge - (y+height)) < height_inc))
++ height = edge - y;
++ }
+
+ handled = TRUE;
+ break;
+@@ -2008,11 +2089,15 @@
+ case SouthWestGravity:
+ case SouthEastGravity:
+ /* Move top edge up */
+- edge = meta_window_find_next_horizontal_edge (window, FALSE);
+ y -= height_inc;
+-
+- if (smart_snap || ((edge > y) && ABS (edge - y) < height_inc))
+- y = edge;
++
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_horizontal_edge (window, FALSE);
++
++ if (smart_snap || ((edge > y) && ABS (edge - y) < height_inc))
++ y = edge;
++ }
+
+ height += (orig_y - y);
+ break;
+@@ -2035,12 +2120,16 @@
+ case NorthWestGravity:
+ case NorthEastGravity:
+ /* Move bottom edge down */
+- edge = meta_window_find_next_horizontal_edge (window, TRUE);
+ height += height_inc;
+-
+- if (smart_snap || ((edge < (y+height)) &&
+- ABS (edge - (y+height)) < height_inc))
+- height = edge - y;
++
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_horizontal_edge (window, TRUE);
++
++ if (smart_snap || ((edge < (y+height)) &&
++ ABS (edge - (y+height)) < height_inc))
++ height = edge - y;
++ }
+
+ handled = TRUE;
+ break;
+@@ -2049,11 +2138,15 @@
+ case SouthWestGravity:
+ case SouthEastGravity:
+ /* Move top edge down */
+- edge = meta_window_find_next_horizontal_edge (window, FALSE);
+ y += height_inc;
+-
+- if (smart_snap || ((edge < y) && ABS (edge - y) < height_inc))
+- y = edge;
++
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_horizontal_edge (window, FALSE);
++
++ if (smart_snap || ((edge < y) && ABS (edge - y) < height_inc))
++ y = edge;
++ }
+
+ height -= (y - orig_y);
+ break;
+@@ -2076,11 +2169,15 @@
+ case SouthEastGravity:
+ case NorthEastGravity:
+ /* Move left edge left */
+- edge = meta_window_find_next_vertical_edge (window, TRUE);
+ x -= width_inc;
+
+- if (smart_snap || ((edge > x) && ABS (edge - x) < width_inc))
+- x = edge;
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_vertical_edge (window, TRUE);
++
++ if (smart_snap || ((edge > x) && ABS (edge - x) < width_inc))
++ x = edge;
++ }
+
+ width += (orig_x - x);
+ break;
+@@ -2089,12 +2186,16 @@
+ case SouthWestGravity:
+ case NorthWestGravity:
+ /* Move right edge left */
+- edge = meta_window_find_next_vertical_edge (window, FALSE);
+ width -= width_inc;
+
+- if (smart_snap || ((edge > (x+width)) &&
+- ABS (edge - (x+width)) < width_inc))
+- width = edge - x;
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_vertical_edge (window, FALSE);
++
++ if (smart_snap || ((edge > (x+width)) &&
++ ABS (edge - (x+width)) < width_inc))
++ width = edge - x;
++ }
+
+ handled = TRUE;
+ break;
+@@ -2117,11 +2218,15 @@
+ case SouthEastGravity:
+ case NorthEastGravity:
+ /* Move left edge right */
+- edge = meta_window_find_next_vertical_edge (window, FALSE);
+ x += width_inc;
+-
+- if (smart_snap || ((edge < x) && ABS (edge - x) < width_inc))
+- x = edge;
++
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_vertical_edge (window, FALSE);
++
++ if (smart_snap || ((edge < x) && ABS (edge - x) < width_inc))
++ x = edge;
++ }
+
+ width -= (x - orig_x);
+ break;
+@@ -2130,12 +2235,16 @@
+ case SouthWestGravity:
+ case NorthWestGravity:
+ /* Move right edge right */
+- edge = meta_window_find_next_vertical_edge (window, TRUE);
+ width += width_inc;
+-
+- if (smart_snap || ((edge > (x+width)) &&
+- ABS (edge - (x+width)) < width_inc))
+- width = edge - x;
++
++ if (!display->grab_wireframe_active)
++ {
++ edge = meta_window_find_next_vertical_edge (window, TRUE);
++
++ if (smart_snap || ((edge > (x+width)) &&
++ ABS (edge - (x+width)) < width_inc))
++ width = edge - x;
++ }
+
+ handled = TRUE;
+ break;
+@@ -2162,8 +2271,32 @@
+
+ if (handled)
+ {
+- meta_window_move_resize (window, TRUE, x, y, width, height);
+- meta_window_update_resize_grab_op (window, FALSE);
++ meta_topic (META_DEBUG_KEYBINDINGS,
++ "Computed new window location %d,%d %dx%d due to keypress\n",
++ x, y, width, height);
++
++ if (display->grab_wireframe_active)
++ {
++ MetaRectangle new_xor;
++
++ new_xor.x = x;
++ new_xor.y = y;
++ new_xor.width = width;
++ new_xor.height = height;
++
++ meta_effects_update_wireframe (window->screen,
++ &window->display->grab_wireframe_rect,
++ &new_xor);
++ window->display->grab_wireframe_rect = new_xor;
++
++ /* do this after drawing the wires, so we don't draw over it */
++ meta_window_refresh_resize_popup (window);
++ }
++ else
++ {
++ meta_window_move_resize (window, TRUE, x, y, width, height);
++ }
++ meta_window_update_keyboard_resize (window, FALSE);
+ }
+
+ return handled;
+diff -Nuard metacity-2.6.3.orig/src/metacity.schemas.in metacity-2.6.3/src/metacity.schemas.in
+--- metacity-2.6.3.orig/src/metacity.schemas.in 2003-06-27 16:49:56.000000000 +0200
++++ metacity-2.6.3/src/metacity.schemas.in 2003-12-03 21:24:03.615519384 +0100
+@@ -257,6 +257,25 @@
+ </locale>
+ </schema>
+
++ <schema>
++ <key>/schemas/apps/metacity/general/reduced_resources</key>
++ <applyto>/apps/metacity/general/reduced_resources</applyto>
++ <owner>metacity</owner>
++ <type>bool</type>
++ <default>false</default>
++ <locale name="C">
++ <short>If true, trade off usability for less resource usage</short>
++ <long>
++ If true, metacity will give the user less feedback and
++ less sense of "direct manipulation", by using wireframes,
++ avoiding animations, or other means. This is a significant
++ reduction in usability for many users, but may allow
++ legacy applications and terminal servers to function
++ when they would otherwise be impractical.
++ </long>
++ </locale>
++ </schema>
++
+ <!-- Window Keybindings -->
+
+ <schema>
+diff -Nuard metacity-2.6.3.orig/src/prefs.c metacity-2.6.3/src/prefs.c
+--- metacity-2.6.3.orig/src/prefs.c 2003-06-27 16:49:56.000000000 +0200
++++ metacity-2.6.3/src/prefs.c 2003-12-03 21:24:03.617519080 +0100
+@@ -51,6 +51,7 @@
+ #define KEY_APPLICATION_BASED "/apps/metacity/general/application_based"
+ #define KEY_DISABLE_WORKAROUNDS "/apps/metacity/general/disable_workarounds"
+ #define KEY_BUTTON_LAYOUT "/apps/metacity/general/button_layout"
++#define KEY_REDUCED_RESOURCES "/apps/metacity/general/reduced_resources"
+
+ #define KEY_COMMAND_PREFIX "/apps/metacity/keybinding_commands/command_"
+ #define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings"
+@@ -83,6 +84,8 @@
+ static gboolean auto_raise_delay = 500;
+ static gboolean provide_visual_bell = TRUE;
+ static gboolean bell_is_audible = TRUE;
++static gboolean reduced_resources = FALSE;
++
+ static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_INVALID;
+ static MetaButtonLayout button_layout = {
+ {
+@@ -129,6 +132,7 @@
+ const char *value);
+ static gboolean update_workspace_name (const char *name,
+ const char *value);
++static gboolean update_reduced_resources (gboolean value);
+
+ static void change_notify (GConfClient *client,
+ guint cnxn_id,
+@@ -372,7 +376,6 @@
+ cleanup_error (&err);
+ update_button_layout (str_val);
+ g_free (str_val);
+-#endif /* HAVE_GCONF */
+
+ bool_val = gconf_client_get_bool (default_client, KEY_VISUAL_BELL,
+ &err);
+@@ -388,6 +391,12 @@
+ update_visual_bell_type (str_val);
+ g_free (str_val);
+
++ bool_val = gconf_client_get_bool (default_client, KEY_REDUCED_RESOURCES,
++ &err);
++ cleanup_error (&err);
++ update_reduced_resources (bool_val);
++#endif /* HAVE_GCONF */
++
+ /* Load keybindings prefs */
+ init_bindings ();
+
+@@ -733,6 +742,22 @@
+ if (update_visual_bell_type (str))
+ queue_changed (META_PREF_VISUAL_BELL_TYPE);
+ }
++ else if (strcmp (key, KEY_REDUCED_RESOURCES) == 0)
++ {
++ gboolean b;
++
++ if (value && value->type != GCONF_VALUE_BOOL)
++ {
++ meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
++ KEY_REDUCED_RESOURCES);
++ goto out;
++ }
++
++ b = value ? gconf_value_get_bool (value) : reduced_resources;
++
++ if (update_reduced_resources (b))
++ queue_changed (META_PREF_REDUCED_RESOURCES);
++ }
+ else
+ {
+ meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Metacity\n",
+@@ -1239,6 +1264,16 @@
+
+ return old != auto_raise_delay;
+ }
++
++static gboolean
++update_reduced_resources (gboolean value)
++{
++ gboolean old = reduced_resources;
++
++ reduced_resources = value;
++
++ return old != reduced_resources;
++}
+ #endif /* HAVE_GCONF */
+
+ #ifdef WITH_VERBOSE_MODE
+@@ -1305,6 +1340,10 @@
+ case META_PREF_VISUAL_BELL_TYPE:
+ return "VISUAL_BELL_TYPE";
+ break;
++
++ case META_PREF_REDUCED_RESOURCES:
++ return "REDUCED_RESOURCES";
++ break;
+ }
+
+ return "(unknown)";
+@@ -1974,6 +2013,12 @@
+ return auto_raise_delay;
+ }
+
++gboolean
++meta_prefs_get_reduced_resources ()
++{
++ return reduced_resources;
++}
++
+ MetaKeyBindingAction
+ meta_prefs_get_keybinding_action (const char *name)
+ {
+diff -Nuard metacity-2.6.3.orig/src/prefs.h metacity-2.6.3/src/prefs.h
+--- metacity-2.6.3.orig/src/prefs.h 2003-06-27 16:49:56.000000000 +0200
++++ metacity-2.6.3/src/prefs.h 2003-12-03 21:24:03.617519080 +0100
+@@ -45,7 +45,8 @@
+ META_PREF_WORKSPACE_NAMES,
+ META_PREF_VISUAL_BELL,
+ META_PREF_AUDIBLE_BELL,
+- META_PREF_VISUAL_BELL_TYPE
++ META_PREF_VISUAL_BELL_TYPE,
++ META_PREF_REDUCED_RESOURCES
+ } MetaPreference;
+
+ typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
+@@ -69,6 +70,7 @@
+ gboolean meta_prefs_get_disable_workarounds (void);
+ gboolean meta_prefs_get_auto_raise (void);
+ int meta_prefs_get_auto_raise_delay (void);
++gboolean meta_prefs_get_reduced_resources (void);
+
+ const char* meta_prefs_get_command (int i);
+
+diff -Nuard metacity-2.6.3.orig/src/screen.c metacity-2.6.3/src/screen.c
+--- metacity-2.6.3.orig/src/screen.c 2003-08-16 00:09:55.000000000 +0200
++++ metacity-2.6.3/src/screen.c 2003-12-03 21:25:25.123128344 +0100
+@@ -538,10 +538,23 @@
+ screen->starting_corner = META_SCREEN_TOPLEFT;
+
+ screen->showing_desktop = FALSE;
++
++ {
++ XGCValues gc_values;
++
++ gc_values.subwindow_mode = IncludeInferiors;
++ gc_values.function = GXinvert;
++ gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH;
++
++ screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
++ screen->xroot,
++ GCSubwindowMode | GCFunction | GCLineWidth,
++ &gc_values);
++ }
+
+ screen->xinerama_infos = NULL;
+ screen->n_xinerama_infos = 0;
+- screen->last_xinerama_index = 0;
++ screen->last_xinerama_index = 0;
+
+ reload_xinerama_infos (screen);
+
+@@ -679,6 +692,9 @@
+
+ if (screen->work_area_idle != 0)
+ g_source_remove (screen->work_area_idle);
++
++ XFreeGC (screen->display->xdisplay,
++ screen->root_xor_gc);
+
+ g_free (screen->screen_name);
+ g_free (screen);
+diff -Nuard metacity-2.6.3.orig/src/screen.h metacity-2.6.3/src/screen.h
+--- metacity-2.6.3.orig/src/screen.h 2003-08-16 00:09:55.000000000 +0200
++++ metacity-2.6.3/src/screen.h 2003-12-03 21:25:25.123128344 +0100
+@@ -56,6 +56,8 @@
+ META_SCREEN_RIGHT
+ } MetaScreenDirection;
+
++#define META_WIREFRAME_XOR_LINE_WIDTH 5
++
+ struct _MetaScreen
+ {
+ MetaDisplay *display;
+@@ -108,6 +110,9 @@
+ guint showing_desktop : 1;
+
+ int closing;
++
++ /* gc for XOR on root window */
++ GC root_xor_gc;
+ };
+
+ MetaScreen* meta_screen_new (MetaDisplay *display,
+diff -Nuard metacity-2.6.3.orig/src/window.c metacity-2.6.3/src/window.c
+--- metacity-2.6.3.orig/src/window.c 2003-10-26 17:22:54.000000000 +0100
++++ metacity-2.6.3/src/window.c 2003-12-03 21:25:25.323097944 +0100
+@@ -1207,6 +1207,14 @@
+ showing = FALSE;
+ }
+
++#if 0
++ /* 5. See if we're drawing wireframe
++ */
++ if (window->display->grab_window == window &&
++ window->display->grab_wireframe_active)
++ showing = FALSE;
++#endif
++
+ return showing;
+ }
+
+@@ -1231,7 +1239,8 @@
+ * if we are mapped now, we are supposed to
+ * be minimized, and we are on the current workspace.
+ */
+- if (on_workspace && window->minimized && window->mapped)
++ if (on_workspace && window->minimized && window->mapped &&
++ !meta_prefs_get_reduced_resources ())
+ {
+ MetaRectangle icon_rect, window_rect;
+ gboolean result;
+@@ -1857,7 +1866,7 @@
+ if (meta_grab_op_is_moving (window->display->grab_op) &&
+ window->display->grab_window == window)
+ {
+- window->display->grab_initial_window_pos = window->saved_rect;
++ window->display->grab_anchor_window_pos = window->saved_rect;
+ }
+
+ meta_window_move_resize (window,
+@@ -5692,7 +5701,7 @@
+ window->display->grab_last_moveresize_time = current_time;
+
+ meta_topic (META_DEBUG_RESIZING,
+- " Doing move/resize now (%g of %g seconds elapsed)\n",
++ " Checked moveresize freq, allowing move/resize now (%g of %g seconds elapsed)\n",
+ elapsed / 1000.0, 1.0 / max_resizes_per_second);
+
+ return TRUE;
+@@ -5711,12 +5720,20 @@
+ window->display->grab_latest_motion_x = x;
+ window->display->grab_latest_motion_y = y;
+
+- dx = x - window->display->grab_initial_root_x;
+- dy = y - window->display->grab_initial_root_y;
++ dx = x - window->display->grab_anchor_root_x;
++ dy = y - window->display->grab_anchor_root_y;
+
+- new_x = window->display->grab_initial_window_pos.x + dx;
+- new_y = window->display->grab_initial_window_pos.y + dy;
++ new_x = window->display->grab_anchor_window_pos.x + dx;
++ new_y = window->display->grab_anchor_window_pos.y + dy;
+
++ meta_verbose ("x,y = %d,%d anchor ptr %d,%d anchor pos %d,%d dx,dy %d,%d\n",
++ x, y,
++ window->display->grab_anchor_root_x,
++ window->display->grab_anchor_root_y,
++ window->display->grab_anchor_window_pos.x,
++ window->display->grab_anchor_window_pos.y,
++ dx, dy);
++
+ /* shake loose (unmaximize) maximized window if dragged beyond the threshold
+ * in the Y direction. You can't pull a window loose via X motion.
+ */
+@@ -5805,14 +5822,33 @@
+ if (window->maximized)
+ return;
+
+- if (mask & ShiftMask)
++ if (window->display->grab_wireframe_active)
+ {
+- /* snap to edges */
+- new_x = meta_window_find_nearest_vertical_edge (window, new_x);
+- new_y = meta_window_find_nearest_horizontal_edge (window, new_y);
+- }
++ /* FIXME Horribly broken, does not honor position
++ * constraints
++ */
++ MetaRectangle new_xor;
++ new_xor = window->display->grab_wireframe_rect;
++ new_xor.x = new_x;
++ new_xor.y = new_y;
+
+- meta_window_move (window, TRUE, new_x, new_y);
++ meta_effects_update_wireframe (window->screen,
++ &window->display->grab_wireframe_rect,
++ &new_xor);
++ window->display->grab_wireframe_rect = new_xor;
++ }
++ else
++ {
++ /* FIXME, edge snapping broken in wireframe mode */
++ if (mask & ShiftMask)
++ {
++ /* snap to edges */
++ new_x = meta_window_find_nearest_vertical_edge (window, new_x);
++ new_y = meta_window_find_nearest_horizontal_edge (window, new_y);
++ }
++
++ meta_window_move (window, TRUE, new_x, new_y);
++ }
+ }
+
+ static void
+@@ -5823,16 +5859,21 @@
+ int new_w, new_h;
+ int gravity;
+ MetaRectangle old;
++ int new_x, new_y;
+
+ window->display->grab_latest_motion_x = x;
+ window->display->grab_latest_motion_y = y;
+
+- dx = x - window->display->grab_initial_root_x;
+- dy = y - window->display->grab_initial_root_y;
++ dx = x - window->display->grab_anchor_root_x;
++ dy = y - window->display->grab_anchor_root_y;
+
+- new_w = window->display->grab_initial_window_pos.width;
+- new_h = window->display->grab_initial_window_pos.height;
++ new_w = window->display->grab_anchor_window_pos.width;
++ new_h = window->display->grab_anchor_window_pos.height;
+
++ /* FIXME this is only used in wireframe mode */
++ new_x = window->display->grab_anchor_window_pos.x;
++ new_y = window->display->grab_anchor_window_pos.y;
++
+ switch (window->display->grab_op)
+ {
+ case META_GRAB_OP_RESIZING_SE:
+@@ -5851,6 +5892,7 @@
+ case META_GRAB_OP_KEYBOARD_RESIZING_SW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_W:
+ new_w -= dx;
++ new_x += dx;
+ break;
+
+ default:
+@@ -5875,6 +5917,7 @@
+ case META_GRAB_OP_KEYBOARD_RESIZING_NE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NW:
+ new_h -= dy;
++ new_y += dy;
+ break;
+ default:
+ break;
+@@ -5884,12 +5927,42 @@
+ return;
+
+ old = window->rect;
+-
++
+ /* compute gravity of client during operation */
+ gravity = meta_resize_gravity_from_grab_op (window->display->grab_op);
+ g_assert (gravity >= 0);
+
+- meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity);
++ if (window->display->grab_wireframe_active)
++ {
++ /* FIXME This is crap. For example, the wireframe isn't
++ * constrained in the way that a real resize would be. An
++ * obvious elegant solution is to unmap the window during
++ * wireframe, but still resize it; however, that probably
++ * confuses broken clients that have problems with opaque
++ * resize, they probably don't track their visibility.
++ */
++ MetaRectangle new_xor;
++
++ if ((new_x + new_w <= new_x) || (new_y + new_h <= new_y))
++ return;
++
++ new_xor.x = new_x;
++ new_xor.y = new_y;
++ new_xor.width = new_w;
++ new_xor.height = new_h;
++
++ meta_effects_update_wireframe (window->screen,
++ &window->display->grab_wireframe_rect,
++ &new_xor);
++ window->display->grab_wireframe_rect = new_xor;
++
++ /* do this after drawing the wires, so we don't draw over it */
++ meta_window_refresh_resize_popup (window);
++ }
++ else
++ {
++ meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity);
++ }
+
+ /* If we don't actually resize the window, we clear the timestamp,
+ * so we'll quickly try again. Otherwise you get "stuck" because
+@@ -6291,6 +6364,13 @@
+ if (window->display->grab_window != window)
+ return;
+
++ /* FIXME for now we bail out when doing wireframe, because our
++ * server grab keeps us from being able to redraw the stuff
++ * underneath the resize popup.
++ */
++ if (window->display->grab_wireframe_active)
++ return;
++
+ switch (window->display->grab_op)
+ {
+ case META_GRAB_OP_RESIZING_SE:
+@@ -6329,7 +6409,7 @@
+ if (window->display->grab_resize_popup != NULL)
+ {
+ int gravity;
+- int x, y;
++ int x, y, width, height;
+ MetaFrameGeometry fgeom;
+
+ if (window->frame)
+@@ -6345,13 +6425,24 @@
+ gravity = meta_resize_gravity_from_grab_op (window->display->grab_op);
+ g_assert (gravity >= 0);
+
+- meta_window_get_position (window, &x, &y);
++ if (window->display->grab_wireframe_active)
++ {
++ x = window->display->grab_wireframe_rect.x;
++ y = window->display->grab_wireframe_rect.y;
++ width = window->display->grab_wireframe_rect.width;
++ height = window->display->grab_wireframe_rect.height;
++ }
++ else
++ {
++ meta_window_get_position (window, &x, &y);
++ width = window->rect.width;
++ height = window->rect.height;
++ }
+
+ meta_ui_resize_popup_set (window->display->grab_resize_popup,
+ gravity,
+ x, y,
+- window->rect.width,
+- window->rect.height,
++ width, height,
+ window->size_hints.base_width,
+ window->size_hints.base_height,
+ window->size_hints.min_width,
+@@ -6478,53 +6569,70 @@
+ return d.found;
+ }
+
++/* Warp pointer to location appropriate for grab,
++ * return root coordinates where pointer ended up.
++ */
+ static gboolean
+-warp_pointer (MetaWindow *window,
+- MetaGrabOp grab_op,
+- int *x,
+- int *y)
++warp_grab_pointer (MetaWindow *window,
++ MetaGrabOp grab_op,
++ int *x,
++ int *y)
+ {
++ MetaRectangle rect;
++
++ /* We may not have done begin_grab_op yet, i.e. may not be in a grab
++ */
++
++ if (window == window->display->grab_window &&
++ window->display->grab_wireframe_active)
++ rect = window->display->grab_wireframe_rect;
++ else
++ {
++ rect = window->rect;
++ meta_window_get_position (window, &rect.x, &rect.y);
++ }
++
+ switch (grab_op)
+ {
+ case META_GRAB_OP_KEYBOARD_MOVING:
+ case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
+- *x = window->rect.width / 2;
+- *y = window->rect.height / 2;
++ *x = rect.width / 2;
++ *y = rect.height / 2;
+ break;
+
+ case META_GRAB_OP_KEYBOARD_RESIZING_S:
+- *x = window->rect.width / 2;
+- *y = window->rect.height;
++ *x = rect.width / 2;
++ *y = rect.height;
+ break;
+
+ case META_GRAB_OP_KEYBOARD_RESIZING_N:
+- *x = window->rect.width / 2;
++ *x = rect.width / 2;
+ *y = 0;
+ break;
+
+ case META_GRAB_OP_KEYBOARD_RESIZING_W:
+ *x = 0;
+- *y = window->rect.height / 2;
++ *y = rect.height / 2;
+ break;
+
+ case META_GRAB_OP_KEYBOARD_RESIZING_E:
+- *x = window->rect.width;
+- *y = window->rect.height / 2;
++ *x = rect.width;
++ *y = rect.height / 2;
+ break;
+
+ case META_GRAB_OP_KEYBOARD_RESIZING_SE:
+- *x = window->rect.width;
+- *y = window->rect.height;
++ *x = rect.width;
++ *y = rect.height;
+ break;
+
+ case META_GRAB_OP_KEYBOARD_RESIZING_NE:
+- *x = window->rect.width;
++ *x = rect.width;
+ *y = 0;
+ break;
+
+ case META_GRAB_OP_KEYBOARD_RESIZING_SW:
+ *x = 0;
+- *y = window->rect.height;
++ *y = rect.height;
+ break;
+
+ case META_GRAB_OP_KEYBOARD_RESIZING_NW:
+@@ -6536,45 +6644,45 @@
+ return FALSE;
+ }
+
++ *x += rect.x;
++ *y += rect.y;
++
+ meta_error_trap_push_with_return (window->display);
++
++ meta_topic (META_DEBUG_WINDOW_OPS,
++ "Warping pointer to %d,%d with window at %d,%d\n",
++ *x, *y, rect.x, rect.y);
+
+ XWarpPointer (window->display->xdisplay,
+ None,
+- window->xwindow,
++ window->screen->xroot,
+ 0, 0, 0, 0,
+- *x,
+- *y);
++ *x, *y);
+
+ if (meta_error_trap_pop_with_return (window->display, FALSE) != Success)
+ {
+- meta_verbose ("Failed to warp pointer for window %s\n", window->desc);
++ meta_verbose ("Failed to warp pointer for window %s\n",
++ window->desc);
+ return FALSE;
+ }
+-
++
+ return TRUE;
+ }
+
+-gboolean
+-meta_window_warp_pointer (MetaWindow *window,
+- MetaGrabOp grab_op)
+-{
+- int x, y;
+-
+- return warp_pointer (window, grab_op, &x, &y);
+-}
+-
+ void
+ meta_window_begin_grab_op (MetaWindow *window,
+ MetaGrabOp op,
+ Time timestamp)
+ {
+- int x, y, x_offset, y_offset;
+-
+- meta_window_get_position (window, &x, &y);
++ int x, y;
++ gulong grab_start_serial;
+
++ grab_start_serial = XNextRequest (window->display->xdisplay);
++
+ meta_window_raise (window);
+
+- warp_pointer (window, op, &x_offset, &y_offset);
++ warp_grab_pointer (window,
++ op, &x, &y);
+
+ meta_display_begin_grab_op (window->display,
+ window->screen,
+@@ -6582,31 +6690,50 @@
+ op,
+ FALSE, 0, 0,
+ timestamp,
+- x + x_offset,
+- y + y_offset);
++ x, y);
++
++ /* We override the one set in display_begin_grab_op since we
++ * did additional stuff as part of the grabbing process
++ */
++ window->display->grab_start_serial = grab_start_serial;
+ }
+
+ void
+-meta_window_update_resize_grab_op (MetaWindow *window,
+- gboolean update_cursor)
++meta_window_update_keyboard_resize (MetaWindow *window,
++ gboolean update_cursor)
+ {
+- int x, y, x_offset, y_offset;
+-
+- meta_window_get_position (window, &x, &y);
++ int x, y;
+
+- warp_pointer (window, window->display->grab_op, &x_offset, &y_offset);
++ warp_grab_pointer (window,
++ window->display->grab_op,
++ &x, &y);
+
+- /* As we warped the pointer, we have to reset the apparent
+- * initial window state, since if the mouse moves we want
+- * to use those events to do the right thing.
+- */
+- if (window->display->grab_window == window)
+- {
+- window->display->grab_initial_root_x = x + x_offset;
+- window->display->grab_initial_root_y = y + y_offset;
+-
+- window->display->grab_initial_window_pos = window->rect;
+- }
++ {
++ /* As we warped the pointer, we have to reset the anchor state,
++ * since if the mouse moves we want to use those events to do the
++ * right thing. Also, this means that the motion notify
++ * from the pointer warp comes back as a no-op.
++ */
++ int dx, dy;
++
++ dx = x - window->display->grab_anchor_root_x;
++ dy = y - window->display->grab_anchor_root_y;
++
++ window->display->grab_anchor_root_x += dx;
++ window->display->grab_anchor_root_y += dy;
++ if (window->display->grab_wireframe_active)
++ {
++ window->display->grab_anchor_window_pos =
++ window->display->grab_wireframe_rect;
++ }
++ else
++ {
++ window->display->grab_anchor_window_pos = window->rect;
++ meta_window_get_position (window,
++ &window->display->grab_anchor_window_pos.x,
++ &window->display->grab_anchor_window_pos.y);
++ }
++ }
+
+ if (update_cursor)
+ {
+@@ -6620,6 +6747,16 @@
+ }
+
+ void
++meta_window_update_keyboard_move (MetaWindow *window)
++{
++ int x, y;
++
++ warp_grab_pointer (window,
++ window->display->grab_op,
++ &x, &y);
++}
++
++void
+ meta_window_update_layer (MetaWindow *window)
+ {
+ MetaGroup *group;
+diff -Nuard metacity-2.6.3.orig/src/window.h metacity-2.6.3/src/window.h
+--- metacity-2.6.3.orig/src/window.h 2003-10-13 22:15:40.000000000 +0200
++++ metacity-2.6.3/src/window.h 2003-12-03 21:25:25.357092776 +0100
+@@ -472,15 +472,13 @@
+ MetaWindowForeachFunc func,
+ void *data);
+
+-gboolean meta_window_warp_pointer (MetaWindow *window,
+- MetaGrabOp grab_op);
+-
+ void meta_window_begin_grab_op (MetaWindow *window,
+ MetaGrabOp op,
+ Time timestamp);
+
+-void meta_window_update_resize_grab_op (MetaWindow *window,
+- gboolean update_cursor);
++void meta_window_update_keyboard_resize (MetaWindow *window,
++ gboolean update_cursor);
++void meta_window_update_keyboard_move (MetaWindow *window);
+
+ void meta_window_update_layer (MetaWindow *window);
+