summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--src/display.c1
-rw-r--r--src/display.h1
-rw-r--r--src/screen.c60
-rw-r--r--src/screen.h8
-rw-r--r--src/stack.c57
-rw-r--r--src/stack.h13
-rw-r--r--src/window.c117
-rw-r--r--src/workspace.c7
9 files changed, 217 insertions, 67 deletions
diff --git a/ChangeLog b/ChangeLog
index 6a60863..38e493f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2003-01-21 Havoc Pennington <hp@pobox.com>
+
+ Fix for the "mangles focus window when switching workspaces
+ and using mouse focus" bug
+
+ * src/stack.c (meta_stack_get_default_focus_window_at_point): new
+ function
+
+ * src/screen.c (meta_screen_focus_mouse_window): new function
+ (meta_screen_focus_default_window): new function
+
+ * src/workspace.c (meta_workspace_activate): use the
+ new meta_screen_focus_default_window()
+
+2003-01-17 Havoc Pennington <hp@pobox.com>
+
+ * src/window.c (meta_window_handle_mouse_grab_op_event): fix event
+ compression code to use GDK algorithm suggested by Owen, should be
+ more efficient.
+
2003-01-22 Christian Rose <menthos@menthos.com>
* configure.in: Added "mn" to ALL_LINGUAS.
diff --git a/src/display.c b/src/display.c
index 9dac79f..a19e9e4 100644
--- a/src/display.c
+++ b/src/display.c
@@ -2798,6 +2798,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
display->grab_latest_motion_y = root_y;
display->grab_last_moveresize_time.tv_sec = 0;
display->grab_last_moveresize_time.tv_usec = 0;
+ display->grab_motion_notify_time = 0;
#ifdef HAVE_XSYNC
display->grab_update_alarm = None;
#endif
diff --git a/src/display.h b/src/display.h
index 803f021..8bcf50d 100644
--- a/src/display.h
+++ b/src/display.h
@@ -245,6 +245,7 @@ struct _MetaDisplay
MetaRectangle grab_current_window_pos;
MetaResizePopup *grab_resize_popup;
GTimeVal grab_last_moveresize_time;
+ Time grab_motion_notify_time;
#ifdef HAVE_XSYNC
/* alarm monitoring client's _METACITY_UPDATE_COUNTER */
XSyncAlarm grab_update_alarm;
diff --git a/src/screen.c b/src/screen.c
index 483f66a..3dcefb5 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1220,6 +1220,66 @@ meta_screen_focus_top_window (MetaScreen *screen,
}
}
+void
+meta_screen_focus_mouse_window (MetaScreen *screen,
+ MetaWindow *not_this_one)
+{
+ MetaWindow *window;
+ Window root_return, child_return;
+ int root_x_return, root_y_return;
+ int win_x_return, win_y_return;
+ unsigned int mask_return;
+
+ if (not_this_one)
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing mouse window excluding %s\n", not_this_one->desc);
+
+ meta_error_trap_push (screen->display);
+ XQueryPointer (screen->display->xdisplay,
+ screen->xroot,
+ &root_return,
+ &child_return,
+ &root_x_return,
+ &root_y_return,
+ &win_x_return,
+ &win_y_return,
+ &mask_return);
+ meta_error_trap_pop (screen->display, TRUE);
+
+ window = meta_stack_get_default_focus_window_at_point (screen->stack,
+ screen->active_workspace,
+ not_this_one,
+ root_x_return,
+ root_y_return);
+
+ /* FIXME I'm a loser on the CurrentTime front */
+ if (window)
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing mouse window %s\n", window->desc);
+
+ meta_window_focus (window, meta_display_get_current_time (screen->display));
+
+ /* Also raise the window if in click-to-focus */
+ if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK)
+ meta_window_raise (window);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_FOCUS, "No mouse window to focus found\n");
+ }
+}
+
+void
+meta_screen_focus_default_window (MetaScreen *screen,
+ MetaWindow *not_this_one)
+{
+ if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK)
+ meta_screen_focus_top_window (screen, not_this_one);
+ else
+ meta_screen_focus_mouse_window (screen, not_this_one);
+}
+
const MetaXineramaScreenInfo*
meta_screen_get_xinerama_for_window (MetaScreen *screen,
MetaWindow *window)
diff --git a/src/screen.h b/src/screen.h
index 5ab5ec3..16e9070 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -124,8 +124,12 @@ void meta_screen_ensure_tab_popup (MetaScreen *scree
void meta_screen_ensure_workspace_popup (MetaScreen *screen);
-void meta_screen_focus_top_window (MetaScreen *screen,
- MetaWindow *not_this_one);
+void meta_screen_focus_top_window (MetaScreen *screen,
+ MetaWindow *not_this_one);
+void meta_screen_focus_mouse_window (MetaScreen *screen,
+ MetaWindow *not_this_one);
+void meta_screen_focus_default_window (MetaScreen *screen,
+ MetaWindow *not_this_one);
const MetaXineramaScreenInfo* meta_screen_get_current_xinerama (MetaScreen *screen);
const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen *screen,
diff --git a/src/stack.c b/src/stack.c
index e91c620..5cb5dba 100644
--- a/src/stack.c
+++ b/src/stack.c
@@ -1299,12 +1299,27 @@ meta_stack_get_below (MetaStack *stack,
return NULL;
else
return below;
-}
+}
-MetaWindow*
-meta_stack_get_default_focus_window (MetaStack *stack,
- MetaWorkspace *workspace,
- MetaWindow *not_this_one)
+static gboolean
+window_contains_point (MetaWindow *window,
+ int root_x,
+ int root_y)
+{
+ MetaRectangle rect;
+
+ meta_window_get_outer_rect (window, &rect);
+
+ return POINT_IN_RECT (root_x, root_y, rect);
+}
+
+static MetaWindow*
+get_default_focus_window (MetaStack *stack,
+ MetaWorkspace *workspace,
+ MetaWindow *not_this_one,
+ gboolean must_be_at_point,
+ int root_x,
+ int root_y)
{
/* Find the topmost, focusable, mapped, window.
* not_this_one is being unfocused or going away, so exclude it.
@@ -1353,12 +1368,16 @@ meta_stack_get_default_focus_window (MetaStack *stack,
{
if (transient_parent == NULL &&
not_this_one->xtransient_for != None &&
- not_this_one->xtransient_for == window->xwindow)
+ not_this_one->xtransient_for == window->xwindow &&
+ (!must_be_at_point ||
+ window_contains_point (window, root_x, root_y)))
transient_parent = window;
if (topmost_in_group == NULL &&
not_this_one_group != NULL &&
- not_this_one_group == meta_window_get_group (window))
+ not_this_one_group == meta_window_get_group (window) &&
+ (!must_be_at_point ||
+ window_contains_point (window, root_x, root_y)))
topmost_in_group = window;
}
@@ -1367,7 +1386,9 @@ meta_stack_get_default_focus_window (MetaStack *stack,
* focusing dock, even though docks are stacked higher.
*/
if (topmost_overall == NULL &&
- window->type != META_WINDOW_DOCK)
+ window->type != META_WINDOW_DOCK &&
+ (!must_be_at_point ||
+ window_contains_point (window, root_x, root_y)))
topmost_overall = window;
/* We could try to bail out early here for efficiency in
@@ -1388,6 +1409,26 @@ meta_stack_get_default_focus_window (MetaStack *stack,
return topmost_dock;
}
+MetaWindow*
+meta_stack_get_default_focus_window_at_point (MetaStack *stack,
+ MetaWorkspace *workspace,
+ MetaWindow *not_this_one,
+ int root_x,
+ int root_y)
+{
+ return get_default_focus_window (stack, workspace, not_this_one,
+ TRUE, root_x, root_y);
+}
+
+MetaWindow*
+meta_stack_get_default_focus_window (MetaStack *stack,
+ MetaWorkspace *workspace,
+ MetaWindow *not_this_one)
+{
+ return get_default_focus_window (stack, workspace, not_this_one,
+ FALSE, 0, 0);
+}
+
GList*
meta_stack_list_windows (MetaStack *stack,
MetaWorkspace *workspace)
diff --git a/src/stack.h b/src/stack.h
index 89b8aff..b0c21e5 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -118,9 +118,16 @@ MetaWindow* meta_stack_get_above (MetaStack *stack,
MetaWindow* meta_stack_get_below (MetaStack *stack,
MetaWindow *window,
gboolean only_within_layer);
-MetaWindow* meta_stack_get_default_focus_window (MetaStack *stack,
- MetaWorkspace *workspace,
- MetaWindow *not_this_one);
+
+MetaWindow* meta_stack_get_default_focus_window (MetaStack *stack,
+ MetaWorkspace *workspace,
+ MetaWindow *not_this_one);
+MetaWindow* meta_stack_get_default_focus_window_at_point (MetaStack *stack,
+ MetaWorkspace *workspace,
+ MetaWindow *not_this_one,
+ int root_x,
+ int root_y);
+
GList* meta_stack_list_windows (MetaStack *stack,
MetaWorkspace *workspace);
diff --git a/src/window.c b/src/window.c
index cd46f6c..daca294 100644
--- a/src/window.c
+++ b/src/window.c
@@ -6315,61 +6315,78 @@ update_resize (MetaWindow *window,
typedef struct
{
- XEvent prev_event;
- gboolean done;
+ const XEvent *current_event;
int count;
-} CompressEventData;
+ Time last_time;
+} EventScannerData;
static Bool
-compress_event_predicate (Display *display,
+find_last_time_predicate (Display *display,
XEvent *xevent,
XPointer arg)
{
- CompressEventData *ced = (void*) arg;
-
- if (ced->done)
- return False;
- else if (ced->prev_event.type == xevent->type &&
- ced->prev_event.xany.window == xevent->xany.window)
- {
- ced->count += 1;
- return True;
- }
- else if (xevent->type != Expose &&
- xevent->type != ConfigureNotify &&
- xevent->type != PropertyNotify)
+ EventScannerData *esd = (void*) arg;
+
+ if (esd->current_event->type == xevent->type &&
+ esd->current_event->xany.window == xevent->xany.window)
{
- /* Don't compress across most unrelated events, just to be safe */
- ced->done = TRUE;
- return False;
+ esd->count += 1;
+ esd->last_time = xevent->xmotion.time;
}
- else
- return False;
+
+ return False;
}
-static void
-maybe_replace_with_newer_event (MetaWindow *window,
- XEvent *event)
+static gboolean
+check_use_this_motion_notify (MetaWindow *window,
+ XEvent *event)
{
- XEvent new_event;
- CompressEventData ced;
+ EventScannerData esd;
+ XEvent useless;
+
+ /* This code is copied from Owen's GDK code. */
+
+ if (window->display->grab_motion_notify_time != 0)
+ {
+ /* == is really the right test, but I'm all for paranoia */
+ if (window->display->grab_motion_notify_time <=
+ event->xmotion.time)
+ {
+ meta_topic (META_DEBUG_RESIZING,
+ "Arrived at event with time %lu (waiting for %lu), using it\n",
+ (unsigned long) event->xmotion.time,
+ (unsigned long) window->display->grab_motion_notify_time);
+ window->display->grab_motion_notify_time = 0;
+ return TRUE;
+ }
+ else
+ return FALSE; /* haven't reached the saved timestamp yet */
+ }
- /* Chew up all events of the same type on the same window */
+ esd.current_event = event;
+ esd.count = 0;
+ esd.last_time = 0;
- ced.count = 0;
- ced.done = FALSE;
- ced.prev_event = *event;
- while (XCheckIfEvent (window->display->xdisplay,
- &new_event,
- compress_event_predicate,
- (void*) &ced.prev_event))
- ced.prev_event = new_event;
+ /* "useless" isn't filled in because the predicate never returns True */
+ XCheckIfEvent (window->display->xdisplay,
+ &useless,
+ find_last_time_predicate,
+ (XPointer) &esd);
- if (ced.count > 0)
+ if (esd.count > 0)
+ meta_topic (META_DEBUG_RESIZING,
+ "Will skip %d motion events and use the event with time %lu\n",
+ esd.count, (unsigned long) esd.last_time);
+
+ if (esd.last_time == 0)
+ return TRUE;
+ else
{
- meta_topic (META_DEBUG_RESIZING,
- "Compressed %d motion events\n", ced.count);
- *event = ced.prev_event;
+ /* Save this timestamp, and ignore all motion notify
+ * until we get to the one with this stamp.
+ */
+ window->display->grab_motion_notify_time = esd.last_time;
+ return FALSE;
}
}
@@ -6443,21 +6460,23 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
{
if (event->xmotion.root == window->screen->xroot)
{
- maybe_replace_with_newer_event (window, event);
- update_move (window,
- event->xmotion.state,
- event->xmotion.x_root,
- event->xmotion.y_root);
+ if (check_use_this_motion_notify (window,
+ event))
+ update_move (window,
+ event->xmotion.state,
+ event->xmotion.x_root,
+ event->xmotion.y_root);
}
}
else if (meta_grab_op_is_resizing (window->display->grab_op))
{
if (event->xmotion.root == window->screen->xroot)
{
- maybe_replace_with_newer_event (window, event);
- update_resize (window,
- event->xmotion.x_root,
- event->xmotion.y_root);
+ if (check_use_this_motion_notify (window,
+ event))
+ update_resize (window,
+ event->xmotion.x_root,
+ event->xmotion.y_root);
}
}
break;
diff --git a/src/workspace.c b/src/workspace.c
index 40e445d..f6eacc9 100644
--- a/src/workspace.c
+++ b/src/workspace.c
@@ -216,11 +216,8 @@ meta_workspace_activate (MetaWorkspace *workspace)
meta_workspace_queue_calc_showing (old);
meta_workspace_queue_calc_showing (workspace);
- /* in mouse focus modes, this will probably get undone by an EnterNotify,
- * but that's OK
- */
- meta_topic (META_DEBUG_FOCUS, "Focusing top window on new workspace\n");
- meta_screen_focus_top_window (workspace->screen, NULL);
+ meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n");
+ meta_screen_focus_default_window (workspace->screen, NULL);
}
int