/*
* gnome-keyring
*
* Copyright (C) 2011 Collabora Ltd
*
* This program 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.1 of
* the License, or (at your option) any later version.
*
* This program 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 program; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Stef Walter <stefw@collabora.co.uk>
*/
#include "config.h"
#include "gcr-dialog-util.h"
#include <string.h>
typedef struct {
GtkDialog *dialog;
gint response_id;
gboolean was_modal;
gboolean destroyed;
gulong response_sig;
gulong unmap_sig;
gulong delete_sig;
gulong destroy_sig;
} DialogRunClosure;
static void
dialog_run_closure_free (gpointer data)
{
DialogRunClosure *closure = data;
g_object_unref (closure->dialog);
g_assert (closure->response_sig == 0);
g_assert (closure->unmap_sig == 0);
g_assert (closure->delete_sig == 0);
g_assert (closure->destroy_sig == 0);
g_free (closure);
}
static void
complete_async_result (GSimpleAsyncResult *res)
{
DialogRunClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
g_object_ref (res);
if (!closure->destroyed) {
if (!closure->was_modal)
gtk_window_set_modal (GTK_WINDOW (closure->dialog), FALSE);
g_signal_handler_disconnect (closure->dialog, closure->response_sig);
closure->response_sig = 0;
g_signal_handler_disconnect (closure->dialog, closure->unmap_sig);
closure->unmap_sig = 0;
g_signal_handler_disconnect (closure->dialog, closure->delete_sig);
closure->delete_sig = 0;
g_signal_handler_disconnect (closure->dialog, closure->destroy_sig);
closure->destroy_sig = 0;
}
g_simple_async_result_complete (res);
g_object_unref (res);
}
static void
on_dialog_unmap (GtkDialog *dialog,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
complete_async_result (res);
}
static void
on_dialog_response (GtkDialog *dialog,
gint response_id,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
DialogRunClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
closure->response_id = response_id;
complete_async_result (res);
}
static gint
on_dialog_delete (GtkDialog *dialog,
GdkEventAny *event,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
complete_async_result (res);
return TRUE; /* Do not destroy */
}
static void
on_dialog_destroy (GtkDialog *dialog,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
DialogRunClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
/* complete will be called by run_unmap_handler */
closure->destroyed = TRUE;
}
void
_gcr_dialog_util_run_async (GtkDialog *dialog,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
DialogRunClosure *closure;
g_return_if_fail (GTK_IS_DIALOG (dialog));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
res = g_simple_async_result_new (G_OBJECT (dialog), callback, user_data,
_gcr_dialog_util_run_async);
closure = g_new0 (DialogRunClosure, 1);
closure->dialog = g_object_ref (dialog);
closure->response_id = GTK_RESPONSE_NONE;
closure->was_modal = gtk_window_get_modal (GTK_WINDOW (dialog));
if (!closure->was_modal)
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
gtk_widget_show (GTK_WIDGET (dialog));
g_simple_async_result_set_op_res_gpointer (res, closure, dialog_run_closure_free);
closure->response_sig = g_signal_connect_data (dialog, "response",
G_CALLBACK (on_dialog_response),
g_object_ref (res),
(GClosureNotify)g_object_unref, 0);
closure->unmap_sig = g_signal_connect_data (dialog, "unmap",
G_CALLBACK (on_dialog_unmap),
g_object_ref (res),
(GClosureNotify)g_object_unref, 0);
closure->delete_sig = g_signal_connect_data (dialog, "delete-event",
G_CALLBACK (on_dialog_delete),
g_object_ref (res),
(GClosureNotify)g_object_unref, 0);
closure->destroy_sig = g_signal_connect_data (dialog, "destroy",
G_CALLBACK (on_dialog_destroy),
g_object_ref (res),
(GClosureNotify)g_object_unref, 0);
g_object_unref (res);
}
gint
_gcr_dialog_util_run_finish (GtkDialog *dialog,
GAsyncResult *result)
{
DialogRunClosure *closure;
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (dialog),
_gcr_dialog_util_run_async), GTK_RESPONSE_NONE);
closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
return closure->response_id;
}