summaryrefslogtreecommitdiff
path: root/libmetacity/meta-theme-gtk.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmetacity/meta-theme-gtk.c')
-rw-r--r--libmetacity/meta-theme-gtk.c503
1 files changed, 214 insertions, 289 deletions
diff --git a/libmetacity/meta-theme-gtk.c b/libmetacity/meta-theme-gtk.c
index 94fba18d..22a8f67f 100644
--- a/libmetacity/meta-theme-gtk.c
+++ b/libmetacity/meta-theme-gtk.c
@@ -288,120 +288,6 @@ meta_theme_gtk_get_frame_borders (MetaThemeImpl *impl,
scale_border (&borders->total, scale);
}
-static MetaButtonSpace *
-rect_for_type (MetaFrameGeometry *fgeom,
- MetaFrameFlags flags,
- MetaButtonType type)
-{
- switch (type)
- {
- case META_BUTTON_TYPE_MENU:
- if (flags & META_FRAME_ALLOWS_MENU)
- return &fgeom->menu_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_APPMENU:
- if (flags & META_FRAME_ALLOWS_APPMENU)
- return &fgeom->appmenu_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_MINIMIZE:
- if (flags & META_FRAME_ALLOWS_MINIMIZE)
- return &fgeom->min_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_MAXIMIZE:
- if (flags & META_FRAME_ALLOWS_MAXIMIZE)
- return &fgeom->max_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_CLOSE:
- if (flags & META_FRAME_ALLOWS_DELETE)
- return &fgeom->close_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_SHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
- return &fgeom->shade_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_ABOVE:
- if (!(flags & META_FRAME_ABOVE))
- return &fgeom->above_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_STICK:
- if (!(flags & META_FRAME_STUCK))
- return &fgeom->stick_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_UNSHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
- return &fgeom->unshade_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_UNABOVE:
- if (flags & META_FRAME_ABOVE)
- return &fgeom->unabove_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_UNSTICK:
- if (flags & META_FRAME_STUCK)
- return &fgeom->unstick_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_LAST:
- default:
- break;
- }
-
- return NULL;
-}
-
-static gboolean
-strip_button (MetaButtonSpace *func_rects[META_BUTTON_TYPE_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];
-
- ++i;
- }
-
- func_rects[i] = NULL;
-
- return TRUE;
- }
-
- ++i;
- }
-
- return FALSE; /* did not strip anything */
-}
-
static void
meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
MetaFrameLayout *layout,
@@ -425,14 +311,6 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
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_TYPE_LAST];
- MetaButtonSpace *right_func_rects[META_BUTTON_TYPE_LAST];
- gboolean left_buttons_has_spacer[META_BUTTON_TYPE_LAST];
- gboolean right_buttons_has_spacer[META_BUTTON_TYPE_LAST];
-
META_THEME_IMPL_GET_CLASS (impl)->get_frame_borders (impl, layout,
style_info, text_height,
flags, type, &borders);
@@ -464,16 +342,6 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
button_width *= scale;
button_height *= scale;
- /* 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;
@@ -481,35 +349,44 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
if (!layout->hide_buttons)
{
- /* Try to fill in rects */
- for (i = 0; i < META_BUTTON_TYPE_LAST && button_layout->left_buttons[i] != META_BUTTON_TYPE_LAST; i++)
+ MetaButton *button;
+
+ for (i = 0; i < button_layout->n_left_buttons; i++)
{
- left_func_rects[n_left] = rect_for_type (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;
+ button = &button_layout->left_buttons[i];
+ button->visible = is_button_visible (button, flags);
- ++n_left;
+ if (button->visible)
+ {
+ if (button->type != META_BUTTON_TYPE_SPACER)
+ n_left++;
+ else
+ n_left_spacers++;
}
}
- for (i = 0; i < META_BUTTON_TYPE_LAST && button_layout->right_buttons[i] != META_BUTTON_TYPE_LAST; i++)
+ for (i = 0; i < button_layout->n_right_buttons; i++)
{
- right_func_rects[n_right] = rect_for_type (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;
+ button = &button_layout->right_buttons[i];
+ button->visible = is_button_visible (button, flags);
- ++n_right;
+ if (button->visible)
+ {
+ if (button->type != META_BUTTON_TYPE_SPACER)
+ n_left++;
+ else
+ n_left_spacers++;
}
}
}
+ else
+ {
+ for (i = 0; i < button_layout->n_left_buttons; i++)
+ button_layout->left_buttons[i].visible = FALSE;
+
+ for (i = 0; i < button_layout->n_right_buttons; i++)
+ button_layout->right_buttons[i].visible = FALSE;
+ }
/* Be sure buttons fit */
while (n_left > 0 || n_right > 0)
@@ -536,51 +413,41 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
/* First try to remove separators */
if (n_left_spacers > 0)
{
- left_buttons_has_spacer[--n_left_spacers] = FALSE;
- continue;
+ if (strip_button (button_layout->left_buttons,
+ button_layout->n_left_buttons,
+ META_BUTTON_TYPE_SPACER))
+ {
+ n_left_spacers--;
+ continue;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
}
else if (n_right_spacers > 0)
{
- right_buttons_has_spacer[--n_right_spacers] = FALSE;
- continue;
+ if (strip_button (button_layout->right_buttons,
+ button_layout->n_right_buttons,
+ META_BUTTON_TYPE_SPACER))
+ {
+ n_right_spacers--;
+ continue;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
}
/* 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, &n_left, &fgeom->above_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->above_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->stick_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->stick_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->shade_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->shade_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->min_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->min_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->max_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->max_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->close_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->close_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->menu_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->menu_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->appmenu_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->appmenu_rect))
- continue;
+ if (strip_buttons (button_layout, &n_left, &n_right))
+ {
+ continue;
+ }
else
{
g_error ("Could not find a button to strip. n_left = %d n_right = %d",
@@ -588,10 +455,6 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
}
}
- /* Save the button layout */
- button_layout->n_left_buttons = n_left;
- button_layout->n_right_buttons = n_right;
-
/* center buttons vertically */
button_y = borders.invisible.top + layout->gtk.frame_border.top * scale +
(content_height - button_height) / 2;
@@ -600,48 +463,61 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
x = width - borders.invisible.right - layout->gtk.frame_border.right * scale -
layout->gtk.titlebar_border.right * scale;
- i = n_right - 1;
- while (i >= 0)
+ for (i = button_layout->n_right_buttons - 1; i >= 0; i--)
{
- MetaButtonSpace *rect;
+ MetaButton *button;
+ GdkRectangle rect;
+
+ button = &button_layout->right_buttons[i];
+
+ if (button->visible == FALSE)
+ continue;
- if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
+ /* if we go negative, leave the buttons we don't get to as 0 - width */
+ if (x < 0)
break;
x -= layout->gtk.button_margin.right * scale;
- rect = right_func_rects[i];
+ rect.y = button_y;
+ rect.width = button_width;
+ rect.height = button_height;
- rect->visible.x = x - button_width;
- if (right_buttons_has_spacer[i])
- rect->visible.x -= (button_width * 0.75);
+ if (button->type == META_BUTTON_TYPE_SPACER)
+ {
+ rect.x = x - button_width * 0.75;
+ rect.width *= 0.75;
+ }
+ else
+ {
+ rect.x = x - button_width;
+ }
- rect->visible.y = button_y;
- rect->visible.width = button_width;
- rect->visible.height = button_height;
+ button->rect.visible = rect;
+ button->rect.clickable = rect;
- if (flags & META_FRAME_MAXIMIZED ||
- flags & META_FRAME_TILED_LEFT ||
- flags & META_FRAME_TILED_RIGHT)
+ if ((flags & META_FRAME_MAXIMIZED || flags & META_FRAME_TILED_RIGHT) &&
+ i == button_layout->n_right_buttons - 1)
{
- 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->gtk.frame_border.right * scale +
- layout->gtk.titlebar_border.right * scale;
+ gint extra_width;
+ gint extra_height;
+
+ extra_width = layout->gtk.button_margin.right * scale +
+ layout->gtk.frame_border.right * scale +
+ layout->gtk.titlebar_border.right * scale;
+
+ /* FIXME: */
+ extra_height = 0;
+
+ button->rect.clickable.y -= extra_height;
+ button->rect.clickable.width += extra_width;
+ button->rect.clickable.height += extra_height;
}
- else
- g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
- x = rect->visible.x - layout->gtk.button_margin.left * scale;
+ x = rect.x - layout->gtk.button_margin.left * scale;
if (i > 0)
x -= layout->gtk.titlebar_spacing * scale;
-
- --i;
}
/* save right edge of titlebar for later use */
@@ -653,34 +529,50 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
x = borders.invisible.left + layout->gtk.frame_border.left * scale +
layout->gtk.titlebar_border.left * scale;
- for (i = 0; i < n_left; i++)
+ for (i = 0; i < button_layout->n_left_buttons; i++)
{
- MetaButtonSpace *rect;
+ MetaButton *button;
+ GdkRectangle rect;
+
+ button = &button_layout->left_buttons[i];
+
+ if (button->visible == FALSE)
+ continue;
- x += layout->gtk.button_margin.left * scale;
+ rect.x = x + layout->gtk.button_margin.left * scale;
+ rect.y = button_y;
+ rect.width = button_width;
+ rect.height = button_height;
- rect = left_func_rects[i];
+ if (button->type == META_BUTTON_TYPE_SPACER)
+ rect.width *= 0.75;
- rect->visible.x = x;
- rect->visible.y = button_y;
- rect->visible.width = button_width;
- rect->visible.height = button_height;
+ button->rect.visible = rect;
+ button->rect.clickable = rect;
- if (flags & META_FRAME_MAXIMIZED)
+ if ((flags & META_FRAME_MAXIMIZED || flags & META_FRAME_TILED_LEFT) &&
+ i == 0)
{
- rect->clickable.x = rect->visible.x;
- rect->clickable.y = rect->visible.y;
- rect->clickable.width = button_width;
- rect->clickable.height = button_height;
+ gint extra_width;
+ gint extra_height;
+
+ extra_width = layout->gtk.button_margin.left * scale +
+ layout->gtk.frame_border.left * scale +
+ layout->gtk.titlebar_border.left * scale;
+
+ /* FIXME: */
+ extra_height = 0;
+
+ button->rect.clickable.x -= extra_width;
+ button->rect.clickable.y -= extra_height;
+ button->rect.clickable.width += extra_width;
+ button->rect.clickable.height += extra_height;
}
- else
- g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
- x = rect->visible.x + rect->visible.width + layout->gtk.button_margin.right * scale;
- if (i < n_left - 1)
+ x = rect.x + rect.width + layout->gtk.button_margin.right * scale;
+
+ if (i < button_layout->n_left_buttons - 1)
x += layout->gtk.titlebar_spacing * scale;
- if (left_buttons_has_spacer[i])
- x += (button_width * 0.75);
}
/* Center vertically in the available content area */
@@ -747,10 +639,10 @@ meta_theme_gtk_draw_frame (MetaThemeImpl *impl,
gdouble scale;
GtkStyleContext *context;
GtkStateFlags state;
- MetaButtonType button_type;
MetaRectangleDouble visible_rect;
MetaRectangleDouble titlebar_rect;
const MetaFrameBorders *borders;
+ gint side;
/* We opt out of GTK+ HiDPI handling, so we have to do the scaling
* ourselves; the nitty-gritty is a bit confusing, so here is an overview:
@@ -827,49 +719,73 @@ meta_theme_gtk_draw_frame (MetaThemeImpl *impl,
context = meta_style_info_get_style (style_info, META_STYLE_ELEMENT_BUTTON);
state = gtk_style_context_get_state (context);
- for (button_type = 0; button_type < META_BUTTON_TYPE_LAST; button_type++)
- {
- MetaButtonState button_state;
- const char *button_class;
- GdkRectangle tmp_rect;
- MetaRectangleDouble button_rect;
- button_class = get_class_from_button_type (button_type);
+ for (side = 0; side < 2; side++)
+ {
+ MetaButton *buttons;
+ gint n_buttons;
+ gint i;
- if (button_class)
- gtk_style_context_add_class (context, button_class);
+ if (side == 0)
+ {
+ buttons = button_layout->left_buttons;
+ n_buttons = button_layout->n_left_buttons;
+ }
+ else if (side == 1)
+ {
+ buttons = button_layout->right_buttons;
+ n_buttons = button_layout->n_right_buttons;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
- button_state = button_layout->button_states[button_type];
+ for (i = 0; i < n_buttons; i++)
+ {
+ MetaButton *button;
+ gdouble x;
+ gdouble y;
+ gdouble width;
+ gdouble height;
+ const gchar *button_class;
+ const gchar *icon_name;
+ GdkPixbuf *pixbuf;
+
+ button = &buttons[i];
+
+ x = button->rect.visible.x / scale;
+ y = button->rect.visible.y / scale;
+ width = button->rect.visible.width / scale;
+ height = button->rect.visible.height / scale;
+
+ if (!button->visible || button->type == META_BUTTON_TYPE_SPACER ||
+ width <= 0 || height <= 0)
+ {
+ continue;
+ }
- 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);
+ button_class = get_class_from_button_type (button->type);
- cairo_save (cr);
+ if (button_class)
+ gtk_style_context_add_class (context, button_class);
- get_button_rect_for_type (button_type, fgeom, &tmp_rect);
+ 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);
- button_rect.x = tmp_rect.x / scale;
- button_rect.y = tmp_rect.y / scale;
- button_rect.width = tmp_rect.width / scale;
- button_rect.height = tmp_rect.height / scale;
+ 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, x, y, width, height);
+ gtk_render_frame (context, cr, x, y, width, height);
- 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);
+ icon_name = NULL;
+ pixbuf = NULL;
- switch (button_type)
+ switch (button->type)
{
case META_BUTTON_TYPE_CLOSE:
icon_name = "window-close-symbolic";
@@ -895,49 +811,58 @@ meta_theme_gtk_draw_frame (MetaThemeImpl *impl,
case META_BUTTON_TYPE_UNSHADE:
case META_BUTTON_TYPE_UNABOVE:
case META_BUTTON_TYPE_UNSTICK:
+ case META_BUTTON_TYPE_SPACER:
case META_BUTTON_TYPE_LAST:
default:
- icon_name = NULL;
break;
}
if (icon_name)
{
- GtkIconTheme *theme = gtk_icon_theme_get_default ();
+ GtkIconTheme *theme;
GtkIconInfo *info;
+ theme = gtk_icon_theme_get_default ();
info = gtk_icon_theme_lookup_icon_for_scale (theme, icon_name,
style->layout->gtk.icon_size,
scale, 0);
+ g_assert (pixbuf == NULL);
pixbuf = gtk_icon_info_load_symbolic_for_context (info, context, NULL, NULL);
}
if (pixbuf)
{
- float width, height;
- gdouble x, y;
-
- width = gdk_pixbuf_get_width (pixbuf) / scale;
- height = gdk_pixbuf_get_height (pixbuf) / scale;
- 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->gtk.icon_size / scale,
- height / style->layout->gtk.icon_size / scale);
+ gdouble pwidth;
+ gdouble pheight;
+ gdouble px;
+ gdouble py;
+ gdouble scale_x;
+ gdouble scale_y;
+
+ pwidth = gdk_pixbuf_get_width (pixbuf) / scale;
+ pheight = gdk_pixbuf_get_height (pixbuf) / scale;
+ px = x + (width - pwidth) / 2;
+ py = y + (height - pheight) / 2;
+
+ scale_x = pwidth / style->layout->gtk.icon_size / scale;
+ scale_y = pheight / style->layout->gtk.icon_size / scale;
+
+ cairo_translate (cr, px, py);
+ cairo_scale (cr, scale_x, scale_y);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_paint (cr);
g_object_unref (pixbuf);
}
- }
- cairo_restore (cr);
+ cairo_restore (cr);
+
+ if (button_class)
+ gtk_style_context_remove_class (context, button_class);
- if (button_class)
- gtk_style_context_remove_class (context, button_class);
+ gtk_style_context_set_state (context, state);
+ }
}
}