mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 11:32:04 +00:00
display: clean up focus_window vs expected_focus_window
Mutter previously defined display->focus_window as the window that the server says is focused, but kept display->expected_focus_window to indicate the window that we have requested to be focused. But it turns out that "expected_focus_window" was almost always what we wanted. Make MetaDisplay do a better job of tracking focus-related requests and events, and change display->focus_window to be our best guess of the "currently" focused window (ie, the window that will be focused at the time when the server processes the next request we send it). https://bugzilla.gnome.org/show_bug.cgi?id=647706
This commit is contained in:
parent
4f1d62170b
commit
7a4c808e43
@ -103,19 +103,17 @@ struct _MetaDisplay
|
|||||||
#include <meta/atomnames.h>
|
#include <meta/atomnames.h>
|
||||||
#undef item
|
#undef item
|
||||||
|
|
||||||
/* This is the actual window from focus events,
|
/* The window and serial of the most recent FocusIn event. */
|
||||||
* not the one we last set
|
Window server_focus_window;
|
||||||
|
gulong server_focus_serial;
|
||||||
|
|
||||||
|
/* Our best guess as to the "currently" focused window (that is, the
|
||||||
|
* window that we expect will be focused at the point when the X
|
||||||
|
* server processes our next request), and the serial of the request
|
||||||
|
* or event that caused this.
|
||||||
*/
|
*/
|
||||||
MetaWindow *focus_window;
|
MetaWindow *focus_window;
|
||||||
|
gulong focus_serial;
|
||||||
/* window we are expecting a FocusIn event for or the current focus
|
|
||||||
* window if we are not expecting any FocusIn/FocusOut events; not
|
|
||||||
* perfect because applications can call XSetInputFocus directly.
|
|
||||||
* (It could also be messed up if a timestamp later than current
|
|
||||||
* time is sent to meta_display_set_input_focus_window, though that
|
|
||||||
* would be a programming error). See bug 154598 for more info.
|
|
||||||
*/
|
|
||||||
MetaWindow *expected_focus_window;
|
|
||||||
|
|
||||||
/* last timestamp passed to XSetInputFocus */
|
/* last timestamp passed to XSetInputFocus */
|
||||||
guint32 last_focus_time;
|
guint32 last_focus_time;
|
||||||
|
@ -519,7 +519,9 @@ meta_display_open (void)
|
|||||||
the_display->autoraise_timeout_id = 0;
|
the_display->autoraise_timeout_id = 0;
|
||||||
the_display->autoraise_window = NULL;
|
the_display->autoraise_window = NULL;
|
||||||
the_display->focus_window = NULL;
|
the_display->focus_window = NULL;
|
||||||
the_display->expected_focus_window = NULL;
|
the_display->focus_serial = 0;
|
||||||
|
the_display->server_focus_window = None;
|
||||||
|
the_display->server_focus_serial = 0;
|
||||||
the_display->grab_old_window_stacking = NULL;
|
the_display->grab_old_window_stacking = NULL;
|
||||||
|
|
||||||
the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
|
the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
|
||||||
@ -1632,12 +1634,12 @@ meta_display_mouse_mode_focus (MetaDisplay *display,
|
|||||||
* alternative mechanism works great.
|
* alternative mechanism works great.
|
||||||
*/
|
*/
|
||||||
if (meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE &&
|
if (meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE &&
|
||||||
display->expected_focus_window != NULL)
|
display->focus_window != NULL)
|
||||||
{
|
{
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
"Unsetting focus from %s due to mouse entering "
|
"Unsetting focus from %s due to mouse entering "
|
||||||
"the DESKTOP window\n",
|
"the DESKTOP window\n",
|
||||||
display->expected_focus_window->desc);
|
display->focus_window->desc);
|
||||||
meta_display_focus_the_no_focus_window (display,
|
meta_display_focus_the_no_focus_window (display,
|
||||||
window->screen,
|
window->screen,
|
||||||
timestamp);
|
timestamp);
|
||||||
@ -1851,6 +1853,163 @@ get_input_event (MetaDisplay *display,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_focus_window (MetaDisplay *display,
|
||||||
|
MetaWindow *window,
|
||||||
|
gulong serial)
|
||||||
|
{
|
||||||
|
display->focus_serial = serial;
|
||||||
|
|
||||||
|
if (window == display->focus_window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (display->focus_window)
|
||||||
|
{
|
||||||
|
MetaWindow *previous;
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"%s is now the previous focus window due to being focused out or unmapped\n",
|
||||||
|
display->focus_window->desc);
|
||||||
|
|
||||||
|
/* Make sure that signals handlers invoked by
|
||||||
|
* meta_window_set_focused_internal() don't see
|
||||||
|
* display->focus_window->has_focus == FALSE
|
||||||
|
*/
|
||||||
|
previous = display->focus_window;
|
||||||
|
display->focus_window = NULL;
|
||||||
|
|
||||||
|
meta_window_set_focused_internal (previous, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
display->focus_window = window;
|
||||||
|
|
||||||
|
if (display->focus_window)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_FOCUS, "* Focus --> %s with serial %lu\n",
|
||||||
|
display->focus_window->desc, serial);
|
||||||
|
meta_window_set_focused_internal (display->focus_window, TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial);
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (display), "focus-window");
|
||||||
|
meta_display_update_active_window_hint (display);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_window_focus_event (MetaDisplay *display,
|
||||||
|
MetaWindow *window,
|
||||||
|
XIEnterEvent *event,
|
||||||
|
unsigned long serial)
|
||||||
|
{
|
||||||
|
MetaWindow *focus_window;
|
||||||
|
#ifdef WITH_VERBOSE_MODE
|
||||||
|
const char *window_type;
|
||||||
|
|
||||||
|
/* Note the event can be on either the window or the frame,
|
||||||
|
* we focus the frame for shaded windows
|
||||||
|
*/
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
if (event->event == window->xwindow)
|
||||||
|
window_type = "client window";
|
||||||
|
else if (window->frame && event->event == window->frame->xwindow)
|
||||||
|
window_type = "frame window";
|
||||||
|
else
|
||||||
|
window_type = "unknown client window";
|
||||||
|
}
|
||||||
|
else if (meta_display_xwindow_is_a_no_focus_window (display, event->event))
|
||||||
|
window_type = "no_focus_window";
|
||||||
|
else if (meta_display_screen_for_root (display, event->event))
|
||||||
|
window_type = "root window";
|
||||||
|
else
|
||||||
|
window_type = "unknown window";
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Focus %s event received on %s 0x%lx (%s) "
|
||||||
|
"mode %s detail %s serial %lu\n",
|
||||||
|
event->evtype == XI_FocusIn ? "in" :
|
||||||
|
event->evtype == XI_FocusOut ? "out" :
|
||||||
|
"???",
|
||||||
|
window ? window->desc : "",
|
||||||
|
event->event, window_type,
|
||||||
|
meta_event_mode_to_string (event->mode),
|
||||||
|
meta_event_detail_to_string (event->mode),
|
||||||
|
event->serial);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FIXME our pointer tracking is broken; see how
|
||||||
|
* gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c
|
||||||
|
* for how to handle it the correct way. In brief you need to track
|
||||||
|
* pointer focus and regular focus, and handle EnterNotify in
|
||||||
|
* PointerRoot mode with no window manager. However as noted above,
|
||||||
|
* accurate focus tracking will break things because we want to keep
|
||||||
|
* windows "focused" when using keybindings on them, and also we
|
||||||
|
* sometimes "focus" a window by focusing its frame or
|
||||||
|
* no_focus_window; so this all needs rethinking massively.
|
||||||
|
*
|
||||||
|
* My suggestion is to change it so that we clearly separate
|
||||||
|
* actual keyboard focus tracking using the xterm algorithm,
|
||||||
|
* and mutter's "pretend" focus window, and go through all
|
||||||
|
* the code and decide which one should be used in each place;
|
||||||
|
* a hard bit is deciding on a policy for that.
|
||||||
|
*
|
||||||
|
* http://bugzilla.gnome.org/show_bug.cgi?id=90382
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* We ignore grabs, though this is questionable. It may be better to
|
||||||
|
* increase the intelligence of the focus window tracking.
|
||||||
|
*
|
||||||
|
* The problem is that keybindings for windows are done with
|
||||||
|
* XGrabKey, which means focus_window disappears and the front of
|
||||||
|
* the MRU list gets confused from what the user expects once a
|
||||||
|
* keybinding is used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (event->mode == NotifyGrab ||
|
||||||
|
event->mode == NotifyUngrab ||
|
||||||
|
/* From WindowMaker, ignore all funky pointer root events */
|
||||||
|
event->detail > NotifyNonlinearVirtual)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Ignoring focus event generated by a grab or other weirdness\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->evtype == XI_FocusIn)
|
||||||
|
{
|
||||||
|
display->server_focus_window = event->event;
|
||||||
|
display->server_focus_serial = serial;
|
||||||
|
|
||||||
|
if (window && window->override_redirect)
|
||||||
|
focus_window = NULL;
|
||||||
|
else
|
||||||
|
focus_window = window;
|
||||||
|
}
|
||||||
|
else if (event->evtype == XI_FocusOut)
|
||||||
|
{
|
||||||
|
if (event->detail == NotifyInferior)
|
||||||
|
{
|
||||||
|
/* This event means the client moved focus to a subwindow */
|
||||||
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
|
"Ignoring focus out with NotifyInferior\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display->server_focus_window = None;
|
||||||
|
display->server_focus_serial = serial;
|
||||||
|
focus_window = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_return_if_reached ();
|
||||||
|
|
||||||
|
if (display->server_focus_serial >= display->focus_serial)
|
||||||
|
{
|
||||||
|
set_focus_window (display, focus_window,
|
||||||
|
display->server_focus_serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* event_callback:
|
* event_callback:
|
||||||
* @event: The event that just happened
|
* @event: The event that just happened
|
||||||
@ -1894,6 +2053,17 @@ event_callback (XEvent *event,
|
|||||||
display->current_time = event_get_time (display, event);
|
display->current_time = event_get_time (display, event);
|
||||||
display->monitor_cache_invalidated = TRUE;
|
display->monitor_cache_invalidated = TRUE;
|
||||||
|
|
||||||
|
if (event->xany.serial > display->focus_serial &&
|
||||||
|
display->focus_window &&
|
||||||
|
display->focus_window->xwindow != display->server_focus_window)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n",
|
||||||
|
display->focus_window->desc);
|
||||||
|
set_focus_window (display,
|
||||||
|
meta_display_lookup_x_window (display, display->server_focus_window),
|
||||||
|
display->server_focus_serial);
|
||||||
|
}
|
||||||
|
|
||||||
modified = event_get_modified_window (display, event);
|
modified = event_get_modified_window (display, event);
|
||||||
|
|
||||||
input_event = get_input_event (display, event);
|
input_event = get_input_event (display, event);
|
||||||
@ -2350,41 +2520,20 @@ event_callback (XEvent *event,
|
|||||||
break;
|
break;
|
||||||
case XI_FocusIn:
|
case XI_FocusIn:
|
||||||
case XI_FocusOut:
|
case XI_FocusOut:
|
||||||
if (window)
|
/* libXi does not properly copy the serial to the XIEnterEvent, so pull it
|
||||||
{
|
* from the parent XAnyEvent.
|
||||||
meta_window_notify_focus (window, enter_event);
|
* See: https://bugs.freedesktop.org/show_bug.cgi?id=64687
|
||||||
}
|
*/
|
||||||
else if (meta_display_xwindow_is_a_no_focus_window (display,
|
handle_window_focus_event (display, window, enter_event, event->xany.serial);
|
||||||
enter_event->event))
|
if (!window)
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"Focus %s event received on no_focus_window 0x%lx "
|
|
||||||
"mode %s detail %s\n",
|
|
||||||
enter_event->evtype == XI_FocusIn ? "in" :
|
|
||||||
enter_event->evtype == XI_FocusOut ? "out" :
|
|
||||||
"???",
|
|
||||||
enter_event->event,
|
|
||||||
meta_event_mode_to_string (enter_event->mode),
|
|
||||||
meta_event_detail_to_string (enter_event->detail));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
/* Check if the window is a root window. */
|
||||||
MetaScreen *screen =
|
MetaScreen *screen =
|
||||||
meta_display_screen_for_root(display,
|
meta_display_screen_for_root(display,
|
||||||
enter_event->event);
|
enter_event->event);
|
||||||
if (screen == NULL)
|
if (screen == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"Focus %s event received on root window 0x%lx "
|
|
||||||
"mode %s detail %s\n",
|
|
||||||
enter_event->evtype == XI_FocusIn ? "in" :
|
|
||||||
enter_event->evtype == XI_FocusOut ? "out" :
|
|
||||||
"???",
|
|
||||||
enter_event->event,
|
|
||||||
meta_event_mode_to_string (enter_event->mode),
|
|
||||||
meta_event_detail_to_string (enter_event->detail));
|
|
||||||
|
|
||||||
if (enter_event->evtype == XI_FocusIn &&
|
if (enter_event->evtype == XI_FocusIn &&
|
||||||
enter_event->mode == XINotifyDetailNone)
|
enter_event->mode == XINotifyDetailNone)
|
||||||
{
|
{
|
||||||
@ -2521,13 +2670,6 @@ event_callback (XEvent *event,
|
|||||||
window->unmaps_pending);
|
window->unmaps_pending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unfocus on UnmapNotify, do this after the possible
|
|
||||||
* window_free above so that window_free can see if window->has_focus
|
|
||||||
* and move focus to another window
|
|
||||||
*/
|
|
||||||
if (window)
|
|
||||||
meta_window_lost_focus (window);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MapNotify:
|
case MapNotify:
|
||||||
@ -5622,18 +5764,57 @@ meta_display_set_input_focus_window (MetaDisplay *display,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
meta_error_trap_push (display);
|
meta_error_trap_push (display);
|
||||||
|
display->focus_serial = XNextRequest (display->xdisplay);
|
||||||
|
meta_topic (META_DEBUG_FOCUS, "XSetInputFocus(%s, %u) with serial %lu\n",
|
||||||
|
window->desc, timestamp, display->focus_serial);
|
||||||
XSetInputFocus (display->xdisplay,
|
XSetInputFocus (display->xdisplay,
|
||||||
focus_frame ? window->frame->xwindow : window->xwindow,
|
focus_frame ? window->frame->xwindow : window->xwindow,
|
||||||
RevertToPointerRoot,
|
RevertToPointerRoot,
|
||||||
timestamp);
|
timestamp);
|
||||||
meta_error_trap_pop (display);
|
meta_error_trap_pop (display);
|
||||||
|
|
||||||
display->expected_focus_window = window;
|
|
||||||
display->last_focus_time = timestamp;
|
display->last_focus_time = timestamp;
|
||||||
display->active_screen = window->screen;
|
display->active_screen = window->screen;
|
||||||
|
|
||||||
if (window != display->autoraise_window)
|
if (window != display->autoraise_window)
|
||||||
meta_display_remove_autoraise_callback (window->display);
|
meta_display_remove_autoraise_callback (window->display);
|
||||||
|
|
||||||
|
set_focus_window (display, window, display->focus_serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_display_request_take_focus (MetaDisplay *display,
|
||||||
|
MetaWindow *window,
|
||||||
|
guint32 timestamp)
|
||||||
|
{
|
||||||
|
if (timestamp_too_old (display, window, ×tamp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_FOCUS, "WM_TAKE_FOCUS(%s, %u)\n",
|
||||||
|
window->desc, timestamp);
|
||||||
|
|
||||||
|
if (window != display->focus_window)
|
||||||
|
{
|
||||||
|
/* The "Globally Active Input" window case, where the window
|
||||||
|
* doesn't want us to call XSetInputFocus on it, but does
|
||||||
|
* want us to send a WM_TAKE_FOCUS.
|
||||||
|
*
|
||||||
|
* We can't just set display->focus_window to @window, since we
|
||||||
|
* we don't know when (or even if) the window will actually take
|
||||||
|
* focus, so we could end up being wrong for arbitrarily long.
|
||||||
|
* But we also can't leave it set to the current window, or else
|
||||||
|
* bug #597352 would come back. So we focus the no_focus_window
|
||||||
|
* now (and set display->focus_window to that), send the
|
||||||
|
* WM_TAKE_FOCUS, and then just forget about @window
|
||||||
|
* until/unless we get a FocusIn.
|
||||||
|
*/
|
||||||
|
meta_display_focus_the_no_focus_window (display,
|
||||||
|
window->screen,
|
||||||
|
timestamp);
|
||||||
|
}
|
||||||
|
meta_window_send_icccm_message (window,
|
||||||
|
display->atom_WM_TAKE_FOCUS,
|
||||||
|
timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -5644,15 +5825,19 @@ meta_display_focus_the_no_focus_window (MetaDisplay *display,
|
|||||||
if (timestamp_too_old (display, NULL, ×tamp))
|
if (timestamp_too_old (display, NULL, ×tamp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
display->focus_serial = XNextRequest (display->xdisplay);
|
||||||
|
meta_topic (META_DEBUG_FOCUS, "Focusing no_focus_window at %u with serial %lu\n",
|
||||||
|
timestamp, display->focus_serial);
|
||||||
XSetInputFocus (display->xdisplay,
|
XSetInputFocus (display->xdisplay,
|
||||||
screen->no_focus_window,
|
screen->no_focus_window,
|
||||||
RevertToPointerRoot,
|
RevertToPointerRoot,
|
||||||
timestamp);
|
timestamp);
|
||||||
display->expected_focus_window = NULL;
|
|
||||||
display->last_focus_time = timestamp;
|
display->last_focus_time = timestamp;
|
||||||
display->active_screen = screen;
|
display->active_screen = screen;
|
||||||
|
|
||||||
meta_display_remove_autoraise_callback (display);
|
meta_display_remove_autoraise_callback (display);
|
||||||
|
|
||||||
|
set_focus_window (display, NULL, display->focus_serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -5762,11 +5947,9 @@ meta_display_has_shape (MetaDisplay *display)
|
|||||||
* meta_display_get_focus_window:
|
* meta_display_get_focus_window:
|
||||||
* @display: a #MetaDisplay
|
* @display: a #MetaDisplay
|
||||||
*
|
*
|
||||||
* Get the window that, according to events received from X server,
|
* Get our best guess as to the "currently" focused window (that is,
|
||||||
* currently has the input focus. We may have already sent a request
|
* the window that we expect will be focused at the point when the X
|
||||||
* to the X server to move the focus window elsewhere. (The
|
* server processes our next request).
|
||||||
* expected_focus_window records where we've last set the input
|
|
||||||
* focus.)
|
|
||||||
*
|
*
|
||||||
* Return Value: (transfer none): The current focus window
|
* Return Value: (transfer none): The current focus window
|
||||||
*/
|
*/
|
||||||
|
@ -278,7 +278,7 @@ static gboolean
|
|||||||
is_focused_foreach (MetaWindow *window,
|
is_focused_foreach (MetaWindow *window,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
if (window == window->display->expected_focus_window)
|
if (window->has_focus)
|
||||||
{
|
{
|
||||||
*((gboolean*) data) = TRUE;
|
*((gboolean*) data) = TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -335,11 +335,11 @@ get_standalone_layer (MetaWindow *window)
|
|||||||
layer = META_LAYER_BOTTOM;
|
layer = META_LAYER_BOTTOM;
|
||||||
else if (window->fullscreen &&
|
else if (window->fullscreen &&
|
||||||
(focused_transient ||
|
(focused_transient ||
|
||||||
window == window->display->expected_focus_window ||
|
window == window->display->focus_window ||
|
||||||
window->display->expected_focus_window == NULL ||
|
window->display->focus_window == NULL ||
|
||||||
(window->display->expected_focus_window != NULL &&
|
(window->display->focus_window != NULL &&
|
||||||
windows_on_different_monitor (window,
|
windows_on_different_monitor (window,
|
||||||
window->display->expected_focus_window))))
|
window->display->focus_window))))
|
||||||
layer = META_LAYER_FULLSCREEN;
|
layer = META_LAYER_FULLSCREEN;
|
||||||
else if (window->wm_state_above && !META_WINDOW_MAXIMIZED (window))
|
else if (window->wm_state_above && !META_WINDOW_MAXIMIZED (window))
|
||||||
layer = META_LAYER_TOP;
|
layer = META_LAYER_TOP;
|
||||||
|
@ -277,7 +277,7 @@ struct _MetaWindow
|
|||||||
/* EWHH demands attention flag */
|
/* EWHH demands attention flag */
|
||||||
guint wm_state_demands_attention : 1;
|
guint wm_state_demands_attention : 1;
|
||||||
|
|
||||||
/* this flag tracks receipt of focus_in focus_out */
|
/* TRUE iff window == window->display->focus_window */
|
||||||
guint has_focus : 1;
|
guint has_focus : 1;
|
||||||
|
|
||||||
/* Have we placed this window? */
|
/* Have we placed this window? */
|
||||||
@ -590,9 +590,8 @@ gboolean meta_window_property_notify (MetaWindow *window,
|
|||||||
XEvent *event);
|
XEvent *event);
|
||||||
gboolean meta_window_client_message (MetaWindow *window,
|
gboolean meta_window_client_message (MetaWindow *window,
|
||||||
XEvent *event);
|
XEvent *event);
|
||||||
gboolean meta_window_notify_focus (MetaWindow *window,
|
void meta_window_set_focused_internal (MetaWindow *window,
|
||||||
XIEnterEvent *event);
|
gboolean focused);
|
||||||
void meta_window_lost_focus (MetaWindow *window);
|
|
||||||
|
|
||||||
void meta_window_set_current_workspace_hint (MetaWindow *window);
|
void meta_window_set_current_workspace_hint (MetaWindow *window);
|
||||||
|
|
||||||
|
@ -1754,16 +1754,6 @@ meta_window_unmanage (MetaWindow *window,
|
|||||||
window,
|
window,
|
||||||
timestamp);
|
timestamp);
|
||||||
}
|
}
|
||||||
else if (window->display->expected_focus_window == window)
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"Focusing default window since expected focus window freed %s\n",
|
|
||||||
window->desc);
|
|
||||||
window->display->expected_focus_window = NULL;
|
|
||||||
meta_workspace_focus_default_window (window->screen->active_workspace,
|
|
||||||
window,
|
|
||||||
timestamp);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
@ -1771,6 +1761,8 @@ meta_window_unmanage (MetaWindow *window,
|
|||||||
window->desc);
|
window->desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_assert (window->display->focus_window != window);
|
||||||
|
|
||||||
if (window->struts)
|
if (window->struts)
|
||||||
{
|
{
|
||||||
meta_free_gslist_and_elements (window->struts);
|
meta_free_gslist_and_elements (window->struts);
|
||||||
@ -1793,12 +1785,6 @@ meta_window_unmanage (MetaWindow *window,
|
|||||||
|
|
||||||
g_assert (window->display->grab_window != window);
|
g_assert (window->display->grab_window != window);
|
||||||
|
|
||||||
if (window->display->focus_window == window)
|
|
||||||
{
|
|
||||||
window->display->focus_window = NULL;
|
|
||||||
g_object_notify (G_OBJECT (window->display), "focus-window");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window->maximized_horizontally || window->maximized_vertically)
|
if (window->maximized_horizontally || window->maximized_vertically)
|
||||||
unmaximize_window_before_freeing (window);
|
unmaximize_window_before_freeing (window);
|
||||||
|
|
||||||
@ -3332,14 +3318,7 @@ meta_window_hide (MetaWindow *window)
|
|||||||
invalidate_work_areas (window);
|
invalidate_work_areas (window);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The check on expected_focus_window is a temporary workaround for
|
if (window->has_focus)
|
||||||
* https://bugzilla.gnome.org/show_bug.cgi?id=597352
|
|
||||||
* We may have already switched away from this window but not yet
|
|
||||||
* gotten FocusIn/FocusOut events. A more complete comprehensive
|
|
||||||
* fix for these type of issues is described in the bug.
|
|
||||||
*/
|
|
||||||
if (window->has_focus &&
|
|
||||||
window == window->display->expected_focus_window)
|
|
||||||
{
|
{
|
||||||
MetaWindow *not_this_one = NULL;
|
MetaWindow *not_this_one = NULL;
|
||||||
MetaWorkspace *my_workspace = meta_window_get_workspace (window);
|
MetaWorkspace *my_workspace = meta_window_get_workspace (window);
|
||||||
@ -5975,10 +5954,10 @@ meta_window_focus (MetaWindow *window,
|
|||||||
meta_topic (META_DEBUG_FOCUS,
|
meta_topic (META_DEBUG_FOCUS,
|
||||||
"Sending WM_TAKE_FOCUS to %s since take_focus = true\n",
|
"Sending WM_TAKE_FOCUS to %s since take_focus = true\n",
|
||||||
window->desc);
|
window->desc);
|
||||||
meta_window_send_icccm_message (window,
|
|
||||||
window->display->atom_WM_TAKE_FOCUS,
|
meta_display_request_take_focus (window->display,
|
||||||
|
window,
|
||||||
timestamp);
|
timestamp);
|
||||||
window->display->expected_focus_window = window;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6518,7 +6497,7 @@ meta_window_configure_request (MetaWindow *window,
|
|||||||
if (event->xconfigurerequest.value_mask & CWStackMode)
|
if (event->xconfigurerequest.value_mask & CWStackMode)
|
||||||
{
|
{
|
||||||
MetaWindow *active_window;
|
MetaWindow *active_window;
|
||||||
active_window = window->display->expected_focus_window;
|
active_window = window->display->focus_window;
|
||||||
if (meta_prefs_get_disable_workarounds ())
|
if (meta_prefs_get_disable_workarounds ())
|
||||||
{
|
{
|
||||||
meta_topic (META_DEBUG_STACK,
|
meta_topic (META_DEBUG_STACK,
|
||||||
@ -7197,8 +7176,7 @@ meta_window_propagate_focus_appearance (MetaWindow *window,
|
|||||||
parent->attached_focus_window = NULL;
|
parent->attached_focus_window = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_focus_state_changed && !parent->has_focus &&
|
if (child_focus_state_changed && !parent->has_focus)
|
||||||
parent != window->display->expected_focus_window)
|
|
||||||
{
|
{
|
||||||
meta_window_appears_focused_changed (parent);
|
meta_window_appears_focused_changed (parent);
|
||||||
}
|
}
|
||||||
@ -7208,18 +7186,12 @@ meta_window_propagate_focus_appearance (MetaWindow *window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
meta_window_set_focused_internal (MetaWindow *window,
|
meta_window_set_focused_internal (MetaWindow *window,
|
||||||
gboolean focused)
|
gboolean focused)
|
||||||
{
|
{
|
||||||
if (focused)
|
if (focused)
|
||||||
{
|
{
|
||||||
if (window == window->display->focus_window)
|
|
||||||
return;
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"* Focus --> %s\n", window->desc);
|
|
||||||
window->display->focus_window = window;
|
|
||||||
window->has_focus = TRUE;
|
window->has_focus = TRUE;
|
||||||
|
|
||||||
/* Move to the front of the focusing workspace's MRU list.
|
/* Move to the front of the focusing workspace's MRU list.
|
||||||
@ -7278,7 +7250,6 @@ meta_window_set_focused_internal (MetaWindow *window,
|
|||||||
meta_display_ungrab_focus_window_button (window->display, window);
|
meta_display_ungrab_focus_window_button (window->display, window);
|
||||||
|
|
||||||
g_signal_emit (window, window_signals[FOCUS], 0);
|
g_signal_emit (window, window_signals[FOCUS], 0);
|
||||||
g_object_notify (G_OBJECT (window->display), "focus-window");
|
|
||||||
|
|
||||||
if (!window->attached_focus_window)
|
if (!window->attached_focus_window)
|
||||||
meta_window_appears_focused_changed (window);
|
meta_window_appears_focused_changed (window);
|
||||||
@ -7287,12 +7258,7 @@ meta_window_set_focused_internal (MetaWindow *window,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (window != window->display->focus_window)
|
|
||||||
return;
|
|
||||||
|
|
||||||
meta_window_propagate_focus_appearance (window, FALSE);
|
meta_window_propagate_focus_appearance (window, FALSE);
|
||||||
window->display->focus_window = NULL;
|
|
||||||
g_object_notify (G_OBJECT (window->display), "focus-window");
|
|
||||||
window->has_focus = FALSE;
|
window->has_focus = FALSE;
|
||||||
|
|
||||||
if (!window->attached_focus_window)
|
if (!window->attached_focus_window)
|
||||||
@ -7313,115 +7279,6 @@ meta_window_set_focused_internal (MetaWindow *window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
meta_window_lost_focus (MetaWindow *window)
|
|
||||||
{
|
|
||||||
meta_window_set_focused_internal (window, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
meta_window_notify_focus (MetaWindow *window,
|
|
||||||
XIEnterEvent *event)
|
|
||||||
{
|
|
||||||
/* note the event can be on either the window or the frame,
|
|
||||||
* we focus the frame for shaded windows
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The event can be FocusIn, FocusOut, or UnmapNotify.
|
|
||||||
* On UnmapNotify we have to pretend it's focus out,
|
|
||||||
* because we won't get a focus out if it occurs, apparently.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* We ignore grabs, though this is questionable.
|
|
||||||
* It may be better to increase the intelligence of
|
|
||||||
* the focus window tracking.
|
|
||||||
*
|
|
||||||
* The problem is that keybindings for windows are done with
|
|
||||||
* XGrabKey, which means focus_window disappears and the front of
|
|
||||||
* the MRU list gets confused from what the user expects once a
|
|
||||||
* keybinding is used.
|
|
||||||
*/
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"Focus %s event received on %s 0x%lx (%s) "
|
|
||||||
"mode %s detail %s\n",
|
|
||||||
event->evtype == XI_FocusIn ? "in" :
|
|
||||||
event->evtype == XI_FocusOut ? "out" :
|
|
||||||
"???",
|
|
||||||
window->desc, event->event,
|
|
||||||
event->event == window->xwindow ?
|
|
||||||
"client window" :
|
|
||||||
(window->frame && event->event == window->frame->xwindow) ?
|
|
||||||
"frame window" :
|
|
||||||
"unknown window",
|
|
||||||
meta_event_mode_to_string (event->mode),
|
|
||||||
meta_event_detail_to_string (event->detail));
|
|
||||||
|
|
||||||
/* FIXME our pointer tracking is broken; see how
|
|
||||||
* gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c
|
|
||||||
* handle it for the correct way. In brief you need to track
|
|
||||||
* pointer focus and regular focus, and handle EnterNotify in
|
|
||||||
* PointerRoot mode with no window manager. However as noted above,
|
|
||||||
* accurate focus tracking will break things because we want to keep
|
|
||||||
* windows "focused" when using keybindings on them, and also we
|
|
||||||
* sometimes "focus" a window by focusing its frame or
|
|
||||||
* no_focus_window; so this all needs rethinking massively.
|
|
||||||
*
|
|
||||||
* My suggestion is to change it so that we clearly separate
|
|
||||||
* actual keyboard focus tracking using the xterm algorithm,
|
|
||||||
* and mutter's "pretend" focus window, and go through all
|
|
||||||
* the code and decide which one should be used in each place;
|
|
||||||
* a hard bit is deciding on a policy for that.
|
|
||||||
*
|
|
||||||
* http://bugzilla.gnome.org/show_bug.cgi?id=90382
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ((event->evtype == XI_FocusIn ||
|
|
||||||
event->evtype == XI_FocusOut) &&
|
|
||||||
(event->mode == NotifyGrab ||
|
|
||||||
event->mode == NotifyUngrab ||
|
|
||||||
/* From WindowMaker, ignore all funky pointer root events */
|
|
||||||
event->detail > NotifyNonlinearVirtual))
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"Ignoring focus event generated by a grab or other weirdness\n");
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->evtype == XI_FocusIn)
|
|
||||||
{
|
|
||||||
if (window->override_redirect)
|
|
||||||
{
|
|
||||||
window->display->focus_window = NULL;
|
|
||||||
g_object_notify (G_OBJECT (window->display), "focus-window");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
meta_window_set_focused_internal (window, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event->evtype == XI_FocusOut)
|
|
||||||
{
|
|
||||||
if (event->detail == NotifyInferior)
|
|
||||||
{
|
|
||||||
/* This event means the client moved focus to a subwindow */
|
|
||||||
meta_topic (META_DEBUG_FOCUS,
|
|
||||||
"Ignoring focus out on %s with NotifyInferior\n",
|
|
||||||
window->desc);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
meta_window_set_focused_internal (window, FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now set _NET_ACTIVE_WINDOW hint */
|
|
||||||
meta_display_update_active_window_hint (window->display);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
process_property_notify (MetaWindow *window,
|
process_property_notify (MetaWindow *window,
|
||||||
XPropertyEvent *event)
|
XPropertyEvent *event)
|
||||||
|
@ -165,6 +165,10 @@ void meta_display_set_input_focus_window (MetaDisplay *display,
|
|||||||
gboolean focus_frame,
|
gboolean focus_frame,
|
||||||
guint32 timestamp);
|
guint32 timestamp);
|
||||||
|
|
||||||
|
void meta_display_request_take_focus (MetaDisplay *display,
|
||||||
|
MetaWindow *window,
|
||||||
|
guint32 timestamp);
|
||||||
|
|
||||||
/* meta_display_focus_the_no_focus_window is called when the
|
/* meta_display_focus_the_no_focus_window is called when the
|
||||||
* designated no_focus_window should be focused, but is otherwise the
|
* designated no_focus_window should be focused, but is otherwise the
|
||||||
* same as meta_display_set_input_focus_window
|
* same as meta_display_set_input_focus_window
|
||||||
|
@ -857,10 +857,7 @@ meta_convert_meta_to_wnck (MetaWindow *window, MetaScreen *screen)
|
|||||||
WnckWindowDisplayInfo wnck_window;
|
WnckWindowDisplayInfo wnck_window;
|
||||||
wnck_window.icon = window->icon;
|
wnck_window.icon = window->icon;
|
||||||
wnck_window.mini_icon = window->mini_icon;
|
wnck_window.mini_icon = window->mini_icon;
|
||||||
|
wnck_window.is_active = window->has_focus;
|
||||||
wnck_window.is_active = FALSE;
|
|
||||||
if (window == window->display->expected_focus_window)
|
|
||||||
wnck_window.is_active = TRUE;
|
|
||||||
|
|
||||||
if (window->frame)
|
if (window->frame)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user