mirror of
https://github.com/brl/mutter.git
synced 2025-01-06 01:32:15 +00:00
8e172aeecb
It makes sure we do not forget to zero the id and lets us avoid zero checks before. We use it for all new code, lets clean up the existing code base. https://gitlab.gnome.org/GNOME/mutter/merge_requests/947
282 lines
7.4 KiB
C
282 lines
7.4 KiB
C
/* -*- 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
|
*/
|
|
|
|
#define _XOPEN_SOURCE /* for kill() */
|
|
|
|
#include "config.h"
|
|
|
|
#include "core/meta-close-dialog-default-private.h"
|
|
#include "meta/meta-close-dialog.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <signal.h>
|
|
|
|
#include "core/util-private.h"
|
|
#include "core/window-private.h"
|
|
#include "x11/meta-x11-display-private.h"
|
|
|
|
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 (
|
|
"<big><b>%s</b></big>\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->display->x11_display->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);
|
|
|
|
g_clear_handle_id (&dialog_default->child_watch_id, g_source_remove);
|
|
|
|
if (dialog_default->dialog_pid > -1)
|
|
{
|
|
kill (dialog_default->dialog_pid, SIGTERM);
|
|
dialog_default->dialog_pid = -1;
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
g_clear_handle_id (&dialog->child_watch_id, g_source_remove);
|
|
|
|
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);
|
|
}
|