1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* Marco window deletion */
4
5 /*
6 * Copyright (C) 2001, 2002 Havoc Pennington
7 * Copyright (C) 2004 Elijah Newren
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24
25 #define _GNU_SOURCE
26 #define _XOPEN_SOURCE /* for gethostname() and kill() */
27
28 #include <config.h>
29 #include <glib/gi18n-lib.h>
30
31 #include "util.h"
32 #include "window-private.h"
33 #include "errors.h"
34 #include "workspace.h"
35
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <signal.h>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <stdio.h>
43
44 static void meta_window_present_delete_dialog (MetaWindow *window,
45 guint32 timestamp);
46
47 static void
delete_ping_reply_func(MetaDisplay * display,Window xwindow,guint32 timestamp,void * user_data)48 delete_ping_reply_func (MetaDisplay *display,
49 Window xwindow,
50 guint32 timestamp,
51 void *user_data)
52 {
53 meta_topic (META_DEBUG_PING,
54 "Got reply to delete ping for %s\n",
55 ((MetaWindow*)user_data)->desc);
56
57 /* we do nothing */
58 }
59
60 static void
dialog_exited(GPid pid,int status,gpointer user_data)61 dialog_exited (GPid pid,
62 int status,
63 gpointer user_data)
64 {
65 MetaWindow *ours = (MetaWindow*) user_data;
66
67 ours->dialog_pid = -1;
68
69 /* exit status of 1 means the user pressed "Force Quit" */
70 if (WIFEXITED (status) && WEXITSTATUS (status) == 1)
71 meta_window_kill (ours);
72 }
73
74 static void
delete_ping_timeout_func(MetaDisplay * display,Window xwindow,guint32 timestamp,void * user_data)75 delete_ping_timeout_func (MetaDisplay *display,
76 Window xwindow,
77 guint32 timestamp,
78 void *user_data)
79 {
80 MetaWindow *window = user_data;
81 char *window_title;
82 gchar *window_content, *tmp;
83 GPid dialog_pid;
84
85 meta_topic (META_DEBUG_PING,
86 "Got delete ping timeout for %s\n",
87 window->desc);
88
89 if (window->dialog_pid >= 0)
90 {
91 meta_window_present_delete_dialog (window, timestamp);
92 return;
93 }
94
95 window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL);
96
97 /* Translators: %s is a window title */
98 tmp = g_strdup_printf (_("<tt>%s</tt> is not responding."),
99 window_title);
100 window_content = g_strdup_printf (
101 "<big><b>%s</b></big>\n\n<i>%s</i>",
102 tmp,
103 _("You may choose to wait a short while for it to "
104 "continue or force the application to quit entirely."));
105
106 g_free (window_title);
107
108 dialog_pid =
109 meta_show_dialog ("--question",
110 window_content, NULL,
111 window->screen->screen_name,
112 _("_Wait"), _("_Force Quit"), window->xwindow,
113 NULL, NULL);
114
115 g_free (window_content);
116 g_free (tmp);
117
118 window->dialog_pid = dialog_pid;
119 g_child_watch_add (dialog_pid, dialog_exited, window);
120 }
121
122 void
meta_window_delete(MetaWindow * window,guint32 timestamp)123 meta_window_delete (MetaWindow *window,
124 guint32 timestamp)
125 {
126 meta_error_trap_push (window->display);
127 if (window->delete_window)
128 {
129 meta_topic (META_DEBUG_WINDOW_OPS,
130 "Deleting %s with delete_window request\n",
131 window->desc);
132 meta_window_send_icccm_message (window,
133 window->display->atom_WM_DELETE_WINDOW,
134 timestamp);
135 }
136 else
137 {
138 meta_topic (META_DEBUG_WINDOW_OPS,
139 "Deleting %s with explicit kill\n",
140 window->desc);
141 XKillClient (window->display->xdisplay, window->xwindow);
142 }
143 meta_error_trap_pop (window->display, FALSE);
144
145 meta_display_ping_window (window->display,
146 window,
147 timestamp,
148 delete_ping_reply_func,
149 delete_ping_timeout_func,
150 window);
151 }
152
153 void
meta_window_kill(MetaWindow * window)154 meta_window_kill (MetaWindow *window)
155 {
156 char buf[257];
157
158 meta_topic (META_DEBUG_WINDOW_OPS,
159 "Killing %s brutally\n",
160 window->desc);
161
162 if (window->wm_client_machine != NULL &&
163 window->net_wm_pid > 0)
164 {
165 if (gethostname (buf, sizeof(buf)-1) == 0)
166 {
167 if (strcmp (buf, window->wm_client_machine) == 0)
168 {
169 meta_topic (META_DEBUG_WINDOW_OPS,
170 "Killing %s with kill()\n",
171 window->desc);
172
173 if (kill (window->net_wm_pid, 9) < 0)
174 meta_topic (META_DEBUG_WINDOW_OPS,
175 "Failed to signal %s: %s\n",
176 window->desc, strerror (errno));
177 }
178 }
179 else
180 {
181 meta_warning (_("Failed to get hostname: %s\n"),
182 strerror (errno));
183 }
184 }
185
186 meta_topic (META_DEBUG_WINDOW_OPS,
187 "Disconnecting %s with XKillClient()\n",
188 window->desc);
189 meta_error_trap_push (window->display);
190 XKillClient (window->display->xdisplay, window->xwindow);
191 meta_error_trap_pop (window->display, FALSE);
192 }
193
194 void
meta_window_free_delete_dialog(MetaWindow * window)195 meta_window_free_delete_dialog (MetaWindow *window)
196 {
197 if (window->dialog_pid >= 0)
198 {
199 kill (window->dialog_pid, 9);
200 window->dialog_pid = -1;
201 }
202 }
203
204 static void
meta_window_present_delete_dialog(MetaWindow * window,guint32 timestamp)205 meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp)
206 {
207 meta_topic (META_DEBUG_PING,
208 "Presenting existing ping dialog for %s\n",
209 window->desc);
210
211 if (window->dialog_pid >= 0)
212 {
213 GSList *windows;
214 GSList *tmp;
215
216 /* Activate transient for window that belongs to
217 * marco-dialog
218 */
219
220 windows = meta_display_list_windows (window->display);
221 tmp = windows;
222 while (tmp != NULL)
223 {
224 MetaWindow *w = tmp->data;
225
226 if (w->xtransient_for == window->xwindow &&
227 w->res_class &&
228 g_ascii_strcasecmp (w->res_class, "marco-dialog") == 0)
229 {
230 meta_window_activate (w, timestamp);
231 break;
232 }
233
234 tmp = tmp->next;
235 }
236
237 g_slist_free (windows);
238 }
239 }
240