diff options
Diffstat (limited to 'capplets/windows/mate-window-properties.c')
-rw-r--r-- | capplets/windows/mate-window-properties.c | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/capplets/windows/mate-window-properties.c b/capplets/windows/mate-window-properties.c new file mode 100644 index 00000000..74c8a207 --- /dev/null +++ b/capplets/windows/mate-window-properties.c @@ -0,0 +1,636 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ + +/* mate-window-properties.c + * Copyright (C) 2002 Seth Nickell + * Copyright (C) 2002 Red Hat, Inc. + * + * Written by: Seth Nickell <[email protected]> + * Havoc Pennington <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <glib/gi18n.h> +#include <string.h> +#include <mate-wm-manager.h> + +#include "capplet-util.h" +#include "mateconf-property-editor.h" + +typedef struct +{ + int number; + char *name; + const char *value; /* machine-readable name for storing config */ + GtkWidget *radio; +} MouseClickModifier; + +static MateWindowManager *current_wm; /* may be NULL */ +static GtkWidget *dialog_win; +static GObject *focus_mode_checkbutton; +static GObject *autoraise_checkbutton; +static GObject *autoraise_delay_slider; +static GtkWidget *autoraise_delay_hbox; +static GObject *double_click_titlebar_optionmenu; +static GObject *alt_click_hbox; + +static MateWMSettings *settings; +static const MateWMDoubleClickAction *double_click_actions = NULL; +static int n_double_click_actions = 0; + +static MouseClickModifier *mouse_modifiers = NULL; +static int n_mouse_modifiers = 0; + +static void reload_mouse_modifiers (void); + +static void +mouse_focus_toggled_callback (GtkWidget *button, + void *data) +{ + MateWMSettings new_settings; + + new_settings.flags = MATE_WM_SETTING_MOUSE_FOCUS; + new_settings.focus_follows_mouse = + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + if (current_wm != NULL && new_settings.focus_follows_mouse != settings->focus_follows_mouse) + mate_window_manager_change_settings (current_wm, &new_settings); +} + +static void +autoraise_toggled_callback (GtkWidget *button, + void *data) +{ + MateWMSettings new_settings; + + new_settings.flags = MATE_WM_SETTING_AUTORAISE; + new_settings.autoraise = + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + if (current_wm != NULL && new_settings.autoraise != settings->autoraise) + mate_window_manager_change_settings (current_wm, &new_settings); + +} + +static void +autoraise_delay_value_changed_callback (GtkWidget *slider, + void *data) +{ + MateWMSettings new_settings; + + new_settings.flags = MATE_WM_SETTING_AUTORAISE_DELAY; + new_settings.autoraise_delay = + gtk_range_get_value (GTK_RANGE (slider)) * 1000; + + if (current_wm != NULL && new_settings.autoraise_delay != settings->autoraise_delay) + mate_window_manager_change_settings (current_wm, &new_settings); +} + +static void +double_click_titlebar_changed_callback (GtkWidget *optionmenu, + void *data) +{ + MateWMSettings new_settings; + + new_settings.flags = MATE_WM_SETTING_DOUBLE_CLICK_ACTION; + new_settings.double_click_action = + gtk_combo_box_get_active (GTK_COMBO_BOX (optionmenu)); + + if (current_wm != NULL && new_settings.double_click_action != settings->double_click_action) + mate_window_manager_change_settings (current_wm, &new_settings); +} + +static void +alt_click_radio_toggled_callback (GtkWidget *radio, + void *data) +{ + MateWMSettings new_settings; + gboolean active; + MouseClickModifier *modifier = data; + + new_settings.flags = MATE_WM_SETTING_MOUSE_MOVE_MODIFIER; + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio)); + + if (active && current_wm != NULL) { + new_settings.mouse_move_modifier = modifier->value; + + if ((settings->mouse_move_modifier == NULL) || + (strcmp (new_settings.mouse_move_modifier, + settings->mouse_move_modifier) != 0)) + mate_window_manager_change_settings (current_wm, &new_settings); + } +} + +static void +update_sensitivity (void) +{ + gtk_widget_set_sensitive (GTK_WIDGET (autoraise_checkbutton), + settings->focus_follows_mouse); + + gtk_widget_set_sensitive (autoraise_delay_hbox, + settings->focus_follows_mouse && settings->autoraise); + + gtk_widget_set_sensitive (GTK_WIDGET (double_click_titlebar_optionmenu), + n_double_click_actions > 1); + + /* disable the whole dialog while no WM is running, or + * a WM we don't understand is running. We should probably do + * something better. I don't want to just launch the config tool + * as we would on startup though, because then you'd get weirdness + * in the gap time between old and new WM. + */ + gtk_widget_set_sensitive (dialog_win, current_wm != NULL); +} + +static void +init_settings_struct (MateWMSettings *settings) +{ + /* Init fields that weren't initialized */ + if ((settings->flags & MATE_WM_SETTING_MOUSE_FOCUS) == 0) + settings->focus_follows_mouse = FALSE; + + if ((settings->flags & MATE_WM_SETTING_AUTORAISE) == 0) + settings->autoraise = FALSE; + + if ((settings->flags & MATE_WM_SETTING_AUTORAISE_DELAY) == 0) + settings->autoraise_delay = 1000; + + if ((settings->flags & MATE_WM_SETTING_MOUSE_MOVE_MODIFIER) == 0) + settings->mouse_move_modifier = "Super"; + + if ((settings->flags & MATE_WM_SETTING_DOUBLE_CLICK_ACTION) == 0) + settings->double_click_action = 0; +} + +static void +set_alt_click_value (const MateWMSettings *settings) +{ + gboolean match_found = FALSE; + int i; + + /* We look for a matching modifier and set it. */ + if (settings->mouse_move_modifier != NULL) { + for (i = 0; i < n_mouse_modifiers; i ++) + if (strcmp (mouse_modifiers[i].value, + settings->mouse_move_modifier) == 0) { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mouse_modifiers[i].radio), + TRUE); + match_found = TRUE; + break; + } + } + + /* No matching modifier was found; we set all the toggle buttons to be + * insensitive. */ + for (i = 0; i < n_mouse_modifiers; i++) { + gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (mouse_modifiers[i].radio), + ! match_found); + } +} + +static void +reload_settings (void) +{ + MateWMSettings new_settings; + + g_assert (n_mouse_modifiers > 0); + + if (current_wm != NULL) { + new_settings.flags = MATE_WM_SETTING_MOUSE_FOCUS | + MATE_WM_SETTING_AUTORAISE | + MATE_WM_SETTING_AUTORAISE_DELAY | + MATE_WM_SETTING_MOUSE_MOVE_MODIFIER | + MATE_WM_SETTING_DOUBLE_CLICK_ACTION; + + /* this will clear any flags that don't get filled in */ + mate_window_manager_get_settings (current_wm, &new_settings); + } else { + new_settings.flags = 0; + } + + init_settings_struct (&new_settings); + + if (new_settings.focus_follows_mouse != settings->focus_follows_mouse) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (focus_mode_checkbutton), + new_settings.focus_follows_mouse); + + if (new_settings.autoraise != settings->autoraise) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (autoraise_checkbutton), + new_settings.autoraise); + + if (new_settings.autoraise_delay != settings->autoraise_delay) + gtk_range_set_value (GTK_RANGE (autoraise_delay_slider), + new_settings.autoraise_delay / 1000.0); + + if (n_double_click_actions > 0 && + new_settings.double_click_action != settings->double_click_action) { + gtk_combo_box_set_active (GTK_COMBO_BOX (double_click_titlebar_optionmenu), + new_settings.double_click_action); + } + + if (settings->mouse_move_modifier == NULL || + new_settings.mouse_move_modifier == NULL || + strcmp (settings->mouse_move_modifier, + new_settings.mouse_move_modifier) != 0) { + set_alt_click_value (&new_settings); + } + + mate_wm_settings_free (settings); + settings = mate_wm_settings_copy (&new_settings); + + update_sensitivity (); +} + +static void +wm_settings_changed_callback (MateWindowManager *wm, + void *data) +{ + reload_settings (); +} + +static void +update_wm (GdkScreen *screen, + gboolean load_settings) +{ + int i; + + g_assert (n_mouse_modifiers > 0); + + if (current_wm != NULL) { + g_signal_handlers_disconnect_by_func (G_OBJECT (current_wm), + G_CALLBACK (wm_settings_changed_callback), + NULL); + current_wm = NULL; + double_click_actions = NULL; + n_double_click_actions = 0; + } + + current_wm = mate_wm_manager_get_current (screen); + + if (current_wm != NULL) { + g_signal_connect (G_OBJECT (current_wm), "settings_changed", + G_CALLBACK (wm_settings_changed_callback), NULL); + + mate_window_manager_get_double_click_actions (current_wm, + &double_click_actions, + &n_double_click_actions); + + } + + for (i = 0; i < n_double_click_actions; i++) { + gtk_combo_box_append_text (GTK_COMBO_BOX (double_click_titlebar_optionmenu), + double_click_actions[i].human_readable_name); + } + + if (load_settings) + reload_settings (); +} + +static void +wm_changed_callback (GdkScreen *screen, + void *data) +{ + update_wm (screen, TRUE); +} + +static void +response_cb (GtkWidget *dialog_win, + int response_id, + void *data) +{ + + if (response_id == GTK_RESPONSE_HELP) { + capplet_help (GTK_WINDOW (dialog_win), + "goscustdesk-58"); + } else { + gtk_widget_destroy (dialog_win); + } +} + +static void +try_spawn_config_tool (GdkScreen *screen) +{ + GError *error; + + error = NULL; + mate_wm_manager_spawn_config_tool_for_current (screen, &error); + + if (error != NULL) { + GtkWidget *no_tool_dialog; + char *str; + char *escaped; + + escaped = g_markup_escape_text (error->message, -1); + + str = g_strdup_printf ("<b>%s</b>\n\n%s", + _("Cannot start the preferences application for your window manager"), + escaped); + g_free (escaped); + + no_tool_dialog = + gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + " "); + gtk_window_set_title (GTK_WINDOW (no_tool_dialog), ""); + gtk_window_set_resizable (GTK_WINDOW (no_tool_dialog), FALSE); + + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (no_tool_dialog), str); + + g_free (str); + + gtk_dialog_run (GTK_DIALOG (no_tool_dialog)); + + gtk_widget_destroy (no_tool_dialog); + g_error_free (error); + + exit (1); + } + + /* exit, let the config tool handle it */ + exit (0); +} + +int +main (int argc, char **argv) +{ + GdkScreen *screen; + MateWMSettings new_settings; + GtkBuilder *builder; + GError *error = NULL; + int rc = 0; + int i; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + gtk_init (&argc, &argv); + + mate_wm_manager_init (); + + screen = gdk_display_get_default_screen (gdk_display_get_default ()); + + current_wm = mate_wm_manager_get_current (screen); + + if (current_wm == NULL) { + try_spawn_config_tool (screen); + goto out; + } + + builder = gtk_builder_new (); + gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE); + + if (gtk_builder_add_from_file (builder, UIDIR "/mate-window-properties.ui", &error) == 0) { + g_warning ("Could not parse UI file: %s", error->message); + g_error_free (error); + g_object_unref (builder); + rc = 1; + goto out; + } + + dialog_win = GTK_WIDGET (gtk_builder_get_object (builder, + "main-dialog")); + focus_mode_checkbutton = gtk_builder_get_object (builder, + "focus-mode-checkbutton"); + autoraise_checkbutton = gtk_builder_get_object (builder, + "autoraise-checkbutton"); + autoraise_delay_slider = gtk_builder_get_object (builder, + "autoraise-delay-slider"); + autoraise_delay_hbox = GTK_WIDGET (gtk_builder_get_object (builder, + "autoraise-delay-hbox")); + double_click_titlebar_optionmenu = gtk_builder_get_object (builder, + "double-click-titlebar-optionmenu"); + alt_click_hbox = gtk_builder_get_object (builder, "alt-click-box"); + + gtk_range_set_range (GTK_RANGE (autoraise_delay_slider), + 0, 10); + + gtk_range_set_increments (GTK_RANGE (autoraise_delay_slider), + 0.2, 1.0); + + new_settings.flags = 0; + init_settings_struct (&new_settings); + settings = mate_wm_settings_copy (&new_settings); + + reload_mouse_modifiers (); + update_wm (screen, FALSE); + + set_alt_click_value (&new_settings); + gtk_range_set_value (GTK_RANGE (autoraise_delay_slider), + new_settings.autoraise_delay / 1000.0); + gtk_combo_box_set_active (GTK_COMBO_BOX (double_click_titlebar_optionmenu), + new_settings.double_click_action); + + reload_settings (); /* must come before below signal connections */ + + g_signal_connect (G_OBJECT (dialog_win), "response", + G_CALLBACK (response_cb), NULL); + + g_signal_connect (G_OBJECT (dialog_win), "destroy", + G_CALLBACK (gtk_main_quit), NULL); + + + g_signal_connect (focus_mode_checkbutton, "toggled", + G_CALLBACK (mouse_focus_toggled_callback), NULL); + + g_signal_connect (autoraise_checkbutton, "toggled", + G_CALLBACK (autoraise_toggled_callback), NULL); + + g_signal_connect (autoraise_delay_slider, "value_changed", + G_CALLBACK (autoraise_delay_value_changed_callback), NULL); + + g_signal_connect (double_click_titlebar_optionmenu, "changed", + G_CALLBACK (double_click_titlebar_changed_callback), NULL); + + g_signal_connect (G_OBJECT (screen), "window_manager_changed", + G_CALLBACK (wm_changed_callback), NULL); + + i = 0; + while (i < n_mouse_modifiers) { + g_signal_connect (G_OBJECT (mouse_modifiers[i].radio), "toggled", + G_CALLBACK (alt_click_radio_toggled_callback), + &mouse_modifiers[i]); + ++i; + } + + capplet_set_icon (dialog_win, "preferences-system-windows"); + gtk_widget_show (dialog_win); + + gtk_main (); + + g_object_unref (builder); + +out: + return rc; +} + +#include <X11/Xlib.h> +#include <X11/keysym.h> +#include <gdk/gdkx.h> + +static void +fill_radio (GtkRadioButton *group, + MouseClickModifier *modifier) +{ + modifier->radio = + gtk_radio_button_new_with_mnemonic_from_widget (group, + modifier->name); + gtk_box_pack_start (GTK_BOX (alt_click_hbox), + modifier->radio, FALSE, FALSE, 0); + + gtk_widget_show (modifier->radio); +} + +static void +reload_mouse_modifiers (void) +{ + XModifierKeymap *modmap; + KeySym *keymap; + int keysyms_per_keycode; + int map_size; + int i; + gboolean have_meta; + gboolean have_hyper; + gboolean have_super; + int min_keycode, max_keycode; + int mod_meta, mod_super, mod_hyper; + + XDisplayKeycodes (gdk_display, + &min_keycode, + &max_keycode); + + keymap = XGetKeyboardMapping (gdk_display, + min_keycode, + max_keycode - min_keycode, + &keysyms_per_keycode); + + modmap = XGetModifierMapping (gdk_display); + + have_super = FALSE; + have_meta = FALSE; + have_hyper = FALSE; + + /* there are 8 modifiers, and the first 3 are shift, shift lock, + * and control + */ + map_size = 8 * modmap->max_keypermod; + i = 3 * modmap->max_keypermod; + mod_meta = mod_super = mod_hyper = 0; + while (i < map_size) { + /* get the key code at this point in the map, + * see if its keysym is one we're interested in + */ + int keycode = modmap->modifiermap[i]; + + if (keycode >= min_keycode && + keycode <= max_keycode) { + int j = 0; + KeySym *syms = keymap + (keycode - min_keycode) * keysyms_per_keycode; + + while (j < keysyms_per_keycode) { + if (syms[j] == XK_Super_L || + syms[j] == XK_Super_R) + mod_super = i / modmap->max_keypermod; + else if (syms[j] == XK_Hyper_L || + syms[j] == XK_Hyper_R) + mod_hyper = i / modmap->max_keypermod; + else if ((syms[j] == XK_Meta_L || + syms[j] == XK_Meta_R)) + mod_meta = i / modmap->max_keypermod; + ++j; + } + } + + ++i; + } + + if ((1 << mod_meta) != Mod1Mask) + have_meta = TRUE; + if (mod_super != 0 && + mod_super != mod_meta) + have_super = TRUE; + if (mod_hyper != 0 && + mod_hyper != mod_meta && + mod_hyper != mod_super) + have_hyper = TRUE; + + XFreeModifiermap (modmap); + XFree (keymap); + + i = 0; + while (i < n_mouse_modifiers) { + g_free (mouse_modifiers[i].name); + if (mouse_modifiers[i].radio) + gtk_widget_destroy (mouse_modifiers[i].radio); + ++i; + } + g_free (mouse_modifiers); + mouse_modifiers = NULL; + + n_mouse_modifiers = 1; /* alt */ + if (have_super) + ++n_mouse_modifiers; + if (have_hyper) + ++n_mouse_modifiers; + if (have_meta) + ++n_mouse_modifiers; + + mouse_modifiers = g_new0 (MouseClickModifier, n_mouse_modifiers); + + i = 0; + + mouse_modifiers[i].number = i; + mouse_modifiers[i].name = g_strdup (_("_Alt")); + mouse_modifiers[i].value = "Alt"; + ++i; + + if (have_hyper) { + mouse_modifiers[i].number = i; + mouse_modifiers[i].name = g_strdup (_("H_yper")); + mouse_modifiers[i].value = "Hyper"; + ++i; + } + + if (have_super) { + mouse_modifiers[i].number = i; + mouse_modifiers[i].name = g_strdup (_("S_uper (or \"Windows logo\")")); + mouse_modifiers[i].value = "Super"; + ++i; + } + + if (have_meta) { + mouse_modifiers[i].number = i; + mouse_modifiers[i].name = g_strdup (_("_Meta")); + mouse_modifiers[i].value = "Meta"; + ++i; + } + + g_assert (i == n_mouse_modifiers); + + i = 0; + while (i < n_mouse_modifiers) { + fill_radio (i == 0 ? NULL : GTK_RADIO_BUTTON (mouse_modifiers[i-1].radio), + &mouse_modifiers[i]); + ++i; + } +} |