Compare commits

...

55 Commits

Author SHA1 Message Date
7623b97399 Remove legacy theming API
Since the move to GTK+ toplevels, it required removing the preview-widget
and theme-viewer parts of the code. (They didn't work with the new CSS
stuff anyway... shhh..)
2012-05-07 20:37:09 -03:00
8d8e0cb055 uiframe: Make children respect border/padding
Also, center the label horizontally. There's still some shenanigans
I have to figure out with respect to vertical centering...

This should be in GTK+ by default...
2012-05-07 20:33:00 -03:00
1620131434 ui: Make sure to invalidate the style on a retheme/redraw 2012-05-07 20:21:13 -03:00
873da3405c frames: Only realize the widget after it's been properly associated
This makes sure that we don't get into a situation from a GTK+ handler
where we'll have an unassociated frame window.
2012-05-07 20:20:51 -03:00
8a062b39ab display: Make meta_display_retheme_all public 2012-05-07 20:19:51 -03:00
3ab3c8423e theme: Start using MetaUIFrame for the context path
Very soon we'll be scrapping this and doing something different internally
2012-05-05 02:11:34 -03:00
11e1f687f9 theme: Remove support for painting layouts
We'll do this with a GtkLabel child instead. This means that the
mask text shadows are currently broken -- we'll fix up things later
to be better.
2012-05-05 01:30:30 -03:00
25815473e6 theme: Scrap meta_theme_draw_frame
The more public symbols we remove, the closer we get to
not supporting the legacy theme API at all...
2012-05-05 00:00:47 -03:00
5053997021 ui: Scrap MetaFrames, move rest of frame management into MetaUi
Additionally, rename the code that houses MetaUIFrame to uiframe.[ch],
and fix up some other places that depended on MetaFrames.
2012-05-04 23:48:10 -03:00
b6468a7fa5 frames: Add a GtkWindow per frame
Now, now, it's not as bad as it sounds. We're using
gtk_widget_set_parent_window, as used by glade to embed
toplevel windows, to do our magic.
2012-05-04 23:10:28 -03:00
e2e0ead870 theme: Remove some more unused methods 2012-05-04 13:32:53 -04:00
f80a5d892f preview-widget: Don't override settings for the pango layout
This is now in CSS. Remove the now unused meta_gtk_widget_get_font_desc
as well.
2012-05-04 13:30:54 -04:00
5823c5e0f5 ui: Remove text_height from the public theme interface
It wasn't being used
2012-05-04 13:29:18 -04:00
ecac8c9d09 prefs: Remove titlebar font and use-system-font preferences
Specify them in CSS instead.
2012-05-03 23:21:37 -04:00
2666303045 frames: Support rendering layouts 2012-05-03 23:17:36 -04:00
0a9bc8995a frames: Support opacity in frame drawing
There's still a bug here (frame opacity doesn't "kick in" until we
change the frame geometry), and the colors aren't correct (we're
painting on top of a white surface, not a 0-alpha surface), but we
at least remove some redraw issues that come when you're not always
obscuring the last paint.
2012-05-03 16:03:45 -04:00
143436c37c frames: Remove reset_frames / unflicker_bg 2012-05-03 16:00:26 -04:00
7c11e0b0eb frames: Remove caching
XXX hack just to see how slow it is
2012-05-02 14:37:17 -04:00
beccdd64f5 frames: Remove invalidate_cache_timeout
WTF was this for? Was this a hacky bugfix? The git log gives no
information.
2012-05-02 14:37:17 -04:00
dd0a6d7e08 frames: Only make one call to meta_frames_paint 2012-05-02 14:37:17 -04:00
02bb550bd6 theme: Calculate frame geometry borders from CSS
Use the CSS 'border' and 'padding' properties rather than frame geometry.
This is a bit messy, so I'll fix it up with a new path representing the
titlebar soon.
2012-05-02 14:37:17 -04:00
8f789a8fad ui: Remove meta_ui_theme_get_frame_borders
The function is easily replaced, and also becomes more correct
as different window types may have different extents.
2012-05-02 14:37:17 -04:00
865b9df9a9 window-actor: Use MetaRegionBuilder when scanning the visible region
This gives a pretty solid performance improvement when resizing windows.
2012-05-02 14:37:17 -04:00
1e9268045d window-actor: Add a debugging tool to write a region to a PNG
Just a helper function that I keep rewriting all over the place.
2012-05-02 14:37:17 -04:00
20acb73024 frames: Remove get_frame_bounds
It's now unused, and we can't use it if we want to let GTK+ paint and
scan the frame region. With it, we can also stop depending on the
terrible GTK+ hack and remove the corner radius properties in the
frame geometry, as they aren't needed any more.
2012-05-02 14:37:17 -04:00
b97ad209c2 window-actor: Don't use get_frame_bounds
We want to remove it.
2012-05-02 14:37:17 -04:00
f2d8e3266b window-actor: Use cairo to paint regular shape region 2012-05-02 14:37:16 -04:00
11be2fa36a window-actor: Work around cairo bug
Thank to Company and ickle, a cairo bug was identified and then fixed.
They helped me verify I'm not going insane!

http://cgit.freedesktop.org/cairo/commit/?id=ec400daf9ec3bbd8403324db7fcdaf175e185e7b
2012-05-02 14:37:16 -04:00
302302a116 window-actor: Paint the frame mask with GTK+ as well
Use meta_theme_render_background to paint the background of the frame,
and then scan it to give us a region we can use to generate the shape
region from. It may be worth looking at the uses of the shape region
to see if we can replace some (all?) of them by masks instead, so we
don't have to scan the mask.
2012-05-02 14:37:16 -04:00
fd13dad0c4 window-actor: Use cairo_region_create_rectangles
Instead of the bunch of unions.
2012-05-02 14:37:16 -04:00
2da1ed1ae0 theme: Split GtkStateFlags grabbing code out 2012-05-02 14:37:16 -04:00
58f04c7284 Add simple dumb CSS rendering 2012-05-02 14:37:16 -04:00
a6737ef129 theme: Make meta_frame_style_draw_with_style private 2012-05-02 14:37:16 -04:00
52fee4df1c window-actor: Add back antialiased window corners
This simply adds fancy arcs to the mask texture.
2012-05-02 14:37:16 -04:00
8da12ac0e0 window-actor: Punt mask generation to MetaWindowActor
This effectively makes MetaShapedTexture not a MetaShapedTexture,
but a simple and dumb MetaMaskedTexture, with an optimization for
clipped regions.

We're doing this as the mask may need to be more complicated than
made of a region plus a "cairo overlay" -- we eventually want GTK+
to draw the rounded corner background.

Save rounded corners for a later commit, again.
2012-05-02 14:37:16 -04:00
e43f8db6e8 window-actor: Remove an unnecessary frame check
meta_frame_calc_borders will zero out the borders if we don't have a frame.
2012-05-02 14:37:16 -04:00
a7cbc9ad9a meta-shaped-texture: Remove corners for now
We'll add them back with gtk_render_background
2012-05-02 14:37:16 -04:00
0be3f81841 theme: Use a MetaWindow path rather than a GtkWidget path
This is a terrible ugly hack.
2012-05-02 14:37:16 -04:00
f53e26bc39 frames: Fix border-radius stupidity
Since we're breaking the theme format, we don't need to do this any
logner.
2012-05-02 14:37:16 -04:00
cc3be6da4d theme: Parse window radiuses from CSS
This requires a local hack to GTK+ that's ugly and I'm not sharing it.
We'll do things properly soon enough.
2012-05-02 14:37:15 -04:00
fef2a061a8 theme: Require a GTK+ style context in meta_theme_calc_geometry 2012-05-02 14:37:15 -04:00
bdb995d758 theme: Make meta_frame_layout_calc_geometry private 2012-05-02 14:37:15 -04:00
2a729f89aa preview-widget: Remove the unused meta_preview_get_clip_region
Besides being unused, it used meta_theme_get_frame_style. Since we
want to remove the static style layout structs, we need to remove
usage of that. Removing unused usage is the way to go.
2012-05-02 14:37:15 -04:00
af242b27b2 ui: Move theme variant code loading into theme.c
As we'll have a new API that draws using GtkStyleContext, it makes sense
to put all API using GtkStyleContext where the theme code is. Note that
the MetaThemeVariant code is just a stop-gap right now - in the future,
we'll have per-window theming, using CSS infrastructure like includes
for code reuse.
2012-05-02 14:37:15 -04:00
a198ff415a theme: Remove dead code
While the comment claims that we may want to keep this around
for optimization purposes, the operations are raw bitmap operations
that would be cleaner done in cairo.

https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:37:00 -04:00
981c1c2ab5 theme: Remove bogus comment
https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:37:00 -04:00
fb35f9fa49 theme: Replace char array element comparisons with strncmp
https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:37:00 -04:00
9194a04faa theme: Remove COLORIZE feature of images
From a quick code search and grep of gnome-themes-standard, none of
the themes that I inspected used this feature. Since it's the last
thing that uses a lot of old legacy GdkPixbuf code, I'd rather just
consider the feature unsupported at this point and clean up everything
I need to.

https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:37:00 -04:00
a0ed41d8ce theme: Use cairo for drawing uncolorized IMAGEs
https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:37:00 -04:00
e3e87727b6 theme: Use cairo for TINT operations with alpha
https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:37:00 -04:00
2d878f29eb theme: Use cairo for drawing ICON
Thanks to Benjamin Otte for helping me clean this up.

https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:37:00 -04:00
307e4c7d0e theme: Properly indent code
s/tabs/spaces/

https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:37:00 -04:00
43e7687d89 theme: Consolidate unused ops
https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:36:59 -04:00
2e4f67f3f9 theme: Remove our own gradient stuff
Part one of porting to cairo. This requires removing support for a seldomly
used feature in the theme format - alpha gradients on tint, icon and image.
Grepping through gnome-themes-standard and searching for code, I couldn't
find any usage of this feature, so I consider it safe to remove.

Thanks to Benjamin Otte for helping me clean this up.

https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:36:59 -04:00
69c11b59c4 theme: Remove unused RECTANGLE code
https://bugzilla.gnome.org/show_bug.cgi?id=662962
2012-05-02 14:36:59 -04:00
39 changed files with 1525 additions and 19584 deletions

View File

@ -259,8 +259,6 @@ Overview of Theme Format Version 1
<!-- color obtained by a 0.5 alpha composite of the second color onto the first -->
<color value="blend/gtk:bg[SELECTED]/gtk:fg[SELECTED]/0.5"/>
</gradient>
<!-- image has an optional colorize="#color" attribute to give the
image a certain color -->
<image filename="foo.png" alpha="0.7"
x="10" y="30" width="width / 3" height="height / 4"/>
<gtk_arrow state="normal" shadow="in" arrow="up"

View File

@ -88,8 +88,6 @@ libmutter_la_SOURCES = \
core/eventqueue.h \
core/frame.c \
core/frame.h \
ui/gradient.c \
meta/gradient.h \
core/group-private.h \
core/group-props.c \
core/group-props.h \
@ -130,8 +128,8 @@ libmutter_la_SOURCES = \
core/core.h \
ui/ui.h \
inlinepixbufs.h \
ui/frames.c \
ui/frames.h \
ui/uiframe.c \
ui/uiframe.h \
ui/menu.c \
ui/menu.h \
ui/metaaccellabel.c \
@ -142,13 +140,7 @@ libmutter_la_SOURCES = \
ui/tabpopup.h \
ui/tile-preview.c \
ui/tile-preview.h \
ui/theme-parser.c \
ui/theme.c \
meta/theme.h \
ui/theme-private.h \
ui/ui.c \
meta/preview-widget.h \
ui/preview-widget.c \
$(mutter_built_sources)
libmutter_la_LDFLAGS = -no-undefined
@ -163,7 +155,6 @@ libmutterinclude_base_headers = \
meta/compositor.h \
meta/display.h \
meta/errors.h \
meta/gradient.h \
meta/group.h \
meta/keybindings.h \
meta/main.h \
@ -174,7 +165,6 @@ libmutterinclude_base_headers = \
meta/meta-window-actor.h \
meta/prefs.h \
meta/screen.h \
meta/theme.h \
meta/types.h \
meta/util.h \
meta/window.h \
@ -183,7 +173,6 @@ libmutterinclude_base_headers = \
# Excluded from scanning for introspection but installed
# atomnames.h: macros cause problems for scanning process
libmutterinclude_extra_headers = \
meta/preview-widget.h \
meta/atomnames.h
libmutterincludedir = $(includedir)/mutter/meta
@ -192,10 +181,7 @@ libmutterinclude_HEADERS = \
$(libmutterinclude_base_headers) \
$(libmutterinclude_extra_headers)
mutter_theme_viewer_SOURCES= \
ui/theme-viewer.c
bin_PROGRAMS=mutter mutter-theme-viewer
bin_PROGRAMS=mutter
mutter_SOURCES = core/mutter.c
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
@ -233,16 +219,12 @@ Meta-$(api_version).gir: libmutter.la
endif
mutter_theme_viewer_LDADD= $(MUTTER_LIBS) libmutter.la
testboxes_SOURCES = core/testboxes.c
testgradient_SOURCES = ui/testgradient.c
testasyncgetprop_SOURCES = core/testasyncgetprop.c
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
noinst_PROGRAMS=testboxes testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
@INTLTOOL_DESKTOP_RULE@

View File

