summaryrefslogtreecommitdiff
path: root/src/core/delete.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/delete.c')
-rw-r--r--src/core/delete.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/core/delete.c b/src/core/delete.c
new file mode 100644
index 00000000..f0590e3b
--- /dev/null
+++ b/src/core/delete.c
@@ -0,0 +1,266 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* Marco window deletion */
+
+/*
+ * Copyright (C) 2001, 2002 Havoc Pennington
+ * Copyright (C) 2004 Elijah Newren
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#define _SVID_SOURCE /* for gethostname() */
+
+#include <config.h>
+#include "util.h"
+#include "window-private.h"
+#include "errors.h"
+#include "workspace.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static void meta_window_present_delete_dialog (MetaWindow *window,
+ guint32 timestamp);
+
+static void
+delete_ping_reply_func (MetaDisplay *display,
+ Window xwindow,
+ guint32 timestamp,
+ void *user_data)
+{
+ meta_topic (META_DEBUG_PING,
+ "Got reply to delete ping for %s\n",
+ ((MetaWindow*)user_data)->desc);
+
+ /* we do nothing */
+}
+
+static void
+dialog_exited (GPid pid,
+ int status,
+ gpointer user_data)
+{
+ MetaWindow *ours = (MetaWindow*) user_data;
+
+ ours->dialog_pid = -1;
+
+ /* exit status of 1 means the user pressed "Force Quit" */
+ if (WIFEXITED (status) && WEXITSTATUS (status) == 1)
+ meta_window_kill (ours);
+}
+
+static void
+delete_ping_timeout_func (MetaDisplay *display,
+ Window xwindow,
+ guint32 timestamp,
+ void *user_data)
+{
+ MetaWindow *window = user_data;
+ char *window_title;
+ gchar *window_content, *tmp;
+ GPid dialog_pid;
+
+ meta_topic (META_DEBUG_PING,
+ "Got delete ping timeout for %s\n",
+ window->desc);
+
+ if (window->dialog_pid >= 0)
+ {
+ meta_window_present_delete_dialog (window, timestamp);
+ return;
+ }
+
+ window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL);
+
+ /* Translators: %s is a window title */
+ tmp = g_strdup_printf (_("<tt>%s</tt> is not responding."),
+ window_title);
+ window_content = g_strdup_printf (
+ "<big><b>%s</b></big>\n\n<i>%s</i>",
+ tmp,
+ _("You may choose to wait a short while for it to "
+ "continue or force the application to quit entirely."));
+
+ g_free (window_title);
+
+ dialog_pid =
+ meta_show_dialog ("--question",
+ window_content, 0,
+ window->screen->number,
+ _("_Wait"), _("_Force Quit"), window->xwindow,
+ NULL, NULL);
+
+ g_free (window_content);
+ g_free (tmp);
+
+ window->dialog_pid = dialog_pid;
+ g_child_watch_add (dialog_pid, dialog_exited, window);
+}
+
+void
+meta_window_delete (MetaWindow *window,
+ guint32 timestamp)
+{
+ meta_error_trap_push (window->display);
+ if (window->delete_window)
+ {
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Deleting %s with delete_window request\n",
+ window->desc);
+ meta_window_send_icccm_message (window,
+ window->display->atom_WM_DELETE_WINDOW,
+ timestamp);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Deleting %s with explicit kill\n",
+ window->desc);
+ XKillClient (window->display->xdisplay, window->xwindow);
+ }
+ meta_error_trap_pop (window->display, FALSE);
+
+ meta_display_ping_window (window->display,
+ window,
+ timestamp,
+ delete_ping_reply_func,
+ delete_ping_timeout_func,
+ window);
+
+ if (window->has_focus)
+ {
+ /* FIXME Clean this up someday
+ * http://bugzilla.gnome.org/show_bug.cgi?id=108706
+ */
+#if 0
+ /* This is unfortunately going to result in weirdness
+ * if the window doesn't respond to the delete event.
+ * I don't know how to avoid that though.
+ */
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing default window because focus window %s was deleted/killed\n",
+ window->desc);
+ meta_workspace_focus_default_window (window->screen->active_workspace,
+ window);
+#else
+ meta_topic (META_DEBUG_FOCUS,
+ "Not unfocusing %s on delete/kill\n",
+ window->desc);
+#endif
+ }
+ else
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Window %s was deleted/killed but didn't have focus\n",
+ window->desc);
+ }
+}
+
+
+void
+meta_window_kill (MetaWindow *window)
+{
+ char buf[257];
+
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Killing %s brutally\n",
+ window->desc);
+
+ if (window->wm_client_machine != NULL &&
+ window->net_wm_pid > 0)
+ {
+ if (gethostname (buf, sizeof(buf)-1) == 0)
+ {
+ if (strcmp (buf, window->wm_client_machine) == 0)
+ {
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Killing %s with kill()\n",
+ window->desc);
+
+ if (kill (window->net_wm_pid, 9) < 0)
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Failed to signal %s: %s\n",
+ window->desc, strerror (errno));
+ }
+ }
+ else
+ {
+ meta_warning (_("Failed to get hostname: %s\n"),
+ strerror (errno));
+ }
+ }
+
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Disconnecting %s with XKillClient()\n",
+ window->desc);
+ meta_error_trap_push (window->display);
+ XKillClient (window->display->xdisplay, window->xwindow);
+ meta_error_trap_pop (window->display, FALSE);
+}
+
+void
+meta_window_free_delete_dialog (MetaWindow *window)
+{
+ if (window->dialog_pid >= 0)
+ {
+ kill (window->dialog_pid, 9);
+ window->dialog_pid = -1;
+ }
+}
+
+static void
+meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp)
+{
+ meta_topic (META_DEBUG_PING,
+ "Presenting existing ping dialog for %s\n",
+ window->desc);
+
+ if (window->dialog_pid >= 0)
+ {
+ GSList *windows;
+ GSList *tmp;
+
+ /* Activate transient for window that belongs to
+ * marco-dialog
+ */
+
+ windows = meta_display_list_windows (window->display);
+ tmp = windows;
+ while (tmp != NULL)
+ {
+ MetaWindow *w = tmp->data;
+
+ if (w->xtransient_for == window->xwindow &&
+ w->res_class &&
+ g_ascii_strcasecmp (w->res_class, "marco-dialog") == 0)
+ {
+ meta_window_activate (w, timestamp);
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (windows);
+ }
+}