Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/metacity/ChangeLog,v
retrieving revision 1.678
diff -u -p -u -r1.678 ChangeLog
--- ChangeLog	7 Jun 2003 17:15:32 -0000	1.678
+++ ChangeLog	12 Jun 2003 05:38:40 -0000
@@ -1,3 +1,27 @@
+2003-06-12  Havoc Pennington  <hp@pobox.com>
+
+	* src/display.c (event_callback): make raise-on-click explicitly 
+	only happen in click to focus mode.
+
+	* src/window.c (update_move): apply patch from Jurg Billeter to
+	allow you to "shake loose" maximized windows and move them between
+	Xinerama heads. #93586
+
+	* src/display.c: delete event_queue_callback
+
+	* src/display.h (struct _MetaDisplay): get rid of
+	grab_current_window_pos and grab_current_root_[xy] as I could find
+	absolutely no code using them for anything. They were just sort of
+	randomly assigned to for no apparent reason.
+	
+	* src/display.c (event_callback): double-click timeout is per
+	screen, so get the screen and pass screen->ui to
+	meta_ui_get_double_click_timeout()
+
+	* src/ui.c (meta_ui_get_double_click_timeout): take a MetaUI
+	argument so we get the right settings for each screen
+	(meta_ui_get_drag_threshold): new function
+
 2003-06-07  Rob Adams  <robadams@ucla.edu>
 
 	* src/window.c (meta_window_new): call meta_group_compute_group
Index: src/display.c
===================================================================
RCS file: /cvs/gnome/metacity/src/display.c,v
retrieving revision 1.187
diff -u -p -u -r1.187 display.c
--- src/display.c	30 May 2003 20:24:00 -0000	1.187
+++ src/display.c	12 Jun 2003 05:38:41 -0000
@@ -77,8 +77,6 @@ static GSList *all_displays = NULL;
 
 static void   meta_spew_event           (MetaDisplay    *display,
                                          XEvent         *event);
