Use zenity for the session management dialogue that warns about

clueless clients, not metacity-dialog.  This is the last change
	away from metacity-dialog and therefore closes #521914.
	* src/Makefile.am:
	* src/core/session.c:
	* src/core/util.c:
	* src/include/util.h:
	* src/ui/metacity-dialog.c (deleted):


svn path=/trunk/; revision=4163
This commit is contained in:
Thomas James Alexander Thurman 2009-02-20 19:48:04 +00:00
parent 24f2df926a
commit 0b3f45bb1b
6 changed files with 77 additions and 581 deletions

View File

@ -1,3 +1,15 @@
2009-02-11 Thomas Thurman <tthurman@gnome.org>
Use zenity for the session management dialogue that warns about
clueless clients, not metacity-dialog. This is the last change
away from metacity-dialog and therefore closes #521914.
* src/Makefile.am:
* src/core/session.c:
* src/core/util.c:
* src/include/util.h:
* src/ui/metacity-dialog.c (deleted):
2009-02-12 Matthias Clasen <mclasen@redhat.com>
* src/core/bell.c (meta_bell_set_audible): Now that we are

View File

@ -134,9 +134,6 @@ libmetacityinclude_HEADERS = \
metacity_theme_viewer_SOURCES= \
ui/theme-viewer.c
metacity_dialog_SOURCES= \
ui/metacity-dialog.c
schema_bindings_SOURCES = \
core/schema-bindings.c \
metacity.schemas.in.in
@ -147,12 +144,10 @@ metacity.schemas.in: schema_bindings ${srcdir}/metacity.schemas.in.in
${builddir}/schema_bindings ${srcdir}/metacity.schemas.in.in ${builddir}/metacity.schemas.in
bin_PROGRAMS=metacity metacity-theme-viewer
libexec_PROGRAMS=metacity-dialog
EFENCE=
metacity_LDADD=@METACITY_LIBS@ $(EFENCE)
metacity_theme_viewer_LDADD= @METACITY_LIBS@ libmetacity-private.la
metacity_dialog_LDADD=@METACITY_LIBS@
testboxes_SOURCES=include/util.h core/util.c include/boxes.h core/boxes.c core/testboxes.c
testgradient_SOURCES=ui/gradient.h ui/gradient.c ui/testgradient.c

View File

@ -1731,13 +1731,6 @@ windows_cmp_by_title (MetaWindow *a,
return g_utf8_collate (a->title, b->title);
}
typedef struct
{
int child_pid;
int child_pipe;
gboolean shutdown;
} LameClientsDialogData;
static void
finish_interact (gboolean shutdown)
{
@ -1749,63 +1742,26 @@ finish_interact (gboolean shutdown)
}
}
static gboolean
io_from_warning_dialog (GIOChannel *channel,
GIOCondition condition,
gpointer data)
static void
sigchld_handler (MetaNexus *nexus, guint arg1, gpointer arg2, gpointer user_data)
{
LameClientsDialogData *d;
gboolean shutdown = GPOINTER_TO_INT (user_data);
d = data;
meta_topic (META_DEBUG_PING,
"IO handler from lame clients dialog, condition = %x\n",
condition);
if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR))
if (arg1 == 0) /* pressed "OK" */
{
finish_interact (d->shutdown);
/* Remove the callback, freeing data */
return FALSE;
finish_interact (shutdown);
}
else if (condition & G_IO_IN)
{
/* Check for EOF */
char buf[16];
int ret;
ret = read (d->child_pipe, buf, sizeof (buf));
if (ret == 0)
{
finish_interact (d->shutdown);
return FALSE;
}
}
/* Keep callback installed */
return TRUE;
}
static void
warn_about_lame_clients_and_finish_interact (gboolean shutdown)
{
GSList *lame;
GSList *lame = NULL;
GSList *windows;
char **argv;
int i;
GSList *lame_details = NULL;
GSList *tmp;
int len;
int child_pid;
int child_pipe;
GError *err;
GIOChannel *channel;
LameClientsDialogData *d;
guint32 timestamp;
char timestampbuf[32];
GSList *columns = NULL;
lame = NULL;
windows = meta_display_list_windows (meta_get_display ());
tmp = windows;
while (tmp != NULL)
@ -1833,76 +1789,42 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown)
return;
}
columns = g_slist_prepend (columns, "Window");
columns = g_slist_prepend (columns, "Class");
lame = g_slist_sort (lame, (GCompareFunc) windows_cmp_by_title);
timestamp = meta_display_get_current_time_roundtrip (meta_get_display ());
sprintf (timestampbuf, "%u", timestamp);
len = g_slist_length (lame);
len *= 2; /* titles and also classes */
len += 2; /* --timestamp flag and actual timestamp */
len += 1; /* NULL term */
len += 2; /* metacity-dialog command and option */
argv = g_new0 (char*, len);
i = 0;
argv[i] = METACITY_LIBEXECDIR"/metacity-dialog";
++i;
argv[i] = "--timestamp";
++i;
argv[i] = timestampbuf;
++i;
argv[i] = "--warn-about-no-sm-support";
++i;
tmp = lame;
while (tmp != NULL)
{
MetaWindow *w = tmp->data;
argv[i] = w->title;
++i;
argv[i] = w->res_class ? w->res_class : "";
++i;
lame_details = g_slist_prepend (lame_details,
w->res_class ? w->res_class : "");
lame_details = g_slist_prepend (lame_details,
w->title);
tmp = tmp->next;
}
child_pipe = -1;
child_pid = -1;
err = NULL;
if (!g_spawn_async_with_pipes ("/",
argv,
NULL,
0,
NULL, NULL,
&child_pid,
NULL,
&child_pipe,
NULL,
&err))
{
meta_warning (_("Error launching metacity-dialog to warn about apps that don't support session management: %s\n"),
err->message);
g_error_free (err);
}
g_free (argv);
g_slist_free (lame);
d = g_new0 (LameClientsDialogData, 1);
d->child_pipe = child_pipe;
d->child_pid = child_pid;
d->shutdown = shutdown;
meta_show_dialog("--list",
_("These windows do not support &quot;save current setup&quot; "
"and will have to be restarted manually next time "
"you log in."),
"240",
meta_screen_get_screen_number (meta_get_display()->active_screen),
NULL, NULL,
None,
columns,
lame_details);
g_slist_free (lame_details);
g_signal_connect (sigchld_nexus, "sigchld",
G_CALLBACK (sigchld_handler),
GINT_TO_POINTER (shutdown));
channel = g_io_channel_unix_new (d->child_pipe);
g_io_add_watch_full (channel, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
io_from_warning_dialog,
d, g_free);
g_io_channel_unref (channel);
}
#endif /* HAVE_SM */