@ -30,13 +30,11 @@
#include <meta/meta-shaped-texture.h>
#include "meta-texture-tower.h"
#include "meta-texture-rectangle.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
#include <string.h>
static void meta_shaped_texture_dispose (GObject *object);
@ -54,8 +52,6 @@ static void meta_shaped_texture_get_preferred_height (ClutterActor *self,
gfloat *min_height_p,
gfloat *natural_height_p);
static void meta_shaped_texture_dirty_mask (MetaShapedTexture *stex);
static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume);
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
@ -75,13 +71,8 @@ struct _MetaShapedTexturePrivate
CoglHandle material_unshaped;
cairo_region_t *clip_region;
cairo_region_t *shape_region;
cairo_region_t *overlay_region;
cairo_path_t *overlay_path;
guint tex_width, tex_height;
guint mask_width, mask_height;
guint create_mipmaps : 1;
};
@ -110,9 +101,6 @@ meta_shaped_texture_init (MetaShapedTexture *self)
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
priv->shape_region = NULL;
priv->overlay_path = NULL;
priv->overlay_region = NULL;
priv->paint_tower = meta_texture_tower_new ();
priv->texture = COGL_INVALID_HANDLE;
priv->mask_texture = COGL_INVALID_HANDLE;
@ -129,8 +117,6 @@ meta_shaped_texture_dispose (GObject *object)
meta_texture_tower_free (priv->paint_tower);
priv->paint_tower = NULL;
meta_shaped_texture_dirty_mask (self);
if (priv->material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->material);
@ -147,178 +133,11 @@ meta_shaped_texture_dispose (GObject *object)
priv->texture = COGL_INVALID_HANDLE;
}
meta_shaped_texture_set_shape_region (self, NULL);
meta_shaped_texture_set_clip_region (self, NULL);
meta_shaped_texture_set_overlay_path (self, NULL, NULL);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
}
static void
meta_shaped_texture_dirty_mask (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
if (priv->mask_texture != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->mask_texture);
priv->mask_texture = COGL_INVALID_HANDLE;
}
if (priv->material != COGL_INVALID_HANDLE)
cogl_material_set_layer (priv->material, 1, COGL_INVALID_HANDLE);
}
static void
install_overlay_path (MetaShapedTexture *stex,
guchar *mask_data,
int tex_width,
int tex_height,
int stride)
{
MetaShapedTexturePrivate *priv = stex->priv;
int i, n_rects;
cairo_t *cr;
cairo_rectangle_int_t rect;
cairo_surface_t *surface;
if (priv->overlay_region == NULL)
return;
surface = cairo_image_surface_create_for_data (mask_data,
CAIRO_FORMAT_A8,
tex_width,
tex_height,
stride);
cr = cairo_create (surface);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
n_rects = cairo_region_num_rectangles (priv->overlay_region);
for (i = 0; i < n_rects; i++)
{
cairo_region_get_rectangle (priv->overlay_region, i, &rect);
cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
}
cairo_fill_preserve (cr);
if (priv->overlay_path == NULL)
{
/* If we have an overlay region but not an overlay path, then we
* just need to clear the rectangles in the overlay region. */
goto out;
}
cairo_clip (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr, 1, 1, 1, 1);
cairo_append_path (cr, priv->overlay_path);
cairo_fill (cr);
out:
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
static void
meta_shaped_texture_ensure_mask (MetaShapedTexture *stex)
{
MetaShapedTexturePrivate *priv = stex->priv;
CoglHandle paint_tex;
guint tex_width, tex_height;
paint_tex = priv->texture;
if (paint_tex == COGL_INVALID_HANDLE)
return;
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
/* If the mask texture we have was created for a different size then
recreate it */
if (priv->mask_texture != COGL_INVALID_HANDLE
&& (priv->mask_width != tex_width || priv->mask_height != tex_height))
meta_shaped_texture_dirty_mask (stex);
/* If we don't have a mask texture yet then create one */
if (priv->mask_texture == COGL_INVALID_HANDLE)
{
guchar *mask_data;
int i;
int n_rects;
int stride;
/* If we have no shape region and no (or an empty) overlay region, we
* don't need to create a full mask texture, so quit early. */
if (priv->shape_region == NULL &&
(priv->overlay_region == NULL ||
cairo_region_num_rectangles (priv->overlay_region) == 0))
{
return;
}
stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width);
/* Create data for an empty image */
mask_data = g_malloc0 (stride * tex_height);
n_rects = cairo_region_num_rectangles (priv->shape_region);
/* Fill in each rectangle. */
for (i = 0; i < n_rects; i ++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (priv->shape_region, i, &rect);
gint x1 = rect.x, x2 = x1 + rect.width;
gint y1 = rect.y, y2 = y1 + rect.height;
guchar *p;
/* Clip the rectangle to the size of the texture */
x1 = CLAMP (x1, 0, (gint) tex_width - 1);
x2 = CLAMP (x2, x1, (gint) tex_width);
y1 = CLAMP (y1, 0, (gint) tex_height - 1);
y2 = CLAMP (y2, y1, (gint) tex_height);
/* Fill the rectangle */
for (p = mask_data + y1 * stride + x1;
y1 < y2;
y1++, p += stride)
memset (p, 255, x2 - x1);
}
install_overlay_path (stex, mask_data, tex_width, tex_height, stride);
if (meta_texture_rectangle_check (paint_tex))
priv->mask_texture = meta_texture_rectangle_new (tex_width, tex_height,
COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_A_8,
stride,
mask_data,
NULL /* error */);
else
{
/* Note: we don't allow slicing for this texture because we
* need to use it with multi-texturing which doesn't support
* sliced textures */
priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_ANY,
stride,
mask_data);
}
g_free (mask_data);
priv->mask_width = tex_width;
priv->mask_height = tex_height;
}
}
static void
meta_shaped_texture_paint (ClutterActor *actor)
{
@ -368,9 +187,9 @@ meta_shaped_texture_paint (ClutterActor *actor)
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
if (priv->shape_region == NULL)
if (priv->mask_texture == COGL_INVALID_HANDLE)
{
/* No region means an unclipped shape. Use a single-layer texture. */
/* Use a single-layer texture if we don't have a mask. */
if (priv->material_unshaped == COGL_INVALID_HANDLE)
{
@ -383,8 +202,6 @@ meta_shaped_texture_paint (ClutterActor *actor)
}
else
{
meta_shaped_texture_ensure_mask (stex);
if (priv->material == COGL_INVALID_HANDLE)
{
if (G_UNLIKELY (material_template == COGL_INVALID_HANDLE))
@ -475,7 +292,7 @@ meta_shaped_texture_pick (ClutterActor *actor,
MetaShapedTexturePrivate *priv = stex->priv;
/* If there is no region then use the regular pick */
if (priv->shape_region == NULL)
if (priv->mask_texture == COGL_INVALID_HANDLE)
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)
->pick (actor, color);
else if (clutter_actor_should_pick_paint (actor))
@ -495,8 +312,6 @@ meta_shaped_texture_pick (ClutterActor *actor,
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
meta_shaped_texture_ensure_mask (stex);
cogl_set_source_color4ub (color->red, color->green, color->blue,
color->alpha);
@ -587,8 +402,8 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
}
void
meta_shaped_texture_set_shape_region (MetaShapedTexture *stex,
cairo_region_t *region)
meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
CoglHandle mask_texture)
{
MetaShapedTexturePrivate *priv;
@ -596,19 +411,18 @@ meta_shaped_texture_set_shape_region (MetaShapedTexture *stex,
priv = stex->priv;
if (priv->shape_region != NULL)
if (priv->mask_texture != COGL_INVALID_HANDLE)
{
cairo_region_destroy (priv->shape_region);
priv->shape_region = NULL;
cogl_handle_unref (priv->mask_texture);
priv->mask_texture = COGL_INVALID_HANDLE;
}
if (region != NULL)
if (mask_texture != COGL_INVALID_HANDLE)
{
cairo_region_reference (region);
priv->shape_region = region;
priv->mask_texture = mask_texture;
cogl_handle_ref (priv->mask_texture);
}
meta_shaped_texture_dirty_mask (stex);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
@ -727,48 +541,6 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex)
return stex->priv->texture;
}
/**
* meta_shaped_texture_set_overlay_path:
* @stex: a #MetaShapedTexture
* @overlay_region: A region containing the parts of the mask to overlay.
* All rectangles in this region are wiped clear to full transparency,
* and the overlay path is clipped to this region.
* @overlay_path: (transfer full): This path will be painted onto the mask
* texture with a fully opaque source. Due to the lack of refcounting
* in #cairo_path_t, ownership of the path is assumed.
*/
void
meta_shaped_texture_set_overlay_path (MetaShapedTexture *stex,
cairo_region_t *overlay_region,
cairo_path_t *overlay_path)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
if (priv->overlay_region != NULL)
{
cairo_region_destroy (priv->overlay_region);
priv->overlay_region = NULL;
}
if (priv->overlay_path != NULL)
{
cairo_path_destroy (priv->overlay_path);
priv->overlay_path = NULL;
}
cairo_region_reference (overlay_region);
priv->overlay_region = overlay_region;
/* cairo_path_t does not have refcounting. */
priv->overlay_path = overlay_path;
meta_shaped_texture_dirty_mask (stex);
}
/**
* meta_shaped_texture_set_clip_region:
* @stex: a #MetaShapedTexture

View File

@ -13,6 +13,7 @@
#define COGL_ENABLE_EXPERIMENTAL_API
#include <cogl/cogl-texture-pixmap-x11.h>
#include <gdk/gdk.h> /* for gdk_rectangle_union() */
#include <string.h>
#include <meta/display.h>
#include <meta/errors.h>
@ -24,6 +25,8 @@
#include "compositor-private.h"
#include "meta-shadow-factory-private.h"
#include "meta-window-actor-private.h"
#include "meta-texture-rectangle.h"
#include "region-utils.h"
enum {
POSITION_CHANGED,
@ -649,15 +652,14 @@ meta_window_actor_paint (ClutterActor *actor)
/* The frame bounds are already subtracted from priv->shadow_clip
* if that exists.
*/
if (!clip && clip_shadow_under_window (self))
if (!clip && clip_shadow_under_window (self) && priv->shape_region != NULL)
{
cairo_region_t *frame_bounds = meta_window_get_frame_bounds (priv->window);
cairo_rectangle_int_t bounds;
meta_window_actor_get_shadow_bounds (self, appears_focused, &bounds);
clip = cairo_region_create_rectangle (&bounds);
cairo_region_subtract (clip, frame_bounds);
cairo_region_subtract (clip, priv->shape_region);
}
meta_shadow_paint (shadow,
@ -1635,7 +1637,6 @@ meta_window_actor_update_shape_region (MetaWindowActor *self,
/* region must be non-null */
priv->shape_region = region;
cairo_region_reference (region);
/* Our "shape_region" is called the "bounding region" in the X Shape
* Extension Documentation.
@ -1681,7 +1682,7 @@ meta_window_actor_get_obscured_region (MetaWindowActor *self)
#if 0
/* Print out a region; useful for debugging */
static void
dump_region (cairo_region_t *region)
print_region (cairo_region_t *region)
{
int n_rects;
int i;
@ -1699,6 +1700,26 @@ dump_region (cairo_region_t *region)
}
#endif
#if 0
/* Dump a region to a PNG file; useful for debugging */
static void
see_region (cairo_region_t *region,
int width,
int height,
char *filename)
{
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
cairo_t *cr = cairo_create (surface);
gdk_cairo_region (cr, region);
cairo_fill (cr);
cairo_surface_write_to_png (surface, filename);
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
#endif
/**
* meta_window_actor_set_visible_region:
* @self: a #MetaWindowActor
@ -1743,11 +1764,8 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
meta_window_actor_clear_shadow_clip (self);
priv->shadow_clip = cairo_region_copy (beneath_region);
if (clip_shadow_under_window (self))
{
cairo_region_t *frame_bounds = meta_window_get_frame_bounds (priv->window);
cairo_region_subtract (priv->shadow_clip, frame_bounds);
}
if (clip_shadow_under_window (self) && priv->shape_region != NULL)
cairo_region_subtract (priv->shadow_clip, priv->shape_region);
}
}
@ -1989,121 +2007,136 @@ meta_window_actor_sync_visibility (MetaWindowActor *self)
}
}
static inline void
set_integral_bounding_rect (cairo_rectangle_int_t *rect,
double x, double y,
double width, double height)
static cairo_region_t *
scan_visible_region (guchar *mask_data,
int stride,
cairo_region_t *scan_area)
{
rect->x = floor(x);
rect->y = floor(y);
rect->width = ceil(x + width) - rect->x;
rect->height = ceil(y + height) - rect->y;
int i, n_rects = cairo_region_num_rectangles (scan_area);
MetaRegionBuilder builder;
meta_region_builder_init (&builder);
for (i = 0; i < n_rects; i++)
{
int x, y;
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (scan_area, i, &rect);
for (y = rect.y; y < (rect.y + rect.height); y++)
{
for (x = rect.x; x < (rect.x + rect.width); x++)
{
int w = x;
while (mask_data[y * stride + w] == 255 && w < (rect.x + rect.width))
w++;
if (w > 0)
{
meta_region_builder_add_rectangle (&builder, x, y, w - x, 1);
x = w;
}
}
}
}
return meta_region_builder_finish (&builder);
}
static void
update_corners (MetaWindowActor *self,
MetaFrameBorders *borders)
build_and_scan_frame_mask (MetaWindowActor *self,
cairo_rectangle_int_t *client_area,
cairo_region_t *shape_region)
{
MetaWindowActorPrivate *priv = self->priv;
MetaRectangle outer;
cairo_rectangle_int_t corner_rects[4];
cairo_region_t *corner_region;
cairo_path_t *corner_path;
float top_left, top_right, bottom_left, bottom_right;
float x, y;
/* need these to build a path */
guchar *mask_data;
guint tex_width, tex_height;
CoglHandle paint_tex, mask_texture;
int stride;
cairo_t *cr;
cairo_surface_t *surface;
if (!priv->window->frame)
{
meta_shaped_texture_set_overlay_path (META_SHAPED_TEXTURE (priv->actor),
NULL, NULL);
return;
}
paint_tex = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor));
if (paint_tex == COGL_INVALID_HANDLE)
return;
meta_window_get_outer_rect (priv->window, &outer);
tex_width = cogl_texture_get_width (paint_tex);
tex_height = cogl_texture_get_height (paint_tex);
meta_frame_get_corner_radiuses (priv->window->frame,
&top_left,
&top_right,
&bottom_left,
&bottom_right);
stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width);
/* Unfortunately, cairo does not allow us to create a context
* without a surface. Create a 0x0 image surface to "paint to"
* so we can get the path. */
surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
0, 0);
/* Create data for an empty image */
mask_data = g_malloc0 (stride * tex_height);
surface = cairo_image_surface_create_for_data (mask_data,
CAIRO_FORMAT_A8,
tex_width,
tex_height,
stride);
cr = cairo_create (surface);
/* top left */
x = borders->invisible.left;
y = borders->invisible.top;
gdk_cairo_region (cr, shape_region);
cairo_fill (cr);
set_integral_bounding_rect (&corner_rects[0],
x, y, top_left, top_left);
if (priv->window->frame != NULL)
{
cairo_region_t *frame_paint_region, *scanned_region;
cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
cairo_arc (cr,
x + top_left,
y + top_left,
top_left,
0, M_PI*2);
/* Make sure we don't paint the frame over the client window. */
frame_paint_region = cairo_region_create_rectangle (&rect);
cairo_region_subtract_rectangle (frame_paint_region, client_area);
gdk_cairo_region (cr, frame_paint_region);
cairo_clip (cr);
/* top right */
x = borders->invisible.left + outer.width - top_right;
y = borders->invisible.top;
/* XXX: work around cairo bug. remove when released
* http://cgit.freedesktop.org/cairo/commit/?id=ec400daf9ec3bbd8403324db7fcdaf175e185e7b
*/
cairo_push_group (cr);
set_integral_bounding_rect (&corner_rects[1],
x, y, top_right, top_right);
meta_frame_render_background (priv->window->frame, cr);
cairo_arc (cr,
x,
y + top_right,
top_right,
0, M_PI*2);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
/* bottom right */
x = borders->invisible.left + outer.width - bottom_right;
y = borders->invisible.top + outer.height - bottom_right;
cairo_surface_flush (surface);
scanned_region = scan_visible_region (mask_data, stride, frame_paint_region);
cairo_region_union (shape_region, scanned_region);
cairo_region_destroy (scanned_region);
}
set_integral_bounding_rect (&corner_rects[2],
x, y, bottom_right, bottom_right);
cairo_arc (cr,
x,
y,
bottom_right,
0, M_PI*2);
/* bottom left */
x = borders->invisible.left;
y = borders->invisible.top + outer.height - bottom_left;
set_integral_bounding_rect (&corner_rects[3],
x, y, bottom_left, bottom_left);
cairo_arc (cr,
x + bottom_left,
y,
bottom_left,
0, M_PI*2);
corner_path = cairo_copy_path (cr);
cairo_surface_destroy (surface);
cairo_destroy (cr);
cairo_surface_destroy (surface);
corner_region = cairo_region_create_rectangles (corner_rects, 4);
if (meta_texture_rectangle_check (paint_tex))
{
mask_texture = meta_texture_rectangle_new (tex_width, tex_height,
COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_A_8,
stride,
mask_data,
NULL /* error */);
}
else
{
/* Note: we don't allow slicing for this texture because we
* need to use it with multi-texturing which doesn't support
* sliced textures */
mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_ANY,
stride,
mask_data);
}
meta_shaped_texture_set_overlay_path (META_SHAPED_TEXTURE (priv->actor),
corner_region, corner_path);
cairo_region_destroy (corner_region);
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor),
mask_texture);
cogl_handle_unref (mask_texture);
g_free (mask_data);
}
static void
@ -2114,53 +2147,30 @@ check_needs_reshape (MetaWindowActor *self)
MetaDisplay *display = meta_screen_get_display (screen);
MetaFrameBorders borders;
cairo_region_t *region;
cairo_rectangle_int_t client_area;
if (!priv->needs_reshape)
return;
meta_shaped_texture_set_shape_region (META_SHAPED_TEXTURE (priv->actor), NULL);
meta_window_actor_clear_shape_region (self);
meta_frame_calc_borders (priv->window->frame, &borders);
region = meta_window_get_frame_bounds (priv->window);
if (region != NULL)
{
/* This returns the window's internal frame bounds region,
* so we need to copy it because we modify it below. */
region = cairo_region_copy (region);
}
else
{
/* If we have no region, we have no frame. We have no frame,
* so just use the bounding region instead */
region = cairo_region_copy (priv->bounding_region);
}
client_area.x = borders.total.left;
client_area.y = borders.total.top;
client_area.width = priv->window->rect.width;
client_area.height = priv->window->rect.height;
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), COGL_INVALID_HANDLE);
meta_window_actor_clear_shape_region (self);
#ifdef HAVE_SHAPE
if (priv->window->has_shape)
{
/* Translate the set of XShape rectangles that we
* get from the X server to a cairo_region. */
Display *xdisplay = meta_display_get_xdisplay (display);
XRectangle *rects;
cairo_rectangle_int_t *cairo_rects = NULL;
int n_rects, ordering;
cairo_rectangle_int_t client_area;
client_area.width = priv->window->rect.width;
client_area.height = priv->window->rect.height;
if (priv->window->frame)
{
client_area.x = borders.total.left;
client_area.y = borders.total.top;
}
else
{
client_area.x = 0;
client_area.y = 0;
}
/* Punch out client area. */
cairo_region_subtract_rectangle (region, &client_area);
meta_error_trap_push (display);
rects = XShapeGetRectangles (xdisplay,
@ -2172,29 +2182,37 @@ check_needs_reshape (MetaWindowActor *self)
if (rects)
{
cairo_rects = g_new (cairo_rectangle_int_t, n_rects);
int i;
for (i = 0; i < n_rects; i ++)
{
cairo_rectangle_int_t rect = { rects[i].x + client_area.x,
rects[i].y + client_area.y,
rects[i].width,
rects[i].height };
cairo_region_union_rectangle (region, &rect);
cairo_rects[i].x = client_area.x + rects[i].x;
cairo_rects[i].y = client_area.y + rects[i].y;
cairo_rects[i].width = rects[i].width;
cairo_rects[i].height = rects[i].height;
}
XFree (rects);
}
region = cairo_region_create_rectangles (cairo_rects, n_rects);
g_free (cairo_rects);
}
else
#endif
{
/* If we don't have a shape on the server, that means that
* we have an implicit shape of one rectangle covering the
* entire window. */
region = cairo_region_create_rectangle (&client_area);
}
meta_shaped_texture_set_shape_region (META_SHAPED_TEXTURE (priv->actor),
region);
/* This takes the region, generates a mask using GTK+
* and scans the mask looking for all opaque pixels,
* adding it to region.
*/
build_and_scan_frame_mask (self, &client_area, region);
meta_window_actor_update_shape_region (self, region);
cairo_region_destroy (region);
update_corners (self, &borders);
priv->needs_reshape = FALSE;
meta_window_actor_invalidate_shadow (self);
}

View File

@ -43,25 +43,10 @@
/* Optimium performance seems to be with MAX_CHUNK_RECTANGLES=4; 8 is about 10% slower.
* But using 8 may be more robust to systems with slow malloc(). */
#define MAX_CHUNK_RECTANGLES 8
/* XXX: keep in sync with region-utils.h */
#define MAX_LEVELS 16
typedef struct
{
/* To merge regions in binary tree order, we need to keep track of
* the regions that we've already merged together at different
* levels of the tree. We fill in an array in the pattern:
*
* |a |
* |b |a |
* |c | |ab |
* |d |c |ab |
* |e | | |abcd|
*/
cairo_region_t *levels[MAX_LEVELS];
int n_levels;
} MetaRegionBuilder;
static void
void
meta_region_builder_init (MetaRegionBuilder *builder)
{
int i;
@ -70,7 +55,7 @@ meta_region_builder_init (MetaRegionBuilder *builder)
builder->n_levels = 1;
}
static void
void
meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
int x,
int y,
@ -115,7 +100,7 @@ meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
}
}
static cairo_region_t *
cairo_region_t *
meta_region_builder_finish (MetaRegionBuilder *builder)
{
cairo_region_t *result = NULL;

View File

@ -63,6 +63,34 @@ struct _MetaRegionIterator {
cairo_rectangle_int_t next_rectangle;
};
typedef struct _MetaRegionBuilder MetaRegionBuilder;
/* XXX: keep in sync with region-utils.c */
#define MAX_LEVELS 16
struct _MetaRegionBuilder {
/* To merge regions in binary tree order, we need to keep track of
* the regions that we've already merged together at different
* levels of the tree. We fill in an array in the pattern:
*
* |a |
* |b |a |
* |c | |ab |
* |d |c |ab |
* |e | | |abcd|
*/
cairo_region_t *levels[MAX_LEVELS];
int n_levels;
};
#undef MAX_LEVELS
void meta_region_builder_init (MetaRegionBuilder *builder);
void meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
int x,
int y,
int width,
int height);
cairo_region_t * meta_region_builder_finish (MetaRegionBuilder *builder);
void meta_region_iterator_init (MetaRegionIterator *iter,
cairo_region_t *region);
gboolean meta_region_iterator_at_end (MetaRegionIterator *iter);

