1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* Metacity 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, see <http://www.gnu.org/licenses/>.
21 */
22
23 #define _GNU_SOURCE
24 #define _XOPEN_SOURCE /* for gethostname() and kill() */
25
26 #include <config.h>
27 #include "util.h"
28 #include "window-private.h"
29 #include "errors.h"
30 #include "workspace.h"
31
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <signal.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdio.h>
39
40 static void meta_window_present_delete_dialog (MetaWindow *window,
41 guint32 timestamp);
42
43 static void
delete_ping_reply_func(MetaDisplay * display,Window xwindow,guint32 timestamp,void * user_data)44 delete_ping_reply_func (MetaDisplay *display,
45 Window xwindow,
46 guint32 timestamp,
47 void *user_data)
48 {
49 meta_topic (META_DEBUG_PING,
50 "Got reply to delete ping for %s\n",
51 ((MetaWindow*)user_data)->desc);
52
53 /* we do nothing */
54 }
55
56 static void
dialog_exited(GPid pid,int status,gpointer user_data)57 dialog_exited (GPid pid,
58 int status,
59 gpointer user_data)
60 {
61 MetaWindow *ours = (MetaWindow*) user_data;
62
63 ours->dialog_pid = -1;
64
65 /* exit status of 1 means the user pressed "Force Quit" */
66 if (WIFEXITED (status) && WEXITSTATUS (status) == 1)
67 meta_window_kill (ours);
68 }
69
70 static void
delete_ping_timeout_func(MetaDisplay * display,Window xwindow,guint32 timestamp,void * user_data)71 delete_ping_timeout_func (MetaDisplay *display,
72 Window xwindow,
73 guint32 timestamp,
74 void *user_data)
75 {
76 MetaWindow *window = user_data;
77 char *window_title;
78 gchar *window_content, *tmp;
79 GPid dialog_pid;
80
81 meta_topic (META_DEBUG_PING,
82 "Got delete ping timeout for %s\n",
83 window->desc);
84
85 if (window->dialog_pid >= 0)
86 {
87 meta_window_present_delete_dialog (window, timestamp);
88 return;
89 }
90
91 window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL);
92
93 /* Translators: %s is a window title */
94 tmp = g_strdup_printf (_("<tt>%s</tt> is not responding."),
95 window_title);
96 window_content = g_strdup_printf (
97 "<big><b>%s</b></big>\n\n<i>%s</i>",
98 tmp,
99 _("You may choose to wait a short while for it to "
100 "continue or force the application to quit entirely."));
101
102 g_free (window_title);
103
104 dialog_pid =
105 meta_show_dialog ("--question",
106 window_content, NULL,
107 window->screen->screen_name,
108 _("_Wait"), _("_Force Quit"), window->xwindow,
109 NULL, NULL);
110
111 g_free (window_content);
112 g_free (tmp);
113
114 window->dialog_pid = dialog_pid;
115 g_child_watch_add (dialog_pid, dialog_exited, window);
116 }
117
118 void
meta_window_delete(MetaWindow * window,guint32 timestamp)119 meta_window_delete (MetaWindow *window,
120 guint32 timestamp)
121 {
122 meta_error_trap_push (window->display);
123 if (window->delete_window)
124 {
125 meta_topic (META_DEBUG_WINDOW_OPS,
126 "Deleting %s with delete_window request\n",
127 window->desc);
128 meta_window_send_icccm_message (window,
129 window->display->atom_WM_DELETE_WINDOW,
130 timestamp);
131 }
132 else
133 {
134 meta_topic (META_DEBUG_WINDOW_OPS,
135 "Deleting %s with explicit kill\n",
136 window->desc);
137 XKillClient (window->display->xdisplay, window->xwindow);
138 }
139 meta_error_trap_pop (window->display);
140
141 meta_display_ping_window (window->display,
142 window,
143 timestamp,
144 delete_ping_reply_func,
145 delete_ping_timeout_func,
146 window);
147 }
148
149 void
meta_window_kill(MetaWindow * window)150 meta_window_kill (MetaWindow *window)
151 {
152 pid_t client_pid;
153 char buf[257];
154
155 meta_topic (META_DEBUG_WINDOW_OPS,
156 "Killing %s brutally\n",
157 window->desc);
158
159 client_pid = meta_window_get_client_pid (window);
160
161 if (window->wm_client_machine != NULL &&
162 client_pid > 0)
163 {
164 if (gethostname (buf, sizeof(buf)-1) == 0)
165 {
166 if (strcmp (buf, window->wm_client_machine) == 0)
167 {
168 meta_topic (META_DEBUG_WINDOW_OPS,
169 "Killing %s with kill()\n",
170 window->desc);
171
172 if (kill (client_pid, 9) < 0)
173 meta_topic (META_DEBUG_WINDOW_OPS,
174 "Failed to signal %s: %s\n",
175 window->desc, strerror (errno));
176 }
177 }
178 else
179 {
180 g_warning ("Failed to get hostname: %s", strerror (errno));
181 }
182 }
183
184 meta_topic (META_DEBUG_WINDOW_OPS,
185 "Disconnecting %s with XKillClient()\n",
186 window->desc);
187 meta_error_trap_push (window->display);
188 XKillClient (window->display->xdisplay, window->xwindow);
189 meta_error_trap_pop (window->display);
190 }
191
192 void
meta_window_free_delete_dialog(MetaWindow * window)193 meta_window_free_delete_dialog (MetaWindow *window)
194 {
195 if (window->dialog_pid >= 0)
196 {
197 kill (window->dialog_pid, 9);
198 window->dialog_pid = -1;
199 }
200 }
201
202 static void
meta_window_present_delete_dialog(MetaWindow * window,guint32 timestamp)203 meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp)
204 {
205 meta_topic (META_DEBUG_PING,
206 "Presenting existing ping dialog for %s\n",
207 window->desc);
208
209 if (window->dialog_pid >= 0)
210 {
211 GSList *windows;
212 GSList *tmp;
213
214 /* Activate transient for window that belongs to
215 * metacity-dialog
216 */
217
218 windows = meta_display_list_windows (window->display, META_LIST_DEFAULT);
219 tmp = windows;
220 while (tmp != NULL)
221 {
222 MetaWindow *w = tmp->data;
223
224 if (w->xtransient_for == window->xwindow &&
225 w->res_class &&
226 g_ascii_strcasecmp (w->res_class, "metacity-dialog") == 0)
227 {
228 meta_window_activate (w, timestamp);
229 break;
230 }
231
232 tmp = tmp->next;
233 }
234
235 g_slist_free (windows);
236 }
237 }
238