broadway: use 'click-to-focus' approach instead of 'focus-follows-mouse'
The broadway backend would move the focus from one window to another based on where the mouse was (i.e. 'focus-follows-mouse' approach). Handling the focus this wait didn't play well with widgets which rely on focus-in-event and focus-out-event, like the GtkEntry when using a completion popup window, see e.g: https://bugzilla.gnome.org/show_bug.cgi?id=708984 So instead, setup broadway to require a click in a window to move the focus (i.e. 'click-to-focus' approach): * The implicit GDK_FOCUS_CHANGE events that were generated upon reception of BROADWAY_EVENT_ENTER or BROADWAY_EVENT_LEAVE are removed. * The broadway daemon will now keep track of which is the focused window * Whenever the daemon detects an incoming BROADWAY_EVENT_BUTTON_PRESS, it will trigger the focused window switch, which sends a new BROADWAY_EVENT_FOCUS to the client, specifying which windows holds the focus. * Upon reception of a BROADWAY_EVENT_FOCUS, the client will generate a new GDK_FOCUS_CHANGE. * gdk_broadway_window_focus() was also implemented, which now requests the focus to the broadway server using a new BROADWAY_REQUEST_FOCUS_WINDOW. This is based on an initial patch from Aleksander Morgado <aleksander@lanedo.com>.
This commit is contained in:
@ -21,7 +21,8 @@ typedef enum {
|
||||
BROADWAY_EVENT_UNGRAB_NOTIFY = 'u',
|
||||
BROADWAY_EVENT_CONFIGURE_NOTIFY = 'w',
|
||||
BROADWAY_EVENT_DELETE_NOTIFY = 'W',
|
||||
BROADWAY_EVENT_SCREEN_SIZE_CHANGED = 'd'
|
||||
BROADWAY_EVENT_SCREEN_SIZE_CHANGED = 'd',
|
||||
BROADWAY_EVENT_FOCUS = 'f'
|
||||
} BroadwayEventType;
|
||||
|
||||
typedef enum {
|
||||
@ -104,6 +105,11 @@ typedef struct {
|
||||
gint32 id;
|
||||
} BroadwayInputDeleteNotify;
|
||||
|
||||
typedef struct {
|
||||
BroadwayInputBaseMsg base;
|
||||
gint32 id;
|
||||
} BroadwayInputFocusMsg;
|
||||
|
||||
typedef union {
|
||||
BroadwayInputBaseMsg base;
|
||||
BroadwayInputPointerMsg pointer;
|
||||
@ -115,6 +121,7 @@ typedef union {
|
||||
BroadwayInputConfigureNotify configure_notify;
|
||||
BroadwayInputDeleteNotify delete_notify;
|
||||
BroadwayInputScreenResizeNotify screen_resize_notify;
|
||||
BroadwayInputFocusMsg focus;
|
||||
} BroadwayInputMsg;
|
||||
|
||||
typedef enum {
|
||||
@ -129,7 +136,8 @@ typedef enum {
|
||||
BROADWAY_REQUEST_UPDATE,
|
||||
BROADWAY_REQUEST_MOVE_RESIZE,
|
||||
BROADWAY_REQUEST_GRAB_POINTER,
|
||||
BROADWAY_REQUEST_UNGRAB_POINTER
|
||||
BROADWAY_REQUEST_UNGRAB_POINTER,
|
||||
BROADWAY_REQUEST_FOCUS_WINDOW
|
||||
} BroadwayRequestType;
|
||||
|
||||
typedef struct {
|
||||
@ -141,7 +149,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
BroadwayRequestBase base;
|
||||
guint32 id;
|
||||
} BroadwayRequestDestroyWindow, BroadwayRequestShowWindow, BroadwayRequestHideWindow;
|
||||
} BroadwayRequestDestroyWindow, BroadwayRequestShowWindow, BroadwayRequestHideWindow, BroadwayRequestFocusWindow;
|
||||
|
||||
typedef struct {
|
||||
BroadwayRequestBase base;
|
||||
@ -213,6 +221,7 @@ typedef union {
|
||||
BroadwayRequestGrabPointer grab_pointer;
|
||||
BroadwayRequestUngrabPointer ungrab_pointer;
|
||||
BroadwayRequestTranslate translate;
|
||||
BroadwayRequestFocusWindow focus_window;
|
||||
} BroadwayRequest;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@ -54,6 +54,7 @@ struct _BroadwayServer {
|
||||
GHashTable *id_ht;
|
||||
GList *toplevels;
|
||||
BroadwayWindow *root;
|
||||
gint32 focused_window_id; /* -1 => none */
|
||||
|
||||
guint32 screen_width;
|
||||
guint32 screen_height;
|
||||
@ -215,6 +216,10 @@ update_event_state (BroadwayServer *server,
|
||||
break;
|
||||
case BROADWAY_EVENT_BUTTON_PRESS:
|
||||
case BROADWAY_EVENT_BUTTON_RELEASE:
|
||||
if (message->base.type == BROADWAY_EVENT_BUTTON_PRESS &&
|
||||
server->focused_window_id != message->pointer.mouse_window_id)
|
||||
broadway_server_focus_window (server, message->pointer.mouse_window_id);
|
||||
|
||||
server->last_x = message->pointer.root_x;
|
||||
server->last_y = message->pointer.root_y;
|
||||
server->last_state = message->pointer.state;
|
||||
@ -1460,6 +1465,26 @@ broadway_server_window_move_resize (BroadwayServer *server,
|
||||
return sent;
|
||||
}
|
||||
|
||||
void
|
||||
broadway_server_focus_window (BroadwayServer *server,
|
||||
gint new_focused_window)
|
||||
{
|
||||
BroadwayInputMsg focus_msg;
|
||||
|
||||
if (server->focused_window_id == new_focused_window)
|
||||
return;
|
||||
|
||||
/* Keep track of the new focused window */
|
||||
server->focused_window_id = new_focused_window;
|
||||
|
||||
memset (&focus_msg, 0, sizeof (focus_msg));
|
||||
focus_msg.base.type = BROADWAY_EVENT_FOCUS;
|
||||
focus_msg.base.time = broadway_server_get_last_seen_time (server);
|
||||
focus_msg.focus.id = new_focused_window;
|
||||
|
||||
broadway_events_got_input (&focus_msg, -1);
|
||||
}
|
||||
|
||||
guint32
|
||||
broadway_server_grab_pointer (BroadwayServer *server,
|
||||
gint client_id,
|
||||
|
||||
@ -78,6 +78,8 @@ gboolean broadway_server_window_move_resize (BroadwayServer *
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
void broadway_server_focus_window (BroadwayServer *server,
|
||||
gint new_focused_window);
|
||||
cairo_surface_t * broadway_server_open_surface (BroadwayServer *server,
|
||||
guint32 id,
|
||||
char *name,
|
||||
|
||||
@ -294,6 +294,9 @@ client_handle_request (BroadwayClient *client,
|
||||
send_reply (client, request, (BroadwayReply *)&reply_ungrab_pointer, sizeof (reply_ungrab_pointer),
|
||||
BROADWAY_REPLY_UNGRAB_POINTER);
|
||||
break;
|
||||
case BROADWAY_REQUEST_FOCUS_WINDOW:
|
||||
broadway_server_focus_window (server, request->focus_window.id);
|
||||
break;
|
||||
default:
|
||||
g_warning ("Unknown request of type %d\n", request->base.type);
|
||||
}
|
||||
@ -537,6 +540,8 @@ get_event_size (int type)
|
||||
return sizeof (BroadwayInputDeleteNotify);
|
||||
case BROADWAY_EVENT_SCREEN_SIZE_CHANGED:
|
||||
return sizeof (BroadwayInputScreenResizeNotify);
|
||||
case BROADWAY_EVENT_FOCUS:
|
||||
return sizeof (BroadwayInputFocusMsg);
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
@ -497,6 +497,17 @@ _gdk_broadway_server_window_hide (GdkBroadwayServer *server,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_broadway_server_window_focus (GdkBroadwayServer *server,
|
||||
gint id)
|
||||
{
|
||||
BroadwayRequestFocusWindow msg;
|
||||
|
||||
msg.id = id;
|
||||
gdk_broadway_server_send_message (server, msg,
|
||||
BROADWAY_REQUEST_FOCUS_WINDOW);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server,
|
||||
gint id, gint parent)
|
||||
|
||||
@ -47,6 +47,8 @@ gboolean _gdk_broadway_server_window_show (GdkBroadwaySer
|
||||
gint id);
|
||||
gboolean _gdk_broadway_server_window_hide (GdkBroadwayServer *server,
|
||||
gint id);
|
||||
void _gdk_broadway_server_window_focus (GdkBroadwayServer *server,
|
||||
gint id);
|
||||
void _gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server,
|
||||
gint id,
|
||||
gint parent);
|
||||
|
||||
@ -117,14 +117,6 @@ _gdk_broadway_events_got_input (BroadwayInputMsg *message)
|
||||
|
||||
node = _gdk_event_queue_append (display, event);
|
||||
_gdk_windowing_got_event (display, node, event, message->base.serial);
|
||||
|
||||
event = gdk_event_new (GDK_FOCUS_CHANGE);
|
||||
event->focus_change.window = g_object_ref (window);
|
||||
event->focus_change.in = TRUE;
|
||||
gdk_event_set_device (event, display->core_pointer);
|
||||
|
||||
node = _gdk_event_queue_append (display, event);
|
||||
_gdk_windowing_got_event (display, node, event, message->base.serial);
|
||||
}
|
||||
break;
|
||||
case BROADWAY_EVENT_LEAVE:
|
||||
@ -145,14 +137,6 @@ _gdk_broadway_events_got_input (BroadwayInputMsg *message)
|
||||
|
||||
node = _gdk_event_queue_append (display, event);
|
||||
_gdk_windowing_got_event (display, node, event, message->base.serial);
|
||||
|
||||
event = gdk_event_new (GDK_FOCUS_CHANGE);
|
||||
event->focus_change.window = g_object_ref (window);
|
||||
event->focus_change.in = FALSE;
|
||||
gdk_event_set_device (event, display->core_pointer);
|
||||
|
||||
node = _gdk_event_queue_append (display, event);
|
||||
_gdk_windowing_got_event (display, node, event, message->base.serial);
|
||||
}
|
||||
break;
|
||||
case BROADWAY_EVENT_POINTER_MOVE:
|
||||
@ -295,6 +279,19 @@ _gdk_broadway_events_got_input (BroadwayInputMsg *message)
|
||||
_gdk_broadway_screen_size_changed (screen, &message->screen_resize_notify);
|
||||
break;
|
||||
|
||||
case BROADWAY_EVENT_FOCUS:
|
||||
window = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->focus.id));
|
||||
if (window)
|
||||
{
|
||||
event = gdk_event_new (GDK_FOCUS_CHANGE);
|
||||
event->focus_change.window = g_object_ref (window);
|
||||
event->focus_change.in = TRUE;
|
||||
gdk_event_set_device (event, display->core_pointer);
|
||||
node = _gdk_event_queue_append (display, event);
|
||||
_gdk_windowing_got_event (display, node, event, message->base.serial);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_printerr ("_gdk_broadway_events_got_input - Unknown input command %c\n", message->base.type);
|
||||
break;
|
||||
|
||||
@ -537,6 +537,19 @@ static void
|
||||
gdk_broadway_window_focus (GdkWindow *window,
|
||||
guint32 timestamp)
|
||||
{
|
||||
GdkWindowImplBroadway *impl;
|
||||
GdkBroadwayDisplay *broadway_display;
|
||||
|
||||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||||
|
||||
if (GDK_WINDOW_DESTROYED (window) ||
|
||||
!window->accept_focus)
|
||||
return;
|
||||
|
||||
impl = GDK_WINDOW_IMPL_BROADWAY (window->impl);
|
||||
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window));
|
||||
_gdk_broadway_server_window_focus (broadway_display->server,
|
||||
impl->id);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
Reference in New Issue
Block a user