gdk/broadway: Implements modal hint for Broadway surface
authorMaxim Zakharov <zakhma@muli.com.au>
Mon, 31 Jan 2022 00:30:32 +0000 (11:30 +1100)
committerMaxim Zakharov <zakhma@muli.com.au>
Tue, 17 May 2022 05:18:30 +0000 (15:18 +1000)
Ensures modal window is raised above parent; does return focus to
parent window when transient child window is closed.

That solves problems with overlapped modal window and focus loss in
complex multi window UI.

gdk/broadway/broadway-protocol.h
gdk/broadway/broadway-server.c
gdk/broadway/broadway-server.h
gdk/broadway/broadwayd.c
gdk/broadway/gdkbroadway-server.c
gdk/broadway/gdkbroadway-server.h
gdk/broadway/gdkeventsource.c
gdk/broadway/gdksurface-broadway.c
gdk/broadway/gdksurface-broadway.h

index 9b56dff6dfc028706eba8550162c8f3c0e4efdb1..875d6ac1432d7e3022c0e04e3ee25419a4509f4b 100644 (file)
@@ -213,6 +213,7 @@ typedef enum {
   BROADWAY_REQUEST_RELEASE_TEXTURE,
   BROADWAY_REQUEST_SET_NODES,
   BROADWAY_REQUEST_ROUNDTRIP,
+  BROADWAY_REQUEST_SET_MODAL_HINT,
 } BroadwayRequestType;
 
 typedef struct {
@@ -293,6 +294,12 @@ typedef struct {
   guint32 show_keyboard;
 } BroadwayRequestSetShowKeyboard;
 
+typedef struct {
+  BroadwayRequestBase base;
+  guint32 id;
+  gboolean modal_hint;
+} BroadwayRequestSetModalHint;
+
 typedef union {
   BroadwayRequestBase base;
   BroadwayRequestNewSurface new_surface;
@@ -312,6 +319,7 @@ typedef union {
   BroadwayRequestUploadTexture upload_texture;
   BroadwayRequestReleaseTexture release_texture;
   BroadwayRequestSetNodes set_nodes;
+  BroadwayRequestSetModalHint set_modal_hint;
 } BroadwayRequest;
 
 typedef enum {
index b90c849f94e1d998626cba773ef2d440bc1d42f4..8c0be3818e1b800da307402c7e2e2b589da01794 100644 (file)
@@ -128,6 +128,7 @@ struct BroadwaySurface {
   gboolean visible;
   gint32 transient_for;
   guint32 texture;
+  gboolean modal_hint;
   BroadwayNode *nodes;
   GHashTable *node_lookup;
 };
@@ -425,6 +426,14 @@ update_event_state (BroadwayServer *server,
       {
         surface->x = message->configure_notify.x;
         surface->y = message->configure_notify.y;
+
+       if (server->focused_surface_id != message->configure_notify.id &&
+           server->pointer_grab_surface_id == -1 && surface->modal_hint)
+       {
+         broadway_server_surface_raise (server, message->configure_notify.id);
+         broadway_server_focus_surface (server, message->configure_notify.id);
+         broadway_server_flush (server);
+       }
       }
     break;
   case BROADWAY_EVENT_ROUNDTRIP_NOTIFY:
@@ -1572,6 +1581,7 @@ broadway_server_destroy_surface (BroadwayServer *server,
                                  int id)
 {
   BroadwaySurface *surface;
+  gint32 transient_for = -1;
 
   if (server->mouse_in_surface_id == id)
     {
@@ -1589,11 +1599,24 @@ broadway_server_destroy_surface (BroadwayServer *server,
   surface = broadway_server_lookup_surface (server, id);
   if (surface != NULL)
     {
+      if (server->focused_surface_id == id)
+       transient_for = surface->transient_for;
+
       server->surfaces = g_list_remove (server->surfaces, surface);
       g_hash_table_remove (server->surface_id_hash,
                            GINT_TO_POINTER (id));
       broadway_surface_free (server, surface);
     }
+
+  if (transient_for != -1)
+    {
+      surface = broadway_server_lookup_surface (server, transient_for);
+      if (surface != NULL)
+        {
+         broadway_server_focus_surface (server, transient_for);
+         broadway_server_flush (server);
+       }
+    }
 }
 
 gboolean
@@ -1714,6 +1737,19 @@ broadway_server_surface_set_transient_for (BroadwayServer *server,
     }
 }
 
+void
+broadway_server_surface_set_modal_hint (BroadwayServer *server,
+                                        int id, gboolean modal_hint)
+{
+  BroadwaySurface *surface;
+
+  surface = broadway_server_lookup_surface (server, id);
+  if (surface == NULL)
+    return;
+
+  surface->modal_hint = modal_hint;
+}
+
 gboolean
 broadway_server_has_client (BroadwayServer *server)
 {
index fd027a664ee824e0653dc9963f47cdd611f2d210..1f7faad7ea161d9c55d9e8332e121005277d6478 100644 (file)
@@ -130,6 +130,9 @@ gboolean            broadway_server_surface_move_resize       (BroadwayServer  *
                                                                int              height);
 void                broadway_server_focus_surface             (BroadwayServer  *server,
                                                                int              new_focused_surface);
+void                broadway_server_surface_set_modal_hint    (BroadwayServer *server,
+                                                               int             id,
+                                                               gboolean        modal_hint);
 
 
 #endif /* __BROADWAY_SERVER__ */
index 9cfa48f1387d2ad46e70414f852883619e49f2f0..689ce72960b2370e74a997ddd29956095b5e7efb 100644 (file)
@@ -384,6 +384,11 @@ client_handle_request (BroadwayClient *client,
     case BROADWAY_REQUEST_SET_SHOW_KEYBOARD:
       broadway_server_set_show_keyboard (server, request->set_show_keyboard.show_keyboard);
       break;
+    case BROADWAY_REQUEST_SET_MODAL_HINT:
+      broadway_server_surface_set_modal_hint (server,
+                                              request->set_modal_hint.id,
+                                              request->set_modal_hint.modal_hint);
+      break;
     default:
       g_warning ("Unknown request of type %d", request->base.type);
     }
index bd221f54424682dcfbc27ff410ef2155e4e728e2..133c7a50fae3095f3951882ae71c819f90b0448e 100644 (file)
@@ -561,6 +561,18 @@ _gdk_broadway_server_surface_set_transient_for (GdkBroadwayServer *server,
                                     BROADWAY_REQUEST_SET_TRANSIENT_FOR);
 }
 
+void
+_gdk_broadway_server_surface_set_modal_hint (GdkBroadwayServer *server,
+                                             int id, gboolean modal_hint)
+{
+  BroadwayRequestSetModalHint msg;
+
+  msg.id = id;
+  msg.modal_hint = modal_hint;
+  gdk_broadway_server_send_message (server, msg,
+                                   BROADWAY_REQUEST_SET_MODAL_HINT);
+}
+
 static int
 open_shared_memory (void)
 {
index d4557d556bd7f73911ef74f2f73063c37cefa42d..3fac98a75b08c9e3c69ec5317c29318a5e11af14 100644 (file)
@@ -78,5 +78,8 @@ gboolean           _gdk_broadway_server_surface_move_resize       (GdkBroadwaySe
                                                                  int                 y,
                                                                  int                 width,
                                                                  int                 height);
+void               _gdk_broadway_server_surface_set_modal_hint   (GdkBroadwayServer *server,
+                                                                  int                id,
+                                                                  gboolean           modal_hint);
 
 #endif /* __GDK_BROADWAY_SERVER__ */
index 9ae9022a4100474e238424e91eb5c12eda9b6d4e..17e934d48d180ad6907cfdd4603fa3c536fa617b 100644 (file)
@@ -82,6 +82,26 @@ gdk_event_source_check (GSource *source)
   return retval;
 }
 
+static void
+handle_focus_change (GdkEvent *event)
+{
+  GdkSurface *surface = gdk_event_get_surface(event);
+  GdkEvent *focus_event;
+  gboolean focus_in = (gdk_event_get_event_type (event) == GDK_ENTER_NOTIFY);
+
+  if (gdk_crossing_event_get_detail (event) == GDK_NOTIFY_INFERIOR)
+    return;
+
+  if (!gdk_crossing_event_get_focus (event) )
+    return;
+
+  focus_event = gdk_focus_event_new (gdk_event_get_surface (event),
+                                    gdk_event_get_device (event),
+                                    focus_in);
+  gdk_display_put_event (gdk_event_get_display (event), focus_event);
+  gdk_event_unref (focus_event);
+}
+
 void
 _gdk_broadway_events_got_input (GdkDisplay *display,
                                 BroadwayInputMsg *message)
@@ -110,6 +130,8 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
 
         node = _gdk_event_queue_append (display, event);
         _gdk_windowing_got_event (display, node, event, message->base.serial);
+
+       handle_focus_change (event);
       }
     break;
   case BROADWAY_EVENT_LEAVE:
@@ -126,6 +148,8 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
                                         message->crossing.mode,
                                         GDK_NOTIFY_ANCESTOR);
 
+       handle_focus_change (event);
+
         node = _gdk_event_queue_append (display, event);
         _gdk_windowing_got_event (display, node, event, message->base.serial);
       }
index d341303526718bf514d531f37e4bcf146977d9e4..b3e5c235f0e02cba0f224dc731b160e080eb71d4 100644 (file)
@@ -709,6 +709,21 @@ gdk_broadway_surface_set_transient_for (GdkSurface *surface,
   _gdk_broadway_server_surface_set_transient_for (display->server, impl->id, impl->transient_for);
 }
 
+static void
+gdk_broadway_surface_set_modal_hint (GdkSurface *surface,
+                                     gboolean   modal)
+ {
+  GdkBroadwayDisplay *display;
+  GdkBroadwaySurface *impl;
+
+  impl = GDK_BROADWAY_SURFACE (surface);
+
+  impl->modal_hint = modal;
+
+  display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (surface));
+  _gdk_broadway_server_surface_set_modal_hint (display->server, impl->id, impl->modal_hint);
+ }
+
 static void
 gdk_broadway_surface_get_geometry (GdkSurface *surface,
                                    int        *x,
@@ -1433,6 +1448,8 @@ gdk_broadway_toplevel_set_property (GObject      *object,
       break;
 
     case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
+      gdk_broadway_surface_set_modal_hint (surface, g_value_get_boolean (value));
+      g_object_notify_by_pspec (G_OBJECT (surface), pspec);
       break;
 
     case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
@@ -1479,6 +1496,10 @@ gdk_broadway_toplevel_get_property (GObject    *object,
       g_value_set_object (value, surface->transient_for);
       break;
 
+    case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
+      g_value_set_boolean (value, surface->modal_hint);
+      break;
+
     case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
       g_value_set_pointer (value, NULL);
       break;
index f944306758351740c1780f93d9866cfb3ab1fe5b..bdeb96016275e7421e1dd9d0cc4cae8b4df40b68 100644 (file)
@@ -54,6 +54,7 @@ struct _GdkBroadwaySurface
 
   gboolean dirty;
   gboolean last_synced;
+  gboolean modal_hint;
 
   GdkGeometry geometry_hints;
   GdkSurfaceHints geometry_hints_mask;