summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference/gtk/gtk3-sections.txt1
-rw-r--r--docs/reference/gtk/migrating-smclient-GtkApplication.xml11
-rw-r--r--gtk/gtk.symbols1
-rw-r--r--gtk/gtkapplication.c277
-rw-r--r--gtk/gtkapplication.h6
-rw-r--r--tests/testlogout.c55
6 files changed, 104 insertions, 247 deletions
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 55049f7409..83c134ca5c 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -7009,7 +7009,6 @@ gtk_application_remove_window
gtk_application_get_windows
<SUBSECTION>
-gtk_application_quit_response
GtkApplicationInhibitFlags
gtk_application_inhibit
gtk_application_uninhibit
diff --git a/docs/reference/gtk/migrating-smclient-GtkApplication.xml b/docs/reference/gtk/migrating-smclient-GtkApplication.xml
index 58cae9a1b8..38bb417d5d 100644
--- a/docs/reference/gtk/migrating-smclient-GtkApplication.xml
+++ b/docs/reference/gtk/migrating-smclient-GtkApplication.xml
@@ -21,8 +21,7 @@
<para>
Starting with GTK+ 3.4, #GtkApplication supports logout notification
- and negotiation in the same way as EggSMClient, using the same
- basic API:
+ and negotiation similar to EggSMClient.
</para>
<table>
<tgroup cols="2">
@@ -31,10 +30,10 @@
<row><entry>EggSMClient</entry><entry>GtkApplication</entry></row>
</thead>
<tbody>
- <row><entry>EggSMClient::quit-requested</entry><entry>#GtkApplication::quit-requested</entry></row>
- <row><entry>EggSMClient::quit</entry><entry>#GtkApplication::quit</entry></row>
- <row><entry>EggSMClient::quit-cancelled</entry><entry>#GtkApplication::quit-cancelled</entry></row>
- <row><entry>egg_sm_client_will_quit</entry><entry>gtk_application_quit_response()</entry></row>
+ <row><entry>EggSMClient::quit-requested</entry><entry>instead of calling will_quit (FALSE,...) in response to this signal, install an inhibitor</entry></row>
+ <row><entry>EggSMClient::quit</entry><entry>the #GtkApplication::quit signal</entry></row>
+ <row><entry>EggSMClient::quit-cancelled</entry><entry></entry></row>
+ <row><entry>egg_sm_client_will_quit</entry><entry>instead of calling will_quit (FALSE,...), install an inhibitor</entry></row>
<row><entry>egg_sm_client_end_session</entry><entry>gtk_application_end_session()</entry></row>
</tbody>
</tgroup>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 9108ebcf7b..8a83719e85 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -236,7 +236,6 @@ gtk_application_inhibit
gtk_application_inhibit_flags_get_type
gtk_application_is_inhibited
gtk_application_new
-gtk_application_quit_response
gtk_application_remove_accelerator
gtk_application_remove_window
gtk_application_set_app_menu
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index e87dc45781..737c51d35c 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -109,7 +109,7 @@
* life-cycle.
*
* An application can be informed when the session is about to end
- * by connecting to the #GtkApplication::quit-requested signal.
+ * by connecting to the #GtkApplication::quit signal.
*
* An application can request the session to be ended by calling
* gtk_application_end_session().
@@ -126,8 +126,6 @@
enum {
WINDOW_ADDED,
WINDOW_REMOVED,
- QUIT_REQUESTED,
- QUIT_CANCELLED,
QUIT,
LAST_SIGNAL
};
@@ -146,7 +144,6 @@ struct _GtkApplicationPrivate
GList *windows;
gboolean register_session;
- gboolean quit_requested;
#ifdef GDK_WINDOWING_X11
GDBusConnection *session_bus;
@@ -163,6 +160,9 @@ struct _GtkApplicationPrivate
GActionMuxer *muxer;
GMenu *combined;
+ GHashTable *inhibitors;
+ gint quit_inhibited;
+ guint next_cookie;
AppleEvent quit_event, quit_reply;
gboolean quitting;
#endif
@@ -297,6 +297,8 @@ gtk_application_shutdown_quartz (GtkApplication *application)
g_object_unref (application->priv->muxer);
application->priv->muxer = NULL;
+
+ g_hash_table_unref (application->priv->inhibitors);
}
static void
@@ -577,6 +579,13 @@ gtk_application_set_property (GObject *object,
}
static void
+gtk_application_quit (GtkApplication *app)
+{
+ /* we are asked to quit, so don't linger */
+ g_application_set_inactivity_timeout (G_APPLICATION (app), 0);
+}
+
+static void
gtk_application_class_init (GtkApplicationClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
@@ -594,6 +603,7 @@ gtk_application_class_init (GtkApplicationClass *class)
class->window_added = gtk_application_window_added;
class->window_removed = gtk_application_window_removed;
+ class->quit = gtk_application_quit;
g_type_class_add_private (class, sizeof (GtkApplicationPrivate));
@@ -633,56 +643,6 @@ gtk_application_class_init (GtkApplicationClass *class)
G_TYPE_NONE, 1, GTK_TYPE_WINDOW);
/**
- * GtkApplication::quit-requested:
- * @application: the #GtkApplication
- *
- * Emitted when the session manager requests that the application
- * exit (generally because the user is logging out). The application
- * should decide whether or not it is willing to quit and then call
- * g_application_quit_response(), passing %TRUE or %FALSE to give its
- * answer to the session manager. It does not need to give an answer
- * before returning from the signal handler; the answer can be given
- * later on, but <emphasis>the application must not attempt to perform
- * any actions or interact with the user</emphasis> in response to
- * this signal. Any actions required for a clean shutdown should take
- * place in response to the #GtkApplication::quit signal.
- *
- * The application should limit its operations until either the
- * #GApplication::quit or #GtkApplication::quit-cancelled signals is
- * emitted.
- *
- * To receive this signal, you need to set the
- * #GtkApplication::register-session property
- * when creating the application object.
- *
- * Since: 3.4
- */
- gtk_application_signals[QUIT_REQUESTED] =
- g_signal_new ("quit-requested", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkApplicationClass, quit_requested),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- /**
- * GtkApplication::quit-cancelled:
- * @application: the #GtkApplication
- *
- * Emitted when the session manager decides to cancel a logout after
- * the application has already agreed to quit. After receiving this
- * signal, the application can go back to what it was doing before
- * receiving the #GtkApplication::quit-requested signal.
- *
- * To receive this signal, you need to set the
- * #GtkApplication::register-session property
- * when creating the application object.
- *
- * Since: 3.4
- */
- gtk_application_signals[QUIT_CANCELLED] =
- g_signal_new ("quit-cancelled", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkApplicationClass, quit_cancelled),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- /**
* GtkApplication::quit:
* @application: the #GtkApplication
*
@@ -691,9 +651,9 @@ gtk_application_class_init (GtkApplicationClass *class)
* should exit as soon as possible after receiving this signal; if
* it does not, the session manager may choose to forcibly kill it.
*
- * Normally, an application would only be sent a ::quit if it
- * agreed to quit in response to a #GtkApplication::quit-requested
- * signal. However, this is not guaranteed; in some situations the
+ * Normally, an application would only be sent a ::quit if there
+ * are no inhibitors (see gtk_application_inhibit()).
+ * However, this is not guaranteed; in some situations the
* session manager may decide to end the session without giving
* applications a chance to object.
*
@@ -704,7 +664,7 @@ gtk_application_class_init (GtkApplicationClass *class)
* Since: 3.4
*/
gtk_application_signals[QUIT] =
- g_signal_new ("quit", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
+ g_signal_new ("quit", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkApplicationClass, quit),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
@@ -1064,6 +1024,20 @@ unregister_client (GtkApplication *app)
}
static void
+gtk_application_quit_response (GtkApplication *application,
+ gboolean will_quit,
+ const gchar *reason)
+{
+ g_debug ("Calling EndSessionResponse %d '%s'", will_quit, reason);
+
+ g_dbus_proxy_call (application->priv->client_proxy,
+ "EndSessionResponse",
+ g_variant_new ("(bs)", will_quit, reason ? reason : ""),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL, NULL, NULL);
+}
+static void
client_proxy_signal (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
@@ -1073,22 +1047,19 @@ client_proxy_signal (GDBusProxy *proxy,
if (strcmp (signal_name, "QueryEndSession") == 0)
{
g_debug ("Received QueryEndSession");
- app->priv->quit_requested = TRUE;
- g_signal_emit (app, gtk_application_signals[QUIT_REQUESTED], 0);
+ gtk_application_quit_response (app, TRUE, NULL);
+ }
+ else if (strcmp (signal_name, "CancelEndSession") == 0)
+ {
+ g_debug ("Received CancelEndSession");
}
else if (strcmp (signal_name, "EndSession") == 0)
{
g_debug ("Received EndSession");
- app->priv->quit_requested = TRUE;
gtk_application_quit_response (app, TRUE, NULL);
unregister_client (app);
g_signal_emit (app, gtk_application_signals[QUIT], 0);
}
- else if (strcmp (signal_name, "CancelEndSession") == 0)
- {
- g_debug ("Received CancelEndSession");
- g_signal_emit (app, gtk_application_signals[QUIT_CANCELLED], 0);
- }
else if (strcmp (signal_name, "Stop") == 0)
{
g_debug ("Received Stop");
@@ -1186,52 +1157,7 @@ gtk_application_startup_session_dbus (GtkApplication *app)
g_signal_connect (app->priv->client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), app);
}
-/**
- * gtk_application_quit_response:
- * @application: the #GtkApplication
- * @will_quit: whether the application agrees to quit
- * @reason: (allow-none): a short human-readable string that explains
- * why quitting is not possible
- *
- * This function <emphasis>must</emphasis> be called in response to the
- * #GtkApplication::quit-requested signal, to indicate whether or
- * not the application is willing to quit. The application may call
- * it either directly from the signal handler, or at some later point.
- *
- * It should be stressed that <emphasis>applications should not assume
- * that they have the ability to block logout or shutdown</emphasis>,
- * even when %FALSE is passed for @will_quit.
- *
- * After calling this method, the application should wait to receive
- * either #GtkApplication::quit-cancelled or #GtkApplication::quit.
- *
- * If the application does not connect to #GtkApplication::quit-requested,
- * #GtkApplication will call this method on its behalf (passing %TRUE
- * for @will_quit).
- *
- * Since: 3.4
- */
-void
-gtk_application_quit_response (GtkApplication *application,
- gboolean will_quit,
- const gchar *reason)
-{
- g_return_if_fail (GTK_IS_APPLICATION (application));
- g_return_if_fail (!g_application_get_is_remote (G_APPLICATION (application)));
- g_return_if_fail (application->priv->client_proxy != NULL);
- g_return_if_fail (application->priv->quit_requested);
-
- application->priv->quit_requested = FALSE;
- g_debug ("Calling EndSessionResponse %d '%s'", will_quit, reason);
-
- g_dbus_proxy_call (application->priv->client_proxy,
- "EndSessionResponse",
- g_variant_new ("(bs)", will_quit, reason ? reason : ""),
- G_DBUS_CALL_FLAGS_NONE,
- G_MAXINT,
- NULL, NULL, NULL);
-}
/**
* GtkApplicationInhibitFlags:
@@ -1417,8 +1343,8 @@ gtk_application_is_inhibited (GtkApplication *application,
* Requests that the session manager end the current session.
* @style indicates how the session should be ended, and
* @request_confirmation indicates whether or not the user should be
- * given a chance to confirm the action. Both of these flags are merely
- * hints though; the session manager may choose to ignore them.
+ * given a chance to confirm the action. Both of these parameters are
+ * merely hints though; the session manager may choose to ignore them.
*
* Return value: %TRUE if the request was sent; %FALSE if it could not
* be sent (eg, because it could not connect to the session manager)
@@ -1462,46 +1388,6 @@ gtk_application_end_session (GtkApplication *application,
/* OS X implementation copied from EggSMClient */
-static gboolean
-idle_quit_requested (gpointer client)
-{
- g_signal_emit (client, gtk_application_signals[QUIT_REQUESTED], 0);
-
- return FALSE;
-}
-
-static pascal OSErr
-quit_requested (const AppleEvent *aevt,
- AppleEvent *reply,
- long refcon)
-{
- GtkApplication *app = GSIZE_TO_POINTER ((gsize)refcon);
-
- g_return_val_if_fail (!app->priv->quit_requested, userCanceledErr);
-
- /* FIXME AEInteractWithUser? */
- osx->quit_requested = TRUE;
- AEDuplicateDesc (aevt, &app->priv->quit_event);
- AEDuplicateDesc (reply, &app->priv->quit_reply);
- AESuspendTheCurrentEvent (aevt);
-
- /* Don't emit the "quit_requested" signal immediately, since we're
- * called from a weird point in the guts of gdkeventloop-quartz.c
- */
- g_idle_add (idle_quit_requested, app);
-
- return noErr;
-}
-
-static void
-gtk_application_startup_session_quartz (GtkApplication *app)
-{
- if (app->priv->register_session)
- AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
- NewAEEventHandlerUPP (quit_requested),
- (long)GPOINTER_TO_SIZE (app), false);
-}
-
static pascal OSErr
quit_requested_resumed (const AppleEvent *aevt,
AppleEvent *reply,
@@ -1509,9 +1395,7 @@ quit_requested_resumed (const AppleEvent *aevt,
{
GtkApplication *app = GSIZE_TO_POINTER ((gsize)refcon);
- app->priv->quit_requested = FALSE;
-
- return app->priv->quitting ? noErr : userCanceledErr;
+ return app->priv->quit_inhibit == 0 ? noErr : userCanceledErr;
}
static gboolean
@@ -1529,29 +1413,41 @@ idle_will_quit (gpointer data)
AEDisposeDesc (&app->quit->quit_event);
AEDisposeDesc (&app->quit->quit_reply);
- if (app->priv->quitting)
+ if (app->priv->quit_inhibit == 0)
g_signal_emit (app, gtk_application_signals[QUIT], 0);
return FALSE;
}
-void
-gtk_application_quit_response (GtkApplication *application,
- gboolean will_quit,
- const gchar *reason)
+static pascal OSErr
+quit_requested (const AppleEvent *aevt,
+ AppleEvent *reply,
+ long refcon)
{
- g_return_if_fail (GTK_IS_APPLICATION (application));
- g_return_if_fail (!g_application_get_is_remote (G_APPLICATION (application)));
- g_return_if_fail (application->priv->quit_requested);
+ GtkApplication *app = GSIZE_TO_POINTER ((gsize)refcon);
- application->priv->quitting = will_quit;
+ /* FIXME AEInteractWithUser? */
+ AEDuplicateDesc (aevt, &app->priv->quit_event);
+ AEDuplicateDesc (reply, &app->priv->quit_reply);
+ AESuspendTheCurrentEvent (aevt);
- /* Finish in an idle handler since the caller might have called
- * gtk_application_quit_response() from inside the ::quit-requested
- * signal handler, but may not expect the ::quit signal to arrive
- * during the gtk_application_quit_response() call.
+ /* Don't emit the "quit" signal immediately, since we're
+ * called from a weird point in the guts of gdkeventloop-quartz.c
*/
- g_idle_add (idle_will_quit, application);
+ g_idle_add (idle_will_quit, app);
+
+ return noErr;
+}
+
+static void
+gtk_application_startup_session_quartz (GtkApplication *app)
+{
+ if (app->priv->register_session)
+ AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerUPP (quit_requested),
+ (long)GPOINTER_TO_SIZE (app), false);
+
+ app->priv->inhibitors = g_hash_table_new (NULL, NULL);
}
guint
@@ -1560,19 +1456,51 @@ gtk_application_inhibit (GtkApplication *application,
GtkApplicationInhibitFlags flags,
const gchar *reason)
{
- return 0;
+ guint cookie;
+
+ g_return_val_if_fail (GTK_IS_APPLICATION (application), 0);
+ g_return_val_if_fail (flags != 0, 0);
+
+ application->priv->next_cookie++;
+ cookie = application->priv->next_cookie;
+
+ g_hash_table_insert (application->priv->inhibitors,
+ GUINT_TO_POINTER (cookie),
+ GUINT_TO_POINTER (flags));
+
+ if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ application->priv->quit_inhibit++;
+
+ return cookie;
}
void
gtk_application_uninhibit (GtkApplication *application,
guint cookie)
{
+ GApplicationInhibitFlags flags;
+
+ flags = GPOINTER_TO_UINT (g_hash_table_lookup (application->priv->inhibitors, GUINT_TO_POINTER (cookie)));
+
+ if (flags == 0)
+ {
+ g_warning ("Invalid inhibitor cookie");
+ return;
+ }
+
+ g_hash_table_remove (application->priv->inhibitors, GUINT_TO_POINTER (cookie));
+
+ if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ application->priv->quit_inhibit--;
}
gboolean
gtk_application_is_inhibited (GtkApplication *application,
GtkApplicationInhibitFlags flags)
{
+ if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ return application->priv->quit_inhibit > 0;
+
return FALSE;
}
@@ -1636,13 +1564,6 @@ gtk_application_end_session (GtkApplication *application,
* http://msdn.microsoft.com/en-us/library/ms700677%28VS.85%29.aspx
*/
-void
-gtk_application_quit_response (GtkApplication *application,
- gboolean will_quit,
- const gchar *reason)
-{
-}
-
guint
gtk_application_inhibit (GtkApplication *application,
GtkWindow *window,
diff --git a/gtk/gtkapplication.h b/gtk/gtkapplication.h
index 4e38441631..2d41c9fff4 100644
--- a/gtk/gtkapplication.h
+++ b/gtk/gtkapplication.h
@@ -59,8 +59,6 @@ struct _GtkApplicationClass
void (*window_removed) (GtkApplication *application,
GtkWindow *window);
- void (*quit_requested) (GtkApplication *application);
- void (*quit_cancelled) (GtkApplication *application);
void (*quit) (GtkApplication *application);
/*< private >*/
@@ -95,10 +93,6 @@ void gtk_application_remove_accelerator (GtkApplication *application
const gchar *action_name,
GVariant *parameter);
-void gtk_application_quit_response (GtkApplication *application,
- gboolean will_quit,
- const gchar *reason);
-
typedef enum
{
GTK_APPLICATION_INHIBIT_LOGOUT = (1 << 0),
diff --git a/tests/testlogout.c b/tests/testlogout.c
index a896bd4584..a278c7b133 100644
--- a/tests/testlogout.c
+++ b/tests/testlogout.c
@@ -1,7 +1,5 @@
#include <gtk/gtk.h>
-static gboolean will_quit = TRUE;
-static gchar *reason;
static GtkWidget *inhibit_entry;
static GtkWidget *inhibit_logout;
static GtkWidget *inhibit_switch;
@@ -36,19 +34,6 @@ end_session (GtkButton *button, GtkApplication *app)
}
static void
-toggle_will_quit (GtkToggleButton *button, gpointer data)
-{
- will_quit = gtk_toggle_button_get_active (button);
-}
-
-static void
-reason_changed (GtkEntry *entry, GParamSpec *pspec, GtkApplication *app)
-{
- g_free (reason);
- reason = g_strdup (gtk_entry_get_text (entry));
-}
-
-static void
inhibitor_toggled (GtkToggleButton *button, GtkApplication *app)
{
gboolean active;
@@ -118,7 +103,6 @@ activate (GtkApplication *app,
GtkWidget *separator;
GtkWidget *grid;
GtkWidget *button;
- GtkWidget *entry;
GtkWidget *label;
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
@@ -168,26 +152,6 @@ activate (GtkApplication *app,
gtk_container_add (GTK_CONTAINER (box), grid);
- button = gtk_check_button_new_with_label ("Will quit");
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), will_quit);
- g_signal_connect (button, "toggled",
- G_CALLBACK (toggle_will_quit), NULL);
- gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);
-
- entry = gtk_entry_new ();
- g_signal_connect (entry, "notify::text",
- G_CALLBACK (reason_changed), app);
- gtk_grid_attach (GTK_GRID (grid), entry, 1, 0, 1, 1);
-
- separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
- gtk_container_add (GTK_CONTAINER (box), separator);
-
- grid = gtk_grid_new ();
- gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
- gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
-
- gtk_container_add (GTK_CONTAINER (box), grid);
-
end_combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (end_combo), "logout", "Logout");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (end_combo), "reboot", "Reboot");
@@ -211,27 +175,12 @@ activate (GtkApplication *app,
}
static void
-quit_requested (GtkApplication *app,
- gpointer data)
-{
- g_print ("Received quit-requested, reply: %d, '%s'\n", will_quit, reason);
- gtk_application_quit_response (app, will_quit, reason);
-}
-
-static void
quit (GtkApplication *app,
gpointer data)
{
g_print ("Received quit\n");
}
-static void
-quit_cancelled (GtkApplication *app,
- gpointer data)
-{
- g_print ("received quit-cancelled\n");
-}
-
int
main (int argc, char *argv[])
{
@@ -242,12 +191,8 @@ main (int argc, char *argv[])
g_signal_connect (app, "activate",
G_CALLBACK (activate), NULL);
- g_signal_connect (app, "quit-requested",
- G_CALLBACK (quit_requested), NULL);
g_signal_connect (app, "quit",
G_CALLBACK (quit), NULL);
- g_signal_connect (app, "quit-cancelled",
- G_CALLBACK (quit_cancelled), NULL);
g_application_run (G_APPLICATION (app), argc, argv);