diff options
| -rw-r--r-- | src/ui/theme.c | 314 | ||||
| -rw-r--r-- | src/ui/theme.h | 1 | 
2 files changed, 291 insertions, 24 deletions
| diff --git a/src/ui/theme.c b/src/ui/theme.c index 11cf3608..e15cf2ec 100644 --- a/src/ui/theme.c +++ b/src/ui/theme.c @@ -96,6 +96,114 @@ static void hls_to_rgb			(gdouble	 *h,   */  static MetaTheme *meta_current_theme = NULL; +static cairo_surface_t * +scale_surface (cairo_surface_t *surface, +               gdouble          old_width, +               gdouble          old_height, +               gdouble          new_width, +               gdouble          new_height, +               gboolean         vertical_stripes, +               gboolean         horizontal_stripes) +{ +  gdouble scale_x; +  gdouble scale_y; +  cairo_content_t content; +  gint width; +  gint height; +  cairo_surface_t *scaled; +  cairo_t *cr; + +  scale_x = new_width / old_width; +  scale_y = new_height / old_height; + +  if (horizontal_stripes && !vertical_stripes) +    { +      new_width = old_width; +      scale_x = 1.0; +    } +  else if (vertical_stripes && !horizontal_stripes) +    { +      new_height = old_height; +      scale_y = 1.0; +    } + +  content = CAIRO_CONTENT_COLOR_ALPHA; +  width = ceil (new_width); +  height = ceil (new_height); + +  scaled = cairo_surface_create_similar (surface, content, width, height); +  cr = cairo_create (scaled); + +  cairo_scale (cr, scale_x, scale_y); +  cairo_set_source_surface (cr, surface, 0, 0); + +  cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + +  cairo_paint (cr); +  cairo_destroy (cr); + +  return scaled; +} + +static cairo_surface_t * +get_surface_from_pixbuf (GdkPixbuf         *pixbuf, +                         MetaImageFillType  fill_type, +                         gdouble            width, +                         gdouble            height, +                         gboolean           vertical_stripes, +                         gboolean           horizontal_stripes) +{ +  gdouble pixbuf_width; +  gdouble pixbuf_height; +  cairo_surface_t *surface; +  cairo_content_t content; +  cairo_surface_t *copy; +  cairo_t *cr; + +  pixbuf_width = gdk_pixbuf_get_width (pixbuf); +  pixbuf_height = gdk_pixbuf_get_height (pixbuf); +  surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL); + +  if (pixbuf_width == width && pixbuf_height == height) +    { +      return surface; +    } + +  if (fill_type != META_IMAGE_FILL_TILE) +    { +      cairo_surface_t *scaled; + +      scaled = scale_surface (surface, pixbuf_width, pixbuf_height, +                              width, height, vertical_stripes, +                              horizontal_stripes); + +      cairo_surface_destroy (surface); +      surface = scaled; +    } + +  content = CAIRO_CONTENT_COLOR_ALPHA; +  width = ceil (width); +  height = ceil (height); + +  copy = cairo_surface_create_similar (surface, content, width, height); +  cr = cairo_create (copy); + +  cairo_set_source_surface (cr, surface, 0, 0); + +  if (fill_type == META_IMAGE_FILL_TILE || +      vertical_stripes || horizontal_stripes) +    { +      cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); +    } + +  cairo_paint (cr); +  cairo_destroy (cr); + +  cairo_surface_destroy (surface); + +  return copy; +} +  static GdkPixbuf *  colorize_pixbuf (GdkPixbuf *orig,                   GdkRGBA   *new_color) @@ -1149,6 +1257,38 @@ meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec)    g_free (spec);  } +cairo_pattern_t * +meta_alpha_gradient_spec_get_mask (const MetaAlphaGradientSpec *spec) +{ +  gint n_alphas; +  cairo_pattern_t *pattern; +  gint i; + +  /* Hardcoded in theme-parser.c */ +  g_assert (spec->type == META_GRADIENT_HORIZONTAL); + +  n_alphas = spec->n_alphas; +  if (n_alphas == 0) +    return NULL; + +  if (n_alphas == 1) +    return cairo_pattern_create_rgba (0, 0, 0, spec->alphas[0] / 255.0); + +  pattern = cairo_pattern_create_linear (0, 0, 1, 0); + +  for (i = 0; i < n_alphas; i++) +    cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_alphas - 1), +                                       0, 0, 0, spec->alphas[i] / 255.0); + +  if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS) +    { +      cairo_pattern_destroy (pattern); +      return NULL; +    } + +  return pattern; +} +  MetaColorSpec*  meta_color_spec_new (MetaColorSpecType type)  { @@ -3625,6 +3765,94 @@ draw_op_as_pixbuf (const MetaDrawOp    *op,    return pixbuf;  } +static cairo_surface_t * +draw_op_as_surface (const MetaDrawOp   *op, +                    GtkStyleContext    *style, +                    const MetaDrawInfo *info, +                    gdouble             width, +                    gdouble             height) +{ +  cairo_surface_t *surface; + +  surface = NULL; + +  switch (op->type) +    { +    case META_DRAW_IMAGE: +      { +        if (op->data.image.colorize_spec) +          { +            GdkRGBA color; + +            meta_color_spec_render (op->data.image.colorize_spec, +                                    style, &color); + +            if (op->data.image.colorize_cache_pixbuf == NULL || +                op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)) +              { +                if (op->data.image.colorize_cache_pixbuf) +                  g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)); + +                /* const cast here */ +                ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf = +                  colorize_pixbuf (op->data.image.pixbuf, +                                   &color); +                ((MetaDrawOp*)op)->data.image.colorize_cache_pixel = +                  GDK_COLOR_RGB (color); +              } + +            if (op->data.image.colorize_cache_pixbuf) +              { +                surface = get_surface_from_pixbuf (op->data.image.colorize_cache_pixbuf, +                                                   op->data.image.fill_type, +                                                   width, height, +                                                   op->data.image.vertical_stripes, +                                                   op->data.image.horizontal_stripes); +              } +          } +        else +          { +            surface = get_surface_from_pixbuf (op->data.image.pixbuf, +                                               op->data.image.fill_type, +                                               width, height, +                                               op->data.image.vertical_stripes, +                                               op->data.image.horizontal_stripes); +          } +        break; +      } + +    case META_DRAW_ICON: +      if (info->mini_icon && +          width <= gdk_pixbuf_get_width (info->mini_icon) && +          height <= gdk_pixbuf_get_height (info->mini_icon)) +        surface = get_surface_from_pixbuf (info->mini_icon, op->data.icon.fill_type, +                                           width, height, FALSE, FALSE); +      else if (info->icon) +        surface = get_surface_from_pixbuf (info->icon, op->data.icon.fill_type, +                                           width, height, FALSE, FALSE); +      break; + +    case META_DRAW_TINT: +    case META_DRAW_LINE: +    case META_DRAW_RECTANGLE: +    case META_DRAW_ARC: +    case META_DRAW_CLIP: +    case META_DRAW_GRADIENT: +    case META_DRAW_GTK_ARROW: +    case META_DRAW_GTK_BOX: +    case META_DRAW_GTK_VLINE: +    case META_DRAW_TITLE: +    case META_DRAW_OP_LIST: +    case META_DRAW_TILE: +      break; + +    default: +      break; +    } + +  return surface; +} +  static void  fill_env (MetaPositionExprEnv *env,            const MetaDrawInfo  *info, @@ -3897,8 +4125,12 @@ meta_draw_op_draw_with_env (const MetaDrawOp    *op,      case META_DRAW_IMAGE:        { -        int rx, ry, rwidth, rheight; -        GdkPixbuf *pixbuf; +        gint scale; +        gdouble rx, ry, rwidth, rheight; +        cairo_surface_t *surface; + +        scale = gdk_window_get_scale_factor (gdk_get_default_root_window ()); +        cairo_scale (cr, 1.0 / scale, 1.0 / scale);          if (op->data.image.pixbuf)            { @@ -3906,21 +4138,36 @@ meta_draw_op_draw_with_env (const MetaDrawOp    *op,              env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);            } -        rwidth = parse_size_unchecked (op->data.image.width, env); -        rheight = parse_size_unchecked (op->data.image.height, env); +        rwidth = parse_size_unchecked (op->data.image.width, env) * scale; +        rheight = parse_size_unchecked (op->data.image.height, env) * scale; -        pixbuf = draw_op_as_pixbuf (op, style_gtk, info, -                                    rwidth, rheight); +        surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight); -        if (pixbuf) +        if (surface)            { -            rx = parse_x_position_unchecked (op->data.image.x, env); -            ry = parse_y_position_unchecked (op->data.image.y, env); +            rx = parse_x_position_unchecked (op->data.image.x, env) * scale; +            ry = parse_y_position_unchecked (op->data.image.y, env) * scale; -            gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry); -            cairo_paint (cr); +            cairo_set_source_surface (cr, surface, rx, ry); -            g_object_unref (G_OBJECT (pixbuf)); +            if (op->data.image.alpha_spec) +              { +                cairo_pattern_t *pattern; + +                cairo_translate (cr, rx, ry); +                cairo_scale (cr, rwidth, rheight); + +                pattern = meta_alpha_gradient_spec_get_mask (op->data.image.alpha_spec); +                cairo_mask (cr, pattern); + +                cairo_pattern_destroy (pattern); +              } +            else +              { +                cairo_paint (cr); +              } + +            cairo_surface_destroy (surface);            }        }        break; @@ -3989,24 +4236,43 @@ meta_draw_op_draw_with_env (const MetaDrawOp    *op,      case META_DRAW_ICON:        { -        int rx, ry, rwidth, rheight; -        GdkPixbuf *pixbuf; +        gint scale; +        gdouble rx, ry, rwidth, rheight; +        cairo_surface_t *surface; + +        scale = gdk_window_get_scale_factor (gdk_get_default_root_window ()); +        cairo_scale (cr, 1.0 / scale, 1.0 / scale); -        rwidth = parse_size_unchecked (op->data.icon.width, env); -        rheight = parse_size_unchecked (op->data.icon.height, env); +        rwidth = parse_size_unchecked (op->data.icon.width, env) * scale; +        rheight = parse_size_unchecked (op->data.icon.height, env) * scale; -        pixbuf = draw_op_as_pixbuf (op, style_gtk, info, -                                    rwidth, rheight); +        surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight); -        if (pixbuf) +        if (surface)            { -            rx = parse_x_position_unchecked (op->data.icon.x, env); -            ry = parse_y_position_unchecked (op->data.icon.y, env); +            rx = parse_x_position_unchecked (op->data.icon.x, env) * scale; +            ry = parse_y_position_unchecked (op->data.icon.y, env) * scale; -            gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry); -            cairo_paint (cr); +            cairo_set_source_surface (cr, surface, rx, ry); -            g_object_unref (G_OBJECT (pixbuf)); +            if (op->data.icon.alpha_spec) +              { +                cairo_pattern_t *pattern; + +                cairo_translate (cr, rx, ry); +                cairo_scale (cr, rwidth, rheight); + +                pattern = meta_alpha_gradient_spec_get_mask (op->data.icon.alpha_spec); +                cairo_mask (cr, pattern); + +                cairo_pattern_destroy (pattern); +              } +            else +              { +                cairo_paint (cr); +              } + +            cairo_surface_destroy (surface);            }        }        break; diff --git a/src/ui/theme.h b/src/ui/theme.h index 34b98935..9dfb8d89 100644 --- a/src/ui/theme.h +++ b/src/ui/theme.h @@ -964,6 +964,7 @@ gboolean          meta_gradient_spec_validate (MetaGradientSpec     *spec,  MetaAlphaGradientSpec* meta_alpha_gradient_spec_new  (MetaGradientType       type,                                                        int                    n_alphas);  void                   meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec); +cairo_pattern_t *      meta_alpha_gradient_spec_get_mask (const MetaAlphaGradientSpec *spec);  MetaFrameStyle* meta_frame_style_new   (MetaFrameStyle *parent); | 