View File

@ -408,7 +408,6 @@ const char* meta_event_mode_to_string (int m);
const char* meta_event_detail_to_string (int d);
void meta_display_queue_retheme_all_windows (MetaDisplay *display);
void meta_display_retheme_all (void);
void meta_display_set_cursor_theme (const char *theme,
int size);

View File

@ -2571,9 +2571,6 @@ event_callback (XEvent *event,
else if (event->xclient.message_type ==
display->atom__MUTTER_RELOAD_THEME_MESSAGE)
{
meta_verbose ("Received reload theme request\n");
meta_ui_set_current_theme (meta_prefs_get_theme (),
TRUE);
meta_display_retheme_all ();
}
else if (event->xclient.message_type ==
@ -4385,10 +4382,9 @@ process_request_frame_extents (MetaDisplay *display,
}
/* Return estimated frame extents for a normal window. */
meta_ui_theme_get_frame_borders (screen->ui,
META_FRAME_TYPE_NORMAL,
0,
&borders);
meta_ui_get_frame_borders (screen->ui,
xwindow,
&borders);
data[0] = borders.visible.left;
data[1] = borders.visible.right;
data[2] = borders.visible.top;

View File

@ -113,9 +113,18 @@ meta_window_ensure_frame (MetaWindow *window)
attrs.event_mask = EVENT_MASK;
XChangeWindowAttributes (window->display->xdisplay,
frame->xwindow, CWEventMask, &attrs);
/* stick frame to the window */
window->frame = frame;
meta_display_register_x_window (window->display, &frame->xwindow, window);
meta_ui_realize_frame_window (window->screen->ui, frame->xwindow);
if (window->title)
meta_ui_set_frame_title (window->screen->ui,
window->frame->xwindow,
window->title);
/* Reparent the client window; it may be destroyed,
* thus the error trap. We'll get a destroy notify later
* and free everything. Comment in FVWM source code says
@ -148,20 +157,6 @@ meta_window_ensure_frame (MetaWindow *window)
window->rect.y);
/* FIXME handle this error */
meta_error_trap_pop (window->display);
/* stick frame to the window */
window->frame = frame;
/* Now that frame->xwindow is registered with window, we can set its
* style and background.
*/
meta_ui_update_frame_style (window->screen->ui, frame->xwindow);
meta_ui_reset_frame_bg (window->screen->ui, frame->xwindow);
if (window->title)
meta_ui_set_frame_title (window->screen->ui,
window->frame->xwindow,
window->title);
/* Move keybindings to frame instead of window */
meta_window_grab_keys (window);
@ -220,11 +215,6 @@ meta_window_destroy_frame (MetaWindow *window)
frame->xwindow);
window->frame = NULL;
if (window->frame_bounds)
{
cairo_region_destroy (window->frame_bounds);
window->frame_bounds = NULL;
}
/* Move keybindings to window instead of frame */
meta_window_grab_keys (window);
@ -333,16 +323,12 @@ meta_frame_calc_borders (MetaFrame *frame,
}
void
meta_frame_get_corner_radiuses (MetaFrame *frame,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right)
meta_frame_render_background (MetaFrame *frame,
cairo_t *cr)
{
meta_ui_get_corner_radiuses (frame->window->screen->ui,
frame->xwindow,
top_left, top_right,
bottom_left, bottom_right);
meta_ui_render_background (frame->window->screen->ui,
frame->xwindow,
cr);
}
gboolean
@ -358,15 +344,6 @@ meta_frame_sync_to_window (MetaFrame *frame,
frame->rect.x + frame->rect.width,
frame->rect.y + frame->rect.height);
/* set bg to none to avoid flicker */
if (need_resize)
{
meta_ui_unflicker_frame_bg (frame->window->screen->ui,
frame->xwindow,
frame->rect.width,
frame->rect.height);
}
meta_ui_move_resize_frame (frame->window->screen->ui,
frame->xwindow,
frame->rect.x,
@ -376,30 +353,18 @@ meta_frame_sync_to_window (MetaFrame *frame,
if (need_resize)
{
meta_ui_reset_frame_bg (frame->window->screen->ui,
frame->xwindow);
/* If we're interactively resizing the frame, repaint
* it immediately so we don't start to lag.
*/
if (frame->window->display->grab_window ==
frame->window)
meta_ui_repaint_frame (frame->window->screen->ui,
frame->xwindow);
meta_ui_queue_frame_draw (frame->window->screen->ui,
frame->xwindow);
}
return need_resize;
}
cairo_region_t *
meta_frame_get_frame_bounds (MetaFrame *frame)
{
return meta_ui_get_frame_bounds (frame->window->screen->ui,
frame->xwindow,
frame->rect.width,
frame->rect.height);
}
void
meta_frame_queue_draw (MetaFrame *frame)
{

View File

@ -63,19 +63,14 @@ Window meta_frame_get_xwindow (MetaFrame *frame);
void meta_frame_calc_borders (MetaFrame *frame,
MetaFrameBorders *borders);
void meta_frame_get_corner_radiuses (MetaFrame *frame,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right);
void meta_frame_render_background (MetaFrame *frame,
cairo_t *cr);
gboolean meta_frame_sync_to_window (MetaFrame *frame,
int gravity,
gboolean need_move,
gboolean need_resize);
cairo_region_t *meta_frame_get_frame_bounds (MetaFrame *frame);
void meta_frame_set_screen_cursor (MetaFrame *frame,
MetaCursor cursor);

View File

@ -477,42 +477,6 @@ meta_run (void)
if (g_getenv ("MUTTER_G_FATAL_WARNINGS") != NULL)
g_log_set_always_fatal (G_LOG_LEVEL_MASK);
meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE);
/* Try to find some theme that'll work if the theme preference
* doesn't exist. First try Simple (the default theme) then just
* try anything in the themes directory.
*/
if (!meta_ui_have_a_theme ())
meta_ui_set_current_theme ("Simple", FALSE);
if (!meta_ui_have_a_theme ())
{
const char *dir_entry = NULL;
GError *err = NULL;
GDir *themes_dir = NULL;
if (!(themes_dir = g_dir_open (MUTTER_DATADIR"/themes", 0, &err)))
{
meta_fatal (_("Failed to scan themes directory: %s\n"), err->message);
g_error_free (err);
}
else
{
while (((dir_entry = g_dir_read_name (themes_dir)) != NULL) &&
(!meta_ui_have_a_theme ()))
{
meta_ui_set_current_theme (dir_entry, FALSE);
}
g_dir_close (themes_dir);
}
}
if (!meta_ui_have_a_theme ())
meta_fatal (_("Could not find a theme! Be sure %s exists and contains the usual themes.\n"),
MUTTER_DATADIR"/themes");
/* Connect to SM as late as possible - but before managing display,
* or we might try to manage a window before we have the session
* info
@ -588,9 +552,7 @@ prefs_changed_callback (MetaPreference pref,
{
switch (pref)
{
case META_PREF_THEME:
case META_PREF_DRAGGABLE_BORDER_WIDTH:
meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE);
meta_display_retheme_all ();
break;

View File

@ -42,7 +42,6 @@
* not given a name here, because the purpose of the unified handlers
* is that keys should be referred to exactly once.
*/
#define KEY_TITLEBAR_FONT "titlebar-font"
#define KEY_NUM_WORKSPACES "num-workspaces"
#define KEY_WORKSPACE_NAMES "workspace-names"
@ -69,14 +68,11 @@ static guint changed_idle;
static GList *listeners = NULL;
static GHashTable *settings_schemas;
static gboolean use_system_font = FALSE;
static PangoFontDescription *titlebar_font = NULL;
static MetaVirtualModifier mouse_button_mods = Mod1Mask;
static GDesktopFocusMode focus_mode = G_DESKTOP_FOCUS_MODE_CLICK;
static GDesktopFocusNewWindows focus_new_windows = G_DESKTOP_FOCUS_NEW_WINDOWS_SMART;
static gboolean raise_on_click = TRUE;
static gboolean attach_modal_dialogs = FALSE;
static char* current_theme = NULL;
static int num_workspaces = 4;
static GDesktopTitlebarAction action_double_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE;
static GDesktopTitlebarAction action_middle_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_LOWER;
@ -127,8 +123,6 @@ static void queue_changed (MetaPreference pref);
static void maybe_give_disable_workarounds_warning (void);
static gboolean titlebar_handler (GVariant*, gpointer*, gpointer);
static gboolean theme_name_handler (GVariant*, gpointer*, gpointer);
static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer);
static gboolean button_layout_handler (GVariant*, gpointer*, gpointer);
@ -266,13 +260,6 @@ static MetaBoolPreference preferences_bool[] =
},
&raise_on_click,
},
{
{ "titlebar-uses-system-font",
SCHEMA_GENERAL,
META_PREF_TITLEBAR_FONT, /* note! shares a pref */
},
&use_system_font,
},
{
{ "dynamic-workspaces",
SCHEMA_MUTTER,
@ -370,22 +357,6 @@ static MetaStringPreference preferences_string[] =
mouse_button_mods_handler,
NULL,
},
{
{ "theme",
SCHEMA_GENERAL,
META_PREF_THEME,
},
theme_name_handler,
NULL,
},
{
{ KEY_TITLEBAR_FONT,
SCHEMA_GENERAL,
META_PREF_TITLEBAR_FONT,
},
titlebar_handler,
NULL,
},
{
{ "button-layout",
SCHEMA_GENERAL,
@ -1099,12 +1070,6 @@ meta_prefs_get_raise_on_click (void)
return raise_on_click || focus_mode == G_DESKTOP_FOCUS_MODE_CLICK;
}
const char*
meta_prefs_get_theme (void)
{
return current_theme;
}
const char*
meta_prefs_get_cursor_theme (void)
{
@ -1122,70 +1087,6 @@ meta_prefs_get_cursor_size (void)
/* Handlers for string preferences. */
/****************************************************************************/
static gboolean
titlebar_handler (GVariant *value,
gpointer *result,
gpointer data)
{
PangoFontDescription *desc;
const gchar *string_value;
*result = NULL; /* ignored */
string_value = g_variant_get_string (value, NULL);
desc = pango_font_description_from_string (string_value);
if (desc == NULL)
{
meta_warning (_("Could not parse font description "
"\"%s\" from GSettings key %s\n"),
string_value ? string_value : "(null)",
KEY_TITLEBAR_FONT);
return FALSE;
}
/* Is the new description the same as the old? */
if (titlebar_font &&
pango_font_description_equal (desc, titlebar_font))
{
pango_font_description_free (desc);
}
else
{
if (titlebar_font)
pango_font_description_free (titlebar_font);
titlebar_font = desc;
queue_changed (META_PREF_TITLEBAR_FONT);
}
return TRUE;
}
static gboolean
theme_name_handler (GVariant *value,
gpointer *result,
gpointer data)
{
const gchar *string_value;
*result = NULL; /* ignored */
string_value = g_variant_get_string (value, NULL);
if (!string_value || !*string_value)
return FALSE;
if (g_strcmp0 (current_theme, string_value) != 0)
{
if (current_theme)
g_free (current_theme);
current_theme = g_strdup (string_value);
queue_changed (META_PREF_THEME);
}
return TRUE;
}
static gboolean
mouse_button_mods_handler (GVariant *value,
gpointer *result,
@ -1478,15 +1379,6 @@ button_layout_handler (GVariant *value,
return TRUE;
}
const PangoFontDescription*
meta_prefs_get_titlebar_font (void)
{
if (use_system_font)
return NULL;
else
return titlebar_font;
}
int
meta_prefs_get_num_workspaces (void)
{
@ -1534,12 +1426,6 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_RAISE_ON_CLICK:
return "RAISE_ON_CLICK";
case META_PREF_THEME:
return "THEME";
case META_PREF_TITLEBAR_FONT:
return "TITLEBAR_FONT";
case META_PREF_NUM_WORKSPACES:
return "NUM_WORKSPACES";

View File

@ -926,5 +926,43 @@ meta_later_remove (guint later_id)
}
}
/**
* meta_frame_type_to_string:
*
* Converts a frame type enum value to the name string that would
* appear in the theme definition file.
*
* Return value: the string value
*/
const char*
meta_frame_type_to_string (MetaFrameType type)
{
switch (type)
{
case META_FRAME_TYPE_NORMAL:
return "normal";
case META_FRAME_TYPE_DIALOG:
return "dialog";
case META_FRAME_TYPE_MODAL_DIALOG:
return "modal_dialog";
case META_FRAME_TYPE_UTILITY:
return "utility";
case META_FRAME_TYPE_MENU:
return "menu";
case META_FRAME_TYPE_BORDER:
return "border";
case META_FRAME_TYPE_ATTACHED:
return "attached";
#if 0
case META_FRAME_TYPE_TOOLBAR:
return "toolbar";
#endif
case META_FRAME_TYPE_LAST:
break;
}
return "<unknown>";
}
/* eof util.c */

View File

@ -333,9 +333,6 @@ struct _MetaWindow
/* if TRUE, window is attached to its parent */
guint attached : 1;
/* if non-NULL, the bounds of the window frame */
cairo_region_t *frame_bounds;
/* Note: can be NULL */
GSList *struts;

View File

@ -1588,7 +1588,7 @@ reload_gtk_theme_variant (MetaWindow *window,
window->gtk_theme_variant = g_strdup (requested_variant);
if (window->frame)
meta_ui_update_frame_style (window->screen->ui, window->frame->xwindow);
meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow);
}
}
@ -1616,7 +1616,7 @@ reload_gtk_hide_titlebar_when_maximized (MetaWindow *window,
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
if (window->frame)
meta_ui_update_frame_style (window->screen->ui, window->frame->xwindow);
meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow);
}
}

View File

