+
+
+
+/**
+ * GtkApplicationInhibitFlags:
+ * @GTK_APPLICATION_INHIBIT_LOGOUT: Inhibit ending the user session
+ * by logging out or by shutting down the computer
+ * @GTK_APPLICATION_INHIBIT_SWITCH: Inhibit user switching
+ * @GTK_APPLICATION_INHIBIT_SUSPEND: Inhibit suspending the
+ * session or computer
+ * @GTK_APPLICATION_INHIBIT_IDLE: Inhibit the session being
+ * marked as idle (and possibly locked)
+ *
+ * Types of user actions that may be blocked by gtk_application_inhibit().
+ *
+ * Since: 3.4
+ */
+
+/**
+ * gtk_application_inhibit:
+ * @application: the #GApplication
+ * @window: (allow-none): a #GtkWindow, or %NULL
+ * @flags: what types of actions should be inhibited
+ * @reason: (allow-none): a short, human-readable string that explains
+ * why these operations are inhibited
+ *
+ * Inform the session manager that certain types of actions should be
+ * inhibited. This is not guaranteed to work on all platforms and for
+ * all types of actions.
+ *
+ * Applications should invoke this method when they begin an operation
+ * that should not be interrupted, such as creating a CD or DVD. The
+ * types of actions that may be blocked are specified by the @flags
+ * parameter. When the application completes the operation it should
+ * call gtk_application_uninhibit() to remove the inhibitor. Note that
+ * an application can have multiple inhibitors, and all of the must
+ * be individually removed. Inhibitors are also cleared when the
+ * application exits.
+ *
+ * Applications should not expect that they will always be able to block
+ * the action. In most cases, users will be given the option to force
+ * the action to take place.
+ *
+ * Reasons should be short and to the point.
+ *
+ * If @window is given, the session manager may point the user to
+ * this window to find out more about why the action is inhibited.
+ *
+ * Returns: A non-zero cookie that is used to uniquely identify this
+ * request. It should be used as an argument to gtk_application_uninhibit()
+ * in order to remove the request. If the platform does not support
+ * inhibiting or the request failed for some reason, 0 is returned.
+ *
+ * Since: 3.4
+ */
+guint
+gtk_application_inhibit (GtkApplication *application,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason)
+{
+ GVariant *res;
+ GError *error = NULL;
+ guint cookie;
+ guint xid = 0;
+
+ g_return_val_if_fail (GTK_IS_APPLICATION (application), 0);
+ g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), 0);
+ g_return_val_if_fail (application->priv->sm_proxy != NULL, 0);
+
+ if (window != NULL)
+ {
+ GdkWindow *gdkwindow;
+
+ gdkwindow = gtk_widget_get_window (GTK_WIDGET (window));
+ if (gdkwindow == NULL)
+ g_warning ("Inhibit called with an unrealized window");
+ else
+ xid = GDK_WINDOW_XID (gdkwindow);
+ }
+
+ res = g_dbus_proxy_call_sync (application->priv->sm_proxy,
+ "Inhibit",
+ g_variant_new ("(susu)",
+ application->priv->app_id,
+ xid,
+ reason,
+ flags),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ &error);
+ if (error)
+ {
+ g_warning ("Calling Inhibit failed: %s", error->message);
+ g_error_free (error);
+ return 0;
+ }
+
+ g_variant_get (res, "(u)", &cookie);
+ g_variant_unref (res);
+
+ return cookie;
+}
+
+/**
+ * gtk_application_uninhibit:
+ * @application: the #GApplication
+ * @cookie: a cookie that was returned by gtk_application_inhibit()
+ *
+ * Removes an inhibitor that has been established with gtk_application_inhibit().
+ * Inhibitors are also cleared when the application exits.
+ *
+ * Since: 3.4
+ */
+void
+gtk_application_uninhibit (GtkApplication *application,
+ guint cookie)
+{
+ 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->sm_proxy != NULL);
+
+ g_dbus_proxy_call (application->priv->sm_proxy,
+ "Uninhibit",
+ g_variant_new ("(u)", cookie),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL, NULL, NULL);
+}
+
+/**
+ * gtk_application_is_inhibited:
+ * @application: the #GApplication
+ * @flags: what types of actions should be queried
+ *
+ * Determines if any of the actions specified in @flags are
+ * currently inhibited (possibly by another application).
+ *
+ * Returns: %TRUE if any of the actions specified in @flags are inhibited
+ *
+ * Since: 3.4
+ */
+gboolean
+gtk_application_is_inhibited (GtkApplication *application,
+ GtkApplicationInhibitFlags flags)
+{
+ GVariant *res;
+ GError *error = NULL;
+ gboolean inhibited;
+
+ g_return_val_if_fail (GTK_IS_APPLICATION (application), FALSE);
+ g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), FALSE);
+ g_return_val_if_fail (application->priv->sm_proxy != NULL, FALSE);
+
+ res = g_dbus_proxy_call_sync (application->priv->sm_proxy,
+ "IsInhibited",
+ g_variant_new ("(u)", flags),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ &error);
+ if (error)
+ {
+ g_warning ("Calling IsInhibited failed: %s", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ g_variant_get (res, "(b)", &inhibited);
+ g_variant_unref (res);
+
+ return inhibited;
+}
+
+#elif defined(GDK_WINDOWING_QUARTZ)
+
+/* OS X implementation copied from EggSMClient, but simplified since
+ * it doesn't need to interact with the user.
+ */
+
+static gboolean
+idle_will_quit (gpointer data)
+{
+ GtkApplication *app = data;
+
+ if (app->priv->quit_inhibit == 0)
+ g_application_quit (G_APPLICATION (app));
+ else
+ {
+ GtkApplicationQuartzInhibitor *inhibitor;
+ GSList *iter;
+ GtkWidget *dialog;
+
+ for (iter = app->priv->inhibitors; iter; iter = iter->next)
+ {
+ inhibitor = iter->data;
+ if (inhibitor->flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ break;
+ }
+ g_assert (inhibitor != NULL);
+
+ dialog = gtk_message_dialog_new (inhibitor->window,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("%s cannot quit at this time:\n\n%s"),
+ g_get_application_name (),
+ inhibitor->reason);
+ g_signal_connect_swapped (dialog,
+ "response",
+ G_CALLBACK (gtk_widget_destroy),
+ dialog);
+ gtk_widget_show_all (dialog);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static pascal OSErr
+quit_requested (const AppleEvent *aevt,
+ AppleEvent *reply,
+ long refcon)
+{
+ GtkApplication *app = GSIZE_TO_POINTER ((gsize)refcon);
+
+ /* 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_full (G_PRIORITY_DEFAULT, idle_will_quit, app, NULL);
+
+ return app->priv->quit_inhibit == 0 ? noErr : userCanceledErr;
+}
+
+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);
+}
+
+guint
+gtk_application_inhibit (GtkApplication *application,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason)
+{
+ GtkApplicationQuartzInhibitor *inhibitor;
+
+ g_return_val_if_fail (GTK_IS_APPLICATION (application), 0);
+ g_return_val_if_fail (flags != 0, 0);
+
+ inhibitor = g_slice_new (GtkApplicationQuartzInhibitor);
+ inhibitor->cookie = ++application->priv->next_cookie;
+ inhibitor->flags = flags;
+ inhibitor->reason = g_strdup (reason);
+ inhibitor->window = window ? g_object_ref (window) : NULL;
+
+ application->priv->inhibitors = g_slist_prepend (application->priv->inhibitors, inhibitor);
+
+ if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ application->priv->quit_inhibit++;
+
+ return inhibitor->cookie;
+}
+
+void
+gtk_application_uninhibit (GtkApplication *application,
+ guint cookie)
+{
+ GSList *iter;
+
+ for (iter = application->priv->inhibitors; iter; iter = iter->next)
+ {
+ GtkApplicationQuartzInhibitor *inhibitor = iter->data;
+
+ if (inhibitor->cookie == cookie)
+ {
+ if (inhibitor->flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ application->priv->quit_inhibit--;
+ gtk_application_quartz_inhibitor_free (inhibitor);
+ application->priv->inhibitors = g_slist_delete_link (application->priv->inhibitors, iter);
+ return;
+ }
+ }
+
+ g_warning ("Invalid inhibitor cookie");
+}
+
+gboolean
+gtk_application_is_inhibited (GtkApplication *application,
+ GtkApplicationInhibitFlags flags)
+{
+ if (flags & GTK_APPLICATION_INHIBIT_LOGOUT)
+ return application->priv->quit_inhibit > 0;
+
+ return FALSE;
+}
+
+#else
+
+/* Trivial implementation.
+ *
+ * For the inhibit API on Windows, see
+ * http://msdn.microsoft.com/en-us/library/ms700677%28VS.85%29.aspx
+ */
+
+guint
+gtk_application_inhibit (GtkApplication *application,
+ GtkWindow *window,
+ GtkApplicationInhibitFlags flags,
+ const gchar *reason)
+{
+ return 0;
+}
+
+void
+gtk_application_uninhibit (GtkApplication *application,
+ guint cookie)
+{
+}
+
+gboolean
+gtk_application_is_inhibited (GtkApplication *application,
+ GtkApplicationInhibitFlags flags)
+{
+ return FALSE;
+}
+
+#endif