forked from AuroraMiddleware/gtk
51dc4873fd
Its very easy to get extra references to the NativeDialog so that when you release your last reference any visible dialog is not hidden. We handle this by adding a destroy method similar to how you destroy regular toplevels.
660 lines
18 KiB
C
660 lines
18 KiB
C
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
|
|
/* GTK - The GIMP Toolkit
|
|
* gtkfilechoosernative.c: Native File selector dialog
|
|
* Copyright (C) 2015, Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gtknativedialogprivate.h"
|
|
|
|
#include "gtkprivate.h"
|
|
#include "gtkfilechooserdialog.h"
|
|
#include "gtkfilechooserprivate.h"
|
|
#include "gtkfilechooserwidget.h"
|
|
#include "gtkfilechooserwidgetprivate.h"
|
|
#include "gtkfilechooserutils.h"
|
|
#include "gtkfilechooserembed.h"
|
|
#include "gtkfilesystem.h"
|
|
#include "gtksizerequest.h"
|
|
#include "gtktypebuiltins.h"
|
|
#include "gtkintl.h"
|
|
#include "gtksettings.h"
|
|
#include "gtktogglebutton.h"
|
|
#include "gtkstylecontext.h"
|
|
#include "gtkheaderbar.h"
|
|
#include "gtklabel.h"
|
|
#include "gtkfilechooserentry.h"
|
|
|
|
/**
|
|
* SECTION:gtknativedialog
|
|
* @Short_description: Integrate with native dialogs
|
|
* @Title: GtkNativeDialog
|
|
* @See_also: #GtkFileChooserNative, #GtkDialog
|
|
*
|
|
* Native dialogs are platform dialogs that don't use #GtkDialog or
|
|
* #GtkWindow. They are used in order to integrate better with a
|
|
* platform, by looking the same as other native applications and
|
|
* supporting platform specific features.
|
|
*
|
|
* The #GtkDialog functions cannot be used on such objects, but we
|
|
* need a similar API in order to drive them. The #GtkNativeDialog
|
|
* object is an API that allows you to do this. It allows you to set
|
|
* various common properties on the dialog, as well as show and hide
|
|
* it and get a #GtkNativeDialog::response signal when the user finished
|
|
* with the dialog.
|
|
*
|
|
* There is also a gtk_native_dialog_run() helper that makes it easy
|
|
* to run any native dialog in a modal way with a recursive mainloop,
|
|
* similar to gtk_dialog_run().
|
|
*/
|
|
|
|
typedef struct _GtkNativeDialogPrivate GtkNativeDialogPrivate;
|
|
|
|
struct _GtkNativeDialogPrivate
|
|
{
|
|
GtkWindow *transient_for;
|
|
char *title;
|
|
|
|
guint visible : 1;
|
|
guint modal : 1;
|
|
|
|
/* Run state */
|
|
gint run_response_id;
|
|
GMainLoop *run_loop; /* Non-NULL when in run */
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_TITLE,
|
|
PROP_VISIBLE,
|
|
PROP_MODAL,
|
|
PROP_TRANSIENT_FOR,
|
|
|
|
LAST_ARG,
|
|
};
|
|
|
|
enum {
|
|
RESPONSE,
|
|
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static GParamSpec *native_props[LAST_ARG] = { NULL, };
|
|
static guint native_signals[LAST_SIGNAL];
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkNativeDialog, gtk_native_dialog, G_TYPE_OBJECT,
|
|
G_ADD_PRIVATE (GtkNativeDialog))
|
|
|
|
static void
|
|
gtk_native_dialog_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
GtkNativeDialog *self = GTK_NATIVE_DIALOG (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_TITLE:
|
|
gtk_native_dialog_set_title (self, g_value_get_string (value));
|
|
break;
|
|
|
|
case PROP_MODAL:
|
|
gtk_native_dialog_set_modal (self, g_value_get_boolean (value));
|
|
break;
|
|
|
|
case PROP_VISIBLE:
|
|
if (g_value_get_boolean (value))
|
|
gtk_native_dialog_show (self);
|
|
else
|
|
gtk_native_dialog_hide (self);
|
|
break;
|
|
|
|
case PROP_TRANSIENT_FOR:
|
|
gtk_native_dialog_set_transient_for (self, g_value_get_object (value));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_native_dialog_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkNativeDialog *self = GTK_NATIVE_DIALOG (object);
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_TITLE:
|
|
g_value_set_string (value, priv->title);
|
|
break;
|
|
|
|
case PROP_MODAL:
|
|
g_value_set_boolean (value, priv->modal);
|
|
break;
|
|
|
|
case PROP_VISIBLE:
|
|
g_value_set_boolean (value, priv->visible);
|
|
break;
|
|
|
|
case PROP_TRANSIENT_FOR:
|
|
g_value_set_object (value, priv->transient_for);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_native_dialog_dispose (GObject *object)
|
|
{
|
|
GtkNativeDialog *self = GTK_NATIVE_DIALOG (object);
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
if (priv->visible)
|
|
gtk_native_dialog_hide (self);
|
|
|
|
G_OBJECT_CLASS (gtk_native_dialog_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gtk_native_dialog_finalize (GObject *object)
|
|
{
|
|
GtkNativeDialog *self = GTK_NATIVE_DIALOG (object);
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
g_clear_pointer (&priv->title, g_free);
|
|
g_clear_object (&priv->transient_for);
|
|
|
|
G_OBJECT_CLASS (gtk_native_dialog_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gtk_native_dialog_class_init (GtkNativeDialogClass *class)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
|
|
|
gobject_class->set_property = gtk_native_dialog_set_property;
|
|
gobject_class->get_property = gtk_native_dialog_get_property;
|
|
gobject_class->finalize = gtk_native_dialog_finalize;
|
|
gobject_class->dispose = gtk_native_dialog_dispose;
|
|
|
|
/**
|
|
* GtkNativeDialog:title:
|
|
*
|
|
* The title of the dialog window
|
|
*
|
|
* Since: 3.20
|
|
*/
|
|
native_props[PROP_TITLE] =
|
|
g_param_spec_string ("title",
|
|
P_("Dialog Title"),
|
|
P_("The title of the file chooser dialog"),
|
|
NULL,
|
|
GTK_PARAM_READWRITE);
|
|
|
|
/**
|
|
* GtkNativeDialog:modal:
|
|
*
|
|
* Whether the window should be modal with respect to its transient parent.
|
|
*
|
|
* Since: 3.20
|
|
*/
|
|
native_props[PROP_MODAL] =
|
|
g_param_spec_boolean ("modal",
|
|
P_("Modal"),
|
|
P_("If TRUE, the dialog is modal (other windows are not usable while this one is up)"),
|
|
FALSE,
|
|
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
/**
|
|
* GtkNativeDialog:visible:
|
|
*
|
|
* Whether the window is currenlty visible.
|
|
*
|
|
* Since: 3.20
|
|
*/
|
|
native_props[PROP_VISIBLE] =
|
|
g_param_spec_boolean ("visible",
|
|
P_("Visible"),
|
|
P_("Whether the dialog is currently visible"),
|
|
FALSE,
|
|
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
/**
|
|
* GtkNativeDialog:transient-for:
|
|
*
|
|
* The transient parent of the dialog, or %NULL for none.
|
|
*
|
|
* Since: 3.20
|
|
*/
|
|
native_props[PROP_TRANSIENT_FOR] =
|
|
g_param_spec_object ("transient-for",
|
|
P_("Transient for Window"),
|
|
P_("The transient parent of the dialog"),
|
|
GTK_TYPE_WINDOW,
|
|
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
|
|
|
|
g_object_class_install_properties (gobject_class, LAST_ARG, native_props);
|
|
|
|
/**
|
|
* GtkNativeDialog::response:
|
|
* @self: the object on which the signal is emitted
|
|
* @response_id: the response ID
|
|
*
|
|
* Emitted when the user responds to the dialog.
|
|
*
|
|
* When this is called the dialog has been hidden.
|
|
*
|
|
* If you call gtk_native_dialog_hide() before the user responds to
|
|
* the dialog this signal will not be emitted.
|
|
*
|
|
* Since: 3.20
|
|
*/
|
|
native_signals[RESPONSE] =
|
|
g_signal_new (I_("response"),
|
|
G_OBJECT_CLASS_TYPE (class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (GtkNativeDialogClass, response),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__INT,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_INT);
|
|
}
|
|
|
|
static void
|
|
gtk_native_dialog_init (GtkNativeDialog *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_show:
|
|
* @self: a #GtkNativeDialog
|
|
*
|
|
* Shows the dialog on the display, allowing the user to interact with
|
|
* it. When the user accepts the state of the dialog the dialog will
|
|
* be automatically hidden and the #GtkNativeDialog::response signal
|
|
* will be emitted.
|
|
*
|
|
* Multiple calls while the dialog is visible will be ignored.
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
void
|
|
gtk_native_dialog_show (GtkNativeDialog *self)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
GtkNativeDialogClass *klass;
|
|
|
|
g_return_if_fail (GTK_IS_NATIVE_DIALOG (self));
|
|
|
|
if (priv->visible)
|
|
return;
|
|
|
|
klass = GTK_NATIVE_DIALOG_GET_CLASS (self);
|
|
|
|
g_return_if_fail (klass->show != NULL);
|
|
|
|
klass->show (self);
|
|
|
|
priv->visible = TRUE;
|
|
g_object_notify_by_pspec (G_OBJECT (self), native_props[PROP_VISIBLE]);
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_hide:
|
|
* @self: a #GtkNativeDialog
|
|
*
|
|
* Hides the dialog if it is visilbe, aborting any interaction. Once this
|
|
* is called the #GtkNativeDialog::response signal will not be emitted
|
|
* until after the next call to gtk_native_dialog_show().
|
|
*
|
|
* If the dialog is not visible this does nothing.
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
void
|
|
gtk_native_dialog_hide (GtkNativeDialog *self)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
GtkNativeDialogClass *klass;
|
|
|
|
g_return_if_fail (GTK_IS_NATIVE_DIALOG (self));
|
|
|
|
if (!priv->visible)
|
|
return;
|
|
|
|
priv->visible = FALSE;
|
|
|
|
klass = GTK_NATIVE_DIALOG_GET_CLASS (self);
|
|
|
|
g_return_if_fail (klass->hide != NULL);
|
|
|
|
klass->hide (self);
|
|
|
|
if (priv->run_loop && g_main_loop_is_running (priv->run_loop))
|
|
g_main_loop_quit (priv->run_loop);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), native_props[PROP_VISIBLE]);
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_destroy:
|
|
* @self: a #GtkNativeDialog
|
|
*
|
|
* Destroys a dialog.
|
|
*
|
|
* When a dialog is destroyed, it will break any references it holds
|
|
* to other objects. If it is visible it will be hidden and any underlying
|
|
* window system resources will be destroyed.
|
|
*
|
|
* Note that this does not release any reference to the object (as opposed to
|
|
* destroying a GtkWindow) because there is no reference from the windowing
|
|
* system to the #GtkNativeDialog.
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
void
|
|
gtk_native_dialog_destroy (GtkNativeDialog *self)
|
|
{
|
|
g_return_if_fail (GTK_IS_NATIVE_DIALOG (self));
|
|
|
|
g_object_run_dispose (G_OBJECT (self));
|
|
}
|
|
|
|
void
|
|
_gtk_native_dialog_emit_response (GtkNativeDialog *self,
|
|
int response_id)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
priv->visible = FALSE;
|
|
g_object_notify_by_pspec (G_OBJECT (self), native_props[PROP_VISIBLE]);
|
|
|
|
g_signal_emit (self, native_signals[RESPONSE], 0, response_id);
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_get_visible:
|
|
* @self: a #GtkNativeDialog
|
|
*
|
|
* Determines whether the dialog is visible.
|
|
*
|
|
* Returns: %TRUE if the dialog is visible
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
gboolean
|
|
gtk_native_dialog_get_visible (GtkNativeDialog *self)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (GTK_IS_NATIVE_DIALOG (self), FALSE);
|
|
|
|
return priv->visible;
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_set_modal:
|
|
* @self: a #GtkNativeDialog
|
|
* @modal: whether the window is modal
|
|
*
|
|
* Sets a dialog modal or non-modal. Modal dialogs prevent interaction
|
|
* with other windows in the same application. To keep modal dialogs
|
|
* on top of main application windows, use
|
|
* gtk_native_dialog_set_transient_for() to make the dialog transient for the
|
|
* parent; most [window managers][gtk-X11-arch]
|
|
* will then disallow lowering the dialog below the parent.
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
void
|
|
gtk_native_dialog_set_modal (GtkNativeDialog *self,
|
|
gboolean modal)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
g_return_if_fail (GTK_IS_NATIVE_DIALOG (self));
|
|
|
|
modal = modal != FALSE;
|
|
|
|
if (priv->modal == modal)
|
|
return;
|
|
|
|
priv->modal = modal;
|
|
g_object_notify_by_pspec (G_OBJECT (self), native_props[PROP_MODAL]);
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_get_modal:
|
|
* @self: a #GtkNativeDialog
|
|
*
|
|
* Returns whether the dialog is modal. See gtk_native_dialog_set_modal().
|
|
*
|
|
* Returns: %TRUE if the dialog is set to be modal
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
gboolean
|
|
gtk_native_dialog_get_modal (GtkNativeDialog *self)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (GTK_IS_NATIVE_DIALOG (self), FALSE);
|
|
|
|
return priv->modal;
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_set_title:
|
|
* @self: a #GtkNativeDialog
|
|
* @title: title of the dialog
|
|
*
|
|
* Sets the title of the #GtkNativeDialog.
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
void
|
|
gtk_native_dialog_set_title (GtkNativeDialog *self,
|
|
const char *title)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
g_return_if_fail (GTK_IS_NATIVE_DIALOG (self));
|
|
|
|
g_free (priv->title);
|
|
priv->title = g_strdup (title);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), native_props[PROP_TITLE]);
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_get_title:
|
|
* @self: a #GtkNativeDialog
|
|
*
|
|
* Gets the title of the #GtkNativeDialog.
|
|
*
|
|
* Returns: the title of the dialog, or %NULL if none has
|
|
* been set explicitly. The returned string is owned by the widget
|
|
* and must not be modified or freed.
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
const char *
|
|
gtk_native_dialog_get_title (GtkNativeDialog *self)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (GTK_IS_NATIVE_DIALOG (self), NULL);
|
|
|
|
return priv->title;
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_set_transient_for:
|
|
* @self: a #GtkNativeDialog
|
|
* @parent: (allow-none): parent window, or %NULL
|
|
*
|
|
* Dialog windows should be set transient for the main application
|
|
* window they were spawned from. This allows
|
|
* [window managers][gtk-X11-arch] to e.g. keep the
|
|
* dialog on top of the main window, or center the dialog over the
|
|
* main window.
|
|
*
|
|
* Passing %NULL for @parent unsets the current transient window.
|
|
*
|
|
* Since: 3.20
|
|
*/
|
|
void
|
|
gtk_native_dialog_set_transient_for (GtkNativeDialog *self,
|
|
GtkWindow *parent)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
g_return_if_fail (GTK_IS_NATIVE_DIALOG (self));
|
|
|
|
if (g_set_object (&priv->transient_for, parent))
|
|
g_object_notify_by_pspec (G_OBJECT (self), native_props[PROP_TRANSIENT_FOR]);
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_get_transient_for:
|
|
* @self: a #GtkNativeDialog
|
|
*
|
|
* Fetches the transient parent for this window. See
|
|
* gtk_native_dialog_set_transient_for().
|
|
*
|
|
* Returns: (transfer none): the transient parent for this window, or %NULL
|
|
* if no transient parent has been set.
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
GtkWindow *
|
|
gtk_native_dialog_get_transient_for (GtkNativeDialog *self)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (GTK_IS_NATIVE_DIALOG (self), NULL);
|
|
|
|
return priv->transient_for;
|
|
}
|
|
|
|
static void
|
|
run_response_cb (GtkNativeDialog *self,
|
|
gint response_id,
|
|
gpointer data)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
|
|
priv->run_response_id = response_id;
|
|
if (priv->run_loop && g_main_loop_is_running (priv->run_loop))
|
|
g_main_loop_quit (priv->run_loop);
|
|
}
|
|
|
|
/**
|
|
* gtk_native_dialog_run:
|
|
* @self: a #GtkNativeDialog
|
|
*
|
|
* Blocks in a recursive main loop until @self emits the
|
|
* #GtkNativeDialog::response signal. It then returns the response ID
|
|
* from the ::response signal emission.
|
|
*
|
|
* Before entering the recursive main loop, gtk_native_dialog_run()
|
|
* calls gtk_native_dialog_show() on the dialog for you.
|
|
*
|
|
* After gtk_native_dialog_run() returns, then dialog will be hidden.
|
|
*
|
|
* Typical usage of this function might be:
|
|
* |[<!-- language="C" -->
|
|
* gint result = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog));
|
|
* switch (result)
|
|
* {
|
|
* case GTK_RESPONSE_ACCEPT:
|
|
* do_application_specific_something ();
|
|
* break;
|
|
* default:
|
|
* do_nothing_since_dialog_was_cancelled ();
|
|
* break;
|
|
* }
|
|
* g_object_unref (dialog);
|
|
* ]|
|
|
*
|
|
* Note that even though the recursive main loop gives the effect of a
|
|
* modal dialog (it prevents the user from interacting with other
|
|
* windows in the same window group while the dialog is run), callbacks
|
|
* such as timeouts, IO channel watches, DND drops, etc, will
|
|
* be triggered during a gtk_nautilus_dialog_run() call.
|
|
*
|
|
* Returns: response ID
|
|
*
|
|
* Since: 3.20
|
|
**/
|
|
gint
|
|
gtk_native_dialog_run (GtkNativeDialog *self)
|
|
{
|
|
GtkNativeDialogPrivate *priv = gtk_native_dialog_get_instance_private (self);
|
|
gboolean was_modal;
|
|
guint response_handler;
|
|
|
|
g_return_val_if_fail (GTK_IS_NATIVE_DIALOG (self), -1);
|
|
g_return_val_if_fail (!priv->visible, -1);
|
|
g_return_val_if_fail (priv->run_loop == NULL, -1);
|
|
|
|
if (priv->visible || priv->run_loop != NULL)
|
|
return -1;
|
|
|
|
g_object_ref (self);
|
|
|
|
priv->run_response_id = GTK_RESPONSE_NONE;
|
|
priv->run_loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
was_modal = priv->modal;
|
|
gtk_native_dialog_set_modal (self, TRUE);
|
|
|
|
response_handler =
|
|
g_signal_connect (self,
|
|
"response",
|
|
G_CALLBACK (run_response_cb),
|
|
NULL);
|
|
|
|
gtk_native_dialog_show (self);
|
|
|
|
gdk_threads_leave ();
|
|
g_main_loop_run (priv->run_loop);
|
|
gdk_threads_enter ();
|
|
|
|
g_signal_handler_disconnect (self, response_handler);
|
|
|
|
g_main_loop_unref (priv->run_loop);
|
|
priv->run_loop = NULL;
|
|
|
|
if (!was_modal)
|
|
gtk_native_dialog_set_modal (self, FALSE);
|
|
|
|
g_object_unref (self);
|
|
|
|
return priv->run_response_id;
|
|
}
|