diff options
author | Alberts Muktupāvels <alberts.muktupavels@gmail.com> | 2016-02-04 00:15:47 +0200 |
---|---|---|
committer | Alberts Muktupāvels <alberts.muktupavels@gmail.com> | 2016-02-04 00:15:47 +0200 |
commit | 99f79563ae5e2c777544ec59cfdbfb8e4f38c162 (patch) | |
tree | 07e49b63dc34e277d007f8a5c1608f985384a523 | |
parent | aac68269e8a2909ae510e9eb5ffe1f627bd408ee (diff) | |
download | metacity-99f79563ae5e2c777544ec59cfdbfb8e4f38c162.tar.gz |
theme: move get_frame_borders, calc_geometry and draw_frame
-rw-r--r-- | libmetacity/meta-theme-gtk.c | 884 | ||||
-rw-r--r-- | libmetacity/meta-theme-impl-private.h | 66 | ||||
-rw-r--r-- | libmetacity/meta-theme-impl.c | 190 | ||||
-rw-r--r-- | libmetacity/meta-theme-metacity-private.h | 2 | ||||
-rw-r--r-- | libmetacity/meta-theme-metacity.c | 815 | ||||
-rw-r--r-- | libmetacity/meta-theme.c | 124 | ||||
-rw-r--r-- | libmetacity/meta-theme.h | 31 | ||||
-rw-r--r-- | src/ui/theme.c | 1573 | ||||
-rw-r--r-- | src/ui/theme.h | 30 |
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 |