diff --git a/src/Makefile.am b/src/Makefile.am index bd3420f..2ae02c5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,7 +97,9 @@ metacity_SOURCES= \ ui/themewidget.c \ ui/themewidget.h \ ui/ui.c \ - include/all-keybindings.h + include/all-keybindings.h \ + ui/buttonlayout.c \ + include/buttonlayout.h # by setting libmetacity_private_la_CFLAGS, the files shared with # metacity proper will be compiled with different names. @@ -105,6 +107,8 @@ libmetacity_private_la_CFLAGS = libmetacity_private_la_SOURCES= \ core/boxes.c \ include/boxes.h \ + ui/buttonlayout.c \ + include/buttonlayout.h \ ui/gradient.c \ ui/gradient.h \ core/util.c \ @@ -115,7 +119,7 @@ libmetacity_private_la_SOURCES= \ ui/theme-parser.c \ ui/theme-parser.h \ ui/theme.c \ - ui/theme.h + ui/theme.h libmetacity_private_la_LDFLAGS = -no-undefined libmetacity_private_la_LIBADD = @METACITY_LIBS@ @@ -128,6 +132,7 @@ libmetacityinclude_HEADERS = \ include/util.h \ include/common.h \ ui/preview-widget.h \ + include/buttonlayout.h \ ui/theme-parser.h \ ui/theme.h diff --git a/src/core/prefs.c b/src/core/prefs.c index af6e304..da50b61 100644 --- a/src/core/prefs.c +++ b/src/core/prefs.c @@ -25,6 +25,7 @@ #include #include "prefs.h" +#include "buttonlayout.h" #include "ui.h" #include "util.h" #ifdef HAVE_GCONF @@ -101,6 +102,7 @@ static gboolean force_fullscreen = TRUE; static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH; static MetaButtonLayout button_layout; +static gboolean force_button_layout = TRUE; /* The screenshot commands are at the end */ static char *commands[MAX_COMMANDS] = { NULL, }; @@ -392,6 +394,11 @@ static MetaBoolPreference preferences_bool[] = &reduced_resources, FALSE, }, + { "/apps/metacity/general/force_button_layout", + META_PREF_FORCE_BUTTON_LAYOUT, + &force_button_layout, + FALSE, + }, { "/desktop/gnome/interface/accessibility", META_PREF_GNOME_ACCESSIBILITY, &gnome_accessibility, @@ -1372,248 +1379,13 @@ mouse_button_mods_handler (MetaPreference pref, } } -static gboolean -button_layout_equal (const MetaButtonLayout *a, - const MetaButtonLayout *b) -{ - int i; - - i = 0; - while (i < MAX_BUTTONS_PER_CORNER) - { - if (a->left_buttons[i] != b->left_buttons[i]) - return FALSE; - if (a->right_buttons[i] != b->right_buttons[i]) - return FALSE; - if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i]) - return FALSE; - if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i]) - return FALSE; - ++i; - } - - return TRUE; -} - -static MetaButtonFunction -button_function_from_string (const char *str) -{ - /* FIXME: gconf_string_to_enum is the obvious way to do this */ - - if (strcmp (str, "menu") == 0) - return META_BUTTON_FUNCTION_MENU; - else if (strcmp (str, "minimize") == 0) - return META_BUTTON_FUNCTION_MINIMIZE; - else if (strcmp (str, "maximize") == 0) - return META_BUTTON_FUNCTION_MAXIMIZE; - else if (strcmp (str, "close") == 0) - return META_BUTTON_FUNCTION_CLOSE; - else if (strcmp (str, "shade") == 0) - return META_BUTTON_FUNCTION_SHADE; - else if (strcmp (str, "above") == 0) - return META_BUTTON_FUNCTION_ABOVE; - else if (strcmp (str, "stick") == 0) - return META_BUTTON_FUNCTION_STICK; - else - /* don't know; give up */ - return META_BUTTON_FUNCTION_LAST; -} - -static MetaButtonFunction -button_opposite_function (MetaButtonFunction ofwhat) -{ - switch (ofwhat) - { - case META_BUTTON_FUNCTION_SHADE: - return META_BUTTON_FUNCTION_UNSHADE; - case META_BUTTON_FUNCTION_UNSHADE: - return META_BUTTON_FUNCTION_SHADE; - - case META_BUTTON_FUNCTION_ABOVE: - return META_BUTTON_FUNCTION_UNABOVE; - case META_BUTTON_FUNCTION_UNABOVE: - return META_BUTTON_FUNCTION_ABOVE; - - case META_BUTTON_FUNCTION_STICK: - return META_BUTTON_FUNCTION_UNSTICK; - case META_BUTTON_FUNCTION_UNSTICK: - return META_BUTTON_FUNCTION_STICK; - - default: - return META_BUTTON_FUNCTION_LAST; - } -} - static void button_layout_handler (MetaPreference pref, const gchar *string_value, gboolean *inform_listeners) { MetaButtonLayout new_layout; - char **sides = NULL; - int i; - - /* We need to ignore unknown button functions, for - * compat with future versions - */ - - if (string_value) - sides = g_strsplit (string_value, ":", 2); - - if (sides != NULL && sides[0] != NULL) - { - char **buttons; - int b; - gboolean used[META_BUTTON_FUNCTION_LAST]; - - i = 0; - while (i < META_BUTTON_FUNCTION_LAST) - { - used[i] = FALSE; - new_layout.left_buttons_has_spacer[i] = FALSE; - ++i; - } - - buttons = g_strsplit (sides[0], ",", -1); - i = 0; - b = 0; - while (buttons[b] != NULL) - { - MetaButtonFunction f = button_function_from_string (buttons[b]); - if (i > 0 && strcmp("spacer", buttons[b]) == 0) - { - new_layout.left_buttons_has_spacer[i-1] = TRUE; - f = button_opposite_function (f); - - if (f != META_BUTTON_FUNCTION_LAST) - { - new_layout.left_buttons_has_spacer[i-2] = TRUE; - } - } - else - { - if (f != META_BUTTON_FUNCTION_LAST && !used[f]) - { - new_layout.left_buttons[i] = f; - used[f] = TRUE; - ++i; - - f = button_opposite_function (f); - - if (f != META_BUTTON_FUNCTION_LAST) - new_layout.left_buttons[i++] = f; - - } - else - { - meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n", - buttons[b]); - } - } - - ++b; - } - - new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST; - new_layout.left_buttons_has_spacer[i] = FALSE; - - g_strfreev (buttons); - } - - if (sides != NULL && sides[0] != NULL && sides[1] != NULL) - { - char **buttons; - int b; - gboolean used[META_BUTTON_FUNCTION_LAST]; - - i = 0; - while (i < META_BUTTON_FUNCTION_LAST) - { - used[i] = FALSE; - new_layout.right_buttons_has_spacer[i] = FALSE; - ++i; - } - - buttons = g_strsplit (sides[1], ",", -1); - i = 0; - b = 0; - while (buttons[b] != NULL) - { - MetaButtonFunction f = button_function_from_string (buttons[b]); - if (i > 0 && strcmp("spacer", buttons[b]) == 0) - { - new_layout.right_buttons_has_spacer[i-1] = TRUE; - f = button_opposite_function (f); - if (f != META_BUTTON_FUNCTION_LAST) - { - new_layout.right_buttons_has_spacer[i-2] = TRUE; - } - } - else - { - if (f != META_BUTTON_FUNCTION_LAST && !used[f]) - { - new_layout.right_buttons[i] = f; - used[f] = TRUE; - ++i; - - f = button_opposite_function (f); - - if (f != META_BUTTON_FUNCTION_LAST) - new_layout.right_buttons[i++] = f; - - } - else - { - meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n", - buttons[b]); - } - } - - ++b; - } - - new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST; - new_layout.right_buttons_has_spacer[i] = FALSE; - - g_strfreev (buttons); - } - - g_strfreev (sides); - - /* Invert the button layout for RTL languages */ - if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) - { - MetaButtonLayout rtl_layout; - int j; - - for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++); - for (j = 0; j < i; j++) - { - rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1]; - if (j == 0) - rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1]; - else - rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1]; - } - rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST; - rtl_layout.right_buttons_has_spacer[j] = FALSE; - - for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++); - for (j = 0; j < i; j++) - { - rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1]; - if (j == 0) - rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1]; - else - rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1]; - } - rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST; - rtl_layout.left_buttons_has_spacer[j] = FALSE; - - new_layout = rtl_layout; - } - + new_layout = get_meta_button_layout (g_strdup (string_value)); if (button_layout_equal (&button_layout, &new_layout)) { /* Same as before, so duck out */ @@ -1722,6 +1494,9 @@ meta_preference_to_string (MetaPreference pref) case META_PREF_BUTTON_LAYOUT: return "BUTTON_LAYOUT"; + case META_PREF_FORCE_BUTTON_LAYOUT: + return "FORCE_BUTTON_LAYOUT"; + case META_PREF_WORKSPACE_NAMES: return "WORKSPACE_NAMES"; @@ -2725,6 +2500,12 @@ meta_prefs_get_force_fullscreen (void) return force_fullscreen; } +gboolean +meta_prefs_get_force_button_layout (void) +{ + return force_button_layout; +} + void meta_prefs_set_compositing_manager (gboolean whether) { @@ -2749,7 +2530,7 @@ meta_prefs_set_compositing_manager (gboolean whether) #ifndef HAVE_GCONF static void -init_button_layout(void) +init_default_button_layout(void) { MetaButtonLayout button_layout_ltr = { { diff --git a/src/include/prefs.h b/src/include/prefs.h index a4193ff..dfe0418 100644 --- a/src/include/prefs.h +++ b/src/include/prefs.h @@ -49,6 +49,7 @@ typedef enum META_PREF_COMMANDS, META_PREF_TERMINAL_COMMAND, META_PREF_BUTTON_LAYOUT, + META_PREF_FORCE_BUTTON_LAYOUT, META_PREF_WORKSPACE_NAMES, META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL, @@ -100,6 +101,7 @@ const char* meta_prefs_get_terminal_command (void); const char* meta_prefs_get_gconf_key_for_terminal_command (void); void meta_prefs_get_button_layout (MetaButtonLayout *button_layout); +gboolean meta_prefs_get_force_button_layout (void); /* Double, right, middle click can be configured to any titlebar meta-action */ MetaActionTitlebar meta_prefs_get_action_double_click_titlebar (void); diff --git a/src/metacity.schemas.in.in b/src/metacity.schemas.in.in index 97cd280..fff2b7e 100644 --- a/src/metacity.schemas.in.in +++ b/src/metacity.schemas.in.in @@ -64,6 +64,20 @@ + /schemas/apps/metacity/general/force_button_layout + /apps/metacity/general/force_button_layout + metacity + bool + true + + Whether to use a theme's titlebar button layout + + Set this to true to always use the value in button_layout + + + + + /schemas/apps/metacity/general/focus_mode /apps/metacity/general/focus_mode metacity diff --git a/src/ui/frames.c b/src/ui/frames.c index 86d5d76..e008f8e 100644 --- a/src/ui/frames.c +++ b/src/ui/frames.c @@ -195,6 +195,12 @@ prefs_changed_callback (MetaPreference pref, case META_PREF_BUTTON_LAYOUT: meta_frames_button_layout_changed (META_FRAMES (data)); break; + case META_PREF_FORCE_BUTTON_LAYOUT: + meta_frames_button_layout_changed (META_FRAMES (data)); + break; + case META_PREF_THEME: + meta_frames_button_layout_changed (META_FRAMES (data)); + break; default: break; } @@ -545,6 +551,7 @@ meta_frames_calc_geometry (MetaFrames *frames, MetaFrameFlags flags; MetaFrameType type; MetaButtonLayout button_layout; + MetaTheme *current_theme; meta_core_get (gdk_display, frame->xwindow, META_CORE_GET_CLIENT_WIDTH, &width, @@ -555,9 +562,23 @@ meta_frames_calc_geometry (MetaFrames *frames, meta_frames_ensure_layout (frames, frame); - meta_prefs_get_button_layout (&button_layout); - - meta_theme_calc_geometry (meta_theme_get_current (), + current_theme = meta_theme_get_current(); + + if (!meta_prefs_get_force_button_layout()) + { + if (current_theme->has_button_layout == TRUE) + { + button_layout = current_theme->button_layout; + } + else + meta_prefs_get_button_layout (&button_layout); + } + else + { + meta_prefs_get_button_layout (&button_layout); + } + + meta_theme_calc_geometry (current_theme, type, frame->text_height, flags, @@ -2415,7 +2436,20 @@ meta_frames_paint_to_drawable (MetaFrames *frames, meta_frames_ensure_layout (frames, frame); - meta_prefs_get_button_layout (&button_layout); + if (!meta_prefs_get_force_button_layout()) + { + MetaTheme *current_theme = meta_theme_get_current(); + if (current_theme->has_button_layout == TRUE) + { + button_layout = current_theme->button_layout; + } + else + meta_prefs_get_button_layout (&button_layout); + } + else + { + meta_prefs_get_button_layout (&button_layout); + } if (G_LIKELY (GDK_IS_WINDOW (drawable))) { diff --git a/src/ui/theme-parser.c b/src/ui/theme-parser.c index c56e318..2eafd4b 100644 --- a/src/ui/theme-parser.c +++ b/src/ui/theme-parser.c @@ -38,6 +38,8 @@ typedef enum STATE_COPYRIGHT, STATE_DATE, STATE_DESCRIPTION, + /* button layout */ + STATE_BUTTON_LAYOUT, /* constants */ STATE_CONSTANT, /* geometry */ @@ -817,6 +819,26 @@ parse_toplevel_element (GMarkupParseContext *context, push_state (info, STATE_INFO); } + else if (ELEMENT_IS ("button_layout")) + { + if (META_THEME_ALLOWS (info->theme, META_THEME_BUTTON_LAYOUT)) + { + const char *value; + if (!locate_attributes (context, element_name, attribute_names, attribute_values, + error, + "!value", &value, + NULL)) + { + add_context_to_error (error, context); + return; + } + if (!meta_theme_set_button_layout (info->theme, value, error)) + { + add_context_to_error (error, context); + return; + } + } + } else if (ELEMENT_IS ("constant")) { const char *name; @@ -3291,6 +3313,7 @@ start_element_handler (GMarkupParseContext *context, _("Element <%s> is not allowed inside a name/author/date/description element"), element_name); break; + case STATE_BUTTON_LAYOUT: case STATE_CONSTANT: set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("Element <%s> is not allowed inside a element"), @@ -3432,6 +3455,10 @@ end_element_handler (GMarkupParseContext *context, pop_state (info); g_assert (peek_state (info) == STATE_INFO); break; + case STATE_BUTTON_LAYOUT: + pop_state (info); + g_assert (peek_state (info) == STATE_THEME); + break; case STATE_CONSTANT: pop_state (info); g_assert (peek_state (info) == STATE_THEME); @@ -3776,6 +3803,9 @@ text_handler (GMarkupParseContext *context, info->theme->description = g_strndup (text, text_len); break; + case STATE_BUTTON_LAYOUT: + NO_TEXT ("button_layout"); + break; case STATE_CONSTANT: NO_TEXT ("constant"); break; @@ -3876,7 +3906,7 @@ text_handler (GMarkupParseContext *context, /* Highest version of the theme format to * look out for. */ -#define THEME_VERSION 2 +#define THEME_VERSION 3 #define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml" diff --git a/src/ui/theme.c b/src/ui/theme.c index 175eb5b..d537b73 100644 --- a/src/ui/theme.c +++ b/src/ui/theme.c @@ -56,6 +56,7 @@ #include "theme.h" #include "theme-parser.h" #include "util.h" +#include "prefs.h" #include "gradient.h" #include #include @@ -4845,6 +4846,8 @@ meta_theme_new (void) theme->quark_icon_height = g_quark_from_static_string ("icon_height"); theme->quark_title_width = g_quark_from_static_string ("title_width"); theme->quark_title_height = g_quark_from_static_string ("title_height"); + + theme->has_button_layout = FALSE; return theme; } @@ -4884,6 +4887,8 @@ meta_theme_free (MetaTheme *theme) if (theme->style_sets_by_type[i]) meta_frame_style_set_unref (theme->style_sets_by_type[i]); + g_free (&(theme->button_layout)); + DEBUG_FILL_STRUCT (theme); g_free (theme); } @@ -5566,6 +5571,23 @@ meta_theme_lookup_color_constant (MetaTheme *theme, } } +gboolean +meta_theme_set_button_layout (MetaTheme *theme, + const char *value, + GError **error) +{ + if (META_THEME_ALLOWS(theme, META_THEME_BUTTON_LAYOUT)) + { + MetaButtonLayout new_layout; + new_layout = get_meta_button_layout (value); + theme->button_layout = new_layout; + theme->has_button_layout = TRUE; + return TRUE; + } + return FALSE; +} + + PangoFontDescription* meta_gtk_widget_get_font_desc (GtkWidget *widget, diff --git a/src/ui/theme.h b/src/ui/theme.h index ddf777d..63abc19 100644 --- a/src/ui/theme.h +++ b/src/ui/theme.h @@ -27,6 +27,7 @@ #include "boxes.h" #include "gradient.h" #include "common.h" +#include "buttonlayout.h" #include typedef struct _MetaFrameStyle MetaFrameStyle; @@ -819,6 +820,9 @@ struct _MetaTheme GQuark quark_icon_height; GQuark quark_title_width; GQuark quark_title_height; + + MetaButtonLayout button_layout; + gboolean has_button_layout; }; struct _MetaPositionExprEnv @@ -1133,6 +1137,10 @@ gboolean meta_theme_replace_constants (MetaTheme *theme, int n_tokens, GError **err); +gboolean meta_theme_set_button_layout (MetaTheme *theme, + const char *value, + GError **err); + /* random stuff */ PangoFontDescription* meta_gtk_widget_get_font_desc (GtkWidget *widget, @@ -1141,7 +1149,6 @@ PangoFontDescription* meta_gtk_widget_get_font_desc (GtkWidget int meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc, PangoContext *context); - /* Enum converters */ MetaGtkColorComponent meta_color_component_from_string (const char *str); const char* meta_color_component_to_string (MetaGtkColorComponent component); @@ -1186,5 +1193,6 @@ guint meta_theme_earliest_version_with_button (MetaButtonType type); #define META_THEME_HIDDEN_BUTTONS 2 #define META_THEME_COLOR_CONSTANTS 2 #define META_THEME_FRAME_BACKGROUNDS 2 +#define META_THEME_BUTTON_LAYOUT 3 #endif