diff options
author | Alberts Muktupāvels <alberts.muktupavels@gmail.com> | 2016-01-31 04:08:50 +0200 |
---|---|---|
committer | Alberts Muktupāvels <alberts.muktupavels@gmail.com> | 2016-01-31 04:08:50 +0200 |
commit | 942b171e91dcacca2df985aa33abb680d8d8815a (patch) | |
tree | faea87a31676db6e889a9c9d6b59a56d91d16762 /libmetacity/meta-frame-style.c | |
parent | a494336bee2b150942f18b53f0ddce4c04d59d4c (diff) | |
download | metacity-942b171e91dcacca2df985aa33abb680d8d8815a.tar.gz |
libmetacity: add meta-frame-style.[c/h]
Diffstat (limited to 'libmetacity/meta-frame-style.c')
-rw-r--r-- | libmetacity/meta-frame-style.c | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/libmetacity/meta-frame-style.c b/libmetacity/meta-frame-style.c new file mode 100644 index 00000000..2e96dbec --- /dev/null +++ b/libmetacity/meta-frame-style.c @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2016 Alberts Muktupāvels + * + * 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 of the License, 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, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "meta-frame-style.h" +#include "meta-theme.h" + +static const char* +meta_frame_state_to_string (MetaFrameState state) +{ + switch (state) + { + case META_FRAME_STATE_NORMAL: + return "normal"; + case META_FRAME_STATE_MAXIMIZED: + return "maximized"; + case META_FRAME_STATE_TILED_LEFT: + return "tiled_left"; + case META_FRAME_STATE_TILED_RIGHT: + return "tiled_right"; + case META_FRAME_STATE_SHADED: + return "shaded"; + case META_FRAME_STATE_MAXIMIZED_AND_SHADED: + return "maximized_and_shaded"; + case META_FRAME_STATE_TILED_LEFT_AND_SHADED: + return "tiled_left_and_shaded"; + case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: + return "tiled_right_and_shaded"; + case META_FRAME_STATE_LAST: + break; + default: + break; + } + + return "<unknown>"; +} + +static const char* +meta_frame_resize_to_string (MetaFrameResize resize) +{ + switch (resize) + { + case META_FRAME_RESIZE_NONE: + return "none"; + case META_FRAME_RESIZE_VERTICAL: + return "vertical"; + case META_FRAME_RESIZE_HORIZONTAL: + return "horizontal"; + case META_FRAME_RESIZE_BOTH: + return "both"; + case META_FRAME_RESIZE_LAST: + break; + default: + break; + } + + return "<unknown>"; +} + +static const char* +meta_frame_focus_to_string (MetaFrameFocus focus) +{ + switch (focus) + { + case META_FRAME_FOCUS_NO: + return "no"; + case META_FRAME_FOCUS_YES: + return "yes"; + case META_FRAME_FOCUS_LAST: + break; + default: + break; + } + + return "<unknown>"; +} + +static void +free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST]) +{ + int i, j; + + for (i = 0; i < META_BUTTON_TYPE_LAST; i++) + { + for (j = 0; j < META_BUTTON_STATE_LAST; j++) + { + if (op_lists[i][j]) + meta_draw_op_list_unref (op_lists[i][j]); + } + } +} + +static void +free_focus_styles (MetaFrameStyle *focus_styles[META_FRAME_FOCUS_LAST]) +{ + int i; + + for (i = 0; i < META_FRAME_FOCUS_LAST; i++) + { + if (focus_styles[i]) + meta_frame_style_unref (focus_styles[i]); + } +} + +static gboolean +check_state (MetaFrameStyleSet *style_set, + MetaFrameState state, + GError **error) +{ + int i; + + for (i = 0; i < META_FRAME_FOCUS_LAST; i++) + { + if (meta_frame_style_set_get_style (style_set, state, + META_FRAME_RESIZE_NONE, i) == NULL) + { + /* Translators: This error occurs when a <frame> tag is missing + * in theme XML. The "<frame ...>" is intended as a noun phrase, + * and the "missing" qualifies it. You should translate "whatever". + */ + g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, + _("Missing <frame state='%s' resize='%s' focus='%s' style='whatever' />"), + meta_frame_state_to_string (state), + meta_frame_resize_to_string (META_FRAME_RESIZE_NONE), + meta_frame_focus_to_string (i)); + return FALSE; + } + } + + return TRUE; +} + +/** + * Constructor for a MetaFrameStyle. + * + * \param parent The parent style. Data not filled in here will be + * looked for in the parent style, and in its parent + * style, and so on. + * + * \return The newly-constructed style. + */ +MetaFrameStyle * +meta_frame_style_new (MetaFrameStyle *parent) +{ + MetaFrameStyle *style; + + style = g_new0 (MetaFrameStyle, 1); + + style->refcount = 1; + + /* Default alpha is fully opaque */ + style->window_background_alpha = 255; + + style->parent = parent; + if (parent) + meta_frame_style_ref (parent); + + return style; +} + +/** + * Increases the reference count of a frame style. + * If the style is NULL, this is a no-op. + * + * \param style The style. + */ +void +meta_frame_style_ref (MetaFrameStyle *style) +{ + g_return_if_fail (style != NULL); + + style->refcount += 1; +} + +void +meta_frame_style_unref (MetaFrameStyle *style) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->refcount > 0); + + style->refcount -= 1; + + if (style->refcount == 0) + { + int i; + + free_button_ops (style->buttons); + + for (i = 0; i < META_FRAME_PIECE_LAST; i++) + if (style->pieces[i]) + meta_draw_op_list_unref (style->pieces[i]); + + if (style->layout) + meta_frame_layout_unref (style->layout); + + if (style->window_background_color) + meta_color_spec_free (style->window_background_color); + + /* we hold a reference to any parent style */ + if (style->parent) + meta_frame_style_unref (style->parent); + + g_free (style); + } +} + +void +meta_frame_style_apply_scale (const MetaFrameStyle *style, + PangoFontDescription *font_desc) +{ + int size = pango_font_description_get_size (font_desc); + double scale = style->layout->title_scale; + + pango_font_description_set_size (font_desc, MAX (size * scale, 1)); +} + +MetaFrameStyleSet * +meta_frame_style_set_new (MetaFrameStyleSet *parent) +{ + MetaFrameStyleSet *style_set; + + style_set = g_new0 (MetaFrameStyleSet, 1); + + style_set->parent = parent; + if (parent) + meta_frame_style_set_ref (parent); + + style_set->refcount = 1; + + return style_set; +} + +void +meta_frame_style_set_ref (MetaFrameStyleSet *style_set) +{ + g_return_if_fail (style_set != NULL); + + style_set->refcount += 1; +} + +void +meta_frame_style_set_unref (MetaFrameStyleSet *style_set) +{ + g_return_if_fail (style_set != NULL); + g_return_if_fail (style_set->refcount > 0); + + style_set->refcount -= 1; + + if (style_set->refcount == 0) + { + int i; + + for (i = 0; i < META_FRAME_RESIZE_LAST; i++) + { + free_focus_styles (style_set->normal_styles[i]); + free_focus_styles (style_set->shaded_styles[i]); + } + + free_focus_styles (style_set->maximized_styles); + free_focus_styles (style_set->tiled_left_styles); + free_focus_styles (style_set->tiled_right_styles); + free_focus_styles (style_set->maximized_and_shaded_styles); + free_focus_styles (style_set->tiled_left_and_shaded_styles); + free_focus_styles (style_set->tiled_right_and_shaded_styles); + + if (style_set->parent) + meta_frame_style_set_unref (style_set->parent); + + g_free (style_set); + } +} + +gboolean +meta_frame_style_set_validate (MetaFrameStyleSet *style_set, + GError **error) +{ + int i, j; + + g_return_val_if_fail (style_set != NULL, FALSE); + + for (i = 0; i < META_FRAME_RESIZE_LAST; i++) + for (j = 0; j < META_FRAME_FOCUS_LAST; j++) + if (meta_frame_style_set_get_style (style_set,META_FRAME_STATE_NORMAL, + i, j) == NULL) + { + g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, + _("Missing <frame state='%s' resize='%s' focus='%s' style='whatever' />"), + meta_frame_state_to_string (META_FRAME_STATE_NORMAL), + meta_frame_resize_to_string (i), + meta_frame_focus_to_string (j)); + + return FALSE; + } + + if (!check_state (style_set, META_FRAME_STATE_SHADED, error)) + return FALSE; + + if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED, error)) + return FALSE; + + if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED_AND_SHADED, error)) + return FALSE; + + return TRUE; +} + +MetaFrameStyle * +meta_frame_style_set_get_style (MetaFrameStyleSet *style_set, + MetaFrameState state, + MetaFrameResize resize, + MetaFrameFocus focus) +{ + MetaFrameStyle *style; + + style = NULL; + + if (state == META_FRAME_STATE_NORMAL || state == META_FRAME_STATE_SHADED) + { + if (state == META_FRAME_STATE_SHADED) + style = style_set->shaded_styles[resize][focus]; + else + style = style_set->normal_styles[resize][focus]; + + /* Try parent if we failed here */ + if (style == NULL && style_set->parent) + style = meta_frame_style_set_get_style (style_set->parent, state, resize, focus); + + /* Allow people to omit the vert/horz/none resize modes */ + if (style == NULL && resize != META_FRAME_RESIZE_BOTH) + style = meta_frame_style_set_get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus); + } + else + { + MetaFrameStyle **styles; + + styles = NULL; + + switch (state) + { + case META_FRAME_STATE_MAXIMIZED: + styles = style_set->maximized_styles; + break; + case META_FRAME_STATE_TILED_LEFT: + styles = style_set->tiled_left_styles; + break; + case META_FRAME_STATE_TILED_RIGHT: + styles = style_set->tiled_right_styles; + break; + case META_FRAME_STATE_MAXIMIZED_AND_SHADED: + styles = style_set->maximized_and_shaded_styles; + break; + case META_FRAME_STATE_TILED_LEFT_AND_SHADED: + styles = style_set->tiled_left_and_shaded_styles; + break; + case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: + styles = style_set->tiled_right_and_shaded_styles; + break; + case META_FRAME_STATE_NORMAL: + case META_FRAME_STATE_SHADED: + case META_FRAME_STATE_LAST: + default: + g_assert_not_reached (); + break; + } + + style = styles[focus]; + + /* Tiled states are optional, try falling back to non-tiled states */ + if (style == NULL) + { + if (state == META_FRAME_STATE_TILED_LEFT || + state == META_FRAME_STATE_TILED_RIGHT) + style = meta_frame_style_set_get_style (style_set, META_FRAME_STATE_NORMAL, resize, focus); + else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED || + state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED) + style = meta_frame_style_set_get_style (style_set, META_FRAME_STATE_SHADED, resize, focus); + } + + /* Try parent if we failed here */ + if (style == NULL && style_set->parent) + style = meta_frame_style_set_get_style (style_set->parent, state, resize, focus); + } + + return style; +} |