diff options
author | Seth Nickell <snickell@stanford.edu> | 2002-05-11 04:28:20 +0000 |
---|---|---|
committer | Seth Nickell <seth@src.gnome.org> | 2002-05-11 04:28:20 +0000 |
commit | ad15ad16c954beaa819f3ec534b26a7866e5816a (patch) | |
tree | 41bef2050a4eb8a183c4102f7a03f284d06969e5 | |
parent | 00c628d44b96ddfebc99071005d8828611cef549 (diff) | |
download | gnome-control-center-ad15ad16c954beaa819f3ec534b26a7866e5816a.tar.gz |
2002-05-10 Seth Nickell <snickell@stanford.edu>
* .cvsignore:
* Makefile.am:
* gnome-window-properties.c: (wm_selection_changed),
(wm_widget_clear), (wm_widget_new), (wm_widget_add_wm),
(response_cb), (state_changed), (restart_label_update),
(restart_dialog_raise), (restart_dialog_destroyed),
(show_restart_dialog), (hide_restart_dialog), (update_session),
(init_session), (update_gui), (init_callback), (restart_finalize),
(restart_failure), (show_restart_info), (restart_finish),
(restart_callback), (restart), (revert_callback),
(cancel_callback), (apply_wm), (create_dialog), (main):
* gnome-window-properties.glade:
* window-capplet.png:
* window-properties.desktop.in:
* wm-exec.c: (wm_is_running), (find_gnome_wm_window),
(find_wm_window_from_client), (window_has_wm_state),
(descendent_has_wm_state), (find_wm_window_from_hunt),
(find_wm_window), (start_timeout), (start_do), (kill_timeout),
(wm_restart), (wm_guess_current):
* wm-list.c: (is_blank), (wm_compare), (wm_free),
(wm_check_present), (wm_copy), (wm_list_find), (wm_list_find_exec),
(wm_list_find_files), (wm_list_read_dir), (wm_list_init),
(wm_list_save), (wm_list_revert), (wm_list_add), (wm_list_delete),
(wm_list_set_current), (wm_list_get_current), (wm_list_get_revert),
(wm_read_from_xml), (wm_list_read_from_xml), (wm_write_to_xml),
(wm_list_write_to_xml), (xml_read_bool), (xml_write_bool):
* wm-properties.h:
-rw-r--r-- | capplets/windows/.cvsignore | 10 | ||||
-rw-r--r-- | capplets/windows/ChangeLog | 29 | ||||
-rw-r--r-- | capplets/windows/Makefile.am | 31 | ||||
-rw-r--r-- | capplets/windows/gnome-window-properties.c | 797 | ||||
-rw-r--r-- | capplets/windows/gnome-window-properties.glade | 275 | ||||
-rw-r--r-- | capplets/windows/window-capplet.png | bin | 0 -> 3047 bytes | |||
-rw-r--r-- | capplets/windows/window-properties.desktop.in | 8 | ||||
-rw-r--r-- | capplets/windows/wm-exec.c | 331 | ||||
-rw-r--r-- | capplets/windows/wm-list.c | 574 | ||||
-rw-r--r-- | capplets/windows/wm-properties.h | 63 |
10 files changed, 2118 insertions, 0 deletions
diff --git a/capplets/windows/.cvsignore b/capplets/windows/.cvsignore new file mode 100644 index 000000000..9f62da791 --- /dev/null +++ b/capplets/windows/.cvsignore @@ -0,0 +1,10 @@ +Makefile +Makefile.in +.deps +.libs +*.o +*.lo +*.la +gnome-window-properties +window-properties.desktop +*.oaf
\ No newline at end of file diff --git a/capplets/windows/ChangeLog b/capplets/windows/ChangeLog new file mode 100644 index 000000000..6ee03aaa7 --- /dev/null +++ b/capplets/windows/ChangeLog @@ -0,0 +1,29 @@ +2002-05-10 Seth Nickell <snickell@stanford.edu> + + * .cvsignore: + * Makefile.am: + * gnome-window-properties.c: (wm_selection_changed), + (wm_widget_clear), (wm_widget_new), (wm_widget_add_wm), + (response_cb), (state_changed), (restart_label_update), + (restart_dialog_raise), (restart_dialog_destroyed), + (show_restart_dialog), (hide_restart_dialog), (update_session), + (init_session), (update_gui), (init_callback), (restart_finalize), + (restart_failure), (show_restart_info), (restart_finish), + (restart_callback), (restart), (revert_callback), + (cancel_callback), (apply_wm), (create_dialog), (main): + * gnome-window-properties.glade: + * window-capplet.png: + * window-properties.desktop.in: + * wm-exec.c: (wm_is_running), (find_gnome_wm_window), + (find_wm_window_from_client), (window_has_wm_state), + (descendent_has_wm_state), (find_wm_window_from_hunt), + (find_wm_window), (start_timeout), (start_do), (kill_timeout), + (wm_restart), (wm_guess_current): + * wm-list.c: (is_blank), (wm_compare), (wm_free), + (wm_check_present), (wm_copy), (wm_list_find), (wm_list_find_exec), + (wm_list_find_files), (wm_list_read_dir), (wm_list_init), + (wm_list_save), (wm_list_revert), (wm_list_add), (wm_list_delete), + (wm_list_set_current), (wm_list_get_current), (wm_list_get_revert), + (wm_read_from_xml), (wm_list_read_from_xml), (wm_write_to_xml), + (wm_list_write_to_xml), (xml_read_bool), (xml_write_bool): + * wm-properties.h: diff --git a/capplets/windows/Makefile.am b/capplets/windows/Makefile.am new file mode 100644 index 000000000..39547b8a3 --- /dev/null +++ b/capplets/windows/Makefile.am @@ -0,0 +1,31 @@ +bin_PROGRAMS = gnome-window-properties + +gnome_window_properties_LDADD = $(GNOMECC_CAPPLETS_LIBS) +gnome_window_properties_SOURCES = \ + gnome-window-properties.c \ + wm-properties.h \ + wm-exec.c \ + wm-list.c + +@INTLTOOL_DESKTOP_RULE@ + +pixmapdir = $(GNOMECC_PIXMAPS_DIR) +pixmap_DATA = + +Gladedir = $(GNOMECC_GLADE_DIR) +Glade_DATA = gnome-window-properties.glade + +iconsdir = $(GNOMECC_ICONS_DIR) +icons_DATA = window-capplet.png + +desktop_iconsdir = $(datadir)/pixmaps +desktop_icons_DATA = window-capplet.png + +desktopdir = $(GNOMECC_DESKTOP_DIR) +Desktop_in_files = window-properties.desktop.in +desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop) + +INCLUDES = $(GNOMECC_CAPPLETS_CFLAGS) $(DESKTOP_ITEM_CFLAGS) +CLEANFILES = $(GNOMECC_CAPPLETS_CLEANFILES) +EXTRA_DIST = $(Glade_DATA) $(icons_DATA) $(Desktop_in_files) $(pixmap_DATA) + diff --git a/capplets/windows/gnome-window-properties.c b/capplets/windows/gnome-window-properties.c new file mode 100644 index 000000000..bf452c340 --- /dev/null +++ b/capplets/windows/gnome-window-properties.c @@ -0,0 +1,797 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* Copyright (C) 1998-1999 Redhat Software Inc. + * Code available under the Gnu GPL. + * Authors: Jonathan Blandford <jrb@redhat.com> + * Owen Taylor <otaylor@redhat.com> + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gconf/gconf-client.h> +#include <glade/glade.h> +#include <ctype.h> + +#include "capplet-util.h" +#include "gconf-property-editor.h" +#include "wm-properties.h" + +//#include "gnome-startup.h" + +/* prototypes */ +static void restart (gboolean force); +static void revert_callback (void); +static void cancel_callback (void); + +/* structures */ + +typedef struct { + GtkWidget *dialog; + GtkWidget *name_entry; + GtkWidget *exec_entry; + GtkWidget *config_entry; + GtkWidget *sm_toggle; +} WMDialog; + +/* vars. */ +static GtkWidget *capplet; +static GtkWidget *wm_widget; +static GtkWidget *apply_now_button; + +static WindowManager *selected_wm = NULL; + +static GtkWidget *restart_dialog = NULL; +static GtkWidget *restart_label = NULL; +guint restart_dialog_timeout; +gchar *restart_name = NULL; + +/* Time until dialog times out */ +gdouble restart_remaining_time; +gint restart_displayed_time; + +GnomeClient *client = NULL; +gchar *argv0; + +/* Enumeration describing the current state of the capplet. + * in any other state than idle, all controls are !sensitive. + */ +typedef enum { + STATE_IDLE, + STATE_TRY, + STATE_REVERT, + STATE_OK, + STATE_CANCEL, + STATE_TRY_REVERT, /* Currently trying, revert afterwards */ + STATE_TRY_CANCEL /* Currently trying, cancel afterwards */ +} StateType; + +/* The possible transitions between states are described below. + * + + * operation | try revert ok cancel finish + * ===========+================================================= + * IDLE | TRY REVERT OK CANCEL + * TRY | TRY_REVERT OK TRY_CANCEL IDLE + * REVERT | CANCEL CANCEL IDLE + * OK | (quit) + * CANCEL | (quit) + * TRY_REVERT | TRY_CANCEL TRY_CANCEL REVERT + * TRY_CANCEL | CANCEL + * + * When a restart fails, there are three cases + * + * (1) The failure was because the current window manager didn't + * die. We inform the user of the situation, and then + * abort the operation. + * + * (2) The window manager didn't start, and we don't have a + * a fallback. We pop up a error dialog, tell the user + * to start a new window manager, and abort the operation. + * + * (3) The window manager didn't start, and we previously had a + * window manager runnning. We pop up a warning dialog, + * then try to go back to the old window manager. + * + * operation | (1) (2) (3) + * ===========+================================================= + * IDLE | + * TRY | IDLE IDLE TRY + * REVERT | IDLE IDLE REVERT + * OK | (quit) (quit) OK + * CANCEL | (quit) (quit) CANCEL + * TRY_REVERT | REVERT REVERT REVERT + * TRY_CANCEL | CANCEL CANCEL CANCEL + */ + + + +/* Current state + */ +StateType state = STATE_IDLE; + +/* Set TRUE when we've exited the main loop, but restart_pending + */ +gboolean quit_pending = FALSE; + +/* Set TRUE when we're waiting for the WM to restart + */ +gboolean restart_pending = FALSE; + +/* Set TRUE while we are filling in the list + */ +gboolean in_fill = FALSE; + +static gint cap_session_init = 0; +static struct poptOption cap_options[] = { + {"init-session-settings", '\0', POPT_ARG_NONE, &cap_session_init, 0, + N_("Initialize session settings"), NULL}, + {NULL, '\0', 0, NULL, 0} +}; + +static void state_changed (void); +static void update_session (void); + +static GtkWidget *wm_menu; +static GtkWidget *option_menu; +static GList *wm_menu_window_managers; + +static void +wm_selection_changed (GtkOptionMenu *option_menu, gpointer data) +{ + int index; + WindowManager *wm; + + index = gtk_option_menu_get_history (option_menu); + wm = (WindowManager *) g_list_nth (wm_menu_window_managers, index)->data; + + if (!in_fill) { + if (wm != selected_wm) { + selected_wm = wm; + state_changed (); + } + } +} + +static void +wm_widget_clear () +{ + wm_menu_window_managers = NULL; + + wm_menu = gtk_menu_new (); + gtk_widget_show_all (wm_menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), wm_menu); +} + +GtkWidget * +wm_widget_new () +{ + option_menu = gtk_option_menu_new (); + g_signal_connect (G_OBJECT (option_menu), "changed", + wm_selection_changed, NULL); + + wm_widget_clear (); + + gtk_widget_show_all (option_menu); + return option_menu; +} + +static void +wm_widget_add_wm (WindowManager *wm, const char *row_text) +{ + GtkWidget *menu_item; + + menu_item = gtk_menu_item_new_with_label (row_text); + gtk_widget_show_all (menu_item); + + gtk_menu_shell_prepend (GTK_MENU_SHELL (wm_menu), menu_item); + wm_menu_window_managers = g_list_prepend (wm_menu_window_managers, wm); + + if (wm == selected_wm) + gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), 0); +} + +static void +response_cb (GtkDialog *dialog, gint response_id, gpointer data) +{ + switch (response_id) + { + case GTK_RESPONSE_NONE: + case GTK_RESPONSE_CLOSE: + gtk_main_quit (); + break; + } +} + +static void +state_changed (void) +{ + gtk_widget_set_sensitive (apply_now_button, TRUE); +} + +static void +restart_label_update (void) +{ + gchar *tmp; + + if ((gint)restart_remaining_time != restart_displayed_time) { + restart_displayed_time = restart_remaining_time; + + tmp = g_strdup_printf (_("Starting %s\n" + "(%d seconds left before operation times out)"), + restart_name, + restart_displayed_time); + gtk_label_set_text (GTK_LABEL (restart_label), tmp); + g_free (tmp); + } +} + +static gboolean +restart_dialog_raise (gpointer data) +{ + if (restart_dialog && GTK_WIDGET_REALIZED (restart_dialog)) { + restart_remaining_time -= 0.25; + restart_label_update(); + gdk_window_raise (restart_dialog->window); + } + return TRUE; +} + +static void +restart_dialog_destroyed (GtkWidget *widget) +{ + if (restart_dialog_timeout) { + gtk_timeout_remove (restart_dialog_timeout); + restart_dialog_timeout = 0; + } + + restart_dialog = NULL; +} + +static void +show_restart_dialog (gchar *name) +{ + GtkWidget *hbox; + GtkWidget *frame; + GtkWidget *pixmap; + gchar *tmp; + + if (!restart_dialog) { + restart_dialog = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_position (GTK_WINDOW (restart_dialog), + GTK_WIN_POS_CENTER); + + gtk_signal_connect (GTK_OBJECT (restart_dialog), "destroy", + GTK_SIGNAL_FUNC (restart_dialog_destroyed), + &restart_dialog); + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); + gtk_container_add (GTK_CONTAINER (restart_dialog), frame); + + hbox = gtk_hbox_new (FALSE, GNOME_PAD); + gtk_container_set_border_width (GTK_CONTAINER (hbox), GNOME_PAD); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + tmp = gnome_unconditional_pixmap_file("gnome-info.png"); + if (tmp) { + pixmap = gnome_pixmap_new_from_file(tmp); + g_free(tmp); + gtk_box_pack_start (GTK_BOX (hbox), pixmap, FALSE, FALSE, 0); + } + + restart_label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (hbox), restart_label, FALSE, FALSE, GNOME_PAD); + } + + if (!restart_dialog_timeout) { + restart_dialog_timeout = gtk_timeout_add (250, restart_dialog_raise, NULL); + } + + restart_remaining_time = 10.0; + restart_displayed_time = -1; + if (restart_name) + g_free (restart_name); + + restart_name = g_strdup (name); + restart_label_update (); + + gtk_widget_show_all (restart_dialog); +} + +static void +hide_restart_dialog (void) +{ + if (restart_dialog) + gtk_widget_destroy (restart_dialog); +} + +static void +update_session (void) +{ + WindowManager *current_wm = wm_list_get_current(); + gchar *session_args[3]; + + if (!current_wm) + return; + + if (current_wm->session_managed) { + gnome_client_set_restart_style (client, + GNOME_RESTART_NEVER); + + } else { + session_args[0] = argv0; + session_args[1] = "--init-session-settings"; + session_args[2] = NULL; + /* We use a priority of 15 so that we start after + * session-managed WM's (priority 10), for safety. + */ + gnome_client_set_priority (client, 15); + gnome_client_set_restart_style (client, + GNOME_RESTART_ANYWAY); + gnome_client_set_restart_command (client, 2, + session_args); + } + + gnome_client_flush (client); +} + +static void +init_session (void) +{ + GnomeClientFlags flags; + gint token; + + return; + + client = gnome_master_client (); + flags = gnome_client_get_flags (client); + + if (flags & GNOME_CLIENT_IS_CONNECTED) { + /*token = gnome_startup_acquire_token("GNOME_WM_PROPERTIES", + gnome_client_get_id(client));*/ + + if (token) + update_session(); + else { + gnome_client_set_restart_style (client, + GNOME_RESTART_NEVER); + gnome_client_flush (client); + } + } +} + +static void +update_gui (void) +{ + GList *tmp_list; + + wm_widget_clear (); + + in_fill = TRUE; + + tmp_list = window_managers; + while (tmp_list) { + gchar *row_text; + WindowManager *wm; + + wm = tmp_list->data; + + if (wm->is_user && !wm->is_present) { + row_text = g_strconcat (gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_NAME), + _(" (Not found)"), NULL); + } else { + row_text = g_strdup (gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_NAME)); + } + + wm_widget_add_wm (wm, row_text); + + g_free (row_text); + + tmp_list = tmp_list->next; + } + + in_fill = FALSE; + +} + +static void +init_callback (WMResult result, gpointer data) +{ + switch (result) { + case WM_SUCCESS: + break; + case WM_ALREADY_RUNNING: + g_warning (_("wm-properties-capplet: Unable to initialize window manager.\n" + "\tAnother window manager is already running and could not be killed\n")); + break; + case WM_CANT_START: + g_warning (_("wm-properties-capplet: Unable to initialize window manager.\n" + "\t'%s' didn't start\n"), (gchar *)data); + break; + } + + g_free (data); + gtk_main_quit (); +} + +static void +restart_finalize () +{ + wm_list_set_current (selected_wm); + hide_restart_dialog(); + + switch (state) { + case STATE_TRY: + case STATE_REVERT: + gtk_widget_set_sensitive (capplet, TRUE); + update_gui(); + state = STATE_IDLE; + break; + + case STATE_OK: + case STATE_CANCEL: + if (quit_pending) + gtk_main_quit(); + break; + default: + g_warning ("Finalize in state %d!!!\n", state); + return; + } + + restart_pending = FALSE; +} + +static void +restart_failure (WMResult reason) +{ + GtkWidget *msgbox; + WindowManager *current_wm; + gchar *msg = NULL; + gboolean modal = FALSE; + + current_wm = wm_list_get_current (); + + /* Did the previous window manager not die? + */ + if (reason == WM_ALREADY_RUNNING) { + msg = g_strdup (_("Previous window manager did not die\n")); + + switch (state) { + case STATE_TRY: + case STATE_REVERT: + case STATE_OK: + case STATE_CANCEL: + selected_wm = current_wm; + restart_finalize (); + break; + + case STATE_TRY_REVERT: + revert_callback (); + break; + + case STATE_TRY_CANCEL: + cancel_callback (); + break; + + default: + g_warning ("Failure in state %d!!!\n", state); + return; + } + } + /* Is there something reasonable to try to fall back to? + */ + else if (current_wm != selected_wm) { + + switch (state) { + case STATE_TRY: + case STATE_REVERT: + case STATE_OK: + case STATE_CANCEL: + msg = g_strdup_printf (_("Could not start '%s'.\n" + "Falling back to previous window manager '%s'\n"), + selected_wm?gnome_desktop_item_get_string (selected_wm->dentry, GNOME_DESKTOP_ITEM_NAME):"Unknown", + current_wm?gnome_desktop_item_get_string (current_wm->dentry, GNOME_DESKTOP_ITEM_NAME):"Unknown"); + selected_wm = current_wm; + restart(TRUE); + break; + + case STATE_TRY_REVERT: + revert_callback (); + break; + + case STATE_TRY_CANCEL: + cancel_callback (); + break; + + default: + g_warning ("Failure in state %d!!!\n", state); + return; + } + + /* Give up */ + } else { + + switch (state) { + case STATE_OK: + case STATE_CANCEL: + modal = TRUE; /* prevent an immediate exit */ + /* Fall through */ + case STATE_TRY: + case STATE_REVERT: + msg = g_strdup (_("Could not start fallback window manager.\n" + "Please run a window manager manually. You can\n" + "do this by selecting \"Run Program\" in the\n" + "foot menu\n")); + + restart_finalize(); + break; + + case STATE_TRY_REVERT: + revert_callback (); + break; + + case STATE_TRY_CANCEL: + cancel_callback (); + break; + + default: + g_warning ("Failure in state %d!!!\n", state); + return; + } + } + + if (msg) { + msgbox = gnome_message_box_new (msg, + GNOME_MESSAGE_BOX_ERROR, + _("OK"), NULL); + if (modal) + gnome_dialog_run (GNOME_DIALOG (msgbox)); + else + gtk_widget_show (msgbox); + g_free (msg); + } +} + +static void +show_restart_info (void) +{ + gchar *save_session; + + save_session = gnome_is_program_in_path ("save-session"); + + if (save_session != NULL) { + system (save_session); + } + + g_free (save_session); +} + +static void +restart_finish (void) +{ + switch (state) { + case STATE_TRY: + case STATE_REVERT: + case STATE_OK: + case STATE_CANCEL: + hide_restart_dialog(); + show_restart_info (); + restart_finalize(); + break; + + case STATE_TRY_REVERT: + revert_callback (); + break; + + case STATE_TRY_CANCEL: + cancel_callback (); + break; + + default: + g_warning ("Finished in state %d!!!\n", state); + return; + } +} + +static void +restart_callback (WMResult result, gpointer data) +{ + if (result == WM_SUCCESS) + restart_finish (); + else + restart_failure (result); +} + +static void +restart (gboolean force) +{ + WindowManager *current_wm = wm_list_get_current(), *mywm; + static gboolean last_try_was_twm = FALSE; + GnomeDesktopItem *twm_dentry = gnome_desktop_item_new (); + WindowManager twm_fallback = {twm_dentry, "twm", "twm", 0, 0, 1, 0}; + + gnome_desktop_item_set_entry_type (twm_dentry, GNOME_DESKTOP_ITEM_TYPE_APPLICATION); + gnome_desktop_item_set_string (twm_dentry, + GNOME_DESKTOP_ITEM_NAME, "twm"); + gnome_desktop_item_set_string (twm_dentry, + GNOME_DESKTOP_ITEM_COMMENT, "twm"); + gnome_desktop_item_set_string (twm_dentry, + GNOME_DESKTOP_ITEM_EXEC, "twm"); + + if(selected_wm) { + last_try_was_twm = FALSE; + mywm = selected_wm; + } else if(!last_try_was_twm) { + last_try_was_twm = TRUE; + mywm = (WindowManager*)&twm_fallback; + } else { + restart_finalize(); + gnome_desktop_item_unref (twm_dentry); + return; + } + + if (force || current_wm != mywm) { + show_restart_dialog (g_strdup (gnome_desktop_item_get_string (mywm->dentry, GNOME_DESKTOP_ITEM_NAME))); + if (state != STATE_OK && state != STATE_CANCEL) + gtk_widget_set_sensitive (capplet, FALSE); + restart_pending = TRUE; + wm_restart (mywm, + capplet->window, + restart_callback, + NULL); + } else { + restart_finalize (); + } + + gnome_desktop_item_unref (twm_dentry); +} + +static void +revert_callback (void) +{ + StateType old_state = state; + + switch (state) { + case STATE_IDLE: + case STATE_TRY_REVERT: + wm_list_revert(); + selected_wm = wm_list_get_revert(); + state = STATE_REVERT; + + restart (old_state == STATE_TRY_REVERT); + update_gui(); + + break; + + case STATE_TRY: + state = STATE_TRY_REVERT; + break; + + default: + g_warning ("revert callback in state %d!!!\n", state); + return; + } +} + +static void +cancel_callback (void) +{ + StateType old_state = state; + + switch (state) { + case STATE_IDLE: + case STATE_TRY_CANCEL: + wm_list_revert(); + selected_wm = wm_list_get_revert(); + state = STATE_CANCEL; + + restart (old_state == STATE_TRY_CANCEL); + + break; + + case STATE_TRY: + state = STATE_TRY_CANCEL; + break; + + case STATE_REVERT: + state = STATE_CANCEL; + break; + + case STATE_TRY_REVERT: + state = STATE_TRY_CANCEL; + break; + + default: + g_warning ("ok callback in state %d!!!\n", state); + return; + } +} + +static void +apply_wm (GObject *object, gpointer data) +{ + state = STATE_TRY; + restart(FALSE); + wm_list_set_current (selected_wm); + wm_list_save (); + update_session (); +} + +static GladeXML * +create_dialog (void) +{ + GladeXML *dialog; + + dialog = glade_xml_new (GNOMECC_DATA_DIR "/interfaces/gnome-window-properties.glade", "prefs_widget", NULL); + + apply_now_button = WID ("apply_now_button"); + gtk_widget_set_sensitive (apply_now_button, FALSE); + g_signal_connect (G_OBJECT (apply_now_button), "clicked", apply_wm, NULL); + + wm_widget = wm_widget_new (); + + gtk_box_pack_start (GTK_BOX (WID ("wm_widget_box")), wm_widget, TRUE, TRUE, 0); + + update_gui(); + + return dialog; +} + +int +main (int argc, char **argv) +{ + GladeXML *dialog; + GtkWidget *dialog_win; + + bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE); + + argv0 = g_strdup (argv[0]); + gnome_program_init ("wm-properties", VERSION, + LIBGNOMEUI_MODULE, argc, argv, + GNOME_PARAM_POPT_TABLE, &cap_options, + NULL); + + /* Read in the list of window managers, and the current + * window manager + */ + wm_list_init(); + selected_wm = wm_list_get_current(); + + if (!cap_session_init) + { + init_session(); + dialog = create_dialog (); + + dialog_win = gtk_dialog_new_with_buttons + (_("Window Preferences"), NULL, -1, + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, + NULL); + g_signal_connect (G_OBJECT (dialog_win), "response", response_cb, NULL); + + capplet = dialog_win; + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_win)->vbox), WID ("prefs_widget"), TRUE, TRUE, GNOME_PAD_SMALL); + gtk_widget_show_all (dialog_win); + + gtk_main (); + + if (restart_pending) { + quit_pending = TRUE; + gtk_main(); + } + } + else { + if (selected_wm && + !selected_wm->session_managed && + !wm_is_running()) { + + wm_restart (selected_wm, NULL, init_callback, + g_strdup (gnome_desktop_item_get_string (selected_wm->dentry, GNOME_DESKTOP_ITEM_NAME))); + gtk_main (); + } + + init_session(); + } + + return 0; +} diff --git a/capplets/windows/gnome-window-properties.glade b/capplets/windows/gnome-window-properties.glade new file mode 100644 index 000000000..1cdf7fd7a --- /dev/null +++ b/capplets/windows/gnome-window-properties.glade @@ -0,0 +1,275 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> + +<widget class="GtkWindow" id="window1"> + <property name="visible">True</property> + <property name="title" translatable="yes">Window Properties</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + + <child> + <widget class="GtkVBox" id="prefs_widget"> + <property name="border_width">10</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes">Window Manager:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="wm_widget_box"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="apply_now_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Apply Now</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator1"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">10</property> + + <child> + <widget class="GtkHBox" id="hbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkFrame" id="frame2"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <widget class="GtkOptionMenu" id="optionmenu2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">-1</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame3"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <widget class="GtkOptionMenu" id="optionmenu3"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">-1</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame4"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <widget class="GtkOptionMenu" id="optionmenu4"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="history">-1</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="checkbutton1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Select windows when the mouse moves over them</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/capplets/windows/window-capplet.png b/capplets/windows/window-capplet.png Binary files differnew file mode 100644 index 000000000..c085f67ac --- /dev/null +++ b/capplets/windows/window-capplet.png diff --git a/capplets/windows/window-properties.desktop.in b/capplets/windows/window-properties.desktop.in new file mode 100644 index 000000000..51293f59e --- /dev/null +++ b/capplets/windows/window-properties.desktop.in @@ -0,0 +1,8 @@ +[Desktop Entry] +_Name=Mouse +_Comment=Window Properties +Exec=gnome2-window-properties +Icon=window-capplet.png +Terminal=0 +Type=Application +Categories=Application;Settings;
\ No newline at end of file diff --git a/capplets/windows/wm-exec.c b/capplets/windows/wm-exec.c new file mode 100644 index 000000000..f8d9356bf --- /dev/null +++ b/capplets/windows/wm-exec.c @@ -0,0 +1,331 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* Copyright (C) 1998 Redhat Software Inc. + * Code available under the Gnu GPL. + * Authors: Owen Taylor <otaylor@redhat.com> + */ + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <libgnome/libgnome.h> +#include "wm-properties.h" + +typedef struct _RestartInfo RestartInfo; + +struct _RestartInfo { + GnomeDesktopItem *dentry; + gint retries; + WMResultFunc callback; + gpointer data; +}; + +gboolean +wm_is_running (void) +{ + gboolean result; + guint old_mask; + XWindowAttributes attrs; + + gdk_error_trap_push (); + + XGetWindowAttributes (GDK_DISPLAY(), GDK_ROOT_WINDOW(), &attrs); + + XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), + SubstructureRedirectMask); + XSync (GDK_DISPLAY(), False); + if (gdk_error_trap_pop () == 0) { + result = FALSE; + XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), + attrs.your_event_mask); + } else + result = TRUE; + + + return result; +} + +/* Cut and paste from gnome-libs/gnome_win_hints_wm_exists, except that we + * return the xid instead of a window + */ +static Window +find_gnome_wm_window(void) +{ + Atom r_type; + int r_format; + unsigned long count; + unsigned long bytes_remain; + unsigned char *prop, *prop2; + GdkAtom cardinal_atom = gdk_atom_intern ("CARDINAL", FALSE); + + gdk_error_trap_push (); + if (XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + gdk_x11_atom_to_xatom (gdk_atom_intern ("_WIN_SUPPORTING_WM_CHECK", FALSE)), + 0, 1, False, gdk_x11_atom_to_xatom (cardinal_atom), + &r_type, &r_format, + &count, &bytes_remain, &prop) == Success && prop) + { + if (r_type == gdk_x11_atom_to_xatom (cardinal_atom) && r_format == 32 && count == 1) + { + Window n = *(long *)prop; + if (XGetWindowProperty(GDK_DISPLAY(), n, + gdk_x11_atom_to_xatom (gdk_atom_intern ("_WIN_SUPPORTING_WM_CHECK", FALSE)), + 0, 1, False, gdk_x11_atom_to_xatom (cardinal_atom), + &r_type, &r_format, &count, &bytes_remain, + &prop2) == Success && prop) + { + if (r_type == gdk_x11_atom_to_xatom (cardinal_atom) && r_format == 32 && count == 1) + { + XFree(prop); + XFree(prop2); + gdk_error_trap_pop (); + return n; + } + XFree(prop2); + } + } + XFree(prop); + } + gdk_error_trap_pop (); + return None; +} + +static Window +find_wm_window_from_client (GdkWindow *client) +{ + Window window, frame, parent, root; + Window *children; + unsigned int nchildren; + gboolean needs_pop = TRUE; + + if (!client) + return None; + + frame = None; + window = GDK_WINDOW_XWINDOW (client); + + gdk_error_trap_push (); + + while (XQueryTree (GDK_DISPLAY(), window, + &root, &parent, &children, &nchildren)) + { + if (gdk_error_trap_pop != 0) + { + needs_pop = FALSE; + break; + } + + gdk_error_trap_push (); + + if (children) + XFree(children); + + if (window == root) + break; + + if (root == parent) { + frame = window; + break; + } + window = parent; + } + + if (needs_pop) + gdk_error_trap_pop (); + + return frame; +} + +static gboolean +window_has_wm_state (Window window) +{ + Atom r_type; + int r_format; + unsigned long count; + unsigned long bytes_remain; + unsigned char *prop; + + if (XGetWindowProperty(GDK_DISPLAY(), window, + gdk_x11_atom_to_xatom (gdk_atom_intern ("WM_STATE", FALSE)), + 0, 0, False, AnyPropertyType, + &r_type, &r_format, + &count, &bytes_remain, &prop) == Success) { + + if (r_type != None) { + XFree(prop); + return TRUE; + } + } + return FALSE; +} + +static gboolean +descendent_has_wm_state (Window window) +{ + gboolean result = FALSE; + Window parent, root; + Window *children; + unsigned int nchildren; + gint i; + + if (!XQueryTree (GDK_DISPLAY(), window, + &root, &parent, &children, &nchildren)) + return FALSE; + + for (i=0; i<nchildren; i++) { + if (window_has_wm_state (children[i]) || + descendent_has_wm_state (children[i])) { + result = TRUE; + break; + } + } + + if (children) + XFree (children); + + return result; +} + +/* This function tries to find a window manager frame by + * hunting all the children of the root window + */ +static Window +find_wm_window_from_hunt (void) +{ + Window parent, root, frame; + Window *children; + unsigned int nchildren; + gint i; + + frame = None; + + gdk_error_trap_push (); + + XQueryTree (GDK_DISPLAY(), GDK_ROOT_WINDOW (), + &root, &parent, &children, &nchildren); + + /* We are looking for a window that doesn't have WIN_STATE + * set on it, but does have a child with WIN_STATE set + */ + for (i=0; i<nchildren; i++) { + if (!window_has_wm_state (children[i]) && + descendent_has_wm_state (children[i])) { + frame = children[i]; + break; + } + } + + if (children) + XFree (children); + + gdk_error_trap_pop (); + + return frame; +} + +static Window +find_wm_window (GdkWindow *client) +{ + Window wm_window = None; + + /* First, try to find a GNOME compliant WM */ + + wm_window = find_gnome_wm_window(); + + if (!wm_window) { + wm_window = find_wm_window_from_client (client); + } + + if (!wm_window) { + wm_window = find_wm_window_from_hunt (); + } + + return wm_window; +} + +static gboolean +start_timeout (gpointer data) +{ + RestartInfo *info = data; + if (wm_is_running ()) { + info->callback(WM_SUCCESS, info->data); + gnome_desktop_item_unref (info->dentry); + g_free (info); + return FALSE; + } else { + info->retries--; + if (info->retries > 0) + return TRUE; + else { + info->callback(WM_CANT_START, info->data); + gnome_desktop_item_unref (info->dentry); + g_free (info); + return FALSE; + } + } +} + +static void +start_do (RestartInfo *info) +{ + gnome_desktop_item_launch (info->dentry, 0, 0, NULL); + + info->retries = 10; + gtk_timeout_add (1000, start_timeout, info); +} + +static gboolean +kill_timeout (gpointer data) +{ + RestartInfo *info = data; + if (!wm_is_running ()) { + start_do (info); + return FALSE; + } else { + info->retries--; + if (info->retries > 0) + return TRUE; + else { + info->callback(WM_ALREADY_RUNNING, info->data); + gnome_desktop_item_unref (info->dentry); + g_free (info); + return FALSE; + } + } +} + +void +wm_restart (WindowManager *new, + GdkWindow *client, + WMResultFunc callback, + gpointer data) +{ + Window wm_window; + RestartInfo *info; + + g_return_if_fail (new->is_present); + + info = g_new (RestartInfo, 1); + info->dentry = gnome_desktop_item_copy (new->dentry); + info->callback = callback; + info->data = data; + info->retries = 10; + + if (wm_is_running ()) { + wm_window = find_wm_window (client); + if (!wm_window) { + (*callback) (WM_ALREADY_RUNNING, data); + gnome_desktop_item_unref (info->dentry); + g_free (info); + } else { + XKillClient (GDK_DISPLAY(), wm_window); + gtk_timeout_add (1000, kill_timeout, info); + } + } else { + start_do (info); + } +} + +WindowManager * +wm_guess_current (void) +{ + return NULL; +} diff --git a/capplets/windows/wm-list.c b/capplets/windows/wm-list.c new file mode 100644 index 000000000..022971359 --- /dev/null +++ b/capplets/windows/wm-list.c @@ -0,0 +1,574 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* Copyright (C) 1998 Redhat Software Inc. + * Code available under the Gnu GPL. + * Authors: Owen Taylor <otaylor@redhat.com>, + * Bradford Hovinen <hovinen@helixcode.com> + */ + +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include <ctype.h> +#include <libgnome/libgnome.h> +#include <gconf/gconf-client.h> +#include "wm-properties.h" + +#define CONFIG_PREFIX "/desktop/gnome/applications/window_manager" + +/* Current list of window managers */ +GList *window_managers = NULL; + +/* List on startup */ +static GList *window_managers_save = NULL; + +/* Current window manager */ +static WindowManager *current_wm = NULL; + +/* Window manager on startup */ +static WindowManager *current_wm_save = NULL; + +static gboolean xml_read_bool (xmlNodePtr node); +static xmlNodePtr xml_write_bool (gchar *name, + gboolean value); + +gboolean +is_blank (gchar *str) +{ + while (*str) { + if (!isspace(*str)) + return FALSE; + str++; + } + return TRUE; +} + +static gint +wm_compare (gconstpointer a, gconstpointer b) +{ + const WindowManager *wm_a = (const WindowManager *)a; + const WindowManager *wm_b = (const WindowManager *)b; + + return g_strcasecmp (gnome_desktop_item_get_string (wm_a->dentry, GNOME_DESKTOP_ITEM_NAME), gnome_desktop_item_get_string (wm_b->dentry, GNOME_DESKTOP_ITEM_NAME)); +} + +static void +wm_free (WindowManager *wm) +{ + gnome_desktop_item_unref (wm->dentry); + g_free (wm->config_exec); + g_free (wm->config_tryexec);; + g_free (wm); +} + +void +wm_check_present (WindowManager *wm) +{ + gchar *path; + + if (gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_EXEC)) { + if (gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_TRY_EXEC)) { + path = gnome_is_program_in_path (gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_TRY_EXEC)); + wm->is_present = (path != NULL); + if (path) + g_free (path); + } else + wm->is_present = TRUE; + } else + wm->is_present = FALSE; + + if (wm->config_exec) { + if (wm->config_tryexec) { + path = gnome_is_program_in_path (wm->config_tryexec); + wm->is_config_present = (path != NULL); + if (path) + g_free (path); + } else { + path = gnome_is_program_in_path (wm->config_exec); + wm->is_config_present = (path != NULL); + if (path) + g_free (path); + } + } else + wm->is_config_present = FALSE; + +} + +static WindowManager * +wm_copy (WindowManager *wm) +{ + WindowManager *result = g_new (WindowManager, 1); + + result->dentry = gnome_desktop_item_copy (wm->dentry); + result->config_exec = g_strdup (wm->config_exec); + result->config_tryexec = g_strdup (wm->config_tryexec); + + result->session_managed = wm->session_managed; + result->is_user = wm->is_user; + result->is_present = wm->is_present; + result->is_config_present = wm->is_config_present; + + return result; +} + + +static WindowManager * +wm_list_find (GList *list, gchar *name) +{ + GList *tmp_list = list; + while (tmp_list) { + WindowManager *wm = tmp_list->data; + if (strcmp (gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_EXEC), name) == 0) + return wm; + + tmp_list = tmp_list->next; + } + + return NULL; +} + +static WindowManager * +wm_list_find_exec (GList *list, gchar *name) +{ + GList *tmp_list = list; + while (tmp_list) { + WindowManager *wm = tmp_list->data; + if (!gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_EXEC)) + continue; + if (strcmp (gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_EXEC), name) == 0) + return wm; + + tmp_list = tmp_list->next; + } + + return NULL; +} + +static GList * +wm_list_find_files (gchar *directory) +{ + DIR *dir; + struct dirent *child; + GList *result = NULL; + gchar *suffix; + + dir = opendir (directory); + if (dir == NULL) + return NULL; + + while ((child = readdir (dir)) != NULL) { + /* Ignore files without .desktop suffix, and ignore + * .desktop files with no prefix + */ + suffix = child->d_name + strlen (child->d_name) - 8; + /* strlen(".desktop") == 8 */ + + if (suffix <= child->d_name || + strcmp (suffix, ".desktop") != 0) + continue; + + result = g_list_prepend (result, + g_concat_dir_and_file (directory, + child->d_name)); + } + closedir (dir); + + return result; +} + +static void +wm_list_read_dir (gchar *directory, gboolean is_user) +{ + WindowManager *wm; + GList *tmp_list; + GList *files; + gchar *prefix; + + files = wm_list_find_files (directory); + + tmp_list = files; + while (tmp_list) { + wm = g_new (WindowManager, 1); + + wm->dentry = gnome_desktop_item_new_from_file (tmp_list->data, GNOME_DESKTOP_ITEM_TYPE_APPLICATION, NULL); + gnome_desktop_item_set_entry_type (wm->dentry, GNOME_DESKTOP_ITEM_TYPE_APPLICATION); + + if (!wm->dentry) { + g_free (wm); + tmp_list = tmp_list->next; + continue; + } + + prefix = g_strconcat ("=", gnome_desktop_item_get_location (wm->dentry), "=/Window Manager/", NULL); + gnome_config_push_prefix (prefix); + g_free (prefix); + + wm->config_exec = gnome_config_get_string ("ConfigExec"); + wm->config_tryexec = gnome_config_get_string ("ConfigTryExec"); + wm->session_managed = gnome_config_get_bool ("SessionManaged=0"); + wm->is_user = is_user; + + if (wm->config_exec && is_blank (wm->config_exec)) { + g_free (wm->config_exec); + wm->config_exec = NULL; + } + + if (wm->config_tryexec && is_blank (wm->config_tryexec)) { + g_free (wm->config_tryexec); + wm->config_tryexec = NULL; + } + + gnome_config_pop_prefix (); + + wm_check_present (wm); + + if (gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_NAME) && gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_EXEC) && + (wm->is_user || wm->is_present)) { + window_managers = + g_list_insert_sorted (window_managers, + wm, + wm_compare); + window_managers_save = + g_list_insert_sorted (window_managers_save, + wm_copy (wm), + wm_compare); + } else { + wm_free (wm); + } + + + tmp_list = tmp_list->next; + } + g_list_free (files); +} + +void +wm_list_init (void) +{ + gchar *tempdir; + gchar *name; + GConfClient *client; + + tempdir = gnome_unconditional_datadir_file ("gnome/wm-properties/"); + wm_list_read_dir (tempdir, FALSE); + g_free (tempdir); + + tempdir = gnome_util_home_file("wm-properties/"); + wm_list_read_dir (tempdir, TRUE); + g_free (tempdir); + + client = gconf_client_get_default (); + name = gconf_client_get_string (client, CONFIG_PREFIX "/current", NULL); + if (name) { + current_wm = wm_list_find (window_managers, name); + g_free (name); + } + + if (!current_wm) { + name = gconf_client_get_string (client, CONFIG_PREFIX "/default", NULL); + + if (name) { + current_wm = wm_list_find_exec (window_managers, name); + g_free (name); + } + } + + if (!current_wm) { + gchar *wmfile, *prefix; + + wmfile = gnome_unconditional_datadir_file ("default.wm"); + prefix = g_strconcat ("=", wmfile, "=/Default/WM", NULL); + name = gnome_config_get_string (prefix); + + g_free (wmfile); + g_free (prefix); + + if (name) { + current_wm = wm_list_find_exec (window_managers, name); + g_free (name); + } + } + + if (!current_wm && window_managers) + current_wm = window_managers->data; + + if(current_wm) + current_wm_save = wm_list_find (window_managers_save, gnome_desktop_item_get_string (current_wm->dentry, GNOME_DESKTOP_ITEM_NAME)); + + g_object_unref (G_OBJECT (client)); +} + +void +wm_list_save (void) +{ + GList *old_files; + GList *tmp_list; + gchar *tempdir; + gchar *prefix; + WindowManager *wm; + + /* Clean out the current contents of .gnome/wm-desktops + */ + + tempdir = gnome_util_home_file("wm-properties/"); + old_files = wm_list_find_files (tempdir); + g_free (tempdir); + + tmp_list = old_files; + while (tmp_list) { + prefix = g_strconcat ("=", tmp_list->data, "=", NULL); + gnome_config_clean_file (prefix); + gnome_config_sync_file (prefix); + g_free (prefix); + + tmp_list = tmp_list->next; + } + g_list_free (old_files); + + + /* Save the user's desktops + */ + + tmp_list = window_managers; + while (tmp_list) { + wm = tmp_list->data; + + if (wm->is_user) { + gnome_desktop_item_save (wm->dentry, NULL, TRUE, NULL); + + prefix = g_strconcat ("=", gnome_desktop_item_get_location (wm->dentry), "=/Window Manager/", NULL); + gnome_config_push_prefix (prefix); + g_free (prefix); + + if (wm->config_exec) + gnome_config_set_string ("ConfigExec", wm->config_exec); + if (wm->config_tryexec) + gnome_config_set_string ("ConfigTryExec", wm->config_tryexec); + gnome_config_set_bool ("SessionManaged=0", wm->session_managed); + gnome_config_pop_prefix (); + + } + tmp_list = tmp_list->next; + } + + /* Save the current window manager + */ + if(current_wm) + { + GConfClient *client = gconf_client_get_default (); + gconf_client_set_string (client, CONFIG_PREFIX "/current", + gnome_desktop_item_get_string (current_wm->dentry, GNOME_DESKTOP_ITEM_EXEC), + NULL); + g_object_unref (G_OBJECT (client)); + } + + gnome_config_sync (); +} + +void +wm_list_revert (void) +{ + GList *tmp_list; + gchar *old_name = NULL; + + if(current_wm) + old_name = g_strdup (gnome_desktop_item_get_string (current_wm->dentry, GNOME_DESKTOP_ITEM_NAME)); + + g_list_foreach (window_managers, (GFunc)wm_free, NULL); + g_list_free (window_managers); + window_managers = NULL; + + tmp_list = window_managers_save; + while (tmp_list) { + window_managers = g_list_prepend (window_managers, + wm_copy (tmp_list->data)); + tmp_list = tmp_list->next; + } + window_managers = g_list_reverse (window_managers); + current_wm = wm_list_find (window_managers, old_name); + g_free (old_name); +} + +void +wm_list_add (WindowManager *wm) +{ + g_return_if_fail (wm != NULL); + + window_managers = g_list_insert_sorted (window_managers, wm, + wm_compare); +} + +void +wm_list_delete (WindowManager *wm) +{ + GList *node; + + g_return_if_fail (wm != NULL); + g_return_if_fail (wm != current_wm); + + node = g_list_find (window_managers, wm); + g_return_if_fail (node != NULL); + + window_managers = g_list_remove_link (window_managers, node); + g_list_free_1 (node); + wm_free (wm); +} + +void +wm_list_set_current (WindowManager *wm) +{ + current_wm = wm; +} + +WindowManager * +wm_list_get_current (void) +{ + return current_wm; +} + +WindowManager * +wm_list_get_revert (void) +{ + if(current_wm_save) + return wm_list_find (window_managers, gnome_desktop_item_get_string (current_wm_save->dentry, GNOME_DESKTOP_ITEM_NAME)); + else + return NULL; +} + +static WindowManager * +wm_read_from_xml (xmlNodePtr wm_node) +{ + xmlNodePtr node; + WindowManager *wm; + gboolean is_current = FALSE; + + if (strcmp (wm_node->name, "window-manager")) return NULL; + + wm = g_new0 (WindowManager, 1); + + wm->dentry = gnome_desktop_item_new_from_file + (xmlGetProp (wm_node, "desktop-entry"), + GNOME_DESKTOP_ITEM_TYPE_APPLICATION, NULL); + gnome_desktop_item_set_entry_type (wm->dentry, GNOME_DESKTOP_ITEM_TYPE_APPLICATION); + + for (node = wm_node->children; node; node = node->next) { + if (!strcmp (node->name, "config-exec")) + wm->config_exec = xmlNodeGetContent (node); + else if (!strcmp (node->name, "config-tryexec")) + wm->config_tryexec = xmlNodeGetContent (node); + else if (!strcmp (node->name, "session-managed")) + wm->session_managed = xml_read_bool (node); + else if (!strcmp (node->name, "is-user")) + wm->is_user = xml_read_bool (node); + else if (!strcmp (node->name, "is-current")) + is_current = xml_read_bool (node); /* FIXME: sanity check */ + } + + wm_check_present (wm); + + if (wm->dentry == NULL || + (wm->config_exec != NULL && is_blank (wm->config_exec)) || + gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_NAME) == NULL || gnome_desktop_item_get_string (wm->dentry, GNOME_DESKTOP_ITEM_EXEC) == NULL || + !(wm->is_user || wm->is_present)) + { + g_free (wm); + return NULL; + } + + if (is_current) current_wm = wm; + + return wm; +} + +void +wm_list_read_from_xml (xmlDocPtr doc) +{ + xmlNodePtr root_node, node; + WindowManager *wm; + + root_node = xmlDocGetRootElement (doc); + if (strcmp (root_node->name, "wm-prefs")) return; + + for (node = root_node; node; node = node->next) { + if (!strcmp (node->name, "window-manager")) { + wm = wm_read_from_xml (node); + if (wm) window_managers = + g_list_insert_sorted + (window_managers, wm, wm_compare); + } + } +} + +static xmlNodePtr +wm_write_to_xml (WindowManager *wm) +{ + xmlNodePtr node; + + node = xmlNewNode (NULL, "window-manager"); + + xmlNewProp (node, "desktop-entry", gnome_desktop_item_get_location (wm->dentry)); + + if (wm->config_exec != NULL) + xmlNewChild (node, NULL, "config-exec", wm->config_exec); + + xmlAddChild (node, xml_write_bool ("session-managed", + wm->session_managed)); + + xmlAddChild (node, xml_write_bool ("is-user", wm->is_user)); + xmlAddChild (node, xml_write_bool ("is-current", wm == current_wm)); + + return node; +} + +xmlDocPtr +wm_list_write_to_xml (void) +{ + xmlDocPtr doc; + xmlNodePtr root_node, node; + GList *wm_node; + + doc = xmlNewDoc ("1.0"); + root_node = xmlNewDocNode (doc, NULL, "wm-prefs", NULL); + + for (wm_node = window_managers; wm_node; wm_node = wm_node->next) { + node = wm_write_to_xml ((WindowManager *) wm_node->data); + if (node) xmlAddChild (root_node, node); + } + + xmlDocSetRootElement (doc, root_node); + + return doc; +} + +/* Read a boolean value from a node */ + +static gboolean +xml_read_bool (xmlNodePtr node) +{ + char *text; + + text = xmlNodeGetContent (node); + + if (!g_strcasecmp (text, "true")) + return TRUE; + else + return FALSE; +} + +/* Write out a boolean value in a node */ + +static xmlNodePtr +xml_write_bool (gchar *name, gboolean value) +{ + xmlNodePtr node; + + g_return_val_if_fail (name != NULL, NULL); + + node = xmlNewNode (NULL, name); + + if (value) + xmlNodeSetContent (node, "true"); + else + xmlNodeSetContent (node, "false"); + + return node; +} diff --git a/capplets/windows/wm-properties.h b/capplets/windows/wm-properties.h new file mode 100644 index 000000000..f14dc4ea5 --- /dev/null +++ b/capplets/windows/wm-properties.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/* Copyright (C) 1998 Redhat Software Inc. + * Code available under the Gnu GPL. + * Authors: Owen Taylor <otaylor@redhat.com>, + * Bradford Hovinen <hovinen@helixcode.com> + */ + +#include <gdk/gdk.h> +#include <libgnome/libgnome.h> +#include <libgnome/gnome-desktop-item.h> + +#include <libxml/tree.h> + +typedef struct _WindowManager WindowManager; + +struct _WindowManager { + GnomeDesktopItem *dentry; + gchar *config_exec; + gchar *config_tryexec; + gboolean session_managed : 1; + gboolean is_user : 1; + gboolean is_present : 1; + gboolean is_config_present : 1; +}; + +/* Utility functions */ +gboolean is_blank (gchar *str); + +/* Fill in the is_present and is_config_present fields */ +void wm_check_present (WindowManager *wm); + +/* Management of window manager list */ + +void wm_list_init (void); +void wm_list_save (void); +void wm_list_revert (void); +void wm_list_add (WindowManager *window_manager); +void wm_list_delete (WindowManager *window_manager); +void wm_list_set_current (WindowManager *window_manager); +WindowManager *wm_list_get_current (void); +WindowManager *wm_list_get_revert (void); + +void wm_list_read_from_xml (xmlDocPtr doc); +xmlDocPtr wm_list_write_to_xml (void); + +extern GList *window_managers; + +/* Management of current window manager */ + +typedef enum { + WM_SUCCESS, + WM_ALREADY_RUNNING, + WM_CANT_START +} WMResult; + +typedef void (*WMResultFunc) (WMResult result, gpointer data); + +void wm_restart (WindowManager *new, + GdkWindow *client, + WMResultFunc callback, + gpointer data); +gboolean wm_is_running (void); +WindowManager *wm_guess_current (void); |