1
0
Fork 0
mutter-performance-source/src/core/delete.c

520 lines
13 KiB
C
Raw Normal View History

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity 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.
*/
#include <config.h>
#include "util.h"
#include "window.h"
#include "errors.h"
Changed MRU list to be per workspace instead of per display, so sticky 2003-08-15 Ray Strode <halfline@hawaii.rr.com> Changed MRU list to be per workspace instead of per display, so sticky windows don't hijack the window focus after workspace switching (Bug #97635). * src/delete.c (meta_window_delete): Use meta_workspace_focus_top_window instead of meta_screen_focus_top_window. * src/display.c (meta_display_open): Stop using display->mru_list. (find_tab_forward): (find_tab_backward): (meta_display_get_tab_list): Use workspace->mru_list instead of display->mru_list and remove unneeded calls to meta_window_visible_on_workspace * src/display.h: Remove mru_list from MetaDisplay * src/keybindings.c (handle_toggle_desktop): Use meta_workspace_focus_top_window instead of meta_screen_focus_top_window. * src/screen.c (meta_screen_focus_top_window): (meta_screen_focus_default_window): Remove functions. (meta_screen_show_desktop): Use meta_workspace_focus_top_window instead of meta_screen_focus_top_window. * src/screen.h: Remove meta_screen_focus_top_window and meta_screen_focus_default_window declarations. * src/window.c (meta_window_new): Stop using display->mru_list. (meta_window_free): Use meta_workspace_focus_top_window instead of meta_screen_focus_top_window and stop using display->mru_list. (meta_window_stick): Add sticky window to all workspace MRU lists. (meta_window_unstick): Remove non-sticky window from the workspace MRU lists it doesn't belong in. (meta_window_notify_focus): Move newly focused window to the front of active workspace's MRU list. * src/workspace.c (meta_workspace_new): Initialize workspace->mru_list to NULL. (meta_workspace_add_window): Add window to workspace's MRU list. (meta_workspace_remove_window): Remove window from workspace's MRU list. (meta_workspace_activate_with_focus): Use meta_workspace_focus_default_window instead of meta_screen_focus_default_window. (meta_workspace_focus_default_window): (meta_workspace_focus_mru_window): (meta_workspace_focus_top_window): Add functions. * src/workspace.h: Add mru_list to MetaWorkspace and add function declarations for meta_workspace_focus_default_window, meta_workspace_focus_mru_window, meta_workspace_focus_top_window.
2003-08-15 22:09:55 +00:00
#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,
Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ 2006-09-13 Elijah Newren <newren gmail com> * src/common.h (MetaWindowMenuFunc): * src/core.[ch] (meta_core_user_lower_and_unfocus, meta_core_user_focus, meta_core_show_window_menu, meta_core_begin_grab_op, meta_core_end_grab_op): * src/delete.c (delete_ping_reply_func, delete_ping_timeout_func, meta_window_delete): * src/display.[ch] (struct MetaDisplay, struct MetaPingData, sanity_check_timestamps, meta_display_open, event_callback, meta_spew_event, meta_display_set_grab_op_cursor, meta_display_begin_grab_op, meta_display_end_grab_op, meta_display_ping_timeout, meta_display_ping_window, process_pong_message, timestamp_too_old, meta_display_set_input_focus_window): * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard, meta_screen_grab_all_keys, meta_window_grab_all_keys, meta_window_ungrab_all_keys, error_on_generic_command, error_on_command, error_on_terminal_command): * src/metacity-dialog.c (on_realize, warn_about_no_sm_support, error_about_command, main): * src/screen.[ch] (struct _MetaScreen, meta_screen_new, meta_screen_show_desktop, meta_screen_apply_startup_properties): * src/session.c (warn_about_lame_clients_and_finish_interact): * src/window.[ch] (struct _MetaWindow, intervening_user_event_occurred, window_activate, meta_window_delete, meta_window_focus, meta_window_send_icccm_message, meta_window_client_message, menu_callback, meta_window_show_menu, struct EventScannerData, check_use_this_motion_notify, meta_window_begin_grab_op, meta_window_set_user_time): * src/workspace.[ch] (focus_ancestor_or_mru_window, meta_workspace_activate_with_focus, meta_workspace_activate, meta_workspace_focus_default_window, focus_ancestor_or_mru_window): Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ does) instead of Time. #348305
2006-09-13 16:32:33 +00:00
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 Window
window_from_string (const char *str)
{
char *end;
unsigned long l;
end = NULL;
l = strtoul (str, &end, 16);
if (end == NULL || end == str)
{
meta_warning (_("Could not parse \"%s\" as an integer"),
str);
return None;
}
if (*end != '\0')
{
meta_warning (_("Did not understand trailing characters \"%s\" in string \"%s\""),
end, str);
return None;
}
return l;
}
static int
pid_from_string (const char *str)
{
char *end;
long l;
end = NULL;
l = strtol (str, &end, 10);
if (end == NULL || end == str)
{
meta_warning (_("Could not parse \"%s\" as an integer"),
str);
return None;
}
if (*end != '\0')
{
meta_warning (_("Did not understand trailing characters \"%s\" in string \"%s\""),
end, str);
return None;
}
return l;
}
static gboolean
parse_dialog_output (const char *str,
int *pid_out,
Window *win_out)
{
char **split;
split = g_strsplit (str, "\n", 2);
if (split && split[0] && split[1])
{
g_strchomp (split[0]);
g_strchomp (split[1]);
*pid_out = pid_from_string (split[0]);
*win_out = window_from_string (split[1]);
g_strfreev (split);
return TRUE;
}
else
{
g_strfreev (split);
meta_warning (_("Failed to parse message \"%s\" from dialog process\n"),
str);
return FALSE;
}
}
static void
search_and_destroy_window (int pid,
Window xwindow)
{
/* Find the window with the given dialog PID,
* double check that it matches "xwindow", then
* kill the window.
*/
GSList *tmp;
gboolean found;
if (xwindow == None)
{
meta_topic (META_DEBUG_PING,
"Window to destroy is None, doing nothing\n");
return;
}
found = FALSE;
tmp = meta_displays_list ();
while (tmp != NULL)
{
GSList *windows = meta_display_list_windows (tmp->data);
GSList *tmp2;
tmp2 = windows;
while (tmp2 != NULL)
{
MetaWindow *w = tmp2->data;
if (w->dialog_pid == pid)
{
if (w->xwindow != xwindow)
meta_topic (META_DEBUG_PING,
"Dialog pid matches but not xwindow (0x%lx vs. 0x%lx)\n",
w->xwindow, xwindow);
else
{
meta_window_kill (w);
found = TRUE;
}
}
tmp2 = tmp2->next;
}
g_slist_free (windows);
tmp = tmp->next;
}
if (!found)
meta_topic (META_DEBUG_PING,
"Did not find a window with dialog pid %d xwindow 0x%lx\n",
pid, xwindow);
}
static void
release_window_with_fd (int fd)
{
/* Find the window with the given dialog PID,
* double check that it matches "xwindow", then
* kill the window.
*/
GSList *tmp;
gboolean found;
found = FALSE;
tmp = meta_displays_list ();
while (tmp != NULL)
{
GSList *windows = meta_display_list_windows (tmp->data);
GSList *tmp2;
tmp2 = windows;
while (tmp2 != NULL)
{
MetaWindow *w = tmp2->data;
if (w->dialog_pid >= 0 &&
w->dialog_pipe == fd)
{
meta_topic (META_DEBUG_PING,
"Removing dialog with fd %d pid %d from window %s\n",
fd, w->dialog_pid, w->desc);
meta_window_free_delete_dialog (w);
found = TRUE;
}
tmp2 = tmp2->next;
}
g_slist_free (windows);
tmp = tmp->next;
}
if (!found)
meta_topic (META_DEBUG_PING,
"Did not find a window with a dialog pipe %d\n",
fd);
}
static gboolean
io_from_ping_dialog (GIOChannel *channel,
GIOCondition condition,
gpointer data)
{
meta_topic (META_DEBUG_PING,
"IO handler from ping dialog, condition = %x\n",
condition);
if (condition & G_IO_IN)
{
char *str;
2005-12-14 12:47:35 +00:00
unsigned int len;
GError *err;
/* Go ahead and block for all data from child */
str = NULL;
len = 0;
err = NULL;
g_io_channel_read_to_end (channel,
&str, &len,
&err);
if (err)
{
meta_warning (_("Error reading from dialog display process: %s\n"),
err->message);
g_error_free (err);
}
meta_topic (META_DEBUG_PING,
"Read %d bytes strlen %d \"%s\" from child\n",
len, str ? strlen (str) : 0, str ? str : "NULL");
if (len > 0)
{
/* We're supposed to kill the given window */
int pid;
Window xwindow;
if (parse_dialog_output (str, &pid, &xwindow))
search_and_destroy_window (pid, xwindow);
}
g_free (str);
}
release_window_with_fd (g_io_channel_unix_get_fd (channel));
/* Remove the callback */
return FALSE;
}
static void
delete_ping_timeout_func (MetaDisplay *display,
Window xwindow,
Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ 2006-09-13 Elijah Newren <newren gmail com> * src/common.h (MetaWindowMenuFunc): * src/core.[ch] (meta_core_user_lower_and_unfocus, meta_core_user_focus, meta_core_show_window_menu, meta_core_begin_grab_op, meta_core_end_grab_op): * src/delete.c (delete_ping_reply_func, delete_ping_timeout_func, meta_window_delete): * src/display.[ch] (struct MetaDisplay, struct MetaPingData, sanity_check_timestamps, meta_display_open, event_callback, meta_spew_event, meta_display_set_grab_op_cursor, meta_display_begin_grab_op, meta_display_end_grab_op, meta_display_ping_timeout, meta_display_ping_window, process_pong_message, timestamp_too_old, meta_display_set_input_focus_window): * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard, meta_screen_grab_all_keys, meta_window_grab_all_keys, meta_window_ungrab_all_keys, error_on_generic_command, error_on_command, error_on_terminal_command): * src/metacity-dialog.c (on_realize, warn_about_no_sm_support, error_about_command, main): * src/screen.[ch] (struct _MetaScreen, meta_screen_new, meta_screen_show_desktop, meta_screen_apply_startup_properties): * src/session.c (warn_about_lame_clients_and_finish_interact): * src/window.[ch] (struct _MetaWindow, intervening_user_event_occurred, window_activate, meta_window_delete, meta_window_focus, meta_window_send_icccm_message, meta_window_client_message, menu_callback, meta_window_show_menu, struct EventScannerData, check_use_this_motion_notify, meta_window_begin_grab_op, meta_window_set_user_time): * src/workspace.[ch] (focus_ancestor_or_mru_window, meta_workspace_activate_with_focus, meta_workspace_activate, meta_workspace_focus_default_window, focus_ancestor_or_mru_window): Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ does) instead of Time. #348305
2006-09-13 16:32:33 +00:00
guint32 timestamp,
void *user_data)
{
MetaWindow *window = user_data;
GError *err;
int child_pid;
int outpipe;
char *argv[9];
char numbuf[32];
char timestampbuf[32];
char *window_id_str;
char *window_title;
GIOChannel *channel;
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_id_str = g_strdup_printf ("0x%lx", window->xwindow);
window_title = g_locale_from_utf8 (window->title, -1, NULL, NULL, NULL);
sprintf (numbuf, "%d", window->screen->number);
Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ 2006-09-13 Elijah Newren <newren gmail com> * src/common.h (MetaWindowMenuFunc): * src/core.[ch] (meta_core_user_lower_and_unfocus, meta_core_user_focus, meta_core_show_window_menu, meta_core_begin_grab_op, meta_core_end_grab_op): * src/delete.c (delete_ping_reply_func, delete_ping_timeout_func, meta_window_delete): * src/display.[ch] (struct MetaDisplay, struct MetaPingData, sanity_check_timestamps, meta_display_open, event_callback, meta_spew_event, meta_display_set_grab_op_cursor, meta_display_begin_grab_op, meta_display_end_grab_op, meta_display_ping_timeout, meta_display_ping_window, process_pong_message, timestamp_too_old, meta_display_set_input_focus_window): * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard, meta_screen_grab_all_keys, meta_window_grab_all_keys, meta_window_ungrab_all_keys, error_on_generic_command, error_on_command, error_on_terminal_command): * src/metacity-dialog.c (on_realize, warn_about_no_sm_support, error_about_command, main): * src/screen.[ch] (struct _MetaScreen, meta_screen_new, meta_screen_show_desktop, meta_screen_apply_startup_properties): * src/session.c (warn_about_lame_clients_and_finish_interact): * src/window.[ch] (struct _MetaWindow, intervening_user_event_occurred, window_activate, meta_window_delete, meta_window_focus, meta_window_send_icccm_message, meta_window_client_message, menu_callback, meta_window_show_menu, struct EventScannerData, check_use_this_motion_notify, meta_window_begin_grab_op, meta_window_set_user_time): * src/workspace.[ch] (focus_ancestor_or_mru_window, meta_workspace_activate_with_focus, meta_workspace_activate, meta_workspace_focus_default_window, focus_ancestor_or_mru_window): Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ does) instead of Time. #348305
2006-09-13 16:32:33 +00:00
sprintf (timestampbuf, "%u", timestamp);
argv[0] = METACITY_LIBEXECDIR"/metacity-dialog";
argv[1] = "--screen";
argv[2] = numbuf;
argv[3] = "--timestamp";
argv[4] = timestampbuf;
argv[5] = "--kill-window-question";
argv[6] = window_title;
argv[7] = window_id_str;
argv[8] = NULL;
err = NULL;
if (!g_spawn_async_with_pipes ("/",
argv,
NULL,
0,
NULL, NULL,
&child_pid,
NULL,
&outpipe,
NULL,
&err))
{
meta_warning (_("Error launching metacity-dialog to ask about killing an application: %s\n"),
err->message);
g_error_free (err);
goto out;
}
window->dialog_pid = child_pid;
window->dialog_pipe = outpipe;
channel = g_io_channel_unix_new (window->dialog_pipe);
g_io_add_watch_full (channel, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
io_from_ping_dialog,
NULL, NULL);
g_io_channel_unref (channel);
out:
g_free (window_title);
g_free (window_id_str);
}
void
meta_window_delete (MetaWindow *window,
Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ 2006-09-13 Elijah Newren <newren gmail com> * src/common.h (MetaWindowMenuFunc): * src/core.[ch] (meta_core_user_lower_and_unfocus, meta_core_user_focus, meta_core_show_window_menu, meta_core_begin_grab_op, meta_core_end_grab_op): * src/delete.c (delete_ping_reply_func, delete_ping_timeout_func, meta_window_delete): * src/display.[ch] (struct MetaDisplay, struct MetaPingData, sanity_check_timestamps, meta_display_open, event_callback, meta_spew_event, meta_display_set_grab_op_cursor, meta_display_begin_grab_op, meta_display_end_grab_op, meta_display_ping_timeout, meta_display_ping_window, process_pong_message, timestamp_too_old, meta_display_set_input_focus_window): * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard, meta_screen_grab_all_keys, meta_window_grab_all_keys, meta_window_ungrab_all_keys, error_on_generic_command, error_on_command, error_on_terminal_command): * src/metacity-dialog.c (on_realize, warn_about_no_sm_support, error_about_command, main): * src/screen.[ch] (struct _MetaScreen, meta_screen_new, meta_screen_show_desktop, meta_screen_apply_startup_properties): * src/session.c (warn_about_lame_clients_and_finish_interact): * src/window.[ch] (struct _MetaWindow, intervening_user_event_occurred, window_activate, meta_window_delete, meta_window_focus, meta_window_send_icccm_message, meta_window_client_message, menu_callback, meta_window_show_menu, struct EventScannerData, check_use_this_motion_notify, meta_window_begin_grab_op, meta_window_set_user_time): * src/workspace.[ch] (focus_ancestor_or_mru_window, meta_workspace_activate_with_focus, meta_workspace_activate, meta_workspace_focus_default_window, focus_ancestor_or_mru_window): Fix issues on 64-bit machines with timestamps by using guint32 (like gtk+ does) instead of Time. #348305
2006-09-13 16:32:33 +00:00
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);
close (window->dialog_pipe);
window->dialog_pid = -1;
window->dialog_pipe = -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
* metacity-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_strcasecmp (w->res_class, "metacity-dialog") == 0)
{
meta_window_activate (w, timestamp);
break;
}
tmp = tmp->next;
}
g_slist_free (windows);
}
}