@ -217,9 +217,6 @@ meta_window_finalize (GObject *object)
if (window->mini_icon)
g_object_unref (G_OBJECT (window->mini_icon));
if (window->frame_bounds)
cairo_region_destroy (window->frame_bounds);
meta_icon_cache_free (&window->icon_cache);
g_free (window->sm_client_id);
@ -4581,7 +4578,6 @@ meta_window_move_resize_internal (MetaWindow *window,
gboolean need_resize_frame = FALSE;
int size_dx;
int size_dy;
gboolean frame_shape_changed = FALSE;
gboolean is_configure_request;
gboolean do_gravity_adjust;
gboolean is_user_action;
@ -4880,9 +4876,9 @@ meta_window_move_resize_internal (MetaWindow *window,
meta_window_set_gravity (window, StaticGravity);
if (configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame,
gravity,
need_move_frame, need_resize_frame);
meta_frame_sync_to_window (window->frame,
gravity,
need_move_frame, need_resize_frame);
values.border_width = 0;
values.x = client_move_x;
@ -4937,9 +4933,9 @@ meta_window_move_resize_internal (MetaWindow *window,
}
if (!configure_frame_first && window->frame)
frame_shape_changed = meta_frame_sync_to_window (window->frame,
gravity,
need_move_frame, need_resize_frame);
meta_frame_sync_to_window (window->frame,
gravity,
need_move_frame, need_resize_frame);
/* Put gravity back to be nice to lesser window managers */
if (use_static_gravity)
@ -4982,12 +4978,6 @@ meta_window_move_resize_internal (MetaWindow *window,
* b) all constraints are obeyed by window->rect and frame->rect
*/
if (frame_shape_changed && window->frame_bounds)
{
cairo_region_destroy (window->frame_bounds);
window->frame_bounds = NULL;
}
meta_window_foreach_transient (window, maybe_move_attached_dialog, NULL);
meta_stack_update_window_tile_matches (window->screen->stack,
@ -8337,6 +8327,8 @@ meta_window_show_menu (MetaWindow *window,
menu =
meta_ui_window_menu_new (window->screen->ui,
window->display->xdisplay,
window->screen->number,
window->xwindow,
ops,
insensitive,
@ -10649,27 +10641,6 @@ meta_window_get_frame_type (MetaWindow *window)
}
}
/**
* meta_window_get_frame_bounds:
*
* Gets a region representing the outer bounds of the window's frame.
*
* Return value: (transfer none) (allow-none): a #cairo_region_t
* holding the outer bounds of the window, or %NULL if the window
* doesn't have a frame.
*/
cairo_region_t *
meta_window_get_frame_bounds (MetaWindow *window)
{
if (!window->frame_bounds)
{
if (window->frame)
window->frame_bounds = meta_frame_get_frame_bounds (window->frame);
}
return window->frame_bounds;
}
/**
* meta_window_is_attached_dialog:
* @window: a #MetaWindow

View File

@ -175,4 +175,6 @@ void meta_display_unmanage_screen (MetaDisplay *display,
MetaScreen *screen,
guint32 timestamp);
void meta_display_retheme_all (void);
#endif

View File

@ -1,65 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter gradient rendering */
/*
* Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
* WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA. */
#ifndef META_GRADIENT_H
#define META_GRADIENT_H
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdk.h>
typedef enum
{
META_GRADIENT_VERTICAL,
META_GRADIENT_HORIZONTAL,
META_GRADIENT_DIAGONAL,
META_GRADIENT_LAST
} MetaGradientType;
GdkPixbuf* meta_gradient_create_simple (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to,
MetaGradientType style);
GdkPixbuf* meta_gradient_create_multi (int width,
int height,
const GdkRGBA *colors,
int n_colors,
MetaGradientType style);
GdkPixbuf* meta_gradient_create_interwoven (int width,
int height,
const GdkRGBA colors1[2],
int thickness1,
const GdkRGBA colors2[2],
int thickness2);
/* Generate an alpha gradient and multiply it with the existing alpha
* channel of the given pixbuf
*/
void meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type);
#endif

View File

@ -72,12 +72,8 @@ void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
CoglHandle meta_shaped_texture_get_texture (MetaShapedTexture *stex);
void meta_shaped_texture_set_shape_region (MetaShapedTexture *stex,
cairo_region_t *region);
void meta_shaped_texture_set_overlay_path (MetaShapedTexture *stex,
cairo_region_t *overlay_region,
cairo_path_t *overlay_path);
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
CoglHandle mask_texture);
/* Assumes ownership of clip_region */
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,

View File

@ -45,8 +45,6 @@ typedef enum
META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
META_PREF_AUTO_RAISE,
META_PREF_AUTO_RAISE_DELAY,
META_PREF_THEME,
META_PREF_TITLEBAR_FONT,
META_PREF_NUM_WORKSPACES,
META_PREF_DYNAMIC_WORKSPACES,
META_PREF_APPLICATION_BASED,
@ -91,7 +89,6 @@ GDesktopFocusMode meta_prefs_get_focus_mode (void);
GDesktopFocusNewWindows meta_prefs_get_focus_new_windows (void);
gboolean meta_prefs_get_attach_modal_dialogs (void);
gboolean meta_prefs_get_raise_on_click (void);
const char* meta_prefs_get_theme (void);
/* returns NULL if GTK default should be used */
const PangoFontDescription* meta_prefs_get_titlebar_font (void);
int meta_prefs_get_num_workspaces (void);

View File

@ -1,88 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity theme preview widget */
/*
* Copyright (C) 2002 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include <meta/common.h>
#include <meta/theme.h>
#include <gtk/gtk.h>
#ifndef META_PREVIEW_WIDGET_H
#define META_PREVIEW_WIDGET_H
#define META_TYPE_PREVIEW (meta_preview_get_type ())
#define META_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_PREVIEW, MetaPreview))
#define META_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_PREVIEW, MetaPreviewClass))
#define META_IS_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_PREVIEW))
#define META_IS_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_PREVIEW))
#define META_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_PREVIEW, MetaPreviewClass))
typedef struct _MetaPreview MetaPreview;
typedef struct _MetaPreviewClass MetaPreviewClass;
struct _MetaPreview
{
GtkBin bin;
MetaTheme *theme;
char *title;
MetaFrameType type;
MetaFrameFlags flags;
PangoLayout *layout;
int text_height;
MetaFrameBorders borders;
guint borders_cached : 1;
MetaButtonLayout button_layout;
};
struct _MetaPreviewClass
{
GtkBinClass parent_class;
};
GType meta_preview_get_type (void) G_GNUC_CONST;
GtkWidget* meta_preview_new (void);
void meta_preview_set_theme (MetaPreview *preview,
MetaTheme *theme);
void meta_preview_set_title (MetaPreview *preview,
const char *title);
void meta_preview_set_frame_type (MetaPreview *preview,
MetaFrameType type);
void meta_preview_set_frame_flags (MetaPreview *preview,
MetaFrameFlags flags);
void meta_preview_set_button_layout (MetaPreview *preview,
const MetaButtonLayout *button_layout);
cairo_region_t * meta_preview_get_clip_region (MetaPreview *preview,
gint new_window_width,
gint new_window_height);
GdkPixbuf* meta_preview_get_icon (void);
GdkPixbuf* meta_preview_get_mini_icon (void);
#endif

View File

@ -1,47 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity Theme Rendering */
/*
* Copyright (C) 2001 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_THEME_H
#define META_THEME_H
#include <glib.h>
/**
* MetaTheme:
*
*/
typedef struct _MetaTheme MetaTheme;
MetaTheme* meta_theme_get_current (void);
void meta_theme_set_current (const char *name,
gboolean force_reload);
MetaTheme* meta_theme_new (void);
void meta_theme_free (MetaTheme *theme);
gboolean meta_theme_validate (MetaTheme *theme,
GError **error);
MetaTheme* meta_theme_load (const char *theme_name,
GError **err);
#endif

View File

@ -167,8 +167,6 @@ const char *meta_window_get_mutter_hints (MetaWindow *window);
MetaFrameType meta_window_get_frame_type (MetaWindow *window);
cairo_region_t *meta_window_get_frame_bounds (MetaWindow *window);
MetaWindow *meta_window_get_tile_match (MetaWindow *window);
#endif

View File

@ -26,7 +26,6 @@
*/
#include "draw-workspace.h"
#include "theme-private.h"
static void
@ -75,11 +74,8 @@ draw_window (GtkWidget *widget,
{
GdkPixbuf *icon;
int icon_x, icon_y, icon_w, icon_h;
gboolean is_active;
GdkRGBA color;
GtkStyleContext *style;
is_active = win->is_active;
cairo_save (cr);
@ -87,10 +83,7 @@ draw_window (GtkWidget *widget,
cairo_clip (cr);
style = gtk_widget_get_style_context (widget);
if (is_active)
meta_gtk_style_get_light_color (style, state, &color);
else
gtk_style_context_get_background_color (style, state, &color);
gtk_style_context_get_background_color (style, state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_rectangle (cr,
@ -197,7 +190,7 @@ wnck_draw_workspace (GtkWidget *widget,
{
GdkRGBA color;
meta_gtk_style_get_dark_color (style,state, &color);
gtk_style_context_get_background_color (style, state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_rectangle (cr, x, y, width, height);
cairo_fill (cr);

File diff suppressed because it is too large Load Diff

View File

@ -1,173 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity window frame manager widget */
/*
* Copyright (C) 2001 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_FRAMES_H
#define META_FRAMES_H
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <meta/common.h>
#include "theme-private.h"
typedef enum
{
META_FRAME_CONTROL_NONE,
META_FRAME_CONTROL_TITLE,
META_FRAME_CONTROL_DELETE,
META_FRAME_CONTROL_MENU,
META_FRAME_CONTROL_MINIMIZE,
META_FRAME_CONTROL_MAXIMIZE,
META_FRAME_CONTROL_UNMAXIMIZE,
META_FRAME_CONTROL_SHADE,
META_FRAME_CONTROL_UNSHADE,
META_FRAME_CONTROL_ABOVE,
META_FRAME_CONTROL_UNABOVE,
META_FRAME_CONTROL_STICK,
META_FRAME_CONTROL_UNSTICK,
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,
META_FRAME_CONTROL_CLIENT_AREA
} MetaFrameControl;
/* This is one widget that manages all the window frames
* as subwindows.
*/
#define META_TYPE_FRAMES (meta_frames_get_type ())
#define META_FRAMES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_FRAMES, MetaFrames))
#define META_FRAMES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_FRAMES, MetaFramesClass))
#define META_IS_FRAMES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_FRAMES))
#define META_IS_FRAMES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_FRAMES))
#define META_FRAMES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_FRAMES, MetaFramesClass))
typedef struct _MetaFrames MetaFrames;
typedef struct _MetaFramesClass MetaFramesClass;
typedef struct _MetaUIFrame MetaUIFrame;
struct _MetaUIFrame
{
Window xwindow;
GdkWindow *window;
GtkStyleContext *style;
MetaFrameStyle *cache_style;
PangoLayout *layout;
int text_height;
char *title; /* NULL once we have a layout */
guint expose_delayed : 1;
guint shape_applied : 1;
/* FIXME get rid of this, it can just be in the MetaFrames struct */
MetaFrameControl prelit_control;
};
struct _MetaFrames
{
GtkWindow parent_instance;
GHashTable *text_heights;
GHashTable *frames;
MetaUIFrame *last_motion_frame;
GtkStyleContext *normal_style;
GHashTable *style_variants;
int expose_delay_count;
int invalidate_cache_timeout_id;
GList *invalidate_frames;
GHashTable *cache;
};
struct _MetaFramesClass
{
GtkWindowClass parent_class;
};
GType meta_frames_get_type (void) G_GNUC_CONST;
MetaFrames *meta_frames_new (int screen_number);
void meta_frames_manage_window (MetaFrames *frames,
Window xwindow,
GdkWindow *window);
void meta_frames_unmanage_window (MetaFrames *frames,
Window xwindow);
void meta_frames_set_title (MetaFrames *frames,
Window xwindow,
const char *title);
void meta_frames_update_frame_style (MetaFrames *frames,
Window xwindow);
void meta_frames_repaint_frame (MetaFrames *frames,
Window xwindow);
void meta_frames_get_borders (MetaFrames *frames,
Window xwindow,
MetaFrameBorders *borders);
void meta_frames_reset_bg (MetaFrames *frames,
Window xwindow);
void meta_frames_unflicker_bg (MetaFrames *frames,
Window xwindow,
int target_width,
int target_height);
cairo_region_t *meta_frames_get_frame_bounds (MetaFrames *frames,
Window xwindow,
int window_width,
int window_height);
void meta_frames_get_corner_radiuses (MetaFrames *frames,
Window xwindow,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right);
void meta_frames_move_resize_frame (MetaFrames *frames,
Window xwindow,
int x,
int y,
int width,
int height);
void meta_frames_queue_draw (MetaFrames *frames,
Window xwindow);
void meta_frames_notify_menu_hide (MetaFrames *frames);
Window meta_frames_get_moving_frame (MetaFrames *frames);
void meta_frames_push_delay_exposes (MetaFrames *frames);
void meta_frames_pop_delay_exposes (MetaFrames *frames);
#endif

View File

@ -1,865 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity gradient rendering */
/*
* Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
* WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA. */
#include <meta/gradient.h>
#include <meta/util.h>
#include <string.h>
/* This is all Alfredo's and Dan's usual very nice WindowMaker code,
* slightly GTK-ized
*/
static GdkPixbuf* meta_gradient_create_horizontal (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_vertical (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_diagonal (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to);
static GdkPixbuf* meta_gradient_create_multi_horizontal (int width,
int height,
const GdkRGBA *colors,
int count);
static GdkPixbuf* meta_gradient_create_multi_vertical (int width,
int height,
const GdkRGBA *colors,
int count);
static GdkPixbuf* meta_gradient_create_multi_diagonal (int width,
int height,
const GdkRGBA *colors,
int count);
/* Used as the destroy notification function for gdk_pixbuf_new() */
static void
free_buffer (guchar *pixels, gpointer data)
{
g_free (pixels);
}
static GdkPixbuf*
blank_pixbuf (int width, int height, gboolean no_padding)
{
guchar *buf;
int rowstride;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
if (no_padding)
rowstride = width * 3;
else
/* Always align rows to 32-bit boundaries */
rowstride = 4 * ((3 * width + 3) / 4);
buf = g_try_malloc (height * rowstride);
if (!buf)
return NULL;
return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB,
FALSE, 8,
width, height, rowstride,
free_buffer, NULL);
}
/**
* meta_gradient_create_simple:
* @width: Width in pixels
* @height: Height in pixels
* @from: Starting color
* @to: Ending color
* @style: Gradient style
*
* Returns: (transfer full): A new linear gradient
*/
GdkPixbuf*
meta_gradient_create_simple (int width,
int height,
const GdkRGBA *from,
const GdkRGBA *to,
MetaGradientType style)
{
switch (style)
{
case META_GRADIENT_HORIZONTAL:
return meta_gradient_create_horizontal (width, height,
from, to);
case META_GRADIENT_VERTICAL:
return meta_gradient_create_vertical (width, height,
from, to);
case META_GRADIENT_DIAGONAL:
return meta_gradient_create_diagonal (width, height,
from, to);
case META_GRADIENT_LAST:
break;
}
g_assert_not_reached ();
return NULL;
}
/**
* meta_gradient_create_multi:
* @width: Width in pixels
* @height: Height in pixels
* @colors: (array length=n_colors): Array of colors
* @n_colors: Number of colors
* @style: Gradient style
*
* Returns: (transfer full): A new multi-step linear gradient
*/
GdkPixbuf*
meta_gradient_create_multi (int width,
int height,
const GdkRGBA *colors,
int n_colors,
MetaGradientType style)
{
if (n_colors > 2)
{
switch (style)
{
case META_GRADIENT_HORIZONTAL:
return meta_gradient_create_multi_horizontal (width, height, colors, n_colors);
case META_GRADIENT_VERTICAL:
return meta_gradient_create_multi_vertical (width, height, colors, n_colors);
case META_GRADIENT_DIAGONAL:
return meta_gradient_create_multi_diagonal (width, height, colors, n_colors);
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}
else if (n_colors > 1)
{
return meta_gradient_create_simple (width, height, &colors[0], &colors[1],
style);
}
else if (n_colors > 0)
{
return meta_gradient_create_simple (width, height, &colors[0], &colors[0],
style);
}
g_assert_not_reached ();
return NULL;
}
/**
* meta_gradient_create_interwoven: (skip)
*
* Interwoven essentially means we have two vertical gradients,
* cut into horizontal strips of the given thickness, and then the strips
* are alternated. I'm not sure what it's good for, just copied since
* WindowMaker had it.
*/
GdkPixbuf*
meta_gradient_create_interwoven (int width,
int height,
const GdkRGBA colors1[2],
int thickness1,
const GdkRGBA colors2[2],
int thickness2)
{
int i, j, k, l, ll;
long r1, g1, b1, dr1, dg1, db1;
long r2, g2, b2, dr2, dg2, db2;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
pixbuf = blank_pixbuf (width, height, FALSE);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r1 = (long)(colors1[0].red*0xffffff);
g1 = (long)(colors1[0].green*0xffffff);
b1 = (long)(colors1[0].blue*0xffffff);
r2 = (long)(colors2[0].red*0xffffff);
g2 = (long)(colors2[0].green*0xffffff);
b2 = (long)(colors2[0].blue*0xffffff);
dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height;
dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height;
db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height;
dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height;
dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height;
db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(int)height;
for (i=0,k=0,l=0,ll=thickness1; i<height; i++)
{
ptr = pixels + i * rowstride;
if (k == 0)
{
ptr[0] = (unsigned char) (r1>>16);
ptr[1] = (unsigned char) (g1>>16);
ptr[2] = (unsigned char) (b1>>16);
}
else
{
ptr[0] = (unsigned char) (r2>>16);
ptr[1] = (unsigned char) (g2>>16);
ptr[2] = (unsigned char) (b2>>16);
}
for (j=1; j <= width/2; j *= 2)
memcpy (&(ptr[j*3]), ptr, j*3);
memcpy (&(ptr[j*3]), ptr, (width - j)*3);
if (++l == ll)
{
if (k == 0)
{
k = 1;
ll = thickness2;
}
else
{
k = 0;
ll = thickness1;
}
l = 0;
}
r1+=dr1;
g1+=dg1;
b1+=db1;
r2+=dr2;
g2+=dg2;
b2+=db2;
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_horizontal--
* Renders a horizontal linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_horizontal (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
int i;
long r, g, b, dr, dg, db;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int r0, g0, b0;
int rf, gf, bf;
int rowstride;
pixbuf = blank_pixbuf (width, height, FALSE);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
ptr = pixels;
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r0 = (guchar) (from->red * 0xff);
g0 = (guchar) (from->green * 0xff);
b0 = (guchar) (from->blue * 0xff);
rf = (guchar) (to->red * 0xff);
gf = (guchar) (to->green * 0xff);
bf = (guchar) (to->blue * 0xff);
r = r0 << 16;
g = g0 << 16;
b = b0 << 16;
dr = ((rf-r0)<<16)/(int)width;
dg = ((gf-g0)<<16)/(int)width;
db = ((bf-b0)<<16)/(int)width;
/* render the first line */
for (i=0; i<width; i++)
{
*(ptr++) = (unsigned char)(r>>16);
*(ptr++) = (unsigned char)(g>>16);
*(ptr++) = (unsigned char)(b>>16);
r += dr;
g += dg;
b += db;
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_vertical--
* Renders a vertical linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_vertical (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
int i, j;
long r, g, b, dr, dg, db;
GdkPixbuf *pixbuf;
unsigned char *ptr;
int r0, g0, b0;
int rf, gf, bf;
int rowstride;
unsigned char *pixels;
pixbuf = blank_pixbuf (width, height, FALSE);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
r0 = (guchar) (from->red * 0xff);
g0 = (guchar) (from->green * 0xff);
b0 = (guchar) (from->blue * 0xff);
rf = (guchar) (to->red * 0xff);
gf = (guchar) (to->green * 0xff);
bf = (guchar) (to->blue * 0xff);
r = r0<<16;
g = g0<<16;
b = b0<<16;
dr = ((rf-r0)<<16)/(int)height;
dg = ((gf-g0)<<16)/(int)height;
db = ((bf-b0)<<16)/(int)height;
for (i=0; i<height; i++)
{
ptr = pixels + i * rowstride;
ptr[0] = (unsigned char)(r>>16);
ptr[1] = (unsigned char)(g>>16);
ptr[2] = (unsigned char)(b>>16);
for (j=1; j <= width/2; j *= 2)
memcpy (&(ptr[j*3]), ptr, j*3);
memcpy (&(ptr[j*3]), ptr, (width - j)*3);
r+=dr;
g+=dg;
b+=db;
}
return pixbuf;
}
/*
*----------------------------------------------------------------------
* meta_gradient_create_diagonal--
* Renders a diagonal linear gradient of the specified size in the
* GdkPixbuf format with a border of the specified type.
*
* Returns:
* A 24bit GdkPixbuf with the gradient (no alpha channel).
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
static GdkPixbuf*
meta_gradient_create_diagonal (int width, int height,
const GdkRGBA *from,
const GdkRGBA *to)
{
GdkPixbuf *pixbuf, *tmp;
int j;
float a, offset;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
if (width == 1)
return meta_gradient_create_vertical (width, height, from, to);
else if (height == 1)
return meta_gradient_create_horizontal (width, height, from, to);
pixbuf = blank_pixbuf (width, height, FALSE);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to);
if (!tmp)
{
g_object_unref (G_OBJECT (pixbuf));
return NULL;
}
ptr = gdk_pixbuf_get_pixels (tmp);
a = ((float)(width - 1))/((float)(height - 1));
width = width * 3;
/* copy the first line to the other lines with corresponding offset */
for (j=0, offset=0.0; j<rowstride*height; j += rowstride)
{
memcpy (&(pixels[j]), &ptr[3*(int)offset], width);
offset += a;
}
g_object_unref (G_OBJECT (tmp));
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_horizontal (int width, int height,
const GdkRGBA *colors,
int count)
{
int i, j, k;
long r, g, b, dr, dg, db;
GdkPixbuf *pixbuf;
unsigned char *ptr;
unsigned char *pixels;
int width2;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
pixbuf = blank_pixbuf (width, height, FALSE);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
ptr = pixels;
if (count > width)
count = width;
if (count > 1)
width2 = width/(count-1);
else
width2 = width;
k = 0;
r = (long)(colors[0].red * 0xffffff);
g = (long)(colors[0].green * 0xffffff);
b = (long)(colors[0].blue * 0xffffff);
/* render the first line */
for (i=1; i<count; i++)
{
dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)width2;
dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)width2;
db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)width2;
for (j=0; j<width2; j++)
{
*ptr++ = (unsigned char)(r>>16);
*ptr++ = (unsigned char)(g>>16);
*ptr++ = (unsigned char)(b>>16);
r += dr;
g += dg;
b += db;
k++;
}
r = (long)(colors[i].red * 0xffffff);
g = (long)(colors[i].green * 0xffffff);
b = (long)(colors[i].blue * 0xffffff);
}
for (j=k; j<width; j++)
{
*ptr++ = (unsigned char)(r>>16);
*ptr++ = (unsigned char)(g>>16);
*ptr++ = (unsigned char)(b>>16);
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_vertical (int width, int height,
const GdkRGBA *colors,
int count)
{
int i, j, k;
long r, g, b, dr, dg, db;
GdkPixbuf *pixbuf;
unsigned char *ptr, *tmp, *pixels;
int height2;
int x;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
pixbuf = blank_pixbuf (width, height, FALSE);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
ptr = pixels;
if (count > height)
count = height;
if (count > 1)
height2 = height/(count-1);
else
height2 = height;
k = 0;
r = (long)(colors[0].red * 0xffffff);
g = (long)(colors[0].green * 0xffffff);
b = (long)(colors[0].blue * 0xffffff);
for (i=1; i<count; i++)
{
dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)height2;
dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)height2;
db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)height2;
for (j=0; j<height2; j++)
{
ptr[0] = (unsigned char)(r>>16);
ptr[1] = (unsigned char)(g>>16);
ptr[2] = (unsigned char)(b>>16);
for (x=1; x <= width/2; x *= 2)
memcpy (&(ptr[x*3]), ptr, x*3);
memcpy (&(ptr[x*3]), ptr, (width - x)*3);
ptr += rowstride;
r += dr;
g += dg;
b += db;
k++;
}
r = (long)(colors[i].red * 0xffffff);
g = (long)(colors[i].green * 0xffffff);
b = (long)(colors[i].blue * 0xffffff);
}
if (k<height)
{
tmp = ptr;
ptr[0] = (unsigned char) (r>>16);
ptr[1] = (unsigned char) (g>>16);
ptr[2] = (unsigned char) (b>>16);
for (x=1; x <= width/2; x *= 2)
memcpy (&(ptr[x*3]), ptr, x*3);
memcpy (&(ptr[x*3]), ptr, (width - x)*3);
ptr += rowstride;
for (j=k+1; j<height; j++)
{
memcpy (ptr, tmp, rowstride);
ptr += rowstride;
}
}
return pixbuf;
}
static GdkPixbuf*
meta_gradient_create_multi_diagonal (int width, int height,
const GdkRGBA *colors,
int count)
{
GdkPixbuf *pixbuf, *tmp;
float a, offset;
int j;
unsigned char *ptr;
unsigned char *pixels;
int rowstride;
g_return_val_if_fail (count > 2, NULL);
if (width == 1)
return meta_gradient_create_multi_vertical (width, height, colors, count);
else if (height == 1)
return meta_gradient_create_multi_horizontal (width, height, colors, count);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
width, height);
if (pixbuf == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
if (count > width)
count = width;
if (count > height)
count = height;
if (count > 2)
tmp = meta_gradient_create_multi_horizontal (2*width-1, 1, colors, count);
else
/* wrlib multiplies these colors by 256 before passing them in, but
* I think it's a bug in wrlib, so changed here. I could be wrong
* though, if we notice two-color multi diagonals not working.
*/
tmp = meta_gradient_create_horizontal (2*width-1, 1,
&colors[0], &colors[1]);
if (!tmp)
{
g_object_unref (G_OBJECT (pixbuf));
return NULL;
}
ptr = gdk_pixbuf_get_pixels (tmp);
a = ((float)(width - 1))/((float)(height - 1));
width = width * 3;
/* copy the first line to the other lines with corresponding offset */
for (j=0, offset=0; j<rowstride*height; j += rowstride)
{
memcpy (&(pixels[j]), &ptr[3*(int)offset], width);
offset += a;
}
g_object_unref (G_OBJECT (tmp));
return pixbuf;
}
static void
simple_multiply_alpha (GdkPixbuf *pixbuf,
guchar alpha)
{
guchar *pixels;
int rowstride;
int height;
int row;
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
if (alpha == 255)
return;
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
row = 0;
while (row < height)
{
guchar *p;
guchar *end;
p = pixels + row * rowstride;
end = p + rowstride;
while (p != end)
{
p += 3; /* skip RGB */
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) alpha) / (int) 255);
++p; /* skip A */
}
++row;
}
}
static void
meta_gradient_add_alpha_horizontal (GdkPixbuf *pixbuf,
const unsigned char *alphas,
int n_alphas)
{
int i, j;
long a, da;
unsigned char *p;
unsigned char *pixels;
int width2;
int rowstride;
int width, height;
unsigned char *gradient;
unsigned char *gradient_p;
unsigned char *gradient_end;
g_return_if_fail (n_alphas > 0);
if (n_alphas == 1)
{
/* Optimize this */
simple_multiply_alpha (pixbuf, alphas[0]);
return;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
gradient = g_new (unsigned char, width);
gradient_end = gradient + width;
if (n_alphas > width)
n_alphas = width;
if (n_alphas > 1)
width2 = width / (n_alphas - 1);
else
width2 = width;
a = alphas[0] << 8;
gradient_p = gradient;
/* render the gradient into an array */
for (i = 1; i < n_alphas; i++)
{
da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2;
for (j = 0; j < width2; j++)
{
*gradient_p++ = (a >> 8);
a += da;
}
a = alphas[i] << 8;
}
/* get leftover pixels */
while (gradient_p != gradient_end)
{
*gradient_p++ = a >> 8;
}
/* Now for each line of the pixbuf, fill in with the gradient */
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
p = pixels;
i = 0;
while (i < height)
{
unsigned char *row_end = p + rowstride;
gradient_p = gradient;
p += 3;
while (gradient_p != gradient_end)
{
/* multiply the two alpha channels. not sure this is right.
* but some end cases are that if the pixbuf contains 255,
* then it should be modified to contain "alpha"; if the
* pixbuf contains 0, it should remain 0.
*/
/* ((*p / 255.0) * (alpha / 255.0)) * 255; */
*p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255);
p += 4;
++gradient_p;
}
p = row_end;
++i;
}
g_free (gradient);
}
void
meta_gradient_add_alpha (GdkPixbuf *pixbuf,
const guchar *alphas,
int n_alphas,
MetaGradientType type)
{
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf));
g_return_if_fail (n_alphas > 0);
switch (type)
{
case META_GRADIENT_HORIZONTAL:
meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas);
break;
case META_GRADIENT_VERTICAL:
g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_DIAGONAL:
g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n");
break;
case META_GRADIENT_LAST:
g_assert_not_reached ();
break;
}
}

View File

@ -137,7 +137,7 @@ menu_closed (GtkMenu *widget,
menu = data;
meta_frames_notify_menu_hide (menu->frames);
meta_ui_notify_menu_hide (menu->ui);
(* menu->func) (menu,
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
menu->client_xwindow,
@ -157,7 +157,7 @@ activate_cb (GtkWidget *menuitem, gpointer data)
md = data;
meta_frames_notify_menu_hide (md->menu->frames);
meta_ui_notify_menu_hide (md->menu->ui);
(* md->menu->func) (md->menu,
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
md->menu->client_xwindow,
@ -321,7 +321,9 @@ menu_item_new (MenuItem *menuitem, int workspace_id)
}
MetaWindowMenu*
meta_window_menu_new (MetaFrames *frames,
meta_window_menu_new (MetaUI *ui,
Display *display,
gint screen_no,
MetaMenuOp ops,
MetaMenuOp insensitive,
Window client_xwindow,
@ -332,6 +334,8 @@ meta_window_menu_new (MetaFrames *frames,
{
int i;
MetaWindowMenu *menu;
GdkDisplay *gdkdisplay = gdk_x11_lookup_xdisplay (display);
GdkScreen *screen = gdk_display_get_screen (gdkdisplay, screen_no);
/* FIXME: Modifications to 'ops' should happen in meta_window_show_menu */
if (n_workspaces < 2)
@ -341,7 +345,7 @@ meta_window_menu_new (MetaFrames *frames,
ops &= ~(META_MENU_OP_WORKSPACES);
menu = g_new (MetaWindowMenu, 1);
menu->frames = frames;
menu->ui = ui;
menu->client_xwindow = client_xwindow;
menu->func = func;
menu->data = data;
@ -350,8 +354,7 @@ meta_window_menu_new (MetaFrames *frames,
menu->menu = gtk_menu_new ();
gtk_menu_set_screen (GTK_MENU (menu->menu),
gtk_widget_get_screen (GTK_WIDGET (frames)));
gtk_menu_set_screen (GTK_MENU (menu->menu), screen);
for (i = 0; i < (int) G_N_ELEMENTS (menuitems); i++)
{
@ -384,10 +387,7 @@ meta_window_menu_new (MetaFrames *frames,
{
if (ops & META_MENU_OP_WORKSPACES)
{
Display *display;
Window xroot;
GdkScreen *screen;
GdkWindow *window;
GtkWidget *submenu;
int j;
@ -400,10 +400,6 @@ meta_window_menu_new (MetaFrames *frames,
meta_verbose ("Creating %d-workspace menu current space %lu\n",
n_workspaces, active_workspace);
window = gtk_widget_get_window (GTK_WIDGET (frames));
display = GDK_WINDOW_XDISPLAY (window);
screen = gdk_window_get_screen (window);
xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
submenu = gtk_menu_new ();

View File

@ -25,7 +25,7 @@
#define META_MENU_H
#include <gtk/gtk.h>
#include "frames.h"
#include "ui.h"
/* Stock icons */
#define METACITY_STOCK_DELETE "metacity-delete"
@ -34,7 +34,7 @@
struct _MetaWindowMenu
{
MetaFrames *frames;
MetaUI *ui;
Window client_xwindow;
GtkWidget *menu;
MetaWindowMenuFunc func;
@ -43,7 +43,9 @@ struct _MetaWindowMenu
MetaMenuOp insensitive;
};
MetaWindowMenu* meta_window_menu_new (MetaFrames *frames,
MetaWindowMenu* meta_window_menu_new (MetaUI *ui,
Display *display,
gint screen_no,
MetaMenuOp ops,
MetaMenuOp insensitive,
Window client_xwindow,

View File

@ -1,581 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity theme preview widget */
/*
* Copyright (C) 2002 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#define _GNU_SOURCE
#define _XOPEN_SOURCE 600 /* for the maths routines over floats */
#include <math.h>
#include <gtk/gtk.h>
#include <meta/preview-widget.h>
#include "theme-private.h"
static void meta_preview_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural);
static void meta_preview_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural);
static void meta_preview_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean meta_preview_draw (GtkWidget *widget,
cairo_t *cr);
static void meta_preview_finalize (GObject *object);
G_DEFINE_TYPE (MetaPreview, meta_preview, GTK_TYPE_BIN);
static void
meta_preview_class_init (MetaPreviewClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class;
widget_class = (GtkWidgetClass*) class;
gobject_class->finalize = meta_preview_finalize;
widget_class->draw = meta_preview_draw;
widget_class->get_preferred_width = meta_preview_get_preferred_width;
widget_class->get_preferred_height = meta_preview_get_preferred_height;
widget_class->size_allocate = meta_preview_size_allocate;
gtk_container_class_handle_border_width (GTK_CONTAINER_CLASS (class));
}
static void
meta_preview_init (MetaPreview *preview)
{
int i;
gtk_widget_set_has_window (GTK_WIDGET (preview), FALSE);
i = 0;
while (i < MAX_BUTTONS_PER_CORNER)
{
preview->button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
preview->button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
++i;
}
preview->button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU;
preview->button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
preview->button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
preview->button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
preview->type = META_FRAME_TYPE_NORMAL;
preview->flags =
META_FRAME_ALLOWS_DELETE |
META_FRAME_ALLOWS_MENU |
META_FRAME_ALLOWS_MINIMIZE |
META_FRAME_ALLOWS_MAXIMIZE |
META_FRAME_ALLOWS_VERTICAL_RESIZE |
META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
META_FRAME_HAS_FOCUS |
META_FRAME_ALLOWS_SHADE |
META_FRAME_ALLOWS_MOVE;
preview->borders_cached = FALSE;
}
GtkWidget*
meta_preview_new (void)
{
MetaPreview *preview;
preview = g_object_new (META_TYPE_PREVIEW, NULL);
return GTK_WIDGET (preview);
}
static void
meta_preview_finalize (GObject *object)
{
MetaPreview *preview;
preview = META_PREVIEW (object);
g_free (preview->title);
preview->title = NULL;
G_OBJECT_CLASS (meta_preview_parent_class)->finalize (object);
}
static void
ensure_info (MetaPreview *preview)
{
GtkWidget *widget;
widget = GTK_WIDGET (preview);
if (preview->layout == NULL)
{
PangoFontDescription *font_desc;
double scale;
PangoAttrList *attrs;
PangoAttribute *attr;
if (preview->theme)
scale = meta_theme_get_title_scale (preview->theme,
preview->type,
preview->flags);
else
scale = 1.0;
preview->layout = gtk_widget_create_pango_layout (widget,
preview->title);
font_desc = meta_gtk_widget_get_font_desc (widget, scale, NULL);
preview->text_height =
meta_pango_font_desc_get_text_height (font_desc,
gtk_widget_get_pango_context (widget));
attrs = pango_attr_list_new ();
attr = pango_attr_size_new (pango_font_description_get_size (font_desc));
attr->start_index = 0;
attr->end_index = G_MAXINT;
pango_attr_list_insert (attrs, attr);
pango_layout_set_attributes (preview->layout, attrs);
pango_attr_list_unref (attrs);
pango_font_description_free (font_desc);
}
if (!preview->borders_cached)
{
if (preview->theme)
meta_theme_get_frame_borders (preview->theme,
preview->type,
preview->text_height,
preview->flags,
&preview->borders);
else
meta_frame_borders_clear (&preview->borders);
preview->borders_cached = TRUE;
}
}
static gboolean
meta_preview_draw (GtkWidget *widget,
cairo_t *cr)
{
MetaPreview *preview = META_PREVIEW (widget);
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
if (preview->theme)
{
int client_width;
int client_height;
MetaButtonState button_states[META_BUTTON_TYPE_LAST] =
{
META_BUTTON_STATE_NORMAL,
META_BUTTON_STATE_NORMAL,
META_BUTTON_STATE_NORMAL,
META_BUTTON_STATE_NORMAL
};
ensure_info (preview);
cairo_save (cr);
client_width = allocation.width - preview->borders.total.left - preview->borders.total.right;
client_height = allocation.height - preview->borders.total.top - preview->borders.total.bottom;
if (client_width < 0)
client_width = 1;
if (client_height < 0)
client_height = 1;
meta_theme_draw_frame (preview->theme,
widget,
cr,
preview->type,
preview->flags,
client_width, client_height,
preview->layout,
preview->text_height,
&preview->button_layout,
button_states,
meta_preview_get_mini_icon (),
meta_preview_get_icon ());
cairo_restore (cr);
}
/* draw child */
return GTK_WIDGET_CLASS (meta_preview_parent_class)->draw (widget, cr);
}
#define NO_CHILD_WIDTH 80
#define NO_CHILD_HEIGHT 20
static void
meta_preview_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
{
MetaPreview *preview;
GtkWidget *child;
preview = META_PREVIEW (widget);
ensure_info (preview);
*minimum = *natural = preview->borders.total.left + preview->borders.total.right;
child = gtk_bin_get_child (GTK_BIN (preview));
if (child && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gtk_widget_get_preferred_width (child, &child_min, &child_nat);
*minimum += child_min;
*natural += child_nat;
}
else
{
*minimum += NO_CHILD_WIDTH;
*natural += NO_CHILD_WIDTH;
}
}
static void
meta_preview_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
MetaPreview *preview;
GtkWidget *child;
preview = META_PREVIEW (widget);
ensure_info (preview);
*minimum = *natural = preview->borders.total.top + preview->borders.total.bottom;
child = gtk_bin_get_child (GTK_BIN (preview));
if (child && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gtk_widget_get_preferred_height (child, &child_min, &child_nat);
*minimum += child_min;
*natural += child_nat;
}
else
{
*minimum += NO_CHILD_HEIGHT;
*natural += NO_CHILD_HEIGHT;
}
}
static void
meta_preview_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
MetaPreview *preview;
GtkAllocation widget_allocation, child_allocation;
GtkWidget *child;
preview = META_PREVIEW (widget);
ensure_info (preview);
gtk_widget_set_allocation (widget, allocation);
child = gtk_bin_get_child (GTK_BIN (widget));
if (child && gtk_widget_get_visible (child))
{
gtk_widget_get_allocation (widget, &widget_allocation);
child_allocation.x = widget_allocation.x + preview->borders.total.left;
child_allocation.y = widget_allocation.y + preview->borders.total.top;
child_allocation.width = MAX (1, widget_allocation.width - preview->borders.total.left - preview->borders.total.right);
child_allocation.height = MAX (1, widget_allocation.height - preview->borders.total.top - preview->borders.total.bottom);
gtk_widget_size_allocate (child, &child_allocation);
}
}
static void
clear_cache (MetaPreview *preview)
{
if (preview->layout)
{
g_object_unref (G_OBJECT (preview->layout));
preview->layout = NULL;
}
preview->borders_cached = FALSE;
}
void
meta_preview_set_theme (MetaPreview *preview,
MetaTheme *theme)
{
g_return_if_fail (META_IS_PREVIEW (preview));
preview->theme = theme;
clear_cache (preview);
gtk_widget_queue_resize (GTK_WIDGET (preview));
}
void
meta_preview_set_title (MetaPreview *preview,
const char *title)
{
g_return_if_fail (META_IS_PREVIEW (preview));
g_free (preview->title);
preview->title = g_strdup (title);
clear_cache (preview);
gtk_widget_queue_resize (GTK_WIDGET (preview));
}
void
meta_preview_set_frame_type (MetaPreview *preview,
MetaFrameType type)
{
g_return_if_fail (META_IS_PREVIEW (preview));
preview->type = type;
clear_cache (preview);
gtk_widget_queue_resize (GTK_WIDGET (preview));
}
void
meta_preview_set_frame_flags (MetaPreview *preview,
MetaFrameFlags flags)
{
g_return_if_fail (META_IS_PREVIEW (preview));
preview->flags = flags;
clear_cache (preview);
gtk_widget_queue_resize (GTK_WIDGET (preview));
}
void
meta_preview_set_button_layout (MetaPreview *preview,
const MetaButtonLayout *button_layout)
{
g_return_if_fail (META_IS_PREVIEW (preview));
preview->button_layout = *button_layout;
gtk_widget_queue_draw (GTK_WIDGET (preview));
}
GdkPixbuf*
meta_preview_get_icon (void)
{
static GdkPixbuf *default_icon = NULL;
if (default_icon == NULL)
{
GtkIconTheme *theme;
gboolean icon_exists;
theme = gtk_icon_theme_get_default ();
icon_exists = gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME);
if (icon_exists)
default_icon = gtk_icon_theme_load_icon (theme,
META_DEFAULT_ICON_NAME,
META_ICON_WIDTH,
0,
NULL);
else
default_icon = gtk_icon_theme_load_icon (theme,
"gtk-missing-image",
META_ICON_WIDTH,
0,
NULL);
g_assert (default_icon);
}
return default_icon;
}
GdkPixbuf*
meta_preview_get_mini_icon (void)
{
static GdkPixbuf *default_icon = NULL;
if (default_icon == NULL)
{
GtkIconTheme *theme;
gboolean icon_exists;
theme = gtk_icon_theme_get_default ();
icon_exists = gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME);
if (icon_exists)
default_icon = gtk_icon_theme_load_icon (theme,
META_DEFAULT_ICON_NAME,
META_MINI_ICON_WIDTH,
0,
NULL);
else
default_icon = gtk_icon_theme_load_icon (theme,
"gtk-missing-image",
META_MINI_ICON_WIDTH,
0,
NULL);
g_assert (default_icon);
}
return default_icon;
}
cairo_region_t *
meta_preview_get_clip_region (MetaPreview *preview, gint new_window_width, gint new_window_height)
{
cairo_rectangle_int_t xrect;
cairo_region_t *corners_xregion, *window_xregion;
gint flags;
MetaFrameLayout *fgeom;
MetaFrameStyle *frame_style;
g_return_val_if_fail (META_IS_PREVIEW (preview), NULL);
flags = (META_PREVIEW (preview)->flags);
window_xregion = cairo_region_create ();
xrect.x = 0;
xrect.y = 0;
xrect.width = new_window_width;
xrect.height = new_window_height;
cairo_region_union_rectangle (window_xregion, &xrect);
if (preview->theme == NULL)
return window_xregion;
/* Otherwise, we do have a theme, so calculate the corners */
frame_style = meta_theme_get_frame_style (preview->theme,
META_FRAME_TYPE_NORMAL, flags);
fgeom = frame_style->layout;
corners_xregion = cairo_region_create ();
if (fgeom->top_left_corner_rounded_radius != 0)
{
const int corner = fgeom->top_left_corner_rounded_radius;
const float radius = sqrt(corner) + corner;
int i;
for (i=0; i<corner; i++)
{
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
xrect.x = 0;
xrect.y = i;
xrect.width = width;
xrect.height = 1;
cairo_region_union_rectangle (corners_xregion, &xrect);
}
}
if (fgeom->top_right_corner_rounded_radius != 0)
{
const int corner = fgeom->top_right_corner_rounded_radius;
const float radius = sqrt(corner) + corner;
int i;
for (i=0; i<corner; i++)
{
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
xrect.x = new_window_width - width;
xrect.y = i;
xrect.width = width;
xrect.height = 1;
cairo_region_union_rectangle (corners_xregion, &xrect);
}
}
if (fgeom->bottom_left_corner_rounded_radius != 0)
{
const int corner = fgeom->bottom_left_corner_rounded_radius;
const float radius = sqrt(corner) + corner;
int i;
for (i=0; i<corner; i++)
{
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
xrect.x = 0;
xrect.y = new_window_height - i - 1;
xrect.width = width;
xrect.height = 1;
cairo_region_union_rectangle (corners_xregion, &xrect);
}
}
if (fgeom->bottom_right_corner_rounded_radius != 0)
{
const int corner = fgeom->bottom_right_corner_rounded_radius;
const float radius = sqrt(corner) + corner;
int i;
for (i=0; i<corner; i++)
{
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
xrect.x = new_window_width - width;
xrect.y = new_window_height - i - 1;
xrect.width = width;
xrect.height = 1;
cairo_region_union_rectangle (corners_xregion, &xrect);
}
}
cairo_region_subtract (window_xregion, corners_xregion);
cairo_region_destroy (corners_xregion);
return window_xregion;
}

View File

@ -1,317 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter gradient test program */
/*
* Copyright (C) 2002 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA. */
#include <meta/gradient.h>
#include <gtk/gtk.h>
typedef void (* RenderGradientFunc) (cairo_t *cr,
int width,
int height);
static void
draw_checkerboard (cairo_t *cr,
int width,
int height)
{
gint i, j, xcount, ycount;
GdkRGBA color1, color2;
#define CHECK_SIZE 10
#define SPACING 2
color1.red = 30000. / 65535.;
color1.green = 30000. / 65535.;
color1.blue = 30000. / 65535.;
color1.alpha = 1.0;
color2.red = 50000. / 65535.;
color2.green = 50000. / 65535.;
color2.blue = 50000. / 65535.;
color2.alpha = 1.0;
xcount = 0;
i = SPACING;
while (i < width)
{
j = SPACING;
ycount = xcount % 2; /* start with even/odd depending on row */
while (j < height)
{
if (ycount % 2)
gdk_cairo_set_source_rgba (cr, &color1);
else
gdk_cairo_set_source_rgba (cr, &color2);
/* If we're outside event->area, this will do nothing.
* It might be mildly more efficient if we handled
* the clipping ourselves, but again we're feeling lazy.
*/
cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
cairo_fill (cr);
j += CHECK_SIZE + SPACING;
++ycount;
}
i += CHECK_SIZE + SPACING;
++xcount;
}
}
static void
render_simple (cairo_t *cr,
int width, int height,
MetaGradientType type,
gboolean with_alpha)
{
GdkPixbuf *pixbuf;
GdkRGBA from, to;
gdk_rgba_parse (&from, "blue");
gdk_rgba_parse (&to, "green");
pixbuf = meta_gradient_create_simple (width, height,
&from, &to,
type);
if (with_alpha)
{
const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff };
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
GdkPixbuf *new_pixbuf;
new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
g_object_unref (G_OBJECT (pixbuf));
pixbuf = new_pixbuf;
}
meta_gradient_add_alpha (pixbuf,
alphas, G_N_ELEMENTS (alphas),
META_GRADIENT_HORIZONTAL);
draw_checkerboard (cr , width, height);
}
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
}
static void
render_vertical_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_VERTICAL, FALSE);
}
static void
render_horizontal_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_HORIZONTAL, FALSE);
}
static void
render_diagonal_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, FALSE);
}
static void
render_diagonal_alpha_func (cairo_t *cr,
int width, int height)
{
render_simple (cr, width, height, META_GRADIENT_DIAGONAL, TRUE);
}
static void
render_multi (cairo_t *cr,
int width, int height,
MetaGradientType type)
{
GdkPixbuf *pixbuf;
#define N_COLORS 5
GdkRGBA colors[N_COLORS];
gdk_rgba_parse (&colors[0], "red");
gdk_rgba_parse (&colors[1], "blue");
gdk_rgba_parse (&colors[2], "orange");
gdk_rgba_parse (&colors[3], "pink");
gdk_rgba_parse (&colors[4], "green");
pixbuf = meta_gradient_create_multi (width, height,
colors, N_COLORS,
type);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
#undef N_COLORS
}
static void
render_vertical_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_VERTICAL);
}
static void
render_horizontal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_HORIZONTAL);
}
static void
render_diagonal_multi_func (cairo_t *cr,
int width, int height)
{
render_multi (cr, width, height, META_GRADIENT_DIAGONAL);
}
static void
render_interwoven_func (cairo_t *cr,
int width, int height)
{
GdkPixbuf *pixbuf;
#define N_COLORS 4
GdkRGBA colors[N_COLORS];
gdk_rgba_parse (&colors[0], "red");
gdk_rgba_parse (&colors[1], "blue");
gdk_rgba_parse (&colors[2], "pink");
gdk_rgba_parse (&colors[3], "green");
pixbuf = meta_gradient_create_interwoven (width, height,
colors, height / 10,
colors + 2, height / 14);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
g_object_unref (G_OBJECT (pixbuf));
}
static gboolean
draw_callback (GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
RenderGradientFunc func = data;
GtkStyleContext *style;
GdkRGBA color;
style = gtk_widget_get_style_context (widget);
gtk_style_context_save (style);
gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (style, "foreground-color", &color);
gtk_style_context_restore (style);
gdk_cairo_set_source_rgba (cr, &color);
(* func) (cr,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
return FALSE;
}
static GtkWidget*
create_gradient_window (const char *title,
RenderGradientFunc func)
{
GtkWidget *window;
GtkWidget *drawing_area;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), title);
drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 1, 1);
gtk_window_set_default_size (GTK_WINDOW (window), 175, 175);
g_signal_connect (G_OBJECT (drawing_area),
"draw",
G_CALLBACK (draw_callback),
func);
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_show_all (window);
return window;
}
static void
meta_gradient_test (void)
{
create_gradient_window ("Simple vertical",
render_vertical_func);
create_gradient_window ("Simple horizontal",
render_horizontal_func);
create_gradient_window ("Simple diagonal",
render_diagonal_func);
create_gradient_window ("Multi vertical",
render_vertical_multi_func);
create_gradient_window ("Multi horizontal",
render_horizontal_multi_func);
create_gradient_window ("Multi diagonal",
render_diagonal_multi_func);
create_gradient_window ("Interwoven",
render_interwoven_func);
create_gradient_window ("Simple diagonal with horizontal multi alpha",
render_diagonal_alpha_func);
}
int
main (int argc, char **argv)
{
gtk_init (&argc, &argv);
meta_gradient_test ();
gtk_main ();
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,11 +25,10 @@
#include <config.h>
#include <meta/prefs.h>
#include "ui.h"
#include "frames.h"
#include "uiframe.h"
#include <meta/util.h>
#include "menu.h"
#include "core.h"
#include "theme-private.h"
#include "inlinepixbufs.h"
@ -47,7 +46,7 @@ struct _MetaUI
{
Display *xdisplay;
Screen *xscreen;
MetaFrames *frames;
GHashTable *frames;
/* For double-click tracking */
guint button_click_number;
@ -82,7 +81,7 @@ meta_ui_get_display (void)
return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
}
/* We do some of our event handling in frames.c, which expects
/* We do some of our event handling in uiframe.c, which expects
* GDK events delivered by GTK+. However, since the transition to
* client side windows, we can't let GDK see button events, since the
* client-side tracking of implicit and explicit grabs it does will
@ -93,7 +92,7 @@ meta_ui_get_display (void)
* through the normal GDK event handling.
*
* To reduce the amount of code, the only events fields filled out
* below are the ones that frames.c uses. If frames.c is modified to
* below are the ones that uiframe.c uses. If uiframe.c is modified to
* use more fields, more fields need to be filled out below.
*/
@ -270,6 +269,60 @@ meta_ui_remove_event_func (Display *xdisplay,
ef = NULL;
}
static void
queue_draw_func (gpointer key, gpointer value, gpointer data)
{
gtk_widget_queue_draw (GTK_WIDGET (value));
}
static void
button_layout_changed (MetaUI *ui)
{
g_hash_table_foreach (ui->frames, queue_draw_func, NULL);
}
static void
prefs_changed_callback (MetaPreference pref,
void *data)
{
switch (pref)
{
case META_PREF_BUTTON_LAYOUT:
button_layout_changed ((MetaUI *) data);
break;
default:
break;
}
}
static gint
unsigned_long_equal (gconstpointer v1,
gconstpointer v2)
{
return *((const gulong*) v1) == *((const gulong*) v2);
}
static guint
unsigned_long_hash (gconstpointer v)
{
gulong val = * (const gulong *) v;
/* I'm not sure this works so well. */
#if GLIB_SIZEOF_LONG > 4
return (guint) (val ^ (val >> 32));
#else
return val;
#endif
}
static MetaUIFrame*
meta_ui_lookup_window (MetaUI *ui,
Window xwindow)
{
return g_hash_table_lookup (ui->frames, &xwindow);
}
MetaUI*
meta_ui_new (Display *xdisplay,
Screen *screen)
@ -284,11 +337,9 @@ meta_ui_new (Display *xdisplay,
gdisplay = gdk_x11_lookup_xdisplay (xdisplay);
g_assert (gdisplay == gdk_display_get_default ());
ui->frames = meta_frames_new (XScreenNumberOfScreen (screen));
/* This does not actually show any widget. MetaFrames has been hacked so
* that showing it doesn't actually do anything. But we need the flags
* set for GTK to deliver events properly. */
gtk_widget_show (GTK_WIDGET (ui->frames));
ui->frames = g_hash_table_new_full (unsigned_long_hash, unsigned_long_equal,
NULL, (GDestroyNotify) gtk_widget_destroy);
meta_prefs_add_listener (prefs_changed_callback, ui);
g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui);
@ -300,7 +351,9 @@ meta_ui_free (MetaUI *ui)
{
GdkDisplay *gdisplay;
gtk_widget_destroy (GTK_WIDGET (ui->frames));
g_assert (g_hash_table_size (ui->frames) == 0);
meta_prefs_remove_listener (prefs_changed_callback, ui);
g_hash_table_unref (ui->frames);
gdisplay = gdk_x11_lookup_xdisplay (ui->xdisplay);
g_object_set_data (G_OBJECT (gdisplay), "meta-ui", NULL);
@ -310,24 +363,24 @@ meta_ui_free (MetaUI *ui)
void
meta_ui_get_frame_borders (MetaUI *ui,
Window frame_xwindow,
Window xwindow,
MetaFrameBorders *borders)
{
meta_frames_get_borders (ui->frames, frame_xwindow,
borders);
MetaUIFrame *frame = meta_ui_lookup_window (ui, xwindow);
if (frame == NULL)
meta_bug ("No such frame 0x%lx\n", xwindow);
meta_uiframe_get_frame_borders (frame, borders);
}
void
meta_ui_get_corner_radiuses (MetaUI *ui,
Window xwindow,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right)
meta_ui_render_background (MetaUI *ui,
Window xwindow,
cairo_t *cr)
{
meta_frames_get_corner_radiuses (ui->frames, xwindow,
top_left, top_right,
bottom_left, bottom_right);
MetaUIFrame *frame = meta_ui_lookup_window (ui, xwindow);
meta_uiframe_paint (frame, cr);
}
Window
@ -347,6 +400,7 @@ meta_ui_create_frame_window (MetaUI *ui,
gint attributes_mask;
GdkWindow *window;
GdkVisual *visual;
MetaUIFrame *frame;
/* Default depth/visual handles clients with weird visuals; they can
* always be children of the root depth/visual obviously, but
@ -396,28 +450,84 @@ meta_ui_create_frame_window (MetaUI *ui,
&attrs, attributes_mask);
gdk_window_resize (window, width, height);
meta_frames_manage_window (ui->frames, GDK_WINDOW_XID (window), window);
return GDK_WINDOW_XID (window);
frame = g_object_new (META_TYPE_UIFRAME,
"type", GTK_WINDOW_POPUP,
"app-paintable", TRUE,
NULL);
/* This fakes out the widget so it won't actually
* get realized as a server-side window. */
/* XXX: the gtk_widget_set_parent_window call unsets is_toplevel,
* leading to the widget not being realized, which triggers all sorts
* of assertions. Company suggested the below hack until we have
* something better. */
/* gtk_widget_set_parent_window (GTK_WIDGET (frame), window); */
g_object_set_data (G_OBJECT (frame), "gtk-parent-window", g_object_ref (window));
gdk_window_set_user_data (window, frame);
/* Don't set event mask here, it's in frame.c */
frame->window = g_object_ref (window);
frame->xwindow = GDK_WINDOW_XID (window);
frame->prelit_control = META_FRAME_CONTROL_NONE;
/* Don't set the window background yet; we need frame->xwindow to be
* registered with its MetaWindow, which happens after this function
* and meta_ui_create_frame_window() return to meta_window_ensure_frame().
*/
meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
g_hash_table_replace (ui->frames, &frame->xwindow, frame);
return frame->xwindow;
}
void
meta_ui_realize_frame_window (MetaUI *ui,
Window xwindow)
{
MetaUIFrame *frame = meta_ui_lookup_window (ui, xwindow);
gtk_widget_show (GTK_WIDGET (frame));
}
void
meta_ui_destroy_frame_window (MetaUI *ui,
Window xwindow)
{
meta_frames_unmanage_window (ui->frames, xwindow);
MetaUIFrame *frame;
frame = g_hash_table_lookup (ui->frames, &xwindow);
if (frame)
{
/* restore the cursor */
meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
frame->xwindow,
META_CURSOR_DEFAULT);
gdk_window_set_user_data (frame->window, NULL);
g_hash_table_remove (ui->frames, &frame->xwindow);
}
else
meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
}
void
meta_ui_move_resize_frame (MetaUI *ui,
Window frame,
Window xwindow,
int x,
int y,
int width,
int height)
{
meta_frames_move_resize_frame (ui->frames, frame, x, y, width, height);
MetaUIFrame *frame = meta_ui_lookup_window (ui, xwindow);
gdk_window_move_resize (frame->window, x, y, width, height);
gtk_widget_set_size_request (GTK_WIDGET (frame), width, height);
}
void
@ -448,52 +558,15 @@ meta_ui_unmap_frame (MetaUI *ui,
gdk_window_hide (window);
}
void
meta_ui_unflicker_frame_bg (MetaUI *ui,
Window xwindow,
int target_width,
int target_height)
{
meta_frames_unflicker_bg (ui->frames, xwindow,
target_width, target_height);
}
void
meta_ui_update_frame_style (MetaUI *ui,
Window xwindow)
{
meta_frames_update_frame_style (ui->frames, xwindow);
}
void
meta_ui_repaint_frame (MetaUI *ui,
Window xwindow)
{
meta_frames_repaint_frame (ui->frames, xwindow);
}
void
meta_ui_reset_frame_bg (MetaUI *ui,
Window xwindow)
{
meta_frames_reset_bg (ui->frames, xwindow);
}
cairo_region_t *
meta_ui_get_frame_bounds (MetaUI *ui,
Window xwindow,
int window_width,
int window_height)
{
return meta_frames_get_frame_bounds (ui->frames, xwindow,
window_width, window_height);
}
void
meta_ui_queue_frame_draw (MetaUI *ui,
Window xwindow)
{
meta_frames_queue_draw (ui->frames, xwindow);
MetaUIFrame *frame = meta_ui_lookup_window (ui, xwindow);
GtkWidget *widget = GTK_WIDGET (frame);
/* Force a style update. */
gtk_style_context_invalidate (gtk_widget_get_style_context (widget));
gtk_widget_queue_draw (widget);
}
void
@ -501,11 +574,14 @@ meta_ui_set_frame_title (MetaUI *ui,
Window xwindow,
const char *title)
{
meta_frames_set_title (ui->frames, xwindow, title);
MetaUIFrame *frame = meta_ui_lookup_window (ui, xwindow);
meta_uiframe_set_title (frame, title);
}
MetaWindowMenu*
meta_ui_window_menu_new (MetaUI *ui,
Display *display,
gint screen_no,
Window client_xwindow,
MetaMenuOp ops,
MetaMenuOp insensitive,
@ -514,7 +590,7 @@ meta_ui_window_menu_new (MetaUI *ui,
MetaWindowMenuFunc func,
gpointer data)
{
return meta_window_menu_new (ui->frames,
return meta_window_menu_new (ui, display, screen_no,
ops, insensitive,
client_xwindow,
active_workspace,
@ -588,18 +664,6 @@ meta_gdk_pixbuf_get_from_pixmap (Pixmap xpixmap,
return retval;
}
void
meta_ui_push_delay_exposes (MetaUI *ui)
{
meta_frames_push_delay_exposes (ui->frames);
}
void
meta_ui_pop_delay_exposes (MetaUI *ui)
{
meta_frames_pop_delay_exposes (ui->frames);
}
GdkPixbuf*
meta_ui_get_default_window_icon (MetaUI *ui)
{
@ -721,57 +785,6 @@ meta_text_property_to_utf8 (Display *xdisplay,
return retval;
}
void
meta_ui_theme_get_frame_borders (MetaUI *ui,
MetaFrameType type,
MetaFrameFlags flags,
MetaFrameBorders *borders)
{
int text_height;
GtkStyleContext *style = NULL;
PangoContext *context;
const PangoFontDescription *font_desc;
if (meta_ui_have_a_theme ())
{
context = gtk_widget_get_pango_context (GTK_WIDGET (ui->frames));
font_desc = meta_prefs_get_titlebar_font ();
if (!font_desc)
{
style = gtk_style_context_new ();
font_desc = gtk_style_context_get_font (style, 0);
}
text_height = meta_pango_font_desc_get_text_height (font_desc, context);
meta_theme_get_frame_borders (meta_theme_get_current (),
type, text_height, flags,
borders);
}
else
{
meta_frame_borders_clear (borders);
}
if (style != NULL)
g_object_unref (style);
}
void
meta_ui_set_current_theme (const char *name,
gboolean force_reload)
{
meta_theme_set_current (name, force_reload);
meta_invalidate_default_icons ();
}
gboolean
meta_ui_have_a_theme (void)
{
return meta_theme_get_current () != NULL;
}
static void
meta_ui_accelerator_parse (const char *accel,
guint *keysym,
@ -976,7 +989,7 @@ meta_ui_window_is_widget (MetaUI *ui,
{
void *user_data = NULL;
gdk_window_get_user_data (window, &user_data);
return user_data != NULL && user_data != ui->frames;
return user_data != NULL && !META_IS_UIFRAME (user_data);
}
else
return FALSE;
@ -1030,7 +1043,7 @@ meta_ui_get_drag_threshold (MetaUI *ui)
GtkSettings *settings;
int threshold;
settings = gtk_widget_get_settings (GTK_WIDGET (ui->frames));
settings = gtk_settings_get_default ();
threshold = 8;
g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &threshold, NULL);
@ -1047,3 +1060,29 @@ meta_ui_get_direction (void)
return META_UI_DIRECTION_LTR;
}
void
meta_ui_notify_menu_hide (MetaUI *ui)
{
Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
if (meta_core_get_grab_op (display) ==
META_GRAB_OP_CLICKING_MENU)
{
Window grab_frame;
grab_frame = meta_core_get_grab_frame (display);
if (grab_frame != None)
{
MetaUIFrame *frame;
frame = meta_ui_lookup_window (ui, grab_frame);
if (frame)
{
/* XXX: will redo redraw_control with GTK+ widgets
* soon enough */
/* redraw_control (frame, META_FRAME_CONTROL_MENU); */
meta_core_end_grab_op (display, CurrentTime);
}
}
}
}

View File

@ -57,10 +57,6 @@ MetaUI* meta_ui_new (Display *xdisplay,
Screen *screen);
void meta_ui_free (MetaUI *ui);
void meta_ui_theme_get_frame_borders (MetaUI *ui,
MetaFrameType type,
MetaFrameFlags flags,
MetaFrameBorders *borders);
void meta_ui_get_frame_borders (MetaUI *ui,
Window frame_xwindow,
MetaFrameBorders *borders);
@ -73,6 +69,8 @@ Window meta_ui_create_frame_window (MetaUI *ui,
gint height,
gint screen_no,
gulong *create_serial);
void meta_ui_realize_frame_window (MetaUI *ui,
Window xwindow);
void meta_ui_destroy_frame_window (MetaUI *ui,
Window xwindow);
void meta_ui_move_resize_frame (MetaUI *ui,
@ -88,24 +86,9 @@ void meta_ui_map_frame (MetaUI *ui,
void meta_ui_unmap_frame (MetaUI *ui,
Window xwindow);
void meta_ui_unflicker_frame_bg (MetaUI *ui,
Window xwindow,
int target_width,
int target_height);
void meta_ui_reset_frame_bg (MetaUI *ui,
Window xwindow);
cairo_region_t *meta_ui_get_frame_bounds (MetaUI *ui,
Window xwindow,
int window_width,
int window_height);
void meta_ui_get_corner_radiuses (MetaUI *ui,
Window xwindow,
float *top_left,
float *top_right,
float *bottom_left,
float *bottom_right);
void meta_ui_render_background (MetaUI *ui,
Window xwindow,
cairo_t *cr);
void meta_ui_queue_frame_draw (MetaUI *ui,
Window xwindow);
@ -114,13 +97,9 @@ void meta_ui_set_frame_title (MetaUI *ui,
Window xwindow,
const char *title);
void meta_ui_update_frame_style (MetaUI *ui,
Window window);
void meta_ui_repaint_frame (MetaUI *ui,
Window xwindow);
MetaWindowMenu* meta_ui_window_menu_new (MetaUI *ui,
Display *display,
gint screen_no,
Window client_xwindow,
MetaMenuOp ops,
MetaMenuOp insensitive,
@ -143,13 +122,6 @@ GdkPixbuf* meta_gdk_pixbuf_get_from_pixmap (Pixmap xpixmap,
int width,
int height);
/* Used when we have a server grab and draw all over everything,
* then we need to handle exposes after doing that, instead of
* during it
*/
void meta_ui_push_delay_exposes (MetaUI *ui);
void meta_ui_pop_delay_exposes (MetaUI *ui);
GdkPixbuf* meta_ui_get_default_window_icon (MetaUI *ui);
GdkPixbuf* meta_ui_get_default_mini_icon (MetaUI *ui);
@ -159,10 +131,6 @@ gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay,
char* meta_text_property_to_utf8 (Display *xdisplay,
const XTextProperty *prop);
void meta_ui_set_current_theme (const char *name,
gboolean force_reload);
gboolean meta_ui_have_a_theme (void);
/* Not a real key symbol but means "key above the tab key"; this is
* used as the default keybinding for cycle_group.
* 0x2xxxxxxx is a range not used by GDK or X. the remaining digits are
@ -186,6 +154,8 @@ int meta_ui_get_drag_threshold (MetaUI *ui);
MetaUIDirection meta_ui_get_direction (void);
void meta_ui_notify_menu_hide (MetaUI *ui);
#include "tabpopup.h"
#include "tile-preview.h"

940
src/ui/uiframe.c Normal file
View File

@ -0,0 +1,940 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity window frame manager widget */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2005, 2006 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include <math.h>
#include <string.h>
#include <meta/boxes.h>
#include "uiframe.h"
#include <meta/util.h>
#include "core.h"
#include "menu.h"
#include <meta/prefs.h>
#include "ui.h"
#ifdef HAVE_SHAPE
#include <X11/extensions/shape.h>
#endif
static MetaFrameControl get_control (MetaUIFrame *frame,
int x,
int y);
G_DEFINE_TYPE (MetaUIFrame, meta_uiframe, GTK_TYPE_WINDOW);
static void
initialize_style_context (MetaUIFrame *frame)
{
GtkWidget *widget;
GtkCssProvider *provider;
GdkScreen *screen;
char *theme_name, *variant;
if (G_LIKELY (frame->style_context_initialized))
return;
widget = GTK_WIDGET (frame);
screen = gtk_widget_get_screen (widget);
g_object_get (gtk_settings_get_for_screen (screen),
"gtk-theme-name", &theme_name,
NULL);
meta_core_get (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (frame))),
frame->xwindow,
META_CORE_GET_THEME_VARIANT, &variant,
META_CORE_GET_END);
provider = gtk_css_provider_get_named (theme_name, variant);
gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_THEME);
g_free (theme_name);
frame->style_context_initialized = TRUE;
}
static void
sync_state_flags (MetaUIFrame *frame)
{
MetaFrameFlags flags;
GtkStateFlags gtk_flags;
initialize_style_context (frame);
meta_core_get (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (frame))),
frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
gtk_flags = GTK_STATE_FLAG_NORMAL;
if ((flags & META_FRAME_HAS_FOCUS) == 0)
gtk_flags |= GTK_STATE_FLAG_BACKDROP;
gtk_widget_set_state_flags (GTK_WIDGET (frame), gtk_flags, TRUE);
}
void
meta_uiframe_get_frame_borders (MetaUIFrame *frame,
MetaFrameBorders *borders)
{
GtkWidget *widget = GTK_WIDGET (frame);
GtkBorder padding;
GtkStyleContext *style_context;
MetaFrameType type;
MetaFrameFlags flags;
int draggable_borders;
meta_core_get (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (frame))),
frame->xwindow,
META_CORE_GET_FRAME_TYPE, &type,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
/* For a full-screen window, we don't have any borders, visible or not. */
if (flags & META_FRAME_FULLSCREEN)
return;
sync_state_flags (frame);
meta_frame_borders_clear (borders);
style_context = gtk_widget_get_style_context (widget);
gtk_style_context_get_border (style_context,
gtk_widget_get_state_flags (widget),
&borders->visible);
gtk_style_context_get_padding (style_context,
gtk_widget_get_state_flags (widget),
&padding);
borders->visible.left += padding.left;
borders->visible.right += padding.right;
borders->visible.top += padding.top;
borders->visible.bottom += padding.bottom;
draggable_borders = meta_prefs_get_draggable_border_width ();
if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
{
borders->invisible.left = MAX (0, draggable_borders - borders->visible.left);
borders->invisible.right = MAX (0, draggable_borders - borders->visible.right);
}
if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
{
borders->invisible.bottom = MAX (0, draggable_borders - borders->visible.bottom);
/* borders.visible.top is the height of the *title bar*. We can't do the same
* algorithm here, titlebars are expectedly much bigger. Just subtract a couple
* pixels to get a proper feel. */
if (type != META_FRAME_TYPE_ATTACHED)
borders->invisible.top = MAX (0, draggable_borders - 2);
}
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 void
meta_uiframe_finalize (GObject *obj)
{
MetaUIFrame *frame = META_UIFRAME (obj);
if (frame->window)
g_object_unref (frame->window);
}
static void
meta_uiframe_init (MetaUIFrame *frame)
{
GtkWidget *container, *label;
frame->container = container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
frame->label = label = gtk_label_new ("");
frame->style_context_initialized = FALSE;
gtk_container_add (GTK_CONTAINER (frame), container);
gtk_container_add (GTK_CONTAINER (container), frame->label);
gtk_widget_set_hexpand (container, TRUE);
gtk_widget_set_hexpand (label, TRUE);
gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
gtk_widget_set_valign (label, GTK_ALIGN_START);
gtk_widget_show_all (GTK_WIDGET (container));
}
/* The client rectangle surrounds client window; it subtracts both
* the visible and invisible borders from the frame window's size.
*/
static void
get_client_rect (MetaFrameBorders *borders,
int window_width,
int window_height,
cairo_rectangle_int_t *rect)
{
rect->x = borders->total.left;
rect->y = borders->total.top;
rect->width = window_width - borders->total.right - rect->x;
rect->height = window_height - borders->total.bottom - rect->y;
}
void
meta_uiframe_set_title (MetaUIFrame *frame,
const char *title)
{
gtk_label_set_text (GTK_LABEL (frame->label), title);
}
static gboolean
meta_frame_titlebar_event (MetaUIFrame *frame,
GdkEventButton *event,
int action)
{
MetaFrameFlags flags;
Display *display;
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
switch (action)
{
case G_DESKTOP_TITLEBAR_ACTION_TOGGLE_SHADE:
{
meta_core_get (display, frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
if (flags & META_FRAME_ALLOWS_SHADE)
{
if (flags & META_FRAME_SHADED)
meta_core_unshade (display,
frame->xwindow,
event->time);
else
meta_core_shade (display,
frame->xwindow,
event->time);
}
}
break;
case G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE:
{
meta_core_get (display, frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
{
meta_core_toggle_maximize (display, frame->xwindow);
}
}
break;
case G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE_HORIZONTALLY:
{
meta_core_get (display, frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
{
meta_core_toggle_maximize_horizontally (display, frame->xwindow);
}
}
break;
case G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE_VERTICALLY:
{
meta_core_get (display, frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
{
meta_core_toggle_maximize_vertically (display, frame->xwindow);
}
}
break;
case G_DESKTOP_TITLEBAR_ACTION_MINIMIZE:
{
meta_core_get (display, frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
if (flags & META_FRAME_ALLOWS_MINIMIZE)
{
meta_core_minimize (display, frame->xwindow);
}
}
break;
case G_DESKTOP_TITLEBAR_ACTION_NONE:
/* Yaay, a sane user that doesn't use that other weird crap! */
break;
case G_DESKTOP_TITLEBAR_ACTION_LOWER:
meta_core_user_lower_and_unfocus (display,
frame->xwindow,
event->time);
break;
case G_DESKTOP_TITLEBAR_ACTION_MENU:
meta_core_show_window_menu (display,
frame->xwindow,
event->x_root,
event->y_root,
event->button,
event->time);
break;
}
return TRUE;
}
static gboolean
meta_frame_double_click_event (MetaUIFrame *frame,
GdkEventButton *event)
{
int action = meta_prefs_get_action_double_click_titlebar ();
return meta_frame_titlebar_event (frame, event, action);
}
static gboolean
meta_frame_middle_click_event (MetaUIFrame *frame,
GdkEventButton *event)
{
int action = meta_prefs_get_action_middle_click_titlebar();
return meta_frame_titlebar_event (frame, event, action);
}
static gboolean
meta_frame_right_click_event(MetaUIFrame *frame,
GdkEventButton *event)
{
int action = meta_prefs_get_action_right_click_titlebar();
return meta_frame_titlebar_event (frame, event, action);
}
static gboolean
meta_uiframe_button_press_event (GtkWidget *widget,
GdkEventButton *event)
{
MetaUIFrame *frame;
MetaFrameControl control;
Display *display;
frame = META_UIFRAME (widget);
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
/* Remember that the display may have already done something with this event.
* If so there's probably a GrabOp in effect.
*/
control = get_control (frame, event->x, event->y);
/* focus on click, even if click was on client area */
if (event->button == 1 &&
!(control == META_FRAME_CONTROL_MINIMIZE ||
control == META_FRAME_CONTROL_DELETE ||
control == META_FRAME_CONTROL_MAXIMIZE))
{
meta_topic (META_DEBUG_FOCUS,
"Focusing window with frame 0x%lx due to button 1 press\n",
frame->xwindow);
meta_core_user_focus (display,
frame->xwindow,
event->time);
}
/* don't do the rest of this if on client area */
if (control == META_FRAME_CONTROL_CLIENT_AREA)
return FALSE; /* not on the frame, just passed through from client */
/* We want to shade even if we have a GrabOp, since we'll have a move grab
* if we double click the titlebar.
*/
if (control == META_FRAME_CONTROL_TITLE &&
event->button == 1 &&
event->type == GDK_2BUTTON_PRESS)
{
meta_core_end_grab_op (display, event->time);
return meta_frame_double_click_event (frame, event);
}
if (meta_core_get_grab_op (display) !=
META_GRAB_OP_NONE)
return FALSE; /* already up to something */
if (event->button == 1 &&
(control == META_FRAME_CONTROL_MAXIMIZE ||
control == META_FRAME_CONTROL_UNMAXIMIZE ||
control == META_FRAME_CONTROL_MINIMIZE ||
control == META_FRAME_CONTROL_DELETE ||
control == META_FRAME_CONTROL_SHADE ||
control == META_FRAME_CONTROL_UNSHADE ||
control == META_FRAME_CONTROL_ABOVE ||
control == META_FRAME_CONTROL_UNABOVE ||
control == META_FRAME_CONTROL_STICK ||
control == META_FRAME_CONTROL_UNSTICK ||
control == META_FRAME_CONTROL_MENU))
{
MetaGrabOp op = META_GRAB_OP_NONE;
switch (control)
{
case META_FRAME_CONTROL_MINIMIZE:
op = META_GRAB_OP_CLICKING_MINIMIZE;
break;
case META_FRAME_CONTROL_MAXIMIZE:
op = META_GRAB_OP_CLICKING_MAXIMIZE;
break;
case META_FRAME_CONTROL_UNMAXIMIZE:
op = META_GRAB_OP_CLICKING_UNMAXIMIZE;
break;
case META_FRAME_CONTROL_DELETE:
op = META_GRAB_OP_CLICKING_DELETE;
break;
case META_FRAME_CONTROL_MENU:
op = META_GRAB_OP_CLICKING_MENU;
break;
case META_FRAME_CONTROL_SHADE:
op = META_GRAB_OP_CLICKING_SHADE;
break;
case META_FRAME_CONTROL_UNSHADE:
op = META_GRAB_OP_CLICKING_UNSHADE;
break;
case META_FRAME_CONTROL_ABOVE:
op = META_GRAB_OP_CLICKING_ABOVE;
break;
case META_FRAME_CONTROL_UNABOVE:
op = META_GRAB_OP_CLICKING_UNABOVE;
break;
case META_FRAME_CONTROL_STICK:
op = META_GRAB_OP_CLICKING_STICK;
break;
case META_FRAME_CONTROL_UNSTICK:
op = META_GRAB_OP_CLICKING_UNSTICK;
break;
default:
g_assert_not_reached ();
break;
}
meta_core_begin_grab_op (display,
frame->xwindow,
op,
TRUE,
TRUE,
event->button,
0,
event->time,
event->x_root,
event->y_root);
}
else if (event->button == 1 &&
(control == META_FRAME_CONTROL_RESIZE_SE ||
control == META_FRAME_CONTROL_RESIZE_S ||
control == META_FRAME_CONTROL_RESIZE_SW ||
control == META_FRAME_CONTROL_RESIZE_NE ||
control == META_FRAME_CONTROL_RESIZE_N ||
control == META_FRAME_CONTROL_RESIZE_NW ||
control == META_FRAME_CONTROL_RESIZE_E ||
control == META_FRAME_CONTROL_RESIZE_W))
{
MetaGrabOp op;
op = META_GRAB_OP_NONE;
switch (control)
{
case META_FRAME_CONTROL_RESIZE_SE:
op = META_GRAB_OP_RESIZING_SE;
break;
case META_FRAME_CONTROL_RESIZE_S:
op = META_GRAB_OP_RESIZING_S;
break;
case META_FRAME_CONTROL_RESIZE_SW:
op = META_GRAB_OP_RESIZING_SW;
break;
case META_FRAME_CONTROL_RESIZE_NE:
op = META_GRAB_OP_RESIZING_NE;
break;
case META_FRAME_CONTROL_RESIZE_N:
op = META_GRAB_OP_RESIZING_N;
break;
case META_FRAME_CONTROL_RESIZE_NW:
op = META_GRAB_OP_RESIZING_NW;
break;
case META_FRAME_CONTROL_RESIZE_E:
op = META_GRAB_OP_RESIZING_E;
break;
case META_FRAME_CONTROL_RESIZE_W:
op = META_GRAB_OP_RESIZING_W;
break;
default:
g_assert_not_reached ();
break;
}
meta_core_begin_grab_op (display,
frame->xwindow,
op,
TRUE,
TRUE,
event->button,
0,
event->time,
event->x_root,
event->y_root);
}
else if (control == META_FRAME_CONTROL_TITLE &&
event->button == 1)
{
MetaFrameFlags flags;
meta_core_get (display, frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_END);
if (flags & META_FRAME_ALLOWS_MOVE)
{
meta_core_begin_grab_op (display,
frame->xwindow,
META_GRAB_OP_MOVING,
TRUE,
TRUE,
event->button,
0,
event->time,
event->x_root,
event->y_root);
}
}
else if (event->button == 2)
{
return meta_frame_middle_click_event (frame, event);
}
else if (event->button == 3)
{
return meta_frame_right_click_event (frame, event);
}
return TRUE;
}
static gboolean
meta_uiframe_button_release_event (GtkWidget *widget,
GdkEventButton *event)
{
MetaUIFrame *frame;
MetaGrabOp op;
Display *display;
frame = META_UIFRAME (widget);
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
op = meta_core_get_grab_op (display);
if (op == META_GRAB_OP_NONE)
return FALSE;
/* We only handle the releases we handled the presses for (things
* involving frame controls). Window ops that don't require a
* frame are handled in the Xlib part of the code, display.c/window.c
*/
if (frame->xwindow == meta_core_get_grab_frame (display) &&
((int) event->button) == meta_core_get_grab_button (display))
{
MetaFrameControl control;
control = get_control (frame, event->x, event->y);
switch (op)
{
case META_GRAB_OP_CLICKING_MINIMIZE:
if (control == META_FRAME_CONTROL_MINIMIZE)
meta_core_minimize (display, frame->xwindow);
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_MAXIMIZE:
if (control == META_FRAME_CONTROL_MAXIMIZE)
{
/* Focus the window on the maximize */
meta_core_user_focus (display,
frame->xwindow,
event->time);
meta_core_maximize (display, frame->xwindow);
}
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_UNMAXIMIZE:
if (control == META_FRAME_CONTROL_UNMAXIMIZE)
meta_core_unmaximize (display, frame->xwindow);
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_DELETE:
if (control == META_FRAME_CONTROL_DELETE)
meta_core_delete (display, frame->xwindow, event->time);
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_MENU:
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_SHADE:
if (control == META_FRAME_CONTROL_SHADE)
meta_core_shade (display, frame->xwindow, event->time);
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_UNSHADE:
if (control == META_FRAME_CONTROL_UNSHADE)
meta_core_unshade (display, frame->xwindow, event->time);
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_ABOVE:
if (control == META_FRAME_CONTROL_ABOVE)
meta_core_make_above (display, frame->xwindow);
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_UNABOVE:
if (control == META_FRAME_CONTROL_UNABOVE)
meta_core_unmake_above (display, frame->xwindow);
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_STICK:
if (control == META_FRAME_CONTROL_STICK)
meta_core_stick (display, frame->xwindow);
meta_core_end_grab_op (display, event->time);
break;
case META_GRAB_OP_CLICKING_UNSTICK:
if (control == META_FRAME_CONTROL_UNSTICK)
meta_core_unstick (display, frame->xwindow);
meta_core_end_grab_op (display, event->time);
break;
default:
break;
}
}
return TRUE;
}
static void
clip_to_screen (cairo_region_t *region,
MetaUIFrame *frame)
{
cairo_rectangle_int_t frame_area;
cairo_rectangle_int_t screen_area = { 0, 0, 0, 0 };
cairo_region_t *tmp_region;
/* Chop off stuff outside the screen; this optimization
* is crucial to handle huge client windows,
* like "xterm -geometry 1000x1000"
*/
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
frame->xwindow,
META_CORE_GET_FRAME_X, &frame_area.x,
META_CORE_GET_FRAME_Y, &frame_area.y,
META_CORE_GET_FRAME_WIDTH, &frame_area.width,
META_CORE_GET_FRAME_HEIGHT, &frame_area.height,
META_CORE_GET_SCREEN_WIDTH, &screen_area.width,
META_CORE_GET_SCREEN_HEIGHT, &screen_area.height,
META_CORE_GET_END);
cairo_region_translate (region, frame_area.x, frame_area.y);
tmp_region = cairo_region_create_rectangle (&frame_area);
cairo_region_intersect (region, tmp_region);
cairo_region_destroy (tmp_region);
tmp_region = cairo_region_create_rectangle (&screen_area);
cairo_region_intersect (region, tmp_region);
cairo_region_destroy (tmp_region);
cairo_region_translate (region, - frame_area.x, - frame_area.y);
}
static void
subtract_client_area (cairo_region_t *region,
MetaUIFrame *frame)
{
cairo_rectangle_int_t area;
MetaFrameBorders borders;
cairo_region_t *tmp_region;
Display *display;
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
meta_core_get (display, frame->xwindow,
META_CORE_GET_CLIENT_WIDTH, &area.width,
META_CORE_GET_CLIENT_HEIGHT, &area.height,
META_CORE_GET_END);
meta_uiframe_get_frame_borders (frame, &borders);
area.x = borders.total.left;
area.y = borders.total.top;
tmp_region = cairo_region_create_rectangle (&area);
cairo_region_subtract (region, tmp_region);
cairo_region_destroy (tmp_region);
}
void
meta_uiframe_paint (MetaUIFrame *frame,
cairo_t *cr)
{
GtkWidget *widget = GTK_WIDGET (frame);
GtkStyleContext *style_gtk = gtk_widget_get_style_context (widget);
GdkRectangle visible_rect;
MetaFrameBorders borders;
meta_uiframe_get_frame_borders (frame, &borders);
gtk_widget_get_allocation (widget, &visible_rect);
visible_rect.x += borders.invisible.left;
visible_rect.y += borders.invisible.top;
visible_rect.width -= borders.invisible.left + borders.invisible.right;
visible_rect.height -= borders.invisible.top - borders.invisible.bottom;
sync_state_flags (frame);
gtk_render_background (style_gtk, cr,
visible_rect.x,
visible_rect.y,
visible_rect.width,
visible_rect.height);
gtk_render_frame (style_gtk, cr,
visible_rect.x,
visible_rect.y,
visible_rect.width,
visible_rect.height);
/* We chain up to paint the contents here so that the mask
* we paint with meta_frame_render_background can be accurate
* with children. */
GTK_WIDGET_CLASS (meta_uiframe_parent_class)->draw (widget, cr);
}
static gboolean
meta_uiframe_draw (GtkWidget *widget,
cairo_t *cr)
{
MetaUIFrame *frame;
cairo_region_t *region;
cairo_rectangle_int_t clip;
frame = META_UIFRAME (widget);
gdk_cairo_get_clip_rectangle (cr, &clip);
region = cairo_region_create_rectangle (&clip);
clip_to_screen (region, frame);
subtract_client_area (region, frame);
if (cairo_region_num_rectangles (region) == 0)
goto out;
gdk_cairo_region (cr, region);
cairo_clip (cr);
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba (cr, 1, 1, 1, 1);
cairo_paint (cr);
cairo_restore (cr);
meta_uiframe_paint (frame, cr);
out:
cairo_region_destroy (region);
return TRUE;
}
static void
meta_uiframe_style_updated (GtkWidget *widget)
{
MetaUIFrame *frame = META_UIFRAME (widget);
GtkWidget *container = frame->container;
MetaFrameBorders borders;
meta_uiframe_get_frame_borders (frame, &borders);
gtk_widget_set_margin_left (container, borders.total.left);
gtk_widget_set_margin_right (container, borders.total.right);
gtk_widget_set_margin_top (container, borders.invisible.top);
gtk_widget_set_size_request (container, -1, borders.visible.top);
}
static MetaFrameControl
get_control (MetaUIFrame *frame,
int x, int y)
{
MetaFrameBorders borders;
MetaFrameFlags flags;
MetaFrameType type;
gboolean has_vert, has_horiz;
gboolean has_north_resize;
cairo_rectangle_int_t client;
int width, height;
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
frame->xwindow,
META_CORE_GET_FRAME_FLAGS, &flags,
META_CORE_GET_CLIENT_WIDTH, &width,
META_CORE_GET_CLIENT_HEIGHT, &height,
META_CORE_GET_FRAME_TYPE, &type,
META_CORE_GET_END);
meta_uiframe_get_frame_borders (frame, &borders);
get_client_rect (&borders, width, height, &client);
if (POINT_IN_RECT (x, y, client))
return META_FRAME_CONTROL_CLIENT_AREA;
has_north_resize = (type != META_FRAME_TYPE_ATTACHED);
has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0;
has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0;
/* South resize always has priority over north resize,
* in case of overlap.
*/
if (y >= (height - borders.total.bottom) &&
x >= (width - borders.total.right))
{
if (has_vert && has_horiz)
return META_FRAME_CONTROL_RESIZE_SE;
else if (has_vert)
return META_FRAME_CONTROL_RESIZE_S;
else if (has_horiz)
return META_FRAME_CONTROL_RESIZE_E;
}
else if (y >= (height - borders.total.bottom) &&
x <= borders.total.left)
{
if (has_vert && has_horiz)
return META_FRAME_CONTROL_RESIZE_SW;
else if (has_vert)
return META_FRAME_CONTROL_RESIZE_S;
else if (has_horiz)
return META_FRAME_CONTROL_RESIZE_W;
}
else if (y < (borders.invisible.top) &&
x <= borders.total.left && has_north_resize)
{
if (has_vert && has_horiz)
return META_FRAME_CONTROL_RESIZE_NW;
else if (has_vert)
return META_FRAME_CONTROL_RESIZE_N;
else if (has_horiz)
return META_FRAME_CONTROL_RESIZE_W;
}
else if (y < (borders.invisible.top) &&
x >= width - borders.total.right && has_north_resize)
{
if (has_vert && has_horiz)
return META_FRAME_CONTROL_RESIZE_NE;
else if (has_vert)
return META_FRAME_CONTROL_RESIZE_N;
else if (has_horiz)
return META_FRAME_CONTROL_RESIZE_E;
}
else if (y < borders.invisible.top)
{
if (has_vert && has_north_resize)
return META_FRAME_CONTROL_RESIZE_N;
}
else if (y >= (height - borders.total.bottom))
{
if (has_vert)
return META_FRAME_CONTROL_RESIZE_S;
}
else if (x <= borders.total.left)
{
if (has_horiz)
return META_FRAME_CONTROL_RESIZE_W;
}
else if (x >= (width - borders.total.right))
{
if (has_horiz)
return META_FRAME_CONTROL_RESIZE_E;
}
if (y >= borders.total.top)
return META_FRAME_CONTROL_NONE;
else
return META_FRAME_CONTROL_TITLE;
}
static void
meta_uiframe_class_init (MetaUIFrameClass *class)
{
GObjectClass *gobject_class;
GtkWidgetClass *widget_class;
gobject_class = G_OBJECT_CLASS (class);
widget_class = GTK_WIDGET_CLASS (class);
gobject_class->finalize = meta_uiframe_finalize;
widget_class->draw = meta_uiframe_draw;
widget_class->style_updated = meta_uiframe_style_updated;
widget_class->button_press_event = meta_uiframe_button_press_event;
widget_class->button_release_event = meta_uiframe_button_release_event;
}

101
src/ui/uiframe.h Normal file
View File

@ -0,0 +1,101 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Metacity window frame manager widget */
/*
* Copyright (C) 2001 Havoc Pennington
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_UIFRAME_H
#define META_UIFRAME_H
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <meta/common.h>
typedef enum
{
META_FRAME_CONTROL_NONE,
META_FRAME_CONTROL_TITLE,
META_FRAME_CONTROL_DELETE,
META_FRAME_CONTROL_MENU,
META_FRAME_CONTROL_MINIMIZE,
META_FRAME_CONTROL_MAXIMIZE,
META_FRAME_CONTROL_UNMAXIMIZE,
META_FRAME_CONTROL_SHADE,
META_FRAME_CONTROL_UNSHADE,
META_FRAME_CONTROL_ABOVE,
META_FRAME_CONTROL_UNABOVE,
META_FRAME_CONTROL_STICK,
META_FRAME_CONTROL_UNSTICK,
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,
META_FRAME_CONTROL_CLIENT_AREA
} MetaFrameControl;
/* This is one widget that manages all the window frames
* as subwindows.
*/
#define META_TYPE_UIFRAME (meta_uiframe_get_type ())
#define META_UIFRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_UIFRAME, MetaUIFrame))
#define META_UIFRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_UIFRAME, MetaUIFrameClass))
#define META_IS_UIFRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_UIFRAME))
#define META_IS_UIFRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_UIFRAME))
#define META_UIFRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_UIFRAME, MetaUIFrameClass))
typedef struct _MetaUIFrame MetaUIFrame;
typedef struct _MetaUIFrameClass MetaUIFrameClass;
struct _MetaUIFrame
{
GtkWindow parent_instance;
Window xwindow;
GdkWindow *window;
MetaFrameControl prelit_control;
GtkWidget *label;
GtkWidget *container;
gboolean style_context_initialized;
};
struct _MetaUIFrameClass
{
GtkWindowClass parent_class;
};
GType meta_uiframe_get_type (void) G_GNUC_CONST;
void meta_uiframe_set_title (MetaUIFrame *frame,
const char *title);
void meta_uiframe_paint (MetaUIFrame *frame,
cairo_t *cr);
void meta_uiframe_get_frame_borders (MetaUIFrame *frame,
MetaFrameBorders *borders);
#endif