[mutter/wip/carlosg/frozen-app-behavior2: 1/2] core: Change behavior of "application is alive" checks




commit c2b363373b3cd039f72cafbba3f1f4da64d58f4c
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Sep 3 23:38:12 2021 +0200

    core: Change behavior of "application is alive" checks
    
    Change some things in these "app is alive" checks:
    - The dialog timeout is separated from the ping timeout, in order
      to show it again at a constant rate after dismissing, despite in
      flight pings. It still shows immediately after the first failed
      ping.
    - As we want to tap further into is-alive logic, MetaWindow now
      made it a property, that other places in code can fetch and
      subscribe.
    - Motion events trigger ping (as long as there was none other in
      flight for the same window), and are counted between ping and
      pong, in order to preemptively declare the window as not alive
      before there is trouble with event queues being overflown.
    
    This results in a separate logic between "the application does
    not respond" and "we are showing the close dialog" so that the
    former may get triggered independently.

 src/core/delete.c         | 48 +++++++++++++++++++++++++------------
 src/core/display.c        |  3 +++
 src/core/events.c         |  5 +++-
 src/core/window-private.h | 15 ++++++++++++
 src/core/window.c         | 61 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 116 insertions(+), 16 deletions(-)
---
diff --git a/src/core/delete.c b/src/core/delete.c
index 058764b088..2d63b0462a 100644
--- a/src/core/delete.c
+++ b/src/core/delete.c
@@ -22,6 +22,8 @@
 
 #define _XOPEN_SOURCE /* for kill() */
 
+#define MAX_QUEUED_EVENTS 400
+
 #include "config.h"
 
 #include <errno.h>
@@ -39,6 +41,8 @@ close_dialog_response_cb (MetaCloseDialog         *dialog,
 {
   if (response == META_CLOSE_DIALOG_RESPONSE_FORCE_CLOSE)
     meta_window_kill (window);
+  else
+    meta_window_ensure_close_dialog_timeout (window);
 }
 
 static void
@@ -57,23 +61,22 @@ meta_window_ensure_close_dialog (MetaWindow *window)
 }
 
 void
-meta_window_set_alive (MetaWindow *window,
-                       gboolean    is_alive)
+meta_window_show_close_dialog (MetaWindow *window)
 {
-  if (is_alive && window->close_dialog)
-    {
-      meta_close_dialog_hide (window->close_dialog);
-    }
-  else if (!is_alive)
-    {
-      meta_window_ensure_close_dialog (window);
-      meta_close_dialog_show (window->close_dialog);
+  meta_window_ensure_close_dialog (window);
+  meta_close_dialog_show (window->close_dialog);
 
-      if (window->display &&
-          window->display->event_route == META_EVENT_ROUTE_NORMAL &&
-          window == window->display->focus_window)
-        meta_close_dialog_focus (window->close_dialog);
-    }
+  if (window->display &&
+      window->display->event_route == META_EVENT_ROUTE_NORMAL &&
+      window == window->display->focus_window)
+    meta_close_dialog_focus (window->close_dialog);
+}
+
+void
+meta_window_hide_close_dialog (MetaWindow *window)
+{
+  if (window->close_dialog)
+    meta_close_dialog_hide (window->close_dialog);
 }
 
 void
@@ -83,6 +86,21 @@ meta_window_check_alive (MetaWindow *window,
   meta_display_ping_window (window, timestamp);
 }
 
+void
+meta_window_check_alive_on_event (MetaWindow *window,
+                                  guint32     timestamp)
+{
+  if (!meta_window_can_ping (window))
+    return;
+
+  meta_display_ping_window (window, timestamp);
+
+  window->events_during_ping++;
+
+  if (window->events_during_ping > MAX_QUEUED_EVENTS)
+    meta_window_set_alive (window, FALSE);
+}
+
 void
 meta_window_delete (MetaWindow  *window,
                     guint32      timestamp)
diff --git a/src/core/display.c b/src/core/display.c
index 532d024f80..83c255bf60 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2146,6 +2146,7 @@ meta_display_ping_timeout (gpointer data)
   MetaDisplay *display = window->display;
 
   meta_window_set_alive (window, FALSE);
+  meta_window_show_close_dialog (window);
 
   ping_data->ping_timeout_id = 0;
 
@@ -2235,6 +2236,8 @@ meta_display_ping_window (MetaWindow *window,
               serial, window->desc);
 
   META_WINDOW_GET_CLASS (window)->ping (window, serial);
