From 8b680dfdd2b6d4447430bb8da6c3e77c3fc38563 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 6 Jan 2002 04:51:53 +0000 Subject: [PATCH] draw titlebar highlight with snazzy gradient that needs some tweaking to 2002-01-05 Havoc Pennington * src/frames.c (meta_frames_expose_event): draw titlebar highlight with snazzy gradient that needs some tweaking to be less dumb-looking * src/theme.c: replace old theme.[hc] contents with newer stuff that doesn't do anything --- ChangeLog | 9 + src/Makefile.am | 2 + src/frames.c | 26 ++ src/theme.c | 1055 ++++++++++++----------------------------------- src/theme.h | 122 +----- src/util.c | 3 + src/util.h | 3 +- 7 files changed, 312 insertions(+), 908 deletions(-) diff --git a/ChangeLog b/ChangeLog index df35791f6..e03a1ef20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2002-01-05 Havoc Pennington + + * src/frames.c (meta_frames_expose_event): draw titlebar highlight + with snazzy gradient that needs some tweaking to be less + dumb-looking + + * src/theme.c: replace old theme.[hc] contents with newer stuff + that doesn't do anything + 2002-01-05 Havoc Pennington GTK 1.2 plug/socket clients still broken, don't know why. diff --git a/src/Makefile.am b/src/Makefile.am index 5e79e91e9..7bca75d24 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,6 +40,8 @@ metacity_SOURCES= \ stack.h \ tabpopup.c \ tabpopup.h \ + theme.c \ + theme.h \ ui.c \ ui.h \ util.c \ diff --git a/src/frames.c b/src/frames.c index ba81fcae8..6a6549ae1 100644 --- a/src/frames.c +++ b/src/frames.c @@ -25,6 +25,7 @@ #include "core.h" #include "menu.h" #include "fixedtip.h" +#include "theme.h" #define DEFAULT_INNER_BUTTON_BORDER 3 @@ -1759,6 +1760,7 @@ meta_frames_expose_event (GtkWidget *widget, { layout_gc = widget->style->fg_gc[GTK_STATE_SELECTED]; +#if 0 /* Draw blue background */ gdk_draw_rectangle (frame->window, widget->style->bg_gc[GTK_STATE_SELECTED], @@ -1767,6 +1769,30 @@ meta_frames_expose_event (GtkWidget *widget, fgeom.title_rect.y, fgeom.title_rect.width, fgeom.title_rect.height); +#else + { + GdkPixbuf *gradient; + + gradient = meta_theme_get_gradient (META_GRADIENT_HORIZONTAL, + &widget->style->bg[GTK_STATE_SELECTED], + &widget->style->bg[GTK_STATE_NORMAL], + fgeom.title_rect.width, + fgeom.title_rect.height); + + gdk_pixbuf_render_to_drawable (gradient, + frame->window, + widget->style->bg_gc[GTK_STATE_SELECTED], + 0, 0, + fgeom.title_rect.x, + fgeom.title_rect.y, + fgeom.title_rect.width, + fgeom.title_rect.height, + GDK_RGB_DITHER_NORMAL, + 0, 0); + + g_object_unref (G_OBJECT (gradient)); + } +#endif } if (frame->layout) diff --git a/src/theme.c b/src/theme.c index 76d104b92..ada597a93 100644 --- a/src/theme.c +++ b/src/theme.c @@ -1,4 +1,4 @@ -/* Metacity Default Theme Engine */ +/* Metacity Theme Rendering */ /* * Copyright (C) 2001 Havoc Pennington @@ -20,822 +20,281 @@ */ #include "theme.h" -#include "api.h" #include "util.h" +#include -typedef struct _DefaultFrameData DefaultFrameData; -typedef struct _DefaultScreenData DefaultScreenData; -typedef struct _DefaultFrameGeometry DefaultFrameGeometry; - -struct _DefaultFrameGeometry -{ - /* We recalculate this every time, to save RAM */ - int left_width; - int right_width; - int top_height; - int bottom_height; - - MetaRectangle close_rect; - MetaRectangle max_rect; - MetaRectangle min_rect; - MetaRectangle spacer_rect; - MetaRectangle menu_rect; - MetaRectangle title_rect; -}; - -struct _DefaultFrameData -{ - PangoLayout *layout; - int layout_height; -}; - -struct _DefaultScreenData -{ - GC text_gc; - GC fg_gc; - GC light_gc; - GC dark_gc; - GC black_gc; - GC selected_gc; - GC selected_text_gc; - GC active_gc; - GC prelight_gc; -}; - -/* FIXME store this on the screen */ -static DefaultScreenData *screen_data = NULL; - -static gpointer -default_acquire_frame (MetaFrameInfo *info) -{ - DefaultFrameData *d; - PangoFontDescription *desc; - XGCValues vals; - - if (screen_data == NULL) - { - PangoColor color; - - screen_data = g_new (DefaultScreenData, 1); - - vals.foreground = meta_get_x_pixel (info->screen, - &info->colors->fg[META_STATE_NORMAL]); - - screen_data->text_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - screen_data->fg_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - - vals.foreground = meta_get_x_pixel (info->screen, - &info->colors->light[META_STATE_NORMAL]); - screen_data->light_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - - vals.foreground = meta_get_x_pixel (info->screen, - &info->colors->dark[META_STATE_NORMAL]); - screen_data->dark_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - - vals.foreground = meta_get_x_pixel (info->screen, - &info->colors->bg[META_STATE_SELECTED]); - screen_data->selected_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - vals.foreground = meta_get_x_pixel (info->screen, - &info->colors->fg[META_STATE_SELECTED]); - screen_data->selected_text_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - - vals.foreground = meta_get_x_pixel (info->screen, - &info->colors->bg[META_STATE_ACTIVE]); - screen_data->active_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - - vals.foreground = meta_get_x_pixel (info->screen, - &info->colors->bg[META_STATE_PRELIGHT]); - screen_data->prelight_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - - - color.red = color.green = color.blue = 0; - vals.foreground = meta_get_x_pixel (info->screen, - &color); - screen_data->black_gc = XCreateGC (info->display, - RootWindowOfScreen (info->screen), - GCForeground, - &vals); - } - - d = g_new (DefaultFrameData, 1); - - desc = pango_font_description_from_string ("Sans 12"); - d->layout = pango_layout_new (meta_get_pango_context (info->screen, - desc)); - pango_font_description_free (desc); - - d->layout_height = 0; - - return d; -} - +/* fill_gradient routine from GNOME background-properties, CVS says + * Michael Fulbright checked it in, Copyright 1998 Red Hat Inc. + */ static void -default_release_frame (MetaFrameInfo *info, - gpointer frame_data) +fill_gradient (GdkPixbuf *pixbuf, + const GdkColor *c1, + const GdkColor *c2, + int vertical, + int gradient_width, + int gradient_height, + int pixbuf_x, + int pixbuf_y) { - DefaultFrameData *d; + int i, j; + int dr, dg, db; + int gs1; + int vc = (!vertical || (c1 == c2)); + int w = gdk_pixbuf_get_width (pixbuf); + int h = gdk_pixbuf_get_height (pixbuf); + guchar *b, *row; + guchar *d = gdk_pixbuf_get_pixels (pixbuf); + int rowstride = gdk_pixbuf_get_rowstride (pixbuf); - d = frame_data; +#define R1 c1->red +#define G1 c1->green +#define B1 c1->blue +#define R2 c2->red +#define G2 c2->green +#define B2 c2->blue - if (d->layout) - g_object_unref (G_OBJECT (d->layout)); - - g_free (d); -} + dr = R2 - R1; + dg = G2 - G1; + db = B2 - B1; -#define ABOVE_TITLE_PAD 4 -#define BELOW_TITLE_PAD 3 -#define RIGHT_TITLE_PAD 4 -#define LEFT_TITLE_PAD 3 -#define VERTICAL_TEXT_PAD 2 -#define HORIZONTAL_TEXT_PAD 2 -#define LEFT_WIDTH 6 -#define RIGHT_WIDTH 6 -#define BOTTOM_HEIGHT 7 -#define SPACER_SPACING 3 -#define SPACER_WIDTH 2 -#define SPACER_HEIGHT 10 -#define BUTTON_WIDTH 14 -#define BUTTON_HEIGHT 14 -#define BUTTON_PAD 1 -#define INNER_BUTTON_PAD 3 -static void -calc_geometry (MetaFrameInfo *info, - DefaultFrameData *d, - DefaultFrameGeometry *fgeom) -{ - int x; - int button_y; - int title_right_edge; - gboolean shaded; + gs1 = (vertical) ? gradient_height - 1 : gradient_width - 1; - shaded = (info->flags & META_FRAME_SHADED) != 0; - - fgeom->top_height = MAX (d->layout_height + VERTICAL_TEXT_PAD * 2 + ABOVE_TITLE_PAD + BELOW_TITLE_PAD, - BUTTON_HEIGHT + BUTTON_PAD * 2); + row = g_new (unsigned char, rowstride); - fgeom->left_width = LEFT_WIDTH; - fgeom->right_width = RIGHT_WIDTH; - - if (shaded) - fgeom->bottom_height = 0; - else - fgeom->bottom_height = BOTTOM_HEIGHT; - - x = info->width - fgeom->right_width; - button_y = (fgeom->top_height - BUTTON_HEIGHT) / 2; - - if (info->flags & META_FRAME_ALLOWS_DELETE) + if (vc) { - fgeom->close_rect.x = x - BUTTON_PAD - BUTTON_WIDTH; - fgeom->close_rect.y = button_y; - fgeom->close_rect.width = BUTTON_WIDTH; - fgeom->close_rect.height = BUTTON_HEIGHT; - - x = fgeom->close_rect.x; - } - else - { - fgeom->close_rect.x = 0; - fgeom->close_rect.y = 0; - fgeom->close_rect.width = 0; - fgeom->close_rect.height = 0; - } - - if (info->flags & META_FRAME_ALLOWS_MAXIMIZE) - { - fgeom->max_rect.x = x - BUTTON_PAD - BUTTON_WIDTH; - fgeom->max_rect.y = button_y; - fgeom->max_rect.width = BUTTON_WIDTH; - fgeom->max_rect.height = BUTTON_HEIGHT; - - x = fgeom->max_rect.x; - } - else - { - fgeom->max_rect.x = 0; - fgeom->max_rect.y = 0; - fgeom->max_rect.width = 0; - fgeom->max_rect.height = 0; - } - - if (info->flags & META_FRAME_ALLOWS_ICONIFY) - { - fgeom->min_rect.x = x - BUTTON_PAD - BUTTON_WIDTH; - fgeom->min_rect.y = button_y; - fgeom->min_rect.width = BUTTON_WIDTH; - fgeom->min_rect.height = BUTTON_HEIGHT; - - x = fgeom->min_rect.x; - } - else - { - fgeom->min_rect.x = 0; - fgeom->min_rect.y = 0; - fgeom->min_rect.width = 0; - fgeom->min_rect.height = 0; - } - - if (fgeom->close_rect.width > 0 || - fgeom->max_rect.width > 0 || - fgeom->min_rect.width > 0) - { - fgeom->spacer_rect.x = x - SPACER_SPACING - SPACER_WIDTH; - fgeom->spacer_rect.y = (fgeom->top_height - SPACER_HEIGHT) / 2; - fgeom->spacer_rect.width = SPACER_WIDTH; - fgeom->spacer_rect.height = SPACER_HEIGHT; - - x = fgeom->spacer_rect.x; - } - else - { - fgeom->spacer_rect.x = 0; - fgeom->spacer_rect.y = 0; - fgeom->spacer_rect.width = 0; - fgeom->spacer_rect.height = 0; - } - - title_right_edge = x - RIGHT_TITLE_PAD; - - /* Now x changes to be position from the left */ - x = fgeom->left_width; - - if (info->flags & META_FRAME_ALLOWS_MENU) - { - fgeom->menu_rect.x = x + BUTTON_PAD; - fgeom->menu_rect.y = button_y; - fgeom->menu_rect.width = BUTTON_WIDTH; - fgeom->menu_rect.height = BUTTON_HEIGHT; - - x = fgeom->menu_rect.x + fgeom->menu_rect.width; - } - else - { - fgeom->menu_rect.x = 0; - fgeom->menu_rect.y = 0; - fgeom->menu_rect.width = 0; - fgeom->menu_rect.height = 0; - } - - fgeom->title_rect.x = x + LEFT_TITLE_PAD; - fgeom->title_rect.y = ABOVE_TITLE_PAD; - fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x; - fgeom->title_rect.height = fgeom->top_height - ABOVE_TITLE_PAD - BELOW_TITLE_PAD; - - if (fgeom->title_rect.width < 0) - fgeom->title_rect.width = 0; -} - -static void -default_fill_frame_geometry (MetaFrameInfo *info, - MetaFrameGeometry *geom, - gpointer frame_data) -{ - DefaultFrameData *d; - PangoRectangle rect; - DefaultFrameGeometry fgeom; - - d = frame_data; - - if (info->title) - pango_layout_set_text (d->layout, info->title, -1); - else - pango_layout_set_text (d->layout, " ", -1); - - pango_layout_get_pixel_extents (d->layout, NULL, &rect); - - d->layout_height = rect.height; - - calc_geometry (info, d, &fgeom); - geom->top_height = fgeom.top_height; - geom->left_width = fgeom.left_width; - geom->right_width = fgeom.right_width; - geom->bottom_height = fgeom.bottom_height; - - geom->background_pixel = meta_get_x_pixel (info->screen, - &info->colors->bg[META_STATE_NORMAL]); -} - -static void -draw_vline (MetaFrameInfo *info, - Drawable drawable, - GC light_gc, - GC dark_gc, - int y1, - int y2, - int x) -{ - int thickness_light; - int thickness_dark; - int i; - - /* From GTK+ */ - - thickness_light = 1; - thickness_dark = 1; - - for (i = 0; i < thickness_dark; i++) - { - XDrawLine (info->display, drawable, light_gc, - x + i, y2 - i - 1, x + i, y2); - XDrawLine (info->display, drawable, dark_gc, - x + i, y1, x + i, y2 - i - 1); - } - - x += thickness_dark; - for (i = 0; i < thickness_light; i++) - { - XDrawLine (info->display, drawable, dark_gc, - x + i, y1, x + i, y1 + thickness_light - i); - XDrawLine (info->display, drawable, light_gc, - x + i, y1 + thickness_light - i, x + i, y2); - } -} - -static void -draw_varrow (MetaFrameInfo *info, - Drawable drawable, - GC gc, - gboolean down, - gint x, - gint y, - gint width, - gint height) -{ - gint steps, extra; - gint y_start, y_increment; - gint i; - - /* From GTK+ */ - - width = width + width % 2 - 1; /* Force odd */ - - steps = 1 + width / 2; - - extra = height - steps; - - if (down) - { - y_start = y; - y_increment = 1; - } - else - { - y_start = y + height - 1; - y_increment = -1; - } - - for (i = 0; i < extra; i++) - { - XDrawLine (info->display, drawable, - gc, - x, y_start + i * y_increment, - x + width - 1, y_start + i * y_increment); - } - for (; i < height; i++) - { - XDrawLine (info->display, drawable, - gc, - x + (i - extra), y_start + i * y_increment, - x + width - (i - extra) - 1, y_start + i * y_increment); - } -} - -static void -set_clip (Display *display, GC gc, MetaRectangle *rect) -{ - if (rect) - { - XRectangle xrect; - - xrect.x = rect->x; - xrect.y = rect->y; - xrect.width = rect->width; - xrect.height = rect->height; - - XSetClipRectangles (display, gc, 0, 0, - &xrect, 1, YXBanded); - } - else - { - XSetClipMask (display, gc, None); - } -} - -static MetaRectangle* -control_rect (MetaFrameControl control, - DefaultFrameGeometry *fgeom) -{ - MetaRectangle *rect; - - rect = NULL; - switch (control) - { - case META_FRAME_CONTROL_TITLE: - rect = &fgeom->title_rect; - break; - case META_FRAME_CONTROL_DELETE: - rect = &fgeom->close_rect; - break; - case META_FRAME_CONTROL_MENU: - rect = &fgeom->menu_rect; - break; - case META_FRAME_CONTROL_ICONIFY: - rect = &fgeom->min_rect; - break; - case META_FRAME_CONTROL_MAXIMIZE: - rect = &fgeom->max_rect; - break; - case META_FRAME_CONTROL_RESIZE_SE: - break; - case META_FRAME_CONTROL_RESIZE_S: - break; - case META_FRAME_CONTROL_RESIZE_SW: - break; - case META_FRAME_CONTROL_RESIZE_N: - break; - case META_FRAME_CONTROL_RESIZE_NE: - break; - case META_FRAME_CONTROL_RESIZE_NW: - break; - case META_FRAME_CONTROL_RESIZE_W: - break; - case META_FRAME_CONTROL_RESIZE_E: - break; - case META_FRAME_CONTROL_NONE: - break; - } - - return rect; -} - -static void -draw_current_control_bg (MetaFrameInfo *info, - DefaultFrameGeometry *fgeom) -{ - int xoff, yoff; - MetaRectangle *rect; - - xoff = info->xoffset; - yoff = info->yoffset; - - rect = control_rect (info->current_control, fgeom); - - if (rect == NULL) - return; - - if (info->current_control == META_FRAME_CONTROL_TITLE) - return; - - switch (info->current_control_state) - { - /* FIXME turn this off after testing */ - case META_STATE_PRELIGHT: - XFillRectangle (info->display, - info->drawable, - screen_data->prelight_gc, - xoff + rect->x, - yoff + rect->y, - rect->width, rect->height); - break; - - case META_STATE_ACTIVE: - XFillRectangle (info->display, - info->drawable, - screen_data->active_gc, - xoff + rect->x, - yoff + rect->y, - rect->width, rect->height); - break; - - default: - break; - } -} - -static void -default_expose_frame (MetaFrameInfo *info, - int x, int y, - int width, int height, - gpointer frame_data) -{ - DefaultFrameData *d; - XGCValues vals; - int xoff, yoff; - DefaultFrameGeometry fgeom; - - d = frame_data; - - calc_geometry (info, d, &fgeom); - - xoff = info->xoffset; - yoff = info->yoffset; - - /* Black line around outside to give definition */ - XDrawRectangle (info->display, - info->drawable, - screen_data->black_gc, - xoff, yoff, - info->width - 1, - info->height - 1); - - /* Light GC on top/left edges */ - XDrawLine (info->display, - info->drawable, - screen_data->light_gc, - xoff + 1, yoff + 1, - xoff + 1, yoff + info->height - 2); - XDrawLine (info->display, - info->drawable, - screen_data->light_gc, - xoff + 1, yoff + 1, - xoff + info->width - 2, yoff + 1); - - /* Dark GC on bottom/right edges */ - XDrawLine (info->display, - info->drawable, - screen_data->dark_gc, - xoff + info->width - 2, yoff + 1, - xoff + info->width - 2, yoff + info->height - 2); - XDrawLine (info->display, - info->drawable, - screen_data->dark_gc, - xoff + 1, yoff + info->height - 2, - xoff + info->width - 2, yoff + info->height - 2); - - if (info->flags & META_FRAME_HAS_FOCUS) - { - /* Black line around inside while we have focus */ - XDrawRectangle (info->display, - info->drawable, - screen_data->black_gc, - xoff + fgeom.left_width - 1, - yoff + fgeom.top_height - 1, - info->width - fgeom.right_width - fgeom.left_width + 1, - info->height - fgeom.bottom_height - fgeom.top_height + 1); - } - - draw_current_control_bg (info, &fgeom); - - if (y < fgeom.top_height && - fgeom.title_rect.width > 0 && fgeom.title_rect.height > 0) - { - int layout_y; - MetaRectangle clip; - GC layout_gc; - - /* center vertically */ - layout_y = fgeom.title_rect.y + - (fgeom.title_rect.height - d->layout_height) / 2; - - clip = fgeom.title_rect; - clip.x += xoff; - clip.y += yoff; - clip.width -= HORIZONTAL_TEXT_PAD; - - layout_gc = screen_data->text_gc; - - if (info->flags & META_FRAME_HAS_FOCUS) + b = row; + for (j = 0; j < w; j++) { - layout_gc = screen_data->selected_text_gc; - - /* Draw blue background */ - XFillRectangle (info->display, - info->drawable, - screen_data->selected_gc, - xoff + fgeom.title_rect.x, - yoff + fgeom.title_rect.y, - fgeom.title_rect.width, - fgeom.title_rect.height); + *b++ = (R1 + ((j + pixbuf_x) * dr) / gs1) >> 8; + *b++ = (G1 + ((j + pixbuf_x) * dg) / gs1) >> 8; + *b++ = (B1 + ((j + pixbuf_x) * db) / gs1) >> 8; } - - set_clip (info->display, layout_gc, &clip); - - pango_x_render_layout (info->display, - info->drawable, - layout_gc, - d->layout, - xoff + fgeom.title_rect.x + HORIZONTAL_TEXT_PAD, - yoff + layout_y); - set_clip (info->display, screen_data->text_gc, NULL); - } - - if (fgeom.close_rect.width > 0 && fgeom.close_rect.height > 0) - { - XDrawLine (info->display, - info->drawable, - screen_data->fg_gc, - xoff + fgeom.close_rect.x + INNER_BUTTON_PAD, - yoff + fgeom.close_rect.y + INNER_BUTTON_PAD, - xoff + fgeom.close_rect.x + fgeom.close_rect.width - INNER_BUTTON_PAD, - yoff + fgeom.close_rect.y + fgeom.close_rect.height - INNER_BUTTON_PAD); - - - XDrawLine (info->display, - info->drawable, - screen_data->fg_gc, - xoff + fgeom.close_rect.x + INNER_BUTTON_PAD, - yoff + fgeom.close_rect.y + fgeom.close_rect.height - INNER_BUTTON_PAD, - xoff + fgeom.close_rect.x + fgeom.close_rect.width - INNER_BUTTON_PAD, - yoff + fgeom.close_rect.y + INNER_BUTTON_PAD); - } - - if (fgeom.max_rect.width > 0 && fgeom.max_rect.height > 0) - { - XDrawRectangle (info->display, - info->drawable, - screen_data->fg_gc, - xoff + fgeom.max_rect.x + INNER_BUTTON_PAD, - yoff + fgeom.max_rect.y + INNER_BUTTON_PAD, - fgeom.max_rect.width - INNER_BUTTON_PAD * 2, - fgeom.max_rect.height - INNER_BUTTON_PAD * 2); - - vals.line_width = 3; - XChangeGC (info->display, - screen_data->fg_gc, - GCLineWidth, - &vals); - - XDrawLine (info->display, - info->drawable, - screen_data->fg_gc, - xoff + fgeom.max_rect.x + INNER_BUTTON_PAD, - yoff + fgeom.max_rect.y + INNER_BUTTON_PAD + vals.line_width / 2, - xoff + fgeom.max_rect.x + fgeom.max_rect.width - INNER_BUTTON_PAD, - yoff + fgeom.max_rect.y + INNER_BUTTON_PAD + vals.line_width / 2); - - vals.line_width = 0; - XChangeGC (info->display, - screen_data->fg_gc, - GCLineWidth, - &vals); - } - - if (fgeom.min_rect.width > 0 && fgeom.min_rect.height > 0) - { - vals.line_width = 3; - XChangeGC (info->display, - screen_data->fg_gc, - GCLineWidth, - &vals); - - XDrawLine (info->display, - info->drawable, - screen_data->fg_gc, - xoff + fgeom.min_rect.x + INNER_BUTTON_PAD, - yoff + fgeom.min_rect.y + fgeom.min_rect.height - INNER_BUTTON_PAD - vals.line_width / 2, - xoff + fgeom.min_rect.x + fgeom.min_rect.width - INNER_BUTTON_PAD, - yoff + fgeom.min_rect.y + fgeom.min_rect.height - INNER_BUTTON_PAD - vals.line_width / 2); - - vals.line_width = 0; - XChangeGC (info->display, - screen_data->fg_gc, - GCLineWidth, - &vals); } - if (fgeom.spacer_rect.width > 0 && fgeom.spacer_rect.height > 0) + for (i = 0; i < h; i++) { - draw_vline (info, info->drawable, - screen_data->light_gc, - screen_data->dark_gc, - yoff + fgeom.spacer_rect.y, - yoff + fgeom.spacer_rect.y + fgeom.spacer_rect.height, - xoff + fgeom.spacer_rect.x); + if (!vc) + { + unsigned char cr, cg, cb; + cr = (R1 + ((i + pixbuf_y) * dr) / gs1) >> 8; + cg = (G1 + ((i + pixbuf_y) * dg) / gs1) >> 8; + cb = (B1 + ((i + pixbuf_y) * db) / gs1) >> 8; + b = row; + for (j = 0; j < w; j++) + { + *b++ = cr; + *b++ = cg; + *b++ = cb; + } + } + memcpy (d, row, w * 3); + d += rowstride; } + +#undef R1 +#undef G1 +#undef B1 +#undef R2 +#undef G2 +#undef B2 - if (fgeom.menu_rect.width > 0 && fgeom.menu_rect.height > 0) - { - int x, y; - x = fgeom.menu_rect.x; - y = fgeom.menu_rect.y; - x += (fgeom.menu_rect.width - 7) / 2; - y += (fgeom.menu_rect.height - 5) / 2; - - draw_varrow (info, info->drawable, screen_data->fg_gc, TRUE, - xoff + x, yoff + y, 7, 5); - } + g_free (row); } -#define POINT_IN_RECT(xcoord, ycoord, rect) \ - ((xcoord) >= (rect).x && \ - (xcoord) < ((rect).x + (rect).width) && \ - (ycoord) >= (rect).y && \ - (ycoord) < ((rect).y + (rect).height)) +typedef struct _CachedGradient CachedGradient; -#define RESIZE_EXTENDS 10 -static MetaFrameControl -default_get_control (MetaFrameInfo *info, - int x, int y, - gpointer frame_data) +struct _CachedGradient { - DefaultFrameData *d; - DefaultFrameGeometry fgeom; - - d = frame_data; - - calc_geometry (info, d, &fgeom); - - if (POINT_IN_RECT (x, y, fgeom.close_rect)) - return META_FRAME_CONTROL_DELETE; - - if (POINT_IN_RECT (x, y, fgeom.min_rect)) - return META_FRAME_CONTROL_ICONIFY; - - if (POINT_IN_RECT (x, y, fgeom.max_rect)) - return META_FRAME_CONTROL_MAXIMIZE; - - if (POINT_IN_RECT (x, y, fgeom.menu_rect)) - return META_FRAME_CONTROL_MENU; - - if (POINT_IN_RECT (x, y, fgeom.title_rect)) - return META_FRAME_CONTROL_TITLE; - - if (y > (info->height - fgeom.bottom_height - RESIZE_EXTENDS) && - x > (info->width - fgeom.right_width - RESIZE_EXTENDS)) - return META_FRAME_CONTROL_RESIZE_SE; - - return META_FRAME_CONTROL_NONE; -} - -static void -default_get_control_rect (MetaFrameInfo *info, - MetaFrameControl control, - int *x, int *y, - int *width, int *height, - gpointer frame_data) -{ - MetaRectangle *rect; - DefaultFrameData *d; - DefaultFrameGeometry fgeom; - - d = frame_data; - - calc_geometry (info, d, &fgeom); - - rect = control_rect (control, &fgeom); - - if (rect) - { - *x = rect->x; - *y = rect->y; - *width = rect->width; - *height = rect->height; - } - else - { - *x = *y = *width = *height = 0; - } -} - -/* FIXME add this to engine vtable */ -static void -default_release_screen (Screen *screen) -{ - if (screen_data) - { - XFreeGC (DisplayOfScreen (screen), screen_data->text_gc); - XFreeGC (DisplayOfScreen (screen), screen_data->fg_gc); - XFreeGC (DisplayOfScreen (screen), screen_data->selected_gc); - XFreeGC (DisplayOfScreen (screen), screen_data->selected_text_gc); - XFreeGC (DisplayOfScreen (screen), screen_data->black_gc); - XFreeGC (DisplayOfScreen (screen), screen_data->light_gc); - XFreeGC (DisplayOfScreen (screen), screen_data->dark_gc); - XFreeGC (DisplayOfScreen (screen), screen_data->active_gc); - XFreeGC (DisplayOfScreen (screen), screen_data->prelight_gc); - } -} - -MetaThemeEngine meta_default_engine = { - NULL, - default_acquire_frame, - default_release_frame, - default_fill_frame_geometry, - default_expose_frame, - default_get_control, - default_get_control_rect + MetaGradientType type; + GdkColor color_one; + GdkColor color_two; + int width; + int height; + GdkPixbuf *pixbuf; + int access_serial; }; + +static GHashTable *gradient_cache = NULL; +static int access_counter = 0; +static int cache_size = 0; + +#define GRADIENT_SIZE(g) ((g)->width * (g)->height * 4) + +#define MAX_CACHE_SIZE (1024 * 128) /* 128k */ + +static guint +cached_gradient_hash (gconstpointer value) +{ + /* I have no idea how to write a hash function. */ + const CachedGradient *gradient = value; + guint colorone_hash = gdk_color_hash (&gradient->color_one); + guint colortwo_hash = gdk_color_hash (&gradient->color_two); + guint hash = (colorone_hash >> 16) | (colortwo_hash << 16); + + hash ^= gradient->width << 22; + hash ^= gradient->height; + hash ^= gradient->type << 15; + + return hash; +} + +static gboolean +cached_gradient_equal (gconstpointer value_a, + gconstpointer value_b) +{ + const CachedGradient *gradient_a = value_a; + const CachedGradient *gradient_b = value_b; + + return gradient_a->type == gradient_b->type && + gradient_a->width == gradient_b->width && + gradient_a->height == gradient_b->height && + gdk_color_equal (&gradient_a->color_one, &gradient_b->color_one) && + gdk_color_equal (&gradient_a->color_two, &gradient_b->color_two); +} + +static void +hash_listify (gpointer key, gpointer value, gpointer data) +{ + GSList **list = data; + + if (key != value) + meta_bug ("Gradient cache got munged (value was overwritten)\n"); + + *list = g_slist_prepend (*list, value); +} + +/* sort gradients so that least-recently-used are first */ +static int +gradient_lru_compare (gconstpointer a, + gconstpointer b) +{ + const CachedGradient *gradient_a = a; + const CachedGradient *gradient_b = b; + + if (gradient_a->access_serial < gradient_b->access_serial) + return -1; + else if (gradient_a->access_serial > gradient_b->access_serial) + return 1; + else + return 0; +} + +static void +expire_some_old_gradients (void) +{ + GSList *all_gradients; + GSList *tmp; + + all_gradients = NULL; + + g_hash_table_foreach (gradient_cache, hash_listify, &all_gradients); + + all_gradients = g_slist_sort (all_gradients, gradient_lru_compare); + + tmp = all_gradients; + while (tmp != NULL) + { + CachedGradient *gradient = tmp->data; + + if (cache_size < MAX_CACHE_SIZE) + break; + + meta_topic (META_DEBUG_GRADIENT_CACHE, + " Removing gradient of size %d from cache of size %d\n", + GRADIENT_SIZE (gradient), cache_size); + + cache_size -= GRADIENT_SIZE (gradient); + + g_hash_table_remove (gradient_cache, gradient); + + g_object_unref (G_OBJECT (gradient->pixbuf)); + g_free (gradient); + + tmp = tmp->next; + } + + g_slist_free (all_gradients); + + meta_topic (META_DEBUG_GRADIENT_CACHE, + "Cache reduced to size %d bytes %d gradients after expiring old gradients\n", + cache_size, g_hash_table_size (gradient_cache)); +} + +GdkPixbuf* +meta_theme_get_gradient (MetaGradientType type, + const GdkColor *color_one, + const GdkColor *color_two, + int width, + int height) +{ + CachedGradient gradient; + CachedGradient *cached; + GdkPixbuf *retval; + + meta_topic (META_DEBUG_GRADIENT_CACHE, + "Requesting %s gradient one %d/%d/%d two %d/%d/%d " + "%d x %d\n", + type == META_GRADIENT_VERTICAL ? "vertical" : "horizontal", + color_one->red / 255, color_one->green / 255, color_one->blue / 255, + color_two->red / 255, color_two->green / 255, color_two->blue / 255, + width, height); + + if (gradient_cache == NULL) + { + gradient_cache = g_hash_table_new (cached_gradient_hash, + cached_gradient_equal); + } + + gradient.type = type; + gradient.color_one = *color_one; + gradient.color_two = *color_two; + gradient.width = width; + gradient.height = height; + gradient.pixbuf = NULL; + gradient.access_serial = access_counter; + + cached = g_hash_table_lookup (gradient_cache, &gradient); + + if (cached) + { + meta_topic (META_DEBUG_GRADIENT_CACHE, + "Found gradient in cache\n"); + ++access_counter; + cached->access_serial = access_counter; + g_object_ref (G_OBJECT (cached->pixbuf)); + return cached->pixbuf; + } + + gradient.pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, + gradient.width, gradient.height); + + fill_gradient (gradient.pixbuf, + &gradient.color_one, + &gradient.color_two, + type == META_GRADIENT_VERTICAL ? TRUE : FALSE, + gradient.width, + gradient.height, + 0, 0); + + cached = g_new (CachedGradient, 1); + *cached = gradient; + + g_hash_table_insert (gradient_cache, cached, cached); + + meta_topic (META_DEBUG_GRADIENT_CACHE, + "Caching newly-created gradient, size is %d bytes, total cache size %d bytes %d gradients, maximum %d bytes\n", + GRADIENT_SIZE (cached), + cache_size, g_hash_table_size (gradient_cache), MAX_CACHE_SIZE); + + cache_size += GRADIENT_SIZE (cached); + + g_object_ref (G_OBJECT (cached->pixbuf)); /* to return to caller */ + retval = cached->pixbuf; + + if (cache_size > MAX_CACHE_SIZE) + expire_some_old_gradients (); /* may unref "cached->pixbuf" and free "cached" */ + + return retval; +} + diff --git a/src/theme.h b/src/theme.h index 37c46ab83..ee273678a 100644 --- a/src/theme.h +++ b/src/theme.h @@ -1,4 +1,4 @@ -/* Metacity Theme Engine Header */ +/* Metacity Theme Rendering */ /* * Copyright (C) 2001 Havoc Pennington @@ -22,118 +22,22 @@ #ifndef META_THEME_H #define META_THEME_H -/* don't add any internal headers here; theme.h is an installed/public - * header. +#include "frames.h" + +/* theme.[hc] is basically responsible for drawing parts of the UI using + * theme data */ -#include -#include -#include "api.h" - -typedef struct _MetaFrameInfo MetaFrameInfo; -typedef struct _MetaFrameGeometry MetaFrameGeometry; -typedef struct _MetaThemeEngine MetaThemeEngine; typedef enum { - META_FRAME_ALLOWS_DELETE = 1 << 0, - META_FRAME_ALLOWS_MENU = 1 << 1, - META_FRAME_ALLOWS_ICONIFY = 1 << 2, - META_FRAME_ALLOWS_MAXIMIZE = 1 << 3, - META_FRAME_ALLOWS_RESIZE = 1 << 4, - META_FRAME_TRANSIENT = 1 << 5, - META_FRAME_HAS_FOCUS = 1 << 6, - META_FRAME_SHADED = 1 << 7, - META_FRAME_STUCK = 1 << 8 -} MetaFrameFlags; + META_GRADIENT_VERTICAL, + META_GRADIENT_HORIZONTAL +} MetaGradientType; -typedef enum -{ - META_FRAME_CONTROL_NONE, - META_FRAME_CONTROL_TITLE, - META_FRAME_CONTROL_DELETE, - META_FRAME_CONTROL_MENU, - META_FRAME_CONTROL_ICONIFY, - META_FRAME_CONTROL_MAXIMIZE, - META_FRAME_CONTROL_RESIZE_SE, - META_FRAME_CONTROL_RESIZE_S, - META_FRAME_CONTROL_RESIZE_SW, - META_FRAME_CONTROL_RESIZE_N, - META_FRAME_CONTROL_RESIZE_NE, - META_FRAME_CONTROL_RESIZE_NW, - META_FRAME_CONTROL_RESIZE_W, - META_FRAME_CONTROL_RESIZE_E -} MetaFrameControl; - -struct _MetaFrameInfo -{ - /* These are read-only to engines */ - MetaFrameFlags flags; - Window drawable; /* == None except in expose */ - int xoffset, yoffset; /* add to frame coords to get drawable coords */ - Display *display; - Screen *screen; - Visual *visual; - int depth; - - const char *title; - - const MetaUIColors *colors; - - MetaFrameControl current_control; - MetaUIState current_control_state; - - /* Equal to child size before fill_frame_geometry - * has been called - */ - int width; - int height; -}; - -struct _MetaFrameGeometry -{ - /* border sizes (space between frame and child) */ - int left_width; - int right_width; - int top_height; - int bottom_height; - - /* background color */ - unsigned long background_pixel; - - Pixmap shape_mask; - /* FIXME shape region? */ -}; - -struct _MetaThemeEngine -{ - void (* unload_engine) (void); - - /* returns frame_data to use */ - gpointer (* acquire_frame) (MetaFrameInfo *info); - /* should free frame_data */ - void (* release_frame) (MetaFrameInfo *info, - gpointer frame_data); - - void (* fill_frame_geometry) (MetaFrameInfo *info, - MetaFrameGeometry *geom, - gpointer frame_data); - - void (* expose_frame) (MetaFrameInfo *info, - int x, int y, - int width, int height, - gpointer frame_data); - - MetaFrameControl (* get_control) (MetaFrameInfo *info, - int x, int y, - gpointer frame_data); - - void (* get_control_rect) (MetaFrameInfo *info, - MetaFrameControl control, - int *x, int *y, - int *width, int *height, - gpointer frame_data); -}; - -extern MetaThemeEngine meta_default_engine; +GdkPixbuf* meta_theme_get_gradient (MetaGradientType type, + const GdkColor *color_one, + const GdkColor *color_two, + int width, + int height); #endif diff --git a/src/util.c b/src/util.c index fbf36b619..40673ac09 100644 --- a/src/util.c +++ b/src/util.c @@ -175,6 +175,9 @@ topic_name (MetaDebugTopic topic) case META_DEBUG_FOCUS: return "FOCUS"; break; + case META_DEBUG_GRADIENT_CACHE: + return "GRADIENT_CACHE"; + break; } return "Window manager"; diff --git a/src/util.h b/src/util.h index cd71129f3..1e324cbc1 100644 --- a/src/util.h +++ b/src/util.h @@ -45,7 +45,8 @@ void meta_fatal (const char *format, typedef enum { - META_DEBUG_FOCUS + META_DEBUG_FOCUS, + META_DEBUG_GRADIENT_CACHE } MetaDebugTopic;