summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/display.c93
-rw-r--r--src/display.h4
-rw-r--r--src/frames.c3
-rw-r--r--src/keybindings.c20
-rw-r--r--src/screen.c31
-rw-r--r--src/screen.h3
-rw-r--r--src/stack.c54
-rw-r--r--src/stack.h3
-rw-r--r--src/util.c42
-rw-r--r--src/util.h10
-rw-r--r--src/window.c135
-rw-r--r--src/workspace.c6
12 files changed, 368 insertions, 36 deletions
diff --git a/src/display.c b/src/display.c
index d121893..ecebc26 100644
--- a/src/display.c
+++ b/src/display.c
@@ -45,7 +45,8 @@ static gboolean event_callback (XEvent *event,
gpointer data);
static Window event_get_modified_window (MetaDisplay *display,
XEvent *event);
-
+static guint32 event_get_time (MetaDisplay *display,
+ XEvent *event);
@@ -296,6 +297,7 @@ meta_display_open (const char *name)
display->is_double_click = FALSE;
display->last_ignored_unmap_serial = 0;
+ display->current_time = CurrentTime;
display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL;
@@ -620,6 +622,13 @@ grab_op_is_keyboard (MetaGrabOp op)
}
}
+/* Get time of current event, or CurrentTime if none. */
+guint32
+meta_display_get_current_time (MetaDisplay *display)
+{
+ return display->current_time;
+}
+
static gboolean
event_callback (XEvent *event,
gpointer data)
@@ -633,6 +642,8 @@ event_callback (XEvent *event,
if (dump_events)
meta_spew_event (display, event);
+
+ display->current_time = event_get_time (display, event);
/* mark double click events, kind of a hack, oh well. */
if (event->type == ButtonPress)
@@ -727,6 +738,9 @@ event_callback (XEvent *event,
((event->xbutton.state & grab_mask) != 0))
meta_window_raise (window);
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing %s due to button 1 press (display.c)\n",
+ window->desc);
meta_window_focus (window, event->xbutton.time);
if (!frame_was_receiver &&
@@ -805,7 +819,12 @@ event_callback (XEvent *event,
case META_FOCUS_MODE_MOUSE:
if (window->type != META_WINDOW_DOCK &&
window->type != META_WINDOW_DESKTOP)
- meta_window_focus (window, event->xcrossing.time);
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing %s due to enter notify\n",
+ window->desc);
+ meta_window_focus (window, event->xcrossing.time);
+ }
break;
case META_FOCUS_MODE_CLICK:
break;
@@ -828,10 +847,14 @@ event_callback (XEvent *event,
* focused window.
*/
if (window->has_focus)
- XSetInputFocus (display->xdisplay,
- PointerRoot,
- RevertToPointerRoot,
- event->xcrossing.time);
+ {
+ meta_verbose ("Unsetting focus from %s due to LeaveNotify\n",
+ window->desc);
+ XSetInputFocus (display->xdisplay,
+ PointerRoot,
+ RevertToPointerRoot,
+ event->xcrossing.time);
+ }
break;
case META_FOCUS_MODE_SLOPPY:
case META_FOCUS_MODE_CLICK:
@@ -1032,6 +1055,7 @@ event_callback (XEvent *event,
break;
}
+ display->current_time = CurrentTime;
return FALSE;
}
@@ -1109,6 +1133,63 @@ event_get_modified_window (MetaDisplay *display,
}
}
+static guint32
+event_get_time (MetaDisplay *display,
+ XEvent *event)
+{
+ switch (event->type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ return event->xkey.time;
+
+ case ButtonPress:
+ case ButtonRelease:
+ return event->xbutton.time;
+
+ case MotionNotify:
+ return event->xmotion.time;
+
+ case PropertyNotify:
+ return event->xproperty.time;
+
+ case SelectionClear:
+ case SelectionRequest:
+ case SelectionNotify:
+ return event->xselection.time;
+
+ case EnterNotify:
+ case LeaveNotify:
+ return event->xcrossing.time;
+
+ case FocusIn:
+ case FocusOut:
+ case KeymapNotify:
+ case Expose:
+ case GraphicsExpose:
+ case NoExpose:
+ case MapNotify:
+ case UnmapNotify:
+ case VisibilityNotify:
+ case ResizeRequest:
+ case ColormapNotify:
+ case ClientMessage:
+ case CreateNotify:
+ case DestroyNotify:
+ case MapRequest:
+ case ReparentNotify:
+ case ConfigureNotify:
+ case ConfigureRequest:
+ case GravityNotify:
+ case CirculateNotify:
+ case CirculateRequest:
+ case MappingNotify:
+ default:
+ return CurrentTime;
+ }
+}
+
+
static const char*
focus_detail (int d)
{
diff --git a/src/display.h b/src/display.h
index dc8164a..2f85be5 100644
--- a/src/display.h
+++ b/src/display.h
@@ -130,6 +130,8 @@ struct _MetaDisplay
guint is_double_click : 1;
unsigned long last_ignored_unmap_serial;
+
+ guint32 current_time;
/* current window operation */
MetaGrabOp grab_op;
@@ -209,4 +211,6 @@ void meta_display_update_active_window_hint (MetaDisplay *display);
void meta_display_show_desktop (MetaDisplay *display);
void meta_display_unshow_desktop (MetaDisplay *display);
+guint32 meta_display_get_current_time (MetaDisplay *display);
+
#endif
diff --git a/src/frames.c b/src/frames.c
index 91becc1..0222562 100644
--- a/src/frames.c
+++ b/src/frames.c
@@ -1032,6 +1032,9 @@ meta_frames_button_press_event (GtkWidget *widget,
{
meta_core_user_raise (gdk_display,
frame->xwindow);
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing frame 0x%lx due to button 1 press\n",
+ frame->xwindow);
meta_core_user_focus (gdk_display,
frame->xwindow,
event->time);
diff --git a/src/keybindings.c b/src/keybindings.c
index e8c550c..992a338 100644
--- a/src/keybindings.c
+++ b/src/keybindings.c
@@ -355,7 +355,11 @@ meta_window_grab_all_keys (MetaWindow *window)
/* Make sure the window is focused, otherwise the grab
* won't do a lot of good.
*/
- meta_window_focus (window, CurrentTime);
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing %s because we're grabbing all its keys\n",
+ window->desc);
+ meta_window_focus (window,
+ meta_display_get_current_time (window->display));
grabwindow = window->frame ? window->frame->xwindow : window->xwindow;
@@ -376,11 +380,11 @@ meta_window_grab_all_keys (MetaWindow *window)
* presses
*/
meta_error_trap_push (window->display);
- /* FIXME CurrentTime bogus */
+
XGrabKeyboard (window->display->xdisplay,
grabwindow, True,
GrabModeAsync, GrabModeAsync,
- CurrentTime);
+ meta_display_get_current_time (window->display));
result = meta_error_trap_pop (window->display);
if (result != Success)
@@ -413,8 +417,9 @@ meta_window_ungrab_all_keys (MetaWindow *window)
XUngrabKey (window->display->xdisplay,
AnyKey, AnyModifier,
grabwindow);
- /* FIXME CurrentTime bogus */
- XUngrabKeyboard (window->display->xdisplay, CurrentTime);
+
+ XUngrabKeyboard (window->display->xdisplay,
+ meta_display_get_current_time (window->display));
meta_error_trap_pop (window->display);
window->grab_on_frame = FALSE;
@@ -714,6 +719,8 @@ process_tab_grab (MetaDisplay *display,
meta_verbose ("Activating target window\n");
+ meta_topic (META_DEBUG_FOCUS, "Activating %s due to tab popup selection\n",
+ target_window->desc);
meta_window_activate (target_window, event->xkey.time);
return TRUE; /* we already ended the grab */
@@ -1072,6 +1079,9 @@ handle_focus_previous (MetaDisplay *display,
if (window)
{
meta_window_raise (window);
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing %s due to 'focus previous' keybinding\n",
+ window->desc);
meta_window_focus (window, event->xkey.time);
}
}
diff --git a/src/screen.c b/src/screen.c
index 3584248..6731af8 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -640,5 +640,36 @@ meta_screen_ensure_tab_popup (MetaScreen *screen)
screen->tab_popup = meta_ui_tab_popup_new (entries);
g_free (entries);
+ g_slist_free (tab_list);
+
/* don't show tab popup, since proper window isn't selected yet */
}
+
+/* Focus top window on active workspace */
+void
+meta_screen_focus_top_window (MetaScreen *screen,
+ MetaWindow *not_this_one)
+{
+ MetaWindow *window;
+
+ if (not_this_one)
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing top window excluding %s\n", not_this_one->desc);
+
+ window = meta_stack_get_default_focus_window (screen->stack,
+ screen->active_workspace,
+ not_this_one);
+
+ /* FIXME I'm a loser on the CurrentTime front */
+ if (window)
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing top window %s\n", window->desc);
+
+ meta_window_focus (window, meta_display_get_current_time (screen->display));
+ }
+ else
+ {
+ meta_topic (META_DEBUG_FOCUS, "No top window to focus found\n");
+ }
+}
diff --git a/src/screen.h b/src/screen.h
index 688fb4a..bd085d8 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -68,6 +68,9 @@ void meta_screen_set_cursor (MetaScreen *scree
void meta_screen_ensure_tab_popup (MetaScreen *screen);
+void meta_screen_focus_top_window (MetaScreen *screen,
+ MetaWindow *not_this_one);
+
#endif
diff --git a/src/stack.c b/src/stack.c
index f586577..8f03971 100644
--- a/src/stack.c
+++ b/src/stack.c
@@ -869,8 +869,62 @@ meta_stack_get_below (MetaStack *stack,
return link->next->data;
else
return find_prev_below_layer (stack, window->layer);
+}
+
+MetaWindow*
+meta_stack_get_default_focus_window (MetaStack *stack,
+ MetaWorkspace *workspace,
+ MetaWindow *not_this_one)
+{
+ /* FIXME if stack is frozen this is kind of broken. */
+
+ /* Find the topmost, focusable, mapped, window. */
+
+ MetaWindow *topmost_dock;
+ int layer = META_LAYER_LAST;
+
+ topmost_dock = NULL;
+
+ --layer;
+ while (layer >= 0)
+ {
+ GList *link;
+
+ g_assert (layer >= 0 && layer < META_LAYER_LAST);
+
+ /* top of this layer is at the front of the list */
+ link = stack->layers[layer];
+
+ while (link)
+ {
+ MetaWindow *window = link->data;
+
+ if (window &&
+ window != not_this_one &&
+ (workspace == NULL ||
+ meta_window_visible_on_workspace (window, workspace)))
+ {
+ if (topmost_dock == NULL &&
+ window->type == META_WINDOW_DOCK)
+ topmost_dock = window;
+ else
+ return window;
+ }
+
+ link = link->next;
+ }
+
+ --layer;
+ }
+
+ /* If we didn't find a window to focus, we use the topmost dock.
+ * Note that we already tried the desktop - so we prefer focusing
+ * desktop to focusing the dock.
+ */
+ return topmost_dock;
}
+
#define IN_TAB_CHAIN(w) ((w)->type != META_WINDOW_DOCK && (w)->type != META_WINDOW_DESKTOP)
#define GET_XWINDOW(stack, i) (g_array_index ((stack)->windows, \
Window, (i)))
diff --git a/src/stack.h b/src/stack.h
index c1de178..505c63b 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -95,6 +95,9 @@ MetaWindow* meta_stack_get_above (MetaStack *stack,
MetaWindow *window);
MetaWindow* meta_stack_get_below (MetaStack *stack,
MetaWindow *window);
+MetaWindow* meta_stack_get_default_focus_window (MetaStack *stack,
+ MetaWorkspace *workspace,
+ MetaWindow *not_this_one);
MetaWindow* meta_stack_get_tab_next (MetaStack *stack,
MetaWorkspace *workspace,
diff --git a/src/util.c b/src/util.c
index e0f43df..eddd8ad 100644
--- a/src/util.c
+++ b/src/util.c
@@ -167,6 +167,48 @@ meta_verbose (const char *format, ...)
g_free (str);
}
+static const char*
+topic_name (MetaDebugTopic topic)
+{
+ switch (topic)
+ {
+ case META_DEBUG_FOCUS:
+ return "FOCUS";
+ break;
+ }
+
+ return "Window manager";
+}
+
+void
+meta_topic (MetaDebugTopic topic,
+ const char *format,
+ ...)
+{
+ va_list args;
+ gchar *str;
+ FILE *out;
+
+ g_return_if_fail (format != NULL);
+
+ if (!is_verbose)
+ return;
+
+ va_start (args, format);
+ str = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ out = logfile ? logfile : stderr;
+
+ if (no_prefix == 0)
+ fprintf (out, "%s: ", topic_name (topic));
+ fputs (str, out);
+
+ fflush (out);
+
+ g_free (str);
+}
+
void
meta_bug (const char *format, ...)
{
diff --git a/src/util.h b/src/util.h
index f56b5f1..cd71129 100644
--- a/src/util.h
+++ b/src/util.h
@@ -43,6 +43,16 @@ void meta_warning (const char *format,
void meta_fatal (const char *format,
...) G_GNUC_PRINTF (1, 2);
+typedef enum
+{
+ META_DEBUG_FOCUS
+
+} MetaDebugTopic;
+
+void meta_topic (MetaDebugTopic topic,
+ const char *format,
+ ...) G_GNUC_PRINTF (2, 3);
+
void meta_push_no_msg_prefix (void);
void meta_pop_no_msg_prefix (void);
diff --git a/src/window.c b/src/window.c
index 3825dbf..4d04a31 100644
--- a/src/window.c
+++ b/src/window.c
@@ -656,9 +656,30 @@ meta_window_free (MetaWindow *window)
meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
window->unmanaging = TRUE;
-
+
+ /* If we have the focus, focus some other window.
+ * This is done first, so that if the unmap causes
+ * an EnterNotify the EnterNotify will have final say
+ * on what gets focused, maintaining sloppy focus
+ * invariants.
+ */
+ if (window->has_focus)
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing top window since we're unmanaging %s\n",
+ window->desc);
+ meta_screen_focus_top_window (window->screen, window);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Unmanaging window %s which doesn't currently have focus\n",
+ window->desc);
+ }
+
if (window->display->grab_window == window)
- meta_display_end_grab_op (window->display, CurrentTime);
+ meta_display_end_grab_op (window->display,
+ meta_display_get_current_time (window->display));
if (window->display->focus_window == window)
window->display->focus_window = NULL;
@@ -1041,7 +1062,7 @@ meta_window_show (MetaWindow *window)
if (window->shaded)
{
if (window->mapped)
- {
+ {
meta_verbose ("%s actually needs unmap\n", window->desc);
window->mapped = FALSE;
window->unmaps_pending += 1;
@@ -1087,9 +1108,11 @@ meta_window_show (MetaWindow *window)
if (parent && parent->has_focus)
{
- meta_verbose ("Focusing transient window '%s' since parent had focus\n",
- window->desc);
- meta_window_focus (window, CurrentTime); /* FIXME CurrentTime */
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing transient window '%s' since parent had focus\n",
+ window->desc);
+ meta_window_focus (window,
+ meta_display_get_current_time (window->display));
}
}
}
@@ -1131,6 +1154,19 @@ meta_window_minimize (MetaWindow *window)
{
window->minimized = TRUE;
meta_window_queue_calc_showing (window);
+ if (window->has_focus)
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing top window due to minimization of focus window %s\n",
+ window->desc);
+ meta_screen_focus_top_window (window->screen, window);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Minimizing window %s which doesn't have the focus\n",
+ window->desc);
+ }
}
}
@@ -1218,12 +1254,19 @@ meta_window_shade (MetaWindow *window)
}
window->shaded = TRUE;
-
- meta_window_focus (window, CurrentTime);
meta_window_queue_move_resize (window);
meta_window_queue_calc_showing (window);
+ /* After queuing the calc showing, since _focus flushes it,
+ * and we need to focus the frame
+ */
+ meta_topic (META_DEBUG_FOCUS,
+ "Re-focusing window %s after shading it\n",
+ window->desc);
+ meta_window_focus (window,
+ meta_display_get_current_time (window->display));
+
set_net_wm_state (window);
}
}
@@ -1237,9 +1280,12 @@ meta_window_unshade (MetaWindow *window)
window->shaded = FALSE;
meta_window_queue_move_resize (window);
meta_window_queue_calc_showing (window);
+
/* focus the window */
- /* FIXME CurrentTime is bogus */
- meta_window_focus (window, CurrentTime);
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing window %s after unshading it\n",
+ window->desc);
+ meta_window_focus (window, meta_display_get_current_time (window->display));
set_net_wm_state (window);
}
@@ -1259,6 +1305,9 @@ meta_window_activate (MetaWindow *window,
meta_window_unminimize (window);
meta_window_raise (window);
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing window %s due to activation\n",
+ window->desc);
meta_window_focus (window, timestamp);
}
@@ -1962,6 +2011,25 @@ meta_window_delete (MetaWindow *window,
window->desc);
XKillClient (window->display->xdisplay, window->xwindow);
}
+
+ if (window->has_focus)
+ {
+ /* This is unfortunately going to result in weirdness
+ * if the window doesn't respond to the delete event.
+ * I don't know how to avoid that though.
+ */
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing top window because focus window %s was deleted/killed\n",
+ window->desc);
+ meta_screen_focus_top_window (window->screen, window);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Window %s was deleted/killed but didn't have focus\n",
+ window->desc);
+ }
+
meta_error_trap_pop (window->display);
}
@@ -1969,9 +2037,10 @@ void
meta_window_focus (MetaWindow *window,
Time timestamp)
{
- meta_verbose ("Setting input focus to window %s, input: %d take_focus: %d\n",
- window->desc, window->input, window->take_focus);
-
+ meta_topic (META_DEBUG_FOCUS,
+ "Setting input focus to window %s, input: %d take_focus: %d\n",
+ window->desc, window->input, window->take_focus);
+
if (window->display->grab_window &&
window->display->grab_window->all_keys_grabbed)
{
@@ -2303,7 +2372,7 @@ meta_window_client_message (MetaWindow *window,
* in this message, CurrentTime here is sort of
* bogus. But it rarely matters most likely.
*/
- meta_window_delete (window, CurrentTime);
+ meta_window_delete (window, meta_display_get_current_time (window->display));
return TRUE;
}
@@ -2538,7 +2607,7 @@ meta_window_client_message (MetaWindow *window,
op,
FALSE,
button, 0,
- CurrentTime,
+ meta_display_get_current_time (window->display),
x_root,
y_root);
}
@@ -2549,9 +2618,10 @@ meta_window_client_message (MetaWindow *window,
else if (event->xclient.message_type ==
display->atom_net_active_window)
{
- meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s'", window->desc);
+ meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating",
+ window->desc);
- meta_window_activate (window, CurrentTime);
+ meta_window_activate (window, meta_display_get_current_time (window->display));
return TRUE;
}
@@ -2586,12 +2656,20 @@ meta_window_notify_focus (MetaWindow *window,
* and prev_focus_window gets confused from what the
* user expects once a keybinding is used.
*/
+ meta_topic (META_DEBUG_FOCUS,
+ "Focus %s event received\n",
+ event->type == FocusIn ? "in" :
+ event->type == FocusOut ? "out" :
+ event->type == UnmapNotify ? "unmap" :
+ "???");
+
if ((event->type == FocusIn ||
event->type == FocusOut) &&
(event->xfocus.mode == NotifyGrab ||
event->xfocus.mode == NotifyUngrab))
{
- meta_verbose ("Ignoring focus event generated by a grab\n");
+ meta_topic (META_DEBUG_FOCUS,
+ "Ignoring focus event generated by a grab\n");
return TRUE;
}
@@ -2602,11 +2680,13 @@ meta_window_notify_focus (MetaWindow *window,
if (window == window->display->prev_focus_window &&
window->display->focus_window != NULL)
{
- meta_verbose ("%s is now the previous focus window due to another window focused in\n",
- window->display->focus_window->desc);
+ meta_topic (META_DEBUG_FOCUS,
+ "%s is now the previous focus window due to another window focused in\n",
+ window->display->focus_window->desc);
window->display->prev_focus_window = window->display->focus_window;
}
- meta_verbose ("New focus window %s\n", window->desc);
+ meta_topic (META_DEBUG_FOCUS,
+ "New focus window %s\n", window->desc);
window->display->focus_window = window;
}
window->has_focus = TRUE;
@@ -2618,10 +2698,15 @@ meta_window_notify_focus (MetaWindow *window,
{
if (window == window->display->focus_window)
{
- meta_verbose ("%s is now the previous focus window due to being focused out or unmapped\n",
- window->desc);
+ meta_topic (META_DEBUG_FOCUS,
+ "%s is now the previous focus window due to being focused out or unmapped\n",
+ window->desc);
+
window->display->prev_focus_window = window;
+ meta_topic (META_DEBUG_FOCUS,
+ "Clearing focus window (was %s)\n", window->desc);
+
window->display->focus_window = NULL;
}
window->has_focus = FALSE;
@@ -4894,7 +4979,7 @@ menu_callback (MetaWindowMenu *menu,
switch (op)
{
case META_MENU_OP_DELETE:
- meta_window_delete (window, CurrentTime);
+ meta_window_delete (window, meta_display_get_current_time (window->display));
break;
case META_MENU_OP_MINIMIZE:
@@ -4948,7 +5033,7 @@ menu_callback (MetaWindowMenu *menu,
window,
META_GRAB_OP_KEYBOARD_MOVING,
FALSE, 0, 0,
- CurrentTime,
+ meta_display_get_current_time (window->display),
0, 0);
break;
diff --git a/src/workspace.c b/src/workspace.c
index 20eb11e..1b65915 100644
--- a/src/workspace.c
+++ b/src/workspace.c
@@ -189,6 +189,12 @@ 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);
}
int