/* * 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 . */ #include "config.h" #include #include "meta-color-spec-private.h" #include "meta-draw-op-private.h" #include "meta-frame-layout-private.h" #include "meta-frame-style-private.h" #include "meta-theme.h" #include "meta-theme-metacity-private.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 ""; } 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 ""; } 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 ""; } static void free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_FUNCTION_LAST][META_BUTTON_STATE_LAST]) { int i, j; for (i = 0; i < META_BUTTON_FUNCTION_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) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, /* Translators: This error occurs when a tag is missing * in theme XML. The "" is intended as a noun phrase, * and the "missing" qualifies it. You should translate "whatever". */ _("Missing "), 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; } static const char* meta_button_function_to_string (MetaButtonFunction function) { switch (function) { case META_BUTTON_FUNCTION_CLOSE: return "close"; case META_BUTTON_FUNCTION_MAXIMIZE: return "maximize"; case META_BUTTON_FUNCTION_MINIMIZE: return "minimize"; case META_BUTTON_FUNCTION_SHADE: return "shade"; case META_BUTTON_FUNCTION_ABOVE: return "above"; case META_BUTTON_FUNCTION_STICK: return "stick"; case META_BUTTON_FUNCTION_UNSHADE: return "unshade"; case META_BUTTON_FUNCTION_UNABOVE: return "unabove"; case META_BUTTON_FUNCTION_UNSTICK: return "unstick"; case META_BUTTON_FUNCTION_MENU: return "menu"; case META_BUTTON_FUNCTION_APPMENU: return "appmenu"; case META_BUTTON_FUNCTION_LEFT_LEFT_BACKGROUND: return "left_left_background"; case META_BUTTON_FUNCTION_LEFT_MIDDLE_BACKGROUND: return "left_middle_background"; case META_BUTTON_FUNCTION_LEFT_RIGHT_BACKGROUND: return "left_right_background"; case META_BUTTON_FUNCTION_LEFT_SINGLE_BACKGROUND: return "left_single_background"; case META_BUTTON_FUNCTION_RIGHT_LEFT_BACKGROUND: return "right_left_background"; case META_BUTTON_FUNCTION_RIGHT_MIDDLE_BACKGROUND: return "right_middle_background"; case META_BUTTON_FUNCTION_RIGHT_RIGHT_BACKGROUND: return "right_right_background"; case META_BUTTON_FUNCTION_RIGHT_SINGLE_BACKGROUND: return "right_single_background"; case META_BUTTON_FUNCTION_LAST: break; default: break; } return ""; } static const char* meta_button_state_to_string (MetaButtonState state) { switch (state) { case META_BUTTON_STATE_NORMAL: return "normal"; case META_BUTTON_STATE_PRESSED: return "pressed"; case META_BUTTON_STATE_PRELIGHT: return "prelight"; case META_BUTTON_STATE_LAST: break; default: break; } return ""; } /** * 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); } } gboolean meta_frame_style_validate (MetaFrameStyle *style, guint current_theme_version, GError **error) { int i, j; g_return_val_if_fail (style != NULL, FALSE); g_return_val_if_fail (style->layout != NULL, FALSE); for (i = 0; i < META_BUTTON_FUNCTION_LAST; i++) { /* for now the "positional" buttons are optional */ if (i >= META_BUTTON_FUNCTION_CLOSE) { for (j = 0; j < META_BUTTON_STATE_LAST; j++) { guint earliest_version; earliest_version = meta_theme_metacity_earliest_version_with_button (i); if (meta_frame_style_get_button (style, i, j) == NULL && earliest_version <= current_theme_version) { g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED, _("