+
+  window->events_during_ping = 0;
 }
 
 /**
diff --git a/src/core/events.c b/src/core/events.c
index 8afc720efd..70982b7d64 100644
--- a/src/core/events.c
+++ b/src/core/events.c
@@ -201,7 +201,7 @@ meta_display_handle_event (MetaDisplay        *display,
                            const ClutterEvent *event)
 {
   MetaBackend *backend = meta_get_backend ();
-  MetaWindow *window;
+  MetaWindow *window = NULL;
   gboolean bypass_clutter = FALSE;
   G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
   MetaGestureTracker *gesture_tracker;
@@ -474,6 +474,9 @@ meta_display_handle_event (MetaDisplay        *display,
 #ifdef HAVE_WAYLAND
   if (compositor && !bypass_wayland)
     {
+      if (window && event->type == CLUTTER_MOTION)
+        meta_window_check_alive_on_event (window, event->any.time);
+
       if (meta_wayland_compositor_handle_event (compositor, event))
         bypass_clutter = TRUE;
     }
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 1b43239865..77d1453978 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -437,6 +437,9 @@ struct _MetaWindow
   /* whether focus should be restored on map */
   guint restore_focus_on_map : 1;
 
+  /* Whether the window is alive */
+  guint is_alive : 1;
+
   /* if non-NULL, the bounds of the window frame */
   cairo_region_t *frame_bounds;
 
@@ -564,11 +567,14 @@ struct _MetaWindow
   } placement;
 
   guint unmanage_idle_id;
+  guint close_dialog_timeout_id;
 
   pid_t client_pid;
 
   gboolean has_valid_cgroup;
   GFile *cgroup_path;
+
+  unsigned int events_during_ping;
 };
 
 struct _MetaWindowClass
@@ -877,6 +883,11 @@ void meta_window_grab_op_began (MetaWindow *window, MetaGrabOp op);
 void meta_window_grab_op_ended (MetaWindow *window, MetaGrabOp op);
 
 void meta_window_set_alive (MetaWindow *window, gboolean is_alive);
+gboolean meta_window_get_alive (MetaWindow *window);
+
+void meta_window_show_close_dialog (MetaWindow *window);
+void meta_window_hide_close_dialog (MetaWindow *window);
+void meta_window_ensure_close_dialog_timeout (MetaWindow *window);
 
 gboolean meta_window_has_pointer (MetaWindow *window);
 
@@ -898,4 +909,8 @@ gboolean meta_window_is_focus_async (MetaWindow *window);
 GFile *meta_window_get_unit_cgroup (MetaWindow *window);
 gboolean meta_window_unit_cgroup_equal (MetaWindow *window1,
                                         MetaWindow *window2);
+
+void meta_window_check_alive_on_event (MetaWindow *window,
+                                       guint32     timestamp);
+
 #endif
diff --git a/src/core/window.c b/src/core/window.c
index a9ed975d25..91cb377d48 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -214,6 +214,7 @@ enum
   PROP_GTK_APP_MENU_OBJECT_PATH,
   PROP_GTK_MENUBAR_OBJECT_PATH,
   PROP_ON_ALL_WORKSPACES,
+  PROP_IS_ALIVE,
 
   PROP_LAST,
 };
@@ -633,6 +634,13 @@ meta_window_class_init (MetaWindowClass *klass)
                           FALSE,
                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
+  obj_props[PROP_IS_ALIVE] =
+    g_param_spec_boolean ("is-alive",
+                          "Is alive",
+                          "Whether the window responds to pings",
+                          FALSE,
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
 
   window_signals[WORKSPACE_CHANGED] =
@@ -729,6 +737,7 @@ meta_window_init (MetaWindow *self)
 {
   self->stamp = next_window_stamp++;
   meta_prefs_add_listener (prefs_changed_callback, self);
+  self->is_alive = TRUE;
 }
 
 static gboolean
@@ -8816,3 +8825,55 @@ meta_window_get_client_type (MetaWindow *window)
 {
   return window->client_type;
 }
+
+static gboolean
+meta_window_close_dialog_timeout (MetaWindow *window)
+{
+  meta_window_show_close_dialog (window);
+  window->close_dialog_timeout_id = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+void
+meta_window_ensure_close_dialog_timeout (MetaWindow *window)
+{
+  guint check_alive_timeout = meta_prefs_get_check_alive_timeout ();
+
+  if (window->is_alive)
+    return;
+  if (window->close_dialog_timeout_id != 0)
+    return;
+  if (check_alive_timeout == 0)
+    return;
+
+  window->close_dialog_timeout_id =
+    g_timeout_add (check_alive_timeout,
+                   (GSourceFunc) meta_window_close_dialog_timeout,
+                   window);
+  g_source_set_name_by_id (window->close_dialog_timeout_id,
+                           "[mutter] meta_window_close_dialog_timeout");
+}
+
+void
+meta_window_set_alive (MetaWindow *window,
+                       gboolean    is_alive)
+{
+  if (window->is_alive == is_alive)
+    return;
+
+  window->is_alive = is_alive;
+  g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_IS_ALIVE]);
+
+  if (is_alive)
+    {
+      g_clear_handle_id (&window->close_dialog_timeout_id, g_source_remove);
+      meta_window_hide_close_dialog (window);
+    }
+}
+
+gboolean
+meta_window_get_alive (MetaWindow *window)
+{
+  return window->is_alive;
+}


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