View File

@ -548,29 +548,18 @@ meta_show_dialog (const char *type,
const char *ok_text,
const char *cancel_text,
const int transient_for,
const char **columns,
const char **entries)
GSList *columns,
GSList *entries)
{
GError *error = NULL;
char *screen_number_text = g_strdup_printf("%d", screen_number);
/*
We want:
zenity --display X --screen S --title Metacity --error --text "There was an error running <tt>terminal</tt>:\n\nYour computer is on fire."
** with no pipes
zenity --display X --screen S --title Metacity --question --text "<big><b><tt>%s</tt> is not responding.</b></big>\n\n<i>You may choose to wait a short while for it to continue or force the application to quit entirely.</i>"
zenity --display X --screen S --title Metacity --list --timeout 240 --text "These windows do not support \"save current setup\" and will have to be restarted manually next time you log in." --column "Window" --column "Class" "Firefox" "foo" "Duke Nukem Forever" "bar"
*/
const char **argvl;
char **envl;
GSList *tmp;
int i=0;
GPid child_pid;
argvl = g_malloc(sizeof (char*) * 15);
const char **argvl = g_malloc(sizeof (char*) *
(15 +
g_slist_length (columns)*2 +
g_slist_length (entries)));
argvl[i++] = "zenity";
argvl[i++] = type;
@ -594,22 +583,35 @@ zenity --display X --screen S --title Metacity --list --timeout 240 --text "Thes
argvl[i++] = ok_text;
}
if (cancel_text)
if (cancel_text)
{
argvl[i++] = "--cancel-label";
argvl[i++] = cancel_text;
}
}
tmp = columns;
while (tmp)
{
argvl[i++] = "--column";
argvl[i++] = tmp->data;
tmp = tmp->next;
}
tmp = entries;
while (tmp)
{
argvl[i++] = tmp->data;
tmp = tmp->next;
}
argvl[i] = NULL;
if (transient_for)
{
gchar *env = g_strdup_printf("%d", transient_for);
setenv ("WINDOWID", env, 1);
g_free (env);
gchar *env = g_strdup_printf("%d", transient_for);
setenv ("WINDOWID", env, 1);
g_free (env);
}
else
envl = NULL;
g_spawn_async (
"/",
@ -621,6 +623,9 @@ zenity --display X --screen S --title Metacity --list --timeout 240 --text "Thes
&error
);
if (transient_for)
unsetenv ("WINDOWID");
g_free (argvl);
g_free (screen_number_text);

