summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeth Nickell <snickell@stanford.edu>2002-05-11 04:28:20 +0000
committerSeth Nickell <seth@src.gnome.org>2002-05-11 04:28:20 +0000
commitad15ad16c954beaa819f3ec534b26a7866e5816a (patch)
tree41bef2050a4eb8a183c4102f7a03f284d06969e5
parent00c628d44b96ddfebc99071005d8828611cef549 (diff)
downloadgnome-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/.cvsignore10
-rw-r--r--capplets/windows/ChangeLog29
-rw-r--r--capplets/windows/Makefile.am31
-rw-r--r--capplets/windows/gnome-window-properties.c797
-rw-r--r--capplets/windows/gnome-window-properties.glade275
-rw-r--r--capplets/windows/window-capplet.pngbin0 -> 3047 bytes
-rw-r--r--capplets/windows/window-properties.desktop.in8
-rw-r--r--capplets/windows/wm-exec.c331
-rw-r--r--capplets/windows/wm-list.c574
-rw-r--r--capplets/windows/wm-properties.h63
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
new file mode 100644
index 000000000..c085f67ac
--- /dev/null
+++ b/capplets/windows/window-capplet.png
Binary files differ
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);