-static void   event_queue_callback      (XEvent         *event,
-                                         gpointer        data);
 static gboolean event_callback          (XEvent         *event,
                                          gpointer        data);
 static Window event_get_modified_window (MetaDisplay    *display,
@@ -898,14 +896,6 @@ meta_display_is_double_click (MetaDispla
 
 static gboolean dump_events = TRUE;
 
-
-static void
-event_queue_callback (XEvent         *event,
-                      gpointer        data)
-{
-  event_callback (event, data);
-}
-
 static gboolean
 grab_op_is_mouse (MetaGrabOp op)
 {
@@ -1119,6 +1109,28 @@ window_raise_with_delay_callback (void *
   return FALSE;
 }
 
+static int
+double_click_timeout_for_event (MetaDisplay *display,
+                                XEvent      *event)
+{
+  MetaScreen *screen;
+
+  g_assert (event->type == ButtonPress ||
+            event->type == ButtonRelease);
+  
+  screen = meta_display_screen_for_root (display,
+                                         event->xbutton.root);
+  if (screen == NULL)
+    {
+      /* Odd, we aren't managing this screen */
+      meta_warning ("Received button event on root 0x%lx we aren't managing\n",
+                    event->xbutton.root);
+      return 250; /* make up number */
+    }
+  
+  return meta_ui_get_double_click_timeout (screen->ui);
+}                                
+
 static gboolean
 event_callback (XEvent   *event,
                 gpointer  data)
@@ -1154,7 +1166,9 @@ event_callback (XEvent   *event,
       /* mark double click events, kind of a hack, oh well. */
       if (((int)event->xbutton.button) ==  display->last_button_num &&
           event->xbutton.window == display->last_button_xwindow &&
-          event->xbutton.time < (display->last_button_time + meta_ui_get_double_click_timeout ()))
+          event->xbutton.time < (display->last_button_time +
+                                 double_click_timeout_for_event (display,
+                                                                 event)))
         {
           display->is_double_click = TRUE;
           meta_topic (META_DEBUG_EVENTS,
@@ -1321,12 +1335,20 @@ event_callback (XEvent   *event,
                    * frames.c or special-cased if the click was on a
                    * minimize/close button.
                    */
-                  meta_window_raise (window);
-                  
-                  meta_topic (META_DEBUG_FOCUS,
-                              "Focusing %s due to unmodified button %d press (display.c)\n",
-                              window->desc, event->xbutton.button);
-                  meta_window_focus (window, event->xbutton.time);
+                  if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK)
+                    {
+                      meta_window_raise (window);
+                      
+                      meta_topic (META_DEBUG_FOCUS,
+                                  "Focusing %s due to unmodified button %d press (display.c)\n",
+                                  window->desc, event->xbutton.button);
+                      meta_window_focus (window, event->xbutton.time);
+                    }
+                  else
+                    {
+                      meta_topic (META_DEBUG_FOCUS,
+                                  "Not raising/focusing window on click due to mouse/sloppy focus mode\n");
+                    }
                 }
               
               /* you can move on alt-click but not on
@@ -2823,8 +2845,6 @@ meta_display_begin_grab_op (MetaDisplay 
   display->grab_mask = modmask;
   display->grab_initial_root_x = root_x;
   display->grab_initial_root_y = root_y;
-  display->grab_current_root_x = root_x;
-  display->grab_current_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;
@@ -2840,7 +2860,6 @@ meta_display_begin_grab_op (MetaDisplay 
       meta_window_get_position (display->grab_window,
                                 &display->grab_initial_window_pos.x,
                                 &display->grab_initial_window_pos.y);
-      display->grab_current_window_pos = display->grab_initial_window_pos;
 
 #ifdef HAVE_XSYNC
       if (meta_grab_op_is_resizing (display->grab_op) &&
@@ -2930,6 +2949,9 @@ meta_display_end_grab_op (MetaDisplay *d
   if (display->grab_op == META_GRAB_OP_NONE)
     return;
 
+  if (display->grab_window != NULL)
+    display->grab_window->shaken_loose = FALSE;
+  
   if (display->grab_op == META_GRAB_OP_KEYBOARD_TABBING_NORMAL ||
       display->grab_op == META_GRAB_OP_KEYBOARD_TABBING_DOCK ||
       display->grab_op == META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL ||
Index: src/display.h
===================================================================
RCS file: /cvs/gnome/metacity/src/display.h,v
retrieving revision 1.103
diff -u -p -u -r1.103 display.h
--- src/display.h	30 May 2003 20:24:00 -0000	1.103
+++ src/display.h	12 Jun 2003 05:38:41 -0000
@@ -237,15 +237,12 @@ struct _MetaDisplay
   int         grab_button;
   int         grab_initial_root_x;
   int         grab_initial_root_y;
-  int         grab_current_root_x;
-  int         grab_current_root_y;
   int         grab_latest_motion_x;
   int         grab_latest_motion_y;
   gulong      grab_mask;
   guint       grab_have_pointer : 1;
   guint       grab_have_keyboard : 1;
   MetaRectangle grab_initial_window_pos;
-  MetaRectangle grab_current_window_pos;
   MetaResizePopup *grab_resize_popup;
   GTimeVal    grab_last_moveresize_time;
   Time        grab_motion_notify_time;
Index: src/ui.c
===================================================================
RCS file: /cvs/gnome/metacity/src/ui.c,v
retrieving revision 1.49
diff -u -p -u -r1.49 ui.c
--- src/ui.c	30 May 2003 02:53:42 -0000	1.49
+++ src/ui.c	12 Jun 2003 05:38:41 -0000
@@ -767,21 +767,29 @@ meta_stock_icons_init (void)
 }
 
 int
-meta_ui_get_double_click_timeout (void)
+meta_ui_get_double_click_timeout (MetaUI *ui)
 {
   GtkSettings *settings;
-  GObjectClass *klass;
-  int timeout = 0;
+  int timeout;
 
-  settings = gtk_settings_get_default ();
-
-  klass = G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings));
-  if (g_object_class_find_property (klass, "gtk-double-click-time") == NULL) 
-    {
-      return 250;
-    }
+  settings = gtk_widget_get_settings (GTK_WIDGET (ui->frames));
 
+  timeout = 250;
   g_object_get (G_OBJECT (settings), "gtk-double-click-time", &timeout, NULL);
 
   return timeout;
+}
+
+int
+meta_ui_get_drag_threshold (MetaUI *ui)
+{
+  GtkSettings *settings;
+  int threshold;
+
+  settings = gtk_widget_get_settings (GTK_WIDGET (ui->frames));
+
+  threshold = 8;
+  g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &threshold, NULL);
+
+  return threshold;
 }
Index: src/ui.h
===================================================================
RCS file: /cvs/gnome/metacity/src/ui.h,v
retrieving revision 1.28
diff -u -p -u -r1.28 ui.h
--- src/ui.h	30 May 2003 02:53:42 -0000	1.28
+++ src/ui.h	12 Jun 2003 05:38:41 -0000
@@ -165,7 +165,8 @@ gboolean meta_ui_parse_modifier    (cons
 gboolean meta_ui_window_is_widget (MetaUI *ui,
                                    Window  xwindow);
 
-int      meta_ui_get_double_click_timeout (void);
+int      meta_ui_get_double_click_timeout (MetaUI *ui);
+int      meta_ui_get_drag_threshold       (MetaUI *ui);
 
 #include "tabpopup.h"
 
Index: src/window.c
===================================================================
RCS file: /cvs/gnome/metacity/src/window.c,v
retrieving revision 1.284
diff -u -p -u -r1.284 window.c
--- src/window.c	7 Jun 2003 17:15:33 -0000	1.284
+++ src/window.c	12 Jun 2003 05:38:42 -0000
@@ -439,6 +439,7 @@ meta_window_new (MetaDisplay *display,
   window->withdrawn = FALSE;
   window->initial_workspace_set = FALSE;
   window->calc_placement = FALSE;
+  window->shaken_loose = FALSE;
   
   window->unmaps_pending = 0;
   
@@ -5699,15 +5700,95 @@ update_move (MetaWindow  *window,
 {
   int dx, dy;
   int new_x, new_y;
-
+  int shake_threshold;
+  
   window->display->grab_latest_motion_x = x;
   window->display->grab_latest_motion_y = y;
   
-  dx = x - window->display->grab_current_root_x;
-  dy = y - window->display->grab_current_root_y;
+  dx = x - window->display->grab_initial_root_x;
+  dy = y - window->display->grab_initial_root_y;
+
+  new_x = window->display->grab_initial_window_pos.x + dx;
+  new_y = window->display->grab_initial_window_pos.y + 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.
+   */
+
+#define DRAG_THRESHOLD_TO_SHAKE_THRESHOLD_FACTOR 6
+  shake_threshold = meta_ui_get_drag_threshold (window->screen->ui) *
+    DRAG_THRESHOLD_TO_SHAKE_THRESHOLD_FACTOR;
+    
+  if (window->maximized && ABS (dy) >= shake_threshold)
+    {
+      /* Shake loose */
+          
+      window->shaken_loose = TRUE;
+
+      /* Unmaximize at wherever the window would have moved to if it
+       * hadn't been maximized. FIXME if you grab the right side of
+       * the titlebar then on unmaximize the pointer isn't on the
+       * titlebar which is kind of odd.
+       */
+      window->saved_rect.x = new_x;
+      window->saved_rect.y = new_y;
+          
+      meta_window_unmaximize (window);
+
+      return;
+    }
+  /* remaximize window on an other xinerama monitor if window has
+   * been shaken loose or it is still maximized (then move straight)
+   */
+  else if (window->shaken_loose || window->maximized)
+    {
+      const MetaXineramaScreenInfo *wxinerama;
+      int monitor;
+
+      wxinerama = meta_screen_get_xinerama_for_window (window->screen, window);
+
+      for (monitor = 0; monitor < window->screen->n_xinerama_infos; monitor++)
+        {
+          /* FIXME this should check near the top of the work area probably,
+           * maybe only counting full-monitor-width panels in work area
+           * for this purpose.
+           */
+          /* check if cursor is near the top of a xinerama monitor */ 
+          if (x >= window->screen->xinerama_infos[monitor].x_origin &&
+              x < (window->screen->xinerama_infos[monitor].x_origin + 
+                   window->screen->xinerama_infos[monitor].width) &&
+              y >= window->screen->xinerama_infos[monitor].y_origin &&
+              y < (window->screen->xinerama_infos[monitor].y_origin + shake_threshold))
+            {
+              /* move the saved rect if window will become maximized on an
+               * other monitor so user isn't surprised on a later unmaximize
+               */
+              if (wxinerama->number != monitor)
+                {
+                  window->saved_rect.x = window->screen->xinerama_infos[monitor].x_origin;
+                  window->saved_rect.y = window->screen->xinerama_infos[monitor].y_origin;
+                  
+                  if (window->frame) 
+                    {
+                      window->saved_rect.x += window->frame->child_x;
+                      window->saved_rect.y += window->frame->child_y;
+                    }
+
+                  meta_window_unmaximize (window);
+                }
 
-  new_x = window->display->grab_current_window_pos.x + dx;
-  new_y = window->display->grab_current_window_pos.y + dy;
+              window->shaken_loose = FALSE;
+
+              meta_window_maximize (window);
+
+              return;
+            }
+        }
+    }
+
+  /* don't allow a maximized window to move */
+  if (window->maximized)
+    return;
 
   if (mask & ShiftMask)
     {
@@ -5731,11 +5812,11 @@ update_resize (MetaWindow *window,
   window->display->grab_latest_motion_x = x;
   window->display->grab_latest_motion_y = y;
   
-  dx = x - window->display->grab_current_root_x;
-  dy = y - window->display->grab_current_root_y;
+  dx = x - window->display->grab_initial_root_x;
+  dy = y - window->display->grab_initial_root_y;
 
-  new_w = window->display->grab_current_window_pos.width;
-  new_h = window->display->grab_current_window_pos.height;
+  new_w = window->display->grab_initial_window_pos.width;
+  new_h = window->display->grab_initial_window_pos.height;
 
   switch (window->display->grab_op)
     {
@@ -6497,15 +6578,21 @@ meta_window_update_resize_grab_op (MetaW
   int x, y, x_offset, y_offset;
 
   meta_window_get_position (window, &x, &y);
-
+  
   warp_pointer (window, window->display->grab_op, &x_offset, &y_offset);
 
-  window->display->grab_current_root_x = x + x_offset;
-  window->display->grab_current_root_y = y + y_offset;
-
-  if (window->display->grab_window)
-    window->display->grab_current_window_pos = window->rect;
-
+  /* 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;
+    }
+  
   if (update_cursor)
     {
       meta_display_set_grab_op_cursor (window->display,
Index: src/window.h
===================================================================
RCS file: /cvs/gnome/metacity/src/window.h,v
retrieving revision 1.89
diff -u -p -u -r1.89 window.h
--- src/window.h	4 Jun 2003 19:15:46 -0000	1.89
+++ src/window.h	12 Jun 2003 05:38:42 -0000
@@ -228,6 +228,9 @@ struct _MetaWindow
   /* icon props have changed */
   guint need_reread_icon : 1;
   
+  /* if TRUE, window was maximized at start of current grab op */
+  guint shaken_loose : 1;
+
 #ifdef HAVE_XSYNC
   /* XSync update counter */
   XSyncCounter update_counter;
@@ -287,7 +290,11 @@ struct _MetaWindow
   MetaGroup *group;
 };
 
-#define META_WINDOW_ALLOWS_MOVE(w)     ((w)->has_move_func && !(w)->maximized && !(w)->fullscreen)
+/* These differ from window->has_foo_func in that they consider
+ * the dynamic window state such as "maximized", not just the
+ * window's type
+ */
+#define META_WINDOW_ALLOWS_MOVE(w)     ((w)->has_move_func && !(w)->fullscreen)
 #define META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS(w)   ((w)->has_resize_func && !(w)->maximized && !(w)->fullscreen && !(w)->shaded)
 #define META_WINDOW_ALLOWS_RESIZE(w)   (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) &&                \
                                         (((w)->size_hints.min_width < (w)->size_hints.max_width) ||  \
