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