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 #include <config.h>
00026 #include <gtk/gtk.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030
00031 #include <libintl.h>
00032 #define _(x) dgettext (GETTEXT_PACKAGE, x)
00033 #define N_(x) x
00034
00035 #include <gdk/gdkx.h>
00036 #include <X11/Xatom.h>
00037
00038 static Window
00039 window_from_string (const char *str)
00040 {
00041 char *end;
00042 unsigned long l;
00043
00044 end = NULL;
00045
00046 l = strtoul (str, &end, 16);
00047
00048 if (end == NULL || end == str)
00049 {
00050 g_printerr (_("Could not parse \"%s\" as an integer"),
00051 str);
00052 return None;
00053 }
00054
00055 if (*end != '\0')
00056 {
00057 g_printerr (_("Did not understand trailing characters \"%s\" in string \"%s\""),
00058 end, str);
00059 return None;
00060 }
00061
00062 return l;
00063 }
00064
00065 static void
00066 on_realize (GtkWidget *dialog,
00067 void *data)
00068 {
00069 const char *parent_str = data;
00070 Window xwindow;
00071
00072 xwindow = window_from_string (parent_str);
00073
00074 gdk_error_trap_push ();
00075 XSetTransientForHint (gdk_display, GDK_WINDOW_XID (dialog->window),
00076 xwindow);
00077 XSync (gdk_display, False);
00078 gdk_error_trap_pop ();
00079 }
00080
00081 static int
00082 kill_window_question (const char *window_name,
00083 const char *parent_str,
00084 guint32 timestamp)
00085 {
00086 GtkWidget *dialog;
00087 char *str, *tmp;
00088
00089 tmp = g_markup_escape_text (window_name, -1);
00090 str = g_strdup_printf (_("\"%s\" is not responding."), tmp);
00091 g_free (tmp);
00092 dialog = gtk_message_dialog_new (NULL, 0,
00093 GTK_MESSAGE_WARNING,
00094 GTK_BUTTONS_NONE,
00095 "<big><b>%s</b></big>\n\n<i>%s</i>",
00096 str,
00097 _("You may choose to wait a short while "
00098 "for it to continue or force the application "
00099 "to quit entirely."));
00100 g_free (str);
00101 gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-warning");
00102
00103 gtk_label_set_use_markup (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label), TRUE);
00104 gtk_label_set_line_wrap (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label), TRUE);
00105
00106 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
00107 _("_Wait"),
00108 GTK_RESPONSE_REJECT,
00109 _("_Force Quit"),
00110 GTK_RESPONSE_ACCEPT,
00111 NULL);
00112
00113 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
00114
00115 g_signal_connect (G_OBJECT (dialog), "realize",
00116 G_CALLBACK (on_realize), (char*) parent_str);
00117
00118 gtk_widget_realize (dialog);
00119 gdk_x11_window_set_user_time (dialog->window, timestamp);
00120
00121
00122 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
00123 g_print ("%d\n%s\n", (int) getpid (), parent_str);
00124 else
00125 g_print ("%d\n0x0\n", (int) getpid ());
00126
00127 return 0;
00128 }
00129
00130 static char*
00131 latin1_to_utf8 (const char *text)
00132 {
00133 GString *str;
00134 const char *p;
00135
00136 str = g_string_new ("");
00137
00138 p = text;
00139 while (*p)
00140 {
00141 g_string_append_unichar (str, *p);
00142 ++p;
00143 }
00144
00145 return g_string_free (str, FALSE);
00146 }
00147
00148 enum
00149 {
00150 COLUMN_TITLE,
00151 COLUMN_CLASS,
00152 COLUMN_LAST
00153 };
00154
00155 static GtkWidget*
00156 create_lame_apps_list (char **lame_apps)
00157 {
00158 GtkTreeSelection *selection;
00159 GtkCellRenderer *cell;
00160 GtkWidget *tree_view;
00161 GtkTreeViewColumn *column;
00162 GtkListStore *model;
00163 GtkTreeIter iter;
00164 int i;
00165
00166 model = gtk_list_store_new (COLUMN_LAST,
00167 G_TYPE_STRING,
00168 G_TYPE_STRING);
00169
00170 tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
00171
00172 g_object_unref (G_OBJECT (model));
00173
00174 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
00175
00176 gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
00177 GTK_SELECTION_NONE);
00178
00179 i = 0;
00180 while (lame_apps[i])
00181 {
00182 char *s;
00183
00184 gtk_list_store_append (model, &iter);
00185
00186
00187 s = latin1_to_utf8 (lame_apps[i+1]);
00188
00189 gtk_list_store_set (model,
00190 &iter,
00191 COLUMN_TITLE, lame_apps[i],
00192 COLUMN_CLASS, s,
00193 -1);
00194
00195 g_free (s);
00196
00197 i += 2;
00198 }
00199
00200 cell = gtk_cell_renderer_text_new ();
00201
00202 g_object_set (G_OBJECT (cell),
00203 "xpad", 2,
00204 NULL);
00205
00206 column = gtk_tree_view_column_new_with_attributes (_("Title"),
00207 cell,
00208 "text", COLUMN_TITLE,
00209 NULL);
00210
00211 gtk_tree_view_column_set_sort_column_id (column, COLUMN_TITLE);
00212
00213 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
00214 GTK_TREE_VIEW_COLUMN (column));
00215
00216 cell = gtk_cell_renderer_text_new ();
00217
00218 column = gtk_tree_view_column_new_with_attributes (_("Class"),
00219 cell,
00220 "text", COLUMN_CLASS,
00221 NULL);
00222
00223 gtk_tree_view_column_set_sort_column_id (column, COLUMN_CLASS);
00224
00225 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
00226 GTK_TREE_VIEW_COLUMN (column));
00227
00228 return tree_view;
00229 }
00230
00231 static int
00232 warn_about_no_sm_support (char **lame_apps,
00233 guint32 timestamp)
00234 {
00235 GtkWidget *dialog;
00236 GtkWidget *list;
00237 GtkWidget *sw;
00238 GtkWidget *button;
00239
00240 dialog = gtk_message_dialog_new (NULL,
00241 0,
00242 GTK_MESSAGE_WARNING,
00243 GTK_BUTTONS_NONE,
00244 _("These windows do not support \"save current setup\" and will have to be restarted manually next time you log in."));
00245 gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-warning");
00246
00247 g_signal_connect (G_OBJECT (dialog),
00248 "response",
00249 G_CALLBACK (gtk_main_quit),
00250 NULL);
00251
00252
00253 g_timeout_add (4 * 60 * 1000, (GSourceFunc) gtk_main_quit, NULL);
00254
00255 button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
00256 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
00257 list = create_lame_apps_list (lame_apps);
00258
00259 sw = gtk_scrolled_window_new (NULL, NULL);
00260 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
00261 GTK_POLICY_AUTOMATIC,
00262 GTK_POLICY_AUTOMATIC);
00263 gtk_container_set_border_width (GTK_CONTAINER (sw), 3);
00264
00265 gtk_container_add (GTK_CONTAINER (sw), list);
00266
00267
00268 gtk_window_set_geometry_hints (GTK_WINDOW (dialog),
00269 sw, NULL, 0);
00270
00271 gtk_window_set_resizable (GTK_WINDOW(dialog), TRUE);
00272
00273
00274
00275
00276 gtk_window_set_default_size (GTK_WINDOW (dialog),
00277 400, 225);
00278
00279 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
00280 sw,
00281 TRUE, TRUE, 0);
00282
00283 gtk_window_stick (GTK_WINDOW (dialog));
00284
00285 gtk_widget_realize (dialog);
00286 gdk_x11_window_set_user_time (dialog->window, timestamp);
00287
00288 gtk_widget_grab_focus (button);
00289 gtk_widget_show_all (dialog);
00290
00291 gtk_main ();
00292
00293 return 0;
00294 }
00295
00296 static int
00297 error_about_command (const char *gconf_key,
00298 const char *command,
00299 const char *error,
00300 guint32 timestamp)
00301 {
00302 GtkWidget *dialog;
00303
00304
00305
00306 if (*command != '\0')
00307 dialog = gtk_message_dialog_new (NULL, 0,
00308 GTK_MESSAGE_ERROR,
00309 GTK_BUTTONS_CLOSE,
00310 _("There was an error running \"%s\":\n"
00311 "%s."),
00312 command, error);
00313 else
00314 dialog = gtk_message_dialog_new (NULL, 0,
00315 GTK_MESSAGE_ERROR,
00316 GTK_BUTTONS_CLOSE,
00317 "%s", error);
00318 gtk_window_set_icon_name (GTK_WINDOW (dialog), "stock_dialog-error");
00319
00320 gtk_widget_realize (dialog);
00321 gdk_x11_window_set_user_time (dialog->window, timestamp);
00322
00323 gtk_dialog_run (GTK_DIALOG (dialog));
00324
00325 gtk_widget_destroy (dialog);
00326
00327 return 0;
00328 }
00329
00330 static gchar *screen = NULL;
00331 static gchar *timestamp_string = NULL;
00332 static gboolean isset_kill_window_question = FALSE;
00333 static gboolean isset_warn_about_no_sm_support = FALSE;
00334 static gboolean isset_command_failed_error = FALSE;
00335 static gchar **remaining_args;
00336
00337 static const GOptionEntry options[] = {
00338 { "screen", 0, 0, G_OPTION_ARG_STRING, &screen, NULL, NULL},
00339 { "timestamp", 0, 0, G_OPTION_ARG_STRING, ×tamp_string, NULL, NULL},
00340 { "kill-window-question", 'k', 0, G_OPTION_ARG_NONE,
00341 &isset_kill_window_question, NULL, NULL},
00342 { "warn-about-no-sm-support", 'w', 0, G_OPTION_ARG_NONE,
00343 &isset_warn_about_no_sm_support, NULL, NULL},
00344 { "command-failed-error", 'c', 0, G_OPTION_ARG_NONE,
00345 &isset_command_failed_error, NULL, NULL},
00346 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY,
00347 &remaining_args, NULL, NULL},
00348 { NULL}
00349 };
00350
00351 int
00352 main (int argc, char **argv)
00353 {
00354 GOptionContext *ctx;
00355 guint32 timestamp = 0;
00356 gint num_args = 0;
00357
00358 bindtextdomain (GETTEXT_PACKAGE, METACITY_LOCALEDIR);
00359 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
00360 textdomain (GETTEXT_PACKAGE);
00361
00362 gtk_init (&argc, &argv);
00363
00364 ctx = g_option_context_new ("- Dialogs for metacity. "
00365 "This program is intented for use by metacity only.");
00366 g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
00367 g_option_context_parse (ctx, &argc, &argv, NULL);
00368 g_option_context_free (ctx);
00369
00370 if (timestamp_string != NULL)
00371 {
00372 timestamp = strtoul (timestamp_string, NULL, 10);
00373 }
00374
00375 if (remaining_args != NULL)
00376 {
00377 num_args = g_strv_length (remaining_args);
00378 }
00379
00380 if ((isset_kill_window_question && isset_warn_about_no_sm_support) ||
00381 (isset_kill_window_question && isset_command_failed_error) ||
00382 (isset_warn_about_no_sm_support && isset_command_failed_error) ||
00383 timestamp == 0)
00384 {
00385 g_printerr ("bad args to metacity-dialog\n");
00386 return 1;
00387 }
00388
00389 else if (isset_kill_window_question)
00390 {
00391 if (num_args < 2)
00392 {
00393 g_printerr ("bad args to metacity-dialog\n");
00394 return 1;
00395 }
00396 else
00397 {
00398 return kill_window_question (remaining_args[0],
00399 remaining_args[1], timestamp);
00400 }
00401 }
00402
00403 else if (isset_warn_about_no_sm_support)
00404 {
00405
00406 if (num_args == 0 || (num_args % 2) != 0)
00407 {
00408 g_printerr ("bad args to metacity-dialog\n");
00409 return 1;
00410 }
00411 else
00412 {
00413 return warn_about_no_sm_support (&remaining_args[0], timestamp);
00414 }
00415 }
00416
00417 else if (isset_command_failed_error)
00418 {
00419
00420
00421
00422 if (num_args != 3)
00423 {
00424 g_printerr ("bad args to metacity-dialog\n");
00425 return 1;
00426 }
00427 else
00428 {
00429 return error_about_command (remaining_args[0],
00430 remaining_args[1], remaining_args[2], timestamp);
00431 }
00432 }
00433 else
00434 {
00435 g_printerr ("bad args to metacity-dialog\n");
00436 return 1;
00437 }
00438 }