From 020e0bb2acf89f9b229e89a305a88617babecadd Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 11 Jul 2016 13:12:13 +0200 Subject: [PATCH] core: Implement MetaCloseDialogDefault This is basically a copy of the implementation currently residing in src/core/delete.c, which will be eventually deleted in favor of this one. https://bugzilla.gnome.org/show_bug.cgi?id=711619 --- po/POTFILES.in | 1 + src/Makefile.am | 2 + src/core/meta-close-dialog-default-private.h | 33 +++ src/core/meta-close-dialog-default.c | 279 +++++++++++++++++++ 4 files changed, 315 insertions(+) create mode 100644 src/core/meta-close-dialog-default-private.h create mode 100644 src/core/meta-close-dialog-default.c diff --git a/po/POTFILES.in b/po/POTFILES.in index a463e6418..416c0717d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -17,6 +17,7 @@ src/core/display.c src/core/errors.c src/core/keybindings.c src/core/main.c +src/core/meta-close-dialog-default.c src/core/mutter.c src/core/prefs.c src/core/screen.c diff --git a/src/Makefile.am b/src/Makefile.am index ac5786a62..2e8d73b9c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -224,6 +224,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \ core/core.c \ core/meta-close-dialog.c \ meta/meta-close-dialog.h \ + core/meta-close-dialog-default.c \ + core/meta-close-dialog-default-private.h \ core/delete.c \ core/display.c \ core/display-private.h \ diff --git a/src/core/meta-close-dialog-default-private.h b/src/core/meta-close-dialog-default-private.h new file mode 100644 index 000000000..fb4d1d6ab --- /dev/null +++ b/src/core/meta-close-dialog-default-private.h @@ -0,0 +1,33 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2016 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Carlos Garnacho + */ + +#ifndef META_CLOSE_DIALOG_DEFAULT_H +#define META_CLOSE_DIALOG_DEFAULT_H + +#define META_TYPE_CLOSE_DIALOG_DEFAULT (meta_close_dialog_default_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCloseDialogDefault, + meta_close_dialog_default, + META, CLOSE_DIALOG_DEFAULT, + GObject) + +MetaCloseDialog * meta_close_dialog_default_new (MetaWindow *window); + +#endif /* META_CLOSE_DIALOG_DEFAULT_H */ diff --git a/src/core/meta-close-dialog-default.c b/src/core/meta-close-dialog-default.c new file mode 100644 index 000000000..55eb897fa --- /dev/null +++ b/src/core/meta-close-dialog-default.c @@ -0,0 +1,279 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001, 2002 Havoc Pennington + * Copyright (C) 2004 Elijah Newren + * Copyright (C) 2016 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Carlos Garnacho + */ + +#define _XOPEN_SOURCE /* for kill() */ + +#include +#include "util-private.h" +#include "window-private.h" +#include +#include "meta-close-dialog-default-private.h" + +#include +#include +#include + +typedef struct _MetaCloseDialogDefaultPrivate MetaCloseDialogDefaultPrivate; + +struct _MetaCloseDialogDefault +{ + GObject parent_instance; + MetaWindow *window; + int dialog_pid; + guint child_watch_id; +}; + +enum { + PROP_0, + PROP_WINDOW, + N_PROPS +}; + +GParamSpec *pspecs[N_PROPS] = { NULL }; + +static void meta_close_dialog_iface_init (MetaCloseDialogInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaCloseDialogDefault, meta_close_dialog_default, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (META_TYPE_CLOSE_DIALOG, + meta_close_dialog_iface_init)) + +static void +dialog_exited (GPid pid, + int status, + gpointer user_data) +{ + MetaCloseDialogDefault *dialog = user_data; + + dialog->dialog_pid = -1; + + /* exit status of 0 means the user pressed "Force Quit" */ + if (WIFEXITED (status) && WEXITSTATUS (status) == 0) + g_signal_emit_by_name (dialog, "response", META_CLOSE_DIALOG_RESPONSE_FORCE_CLOSE); +} + +static void +present_existing_delete_dialog (MetaCloseDialogDefault *dialog) +{ + MetaWindow *window; + GSList *windows; + GSList *tmp; + + window = dialog->window; + + if (dialog->dialog_pid < 0) + return; + + meta_topic (META_DEBUG_PING, + "Presenting existing ping dialog for %s\n", + window->desc); + + /* Activate transient for window that belongs to + * mutter-dialog + */ + windows = meta_display_list_windows (window->display, META_LIST_DEFAULT); + tmp = windows; + + while (tmp != NULL) + { + MetaWindow *w = tmp->data; + + if (w->transient_for == window && w->res_class && + g_ascii_strcasecmp (w->res_class, "mutter-dialog") == 0) + { + meta_window_activate (w, CLUTTER_CURRENT_TIME); + break; + } + + tmp = tmp->next; + } + + g_slist_free (windows); +} + +static void +meta_close_dialog_default_show (MetaCloseDialog *dialog) +{ + MetaCloseDialogDefault *dialog_default = META_CLOSE_DIALOG_DEFAULT (dialog); + MetaWindow *window = dialog_default->window; + gchar *window_title, *window_content, *tmp; + GPid dialog_pid; + + if (dialog_default->dialog_pid >= 0) + { + present_existing_delete_dialog (dialog_default); + return; + } + + /* This is to get a better string if the title isn't representable + * in the locale encoding; actual conversion to UTF-8 is done inside + * meta_show_dialog */ + if (window->title && window->title[0]) + { + tmp = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL); + if (tmp == NULL) + window_title = NULL; + else + window_title = window->title; + g_free (tmp); + } + else + { + window_title = NULL; + } + + if (window_title) + /* Translators: %s is a window title */ + tmp = g_strdup_printf (_("ā€œ%sā€ is not responding."), window_title); + else + tmp = g_strdup (_("Application is not responding.")); + + window_content = g_strdup_printf ( + "%s\n\n%s", + tmp, + _("You may choose to wait a short while for it to " + "continue or force the application to quit entirely.")); + + dialog_pid = + meta_show_dialog ("--question", + window_content, NULL, + window->screen->screen_name, + _("_Force Quit"), _("_Wait"), + "face-sad-symbolic", window->xwindow, + NULL, NULL); + + g_free (window_content); + g_free (tmp); + + dialog_default->dialog_pid = dialog_pid; + g_child_watch_add (dialog_pid, dialog_exited, dialog); +} + +static void +meta_close_dialog_default_hide (MetaCloseDialog *dialog) +{ + MetaCloseDialogDefault *dialog_default; + + dialog_default = META_CLOSE_DIALOG_DEFAULT (dialog); + + if (dialog_default->child_watch_id) + { + g_source_remove (dialog_default->child_watch_id); + dialog_default->child_watch_id = 0; + } + + if (dialog_default->dialog_pid > -1) + kill (dialog_default->dialog_pid, SIGTERM); +} + +static void +meta_close_dialog_iface_init (MetaCloseDialogInterface *iface) +{ + iface->show = meta_close_dialog_default_show; + iface->hide = meta_close_dialog_default_hide; +} + +static void +meta_close_dialog_default_finalize (GObject *object) +{ + MetaCloseDialogDefault *dialog; + + dialog = META_CLOSE_DIALOG_DEFAULT (object); + + if (dialog->child_watch_id) + g_source_remove (dialog->child_watch_id); + + if (dialog->dialog_pid > -1) + { + kill (dialog->dialog_pid, SIGKILL); + dialog->dialog_pid = -1; + } + + G_OBJECT_CLASS (meta_close_dialog_default_parent_class)->finalize (object); +} + +static void +meta_close_dialog_default_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaCloseDialogDefault *dialog; + + dialog = META_CLOSE_DIALOG_DEFAULT (object); + + switch (prop_id) + { + case PROP_WINDOW: + dialog->window = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_close_dialog_default_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaCloseDialogDefault *dialog; + + dialog = META_CLOSE_DIALOG_DEFAULT (object); + + switch (prop_id) + { + case PROP_WINDOW: + g_value_set_object (value, dialog->window); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_close_dialog_default_class_init (MetaCloseDialogDefaultClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_close_dialog_default_finalize; + object_class->set_property = meta_close_dialog_default_set_property; + object_class->get_property = meta_close_dialog_default_get_property; + + g_object_class_override_property (object_class, PROP_WINDOW, "window"); +} + +static void +meta_close_dialog_default_init (MetaCloseDialogDefault *dialog) +{ + dialog->dialog_pid = -1; +} + +MetaCloseDialog * +meta_close_dialog_default_new (MetaWindow *window) +{ + return g_object_new (META_TYPE_CLOSE_DIALOG_DEFAULT, + "window", window, + NULL); +}