diff options
Diffstat (limited to 'src/ui/metacity-dialog.c')
-rw-r--r-- | src/ui/metacity-dialog.c | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/src/ui/metacity-dialog.c b/src/ui/metacity-dialog.c new file mode 100644 index 0000000..d47a9b3 --- /dev/null +++ b/src/ui/metacity-dialog.c @@ -0,0 +1,438 @@ +/* -*- 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, ×tamp_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; + } +} |