View File

@ -105,8 +105,8 @@ GPid meta_show_dialog (const char *type,
const char *ok_text,
const char *cancel_text,
const int transient_for,
const char **columns,
const char **entries);
GSList *columns,
GSList *entries);
/* To disable verbose mode, we make these functions into no-ops */
#ifdef WITH_VERBOSE_MODE

View File

@ -1,438 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity dialog process */
/*
* Copyright (C) 2001 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 <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
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)
{
g_printerr (_("Could not parse \"%s\" as an integer"),
str);
return None;
}
if (*end != '\0')
{
g_printerr (_("Did not understand trailing characters \"%s\" in string \"%s\""),
end, str);
return None;
}
return l;
}
static void
on_realize (GtkWidget *dialog,
void *data)
{
const char *parent_str = data;
Window xwindow;
xwindow = window_from_string (parent_str);
gdk_error_trap_push ();
XSetTransientForHint (gdk_display, GDK_WINDOW_XID (dialog->window),
xwindow);
XSync (gdk_display, False);
gdk_error_trap_pop ();
}
static int
kill_window_question (const char *window_name,
const char *parent_str,
guint32 timestamp)
{
GtkWidget *dialog;
char *str, *tmp;
tmp = g_markup_escape_text (window_name, -1);
str = g_strdup_printf (_("\"%s\" is not responding."), tmp);
g_free (tmp);
dialog = gtk_message_dialog_new (NULL, 0,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_NONE,
"<big><b>%s</b></big>\n\n<i>%s</i>",
str,
_("You may choose to wait a short while "
"for it to continue or force the application "
"to quit entirely."));
g_free (str);
gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-warning");
gtk_label_set_use_markup (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label), TRUE);
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
_("_Wait"),
GTK_RESPONSE_REJECT,
_("_Force Quit"),
GTK_RESPONSE_ACCEPT,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
g_signal_connect (G_OBJECT (dialog), "realize",
G_CALLBACK (on_realize), (char*) parent_str);
gtk_widget_realize (dialog);
gdk_x11_window_set_user_time (dialog->window, timestamp);
/* return our PID, then window ID that should be killed */
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
g_print ("%d\n%s\n", (int) getpid (), parent_str);
else
g_print ("%d\n0x0\n", (int) getpid ());
return 0;
}
static char*
latin1_to_utf8 (const char *text)
{
GString *str;
const char *p;
str = g_string_new ("");
p = text;
while (*p)
{
g_string_append_unichar (str, *p);
++p;
}
return g_string_free (str, FALSE);
}
enum
{
COLUMN_TITLE,
COLUMN_CLASS,
COLUMN_LAST
};
static GtkWidget*
create_lame_apps_list (char **lame_apps)
{
GtkTreeSelection *selection;
GtkCellRenderer *cell;
GtkWidget *tree_view;
GtkTreeViewColumn *column;
GtkListStore *model;
GtkTreeIter iter;
int i;
model = gtk_list_store_new (COLUMN_LAST,
G_TYPE_STRING,
G_TYPE_STRING);
tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
g_object_unref (G_OBJECT (model));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
GTK_SELECTION_NONE);
i = 0;
while (lame_apps[i])
{
char *s;
gtk_list_store_append (model, &iter);
/* window class is latin-1 */
s = latin1_to_utf8 (lame_apps[i+1]);
gtk_list_store_set (model,
&iter,
COLUMN_TITLE, lame_apps[i],
COLUMN_CLASS, s,
-1);
g_free (s);
i += 2;
}
cell = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (cell),
"xpad", 2,
NULL);
column = gtk_tree_view_column_new_with_attributes (_("Title"),
cell,
"text", COLUMN_TITLE,
NULL);
gtk_tree_view_column_set_sort_column_id (column, COLUMN_TITLE);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
GTK_TREE_VIEW_COLUMN (column));
cell = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes (_("Class"),
cell,
"text", COLUMN_CLASS,
NULL);
gtk_tree_view_column_set_sort_column_id (column, COLUMN_CLASS);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
GTK_TREE_VIEW_COLUMN (column));
return tree_view;
}
static int
warn_about_no_sm_support (char **lame_apps,
guint32 timestamp)
{
GtkWidget *dialog;
GtkWidget *list;
GtkWidget *sw;
GtkWidget *button;
dialog = gtk_message_dialog_new (NULL,
0,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_NONE,
_("These windows do not support \"save current setup\" and will have to be restarted manually next time you log in."));
gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-warning");
g_signal_connect (G_OBJECT (dialog),
"response",
G_CALLBACK (gtk_main_quit),
NULL);
/* Wait 4 minutes then force quit, so we don't wait around all night */
g_timeout_add (4 * 60 * 1000, (GSourceFunc) gtk_main_quit, NULL);
button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
list = create_lame_apps_list (lame_apps);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_set_border_width (GTK_CONTAINER (sw), 3);
gtk_container_add (GTK_CONTAINER (sw), list);
/* sw as geometry widget */
gtk_window_set_geometry_hints (GTK_WINDOW (dialog),
sw, NULL, 0);
gtk_window_set_resizable (GTK_WINDOW(dialog), TRUE);
/* applies to geometry widget; try to avoid scrollbars,
* but don't make the window huge
*/
gtk_window_set_default_size (GTK_WINDOW (dialog),
400, 225);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
sw,
TRUE, TRUE, 0);
gtk_window_stick (GTK_WINDOW (dialog));
gtk_widget_realize (dialog);
gdk_x11_window_set_user_time (dialog->window, timestamp);
gtk_widget_grab_focus (button);
gtk_widget_show_all (dialog);
gtk_main ();
return 0;
}
static int
error_about_command (const char *gconf_key,
const char *command,
const char *error,
guint32 timestamp)
{
GtkWidget *dialog;
/* FIXME offer to change the value of the command's gconf key */
if (*command != '\0')
dialog = gtk_message_dialog_new (NULL, 0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
_("There was an error running \"%s\":\n"
"%s."),
command, error);
else
dialog = gtk_message_dialog_new (NULL, 0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"%s", error);
gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-error");
gtk_widget_realize (dialog);
gdk_x11_window_set_user_time (dialog->window, timestamp);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
return 0;
}
static gchar *screen = NULL;
static gchar *timestamp_string = NULL;
static gboolean isset_kill_window_question = FALSE;
static gboolean isset_warn_about_no_sm_support = FALSE;
static gboolean isset_command_failed_error = FALSE;
static gchar **remaining_args;
static const GOptionEntry options[] = {
{ "screen", 0, 0, G_OPTION_ARG_STRING, &screen, NULL, NULL},
{ "timestamp", 0, 0, G_OPTION_ARG_STRING, &timestamp_string, NULL, NULL},
{ "kill-window-question", 'k', 0, G_OPTION_ARG_NONE,
&isset_kill_window_question, NULL, NULL},
{ "warn-about-no-sm-support", 'w', 0, G_OPTION_ARG_NONE,
&isset_warn_about_no_sm_support, NULL, NULL},
{ "command-failed-error", 'c', 0, G_OPTION_ARG_NONE,
&isset_command_failed_error, NULL, NULL},
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY,
&remaining_args, NULL, NULL},
{ NULL}
};
int
main (int argc, char **argv)
{
GOptionContext *ctx;
guint32 timestamp = 0;
gint num_args = 0;
bindtextdomain (GETTEXT_PACKAGE, METACITY_LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
gtk_init (&argc, &argv);
ctx = g_option_context_new ("- Dialogs for metacity. "
"This program is intented for use by metacity only.");
g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
g_option_context_parse (ctx, &argc, &argv, NULL);
g_option_context_free (ctx);
if (timestamp_string != NULL)
{
timestamp = strtoul (timestamp_string, NULL, 10);
}
if (remaining_args != NULL)
{
num_args = g_strv_length (remaining_args);
}
if ((isset_kill_window_question && isset_warn_about_no_sm_support) ||
(isset_kill_window_question && isset_command_failed_error) ||
(isset_warn_about_no_sm_support && isset_command_failed_error) ||
timestamp == 0)
{
g_printerr ("bad args to metacity-dialog\n");
return 1;
}
else if (isset_kill_window_question)
{
if (num_args < 2)
{
g_printerr ("bad args to metacity-dialog\n");
return 1;
}
else
{
return kill_window_question (remaining_args[0],
remaining_args[1], timestamp);
}
}
else if (isset_warn_about_no_sm_support)
{
/* argc must be even because we want title-class pairs */
if (num_args == 0 || (num_args % 2) != 0)
{
g_printerr ("bad args to metacity-dialog\n");
return 1;
}
else
{
return warn_about_no_sm_support (&remaining_args[0], timestamp);
}
}
else if (isset_command_failed_error)
{
/* the args are the gconf key of the failed command, the text of
* the command, and the error message
*/
if (num_args != 3)
{
g_printerr ("bad args to metacity-dialog\n");
return 1;
}
else
{
return error_about_command (remaining_args[0],
remaining_args[1], remaining_args[2], timestamp);
}
}
else
{
g_printerr ("bad args to metacity-dialog\n");
return 1;
}
}