summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlberts Muktupāvels <alberts.muktupavels@gmail.com>2016-02-04 00:15:47 +0200
committerAlberts Muktupāvels <alberts.muktupavels@gmail.com>2016-02-04 00:15:47 +0200
commit99f79563ae5e2c777544ec59cfdbfb8e4f38c162 (patch)
tree07e49b63dc34e277d007f8a5c1608f985384a523
parentaac68269e8a2909ae510e9eb5ffe1f627bd408ee (diff)
downloadmetacity-99f79563ae5e2c777544ec59cfdbfb8e4f38c162.tar.gz
theme: move get_frame_borders, calc_geometry and draw_frame
-rw-r--r--libmetacity/meta-theme-gtk.c884
-rw-r--r--libmetacity/meta-theme-impl-private.h66
-rw-r--r--libmetacity/meta-theme-impl.c190
-rw-r--r--libmetacity/meta-theme-metacity-private.h2
-rw-r--r--libmetacity/meta-theme-metacity.c815
-rw-r--r--libmetacity/meta-theme.c124
-rw-r--r--libmetacity/meta-theme.h31
-rw-r--r--src/ui/theme.c1573
-rw-r--r--src/ui/theme.h30
9 files changed, 2085 insertions, 1630 deletions
diff --git a/libmetacity/meta-theme-gtk.c b/libmetacity/meta-theme-gtk.c
index 57f00f07..866bd962 100644
--- a/libmetacity/meta-theme-gtk.c
+++ b/libmetacity/meta-theme-gtk.c
@@ -18,6 +18,7 @@
#include "config.h"
#include <gtk/gtk.h>
+#include <string.h>
#include "meta-frame-style.h"
#include "meta-theme-gtk-private.h"
@@ -139,6 +140,886 @@ meta_theme_gtk_get_name (MetaThemeImpl *impl)
}
static void
+get_margin (GtkStyleContext *style,
+ GtkBorder *border)
+{
+ GtkStateFlags state;
+
+ state = gtk_style_context_get_state (style);
+
+ gtk_style_context_get_margin (style, state, border);
+}
+
+static void
+get_padding_and_border (GtkStyleContext *style,
+ GtkBorder *border)
+{
+ GtkBorder tmp;
+ GtkStateFlags state = gtk_style_context_get_state (style);
+
+ gtk_style_context_get_border (style, state, border);
+ gtk_style_context_get_padding (style, state, &tmp);
+
+ border->left += tmp.left;
+ border->top += tmp.top;
+ border->right += tmp.right;
+ border->bottom += tmp.bottom;
+}
+
+static void
+scale_border (GtkBorder *border,
+ double factor)
+{
+ border->left *= factor;
+ border->right *= factor;
+ border->top *= factor;
+ border->bottom *= factor;
+}
+
+static void
+frame_layout_sync_with_style (MetaFrameLayout *layout,
+ MetaStyleInfo *style_info,
+ gboolean composited,
+ MetaFrameFlags flags)
+{
+ GtkStyleContext *style;
+ GtkBorder border;
+ int border_radius, max_radius;
+
+ meta_style_info_set_flags (style_info, flags);
+
+ layout->button_sizing = META_BUTTON_SIZING_FIXED;
+
+ style = style_info->styles[META_STYLE_ELEMENT_DECORATION];
+ get_padding_and_border (style, &border);
+ scale_border (&border, layout->title_scale);
+
+ layout->left_width = border.left;
+ layout->right_width = border.right;
+ layout->top_height = border.top;
+ layout->bottom_height = border.bottom;
+
+ if (composited)
+ get_margin (style, &layout->invisible_border);
+ else
+ {
+ get_margin (style, &border);
+
+ layout->left_width += border.left;
+ layout->right_width += border.right;
+ layout->top_height += border.top;
+ layout->bottom_height += border.bottom;
+ }
+
+ if (layout->hide_buttons)
+ layout->icon_size = 0;
+
+ if (!layout->has_title && layout->hide_buttons)
+ return; /* border-only - be done */
+
+ style = style_info->styles[META_STYLE_ELEMENT_TITLEBAR];
+
+ if (composited)
+ {
+ gtk_style_context_get (style, gtk_style_context_get_state (style),
+ "border-radius", &border_radius,
+ NULL);
+ /* GTK+ currently does not allow us to look up radii of individual
+ * corners; however we don't clip the client area, so with the
+ * current trend of using small/no visible frame borders, most
+ * themes should work fine with this.
+ */
+ layout->top_left_corner_rounded_radius = border_radius;
+ layout->top_right_corner_rounded_radius = border_radius;
+ max_radius = MIN (layout->bottom_height, layout->left_width);
+ layout->bottom_left_corner_rounded_radius = MAX (border_radius, max_radius);
+ max_radius = MIN (layout->bottom_height, layout->right_width);
+ layout->bottom_right_corner_rounded_radius = MAX (border_radius, max_radius);
+ }
+
+ get_padding_and_border (style, &border);
+ scale_border (&border, layout->title_scale);
+ layout->left_titlebar_edge = layout->left_width + border.left;
+ layout->right_titlebar_edge = layout->right_width + border.right;
+ layout->title_vertical_pad = border.top;
+
+ layout->button_border.top = border.top;
+ layout->button_border.bottom = border.bottom;
+ layout->button_border.left = 0;
+ layout->button_border.right = 0;
+
+ layout->button_width = layout->icon_size;
+ layout->button_height = layout->icon_size;
+
+ style = style_info->styles[META_STYLE_ELEMENT_BUTTON];
+ get_padding_and_border (style, &border);
+ scale_border (&border, layout->title_scale);
+ layout->button_width += border.left + border.right;
+ layout->button_height += border.top + border.bottom;
+
+ style = style_info->styles[META_STYLE_ELEMENT_IMAGE];
+ get_padding_and_border (style, &border);
+ scale_border (&border, layout->title_scale);
+ layout->button_width += border.left + border.right;
+ layout->button_height += border.top + border.bottom;
+}
+
+static void
+meta_theme_gtk_get_frame_borders (MetaThemeImpl *impl,
+ MetaFrameLayout *layout,
+ MetaStyleInfo *style_info,
+ gboolean composited,
+ gint text_height,
+ MetaFrameFlags flags,
+ MetaFrameType type,
+ MetaFrameBorders *borders)
+{
+ int buttons_height, title_height;
+
+ frame_layout_sync_with_style (layout, style_info, composited, flags);
+
+ meta_frame_borders_clear (borders);
+
+ /* For a full-screen window, we don't have any borders, visible or not. */
+ if (flags & META_FRAME_FULLSCREEN)
+ return;
+
+ g_return_if_fail (layout != NULL);
+
+ if (!layout->has_title)
+ text_height = 0;
+
+ buttons_height = layout->button_height +
+ layout->button_border.top + layout->button_border.bottom;
+ title_height = text_height +
+ layout->title_vertical_pad +
+ layout->title_border.top + layout->title_border.bottom;
+
+ borders->visible.top = layout->top_height + MAX (buttons_height, title_height);
+ borders->visible.left = layout->left_width;
+ borders->visible.right = layout->right_width;
+ borders->visible.bottom = layout->bottom_height;
+
+ /* FIXME: invisible = MAX (margin, shadow) */
+ borders->invisible.left = layout->invisible_border.left;
+ borders->invisible.right = layout->invisible_border.right;
+ borders->invisible.bottom = layout->invisible_border.bottom;
+ borders->invisible.top = layout->invisible_border.top;
+
+ /*
+ if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
+ {
+ borders->invisible.left = layout->invisible_border.left;
+ borders->invisible.right = layout->invisible_border.right;
+ }
+
+ if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
+ {
+ borders->invisible.bottom = layout->invisible_border.bottom;
+
+ if (type != META_FRAME_TYPE_ATTACHED)
+ borders->invisible.top = layout->invisible_border.top;
+ }
+ */
+
+ borders->total.left = borders->invisible.left + borders->visible.left;
+ borders->total.right = borders->invisible.right + borders->visible.right;
+ borders->total.bottom = borders->invisible.bottom + borders->visible.bottom;
+ borders->total.top = borders->invisible.top + borders->visible.top;
+}
+
+static MetaButtonSpace *
+rect_for_function (MetaFrameGeometry *fgeom,
+ MetaFrameFlags flags,
+ MetaButtonFunction function)
+{
+ switch (function)
+ {
+ case META_BUTTON_FUNCTION_MENU:
+ if (flags & META_FRAME_ALLOWS_MENU)
+ return &fgeom->menu_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_APPMENU:
+ if (flags & META_FRAME_ALLOWS_APPMENU)
+ return &fgeom->appmenu_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_MINIMIZE:
+ if (flags & META_FRAME_ALLOWS_MINIMIZE)
+ return &fgeom->min_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_MAXIMIZE:
+ if (flags & META_FRAME_ALLOWS_MAXIMIZE)
+ return &fgeom->max_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_CLOSE:
+ if (flags & META_FRAME_ALLOWS_DELETE)
+ return &fgeom->close_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_SHADE:
+ if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
+ return &fgeom->shade_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_ABOVE:
+ if (!(flags & META_FRAME_ABOVE))
+ return &fgeom->above_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_STICK:
+ if (!(flags & META_FRAME_STUCK))
+ return &fgeom->stick_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_UNSHADE:
+ if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
+ return &fgeom->unshade_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_UNABOVE:
+ if (flags & META_FRAME_ABOVE)
+ return &fgeom->unabove_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_UNSTICK:
+ if (flags & META_FRAME_STUCK)
+ return &fgeom->unstick_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_LAST:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static gboolean
+strip_button (MetaButtonSpace *func_rects[META_BUTTON_FUNCTION_LAST],
+ GdkRectangle *bg_rects[META_BUTTON_FUNCTION_LAST],
+ int *n_rects,
+ MetaButtonSpace *to_strip)
+{
+ int i;
+
+ i = 0;
+ while (i < *n_rects)
+ {
+ if (func_rects[i] == to_strip)
+ {
+ *n_rects -= 1;
+
+ /* shift the other rects back in the array */
+ while (i < *n_rects)
+ {
+ func_rects[i] = func_rects[i+1];
+ bg_rects[i] = bg_rects[i+1];
+
+ ++i;
+ }
+
+ func_rects[i] = NULL;
+ bg_rects[i] = NULL;
+
+ return TRUE;
+ }
+
+ ++i;
+ }
+
+ return FALSE; /* did not strip anything */
+}
+
+static void
+meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
+ MetaFrameLayout *layout,
+ MetaStyleInfo *style_info,
+ gboolean composited,
+ gint text_height,
+ MetaFrameFlags flags,
+ gint client_width,
+ gint client_height,
+ const MetaButtonLayout *button_layout,
+ MetaFrameType type,
+ MetaFrameGeometry *fgeom)
+{
+ MetaFrameBorders borders;
+ int i, n_left, n_right, n_left_spacers, n_right_spacers;
+ int x;
+ int button_y;
+ int title_right_edge;
+ int width, height;
+ int button_width, button_height;
+ int min_size_for_rounding;
+
+ /* the left/right rects in order; the max # of rects
+ * is the number of button functions
+ */
+ MetaButtonSpace *left_func_rects[META_BUTTON_FUNCTION_LAST];
+ MetaButtonSpace *right_func_rects[META_BUTTON_FUNCTION_LAST];
+ GdkRectangle *left_bg_rects[META_BUTTON_FUNCTION_LAST];
+ gboolean left_buttons_has_spacer[META_BUTTON_FUNCTION_LAST];
+ GdkRectangle *right_bg_rects[META_BUTTON_FUNCTION_LAST];
+ gboolean right_buttons_has_spacer[META_BUTTON_FUNCTION_LAST];
+
+ META_THEME_IMPL_GET_CLASS (impl)->get_frame_borders (impl, layout,
+ style_info, composited,
+ text_height, flags,
+ type, &borders);
+
+ fgeom->borders = borders;
+ fgeom->top_height = layout->top_height;
+
+ width = client_width + borders.total.left + borders.total.right;
+
+ height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
+ borders.total.top + borders.total.bottom;
+
+ fgeom->width = width;
+ fgeom->height = height;
+
+ fgeom->top_titlebar_edge = layout->title_border.top;
+ fgeom->bottom_titlebar_edge = layout->title_border.bottom;
+ fgeom->left_titlebar_edge = layout->left_titlebar_edge;
+ fgeom->right_titlebar_edge = layout->right_titlebar_edge;
+
+ /* gcc warnings */
+ button_width = -1;
+ button_height = -1;
+
+ switch (layout->button_sizing)
+ {
+ case META_BUTTON_SIZING_ASPECT:
+ button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom;
+ button_width = button_height / layout->button_aspect;
+ break;
+ case META_BUTTON_SIZING_FIXED:
+ button_width = layout->button_width;
+ button_height = layout->button_height;
+ break;
+ case META_BUTTON_SIZING_LAST:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* FIXME all this code sort of pretends that duplicate buttons
+ * with the same function are allowed, but that breaks the
+ * code in frames.c, so isn't really allowed right now.
+ * Would need left_close_rect, right_close_rect, etc.
+ */
+
+ /* Init all button rects to 0, lame hack */
+ memset (ADDRESS_OF_BUTTON_RECTS (fgeom), '\0',
+ LENGTH_OF_BUTTON_RECTS);
+
+ n_left = 0;
+ n_right = 0;
+ n_left_spacers = 0;
+ n_right_spacers = 0;
+
+ if (!layout->hide_buttons)
+ {
+ /* Try to fill in rects */
+ for (i = 0; i < META_BUTTON_FUNCTION_LAST && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
+ {
+ left_func_rects[n_left] = rect_for_function (fgeom, flags,
+ button_layout->left_buttons[i]);
+ if (left_func_rects[n_left] != NULL)
+ {
+ left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
+ if (button_layout->left_buttons_has_spacer[i])
+ ++n_left_spacers;
+
+ ++n_left;
+ }
+ }
+
+ for (i = 0; i < META_BUTTON_FUNCTION_LAST && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
+ {
+ right_func_rects[n_right] = rect_for_function (fgeom, flags,
+ button_layout->right_buttons[i]);
+ if (right_func_rects[n_right] != NULL)
+ {
+ right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
+ if (button_layout->right_buttons_has_spacer[i])
+ ++n_right_spacers;
+
+ ++n_right;
+ }
+ }
+ }
+
+ for (i = 0; i < META_BUTTON_FUNCTION_LAST; i++)
+ {
+ left_bg_rects[i] = NULL;
+ right_bg_rects[i] = NULL;
+ }
+
+ for (i = 0; i < n_left; i++)
+ {
+ if (n_left == 1)
+ left_bg_rects[i] = &fgeom->left_single_background;
+ else if (i == 0)
+ left_bg_rects[i] = &fgeom->left_left_background;
+ else if (i == (n_left - 1))
+ left_bg_rects[i] = &fgeom->left_right_background;
+ else
+ left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
+ }
+
+ for (i = 0; i < n_right; i++)
+ {
+ if (n_right == 1)
+ right_bg_rects[i] = &fgeom->right_single_background;
+ else if (i == (n_right - 1))
+ right_bg_rects[i] = &fgeom->right_right_background;
+ else if (i == 0)
+ right_bg_rects[i] = &fgeom->right_left_background;
+ else
+ right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
+ }
+
+ /* Be sure buttons fit */
+ while (n_left > 0 || n_right > 0)
+ {
+ int space_used_by_buttons;
+ int space_available;
+
+ space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
+
+ space_used_by_buttons = 0;
+
+ space_used_by_buttons += button_width * n_left;
+ space_used_by_buttons += (button_width * 0.75) * n_left_spacers;
+ space_used_by_buttons += layout->titlebar_spacing * MAX (n_left - 1, 0);
+
+ space_used_by_buttons += button_width * n_right;
+ space_used_by_buttons += (button_width * 0.75) * n_right_spacers;
+ space_used_by_buttons += layout->titlebar_spacing * MAX (n_right - 1, 0);
+
+ if (space_used_by_buttons <= space_available)
+ break; /* Everything fits, bail out */
+
+ /* First try to remove separators */
+ if (n_left_spacers > 0)
+ {
+ left_buttons_has_spacer[--n_left_spacers] = FALSE;
+ continue;
+ }
+ else if (n_right_spacers > 0)
+ {
+ right_buttons_has_spacer[--n_right_spacers] = FALSE;
+ continue;
+ }
+
+ /* Otherwise we need to shave out a button. Shave
+ * above, stick, shade, min, max, close, then menu (menu is most useful);
+ * prefer the default button locations.
+ */
+ if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->above_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->above_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->stick_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->stick_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->shade_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->shade_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->min_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->min_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->max_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->max_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->close_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->close_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->menu_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->menu_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->appmenu_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->appmenu_rect))
+ continue;
+ else
+ {
+ g_error ("Could not find a button to strip. n_left = %d n_right = %d",
+ n_left, n_right);
+ }
+ }
+
+ /* Save the button layout */
+ fgeom->button_layout = *button_layout;
+ fgeom->n_left_buttons = n_left;
+ fgeom->n_right_buttons = n_right;
+
+ /* center buttons vertically */
+ button_y = (borders.visible.top - fgeom->top_height -
+ (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + fgeom->top_height + borders.invisible.top;
+
+ /* right edge of farthest-right button */
+ x = width - layout->right_titlebar_edge - borders.invisible.right;
+
+ i = n_right - 1;
+ while (i >= 0)
+ {
+ MetaButtonSpace *rect;
+
+ if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
+ break;
+
+ rect = right_func_rects[i];
+
+ rect->visible.x = x - button_width;
+ if (right_buttons_has_spacer[i])
+ rect->visible.x -= (button_width * 0.75);
+
+ rect->visible.y = button_y;
+ rect->visible.width = button_width;
+ rect->visible.height = button_height;
+
+ if (flags & META_FRAME_MAXIMIZED ||
+ flags & META_FRAME_TILED_LEFT ||
+ flags & META_FRAME_TILED_RIGHT)
+ {
+ rect->clickable.x = rect->visible.x;
+ rect->clickable.y = rect->visible.y;
+ rect->clickable.width = button_width;
+ rect->clickable.height = button_height;
+
+ if (i == n_right - 1)
+ rect->clickable.width += layout->right_titlebar_edge + layout->right_width;
+ }
+ else
+ g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
+
+ *(right_bg_rects[i]) = rect->visible;
+
+ x = rect->visible.x;
+
+ if (i > 0)
+ x -= layout->titlebar_spacing;
+
+ --i;
+ }
+
+ /* save right edge of titlebar for later use */
+ title_right_edge = x - layout->title_border.right;
+
+ /* Now x changes to be position from the left and we go through
+ * the left-side buttons
+ */
+ x = layout->left_titlebar_edge + borders.invisible.left;
+ for (i = 0; i < n_left; i++)
+ {
+ MetaButtonSpace *rect;
+
+ rect = left_func_rects[i];
+
+ rect->visible.x = x;
+ rect->visible.y = button_y;
+ rect->visible.width = button_width;
+ rect->visible.height = button_height;
+
+ if (flags & META_FRAME_MAXIMIZED)
+ {
+ rect->clickable.x = rect->visible.x;
+ rect->clickable.y = rect->visible.y;
+ rect->clickable.width = button_width;
+ rect->clickable.height = button_height;
+ }
+ else
+ g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
+
+ x = rect->visible.x + rect->visible.width;
+ if (i < n_left - 1)
+ x += layout->titlebar_spacing;
+ if (left_buttons_has_spacer[i])
+ x += (button_width * 0.75);
+
+ *(left_bg_rects[i]) = rect->visible;
+ }
+
+ /* We always fill as much vertical space as possible with title rect,
+ * rather than centering it like the buttons
+ */
+ fgeom->title_rect.x = x + layout->title_border.left;
+ fgeom->title_rect.y = layout->title_border.top + borders.invisible.top;
+ fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
+ fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom;
+
+ /* Nuke title if it won't fit */
+ if (fgeom->title_rect.width < 0 ||
+ fgeom->title_rect.height < 0)
+ {
+ fgeom->title_rect.width = 0;
+ fgeom->title_rect.height = 0;
+ }
+
+ if (flags & META_FRAME_SHADED)
+ min_size_for_rounding = 0;
+ else
+ min_size_for_rounding = 5;
+
+ fgeom->top_left_corner_rounded_radius = 0;
+ fgeom->top_right_corner_rounded_radius = 0;
+ fgeom->bottom_left_corner_rounded_radius = 0;
+ fgeom->bottom_right_corner_rounded_radius = 0;
+
+ if (borders.visible.top + borders.visible.left >= min_size_for_rounding)
+ fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
+ if (borders.visible.top + borders.visible.right >= min_size_for_rounding)
+ fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
+
+ if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding)
+ fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
+ if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding)
+ fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
+}
+
+static const char *
+get_class_from_button_type (MetaButtonType type)
+{
+ if (type == META_BUTTON_TYPE_CLOSE)
+ return "close";
+ else if (type == META_BUTTON_TYPE_MAXIMIZE)
+ return "maximize";
+ else if (type == META_BUTTON_TYPE_MINIMIZE)
+ return "minimize";
+
+ return NULL;
+}
+
+static void
+meta_theme_gtk_draw_frame (MetaThemeImpl *impl,
+ MetaFrameStyle *style,
+ MetaStyleInfo *style_info,
+ cairo_t *cr,
+ const MetaFrameGeometry *fgeom,
+ PangoLayout *title_layout,
+ MetaFrameFlags flags,
+ MetaButtonState button_states[META_BUTTON_TYPE_LAST],
+ GdkPixbuf *mini_icon,
+ GdkPixbuf *icon)
+{
+ GtkStyleContext *context;
+ GtkStateFlags state;
+ MetaButtonType button_type;
+ GdkRectangle visible_rect;
+ GdkRectangle titlebar_rect;
+ GdkRectangle button_rect;
+ const MetaFrameBorders *borders;
+
+ borders = &fgeom->borders;
+
+ visible_rect.x = borders->invisible.left;
+ visible_rect.y = borders->invisible.top;
+ visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
+ visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
+
+ meta_style_info_set_flags (style_info, flags);
+
+ context = style_info->styles[META_STYLE_ELEMENT_DECORATION];
+ gtk_render_background (context, cr,
+ visible_rect.x, visible_rect.y,
+ visible_rect.width, visible_rect.height);
+ gtk_render_frame (context, cr,
+ visible_rect.x, visible_rect.y,
+ visible_rect.width, visible_rect.height);
+
+ titlebar_rect.x = visible_rect.x + borders->visible.left;
+ titlebar_rect.y = visible_rect.y + fgeom->top_height;
+ titlebar_rect.width = visible_rect.width - borders->visible.left - borders->visible.right;
+ titlebar_rect.height = borders->visible.top - fgeom->top_height;
+
+ context = style_info->styles[META_STYLE_ELEMENT_TITLEBAR];
+ gtk_render_background (context, cr,
+ titlebar_rect.x, titlebar_rect.y,
+ titlebar_rect.width, titlebar_rect.height);
+ gtk_render_frame (context, cr,
+ titlebar_rect.x, titlebar_rect.y,
+ titlebar_rect.width, titlebar_rect.height);
+
+ if (style->layout->has_title && title_layout)
+ {
+ PangoRectangle logical;
+ int text_width, x, y;
+
+ pango_layout_set_width (title_layout, -1);
+ pango_layout_get_pixel_extents (title_layout, NULL, &logical);
+
+ text_width = MIN(fgeom->title_rect.width, logical.width);
+
+ if (text_width < logical.width)
+ pango_layout_set_width (title_layout, PANGO_SCALE * text_width);
+
+ /* Center within the frame if possible */
+ x = titlebar_rect.x + (titlebar_rect.width - text_width) / 2;
+ y = titlebar_rect.y + (titlebar_rect.height - logical.height) / 2;
+
+ if (x < fgeom->title_rect.x)
+ x = fgeom->title_rect.x;
+ else if (x + text_width > fgeom->title_rect.x + fgeom->title_rect.width)
+ x = fgeom->title_rect.x + fgeom->title_rect.width - text_width;
+
+ context = style_info->styles[META_STYLE_ELEMENT_TITLE];
+ gtk_render_layout (context, cr, x, y, title_layout);
+ }
+
+ context = style_info->styles[META_STYLE_ELEMENT_BUTTON];
+ state = gtk_style_context_get_state (context);
+ for (button_type = META_BUTTON_TYPE_CLOSE; button_type < META_BUTTON_TYPE_LAST; button_type++)
+ {
+ MetaButtonState button_state;
+ const char *button_class;
+
+ button_class = get_class_from_button_type (button_type);
+
+ if (button_class)
+ gtk_style_context_add_class (context, button_class);
+
+ get_button_rect (button_type, fgeom, 0, &button_rect);
+
+ button_state = map_button_state (button_type, fgeom, 0, button_states);
+
+ if (button_state == META_BUTTON_STATE_PRELIGHT)
+ gtk_style_context_set_state (context, state | GTK_STATE_PRELIGHT);
+ else if (button_state == META_BUTTON_STATE_PRESSED)
+ gtk_style_context_set_state (context, state | GTK_STATE_ACTIVE);
+ else
+ gtk_style_context_set_state (context, state);
+
+ cairo_save (cr);
+
+ if (button_rect.width > 0 && button_rect.height > 0)
+ {
+ GdkPixbuf *pixbuf = NULL;
+ const char *icon_name = NULL;
+
+ gtk_render_background (context, cr,
+ button_rect.x, button_rect.y,
+ button_rect.width, button_rect.height);
+ gtk_render_frame (context, cr,
+ button_rect.x, button_rect.y,
+ button_rect.width, button_rect.height);
+
+ switch (button_type)
+ {
+ case META_BUTTON_TYPE_CLOSE:
+ icon_name = "window-close-symbolic";
+ break;
+ case META_BUTTON_TYPE_MAXIMIZE:
+ if (flags & META_FRAME_MAXIMIZED)
+ icon_name = "window-restore-symbolic";
+ else
+ icon_name = "window-maximize-symbolic";
+ break;
+ case META_BUTTON_TYPE_MINIMIZE:
+ icon_name = "window-minimize-symbolic";
+ break;
+ case META_BUTTON_TYPE_MENU:
+ icon_name = "open-menu-symbolic";
+ break;
+ case META_BUTTON_TYPE_APPMENU:
+ pixbuf = g_object_ref (mini_icon);
+ break;
+ case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
+ case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
+ case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
+ case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
+ case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
+ case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
+ case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
+ case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
+ case META_BUTTON_TYPE_SHADE:
+ case META_BUTTON_TYPE_ABOVE:
+ case META_BUTTON_TYPE_STICK:
+ case META_BUTTON_TYPE_UNSHADE:
+ case META_BUTTON_TYPE_UNABOVE:
+ case META_BUTTON_TYPE_UNSTICK:
+ case META_BUTTON_TYPE_LAST:
+ default:
+ icon_name = NULL;
+ break;
+ }
+
+ if (icon_name)
+ {
+ GtkIconTheme *theme = gtk_icon_theme_get_default ();
+ GtkIconInfo *info;
+
+ info = gtk_icon_theme_lookup_icon (theme, icon_name, style->layout->icon_size, 0);
+ pixbuf = gtk_icon_info_load_symbolic_for_context (info, context, NULL, NULL);
+ }
+
+ if (pixbuf)
+ {
+ float width, height;
+ int x, y;
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ x = button_rect.x + (button_rect.width - width) / 2;
+ y = button_rect.y + (button_rect.height - height) / 2;
+
+ cairo_translate (cr, x, y);
+ cairo_scale (cr,
+ width / style->layout->icon_size,
+ height / style->layout->icon_size);
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+ cairo_paint (cr);
+
+ g_object_unref (pixbuf);
+ }
+ }
+
+ cairo_restore (cr);
+
+ if (button_class)
+ gtk_style_context_remove_class (context, button_class);
+ }
+}
+
+static void
meta_theme_gtk_class_init (MetaThemeGtkClass *gtk_class)
{
MetaThemeImplClass *impl_class;
@@ -147,6 +1028,9 @@ meta_theme_gtk_class_init (MetaThemeGtkClass *gtk_class)
impl_class->load = meta_theme_gtk_load;
impl_class->get_name = meta_theme_gtk_get_name;
+ impl_class->get_frame_borders = meta_theme_gtk_get_frame_borders;
+ impl_class->calc_geometry = meta_theme_gtk_calc_geometry;
+ impl_class->draw_frame = meta_theme_gtk_draw_frame;
}
static void
diff --git a/libmetacity/meta-theme-impl-private.h b/libmetacity/meta-theme-impl-private.h
index ec83bc44..5278f55c 100644
--- a/libmetacity/meta-theme-impl-private.h
+++ b/libmetacity/meta-theme-impl-private.h
@@ -18,13 +18,15 @@
#ifndef META_THEME_IMPL_PRIVATE_H
#define META_THEME_IMPL_PRIVATE_H
-#include <glib-object.h>
-
+#include "meta-button-layout.h"
#include "meta-frame-enums.h"
#include "meta-frame-style.h"
+#include "meta-style-info.h"
G_BEGIN_DECLS
+typedef struct _MetaFrameGeometry MetaFrameGeometry;
+
#define META_TYPE_THEME_IMPL meta_theme_impl_get_type ()
G_DECLARE_DERIVABLE_TYPE (MetaThemeImpl, meta_theme_impl,
META, THEME_IMPL, GObject)
@@ -33,19 +35,61 @@ struct _MetaThemeImplClass
{
GObjectClass parent_class;
- gboolean (* load) (MetaThemeImpl *impl,
- const gchar *name,
- GError **error);
+ gboolean (* load) (MetaThemeImpl *impl,
+ const gchar *name,
+ GError **error);
+
+ gchar * (* get_name) (MetaThemeImpl *impl);
+
+ void (* get_frame_borders) (MetaThemeImpl *impl,
+ MetaFrameLayout *layout,
+ MetaStyleInfo *style_info,
+ gboolean composited,
+ gint text_height,
+ MetaFrameFlags flags,
+ MetaFrameType type,
+ MetaFrameBorders *borders);
- gchar * (* get_name) (MetaThemeImpl *impl);
+ void (* calc_geometry) (MetaThemeImpl *impl,
+ MetaFrameLayout *layout,
+ MetaStyleInfo *style_info,
+ gboolean composited,
+ gint text_height,
+ MetaFrameFlags flags,
+ gint client_width,
+ gint client_height,
+ const MetaButtonLayout *button_layout,
+ MetaFrameType type,
+ MetaFrameGeometry *fgeom);
+
+ void (* draw_frame) (MetaThemeImpl *impl,
+ MetaFrameStyle *style,
+ MetaStyleInfo *style_info,
+ cairo_t *cr,
+ const MetaFrameGeometry *fgeom,
+ PangoLayout *title_layout,
+ MetaFrameFlags flags,
+ MetaButtonState button_states[META_BUTTON_TYPE_LAST],
+ GdkPixbuf *mini_icon,
+ GdkPixbuf *icon);
};
-void meta_theme_impl_add_style_set (MetaThemeImpl *impl,
- MetaFrameType type,
- MetaFrameStyleSet *style_set);
+void meta_theme_impl_add_style_set (MetaThemeImpl *impl,
+ MetaFrameType type,
+ MetaFrameStyleSet *style_set);
+
+MetaFrameStyleSet *meta_theme_impl_get_style_set (MetaThemeImpl *impl,
+ MetaFrameType type);
+
+void get_button_rect (MetaButtonType type,
+ const MetaFrameGeometry *fgeom,
+ gint middle_background_offset,
+ GdkRectangle *rect);
-MetaFrameStyleSet *meta_theme_impl_get_style_set (MetaThemeImpl *impl,
- MetaFrameType type);
+MetaButtonState map_button_state (MetaButtonType button_type,
+ const MetaFrameGeometry *fgeom,
+ gint middle_bg_offset,
+ MetaButtonState button_states[META_BUTTON_TYPE_LAST]);
G_END_DECLS
diff --git a/libmetacity/meta-theme-impl.c b/libmetacity/meta-theme-impl.c
index 6bf87f34..a454f902 100644
--- a/libmetacity/meta-theme-impl.c
+++ b/libmetacity/meta-theme-impl.c
@@ -30,6 +30,42 @@ typedef struct
G_DEFINE_TYPE_WITH_PRIVATE (MetaThemeImpl, meta_theme_impl, G_TYPE_OBJECT)
+static MetaButtonType
+map_button_function_to_type (MetaButtonFunction function)
+{
+ switch (function)
+ {
+ case META_BUTTON_FUNCTION_SHADE:
+ return META_BUTTON_TYPE_SHADE;
+ case META_BUTTON_FUNCTION_ABOVE:
+ return META_BUTTON_TYPE_ABOVE;
+ case META_BUTTON_FUNCTION_STICK:
+ return META_BUTTON_TYPE_STICK;
+ case META_BUTTON_FUNCTION_UNSHADE:
+ return META_BUTTON_TYPE_UNSHADE;
+ case META_BUTTON_FUNCTION_UNABOVE:
+ return META_BUTTON_TYPE_UNABOVE;
+ case META_BUTTON_FUNCTION_UNSTICK:
+ return META_BUTTON_TYPE_UNSTICK;
+ case META_BUTTON_FUNCTION_MENU:
+ return META_BUTTON_TYPE_MENU;
+ case META_BUTTON_FUNCTION_APPMENU:
+ return META_BUTTON_TYPE_APPMENU;
+ case META_BUTTON_FUNCTION_MINIMIZE:
+ return META_BUTTON_TYPE_MINIMIZE;
+ case META_BUTTON_FUNCTION_MAXIMIZE:
+ return META_BUTTON_TYPE_MAXIMIZE;
+ case META_BUTTON_FUNCTION_CLOSE:
+ return META_BUTTON_TYPE_CLOSE;
+ case META_BUTTON_FUNCTION_LAST:
+ return META_BUTTON_TYPE_LAST;
+ default:
+ break;
+ }
+
+ return META_BUTTON_TYPE_LAST;
+}
+
static void
meta_theme_impl_dispose (GObject *object)
{
@@ -115,3 +151,157 @@ meta_theme_impl_get_style_set (MetaThemeImpl *impl,
return priv->style_sets_by_type[type];
}
+
+void
+get_button_rect (MetaButtonType type,
+ const MetaFrameGeometry *fgeom,
+ gint middle_background_offset,
+ GdkRectangle *rect)
+{
+ switch (type)
+ {
+ case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
+ *rect = fgeom->left_left_background;
+ break;
+
+ case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
+ *rect = fgeom->left_middle_backgrounds[middle_background_offset];
+ break;
+
+ case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
+ *rect = fgeom->left_right_background;
+ break;
+
+ case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
+ *rect = fgeom->left_single_background;
+ break;
+
+ case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
+ *rect = fgeom->right_left_background;
+ break;
+
+ case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
+ *rect = fgeom->right_middle_backgrounds[middle_background_offset];
+ break;
+
+ case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
+ *rect = fgeom->right_right_background;
+ break;
+
+ case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
+ *rect = fgeom->right_single_background;
+ break;
+
+ case META_BUTTON_TYPE_CLOSE:
+ *rect = fgeom->close_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_SHADE:
+ *rect = fgeom->shade_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_UNSHADE:
+ *rect = fgeom->unshade_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_ABOVE:
+ *rect = fgeom->above_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_UNABOVE:
+ *rect = fgeom->unabove_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_STICK:
+ *rect = fgeom->stick_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_UNSTICK:
+ *rect = fgeom->unstick_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_MAXIMIZE:
+ *rect = fgeom->max_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_MINIMIZE:
+ *rect = fgeom->min_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_MENU:
+ *rect = fgeom->menu_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_APPMENU:
+ *rect = fgeom->appmenu_rect.visible;
+ break;
+
+ case META_BUTTON_TYPE_LAST:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+MetaButtonState
+map_button_state (MetaButtonType button_type,
+ const MetaFrameGeometry *fgeom,
+ gint middle_bg_offset,
+ MetaButtonState button_states[META_BUTTON_TYPE_LAST])
+{
+ MetaButtonFunction function = META_BUTTON_FUNCTION_LAST;
+
+ switch (button_type)
+ {
+ /* First handle functions, which map directly */
+ case META_BUTTON_TYPE_SHADE:
+ case META_BUTTON_TYPE_ABOVE:
+ case META_BUTTON_TYPE_STICK:
+ case META_BUTTON_TYPE_UNSHADE:
+ case META_BUTTON_TYPE_UNABOVE:
+ case META_BUTTON_TYPE_UNSTICK:
+ case META_BUTTON_TYPE_MENU:
+ case META_BUTTON_TYPE_APPMENU:
+ case META_BUTTON_TYPE_MINIMIZE:
+ case META_BUTTON_TYPE_MAXIMIZE:
+ case META_BUTTON_TYPE_CLOSE:
+ return button_states[button_type];
+
+ /* Map position buttons to the corresponding function */
+ case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
+ case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
+ if (fgeom->n_right_buttons > 0)
+ function = fgeom->button_layout.right_buttons[0];
+ break;
+ case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
+ if (fgeom->n_right_buttons > 0)
+ function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1];
+ break;
+ case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
+ if (middle_bg_offset + 1 < fgeom->n_right_buttons)
+ function = fgeom->button_layout.right_buttons[middle_bg_offset + 1];
+ break;
+ case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
+ case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
+ if (fgeom->n_left_buttons > 0)
+ function = fgeom->button_layout.left_buttons[0];
+ break;
+ case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
+ if (fgeom->n_left_buttons > 0)
+ function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1];
+ break;
+ case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
+ if (middle_bg_offset + 1 < fgeom->n_left_buttons)
+ function = fgeom->button_layout.left_buttons[middle_bg_offset + 1];
+ break;
+ case META_BUTTON_TYPE_LAST:
+ break;
+ default:
+ break;
+ }
+
+ if (function != META_BUTTON_FUNCTION_LAST)
+ return button_states[map_button_function_to_type (function)];
+
+ return META_BUTTON_STATE_LAST;
+}
diff --git a/libmetacity/meta-theme-metacity-private.h b/libmetacity/meta-theme-metacity-private.h
index 08fe5460..7da67174 100644
--- a/libmetacity/meta-theme-metacity-private.h
+++ b/libmetacity/meta-theme-metacity-private.h
@@ -53,8 +53,6 @@ MetaFrameStyle *meta_theme_metacity_lookup_style (MetaThemeMetacity *
MetaFrameStyleSet *meta_theme_metacity_lookup_style_set (MetaThemeMetacity *metacity,
const gchar *name);
-gboolean meta_theme_metacity_allows_shade_stick_above_buttons (MetaThemeMetacity *metacity);
-
guint meta_theme_metacity_earliest_version_with_button (MetaButtonType type);
G_END_DECLS
diff --git a/libmetacity/meta-theme-metacity.c b/libmetacity/meta-theme-metacity.c
index d98803ae..bb237bea 100644
--- a/libmetacity/meta-theme-metacity.c
+++ b/libmetacity/meta-theme-metacity.c
@@ -20,6 +20,7 @@
#include <glib/gi18n-lib.h>
#include <stdlib.h>
+#include <string.h>
#include "meta-draw-op.h"
#include "meta-frame-layout.h"
@@ -4607,6 +4608,811 @@ meta_theme_metacity_get_name (MetaThemeImpl *impl)
}
static void
+meta_theme_metacity_get_frame_borders (MetaThemeImpl *impl,
+ MetaFrameLayout *layout,
+ MetaStyleInfo *style_info,
+ gboolean composited,
+ gint text_height,
+ MetaFrameFlags flags,
+ MetaFrameType type,
+ MetaFrameBorders *borders)
+{
+ int buttons_height, title_height;
+
+ meta_frame_borders_clear (borders);
+
+ /* For a full-screen window, we don't have any borders, visible or not. */
+ if (flags & META_FRAME_FULLSCREEN)
+ return;
+
+ g_return_if_fail (layout != NULL);
+
+ if (!layout->has_title)
+ text_height = 0;
+
+ buttons_height = layout->button_height +
+ layout->button_border.top + layout->button_border.bottom;
+ title_height = text_height +
+ layout->title_vertical_pad +
+ layout->title_border.top + layout->title_border.bottom;
+
+ borders->visible.top = layout->top_height + MAX (buttons_height, title_height);
+ borders->visible.left = layout->left_width;
+ borders->visible.right = layout->right_width;
+ borders->visible.bottom = layout->bottom_height;
+
+ if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
+ {
+ borders->invisible.left = layout->invisible_border.left;
+ borders->invisible.right = layout->invisible_border.right;
+ }
+
+ if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
+ {
+ borders->invisible.bottom = layout->invisible_border.bottom;
+
+ if (type != META_FRAME_TYPE_ATTACHED)
+ borders->invisible.top = layout->invisible_border.top;
+ }
+
+ borders->total.left = borders->invisible.left + borders->visible.left;
+ borders->total.right = borders->invisible.right + borders->visible.right;
+ borders->total.bottom = borders->invisible.bottom + borders->visible.bottom;
+ borders->total.top = borders->invisible.top + borders->visible.top;
+}
+
+static MetaButtonSpace *
+rect_for_function (MetaThemeMetacity *metacity,
+ MetaFrameGeometry *fgeom,
+ MetaFrameFlags flags,
+ MetaButtonFunction function)
+{
+ if (theme_allows (metacity, META_THEME_SHADE_STICK_ABOVE_BUTTONS))
+ {
+ switch (function)
+ {
+ case META_BUTTON_FUNCTION_SHADE:
+ if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
+ return &fgeom->shade_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_ABOVE:
+ if (!(flags & META_FRAME_ABOVE))
+ return &fgeom->above_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_STICK:
+ if (!(flags & META_FRAME_STUCK))
+ return &fgeom->stick_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_UNSHADE:
+ if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
+ return &fgeom->unshade_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_UNABOVE:
+ if (flags & META_FRAME_ABOVE)
+ return &fgeom->unabove_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_UNSTICK:
+ if (flags & META_FRAME_STUCK)
+ return &fgeom->unstick_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_MENU:
+ case META_BUTTON_FUNCTION_APPMENU:
+ case META_BUTTON_FUNCTION_MINIMIZE:
+ case META_BUTTON_FUNCTION_MAXIMIZE:
+ case META_BUTTON_FUNCTION_CLOSE:
+ case META_BUTTON_FUNCTION_LAST:
+ default:
+ break;
+ }
+
+ /* now consider the buttons which exist in all versions */
+ switch (function)
+ {
+ case META_BUTTON_FUNCTION_MENU:
+ if (flags & META_FRAME_ALLOWS_MENU)
+ return &fgeom->menu_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_APPMENU:
+ if (flags & META_FRAME_ALLOWS_APPMENU)
+ return &fgeom->appmenu_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_MINIMIZE:
+ if (flags & META_FRAME_ALLOWS_MINIMIZE)
+ return &fgeom->min_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_MAXIMIZE:
+ if (flags & META_FRAME_ALLOWS_MAXIMIZE)
+ return &fgeom->max_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_CLOSE:
+ if (flags & META_FRAME_ALLOWS_DELETE)
+ return &fgeom->close_rect;
+ else
+ return NULL;
+
+ case META_BUTTON_FUNCTION_STICK:
+ case META_BUTTON_FUNCTION_SHADE:
+ case META_BUTTON_FUNCTION_ABOVE:
+ case META_BUTTON_FUNCTION_UNSTICK:
+ case META_BUTTON_FUNCTION_UNSHADE:
+ case META_BUTTON_FUNCTION_UNABOVE:
+ /* we are being asked for a >v1 button which hasn't been handled yet,
+ * so obviously we're not in a theme which supports that version.
+ * therefore, we don't show the button. return NULL and all will
+ * be well.
+ */
+ return NULL;
+
+ case META_BUTTON_FUNCTION_LAST:
+ default:
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+strip_button (MetaButtonSpace *func_rects[META_BUTTON_FUNCTION_LAST],
+ GdkRectangle *bg_rects[META_BUTTON_FUNCTION_LAST],
+ int *n_rects,
+ MetaButtonSpace *to_strip)
+{
+ int i;
+
+ i = 0;
+ while (i < *n_rects)
+ {
+ if (func_rects[i] == to_strip)
+ {
+ *n_rects -= 1;
+
+ /* shift the other rects back in the array */
+ while (i < *n_rects)
+ {
+ func_rects[i] = func_rects[i+1];
+ bg_rects[i] = bg_rects[i+1];
+
+ ++i;
+ }
+
+ func_rects[i] = NULL;
+ bg_rects[i] = NULL;
+
+ return TRUE;
+ }
+
+ ++i;
+ }
+
+ return FALSE; /* did not strip anything */
+}
+
+static void
+meta_theme_metacity_calc_geometry (MetaThemeImpl *impl,
+ MetaFrameLayout *layout,
+ MetaStyleInfo *style_info,
+ gboolean composited,
+ gint text_height,
+ MetaFrameFlags flags,
+ gint client_width,
+ gint client_height,
+ const MetaButtonLayout *button_layout,
+ MetaFrameType type,
+ MetaFrameGeometry *fgeom)
+{
+ MetaFrameBorders borders;
+ int i, n_left, n_right, n_left_spacers, n_right_spacers;
+ MetaThemeMetacity *metacity;
+ int x;
+ int button_y;
+ int title_right_edge;
+ int width, height;
+ int button_width, button_height;
+ int min_size_for_rounding;
+
+ /* the left/right rects in order; the max # of rects
+ * is the number of button functions
+ */
+ MetaButtonSpace *left_func_rects[META_BUTTON_FUNCTION_LAST];
+ MetaButtonSpace *right_func_rects[META_BUTTON_FUNCTION_LAST];
+ GdkRectangle *left_bg_rects[META_BUTTON_FUNCTION_LAST];
+ gboolean left_buttons_has_spacer[META_BUTTON_FUNCTION_LAST];
+ GdkRectangle *right_bg_rects[META_BUTTON_FUNCTION_LAST];
+ gboolean right_buttons_has_spacer[META_BUTTON_FUNCTION_LAST];
+
+ META_THEME_IMPL_GET_CLASS (impl)->get_frame_borders (impl, layout,
+ style_info, composited,
+ text_height, flags,
+ type, &borders);
+
+ fgeom->borders = borders;
+ fgeom->top_height = layout->top_height;
+
+ width = client_width + borders.total.left + borders.total.right;
+
+ height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
+ borders.total.top + borders.total.bottom;
+
+ fgeom->width = width;
+ fgeom->height = height;
+
+ fgeom->top_titlebar_edge = layout->title_border.top;
+ fgeom->bottom_titlebar_edge = layout->title_border.bottom;
+ fgeom->left_titlebar_edge = layout->left_titlebar_edge;
+ fgeom->right_titlebar_edge = layout->right_titlebar_edge;
+
+ /* gcc warnings */
+ button_width = -1;
+ button_height = -1;
+
+ switch (layout->button_sizing)
+ {
+ case META_BUTTON_SIZING_ASPECT:
+ button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom;
+ button_width = button_height / layout->button_aspect;
+ break;
+ case META_BUTTON_SIZING_FIXED:
+ button_width = layout->button_width;
+ button_height = layout->button_height;
+ break;
+ case META_BUTTON_SIZING_LAST:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* FIXME all this code sort of pretends that duplicate buttons
+ * with the same function are allowed, but that breaks the
+ * code in frames.c, so isn't really allowed right now.
+ * Would need left_close_rect, right_close_rect, etc.
+ */
+
+ /* Init all button rects to 0, lame hack */
+ memset (ADDRESS_OF_BUTTON_RECTS (fgeom), '\0',
+ LENGTH_OF_BUTTON_RECTS);
+
+ n_left = 0;
+ n_right = 0;
+ n_left_spacers = 0;
+ n_right_spacers = 0;
+
+ metacity = META_THEME_METACITY (impl);
+
+ if (!layout->hide_buttons)
+ {
+ /* Try to fill in rects */
+ for (i = 0; i < META_BUTTON_FUNCTION_LAST && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
+ {
+ left_func_rects[n_left] = rect_for_function (metacity, fgeom, flags,
+ button_layout->left_buttons[i]);
+ if (left_func_rects[n_left] != NULL)
+ {
+ left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
+ if (button_layout->left_buttons_has_spacer[i])
+ ++n_left_spacers;
+
+ ++n_left;
+ }
+ }
+
+ for (i = 0; i < META_BUTTON_FUNCTION_LAST && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
+ {
+ right_func_rects[n_right] = rect_for_function (metacity, fgeom, flags,
+ button_layout->right_buttons[i]);
+ if (right_func_rects[n_right] != NULL)
+ {
+ right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
+ if (button_layout->right_buttons_has_spacer[i])
+ ++n_right_spacers;
+
+ ++n_right;
+ }
+ }
+ }
+
+ for (i = 0; i < META_BUTTON_FUNCTION_LAST; i++)
+ {
+ left_bg_rects[i] = NULL;
+ right_bg_rects[i] = NULL;
+ }
+
+ for (i = 0; i < n_left; i++)
+ {
+ if (n_left == 1)
+ left_bg_rects[i] = &fgeom->left_single_background;
+ else if (i == 0)
+ left_bg_rects[i] = &fgeom->left_left_background;
+ else if (i == (n_left - 1))
+ left_bg_rects[i] = &fgeom->left_right_background;
+ else
+ left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
+ }
+
+ for (i = 0; i < n_right; i++)
+ {
+ if (n_right == 1)
+ right_bg_rects[i] = &fgeom->right_single_background;
+ else if (i == (n_right - 1))
+ right_bg_rects[i] = &fgeom->right_right_background;
+ else if (i == 0)
+ right_bg_rects[i] = &fgeom->right_left_background;
+ else
+ right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
+ }
+
+ /* Be sure buttons fit */
+ while (n_left > 0 || n_right > 0)
+ {
+ int space_used_by_buttons;
+ int space_available;
+
+ space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
+
+ space_used_by_buttons = 0;
+
+ space_used_by_buttons += button_width * n_left;
+ space_used_by_buttons += (button_width * 0.75) * n_left_spacers;
+ space_used_by_buttons += layout->button_border.left * n_left;
+ space_used_by_buttons += layout->button_border.right * n_left;
+
+ space_used_by_buttons += button_width * n_right;
+ space_used_by_buttons += (button_width * 0.75) * n_right_spacers;
+ space_used_by_buttons += layout->button_border.left * n_right;
+ space_used_by_buttons += layout->button_border.right * n_right;
+
+ if (space_used_by_buttons <= space_available)
+ break; /* Everything fits, bail out */
+
+ /* First try to remove separators */
+ if (n_left_spacers > 0)
+ {
+ left_buttons_has_spacer[--n_left_spacers] = FALSE;
+ continue;
+ }
+ else if (n_right_spacers > 0)
+ {
+ right_buttons_has_spacer[--n_right_spacers] = FALSE;
+ continue;
+ }
+
+ /* Otherwise we need to shave out a button. Shave
+ * above, stick, shade, min, max, close, then menu (menu is most useful);
+ * prefer the default button locations.
+ */
+ if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->above_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->above_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->stick_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->stick_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->shade_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->shade_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->min_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->min_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->max_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->max_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->close_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->close_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->menu_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->menu_rect))
+ continue;
+ else if (strip_button (right_func_rects, right_bg_rects,
+ &n_right, &fgeom->appmenu_rect))
+ continue;
+ else if (strip_button (left_func_rects, left_bg_rects,
+ &n_left, &fgeom->appmenu_rect))
+ continue;
+ else
+ {
+ g_error ("Could not find a button to strip. n_left = %d n_right = %d",
+ n_left, n_right);
+ }
+ }
+
+ /* Save the button layout */
+ fgeom->button_layout = *button_layout;
+ fgeom->n_left_buttons = n_left;
+ fgeom->n_right_buttons = n_right;
+
+ /* center buttons vertically */
+ button_y = (borders.visible.top - fgeom->top_height -
+ (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + fgeom->top_height + borders.invisible.top;
+
+ /* right edge of farthest-right button */
+ x = width - layout->right_titlebar_edge - borders.invisible.right;
+
+ i = n_right - 1;
+ while (i >= 0)
+ {
+ MetaButtonSpace *rect;
+
+ if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
+ break;
+
+ rect = right_func_rects[i];
+ rect->visible.x = x - layout->button_border.right - button_width;
+ if (right_buttons_has_spacer[i])
+ rect->visible.x -= (button_width * 0.75);
+
+ rect->visible.y = button_y;
+ rect->visible.width = button_width;
+ rect->visible.height = button_height;
+
+ if (flags & META_FRAME_MAXIMIZED ||
+ flags & META_FRAME_TILED_LEFT ||
+ flags & META_FRAME_TILED_RIGHT)
+ {
+ rect->clickable.x = rect->visible.x;
+ rect->clickable.y = rect->visible.y;
+ rect->clickable.width = button_width;
+ rect->clickable.height = button_height;
+
+ if (i == n_right - 1)
+ rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right;
+ }
+ else
+ g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
+
+ *(right_bg_rects[i]) = rect->visible;
+
+ x = rect->visible.x - layout->button_border.left;
+
+ --i;
+ }
+
+ /* save right edge of titlebar for later use */
+ title_right_edge = x - layout->title_border.right;
+
+ /* Now x changes to be position from the left and we go through
+ * the left-side buttons
+ */
+ x = layout->left_titlebar_edge + borders.invisible.left;
+ for (i = 0; i < n_left; i++)
+ {
+ MetaButtonSpace *rect;
+
+ rect = left_func_rects[i];
+
+ rect->visible.x = x + layout->button_border.left;
+ rect->visible.y = button_y;
+ rect->visible.width = button_width;
+ rect->visible.height = button_height;
+
+ if (flags & META_FRAME_MAXIMIZED)
+ {
+ rect->clickable.x = rect->visible.x;
+ rect->clickable.y = rect->visible.y;
+ rect->clickable.width = button_width;
+ rect->clickable.height = button_height;
+ }
+ else
+ g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
+
+ x = rect->visible.x + rect->visible.width + layout->button_border.right;
+ if (left_buttons_has_spacer[i])
+ x += (button_width * 0.75);
+
+ *(left_bg_rects[i]) = rect->visible;
+ }
+
+ /* We always fill as much vertical space as possible with title rect,
+ * rather than centering it like the buttons
+ */
+ fgeom->title_rect.x = x + layout->title_border.left;
+ fgeom->title_rect.y = layout->title_border.top + borders.invisible.top;
+ fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
+ fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom;
+
+ /* Nuke title if it won't fit */
+ if (fgeom->title_rect.width < 0 ||
+ fgeom->title_rect.height < 0)
+ {
+ fgeom->title_rect.width = 0;
+ fgeom->title_rect.height = 0;
+ }
+
+ if (flags & META_FRAME_SHADED)
+ min_size_for_rounding = 0;
+ else
+ min_size_for_rounding = 5;
+
+ fgeom->top_left_corner_rounded_radius = 0;
+ fgeom->top_right_corner_rounded_radius = 0;
+ fgeom->bottom_left_corner_rounded_radius = 0;
+ fgeom->bottom_right_corner_rounded_radius = 0;
+
+ if (borders.visible.top + borders.visible.left >= min_size_for_rounding)
+ fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
+ if (borders.visible.top + borders.visible.right >= min_size_for_rounding)
+ fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
+
+ if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding)
+ fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
+ if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding)
+ fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
+}
+
+static void
+meta_theme_metacity_draw_frame (MetaThemeImpl *impl,
+ MetaFrameStyle *style,
+ MetaStyleInfo *style_info,
+ cairo_t *cr,
+ const MetaFrameGeometry *fgeom,
+ PangoLayout *title_layout,
+ MetaFrameFlags flags,
+ MetaButtonState button_states[META_BUTTON_TYPE_LAST],
+ GdkPixbuf *mini_icon,
+ GdkPixbuf *icon)
+{
+ int i, j;
+ GdkRectangle visible_rect;
+ GdkRectangle titlebar_rect;
+ GdkRectangle left_titlebar_edge;
+ GdkRectangle right_titlebar_edge;
+ GdkRectangle bottom_titlebar_edge;
+ GdkRectangle top_titlebar_edge;
+ GdkRectangle left_edge, right_edge, bottom_edge;
+ PangoRectangle extents;
+ MetaDrawInfo draw_info;
+ const MetaFrameBorders *borders;
+
+ borders = &fgeom->borders;
+
+ visible_rect.x = borders->invisible.left;
+ visible_rect.y = borders->invisible.top;
+ visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
+ visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
+
+ titlebar_rect.x = visible_rect.x;
+ titlebar_rect.y = visible_rect.y;
+ titlebar_rect.width = visible_rect.width;
+ titlebar_rect.height = borders->visible.top;
+
+ left_titlebar_edge.x = titlebar_rect.x;
+ left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge;
+ left_titlebar_edge.width = fgeom->left_titlebar_edge;
+ left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge;
+
+ right_titlebar_edge.y = left_titlebar_edge.y;
+ right_titlebar_edge.height = left_titlebar_edge.height;
+ right_titlebar_edge.width = fgeom->right_titlebar_edge;
+ right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width;
+
+ top_titlebar_edge.x = titlebar_rect.x;
+ top_titlebar_edge.y = titlebar_rect.y;
+ top_titlebar_edge.width = titlebar_rect.width;
+ top_titlebar_edge.height = fgeom->top_titlebar_edge;
+
+ bottom_titlebar_edge.x = titlebar_rect.x;
+ bottom_titlebar_edge.width = titlebar_rect.width;
+ bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge;
+ bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height;
+
+ left_edge.x = visible_rect.x;
+ left_edge.y = visible_rect.y + borders->visible.top;
+ left_edge.width = borders->visible.left;
+ left_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
+
+ right_edge.x = visible_rect.x + visible_rect.width - borders->visible.right;
+ right_edge.y = visible_rect.y + borders->visible.top;
+ right_edge.width = borders->visible.right;
+ right_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
+
+ bottom_edge.x = visible_rect.x;
+ bottom_edge.y = visible_rect.y + visible_rect.height - borders->visible.bottom;
+ bottom_edge.width = visible_rect.width;
+ bottom_edge.height = borders->visible.bottom;
+
+ if (title_layout)
+ pango_layout_get_pixel_extents (title_layout,
+ NULL, &extents);
+
+ draw_info.mini_icon = mini_icon;
+ draw_info.icon = icon;
+ draw_info.title_layout = title_layout;
+ draw_info.title_layout_width = title_layout ? extents.width : 0;
+ draw_info.title_layout_height = title_layout ? extents.height : 0;
+
+ draw_info.borders = fgeom->borders;
+ draw_info.width = fgeom->width;
+ draw_info.height = fgeom->height;
+
+ /* The enum is in the order the pieces should be rendered. */
+ i = 0;
+ while (i < META_FRAME_PIECE_LAST)
+ {
+ GdkRectangle rect;
+
+ switch ((MetaFramePiece) i)
+ {
+ case META_FRAME_PIECE_ENTIRE_BACKGROUND:
+ rect = visible_rect;
+ break;
+
+ case META_FRAME_PIECE_TITLEBAR:
+ rect = titlebar_rect;
+ break;
+
+ case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
+ rect = left_titlebar_edge;
+ break;
+
+ case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
+ rect = right_titlebar_edge;
+ break;
+
+ case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
+ rect = top_titlebar_edge;
+ break;
+
+ case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
+ rect = bottom_titlebar_edge;
+ break;
+
+ case META_FRAME_PIECE_TITLEBAR_MIDDLE:
+ rect.x = left_titlebar_edge.x + left_titlebar_edge.width;
+ rect.y = top_titlebar_edge.y + top_titlebar_edge.height;
+ rect.width = titlebar_rect.width - left_titlebar_edge.width -
+ right_titlebar_edge.width;
+ rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height;
+ break;
+
+ case META_FRAME_PIECE_TITLE:
+ rect = fgeom->title_rect;
+ break;
+
+ case META_FRAME_PIECE_LEFT_EDGE:
+ rect = left_edge;
+ break;
+
+ case META_FRAME_PIECE_RIGHT_EDGE:
+ rect = right_edge;
+ break;
+
+ case META_FRAME_PIECE_BOTTOM_EDGE:
+ rect = bottom_edge;
+ break;
+
+ case META_FRAME_PIECE_OVERLAY:
+ rect = visible_rect;
+ break;
+
+ case META_FRAME_PIECE_LAST:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ cairo_save (cr);
+
+ gdk_cairo_rectangle (cr, &rect);
+ cairo_clip (cr);
+
+ if (gdk_cairo_get_clip_rectangle (cr, NULL))
+ {
+ MetaDrawOpList *op_list;
+ MetaFrameStyle *parent;
+
+ parent = style;
+ op_list = NULL;
+ while (parent && op_list == NULL)
+ {
+ op_list = parent->pieces[i];
+ parent = parent->parent;
+ }
+
+ if (op_list)
+ {
+ meta_draw_op_list_draw_with_style (op_list,
+ style_info->styles[META_STYLE_ELEMENT_WINDOW],
+ cr,
+ &draw_info,
+ rect);
+ }
+ }
+
+ cairo_restore (cr);
+
+ /* Draw buttons just before overlay */
+ if ((i + 1) == META_FRAME_PIECE_OVERLAY)
+ {
+ MetaDrawOpList *op_list;
+ int middle_bg_offset;
+
+ middle_bg_offset = 0;
+ j = 0;
+ while (j < META_BUTTON_TYPE_LAST)
+ {
+ MetaButtonState button_state;
+
+ get_button_rect (j, fgeom, middle_bg_offset, &rect);
+
+ button_state = map_button_state (j, fgeom, middle_bg_offset, button_states);
+ op_list = meta_frame_style_get_button (style, j, button_state);
+
+ if (op_list)
+ {
+ cairo_save (cr);
+ gdk_cairo_rectangle (cr, &rect);
+ cairo_clip (cr);
+
+ if (gdk_cairo_get_clip_rectangle (cr, NULL))
+ {
+ meta_draw_op_list_draw_with_style (op_list,
+ style_info->styles[META_STYLE_ELEMENT_WINDOW],
+ cr,
+ &draw_info,
+ rect);
+ }
+ cairo_restore (cr);
+ }
+
+ /* MIDDLE_BACKGROUND type may get drawn more than once */
+ if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND ||
+ j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) &&
+ (middle_bg_offset < (MAX_MIDDLE_BACKGROUNDS - 1)))
+ {
+ ++middle_bg_offset;
+ }
+ else
+ {
+ middle_bg_offset = 0;
+ ++j;
+ }
+ }
+ }
+
+ ++i;
+ }
+}
+
+static void
meta_theme_metacity_class_init (MetaThemeMetacityClass *metacity_class)
{
GObjectClass *object_class;
@@ -4620,6 +5426,9 @@ meta_theme_metacity_class_init (MetaThemeMetacityClass *metacity_class)
impl_class->load = meta_theme_metacity_load;
impl_class->get_name = meta_theme_metacity_get_name;
+ impl_class->get_frame_borders = meta_theme_metacity_get_frame_borders;
+ impl_class->calc_geometry = meta_theme_metacity_calc_geometry;
+ impl_class->draw_frame = meta_theme_metacity_draw_frame;
}
static void
@@ -4711,12 +5520,6 @@ meta_theme_metacity_lookup_style_set (MetaThemeMetacity *metacity,
return g_hash_table_lookup (metacity->style_sets, name);
}
-gboolean
-meta_theme_metacity_allows_shade_stick_above_buttons (MetaThemeMetacity *metacity)
-{
- return theme_allows (metacity, META_THEME_SHADE_STICK_ABOVE_BUTTONS);
-}
-
/**
* Returns the earliest version of the theme format which required support
* for a particular button. (For example, "shade" first appeared in v2, and
diff --git a/libmetacity/meta-theme.c b/libmetacity/meta-theme.c
index 5550bdc0..ef88cdcd 100644
--- a/libmetacity/meta-theme.c
+++ b/libmetacity/meta-theme.c
@@ -473,15 +473,125 @@ meta_theme_get_title_scale (MetaTheme *theme,
return style->layout->title_scale;
}
-gboolean
-meta_theme_allows_shade_stick_above_buttons (MetaTheme *theme)
+void
+meta_theme_get_frame_borders (MetaTheme *theme,
+ const gchar *theme_variant,
+ MetaFrameType type,
+ int text_height,
+ MetaFrameFlags flags,
+ MetaFrameBorders *borders)
+{
+ MetaFrameStyle *style;
+ MetaStyleInfo *style_info;
+
+ g_return_if_fail (type < META_FRAME_TYPE_LAST);
+
+ meta_frame_borders_clear (borders);
+
+ style = meta_theme_get_frame_style (theme, type, flags);
+
+ /* Parser is not supposed to allow this currently */
+ if (style == NULL)
+ return;
+
+ style_info = meta_theme_get_style_info (theme, theme_variant);
+
+ META_THEME_IMPL_GET_CLASS (theme->impl)->get_frame_borders (theme->impl,
+ style->layout,
+ style_info,
+ theme->composited,
+ text_height,
+ flags,
+ type,
+ borders);
+}
+
+void
+meta_theme_calc_geometry (MetaTheme *theme,
+ const gchar *theme_variant,
+ MetaFrameType type,
+ gint text_height,
+ MetaFrameFlags flags,
+ gint client_width,
+ gint client_height,
+ const MetaButtonLayout *button_layout,
+ MetaFrameGeometry *fgeom)
{
- MetaThemeMetacity *metacity;
+ MetaFrameStyle *style;
+ MetaStyleInfo *style_info;
- if (theme->type != META_THEME_TYPE_METACITY)
- return TRUE;
+ g_return_if_fail (type < META_FRAME_TYPE_LAST);
- metacity = META_THEME_METACITY (theme->impl);
+ style = meta_theme_get_frame_style (theme, type, flags);
+
+ /* Parser is not supposed to allow this currently */
+ if (style == NULL)
+ return;
+
+ style_info = meta_theme_get_style_info (theme, theme_variant);
+
+ META_THEME_IMPL_GET_CLASS (theme->impl)->calc_geometry (theme->impl,
+ style->layout,
+ style_info,
+ theme->composited,
+ text_height,
+ flags,
+ client_width,
+ client_height,
+ button_layout,
+ type,
+ fgeom);
+}
+
+void
+meta_theme_draw_frame (MetaTheme *theme,
+ const gchar *theme_variant,
+ cairo_t *cr,
+ MetaFrameType type,
+ MetaFrameFlags flags,
+ int client_width,
+ int client_height,
+ PangoLayout *title_layout,
+ int text_height,
+ const MetaButtonLayout *button_layout,
+ MetaButtonState button_states[META_BUTTON_TYPE_LAST],
+ GdkPixbuf *mini_icon,
+ GdkPixbuf *icon)
+{
+ MetaFrameStyle *style;
+ MetaStyleInfo *style_info;
+ MetaFrameGeometry fgeom;
+
+ g_return_if_fail (type < META_FRAME_TYPE_LAST);
+
+ style = meta_theme_get_frame_style (theme, type, flags);
+
+ /* Parser is not supposed to allow this currently */
+ if (style == NULL)
+ return;
- return meta_theme_metacity_allows_shade_stick_above_buttons (metacity);
+ style_info = meta_theme_get_style_info (theme, theme_variant);
+
+ META_THEME_IMPL_GET_CLASS (theme->impl)->calc_geometry (theme->impl,
+ style->layout,
+ style_info,
+ theme->composited,
+ text_height,
+ flags,
+ client_width,
+ client_height,
+ button_layout,
+ type,
+ &fgeom);
+
+ META_THEME_IMPL_GET_CLASS (theme->impl)->draw_frame (theme->impl,
+ style,
+ style_info,
+ cr,
+ &fgeom,
+ title_layout,
+ flags,
+ button_states,
+ mini_icon,
+ icon);
}
diff --git a/libmetacity/meta-theme.h b/libmetacity/meta-theme.h
index ac68c909..cab66552 100644
--- a/libmetacity/meta-theme.h
+++ b/libmetacity/meta-theme.h
@@ -193,7 +193,36 @@ gdouble meta_theme_get_title_scale (MetaTheme
MetaFrameType type,
MetaFrameFlags flags);
-gboolean meta_theme_allows_shade_stick_above_buttons (MetaTheme *theme);
+void meta_theme_get_frame_borders (MetaTheme *theme,
+ const gchar *variant,
+ MetaFrameType type,
+ gint text_height,
+ MetaFrameFlags flags,
+ MetaFrameBorders *borders);
+
+void meta_theme_calc_geometry (MetaTheme *theme,
+ const gchar *variant,
+ MetaFrameType type,
+ gint text_height,
+ MetaFrameFlags flags,
+ gint client_width,
+ gint client_height,
+ const MetaButtonLayout *button_layout,
+ MetaFrameGeometry *fgeom);
+
+void meta_theme_draw_frame (MetaTheme *theme,
+ const gchar *variant,
+ cairo_t *cr,
+ MetaFrameType type,
+ MetaFrameFlags flags,
+ gint client_width,
+ gint client_height,
+ PangoLayout *title_layout,
+ int text_height,
+ const MetaButtonLayout *button_layout,
+ MetaButtonState button_states[META_BUTTON_TYPE_LAST],
+ GdkPixbuf *mini_icon,
+ GdkPixbuf *icon);
G_END_DECLS
diff --git a/src/ui/theme.c b/src/ui/theme.c
index 8370f8b4..918f8d41 100644
--- a/src/ui/theme.c
+++ b/src/ui/theme.c
@@ -66,1452 +66,6 @@
*/
static MetaTheme *meta_current_theme = NULL;
-static void
-meta_frame_layout_get_borders (MetaTheme *theme,
- const MetaFrameLayout *layout,
- int text_height,
- MetaFrameFlags flags,
- MetaFrameType type,
- MetaFrameBorders *borders)
-{
- int buttons_height, title_height;
-
- meta_frame_borders_clear (borders);
-
- /* For a full-screen window, we don't have any borders, visible or not. */
- if (flags & META_FRAME_FULLSCREEN)
- return;
-
- g_return_if_fail (layout != NULL);
-
- if (!layout->has_title)
- text_height = 0;
-
- buttons_height = layout->button_height +
- layout->button_border.top + layout->button_border.bottom;
- title_height = text_height +
- layout->title_vertical_pad +
- layout->title_border.top + layout->title_border.bottom;
-
- borders->visible.top = layout->top_height + MAX (buttons_height, title_height);
- borders->visible.left = layout->left_width;
- borders->visible.right = layout->right_width;
- borders->visible.bottom = layout->bottom_height;
-
- if (meta_theme_get_theme_type (theme) != META_THEME_TYPE_METACITY)
- {
- borders->invisible.left = layout->invisible_border.left;
- borders->invisible.right = layout->invisible_border.right;
- borders->invisible.bottom = layout->invisible_border.bottom;
- borders->invisible.top = layout->invisible_border.top;
- }
- else
- {
- if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
- {
- borders->invisible.left = layout->invisible_border.left;
- borders->invisible.right = layout->invisible_border.right;
- }
-
- if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
- {
- borders->invisible.bottom = layout->invisible_border.bottom;
-
- if (type != META_FRAME_TYPE_ATTACHED)
- borders->invisible.top = layout->invisible_border.top;
- }
- }
-
- borders->total.left = borders->invisible.left + borders->visible.left;
- borders->total.right = borders->invisible.right + borders->visible.right;
- borders->total.bottom = borders->invisible.bottom + borders->visible.bottom;
- borders->total.top = borders->invisible.top + borders->visible.top;
-}
-
-static MetaButtonType
-map_button_function_to_type (MetaButtonFunction function)
-{
- switch (function)
- {
- case META_BUTTON_FUNCTION_SHADE:
- return META_BUTTON_TYPE_SHADE;
- case META_BUTTON_FUNCTION_ABOVE:
- return META_BUTTON_TYPE_ABOVE;
- case META_BUTTON_FUNCTION_STICK:
- return META_BUTTON_TYPE_STICK;
- case META_BUTTON_FUNCTION_UNSHADE:
- return META_BUTTON_TYPE_UNSHADE;
- case META_BUTTON_FUNCTION_UNABOVE:
- return META_BUTTON_TYPE_UNABOVE;
- case META_BUTTON_FUNCTION_UNSTICK:
- return META_BUTTON_TYPE_UNSTICK;
- case META_BUTTON_FUNCTION_MENU:
- return META_BUTTON_TYPE_MENU;
- case META_BUTTON_FUNCTION_APPMENU:
- return META_BUTTON_TYPE_APPMENU;
- case META_BUTTON_FUNCTION_MINIMIZE:
- return META_BUTTON_TYPE_MINIMIZE;
- case META_BUTTON_FUNCTION_MAXIMIZE:
- return META_BUTTON_TYPE_MAXIMIZE;
- case META_BUTTON_FUNCTION_CLOSE:
- return META_BUTTON_TYPE_CLOSE;
- case META_BUTTON_FUNCTION_LAST:
- return META_BUTTON_TYPE_LAST;
- default:
- break;
- }
-
- return META_BUTTON_TYPE_LAST;
-}
-
-static MetaButtonSpace*
-rect_for_function (MetaFrameGeometry *fgeom,
- MetaFrameFlags flags,
- MetaButtonFunction function,
- MetaTheme *theme)
-{
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- {
- if (meta_theme_allows_shade_stick_above_buttons (theme))
- {
- switch (function)
- {
- case META_BUTTON_FUNCTION_SHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
- return &fgeom->shade_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_ABOVE:
- if (!(flags & META_FRAME_ABOVE))
- return &fgeom->above_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_STICK:
- if (!(flags & META_FRAME_STUCK))
- return &fgeom->stick_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_UNSHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
- return &fgeom->unshade_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_UNABOVE:
- if (flags & META_FRAME_ABOVE)
- return &fgeom->unabove_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_UNSTICK:
- if (flags & META_FRAME_STUCK)
- return &fgeom->unstick_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_MENU:
- case META_BUTTON_FUNCTION_APPMENU:
- case META_BUTTON_FUNCTION_MINIMIZE:
- case META_BUTTON_FUNCTION_MAXIMIZE:
- case META_BUTTON_FUNCTION_CLOSE:
- case META_BUTTON_FUNCTION_LAST:
- default:
- break;
- }
-
- /* now consider the buttons which exist in all versions */
- switch (function)
- {
- case META_BUTTON_FUNCTION_MENU:
- if (flags & META_FRAME_ALLOWS_MENU)
- return &fgeom->menu_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_APPMENU:
- if (flags & META_FRAME_ALLOWS_APPMENU)
- return &fgeom->appmenu_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_MINIMIZE:
- if (flags & META_FRAME_ALLOWS_MINIMIZE)
- return &fgeom->min_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_MAXIMIZE:
- if (flags & META_FRAME_ALLOWS_MAXIMIZE)
- return &fgeom->max_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_CLOSE:
- if (flags & META_FRAME_ALLOWS_DELETE)
- return &fgeom->close_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_STICK:
- case META_BUTTON_FUNCTION_SHADE:
- case META_BUTTON_FUNCTION_ABOVE:
- case META_BUTTON_FUNCTION_UNSTICK:
- case META_BUTTON_FUNCTION_UNSHADE:
- case META_BUTTON_FUNCTION_UNABOVE:
- /* we are being asked for a >v1 button which hasn't been handled yet,
- * so obviously we're not in a theme which supports that version.
- * therefore, we don't show the button. return NULL and all will
- * be well.
- */
- return NULL;
-
- case META_BUTTON_FUNCTION_LAST:
- default:
- break;
- }
- }
- }
- else
- {
- switch (function)
- {
- case META_BUTTON_FUNCTION_MENU:
- if (flags & META_FRAME_ALLOWS_MENU)
- return &fgeom->menu_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_APPMENU:
- if (flags & META_FRAME_ALLOWS_APPMENU)
- return &fgeom->appmenu_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_MINIMIZE:
- if (flags & META_FRAME_ALLOWS_MINIMIZE)
- return &fgeom->min_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_MAXIMIZE:
- if (flags & META_FRAME_ALLOWS_MAXIMIZE)
- return &fgeom->max_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_CLOSE:
- if (flags & META_FRAME_ALLOWS_DELETE)
- return &fgeom->close_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_SHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
- return &fgeom->shade_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_ABOVE:
- if (!(flags & META_FRAME_ABOVE))
- return &fgeom->above_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_STICK:
- if (!(flags & META_FRAME_STUCK))
- return &fgeom->stick_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_UNSHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
- return &fgeom->unshade_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_UNABOVE:
- if (flags & META_FRAME_ABOVE)
- return &fgeom->unabove_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_UNSTICK:
- if (flags & META_FRAME_STUCK)
- return &fgeom->unstick_rect;
- else
- return NULL;
-
- case META_BUTTON_FUNCTION_LAST:
- default:
- break;
- }
- }
-
- return NULL;
-}
-
-static gboolean
-strip_button (MetaButtonSpace *func_rects[META_BUTTON_FUNCTION_LAST],
- GdkRectangle *bg_rects[META_BUTTON_FUNCTION_LAST],
- int *n_rects,
- MetaButtonSpace *to_strip)
-{
- int i;
-
- i = 0;
- while (i < *n_rects)
- {
- if (func_rects[i] == to_strip)
- {
- *n_rects -= 1;
-
- /* shift the other rects back in the array */
- while (i < *n_rects)
- {
- func_rects[i] = func_rects[i+1];
- bg_rects[i] = bg_rects[i+1];
-
- ++i;
- }
-
- func_rects[i] = NULL;
- bg_rects[i] = NULL;
-
- return TRUE;
- }
-
- ++i;
- }
-
- return FALSE; /* did not strip anything */
-}
-
-static void
-get_margin (GtkStyleContext *style,
- GtkBorder *border)
-{
- GtkStateFlags state;
-
- state = gtk_style_context_get_state (style);
-
- gtk_style_context_get_margin (style, state, border);
-}
-
-static void
-get_padding_and_border (GtkStyleContext *style,
- GtkBorder *border)
-{
- GtkBorder tmp;
- GtkStateFlags state = gtk_style_context_get_state (style);
-
- gtk_style_context_get_border (style, state, border);
- gtk_style_context_get_padding (style, state, &tmp);
-
- border->left += tmp.left;
- border->top += tmp.top;
- border->right += tmp.right;
- border->bottom += tmp.bottom;
-}
-
-static void
-scale_border (GtkBorder *border,
- double factor)
-{
- border->left *= factor;
- border->right *= factor;
- border->top *= factor;
- border->bottom *= factor;
-}
-
-static void
-meta_frame_layout_sync_with_style (MetaFrameLayout *layout,
- MetaStyleInfo *style_info,
- MetaFrameFlags flags,
- MetaTheme *theme)
-{
- GtkStyleContext *style;
- GtkBorder border;
- int border_radius, max_radius;
-
- /* We don't want GTK+ info for metacity theme */
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- return;
-
- meta_style_info_set_flags (style_info, flags);
-
- layout->button_sizing = META_BUTTON_SIZING_FIXED;
-
- style = style_info->styles[META_STYLE_ELEMENT_DECORATION];
- get_padding_and_border (style, &border);
- scale_border (&border, layout->title_scale);
-
- layout->left_width = border.left;
- layout->right_width = border.right;
- layout->top_height = border.top;
- layout->bottom_height = border.bottom;
-
- if (meta_theme_get_composited (theme))
- get_margin (style, &layout->invisible_border);
- else
- {
- get_margin (style, &border);
-
- layout->left_width += border.left;
- layout->right_width += border.right;
- layout->top_height += border.top;
- layout->bottom_height += border.bottom;
- }
-
- if (layout->hide_buttons)
- layout->icon_size = 0;
-
- if (!layout->has_title && layout->hide_buttons)
- return; /* border-only - be done */
-
- style = style_info->styles[META_STYLE_ELEMENT_TITLEBAR];
-
- if (meta_theme_get_composited (theme))
- {
- gtk_style_context_get (style, gtk_style_context_get_state (style),
- "border-radius", &border_radius,
- NULL);
- /* GTK+ currently does not allow us to look up radii of individual
- * corners; however we don't clip the client area, so with the
- * current trend of using small/no visible frame borders, most
- * themes should work fine with this.
- */
- layout->top_left_corner_rounded_radius = border_radius;
- layout->top_right_corner_rounded_radius = border_radius;
- max_radius = MIN (layout->bottom_height, layout->left_width);
- layout->bottom_left_corner_rounded_radius = MAX (border_radius, max_radius);
- max_radius = MIN (layout->bottom_height, layout->right_width);
- layout->bottom_right_corner_rounded_radius = MAX (border_radius, max_radius);
- }
-
- get_padding_and_border (style, &border);
- scale_border (&border, layout->title_scale);
- layout->left_titlebar_edge = layout->left_width + border.left;
- layout->right_titlebar_edge = layout->right_width + border.right;
- layout->title_vertical_pad = border.top;
-
- layout->button_border.top = border.top;
- layout->button_border.bottom = border.bottom;
- layout->button_border.left = 0;
- layout->button_border.right = 0;
-
- layout->button_width = layout->icon_size;
- layout->button_height = layout->icon_size;
-
- style = style_info->styles[META_STYLE_ELEMENT_BUTTON];
- get_padding_and_border (style, &border);
- scale_border (&border, layout->title_scale);
- layout->button_width += border.left + border.right;
- layout->button_height += border.top + border.bottom;
-
- style = style_info->styles[META_STYLE_ELEMENT_IMAGE];
- get_padding_and_border (style, &border);
- scale_border (&border, layout->title_scale);
- layout->button_width += border.left + border.right;
- layout->button_height += border.top + border.bottom;
-}
-
-static void
-meta_frame_layout_calc_geometry (MetaFrameLayout *layout,
- MetaStyleInfo *style_info,
- int text_height,
- MetaFrameFlags flags,
- int client_width,
- int client_height,
- const MetaButtonLayout *button_layout,
- MetaFrameType type,
- MetaFrameGeometry *fgeom,
- MetaTheme *theme)
-{
- MetaFrameBorders borders;
- int i, n_left, n_right, n_left_spacers, n_right_spacers;
- int x;
- int button_y;
- int title_right_edge;
- int width, height;
- int button_width, button_height;
- int min_size_for_rounding;
-
- /* the left/right rects in order; the max # of rects
- * is the number of button functions
- */
- MetaButtonSpace *left_func_rects[META_BUTTON_FUNCTION_LAST];
- MetaButtonSpace *right_func_rects[META_BUTTON_FUNCTION_LAST];
- GdkRectangle *left_bg_rects[META_BUTTON_FUNCTION_LAST];
- gboolean left_buttons_has_spacer[META_BUTTON_FUNCTION_LAST];
- GdkRectangle *right_bg_rects[META_BUTTON_FUNCTION_LAST];
- gboolean right_buttons_has_spacer[META_BUTTON_FUNCTION_LAST];
-
- meta_frame_layout_sync_with_style (layout, style_info, flags, theme);
-
- meta_frame_layout_get_borders (theme, layout, text_height,
- flags, type, &borders);
-
- fgeom->borders = borders;
- fgeom->top_height = layout->top_height;
-
- width = client_width + borders.total.left + borders.total.right;
-
- height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
- borders.total.top + borders.total.bottom;
-
- fgeom->width = width;
- fgeom->height = height;
-
- fgeom->top_titlebar_edge = layout->title_border.top;
- fgeom->bottom_titlebar_edge = layout->title_border.bottom;
- fgeom->left_titlebar_edge = layout->left_titlebar_edge;
- fgeom->right_titlebar_edge = layout->right_titlebar_edge;
-
- /* gcc warnings */
- button_width = -1;
- button_height = -1;
-
- switch (layout->button_sizing)
- {
- case META_BUTTON_SIZING_ASPECT:
- button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom;
- button_width = button_height / layout->button_aspect;
- break;
- case META_BUTTON_SIZING_FIXED:
- button_width = layout->button_width;
- button_height = layout->button_height;
- break;
- case META_BUTTON_SIZING_LAST:
- default:
- g_assert_not_reached ();
- break;
- }
-
- /* FIXME all this code sort of pretends that duplicate buttons
- * with the same function are allowed, but that breaks the
- * code in frames.c, so isn't really allowed right now.
- * Would need left_close_rect, right_close_rect, etc.
- */
-
- /* Init all button rects to 0, lame hack */
- memset (ADDRESS_OF_BUTTON_RECTS (fgeom), '\0',
- LENGTH_OF_BUTTON_RECTS);
-
- n_left = 0;
- n_right = 0;
- n_left_spacers = 0;
- n_right_spacers = 0;
-
- if (!layout->hide_buttons)
- {
- /* Try to fill in rects */
- for (i = 0; i < META_BUTTON_FUNCTION_LAST && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
- {
- left_func_rects[n_left] = rect_for_function (fgeom, flags,
- button_layout->left_buttons[i],
- theme);
- if (left_func_rects[n_left] != NULL)
- {
- left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
- if (button_layout->left_buttons_has_spacer[i])
- ++n_left_spacers;
-
- ++n_left;
- }
- }
-
- for (i = 0; i < META_BUTTON_FUNCTION_LAST && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
- {
- right_func_rects[n_right] = rect_for_function (fgeom, flags,
- button_layout->right_buttons[i],
- theme);
- if (right_func_rects[n_right] != NULL)
- {
- right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
- if (button_layout->right_buttons_has_spacer[i])
- ++n_right_spacers;
-
- ++n_right;
- }
- }
- }
-
- for (i = 0; i < META_BUTTON_FUNCTION_LAST; i++)
- {
- left_bg_rects[i] = NULL;
- right_bg_rects[i] = NULL;
- }
-
- for (i = 0; i < n_left; i++)
- {
- if (n_left == 1)
- left_bg_rects[i] = &fgeom->left_single_background;
- else if (i == 0)
- left_bg_rects[i] = &fgeom->left_left_background;
- else if (i == (n_left - 1))
- left_bg_rects[i] = &fgeom->left_right_background;
- else
- left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
- }
-
- for (i = 0; i < n_right; i++)
- {
- if (n_right == 1)
- right_bg_rects[i] = &fgeom->right_single_background;
- else if (i == (n_right - 1))
- right_bg_rects[i] = &fgeom->right_right_background;
- else if (i == 0)
- right_bg_rects[i] = &fgeom->right_left_background;
- else
- right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
- }
-
- /* Be sure buttons fit */
- while (n_left > 0 || n_right > 0)
- {
- int space_used_by_buttons;
- int space_available;
-
- space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
-
- space_used_by_buttons = 0;
-
- space_used_by_buttons += button_width * n_left;
- space_used_by_buttons += (button_width * 0.75) * n_left_spacers;
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- {
- space_used_by_buttons += layout->button_border.left * n_left;
- space_used_by_buttons += layout->button_border.right * n_left;
- }
- else
- space_used_by_buttons += layout->titlebar_spacing * MAX (n_left - 1, 0);
-
- space_used_by_buttons += button_width * n_right;
- space_used_by_buttons += (button_width * 0.75) * n_right_spacers;
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- {
- space_used_by_buttons += layout->button_border.left * n_right;
- space_used_by_buttons += layout->button_border.right * n_right;
- }
- else
- space_used_by_buttons += layout->titlebar_spacing * MAX (n_right - 1, 0);
-
- if (space_used_by_buttons <= space_available)
- break; /* Everything fits, bail out */
-
- /* First try to remove separators */
- if (n_left_spacers > 0)
- {
- left_buttons_has_spacer[--n_left_spacers] = FALSE;
- continue;
- }
- else if (n_right_spacers > 0)
- {
- right_buttons_has_spacer[--n_right_spacers] = FALSE;
- continue;
- }
-
- /* Otherwise we need to shave out a button. Shave
- * above, stick, shade, min, max, close, then menu (menu is most useful);
- * prefer the default button locations.
- */
- if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->above_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->above_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->stick_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->stick_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->shade_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->shade_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->min_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->min_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->max_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->max_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->close_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->close_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->menu_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->menu_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->appmenu_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->appmenu_rect))
- continue;
- else
- {
- meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
- n_left, n_right);
- }
- }
-
- /* Save the button layout */
- fgeom->button_layout = *button_layout;
- fgeom->n_left_buttons = n_left;
- fgeom->n_right_buttons = n_right;
-
- /* center buttons vertically */
- button_y = (borders.visible.top - fgeom->top_height -
- (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + fgeom->top_height + borders.invisible.top;
-
- /* right edge of farthest-right button */
- x = width - layout->right_titlebar_edge - borders.invisible.right;
-
- i = n_right - 1;
- while (i >= 0)
- {
- MetaButtonSpace *rect;
-
- if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
- break;
-
- rect = right_func_rects[i];
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- rect->visible.x = x - layout->button_border.right - button_width;
- else
- rect->visible.x = x - button_width;
- if (right_buttons_has_spacer[i])
- rect->visible.x -= (button_width * 0.75);
-
- rect->visible.y = button_y;
- rect->visible.width = button_width;
- rect->visible.height = button_height;
-
- if (flags & META_FRAME_MAXIMIZED ||
- flags & META_FRAME_TILED_LEFT ||
- flags & META_FRAME_TILED_RIGHT)
- {
- rect->clickable.x = rect->visible.x;
- rect->clickable.y = rect->visible.y;
- rect->clickable.width = button_width;
- rect->clickable.height = button_height;
-
- if (i == n_right - 1)
- {
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right;
- else
- rect->clickable.width += layout->right_titlebar_edge + layout->right_width;
- }
-
- }
- else
- g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
-
- *(right_bg_rects[i]) = rect->visible;
-
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- x = rect->visible.x - layout->button_border.left;
- else
- {
- x = rect->visible.x;
-
- if (i > 0)
- x -= layout->titlebar_spacing;
- }
-
- --i;
- }
-
- /* save right edge of titlebar for later use */
- title_right_edge = x - layout->title_border.right;
-
- /* Now x changes to be position from the left and we go through
- * the left-side buttons
- */
- x = layout->left_titlebar_edge + borders.invisible.left;
- for (i = 0; i < n_left; i++)
- {
- MetaButtonSpace *rect;
-
- rect = left_func_rects[i];
-
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- rect->visible.x = x + layout->button_border.left;
- else
- rect->visible.x = x;
- rect->visible.y = button_y;
- rect->visible.width = button_width;
- rect->visible.height = button_height;
-
- if (flags & META_FRAME_MAXIMIZED)
- {
- rect->clickable.x = rect->visible.x;
- rect->clickable.y = rect->visible.y;
- rect->clickable.width = button_width;
- rect->clickable.height = button_height;
- }
- else
- g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
-
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- x = rect->visible.x + rect->visible.width + layout->button_border.right;
- else
- {
- x = rect->visible.x + rect->visible.width;
- if (i < n_left - 1)
- x += layout->titlebar_spacing;
- }
- if (left_buttons_has_spacer[i])
- x += (button_width * 0.75);
-
- *(left_bg_rects[i]) = rect->visible;
- }
-
- /* We always fill as much vertical space as possible with title rect,
- * rather than centering it like the buttons
- */
- fgeom->title_rect.x = x + layout->title_border.left;
- fgeom->title_rect.y = layout->title_border.top + borders.invisible.top;
- fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
- fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom;
-
- /* Nuke title if it won't fit */
- if (fgeom->title_rect.width < 0 ||
- fgeom->title_rect.height < 0)
- {
- fgeom->title_rect.width = 0;
- fgeom->title_rect.height = 0;
- }
-
- if (flags & META_FRAME_SHADED)
- min_size_for_rounding = 0;
- else
- min_size_for_rounding = 5;
-
- fgeom->top_left_corner_rounded_radius = 0;
- fgeom->top_right_corner_rounded_radius = 0;
- fgeom->bottom_left_corner_rounded_radius = 0;
- fgeom->bottom_right_corner_rounded_radius = 0;
-
- if (borders.visible.top + borders.visible.left >= min_size_for_rounding)
- fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
- if (borders.visible.top + borders.visible.right >= min_size_for_rounding)
- fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
-
- if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding)
- fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
- if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding)
- fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
-}
-
-static MetaButtonState
-map_button_state (MetaButtonType button_type,
- const MetaFrameGeometry *fgeom,
- int middle_bg_offset,
- MetaButtonState button_states[META_BUTTON_TYPE_LAST])
-{
- MetaButtonFunction function = META_BUTTON_FUNCTION_LAST;
-
- switch (button_type)
- {
- /* First handle functions, which map directly */
- case META_BUTTON_TYPE_SHADE:
- case META_BUTTON_TYPE_ABOVE:
- case META_BUTTON_TYPE_STICK:
- case META_BUTTON_TYPE_UNSHADE:
- case META_BUTTON_TYPE_UNABOVE:
- case META_BUTTON_TYPE_UNSTICK:
- case META_BUTTON_TYPE_MENU:
- case META_BUTTON_TYPE_APPMENU:
- case META_BUTTON_TYPE_MINIMIZE:
- case META_BUTTON_TYPE_MAXIMIZE:
- case META_BUTTON_TYPE_CLOSE:
- return button_states[button_type];
-
- /* Map position buttons to the corresponding function */
- case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
- case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
- if (fgeom->n_right_buttons > 0)
- function = fgeom->button_layout.right_buttons[0];
- break;
- case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
- if (fgeom->n_right_buttons > 0)
- function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1];
- break;
- case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
- if (middle_bg_offset + 1 < fgeom->n_right_buttons)
- function = fgeom->button_layout.right_buttons[middle_bg_offset + 1];
- break;
- case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
- case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
- if (fgeom->n_left_buttons > 0)
- function = fgeom->button_layout.left_buttons[0];
- break;
- case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
- if (fgeom->n_left_buttons > 0)
- function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1];
- break;
- case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
- if (middle_bg_offset + 1 < fgeom->n_left_buttons)
- function = fgeom->button_layout.left_buttons[middle_bg_offset + 1];
- break;
- case META_BUTTON_TYPE_LAST:
- break;
- default:
- break;
- }
-
- if (function != META_BUTTON_FUNCTION_LAST)
- return button_states[map_button_function_to_type (function)];
-
- return META_BUTTON_STATE_LAST;
-}
-
-static void
-get_button_rect (MetaButtonType type,
- const MetaFrameGeometry *fgeom,
- int middle_background_offset,
- GdkRectangle *rect)
-{
- switch (type)
- {
- case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
- *rect = fgeom->left_left_background;
- break;
-
- case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
- *rect = fgeom->left_middle_backgrounds[middle_background_offset];
- break;
-
- case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
- *rect = fgeom->left_right_background;
- break;
-
- case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
- *rect = fgeom->left_single_background;
- break;
-
- case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
- *rect = fgeom->right_left_background;
- break;
-
- case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
- *rect = fgeom->right_middle_backgrounds[middle_background_offset];
- break;
-
- case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
- *rect = fgeom->right_right_background;
- break;
-
- case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
- *rect = fgeom->right_single_background;
- break;
-
- case META_BUTTON_TYPE_CLOSE:
- *rect = fgeom->close_rect.visible;
- break;
-
- case META_BUTTON_TYPE_SHADE:
- *rect = fgeom->shade_rect.visible;
- break;
-
- case META_BUTTON_TYPE_UNSHADE:
- *rect = fgeom->unshade_rect.visible;
- break;
-
- case META_BUTTON_TYPE_ABOVE:
- *rect = fgeom->above_rect.visible;
- break;
-
- case META_BUTTON_TYPE_UNABOVE:
- *rect = fgeom->unabove_rect.visible;
- break;
-
- case META_BUTTON_TYPE_STICK:
- *rect = fgeom->stick_rect.visible;
- break;
-
- case META_BUTTON_TYPE_UNSTICK:
- *rect = fgeom->unstick_rect.visible;
- break;
-
- case META_BUTTON_TYPE_MAXIMIZE:
- *rect = fgeom->max_rect.visible;
- break;
-
- case META_BUTTON_TYPE_MINIMIZE:
- *rect = fgeom->min_rect.visible;
- break;
-
- case META_BUTTON_TYPE_MENU:
- *rect = fgeom->menu_rect.visible;
- break;
-
- case META_BUTTON_TYPE_APPMENU:
- *rect = fgeom->appmenu_rect.visible;
- break;
-
- case META_BUTTON_TYPE_LAST:
- default:
- g_assert_not_reached ();
- break;
- }
-}
-
-/* Used for metacity theme */
-static void
-meta_frame_style_draw_with_style (MetaFrameStyle *style,
- MetaStyleInfo *style_info,
- cairo_t *cr,
- const MetaFrameGeometry *fgeom,
- PangoLayout *title_layout,
- MetaButtonState button_states[META_BUTTON_TYPE_LAST],
- GdkPixbuf *mini_icon,
- GdkPixbuf *icon)
-{
- int i, j;
- GdkRectangle visible_rect;
- GdkRectangle titlebar_rect;
- GdkRectangle left_titlebar_edge;
- GdkRectangle right_titlebar_edge;
- GdkRectangle bottom_titlebar_edge;
- GdkRectangle top_titlebar_edge;
- GdkRectangle left_edge, right_edge, bottom_edge;
- PangoRectangle extents;
- MetaDrawInfo draw_info;
- const MetaFrameBorders *borders;
-
- borders = &fgeom->borders;
-
- visible_rect.x = borders->invisible.left;
- visible_rect.y = borders->invisible.top;
- visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
- visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
-
- titlebar_rect.x = visible_rect.x;
- titlebar_rect.y = visible_rect.y;
- titlebar_rect.width = visible_rect.width;
- titlebar_rect.height = borders->visible.top;
-
- left_titlebar_edge.x = titlebar_rect.x;
- left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge;
- left_titlebar_edge.width = fgeom->left_titlebar_edge;
- left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge;
-
- right_titlebar_edge.y = left_titlebar_edge.y;
- right_titlebar_edge.height = left_titlebar_edge.height;
- right_titlebar_edge.width = fgeom->right_titlebar_edge;
- right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width;
-
- top_titlebar_edge.x = titlebar_rect.x;
- top_titlebar_edge.y = titlebar_rect.y;
- top_titlebar_edge.width = titlebar_rect.width;
- top_titlebar_edge.height = fgeom->top_titlebar_edge;
-
- bottom_titlebar_edge.x = titlebar_rect.x;
- bottom_titlebar_edge.width = titlebar_rect.width;
- bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge;
- bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height;
-
- left_edge.x = visible_rect.x;
- left_edge.y = visible_rect.y + borders->visible.top;
- left_edge.width = borders->visible.left;
- left_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
-
- right_edge.x = visible_rect.x + visible_rect.width - borders->visible.right;
- right_edge.y = visible_rect.y + borders->visible.top;
- right_edge.width = borders->visible.right;
- right_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
-
- bottom_edge.x = visible_rect.x;
- bottom_edge.y = visible_rect.y + visible_rect.height - borders->visible.bottom;
- bottom_edge.width = visible_rect.width;
- bottom_edge.height = borders->visible.bottom;
-
- if (title_layout)
- pango_layout_get_pixel_extents (title_layout,
- NULL, &extents);
-
- draw_info.mini_icon = mini_icon;
- draw_info.icon = icon;
- draw_info.title_layout = title_layout;
- draw_info.title_layout_width = title_layout ? extents.width : 0;
- draw_info.title_layout_height = title_layout ? extents.height : 0;
-
- draw_info.borders = fgeom->borders;
- draw_info.width = fgeom->width;
- draw_info.height = fgeom->height;
-
- /* The enum is in the order the pieces should be rendered. */
- i = 0;
- while (i < META_FRAME_PIECE_LAST)
- {
- GdkRectangle rect;
-
- switch ((MetaFramePiece) i)
- {
- case META_FRAME_PIECE_ENTIRE_BACKGROUND:
- rect = visible_rect;
- break;
-
- case META_FRAME_PIECE_TITLEBAR:
- rect = titlebar_rect;
- break;
-
- case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
- rect = left_titlebar_edge;
- break;
-
- case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
- rect = right_titlebar_edge;
- break;
-
- case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
- rect = top_titlebar_edge;
- break;
-
- case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
- rect = bottom_titlebar_edge;
- break;
-
- case META_FRAME_PIECE_TITLEBAR_MIDDLE:
- rect.x = left_titlebar_edge.x + left_titlebar_edge.width;
- rect.y = top_titlebar_edge.y + top_titlebar_edge.height;
- rect.width = titlebar_rect.width - left_titlebar_edge.width -
- right_titlebar_edge.width;
- rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height;
- break;
-
- case META_FRAME_PIECE_TITLE:
- rect = fgeom->title_rect;
- break;
-
- case META_FRAME_PIECE_LEFT_EDGE:
- rect = left_edge;
- break;
-
- case META_FRAME_PIECE_RIGHT_EDGE:
- rect = right_edge;
- break;
-
- case META_FRAME_PIECE_BOTTOM_EDGE:
- rect = bottom_edge;
- break;
-
- case META_FRAME_PIECE_OVERLAY:
- rect = visible_rect;
- break;
-
- case META_FRAME_PIECE_LAST:
- default:
- g_assert_not_reached ();
- break;
- }
-
- cairo_save (cr);
-
- gdk_cairo_rectangle (cr, &rect);
- cairo_clip (cr);
-
- if (gdk_cairo_get_clip_rectangle (cr, NULL))
- {
- MetaDrawOpList *op_list;
- MetaFrameStyle *parent;
-
- parent = style;
- op_list = NULL;
- while (parent && op_list == NULL)
- {
- op_list = parent->pieces[i];
- parent = parent->parent;
- }
-
- if (op_list)
- {
- meta_draw_op_list_draw_with_style (op_list,
- style_info->styles[META_STYLE_ELEMENT_WINDOW],
- cr,
- &draw_info,
- rect);
- }
- }
-
- cairo_restore (cr);
-
- /* Draw buttons just before overlay */
- if ((i + 1) == META_FRAME_PIECE_OVERLAY)
- {
- MetaDrawOpList *op_list;
- int middle_bg_offset;
-
- middle_bg_offset = 0;
- j = 0;
- while (j < META_BUTTON_TYPE_LAST)
- {
- MetaButtonState button_state;
-
- get_button_rect (j, fgeom, middle_bg_offset, &rect);
-
- button_state = map_button_state (j, fgeom, middle_bg_offset, button_states);
- op_list = meta_frame_style_get_button (style, j, button_state);
-
- if (op_list)
- {
- cairo_save (cr);
- gdk_cairo_rectangle (cr, &rect);
- cairo_clip (cr);
-
- if (gdk_cairo_get_clip_rectangle (cr, NULL))
- {
- meta_draw_op_list_draw_with_style (op_list,
- style_info->styles[META_STYLE_ELEMENT_WINDOW],
- cr,
- &draw_info,
- rect);
- }
- cairo_restore (cr);
- }
-
- /* MIDDLE_BACKGROUND type may get drawn more than once */
- if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND ||
- j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) &&
- (middle_bg_offset < (MAX_MIDDLE_BACKGROUNDS - 1)))
- {
- ++middle_bg_offset;
- }
- else
- {
- middle_bg_offset = 0;
- ++j;
- }
- }
- }
-
- ++i;
- }
-}
-
-static const char *
-get_class_from_button_type (MetaButtonType type)
-{
- if (type == META_BUTTON_TYPE_CLOSE)
- return "close";
- else if (type == META_BUTTON_TYPE_MAXIMIZE)
- return "maximize";
- else if (type == META_BUTTON_TYPE_MINIMIZE)
- return "minimize";
-
- return NULL;
-}
-
-/* Used for GTK+ theme */
-static void
-meta_frame_style_draw_with_style_gtk (MetaFrameStyle *frame_style,
- MetaStyleInfo *style_info,
- cairo_t *cr,
- const MetaFrameGeometry *fgeom,
- PangoLayout *title_layout,
- MetaFrameFlags flags,
- MetaButtonState button_states[META_BUTTON_TYPE_LAST],
- GdkPixbuf *mini_icon)
-{
- GtkStyleContext *style;
- GtkStateFlags state;
- MetaButtonType button_type;
- GdkRectangle visible_rect;
- GdkRectangle titlebar_rect;
- GdkRectangle button_rect;
- const MetaFrameBorders *borders;
-
- borders = &fgeom->borders;
-
- visible_rect.x = borders->invisible.left;
- visible_rect.y = borders->invisible.top;
- visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
- visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
-
- meta_style_info_set_flags (style_info, flags);
-
- style = style_info->styles[META_STYLE_ELEMENT_DECORATION];
- gtk_render_background (style, cr,
- visible_rect.x, visible_rect.y,
- visible_rect.width, visible_rect.height);
- gtk_render_frame (style, cr,
- visible_rect.x, visible_rect.y,
- visible_rect.width, visible_rect.height);
-
- titlebar_rect.x = visible_rect.x + borders->visible.left;
- titlebar_rect.y = visible_rect.y + fgeom->top_height;
- titlebar_rect.width = visible_rect.width - borders->visible.left - borders->visible.right;
- titlebar_rect.height = borders->visible.top - fgeom->top_height;
-
- style = style_info->styles[META_STYLE_ELEMENT_TITLEBAR];
- gtk_render_background (style, cr,
- titlebar_rect.x, titlebar_rect.y,
- titlebar_rect.width, titlebar_rect.height);
- gtk_render_frame (style, cr,
- titlebar_rect.x, titlebar_rect.y,
- titlebar_rect.width, titlebar_rect.height);
-
- if (frame_style->layout->has_title && title_layout)
- {
- PangoRectangle logical;
- int text_width, x, y;
-
- pango_layout_set_width (title_layout, -1);
- pango_layout_get_pixel_extents (title_layout, NULL, &logical);
-
- text_width = MIN(fgeom->title_rect.width, logical.width);
-
- if (text_width < logical.width)
- pango_layout_set_width (title_layout, PANGO_SCALE * text_width);
-
- /* Center within the frame if possible */
- x = titlebar_rect.x + (titlebar_rect.width - text_width) / 2;
- y = titlebar_rect.y + (titlebar_rect.height - logical.height) / 2;
-
- if (x < fgeom->title_rect.x)
- x = fgeom->title_rect.x;
- else if (x + text_width > fgeom->title_rect.x + fgeom->title_rect.width)
- x = fgeom->title_rect.x + fgeom->title_rect.width - text_width;
-
- style = style_info->styles[META_STYLE_ELEMENT_TITLE];
- gtk_render_layout (style, cr, x, y, title_layout);
- }
-
- style = style_info->styles[META_STYLE_ELEMENT_BUTTON];
- state = gtk_style_context_get_state (style);
- for (button_type = META_BUTTON_TYPE_CLOSE; button_type < META_BUTTON_TYPE_LAST; button_type++)
- {
- MetaButtonState button_state;
- const char *button_class;
-
- button_class = get_class_from_button_type (button_type);
-
- if (button_class)
- gtk_style_context_add_class (style, button_class);
-
- get_button_rect (button_type, fgeom, 0, &button_rect);
-
- button_state = map_button_state (button_type, fgeom, 0, button_states);
-
- if (button_state == META_BUTTON_STATE_PRELIGHT)
- gtk_style_context_set_state (style, state | GTK_STATE_PRELIGHT);
- else if (button_state == META_BUTTON_STATE_PRESSED)
- gtk_style_context_set_state (style, state | GTK_STATE_ACTIVE);
- else
- gtk_style_context_set_state (style, state);
-
- cairo_save (cr);
-
- if (button_rect.width > 0 && button_rect.height > 0)
- {
- GdkPixbuf *pixbuf = NULL;
- const char *icon_name = NULL;
-
- gtk_render_background (style, cr,
- button_rect.x, button_rect.y,
- button_rect.width, button_rect.height);
- gtk_render_frame (style, cr,
- button_rect.x, button_rect.y,
- button_rect.width, button_rect.height);
-
- switch (button_type)
- {
- case META_BUTTON_TYPE_CLOSE:
- icon_name = "window-close-symbolic";
- break;
- case META_BUTTON_TYPE_MAXIMIZE:
- if (flags & META_FRAME_MAXIMIZED)
- icon_name = "window-restore-symbolic";
- else
- icon_name = "window-maximize-symbolic";
- break;
- case META_BUTTON_TYPE_MINIMIZE:
- icon_name = "window-minimize-symbolic";
- break;
- case META_BUTTON_TYPE_MENU:
- icon_name = "open-menu-symbolic";
- break;
- case META_BUTTON_TYPE_APPMENU:
- pixbuf = g_object_ref (mini_icon);
- break;
- case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
- case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
- case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
- case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
- case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
- case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
- case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
- case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
- case META_BUTTON_TYPE_SHADE:
- case META_BUTTON_TYPE_ABOVE:
- case META_BUTTON_TYPE_STICK:
- case META_BUTTON_TYPE_UNSHADE:
- case META_BUTTON_TYPE_UNABOVE:
- case META_BUTTON_TYPE_UNSTICK:
- case META_BUTTON_TYPE_LAST:
- default:
- icon_name = NULL;
- break;
- }
-
- if (icon_name)
- {
- GtkIconTheme *theme = gtk_icon_theme_get_default ();
- GtkIconInfo *info;
-
- info = gtk_icon_theme_lookup_icon (theme, icon_name, frame_style->layout->icon_size, 0);
- pixbuf = gtk_icon_info_load_symbolic_for_context (info, style, NULL, NULL);
- }
-
- if (pixbuf)
- {
- float width, height;
- int x, y;
-
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
- x = button_rect.x + (button_rect.width - width) / 2;
- y = button_rect.y + (button_rect.height - height) / 2;
-
- cairo_translate (cr, x, y);
- cairo_scale (cr,
- width / frame_style->layout->icon_size,
- height / frame_style->layout->icon_size);
- gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
- cairo_paint (cr);
-
- g_object_unref (pixbuf);
- }
- }
-
- cairo_restore (cr);
-
- if (button_class)
- gtk_style_context_remove_class (style, button_class);
- }
-}
-
MetaTheme*
meta_theme_get_current (void)
{
@@ -1568,130 +122,3 @@ meta_theme_set_current (const gchar *name,
g_debug ("New theme is '%s'", name);
}
}
-
-void
-meta_theme_draw_frame (MetaTheme *theme,
- const gchar *theme_variant,
- cairo_t *cr,
- MetaFrameType type,
- MetaFrameFlags flags,
- int client_width,
- int client_height,
- PangoLayout *title_layout,
- int text_height,
- const MetaButtonLayout *button_layout,
- MetaButtonState button_states[META_BUTTON_TYPE_LAST],
- GdkPixbuf *mini_icon,
- GdkPixbuf *icon)
-{
- MetaFrameGeometry fgeom;
- MetaFrameStyle *style;
- MetaStyleInfo *style_info;
-
- g_return_if_fail (type < META_FRAME_TYPE_LAST);
-
- style = meta_theme_get_frame_style (theme, type, flags);
-
- /* Parser is not supposed to allow this currently */
- if (style == NULL)
- return;
-
- style_info = meta_theme_get_style_info (theme, theme_variant);
-
- meta_frame_layout_calc_geometry (style->layout,
- style_info,
- text_height,
- flags,
- client_width, client_height,
- button_layout,
- type,
- &fgeom,
- theme);
-
- if (meta_theme_get_theme_type (theme) == META_THEME_TYPE_METACITY)
- {
- meta_frame_style_draw_with_style (style,
- style_info,
- cr,
- &fgeom,
- title_layout,
- button_states,
- mini_icon,
- icon);
- }
- else
- {
- meta_frame_style_draw_with_style_gtk (style,
- style_info,
- cr,
- &fgeom,
- title_layout,
- flags,
- button_states,
- mini_icon);
- }
-}
-
-void
-meta_theme_get_frame_borders (MetaTheme *theme,
- const gchar *theme_variant,
- MetaFrameType type,
- int text_height,
- MetaFrameFlags flags,
- MetaFrameBorders *borders)
-{
- MetaFrameStyle *style;
- MetaStyleInfo *style_info;
-
- g_return_if_fail (type < META_FRAME_TYPE_LAST);
-
- style = meta_theme_get_frame_style (theme, type, flags);
-
- meta_frame_borders_clear (borders);
-
- /* Parser is not supposed to allow this currently */
- if (style == NULL)
- return;
-
- style_info = meta_theme_get_style_info (theme, theme_variant);
-
- meta_frame_layout_sync_with_style (style->layout, style_info, flags, theme);
-
- meta_frame_layout_get_borders (theme, style->layout, text_height,
- flags, type, borders);
-}
-
-void
-meta_theme_calc_geometry (MetaTheme *theme,
- const gchar *theme_variant,
- MetaFrameType type,
- int text_height,
- MetaFrameFlags flags,
- int client_width,
- int client_height,
- const MetaButtonLayout *button_layout,
- MetaFrameGeometry *fgeom)
-{
- MetaFrameStyle *style;
- MetaStyleInfo *style_info;
-
- g_return_if_fail (type < META_FRAME_TYPE_LAST);
-
- style = meta_theme_get_frame_style (theme, type, flags);
-
- /* Parser is not supposed to allow this currently */
- if (style == NULL)
- return;
-
- style_info = meta_theme_get_style_info (theme, theme_variant);
-
- meta_frame_layout_calc_geometry (style->layout,
- style_info,
- text_height,
- flags,
- client_width, client_height,
- button_layout,
- type,
- fgeom,
- theme);
-}
diff --git a/src/ui/theme.h b/src/ui/theme.h
index 5c1df6e9..e9ae007c 100644
--- a/src/ui/theme.h
+++ b/src/ui/theme.h
@@ -31,34 +31,4 @@ void meta_theme_set_current (const char *name,
gboolean composited,
const PangoFontDescription *titlebar_font);
-void meta_theme_draw_frame (MetaTheme *theme,
- const gchar *variant,
- cairo_t *cr,
- MetaFrameType type,
- MetaFrameFlags flags,
- int client_width,
- int client_height,
- PangoLayout *title_layout,
- int text_height,
- const MetaButtonLayout *button_layout,
- MetaButtonState button_states[META_BUTTON_TYPE_LAST],
- GdkPixbuf *mini_icon,
- GdkPixbuf *icon);
-
-void meta_theme_get_frame_borders (MetaTheme *theme,
- const gchar *variant,
- MetaFrameType type,
- int text_height,
- MetaFrameFlags flags,
- MetaFrameBorders *borders);
-void meta_theme_calc_geometry (MetaTheme *theme,
- const gchar *variant,
- MetaFrameType type,
- int text_height,
- MetaFrameFlags flags,
- int client_width,
- int client_height,
- const MetaButtonLayout *button_layout,
- MetaFrameGeometry *fgeom);
-
#endif