00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #define _GNU_SOURCE
00026 #define _SVID_SOURCE
00027
00028 #include <config.h>
00029 #include "util.h"
00030 #include "window-private.h"
00031 #include "errors.h"
00032 #include "workspace.h"
00033
00034 #include <sys/types.h>
00035 #include <signal.h>
00036 #include <unistd.h>
00037 #include <errno.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041
00042 static void meta_window_present_delete_dialog (MetaWindow *window,
00043 guint32 timestamp);
00044
00045 static void
00046 delete_ping_reply_func (MetaDisplay *display,
00047 Window xwindow,
00048 guint32 timestamp,
00049 void *user_data)
00050 {
00051 meta_topic (META_DEBUG_PING,
00052 "Got reply to delete ping for %s\n",
00053 ((MetaWindow*)user_data)->desc);
00054
00055
00056 }
00057
00058 static Window
00059 window_from_string (const char *str)
00060 {
00061 char *end;
00062 unsigned long l;
00063
00064 end = NULL;
00065
00066 l = strtoul (str, &end, 16);
00067
00068 if (end == NULL || end == str)
00069 {
00070 meta_warning (_("Could not parse \"%s\" as an integer"),
00071 str);
00072 return None;
00073 }
00074
00075 if (*end != '\0')
00076 {
00077 meta_warning (_("Did not understand trailing characters \"%s\" in string \"%s\""),
00078 end, str);
00079 return None;
00080 }
00081
00082 return l;
00083 }
00084
00085 static int
00086 pid_from_string (const char *str)
00087 {
00088 char *end;
00089 long l;
00090
00091 end = NULL;
00092
00093 l = strtol (str, &end, 10);
00094
00095 if (end == NULL || end == str)
00096 {
00097 meta_warning (_("Could not parse \"%s\" as an integer"),
00098 str);
00099 return None;
00100 }
00101
00102 if (*end != '\0')
00103 {
00104 meta_warning (_("Did not understand trailing characters \"%s\" in string \"%s\""),
00105 end, str);
00106 return None;
00107 }
00108
00109 return l;
00110 }
00111
00112 static gboolean
00113 parse_dialog_output (const char *str,
00114 int *pid_out,
00115 Window *win_out)
00116 {
00117 char **split;
00118
00119 split = g_strsplit (str, "\n", 2);
00120 if (split && split[0] && split[1])
00121 {
00122 g_strchomp (split[0]);
00123 g_strchomp (split[1]);
00124
00125 *pid_out = pid_from_string (split[0]);
00126 *win_out = window_from_string (split[1]);
00127
00128 g_strfreev (split);
00129
00130 return TRUE;
00131 }
00132 else
00133 {
00134 g_strfreev (split);
00135 meta_warning (_("Failed to parse message \"%s\" from dialog process\n"),
00136 str);
00137 return FALSE;
00138 }
00139 }
00140
00141 static void
00142 search_and_destroy_window (int pid,
00143 Window xwindow)
00144 {
00145
00146
00147
00148
00149 GSList *tmp;
00150 gboolean found = FALSE;
00151 GSList *windows;
00152
00153 if (xwindow == None)
00154 {
00155 meta_topic (META_DEBUG_PING,
00156 "Window to destroy is None, doing nothing\n");
00157 return;
00158 }
00159
00160 windows = meta_display_list_windows (meta_get_display ());
00161 tmp = windows;
00162
00163 while (tmp != NULL)
00164 {
00165 MetaWindow *w = tmp->data;
00166
00167 if (w->dialog_pid == pid)
00168 {
00169 if (w->xwindow != xwindow)
00170 meta_topic (META_DEBUG_PING,
00171 "Dialog pid matches but not xwindow (0x%lx vs. 0x%lx)\n",
00172 w->xwindow, xwindow);
00173 else
00174 {
00175 meta_window_kill (w);
00176 found = TRUE;
00177 }
00178 }
00179
00180 tmp = tmp->next;
00181 }
00182
00183 g_slist_free (windows);
00184
00185 if (!found)
00186 meta_topic (META_DEBUG_PING,
00187 "Did not find a window with dialog pid %d xwindow 0x%lx\n",
00188 pid, xwindow);
00189 }
00190
00191 static void
00192 release_window_with_fd (int fd)
00193 {
00194
00195
00196
00197
00198 gboolean found = FALSE;
00199
00200 GSList *windows = meta_display_list_windows (meta_get_display ());
00201 GSList *tmp = windows;
00202
00203 while (tmp != NULL)
00204 {
00205 MetaWindow *w = tmp->data;
00206
00207 if (w->dialog_pid >= 0 &&
00208 w->dialog_pipe == fd)
00209 {
00210 meta_topic (META_DEBUG_PING,
00211 "Removing dialog with fd %d pid %d from window %s\n",
00212 fd, w->dialog_pid, w->desc);
00213 meta_window_free_delete_dialog (w);
00214 found = TRUE;
00215 }
00216
00217 tmp = tmp->next;
00218 }
00219
00220 g_slist_free (windows);
00221
00222 if (!found)
00223 meta_topic (META_DEBUG_PING,
00224 "Did not find a window with a dialog pipe %d\n",
00225 fd);
00226 }
00227
00228 static gboolean
00229 io_from_ping_dialog (GIOChannel *channel,
00230 GIOCondition condition,
00231 gpointer data)
00232 {
00233 meta_topic (META_DEBUG_PING,
00234 "IO handler from ping dialog, condition = %x\n",
00235 condition);
00236
00237 if (condition & G_IO_IN)
00238 {
00239 char *str;
00240 gsize len;
00241 GError *err;
00242
00243
00244 str = NULL;
00245 len = 0;
00246 err = NULL;
00247 g_io_channel_read_to_end (channel,
00248 &str, &len,
00249 &err);
00250
00251 if (err)
00252 {
00253 meta_warning (_("Error reading from dialog display process: %s\n"),
00254 err->message);
00255 g_error_free (err);
00256 }
00257
00258 meta_topic (META_DEBUG_PING,
00259 "Read %" G_GSIZE_FORMAT " bytes strlen %d \"%s\" from child\n",
00260 len, str ? (int) strlen (str) : 0, str ? str : "NULL");
00261
00262 if (len > 0)
00263 {
00264
00265 int pid;
00266 Window xwindow;
00267
00268 if (parse_dialog_output (str, &pid, &xwindow))
00269 search_and_destroy_window (pid, xwindow);
00270 }
00271
00272 g_free (str);
00273 }
00274
00275 release_window_with_fd (g_io_channel_unix_get_fd (channel));
00276
00277
00278 return FALSE;
00279 }
00280
00281 static void
00282 delete_ping_timeout_func (MetaDisplay *display,
00283 Window xwindow,
00284 guint32 timestamp,
00285 void *user_data)
00286 {
00287 MetaWindow *window = user_data;
00288 GError *err;
00289 int child_pid;
00290 int outpipe;
00291 char *argv[9];
00292 char numbuf[32];
00293 char timestampbuf[32];
00294 char *window_id_str;
00295 char *window_title;
00296 GIOChannel *channel;
00297
00298 meta_topic (META_DEBUG_PING,
00299 "Got delete ping timeout for %s\n",
00300 window->desc);
00301
00302 if (window->dialog_pid >= 0)
00303 {
00304 meta_window_present_delete_dialog (window, timestamp);
00305 return;
00306 }
00307
00308 window_id_str = g_strdup_printf ("0x%lx", window->xwindow);
00309 window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL);
00310
00311 sprintf (numbuf, "%d", window->screen->number);
00312 sprintf (timestampbuf, "%u", timestamp);
00313
00314 argv[0] = METACITY_LIBEXECDIR"/metacity-dialog";
00315 argv[1] = "--screen";
00316 argv[2] = numbuf;
00317 argv[3] = "--timestamp";
00318 argv[4] = timestampbuf;
00319 argv[5] = "--kill-window-question";
00320 argv[6] = window_title;
00321 argv[7] = window_id_str;
00322 argv[8] = NULL;
00323
00324 err = NULL;
00325 if (!g_spawn_async_with_pipes ("/",
00326 argv,
00327 NULL,
00328 0,
00329 NULL, NULL,
00330 &child_pid,
00331 NULL,
00332 &outpipe,
00333 NULL,
00334 &err))
00335 {
00336 meta_warning (_("Error launching metacity-dialog to ask about killing an application: %s\n"),
00337 err->message);
00338 g_error_free (err);
00339 goto out;
00340 }
00341
00342 window->dialog_pid = child_pid;
00343 window->dialog_pipe = outpipe;
00344
00345 channel = g_io_channel_unix_new (window->dialog_pipe);
00346 g_io_add_watch_full (channel, G_PRIORITY_DEFAULT,
00347 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
00348 io_from_ping_dialog,
00349 NULL, NULL);
00350 g_io_channel_unref (channel);
00351
00352 out:
00353 g_free (window_title);
00354 g_free (window_id_str);
00355 }
00356
00357 void
00358 meta_window_delete (MetaWindow *window,
00359 guint32 timestamp)
00360 {
00361 meta_error_trap_push (window->display);
00362 if (window->delete_window)
00363 {
00364 meta_topic (META_DEBUG_WINDOW_OPS,
00365 "Deleting %s with delete_window request\n",
00366 window->desc);
00367 meta_window_send_icccm_message (window,
00368 window->display->atom_WM_DELETE_WINDOW,
00369 timestamp);
00370 }
00371 else
00372 {
00373 meta_topic (META_DEBUG_WINDOW_OPS,
00374 "Deleting %s with explicit kill\n",
00375 window->desc);
00376 XKillClient (window->display->xdisplay, window->xwindow);
00377 }
00378 meta_error_trap_pop (window->display, FALSE);
00379
00380 meta_display_ping_window (window->display,
00381 window,
00382 timestamp,
00383 delete_ping_reply_func,
00384 delete_ping_timeout_func,
00385 window);
00386
00387 if (window->has_focus)
00388 {
00389
00390
00391
00392 #if 0
00393
00394
00395
00396
00397 meta_topic (META_DEBUG_FOCUS,
00398 "Focusing default window because focus window %s was deleted/killed\n",
00399 window->desc);
00400 meta_workspace_focus_default_window (window->screen->active_workspace,
00401 window);
00402 #else
00403 meta_topic (META_DEBUG_FOCUS,
00404 "Not unfocusing %s on delete/kill\n",
00405 window->desc);
00406 #endif
00407 }
00408 else
00409 {
00410 meta_topic (META_DEBUG_FOCUS,
00411 "Window %s was deleted/killed but didn't have focus\n",
00412 window->desc);
00413 }
00414 }
00415
00416
00417 void
00418 meta_window_kill (MetaWindow *window)
00419 {
00420 char buf[257];
00421
00422 meta_topic (META_DEBUG_WINDOW_OPS,
00423 "Killing %s brutally\n",
00424 window->desc);
00425
00426 if (window->wm_client_machine != NULL &&
00427 window->net_wm_pid > 0)
00428 {
00429 if (gethostname (buf, sizeof(buf)-1) == 0)
00430 {
00431 if (strcmp (buf, window->wm_client_machine) == 0)
00432 {
00433 meta_topic (META_DEBUG_WINDOW_OPS,
00434 "Killing %s with kill()\n",
00435 window->desc);
00436
00437 if (kill (window->net_wm_pid, 9) < 0)
00438 meta_topic (META_DEBUG_WINDOW_OPS,
00439 "Failed to signal %s: %s\n",
00440 window->desc, strerror (errno));
00441 }
00442 }
00443 else
00444 {
00445 meta_warning (_("Failed to get hostname: %s\n"),
00446 strerror (errno));
00447 }
00448 }
00449
00450 meta_topic (META_DEBUG_WINDOW_OPS,
00451 "Disconnecting %s with XKillClient()\n",
00452 window->desc);
00453 meta_error_trap_push (window->display);
00454 XKillClient (window->display->xdisplay, window->xwindow);
00455 meta_error_trap_pop (window->display, FALSE);
00456 }
00457
00458 void
00459 meta_window_free_delete_dialog (MetaWindow *window)
00460 {
00461 if (window->dialog_pid >= 0)
00462 {
00463 kill (window->dialog_pid, 9);
00464 close (window->dialog_pipe);
00465 window->dialog_pid = -1;
00466 window->dialog_pipe = -1;
00467 }
00468 }
00469
00470 static void
00471 meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp)
00472 {
00473 meta_topic (META_DEBUG_PING,
00474 "Presenting existing ping dialog for %s\n",
00475 window->desc);
00476
00477 if (window->dialog_pid >= 0)
00478 {
00479 GSList *windows;
00480 GSList *tmp;
00481
00482
00483
00484
00485
00486 windows = meta_display_list_windows (window->display);
00487 tmp = windows;
00488 while (tmp != NULL)
00489 {
00490 MetaWindow *w = tmp->data;
00491
00492 if (w->xtransient_for == window->xwindow &&
00493 w->res_class &&
00494 g_strcasecmp (w->res_class, "metacity-dialog") == 0)
00495 {
00496 meta_window_activate (w, timestamp);
00497 break;
00498 }
00499
00500 tmp = tmp->next;
00501 }
00502
00503 g_slist_free (windows);
00504 }
00505 }