[gtk+] broadway: use 'click-to-focus' approach instead of 'focus-follows-mouse'



commit ddade6649613be5442af39b632f0277220bd6fa3
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Nov 12 12:03:50 2013 +0100

    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>.

 gdk/broadway/broadway-protocol.h  |   15 ++++++++++++---
 gdk/broadway/broadway-server.c    |   25 +++++++++++++++++++++++++
 gdk/broadway/broadway-server.h    |    2 ++
 gdk/broadway/broadwayd.c          |    5 +++++
 gdk/broadway/gdkbroadway-server.c |   11 +++++++++++
 gdk/broadway/gdkbroadway-server.h |    2 ++
 gdk/broadway/gdkeventsource.c     |   29 +++++++++++++----------------
 gdk/broadway/gdkwindow-broadway.c |   13 +++++++++++++
 8 files changed, 83 insertions(+), 19 deletions(-)
---
diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h
index 7c25f8c..d42625f 100644
--- a/gdk/broadway/broadway-protocol.h
+++ b/gdk/broadway/broadway-protocol.h
@@ -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 {
diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c
index c3ebef6..ae88cce 100644
--- a/gdk/broadway/broadway-server.c
+++ b/gdk/broadway/broadway-server.c
@@ -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,
diff --git a/gdk/broadway/broadway-server.h b/gdk/broadway/broadway-server.h
index 7941bcd..e5a3718 100644
--- a/gdk/broadway/broadway-server.h
+++ b/gdk/broadway/broadway-server.h
@@ -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,
diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c
index eb98528..8c24a4f 100644
--- a/gdk/broadway/broadwayd.c
+++ b/gdk/broadway/broadwayd.c
@@ -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 ();
     }
diff --git a/gdk/broadway/gdkbroadway-server.c b/gdk/broadway/gdkbroadway-server.c
index 0324764..d85cfa5 100644
--- a/gdk/broadway/gdkbroadway-server.c
+++ b/gdk/broadway/gdkbroadway-server.c
@@ -498,6 +498,17 @@ _gdk_broadway_server_window_hide (GdkBroadwayServer *server,
 }
 
 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)
 {
diff --git a/gdk/broadway/gdkbroadway-server.h b/gdk/broadway/gdkbroadway-server.h
index 2b93a85..0ddf39e 100644
--- a/gdk/broadway/gdkbroadway-server.h
+++ b/gdk/broadway/gdkbroadway-server.h
@@ -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);
diff --git a/gdk/broadway/gdkeventsource.c b/gdk/broadway/gdkeventsource.c
index d7cdede..5330d6b 100644
--- a/gdk/broadway/gdkeventsource.c
+++ b/gdk/broadway/gdkeventsource.c
@@ -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;
diff --git a/gdk/broadway/gdkwindow-broadway.c b/gdk/broadway/gdkwindow-broadway.c
index 8cd0602..5a67bb1 100644
--- a/gdk/broadway/gdkwindow-broadway.c
+++ b/gdk/broadway/gdkwindow-broadway.c
@@ -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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]