From 90ff51acdb483a306632b65d521d7114f58fa8a0 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 30 May 2002 03:54:10 +0000 Subject: [PATCH] improve error about failing to open session manager. 2002-05-29 Havoc Pennington * src/session.c (meta_session_init): improve error about failing to open session manager. (shutdown_cancelled_callback): send SmcSaveYourselfDone when we get cancelled (interact_callback): implement an interact callback that complains about lame clients that can't be saved. Still somewhat buggy in that it sends InteractDone before the user has closed the dialog. --- ChangeLog | 11 +++ src/metacity-dialog.c | 161 ++++++++++++++++++++++++++++++++++++++++++ src/session.c | 153 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 321 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 155f1f0cd..608ce04ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2002-05-29 Havoc Pennington + + * src/session.c (meta_session_init): improve error about failing + to open session manager. + (shutdown_cancelled_callback): send SmcSaveYourselfDone when we + get cancelled + (interact_callback): implement an interact callback that complains + about lame clients that can't be saved. Still somewhat buggy + in that it sends InteractDone before the user has closed the + dialog. + 2002-05-29 Havoc Pennington * src/tools/metacity-mag.c: add a magnifier I'm using when making diff --git a/src/metacity-dialog.c b/src/metacity-dialog.c index 1e9b2f722..6a8a6a910 100644 --- a/src/metacity-dialog.c +++ b/src/metacity-dialog.c @@ -109,6 +109,156 @@ kill_window_question (const char *window_name, 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) +{ + GtkWidget *dialog; + GtkWidget *list; + GtkWidget *sw; + + dialog = gtk_message_dialog_new (NULL, + 0, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CLOSE, + _("These windows do not support \"save current setup\" and will have to be restarted manually next time you log in.")); + + g_signal_connect (G_OBJECT (dialog), + "response", + G_CALLBACK (gtk_main_quit), + NULL); + + 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); + + /* 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_widget_show_all (dialog); + + gtk_main (); + + return 0; +} + int main (int argc, char **argv) { @@ -134,6 +284,17 @@ main (int argc, char **argv) return kill_window_question (argv[2], argv[3]); } + else if (strcmp (argv[1], "--warn-about-no-sm-support") == 0) + { + /* argc must be even because we want title-class pairs */ + if (argc < 3 || (argc % 2) != 0) + { + g_printerr ("bad args to metacity-dialog\n"); + return 1; + } + + return warn_about_no_sm_support (&argv[2]); + } g_printerr ("bad args to metacity-dialog\n"); return 1; diff --git a/src/session.c b/src/session.c index 5facaea95..3c965a6cb 100644 --- a/src/session.c +++ b/src/session.c @@ -73,6 +73,7 @@ static char* load_state (const char *previous_save_file); static void regenerate_save_file (void); static const char* full_save_file (void); static const char* base_save_file (void); +static void warn_about_lame_clients (void); /* This is called when data is available on an ICE connection. */ static gboolean @@ -181,6 +182,8 @@ typedef enum STATE_SAVING_PHASE_1, STATE_WAITING_FOR_PHASE_2, STATE_SAVING_PHASE_2, + STATE_WAITING_FOR_INTERACT, + STATE_DONE_WITH_INTERACT, STATE_FROZEN, STATE_REGISTERING } ClientState; @@ -206,6 +209,7 @@ static void set_clone_restart_commands (void); static char *client_id = NULL; static gpointer session_connection = NULL; static ClientState current_state = STATE_DISCONNECTED; +static gboolean interaction_allowed = FALSE; void meta_session_init (const char *previous_client_id, @@ -266,7 +270,7 @@ meta_session_init (const char *previous_client_id, if (session_connection == NULL) { - meta_warning ("Failed to open connection to session manager: %s\n", buf); + meta_warning (_("Failed to a open connection to a session manager, so window positions will not be saved: %s\n"), buf); goto out; } @@ -374,8 +378,26 @@ save_yourself_possibly_done (gboolean shutdown, current_state = STATE_WAITING_FOR_PHASE_2; } + if (current_state == STATE_SAVING_PHASE_2 && + interaction_allowed) + { + Status status; + + status = SmcInteractRequest (session_connection, + /* ignore this feature of the protocol by always + * claiming normal + */ + SmDialogNormal, + interact_callback, + GINT_TO_POINTER (shutdown)); + + if (status) + current_state = STATE_WAITING_FOR_INTERACT; + } + if (current_state == STATE_SAVING_PHASE_1 || - current_state == STATE_SAVING_PHASE_2) + current_state == STATE_SAVING_PHASE_2 || + current_state == STATE_DONE_WITH_INTERACT) { SmcSaveYourselfDone (session_connection, successful); @@ -387,7 +409,6 @@ save_yourself_possibly_done (gboolean shutdown, } } - static void save_phase_2_callback (SmcConn smc_conn, SmPointer client_data) { @@ -435,6 +456,8 @@ save_yourself_callback (SmcConn smc_conn, } #endif + interaction_allowed = interact_style != SmInteractStyleNone; + current_state = STATE_SAVING_PHASE_1; regenerate_save_file (); @@ -462,13 +485,29 @@ save_complete_callback (SmcConn smc_conn, SmPointer client_data) static void shutdown_cancelled_callback (SmcConn smc_conn, SmPointer client_data) { - /* nothing */ + if (session_connection != NULL && + (current_state != STATE_IDLE && current_state != STATE_FROZEN)) + { + SmcSaveYourselfDone (session_connection, True); + current_state = STATE_IDLE; + } } static void interact_callback (SmcConn smc_conn, SmPointer client_data) { /* nothing */ + gboolean shutdown; + + shutdown = GPOINTER_TO_INT (client_data); + + current_state = STATE_DONE_WITH_INTERACT; + + warn_about_lame_clients (); + + SmcInteractDone (session_connection, False /* don't cancel logout */); + + save_yourself_possibly_done (shutdown, TRUE); } static void @@ -1546,4 +1585,110 @@ base_save_file (void) return relative_save_path; } +static int +windows_cmp_by_title (MetaWindow *a, + MetaWindow *b) +{ + return g_utf8_collate (a->title, b->title); +} + +static void +warn_about_lame_clients (void) +{ + GSList *displays; + GSList *display_iter; + GSList *lame; + char **argv; + int i; + GSList *tmp; + int len; + int child_pid; + GError *err; + + lame = NULL; + displays = meta_displays_list (); + display_iter = displays; + while (display_iter != NULL) + { + GSList *windows; + + windows = meta_display_list_windows (display_iter->data); + tmp = windows; + while (tmp != NULL) + { + MetaWindow *window; + + window = tmp->data; + + /* only complain about normal windows, the others + * are kind of dumb to worry about + */ + if (window->sm_client_id == NULL && + window->type == META_WINDOW_NORMAL) + lame = g_slist_prepend (lame, window); + + tmp = tmp->next; + } + + g_slist_free (windows); + + display_iter = display_iter->next; + } + /* don't need to free displays */ + displays = NULL; + + lame = g_slist_sort (lame, (GCompareFunc) windows_cmp_by_title); + + len = g_slist_length (lame); + len *= 2; /* titles and also classes */ + 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] = "--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; + + tmp = tmp->next; + } + + err = NULL; + if (!g_spawn_async_with_pipes ("/", + argv, + NULL, + 0, + NULL, NULL, + &child_pid, + NULL, + NULL, + 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); + + /* FIXME we need to keep a pipe to the child open to detect when it exits, and + * only send InteractDone when the child has exited. + */ +} + #endif /* HAVE_SM */