Commit ee1361fb authored by Havoc Pennington's avatar Havoc Pennington Committed by Havoc Pennington
Browse files

focus top window when switching to a new workspace

2002-01-03  Havoc Pennington  <hp@pobox.com>

	* src/workspace.c (meta_workspace_activate): focus top window when
	switching to a new workspace

	* src/util.c (meta_topic): start putting verbose output in
	categories

	* src/window.c (meta_window_shade): focus frame after we queue
	the calc_showing so the maps/unmaps have already happened.

	* src/display.c (meta_display_get_current_time): add the "get time
	of current event" function and call it occasionally.

	* src/window.c (meta_window_free): if we have focus, call
	meta_screen_focus_top_window().
	(meta_window_minimize): ditto
	(meta_window_delete): ditto

	* src/screen.c (meta_screen_ensure_tab_popup): fix memory leak -
	didn't free tab list
	(meta_screen_focus_top_window): new function to use when we unmap
	or unmanage a focused window

	* src/stack.c (meta_stack_get_default_focus_window): function used
	in meta_screen_focus_top_window
parent 86e9191d
2002-01-03 Havoc Pennington <hp@pobox.com>
* src/workspace.c (meta_workspace_activate): focus top window when
switching to a new workspace
* src/util.c (meta_topic): start putting verbose output in
categories
* src/window.c (meta_window_shade): focus frame after we queue
the calc_showing so the maps/unmaps have already happened.
* src/display.c (meta_display_get_current_time): add the "get time
of current event" function and call it occasionally.
* src/window.c (meta_window_free): if we have focus, call
meta_screen_focus_top_window().
(meta_window_minimize): ditto
(meta_window_delete): ditto
* src/screen.c (meta_screen_ensure_tab_popup): fix memory leak -
didn't free tab list
(meta_screen_focus_top_window): new function to use when we unmap
or unmanage a focused window
* src/stack.c (meta_stack_get_default_focus_window): function used
in meta_screen_focus_top_window
2001-12-21 Havoc Pennington <hp@redhat.com>
* src/frame.c (meta_window_ensure_frame): add a server grab
......
......@@ -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)
{
......
......@@ -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
......@@ -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);
......
......@@ -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);
}
}
......@@ -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");
}
}
......@@ -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
......
......@@ -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)))
......
......@@ -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,
......
......@@ -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, ...)
{
......
......@@ -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);
......
......@@ -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 ==