Added "above" to the list of flags a frame can have, so that we know when

* common.h: Added "above" to the list of flags a frame can have, so
	that we know when to mark it as always on top.  Added six grab ops,
	one to do and one to undo each of the three new titlebar buttons
	(shade, above, stick).  Added six new button functions, similarly.
	(#96229)

        * frame.c (meta_frame_get_flags): If a frame has the WM_STATE_ABOVE X
         attribute, set META_FRAME_ABOVE in its flags.

        * frames.c (meta_frames_apply_shapes): Allow variable amounts of
         rounding. (#113162)

        * frames.c (show_tip_now, meta_frames_paint_to_drawable, control_rect,
	 get_control): extend handling of existing buttons to the
         3*2 new kinds of button. (#96229)

        * frames.c (meta_frames_button_press_event): translate clicks on the 3*2
         new kinds of button to the new grab ops. (#96229)

        * frames.c (meta_frames_button_release_event): implement the various
        actions for the 3*2 new kinds of button. (#96229)

        * frames.c (meta_frames_update_prelit_control,
         meta_frames_motion_notify_event): extend existing motion
         notifications for buttons to the 3*2 new kinds of button. (#96229)

        * frames.c (meta_frames_set_window_background): handle specified
         background colours and alpha transparency. (#151261)

        * frames.h (MetaFrameControl): New control types for the 3*2 new kinds
	 of button.  (#96229)

        * iconcache.[ch] (meta_read_icons): use theme's fallback icons if a
	 window has no icon; use metacity's fallback icons only if the theme
         does not provide any. (#11363)

        * iconcache.[ch] (meta_invalidate_default_icons (new function)): clear
         icon cache on windows using default icons, and update them. (#11363)

        * main.c (main): added \n to error message.

        * prefs.c (button_function_from_string): extend for 3 new button
	 types. (#96229)

        * prefs.c (button_opposite_function (new function)): return a button
         function's inverse (shade -> unshade, etc) (#96229)

        * prefs.c (update_button_layout): allocate space for a button's
	 inverse, if it has one. (#96229)

        * theme-parser.c (ParseState): add state for fallback icons (#11363)

        * theme-parser.c (ParseInfo): add format_version; remove
         menu_icon_* (#114305)

        * theme-parser.c (parse_positive_integer): add lookup for integer
	 constants (#331356)

        * theme-parser.c (parse_rounding (new function)): parse window
	 rounding amount (#113162)

        * theme-parser.c (parse_alpha): don't set error if the number can't
	 be parsed since it'll already be set; change tolerance in comparison
	 from 1e6 to 1e-6

        * theme-parser.c (parse_color (new function)): parse colour, including
	 possible constant lookup.

        * theme-parser.c (parse_toplevel_element): allow defining of various
	new kinds of constant; allow
	hide_buttons (#121639) and more detailed rounding attributes on
	<frame_geometry> (#113162); allow background and alpha attributes on
	<frame_style>; (#151261) remove support for <menu_icon> except as
	stub; (#114305) add support for loading stock images (#113465); add
        support for <fallback>. (#11363))

        * theme-parser.c (parse_draw_op_element): add from and to attribute
         for arcs. (#121603)

        * theme-parser.c (parse_style_element): add check for theme version
         supporting a button function. (#96229)

        * theme-parser.c (parse_style_set_element): add ability for shaded
	 windows to be resizable (#114304)

        * theme-parser.c (meta_theme_load): add theme versioning routine.

        * theme.c ( meta_frame_layout_get_borders): return rectangles for
	 the new 3*2 kinds of button, except where they're
         inapplicable. (#96229)

        * theme.c (meta_frame_layout_calc_geometry): don't format buttons on
	windows with no buttons (#121639); strip the 3*2 new kinds of button
	correctly (#96229); allow variable amounts of rounding (#113162).

        * theme.c (meta_frame_style_new): set alpha to 255 by
        default. (#151261)

        * theme.c (meta_frame_style_unref): free colour spec if
        allocated. (#151261)

        * theme.c (meta_frame_style_validate): it's only an error not to
        include a button if that button is valid in the current
        theme. (#96229)

        * theme.c (button_rect): return rectangles for the new 3*2 kinds
	of button. (#96229)

        * theme.c (meta_frame_style_set_unref): free differently resizable
	shaded styles. (#114304)

        * theme.c (get_style): look up differently resizable styles
        for shaded windows. (#114304)

        * theme.c (free_menu_ops (removed function), get_menu_icon
	 (removed function), meta_theme_draw_menu_icon (removed function),
         meta_menu_icon_type_from_string (removed function),
         meta_menu_icon_type_to_string (removed function),
         meta_theme_free, meta_theme_validate): removed menu icon code. (#114305)

        * theme.c (meta_theme_load_image): add size_of_theme_icons
	parameter. (#113465)

        * theme.c (meta_theme_define_color_constant (new function),
        meta_theme_lookup_color_constant (new function)): allow
        definition of colour constants. (#129747)

        * theme.c (meta_button_type_from_string, meta_button_type_to_string):
        add the 3*2 new kinds of button. (#96229)

        * theme.c (meta_theme_earliest_version_with_button (new function)):
        return the theme version each button was introduced in. (#96229)

        * theme.h ( MetaFrameLayout): add "hide_buttons" flag (#121639) and
	corner radiuses. (#113162)

        * theme.h (MetaFrameGeometry): add rectangles for the 3*2 new
	buttons. (#96229)

        * theme.h (MetaButtonType): the 3*2 new buttons. (#96229)

        * theme.h (MetaFrameStyle): add window_background_color and
        window_background_alpha so that we can specify background on a
        <frame_style>. (#151261)

        * theme.h (MetaFrameStyleSet): shaded_styles gets resize
	dimension. (#114304)

        * theme.h (MetaTheme): added format_version, color_constants
        hash, (#129747) fallback_icon and fallback_mini_icon, (#11363)
        and removed menu_icons. (#114305)

        * theme.h (META_THEME_ALLOWS (new macro)): return whether a theme
        supports a given feature. Also, several macros representing
        new features in v2.

        * ui.c (meta_ui_set_current_theme)): also invalidate default
        icons. (#11363)

        * window.[ch] (meta_window_update_icon_now)): became
	non-static. (#11363)
This commit is contained in:
Thomas James Alexander Thurman 2006-10-07 16:56:47 +00:00
parent 9e341dd4d8
commit 90359a5346
17 changed files with 1470 additions and 523 deletions

164
ChangeLog
View File

@ -1,3 +1,167 @@
2006-10-07 Thomas Thurman <thomas@thurman.org.uk>
* common.h: Added "above" to the list of flags a frame can have, so
that we know when to mark it as always on top. Added six grab ops,
one to do and one to undo each of the three new titlebar buttons
(shade, above, stick). Added six new button functions, similarly.
(#96229)
* frame.c (meta_frame_get_flags): If a frame has the WM_STATE_ABOVE X
attribute, set META_FRAME_ABOVE in its flags.
* frames.c (meta_frames_apply_shapes): Allow variable amounts of
rounding. (#113162)
* frames.c (show_tip_now, meta_frames_paint_to_drawable, control_rect,
get_control): extend handling of existing buttons to the
3*2 new kinds of button. (#96229)
* frames.c (meta_frames_button_press_event): translate clicks on the 3*2
new kinds of button to the new grab ops. (#96229)
* frames.c (meta_frames_button_release_event): implement the various
actions for the 3*2 new kinds of button. (#96229)
* frames.c (meta_frames_update_prelit_control,
meta_frames_motion_notify_event): extend existing motion
notifications for buttons to the 3*2 new kinds of button. (#96229)
* frames.c (meta_frames_set_window_background): handle specified
background colours and alpha transparency. (#151261)
* frames.h (MetaFrameControl): New control types for the 3*2 new kinds
of button. (#96229)
* iconcache.[ch] (meta_read_icons): use theme's fallback icons if a
window has no icon; use metacity's fallback icons only if the theme
does not provide any. (#11363)
* iconcache.[ch] (meta_invalidate_default_icons (new function)): clear
icon cache on windows using default icons, and update them. (#11363)
* main.c (main): added \n to error message.
* prefs.c (button_function_from_string): extend for 3 new button
types. (#96229)
* prefs.c (button_opposite_function (new function)): return a button
function's inverse (shade -> unshade, etc) (#96229)
* prefs.c (update_button_layout): allocate space for a button's
inverse, if it has one. (#96229)
* theme-parser.c (ParseState): add state for fallback icons (#11363)
* theme-parser.c (ParseInfo): add format_version; remove
menu_icon_* (#114305)
* theme-parser.c (parse_positive_integer): add lookup for integer
constants (#331356)
* theme-parser.c (parse_rounding (new function)): parse window
rounding amount (#113162)
* theme-parser.c (parse_alpha): don't set error if the number can't
be parsed since it'll already be set; change tolerance in comparison
from 1e6 to 1e-6
* theme-parser.c (parse_color (new function)): parse colour, including
possible constant lookup.
* theme-parser.c (parse_toplevel_element): allow defining of various
new kinds of constant; allow
hide_buttons (#121639) and more detailed rounding attributes on
<frame_geometry> (#113162); allow background and alpha attributes on
<frame_style>; (#151261) remove support for <menu_icon> except as
stub; (#114305) add support for loading stock images (#113465); add
support for <fallback>. (#11363))
* theme-parser.c (parse_draw_op_element): add from and to attribute
for arcs. (#121603)
* theme-parser.c (parse_style_element): add check for theme version
supporting a button function. (#96229)
* theme-parser.c (parse_style_set_element): add ability for shaded
windows to be resizable (#114304)
* theme-parser.c (meta_theme_load): add theme versioning routine.
* theme.c ( meta_frame_layout_get_borders): return rectangles for
the new 3*2 kinds of button, except where they're
inapplicable. (#96229)
* theme.c (meta_frame_layout_calc_geometry): don't format buttons on
windows with no buttons (#121639); strip the 3*2 new kinds of button
correctly (#96229); allow variable amounts of rounding (#113162).
* theme.c (meta_frame_style_new): set alpha to 255 by
default. (#151261)
* theme.c (meta_frame_style_unref): free colour spec if
allocated. (#151261)
* theme.c (meta_frame_style_validate): it's only an error not to
include a button if that button is valid in the current
theme. (#96229)
* theme.c (button_rect): return rectangles for the new 3*2 kinds
of button. (#96229)
* theme.c (meta_frame_style_set_unref): free differently resizable
shaded styles. (#114304)
* theme.c (get_style): look up differently resizable styles
for shaded windows. (#114304)
* theme.c (free_menu_ops (removed function), get_menu_icon
(removed function), meta_theme_draw_menu_icon (removed function),
meta_menu_icon_type_from_string (removed function),
meta_menu_icon_type_to_string (removed function),
meta_theme_free, meta_theme_validate): removed menu icon code. (#114305)
* theme.c (meta_theme_load_image): add size_of_theme_icons
parameter. (#113465)
* theme.c (meta_theme_define_color_constant (new function),
meta_theme_lookup_color_constant (new function)): allow
definition of colour constants. (#129747)
* theme.c (meta_button_type_from_string, meta_button_type_to_string):
add the 3*2 new kinds of button. (#96229)
* theme.c (meta_theme_earliest_version_with_button (new function)):
return the theme version each button was introduced in. (#96229)
* theme.h ( MetaFrameLayout): add "hide_buttons" flag (#121639) and
corner radiuses. (#113162)
* theme.h (MetaFrameGeometry): add rectangles for the 3*2 new
buttons. (#96229)
* theme.h (MetaButtonType): the 3*2 new buttons. (#96229)
* theme.h (MetaFrameStyle): add window_background_color and
window_background_alpha so that we can specify background on a
<frame_style>. (#151261)
* theme.h (MetaFrameStyleSet): shaded_styles gets resize
dimension. (#114304)
* theme.h (MetaTheme): added format_version, color_constants
hash, (#129747) fallback_icon and fallback_mini_icon, (#11363)
and removed menu_icons. (#114305)
* theme.h (META_THEME_ALLOWS (new macro)): return whether a theme
supports a given feature. Also, several macros representing
new features in v2.
* ui.c (meta_ui_set_current_theme)): also invalidate default
icons. (#11363)
* window.[ch] (meta_window_update_icon_now)): became
non-static. (#11363)
2006-10-06 Elijah Newren <newren gmail com> 2006-10-06 Elijah Newren <newren gmail com>
* src/metacity-dialog.c (kill_window_question): Be nice to * src/metacity-dialog.c (kill_window_question): Be nice to

View File

@ -46,7 +46,8 @@ typedef enum
META_FRAME_ALLOWS_SHADE = 1 << 10, META_FRAME_ALLOWS_SHADE = 1 << 10,
META_FRAME_ALLOWS_MOVE = 1 << 11, META_FRAME_ALLOWS_MOVE = 1 << 11,
META_FRAME_FULLSCREEN = 1 << 12, META_FRAME_FULLSCREEN = 1 << 12,
META_FRAME_IS_FLASHING = 1 << 13 META_FRAME_IS_FLASHING = 1 << 13,
META_FRAME_ABOVE = 1 << 14
} MetaFrameFlags; } MetaFrameFlags;
typedef enum typedef enum
@ -131,7 +132,13 @@ typedef enum
META_GRAB_OP_CLICKING_MAXIMIZE, META_GRAB_OP_CLICKING_MAXIMIZE,
META_GRAB_OP_CLICKING_UNMAXIMIZE, META_GRAB_OP_CLICKING_UNMAXIMIZE,
META_GRAB_OP_CLICKING_DELETE, META_GRAB_OP_CLICKING_DELETE,
META_GRAB_OP_CLICKING_MENU META_GRAB_OP_CLICKING_MENU,
META_GRAB_OP_CLICKING_SHADE,
META_GRAB_OP_CLICKING_UNSHADE,
META_GRAB_OP_CLICKING_ABOVE,
META_GRAB_OP_CLICKING_UNABOVE,
META_GRAB_OP_CLICKING_STICK,
META_GRAB_OP_CLICKING_UNSTICK
} MetaGrabOp; } MetaGrabOp;
typedef enum typedef enum
@ -226,6 +233,12 @@ typedef enum
META_BUTTON_FUNCTION_MINIMIZE, META_BUTTON_FUNCTION_MINIMIZE,
META_BUTTON_FUNCTION_MAXIMIZE, META_BUTTON_FUNCTION_MAXIMIZE,
META_BUTTON_FUNCTION_CLOSE, META_BUTTON_FUNCTION_CLOSE,
META_BUTTON_FUNCTION_SHADE,
META_BUTTON_FUNCTION_ABOVE,
META_BUTTON_FUNCTION_STICK,
META_BUTTON_FUNCTION_UNSHADE,
META_BUTTON_FUNCTION_UNABOVE,
META_BUTTON_FUNCTION_UNSTICK,
META_BUTTON_FUNCTION_LAST META_BUTTON_FUNCTION_LAST
} MetaButtonFunction; } MetaButtonFunction;

View File

@ -29,6 +29,17 @@
#include "workspace.h" #include "workspace.h"
#include "prefs.h" #include "prefs.h"
/* Looks up the MetaWindow representing the frame of the given X window.
* Used as a helper function by a bunch of the functions below.
*
* FIXME: The functions that use this function throw the result away
* after use. Many of these functions tend to be called in small groups,
* which results in get_window() getting called several times in succession
* with the same parameters. We should profile to see whether this wastes
* much time, and if it does we should look into a generalised
* meta_core_get_window_info() which takes a bunch of pointers to variables
* to put its results in, and only fills in the non-null ones.
*/
static MetaWindow * static MetaWindow *
get_window (Display *xdisplay, get_window (Display *xdisplay,
Window frame_xwindow) Window frame_xwindow)
@ -62,6 +73,19 @@ meta_core_get_client_size (Display *xdisplay,
*height = window->rect.height; *height = window->rect.height;
} }
gboolean
meta_core_window_has_frame (Display *xdisplay,
Window frame_xwindow)
{
MetaDisplay *display;
MetaWindow *window;
display = meta_display_for_x_display (xdisplay);
window = meta_display_lookup_x_window (display, frame_xwindow);
return window != NULL && window->frame != NULL;
}
gboolean gboolean
meta_core_titlebar_is_onscreen (Display *xdisplay, meta_core_titlebar_is_onscreen (Display *xdisplay,
Window frame_xwindow) Window frame_xwindow)
@ -368,6 +392,24 @@ meta_core_unstick (Display *xdisplay,
meta_window_unstick (window); meta_window_unstick (window);
} }
void
meta_core_make_above (Display *xdisplay,
Window frame_xwindow)
{
MetaWindow *window = get_window (xdisplay, frame_xwindow);
meta_window_make_above (window);
}
void
meta_core_unmake_above (Display *xdisplay,
Window frame_xwindow)
{
MetaWindow *window = get_window (xdisplay, frame_xwindow);
meta_window_unmake_above (window);
}
void void
meta_core_stick (Display *xdisplay, meta_core_stick (Display *xdisplay,
Window frame_xwindow) Window frame_xwindow)
@ -712,3 +754,31 @@ meta_core_increment_event_serial (Display *xdisplay)
meta_display_increment_event_serial (display); meta_display_increment_event_serial (display);
} }
void
meta_invalidate_default_icons (void)
{
GSList *displays, *windows;
for (displays = meta_displays_list ();
displays != NULL;
displays = displays->next)
{
for (windows = meta_display_list_windows (displays->data);
windows != NULL;
windows = windows->next)
{
MetaWindow *window = (MetaWindow*)windows->data;
if (window->icon_cache.origin == USING_FALLBACK_ICON)
{
meta_icon_cache_free (&(window->icon_cache));
meta_window_update_icon_now (window);
}
}
g_slist_free (windows);
}
}

View File

@ -37,6 +37,10 @@ void meta_core_get_client_size (Display *xdisplay,
gboolean meta_core_titlebar_is_onscreen (Display *xdisplay, gboolean meta_core_titlebar_is_onscreen (Display *xdisplay,
Window frame_xwindow); Window frame_xwindow);
gboolean meta_core_window_has_frame (Display *xdisplay,
Window frame_xwindow);
Window meta_core_get_client_xwindow (Display *xdisplay, Window meta_core_get_client_xwindow (Display *xdisplay,
Window frame_xwindow); Window frame_xwindow);
@ -106,6 +110,10 @@ void meta_core_unstick (Display *xdisplay,
Window frame_xwindow); Window frame_xwindow);
void meta_core_stick (Display *xdisplay, void meta_core_stick (Display *xdisplay,
Window frame_xwindow); Window frame_xwindow);
void meta_core_unmake_above (Display *xdisplay,
Window frame_xwindow);
void meta_core_make_above (Display *xdisplay,
Window frame_xwindow);
void meta_core_change_workspace (Display *xdisplay, void meta_core_change_workspace (Display *xdisplay,
Window frame_xwindow, Window frame_xwindow,
int new_workspace); int new_workspace);
@ -175,6 +183,8 @@ void meta_core_increment_event_serial (Display *display);
int meta_ui_get_last_event_serial (Display *xdisplay); int meta_ui_get_last_event_serial (Display *xdisplay);
void meta_invalidate_default_icons (void);
#endif #endif

View File

@ -279,6 +279,9 @@ meta_frame_get_flags (MetaFrame *frame)
if (frame->is_flashing) if (frame->is_flashing)
flags |= META_FRAME_IS_FLASHING; flags |= META_FRAME_IS_FLASHING;
if (frame->window->wm_state_above)
flags |= META_FRAME_ABOVE;
return flags; return flags;
} }

View File

@ -24,6 +24,7 @@
*/ */
#include <config.h> #include <config.h>
#include <math.h>
#include "boxes.h" #include "boxes.h"
#include "frames.h" #include "frames.h"
#include "util.h" #include "util.h"
@ -757,10 +758,10 @@ meta_frames_apply_shapes (MetaFrames *frames,
meta_frames_calc_geometry (frames, frame, &fgeom); meta_frames_calc_geometry (frames, frame, &fgeom);
if (!(fgeom.top_left_corner_rounded || if (!(fgeom.top_left_corner_rounded_radius != 0 ||
fgeom.top_right_corner_rounded || fgeom.top_right_corner_rounded_radius != 0 ||
fgeom.bottom_left_corner_rounded || fgeom.bottom_left_corner_rounded_radius != 0 ||
fgeom.bottom_right_corner_rounded || fgeom.bottom_right_corner_rounded_radius != 0 ||
window_has_shape)) window_has_shape))
{ {
if (frame->shape_applied) if (frame->shape_applied)
@ -785,102 +786,72 @@ meta_frames_apply_shapes (MetaFrames *frames,
corners_xregion = XCreateRegion (); corners_xregion = XCreateRegion ();
if (fgeom.top_left_corner_rounded) if (fgeom.top_left_corner_rounded_radius != 0)
{ {
const int radius = fgeom.top_left_corner_rounded_radius;
int i;
for (i=0; i<radius; i++)
{
const int width = 1 + (radius - floor(sqrt(radius*radius - (radius-i)*(radius-i))));
xrect.x = 0; xrect.x = 0;
xrect.y = 0; xrect.y = i;
xrect.width = 5; xrect.width = width;
xrect.height = 1; xrect.height = 1;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion); XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
}
xrect.y = 1;
xrect.width = 3;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
xrect.y = 2;
xrect.width = 2;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
xrect.y = 3;
xrect.width = 1;
xrect.height = 2;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
} }
if (fgeom.top_right_corner_rounded) if (fgeom.top_right_corner_rounded_radius != 0)
{ {
xrect.x = new_window_width - 5; const int radius = fgeom.top_right_corner_rounded_radius;
xrect.y = 0; int i;
xrect.width = 5;
for (i=0; i<radius; i++)
{
const int width = 1 + (radius - floor(sqrt(radius*radius - (radius-i)*(radius-i))));
xrect.x = new_window_width - width;
xrect.y = i;
xrect.width = width;
xrect.height = 1; xrect.height = 1;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion); XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
}
xrect.y = 1;
xrect.x = new_window_width - 3;
xrect.width = 3;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
xrect.y = 2;
xrect.x = new_window_width - 2;
xrect.width = 2;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
xrect.y = 3;
xrect.x = new_window_width - 1;
xrect.width = 1;
xrect.height = 2;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
} }
if (fgeom.bottom_left_corner_rounded) if (fgeom.bottom_left_corner_rounded_radius != 0)
{ {
const int radius = fgeom.bottom_left_corner_rounded_radius;
int i;
for (i=0; i<radius; i++)
{
const int width = 1 + (radius - floor(sqrt(radius*radius - (radius-i)*(radius-i))));
xrect.x = 0; xrect.x = 0;
xrect.y = new_window_height - 1; xrect.y = new_window_height - i;
xrect.width = 5; xrect.width = width;
xrect.height = 1; xrect.height = 1;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion); XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
}
xrect.y = new_window_height - 2;
xrect.width = 3;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
xrect.y = new_window_height - 3;
xrect.width = 2;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
xrect.y = new_window_height - 5;
xrect.width = 1;
xrect.height = 2;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
} }
if (fgeom.bottom_right_corner_rounded) if (fgeom.bottom_right_corner_rounded_radius != 0)
{ {
xrect.x = new_window_width - 5; const int radius = fgeom.bottom_right_corner_rounded_radius;
xrect.y = new_window_height - 1; int i;
xrect.width = 5;
for (i=0; i<radius; i++)
{
const int width = 1 + (radius - floor(sqrt(radius*radius - (radius-i)*(radius-i))));
xrect.x = new_window_width - width;
xrect.y = new_window_height - i;
xrect.width = width;
xrect.height = 1; xrect.height = 1;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion); XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
}
xrect.y = new_window_height - 2;
xrect.x = new_window_width - 3;
xrect.width = 3;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
xrect.y = new_window_height - 3;
xrect.x = new_window_width - 2;
xrect.width = 2;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
xrect.y = new_window_height - 5;
xrect.x = new_window_width - 1;
xrect.width = 1;
xrect.height = 2;
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
} }
window_xregion = XCreateRegion (); window_xregion = XCreateRegion ();
@ -1102,6 +1073,24 @@ show_tip_now (MetaFrames *frames)
case META_FRAME_CONTROL_UNMAXIMIZE: case META_FRAME_CONTROL_UNMAXIMIZE:
tiptext = _("Unmaximize Window"); tiptext = _("Unmaximize Window");
break; break;
case META_FRAME_CONTROL_SHADE:
tiptext = _("Roll Up Window");
break;
case META_FRAME_CONTROL_UNSHADE:
tiptext = _("Unroll Window");
break;
case META_FRAME_CONTROL_ABOVE:
tiptext = _("Keep Window On Top");
break;
case META_FRAME_CONTROL_UNABOVE:
tiptext = _("Remove Window From Top");
break;
case META_FRAME_CONTROL_STICK:
tiptext = _("Always On Visible Workspace");
break;
case META_FRAME_CONTROL_UNSTICK:
tiptext = _("Put Window On Only One Workspace");
break;
case META_FRAME_CONTROL_RESIZE_SE: case META_FRAME_CONTROL_RESIZE_SE:
break; break;
case META_FRAME_CONTROL_RESIZE_S: case META_FRAME_CONTROL_RESIZE_S:
@ -1308,6 +1297,12 @@ meta_frames_button_press_event (GtkWidget *widget,
control == META_FRAME_CONTROL_UNMAXIMIZE || control == META_FRAME_CONTROL_UNMAXIMIZE ||
control == META_FRAME_CONTROL_MINIMIZE || control == META_FRAME_CONTROL_MINIMIZE ||
control == META_FRAME_CONTROL_DELETE || 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)) control == META_FRAME_CONTROL_MENU))
{ {
MetaGrabOp op = META_GRAB_OP_NONE; MetaGrabOp op = META_GRAB_OP_NONE;
@ -1329,6 +1324,24 @@ meta_frames_button_press_event (GtkWidget *widget,
case META_FRAME_CONTROL_MENU: case META_FRAME_CONTROL_MENU:
op = META_GRAB_OP_CLICKING_MENU; op = META_GRAB_OP_CLICKING_MENU;
break; 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: default:
g_assert_not_reached (); g_assert_not_reached ();
break; break;
@ -1567,6 +1580,48 @@ meta_frames_button_release_event (GtkWidget *widget,
meta_core_end_grab_op (gdk_display, event->time); meta_core_end_grab_op (gdk_display, event->time);
break; break;
case META_GRAB_OP_CLICKING_SHADE:
if (control == META_FRAME_CONTROL_SHADE)
meta_core_shade (gdk_display, frame->xwindow, event->time);
meta_core_end_grab_op (gdk_display, event->time);
break;
case META_GRAB_OP_CLICKING_UNSHADE:
if (control == META_FRAME_CONTROL_UNSHADE)
meta_core_unshade (gdk_display, frame->xwindow, event->time);
meta_core_end_grab_op (gdk_display, event->time);
break;
case META_GRAB_OP_CLICKING_ABOVE:
if (control == META_FRAME_CONTROL_ABOVE)
meta_core_make_above (gdk_display, frame->xwindow);
meta_core_end_grab_op (gdk_display, event->time);
break;
case META_GRAB_OP_CLICKING_UNABOVE:
if (control == META_FRAME_CONTROL_UNABOVE)
meta_core_unmake_above (gdk_display, frame->xwindow);
meta_core_end_grab_op (gdk_display, event->time);
break;
case META_GRAB_OP_CLICKING_STICK:
if (control == META_FRAME_CONTROL_STICK)
meta_core_stick (gdk_display, frame->xwindow);
meta_core_end_grab_op (gdk_display, event->time);
break;
case META_GRAB_OP_CLICKING_UNSTICK:
if (control == META_FRAME_CONTROL_UNSTICK)
meta_core_unstick (gdk_display, frame->xwindow);
meta_core_end_grab_op (gdk_display, event->time);
break;
default: default:
break; break;
} }
@ -1590,6 +1645,7 @@ meta_frames_update_prelit_control (MetaFrames *frames,
MetaFrameControl old_control; MetaFrameControl old_control;
MetaCursor cursor; MetaCursor cursor;
meta_verbose ("Updating prelit control from %u to %u\n", meta_verbose ("Updating prelit control from %u to %u\n",
frame->prelit_control, control); frame->prelit_control, control);
@ -1613,6 +1669,18 @@ meta_frames_update_prelit_control (MetaFrames *frames,
break; break;
case META_FRAME_CONTROL_UNMAXIMIZE: case META_FRAME_CONTROL_UNMAXIMIZE:
break; break;
case META_FRAME_CONTROL_SHADE:
break;
case META_FRAME_CONTROL_UNSHADE:
break;
case META_FRAME_CONTROL_ABOVE:
break;
case META_FRAME_CONTROL_UNABOVE:
break;
case META_FRAME_CONTROL_STICK:
break;
case META_FRAME_CONTROL_UNSTICK:
break;
case META_FRAME_CONTROL_RESIZE_SE: case META_FRAME_CONTROL_RESIZE_SE:
cursor = META_CURSOR_SE_RESIZE; cursor = META_CURSOR_SE_RESIZE;
break; break;
@ -1650,6 +1718,12 @@ meta_frames_update_prelit_control (MetaFrames *frames,
case META_FRAME_CONTROL_MINIMIZE: case META_FRAME_CONTROL_MINIMIZE:
case META_FRAME_CONTROL_MAXIMIZE: case META_FRAME_CONTROL_MAXIMIZE:
case META_FRAME_CONTROL_DELETE: case META_FRAME_CONTROL_DELETE:
case META_FRAME_CONTROL_SHADE:
case META_FRAME_CONTROL_UNSHADE:
case META_FRAME_CONTROL_ABOVE:
case META_FRAME_CONTROL_UNABOVE:
case META_FRAME_CONTROL_STICK:
case META_FRAME_CONTROL_UNSTICK:
case META_FRAME_CONTROL_UNMAXIMIZE: case META_FRAME_CONTROL_UNMAXIMIZE:
/* leave control set */ /* leave control set */
break; break;
@ -1698,6 +1772,12 @@ meta_frames_motion_notify_event (GtkWidget *widget,
case META_GRAB_OP_CLICKING_MINIMIZE: case META_GRAB_OP_CLICKING_MINIMIZE:
case META_GRAB_OP_CLICKING_MAXIMIZE: case META_GRAB_OP_CLICKING_MAXIMIZE:
case META_GRAB_OP_CLICKING_UNMAXIMIZE: case META_GRAB_OP_CLICKING_UNMAXIMIZE:
case META_GRAB_OP_CLICKING_SHADE:
case META_GRAB_OP_CLICKING_UNSHADE:
case META_GRAB_OP_CLICKING_ABOVE:
case META_GRAB_OP_CLICKING_UNABOVE:
case META_GRAB_OP_CLICKING_STICK:
case META_GRAB_OP_CLICKING_UNSTICK:
{ {
MetaFrameControl control; MetaFrameControl control;
int x, y; int x, y;
@ -1716,7 +1796,19 @@ meta_frames_motion_notify_event (GtkWidget *widget,
grab_op == META_GRAB_OP_CLICKING_MINIMIZE) || grab_op == META_GRAB_OP_CLICKING_MINIMIZE) ||
(control == META_FRAME_CONTROL_MAXIMIZE && (control == META_FRAME_CONTROL_MAXIMIZE &&
(grab_op == META_GRAB_OP_CLICKING_MAXIMIZE || (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE ||
grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)))) grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)) ||
(control == META_FRAME_CONTROL_SHADE &&
grab_op == META_GRAB_OP_CLICKING_SHADE) ||
(control == META_FRAME_CONTROL_UNSHADE &&
grab_op == META_GRAB_OP_CLICKING_UNSHADE) ||
(control == META_FRAME_CONTROL_ABOVE &&
grab_op == META_GRAB_OP_CLICKING_ABOVE) ||
(control == META_FRAME_CONTROL_UNABOVE &&
grab_op == META_GRAB_OP_CLICKING_UNABOVE) ||
(control == META_FRAME_CONTROL_STICK &&
grab_op == META_GRAB_OP_CLICKING_STICK) ||
(control == META_FRAME_CONTROL_UNSTICK &&
grab_op == META_GRAB_OP_CLICKING_UNSTICK)))
control = META_FRAME_CONTROL_NONE; control = META_FRAME_CONTROL_NONE;
/* Update prelit control and cursor */ /* Update prelit control and cursor */
@ -2097,6 +2189,42 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
else else
button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT; button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
break; break;
case META_FRAME_CONTROL_SHADE:
if (grab_op == META_GRAB_OP_CLICKING_SHADE)
button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED;
else
button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT;
break;
case META_FRAME_CONTROL_UNSHADE:
if (grab_op == META_GRAB_OP_CLICKING_UNSHADE)
button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED;
else
button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT;
break;
case META_FRAME_CONTROL_ABOVE:
if (grab_op == META_GRAB_OP_CLICKING_ABOVE)
button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED;
else
button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT;
break;
case META_FRAME_CONTROL_UNABOVE:
if (grab_op == META_GRAB_OP_CLICKING_UNABOVE)
button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED;
else
button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT;
break;
case META_FRAME_CONTROL_STICK:
if (grab_op == META_GRAB_OP_CLICKING_STICK)
button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED;
else
button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT;
break;
case META_FRAME_CONTROL_UNSTICK:
if (grab_op == META_GRAB_OP_CLICKING_UNSTICK)
button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED;
else
button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT;
break;
case META_FRAME_CONTROL_DELETE: case META_FRAME_CONTROL_DELETE:
if (grab_op == META_GRAB_OP_CLICKING_DELETE) if (grab_op == META_GRAB_OP_CLICKING_DELETE)
button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED; button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED;
@ -2182,17 +2310,52 @@ static void
meta_frames_set_window_background (MetaFrames *frames, meta_frames_set_window_background (MetaFrames *frames,
MetaUIFrame *frame) MetaUIFrame *frame)
{ {
MetaFrameFlags flags;
MetaFrameType type;
MetaFrameStyle *style;
gboolean frame_exists;
frame_exists = meta_core_window_has_frame (gdk_display, frame->xwindow);
if (frame_exists)
{
flags = meta_core_get_frame_flags (gdk_display, frame->xwindow);
type = meta_core_get_frame_type (gdk_display, frame->xwindow);
style = meta_theme_get_frame_style (meta_theme_get_current (),
type, flags);
}
if (frame_exists && style->window_background_color != NULL)
{
GdkColor color;
GdkVisual *visual;
meta_color_spec_render (style->window_background_color,
GTK_WIDGET (frames),
&color);
/* Fill in color.pixel */
gdk_rgb_find_color (gtk_widget_get_colormap (GTK_WIDGET (frames)),
&color);
/* Set A in ARGB to window_background_alpha, if we have ARGB */
visual = gtk_widget_get_visual (GTK_WIDGET (frames));
if (visual->depth == 32) /* we have ARGB */
{
color.pixel = (color.pixel & 0xffffff) &
style->window_background_alpha << 24;
}
gdk_window_set_background (frame->window, &color);
}
else
{
gtk_style_set_background (GTK_WIDGET (frames)->style, gtk_style_set_background (GTK_WIDGET (frames)->style,
frame->window, GTK_STATE_NORMAL); frame->window, GTK_STATE_NORMAL);
#if 0
/* This is what we want for transparent background */
{
col.pixel = 0;
gdk_window_set_background (window, &col);
} }
#endif }
}
static gboolean static gboolean
meta_frames_enter_notify_event (GtkWidget *widget, meta_frames_enter_notify_event (GtkWidget *widget,
@ -2259,6 +2422,24 @@ control_rect (MetaFrameControl control,
case META_FRAME_CONTROL_UNMAXIMIZE: case META_FRAME_CONTROL_UNMAXIMIZE:
rect = &fgeom->max_rect.visible; rect = &fgeom->max_rect.visible;
break; break;
case META_FRAME_CONTROL_SHADE:
rect = &fgeom->shade_rect.visible;
break;
case META_FRAME_CONTROL_UNSHADE:
rect = &fgeom->unshade_rect.visible;
break;
case META_FRAME_CONTROL_ABOVE:
rect = &fgeom->above_rect.visible;
break;
case META_FRAME_CONTROL_UNABOVE:
rect = &fgeom->unabove_rect.visible;
break;
case META_FRAME_CONTROL_STICK:
rect = &fgeom->stick_rect.visible;
break;
case META_FRAME_CONTROL_UNSTICK:
rect = &fgeom->unstick_rect.visible;
break;
case META_FRAME_CONTROL_RESIZE_SE: case META_FRAME_CONTROL_RESIZE_SE:
break; break;
case META_FRAME_CONTROL_RESIZE_S: case META_FRAME_CONTROL_RESIZE_S:
@ -2336,6 +2517,36 @@ get_control (MetaFrames *frames,
return META_FRAME_CONTROL_MAXIMIZE; return META_FRAME_CONTROL_MAXIMIZE;
} }
if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable))
{
return META_FRAME_CONTROL_SHADE;
}
if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable))
{
return META_FRAME_CONTROL_UNSHADE;
}
if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable))
{
return META_FRAME_CONTROL_ABOVE;
}
if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable))
{
return META_FRAME_CONTROL_UNABOVE;
}
if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable))
{
return META_FRAME_CONTROL_STICK;
}
if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable))
{
return META_FRAME_CONTROL_UNSTICK;
}
/* South resize always has priority over north resize, /* South resize always has priority over north resize,
* in case of overlap. * in case of overlap.
*/ */

View File

@ -38,6 +38,12 @@ typedef enum
META_FRAME_CONTROL_MINIMIZE, META_FRAME_CONTROL_MINIMIZE,
META_FRAME_CONTROL_MAXIMIZE, META_FRAME_CONTROL_MAXIMIZE,
META_FRAME_CONTROL_UNMAXIMIZE, 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_SE,
META_FRAME_CONTROL_RESIZE_S, META_FRAME_CONTROL_RESIZE_S,
META_FRAME_CONTROL_RESIZE_SW, META_FRAME_CONTROL_RESIZE_SW,

View File

@ -25,6 +25,7 @@
#include "iconcache.h" #include "iconcache.h"
#include "ui.h" #include "ui.h"
#include "errors.h" #include "errors.h"
#include "theme.h"
#include <X11/Xatom.h> #include <X11/Xatom.h>
@ -499,19 +500,6 @@ get_kwm_win_icon (MetaDisplay *display,
return; return;
} }
typedef enum
{
/* These MUST be in ascending order of preference;
* i.e. if we get _NET_WM_ICON and already have
* WM_HINTS, we prefer _NET_WM_ICON
*/
USING_NO_ICON,
USING_FALLBACK_ICON,
USING_KWM_WIN_ICON,
USING_WM_HINTS,
USING_NET_WM_ICON
} IconOrigin;
void void
meta_icon_cache_init (MetaIconCache *icon_cache) meta_icon_cache_init (MetaIconCache *icon_cache)
{ {
@ -829,6 +817,10 @@ meta_read_icons (MetaScreen *screen,
if (icon_cache->want_fallback && if (icon_cache->want_fallback &&
icon_cache->origin < USING_FALLBACK_ICON) icon_cache->origin < USING_FALLBACK_ICON)
{
MetaTheme *theme = meta_theme_get_current ();
if (theme->fallback_icon == NULL || theme->fallback_mini_icon == NULL)
{ {
get_fallback_icons (screen, get_fallback_icons (screen,
iconp, iconp,
@ -837,6 +829,12 @@ meta_read_icons (MetaScreen *screen,
mini_iconp, mini_iconp,
ideal_mini_width, ideal_mini_width,
ideal_mini_height); ideal_mini_height);
}
if (theme->fallback_icon != NULL)
*iconp = theme->fallback_icon;
if (theme->fallback_mini_icon != NULL)
*mini_iconp = theme->fallback_mini_icon;
replace_cache (icon_cache, USING_FALLBACK_ICON, replace_cache (icon_cache, USING_FALLBACK_ICON,
*iconp, *mini_iconp); *iconp, *mini_iconp);

View File

@ -28,6 +28,19 @@
typedef struct _MetaIconCache MetaIconCache; typedef struct _MetaIconCache MetaIconCache;
typedef enum
{
/* These MUST be in ascending order of preference;
* i.e. if we get _NET_WM_ICON and already have
* WM_HINTS, we prefer _NET_WM_ICON
*/
USING_NO_ICON,
USING_FALLBACK_ICON,
USING_KWM_WIN_ICON,
USING_WM_HINTS,
USING_NET_WM_ICON
} IconOrigin;
struct _MetaIconCache struct _MetaIconCache
{ {
int origin; int origin;

View File

@ -365,7 +365,7 @@ main (int argc, char **argv)
} }
if (!meta_ui_have_a_theme ()) if (!meta_ui_have_a_theme ())
meta_fatal (_("Could not find a theme! Be sure %s exists and contains the usual themes."), meta_fatal (_("Could not find a theme! Be sure %s exists and contains the usual themes.\n"),
METACITY_DATADIR"/themes"); METACITY_DATADIR"/themes");
/* Connect to SM as late as possible - but before managing display, /* Connect to SM as late as possible - but before managing display,

View File

@ -1381,10 +1381,42 @@ button_function_from_string (const char *str)
return META_BUTTON_FUNCTION_MAXIMIZE; return META_BUTTON_FUNCTION_MAXIMIZE;
else if (strcmp (str, "close") == 0) else if (strcmp (str, "close") == 0)
return META_BUTTON_FUNCTION_CLOSE; return META_BUTTON_FUNCTION_CLOSE;
else if (strcmp (str, "shade") == 0)
return META_BUTTON_FUNCTION_SHADE;
else if (strcmp (str, "above") == 0)
return META_BUTTON_FUNCTION_ABOVE;
else if (strcmp (str, "stick") == 0)
return META_BUTTON_FUNCTION_STICK;
else else
/* don't know; give up */
return META_BUTTON_FUNCTION_LAST; return META_BUTTON_FUNCTION_LAST;
} }
static MetaButtonFunction
button_opposite_function (MetaButtonFunction ofwhat)
{
switch (ofwhat)
{
case META_BUTTON_FUNCTION_SHADE:
return META_BUTTON_FUNCTION_UNSHADE;
case META_BUTTON_FUNCTION_UNSHADE:
return META_BUTTON_FUNCTION_SHADE;
case META_BUTTON_FUNCTION_ABOVE:
return META_BUTTON_FUNCTION_UNABOVE;
case META_BUTTON_FUNCTION_UNABOVE:
return META_BUTTON_FUNCTION_ABOVE;
case META_BUTTON_FUNCTION_STICK:
return META_BUTTON_FUNCTION_UNSTICK;
case META_BUTTON_FUNCTION_UNSTICK:
return META_BUTTON_FUNCTION_STICK;
default:
return META_BUTTON_FUNCTION_LAST;
}
}
static gboolean static gboolean
update_button_layout (const char *value) update_button_layout (const char *value)
{ {
@ -1435,6 +1467,11 @@ update_button_layout (const char *value)
new_layout.left_buttons[i] = f; new_layout.left_buttons[i] = f;
used[f] = TRUE; used[f] = TRUE;
++i; ++i;
f = button_opposite_function (f);
if (f != META_BUTTON_FUNCTION_LAST)
new_layout.left_buttons[i++] = f;
} }
else else
{ {
@ -1473,6 +1510,11 @@ update_button_layout (const char *value)
new_layout.right_buttons[i] = f; new_layout.right_buttons[i] = f;
used[f] = TRUE; used[f] = TRUE;
++i; ++i;
f = button_opposite_function (f);
if (f != META_BUTTON_FUNCTION_LAST)
new_layout.right_buttons[i++] = f;
} }
else else
{ {

View File

@ -73,7 +73,9 @@ typedef enum
/* assigning style sets to windows */ /* assigning style sets to windows */
STATE_WINDOW, STATE_WINDOW,
/* and menu icons */ /* and menu icons */
STATE_MENU_ICON STATE_MENU_ICON,
/* fallback icons */
STATE_FALLBACK
} ParseState; } ParseState;
typedef struct typedef struct
@ -84,6 +86,7 @@ typedef struct
char *theme_file; /* theme filename */ char *theme_file; /* theme filename */
char *theme_dir; /* dir the theme is inside */ char *theme_dir; /* dir the theme is inside */
MetaTheme *theme; /* theme being parsed */ MetaTheme *theme; /* theme being parsed */
guint format_version; /* version of format of theme file */
char *name; /* name of named thing being parsed */ char *name; /* name of named thing being parsed */
MetaFrameLayout *layout; /* layout being parsed if any */ MetaFrameLayout *layout; /* layout being parsed if any */
MetaDrawOpList *op_list; /* op list being parsed if any */ MetaDrawOpList *op_list; /* op list being parsed if any */
@ -93,8 +96,6 @@ typedef struct
MetaFramePiece piece; /* position of piece being parsed */ MetaFramePiece piece; /* position of piece being parsed */
MetaButtonType button_type; /* type of button/menuitem being parsed */ MetaButtonType button_type; /* type of button/menuitem being parsed */
MetaButtonState button_state; /* state of button being parsed */ MetaButtonState button_state; /* state of button being parsed */
MetaMenuIconType menu_icon_type; /* type of menu icon being parsed */
GtkStateType menu_icon_state; /* state of menu icon being parsed */
} ParseInfo; } ParseInfo;
static void set_error (GError **err, static void set_error (GError **err,
@ -451,15 +452,29 @@ static gboolean
parse_positive_integer (const char *str, parse_positive_integer (const char *str,
int *val, int *val,
GMarkupParseContext *context, GMarkupParseContext *context,
MetaTheme *theme,
GError **error) GError **error)
{ {
char *end; char *end;
long l; long l;
int j;
*val = 0; *val = 0;
end = NULL; end = NULL;
/* Is str a constant? */
if (META_THEME_ALLOWS (theme, META_THEME_UBIQUITOUS_CONSTANTS) &&
meta_theme_lookup_int_constant (theme, str, &j))
{
/* Yes. */
l = j;
}
else
{
/* No. Let's try parsing it instead. */
l = strtol (str, &end, 10); l = strtol (str, &end, 10);
if (end == NULL || end == str) if (end == NULL || end == str)
@ -479,6 +494,7 @@ parse_positive_integer (const char *str,
end, str); end, str);
return FALSE; return FALSE;
} }
}
if (l < 0) if (l < 0)
{ {
@ -559,6 +575,41 @@ parse_boolean (const char *str,
return TRUE; return TRUE;
} }
static gboolean
parse_rounding (const char *str,
guint *val,
GMarkupParseContext *context,
MetaTheme *theme,
GError **error)
{
if (strcmp ("true", str) == 0)
*val = 5; /* historical "true" value */
else if (strcmp ("false", str) == 0)
*val = 0;
else
{
int tmp;
gboolean result;
if (!META_THEME_ALLOWS (theme, META_THEME_VARIED_ROUND_CORNERS))
{
/* Not known in this version, so bail. */
set_error (error, context, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Boolean values must be \"true\" or \"false\" not \"%s\""),
str);
return FALSE;
}
result = parse_positive_integer (str, &tmp, context, theme, error);
*val = tmp;
return result;
}
return TRUE;
}
static gboolean static gboolean
parse_angle (const char *str, parse_angle (const char *str,
double *val, double *val,
@ -624,17 +675,14 @@ parse_alpha (const char *str,
if (!parse_double (split[i], &v, context, error)) if (!parse_double (split[i], &v, context, error))
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, /* clear up, but don't set error: it was set by parse_double */
_("Could not parse \"%s\" as a floating point number"),
split[i]);
g_strfreev (split); g_strfreev (split);
meta_alpha_gradient_spec_free (spec); meta_alpha_gradient_spec_free (spec);
return FALSE; return FALSE;
} }
if (v < (0.0 - 1e6) || v > (1.0 + 1e6)) if (v < (0.0 - 1e-6) || v > (1.0 + 1e-6))
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"), _("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"),
@ -658,6 +706,25 @@ parse_alpha (const char *str,
return TRUE; return TRUE;
} }
static MetaColorSpec*
parse_color (MetaTheme *theme,
const char *str,
GError **err)
{
char* referent;
if (META_THEME_ALLOWS (theme, META_THEME_COLOR_CONSTANTS) &&
meta_theme_lookup_color_constant (theme, str, &referent))
{
if (referent)
return meta_color_spec_new_from_string (referent, err);
/* no need to free referent: it's a pointer into the actual hash table */
}
return meta_color_spec_new_from_string (str, err);
}
static gboolean static gboolean
parse_title_scale (const char *str, parse_title_scale (const char *str,
double *val, double *val,
@ -716,8 +783,8 @@ parse_toplevel_element (GMarkupParseContext *context,
{ {
const char *name; const char *name;
const char *value; const char *value;
int ival; int ival = 0;
double dval; double dval = 0.0;
if (!locate_attributes (context, element_name, attribute_names, attribute_values, if (!locate_attributes (context, element_name, attribute_names, attribute_values,
error, error,
@ -741,11 +808,9 @@ parse_toplevel_element (GMarkupParseContext *context,
return; return;
} }
if (strchr (value, '.')) if (strchr (value, '.') && parse_double (value, &dval, context, error))
{ {
dval = 0.0; g_clear_error (error);
if (!parse_double (value, &dval, context, error))
return;
if (!meta_theme_define_float_constant (info->theme, if (!meta_theme_define_float_constant (info->theme,
name, name,
@ -756,11 +821,9 @@ parse_toplevel_element (GMarkupParseContext *context,
return; return;
} }
} }
else else if (parse_positive_integer (value, &ival, context, info->theme, error))
{ {
ival = 0; g_clear_error (error);
if (!parse_positive_integer (value, &ival, context, error))
return;
if (!meta_theme_define_int_constant (info->theme, if (!meta_theme_define_int_constant (info->theme,
name, name,
@ -771,6 +834,19 @@ parse_toplevel_element (GMarkupParseContext *context,
return; return;
} }
} }
else
{
g_clear_error (error);
if (!meta_theme_define_color_constant (info->theme,
name,
value,
error))
{
add_context_to_error (error, context);
return;
}
}
push_state (info, STATE_CONSTANT); push_state (info, STATE_CONSTANT);
} }
@ -784,11 +860,13 @@ parse_toplevel_element (GMarkupParseContext *context,
const char *rounded_top_right = NULL; const char *rounded_top_right = NULL;
const char *rounded_bottom_left = NULL; const char *rounded_bottom_left = NULL;
const char *rounded_bottom_right = NULL; const char *rounded_bottom_right = NULL;
const char *hide_buttons = NULL;
gboolean has_title_val; gboolean has_title_val;
gboolean rounded_top_left_val; guint rounded_top_left_val;
gboolean rounded_top_right_val; guint rounded_top_right_val;
gboolean rounded_bottom_left_val; guint rounded_bottom_left_val;
gboolean rounded_bottom_right_val; guint rounded_bottom_right_val;
gboolean hide_buttons_val;
double title_scale_val; double title_scale_val;
MetaFrameLayout *parent_layout; MetaFrameLayout *parent_layout;
@ -800,6 +878,7 @@ parse_toplevel_element (GMarkupParseContext *context,
"rounded_top_right", &rounded_top_right, "rounded_top_right", &rounded_top_right,
"rounded_bottom_left", &rounded_bottom_left, "rounded_bottom_left", &rounded_bottom_left,
"rounded_bottom_right", &rounded_bottom_right, "rounded_bottom_right", &rounded_bottom_right,
"hide_buttons", &hide_buttons,
NULL)) NULL))
return; return;
@ -815,18 +894,22 @@ parse_toplevel_element (GMarkupParseContext *context,
if (has_title && !parse_boolean (has_title, &has_title_val, context, error)) if (has_title && !parse_boolean (has_title, &has_title_val, context, error))
return; return;
rounded_top_left_val = FALSE; hide_buttons_val = FALSE;
rounded_top_right_val = FALSE; if (hide_buttons && !parse_boolean (hide_buttons, &hide_buttons_val, context, error))
rounded_bottom_left_val = FALSE; return;
rounded_bottom_right_val = FALSE;
if (rounded_top_left && !parse_boolean (rounded_top_left, &rounded_top_left_val, context, error)) rounded_top_left_val = 0;
rounded_top_right_val = 0;
rounded_bottom_left_val = 0;
rounded_bottom_right_val = 0;
if (rounded_top_left && !parse_rounding (rounded_top_left, &rounded_top_left_val, context, info->theme, error))
return; return;
if (rounded_top_right && !parse_boolean (rounded_top_right, &rounded_top_right_val, context, error)) if (rounded_top_right && !parse_rounding (rounded_top_right, &rounded_top_right_val, context, info->theme, error))
return; return;
if (rounded_bottom_left && !parse_boolean (rounded_bottom_left, &rounded_bottom_left_val, context, error)) if (rounded_bottom_left && !parse_rounding (rounded_bottom_left, &rounded_bottom_left_val, context, info->theme, error))
return; return;
if (rounded_bottom_right && !parse_boolean (rounded_bottom_right, &rounded_bottom_right_val, context, error)) if (rounded_bottom_right && !parse_rounding (rounded_bottom_right, &rounded_bottom_right_val, context, info->theme, error))
return; return;
title_scale_val = 1.0; title_scale_val = 1.0;
@ -864,20 +947,23 @@ parse_toplevel_element (GMarkupParseContext *context,
if (has_title) /* only if explicit, otherwise inherit */ if (has_title) /* only if explicit, otherwise inherit */
info->layout->has_title = has_title_val; info->layout->has_title = has_title_val;
if (META_THEME_ALLOWS (info->theme, META_THEME_HIDDEN_BUTTONS) && hide_buttons_val)
info->layout->hide_buttons = hide_buttons_val;
if (title_scale) if (title_scale)
info->layout->title_scale = title_scale_val; info->layout->title_scale = title_scale_val;
if (rounded_top_left) if (rounded_top_left)
info->layout->top_left_corner_rounded = rounded_top_left_val; info->layout->top_left_corner_rounded_radius = rounded_top_left_val;
if (rounded_top_right) if (rounded_top_right)
info->layout->top_right_corner_rounded = rounded_top_right_val; info->layout->top_right_corner_rounded_radius = rounded_top_right_val;
if (rounded_bottom_left) if (rounded_bottom_left)
info->layout->bottom_left_corner_rounded = rounded_bottom_left_val; info->layout->bottom_left_corner_rounded_radius = rounded_bottom_left_val;
if (rounded_bottom_right) if (rounded_bottom_right)
info->layout->bottom_right_corner_rounded = rounded_bottom_right_val; info->layout->bottom_right_corner_rounded_radius = rounded_bottom_right_val;
meta_theme_insert_layout (info->theme, name, info->layout); meta_theme_insert_layout (info->theme, name, info->layout);
@ -921,6 +1007,8 @@ parse_toplevel_element (GMarkupParseContext *context,
const char *name = NULL; const char *name = NULL;
const char *parent = NULL; const char *parent = NULL;
const char *geometry = NULL; const char *geometry = NULL;
const char *background = NULL;
const char *alpha = NULL;
MetaFrameStyle *parent_style; MetaFrameStyle *parent_style;
MetaFrameLayout *layout; MetaFrameLayout *layout;
@ -928,6 +1016,8 @@ parse_toplevel_element (GMarkupParseContext *context,
error, error,
"name", &name, "parent", &parent, "name", &name, "parent", &parent,
"geometry", &geometry, "geometry", &geometry,
"background", &background,
"alpha", &alpha,
NULL)) NULL))
return; return;
@ -992,6 +1082,40 @@ parse_toplevel_element (GMarkupParseContext *context,
meta_frame_layout_ref (layout); meta_frame_layout_ref (layout);
info->style->layout = layout; info->style->layout = layout;
if (background != NULL && META_THEME_ALLOWS (info->theme, META_THEME_FRAME_BACKGROUNDS))
{
info->style->window_background_color = meta_color_spec_new_from_string (background, error);
if (!info->style->window_background_color)
return;
if (alpha != NULL)
{
gboolean success;
MetaAlphaGradientSpec *alpha_vector;
g_clear_error (error);
/* fortunately, we already have a routine to parse alpha values,
* though it produces a vector of them, which is a superset of
* what we want.
*/
success = parse_alpha (alpha, &alpha_vector, context, error);
if (!success)
return;
/* alpha_vector->alphas must contain at least one element */
info->style->window_background_alpha = alpha_vector->alphas[0];
meta_alpha_gradient_spec_free (alpha_vector);
}
}
else if (alpha != NULL)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("You must specify a background for an alpha value to be meaningful"));
return;
}
meta_theme_insert_style (info->theme, name, info->style); meta_theme_insert_style (info->theme, name, info->style);
push_state (info, STATE_FRAME_STYLE); push_state (info, STATE_FRAME_STYLE);
@ -1110,82 +1234,50 @@ parse_toplevel_element (GMarkupParseContext *context,
} }
else if (ELEMENT_IS ("menu_icon")) else if (ELEMENT_IS ("menu_icon"))
{ {
const char *function = NULL; /* Not supported any more, but we have to parse it if they include it,
const char *state = NULL; * for backwards compatibility.
const char *draw_ops = NULL; */
g_assert (info->op_list == NULL);
push_state (info, STATE_MENU_ICON);
}
else if (ELEMENT_IS ("fallback"))
{
const char *icon = NULL;
const char *mini_icon = NULL;
if (!locate_attributes (context, element_name, attribute_names, attribute_values, if (!locate_attributes (context, element_name, attribute_names, attribute_values,
error, error,
"function", &function, "icon", &icon,
"state", &state, "mini_icon", &mini_icon,
"draw_ops", &draw_ops,
NULL)) NULL))
return; return;
if (function == NULL) if (icon)
{
if (info->theme->fallback_icon != NULL)
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("No \"%s\" attribute on <%s> element"), _("Theme already has a fallback icon"));
"function", element_name);
return; return;
} }
if (state == NULL) info->theme->fallback_icon = meta_theme_load_image(info->theme, icon, 64, error);
}
if (mini_icon)
{
if (info->theme->fallback_mini_icon != NULL)
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("No \"%s\" attribute on <%s> element"), _("Theme already has a fallback mini_icon"));
"state", element_name);
return; return;
} }
info->menu_icon_type = meta_menu_icon_type_from_string (function); info->theme->fallback_mini_icon = meta_theme_load_image(info->theme, mini_icon, 16, error);
if (info->menu_icon_type == META_BUTTON_TYPE_LAST)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Unknown function \"%s\" for menu icon"),
function);
return;
} }
info->menu_icon_state = meta_gtk_state_from_string (state); push_state (info, STATE_FALLBACK);
if (((int) info->menu_icon_state) == -1)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Unknown state \"%s\" for menu icon"),
state);
return;
}
if (info->theme->menu_icons[info->menu_icon_type][info->menu_icon_state] != NULL)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Theme already has a menu icon for function %s state %s"),
function, state);
return;
}
g_assert (info->op_list == NULL);
if (draw_ops)
{
MetaDrawOpList *op_list;
op_list = meta_theme_lookup_draw_op_list (info->theme,
draw_ops);
if (op_list == NULL)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("No <draw_ops> with the name \"%s\" has been defined"),
draw_ops);
return;
}
meta_draw_op_list_ref (op_list);
info->op_list = op_list;
}
push_state (info, STATE_MENU_ICON);
} }
else else
{ {
@ -1293,7 +1385,7 @@ parse_distance (GMarkupParseContext *context,
} }
val = 0; val = 0;
if (!parse_positive_integer (value, &val, context, error)) if (!parse_positive_integer (value, &val, context, info->theme, error))
return; return;
g_assert (val >= 0); /* yeah, "non-negative" not "positive" get over it */ g_assert (val >= 0); /* yeah, "non-negative" not "positive" get over it */
@ -1471,19 +1563,19 @@ parse_border (GMarkupParseContext *context,
} }
top_val = 0; top_val = 0;
if (!parse_positive_integer (top, &top_val, context, error)) if (!parse_positive_integer (top, &top_val, context, info->theme, error))
return; return;
bottom_val = 0; bottom_val = 0;
if (!parse_positive_integer (bottom, &bottom_val, context, error)) if (!parse_positive_integer (bottom, &bottom_val, context, info->theme, error))
return; return;
left_val = 0; left_val = 0;
if (!parse_positive_integer (left, &left_val, context, error)) if (!parse_positive_integer (left, &left_val, context, info->theme, error))
return; return;
right_val = 0; right_val = 0;
if (!parse_positive_integer (right, &right_val, context, error)) if (!parse_positive_integer (right, &right_val, context, info->theme, error))
return; return;
g_assert (info->layout); g_assert (info->layout);
@ -1697,23 +1789,23 @@ parse_draw_op_element (GMarkupParseContext *context,
dash_on_val = 0; dash_on_val = 0;
if (dash_on_length && if (dash_on_length &&
!parse_positive_integer (dash_on_length, &dash_on_val, context, error)) !parse_positive_integer (dash_on_length, &dash_on_val, context, info->theme, error))
return; return;
dash_off_val = 0; dash_off_val = 0;
if (dash_off_length && if (dash_off_length &&
!parse_positive_integer (dash_off_length, &dash_off_val, context, error)) !parse_positive_integer (dash_off_length, &dash_off_val, context, info->theme, error))
return; return;
width_val = 0; width_val = 0;
if (width && if (width &&
!parse_positive_integer (width, &width_val, context, error)) !parse_positive_integer (width, &width_val, context, info->theme, error))
return; return;
/* Check last so we don't have to free it when other /* Check last so we don't have to free it when other
* stuff fails * stuff fails
*/ */
color_spec = meta_color_spec_new_from_string (color, error); color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL) if (color_spec == NULL)
{ {
add_context_to_error (error, context); add_context_to_error (error, context);
@ -1812,7 +1904,7 @@ parse_draw_op_element (GMarkupParseContext *context,
/* Check last so we don't have to free it when other /* Check last so we don't have to free it when other
* stuff fails * stuff fails
*/ */
color_spec = meta_color_spec_new_from_string (color, error); color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL) if (color_spec == NULL)
{ {
add_context_to_error (error, context); add_context_to_error (error, context);
@ -1845,6 +1937,8 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *filled; const char *filled;
const char *start_angle; const char *start_angle;
const char *extent_angle; const char *extent_angle;
const char *from;
const char *to;
gboolean filled_val; gboolean filled_val;
double start_angle_val; double start_angle_val;
double extent_angle_val; double extent_angle_val;
@ -1858,6 +1952,8 @@ parse_draw_op_element (GMarkupParseContext *context,
"filled", &filled, "filled", &filled,
"start_angle", &start_angle, "start_angle", &start_angle,
"extent_angle", &extent_angle, "extent_angle", &extent_angle,
"from", &from,
"to", &to,
NULL)) NULL))
return; return;
@ -1896,6 +1992,24 @@ parse_draw_op_element (GMarkupParseContext *context,
return; return;
} }
if (META_THEME_ALLOWS (info->theme, META_THEME_DEGREES_IN_ARCS) )
{
if (start_angle == NULL && from == NULL)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("No \"start_angle\" or \"from\" attribute on element <%s>"), element_name);
return;
}
if (extent_angle == NULL && to == NULL)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("No \"extent_angle\" or \"to\" attribute on element <%s>"), element_name);
return;
}
}
else
{
if (start_angle == NULL) if (start_angle == NULL)
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
@ -1909,6 +2023,8 @@ parse_draw_op_element (GMarkupParseContext *context,
_("No \"extent_angle\" attribute on element <%s>"), element_name); _("No \"extent_angle\" attribute on element <%s>"), element_name);
return; return;
} }
}
if (!check_expression (x, FALSE, info->theme, context, error)) if (!check_expression (x, FALSE, info->theme, context, error))
return; return;
@ -1922,11 +2038,31 @@ parse_draw_op_element (GMarkupParseContext *context,
if (!check_expression (height, FALSE, info->theme, context, error)) if (!check_expression (height, FALSE, info->theme, context, error))
return; return;
if (!parse_angle (start_angle, &start_angle_val, context, error)) if (start_angle == NULL)
{
if (!parse_angle (from, &start_angle_val, context, error))
return; return;
start_angle_val = (180-start_angle_val)/360.0;
}
else
{
if (!parse_angle (start_angle, &start_angle_val, context, error))
return;
}
if (extent_angle == NULL)
{
if (!parse_angle (to, &extent_angle_val, context, error))
return;
extent_angle_val = ((180-extent_angle_val)/360.0) - start_angle_val;
}
else
{
if (!parse_angle (extent_angle, &extent_angle_val, context, error)) if (!parse_angle (extent_angle, &extent_angle_val, context, error))
return; return;
}
filled_val = FALSE; filled_val = FALSE;
if (filled && !parse_boolean (filled, &filled_val, context, error)) if (filled && !parse_boolean (filled, &filled_val, context, error))
@ -1935,7 +2071,7 @@ parse_draw_op_element (GMarkupParseContext *context,
/* Check last so we don't have to free it when other /* Check last so we don't have to free it when other
* stuff fails * stuff fails
*/ */
color_spec = meta_color_spec_new_from_string (color, error); color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL) if (color_spec == NULL)
{ {
add_context_to_error (error, context); add_context_to_error (error, context);
@ -2109,7 +2245,7 @@ parse_draw_op_element (GMarkupParseContext *context,
/* Check last so we don't have to free it when other /* Check last so we don't have to free it when other
* stuff fails * stuff fails
*/ */
color_spec = meta_color_spec_new_from_string (color, error); color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL) if (color_spec == NULL)
{ {
if (alpha_spec) if (alpha_spec)
@ -2321,9 +2457,12 @@ parse_draw_op_element (GMarkupParseContext *context,
} }
/* Check last so we don't have to free it when other /* Check last so we don't have to free it when other
* stuff fails * stuff fails.
*
* If it's a theme image, ask for it at 64px, which is
* the largest possible. We scale it anyway.
*/ */
pixbuf = meta_theme_load_image (info->theme, filename, error); pixbuf = meta_theme_load_image (info->theme, filename, 64, error);
if (pixbuf == NULL) if (pixbuf == NULL)
{ {
@ -2333,7 +2472,7 @@ parse_draw_op_element (GMarkupParseContext *context,
if (colorize) if (colorize)
{ {
colorize_spec = meta_color_spec_new_from_string (colorize, error); colorize_spec = parse_color (info->theme, colorize, error);
if (colorize_spec == NULL) if (colorize_spec == NULL)
{ {
@ -2892,7 +3031,7 @@ parse_draw_op_element (GMarkupParseContext *context,
/* Check last so we don't have to free it when other /* Check last so we don't have to free it when other
* stuff fails * stuff fails
*/ */
color_spec = meta_color_spec_new_from_string (color, error); color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL) if (color_spec == NULL)
{ {
add_context_to_error (error, context); add_context_to_error (error, context);
@ -3154,7 +3293,7 @@ parse_gradient_element (GMarkupParseContext *context,
return; return;
} }
color_spec = meta_color_spec_new_from_string (value, error); color_spec = parse_color (info->theme, value, error);
if (color_spec == NULL) if (color_spec == NULL)
{ {
add_context_to_error (error, context); add_context_to_error (error, context);
@ -3281,7 +3420,7 @@ parse_style_element (GMarkupParseContext *context,
return; return;
} }
info->button_type = meta_button_type_from_string (function); info->button_type = meta_button_type_from_string (function, info->theme);
if (info->button_type == META_BUTTON_TYPE_LAST) if (info->button_type == META_BUTTON_TYPE_LAST)
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
@ -3290,6 +3429,18 @@ parse_style_element (GMarkupParseContext *context,
return; return;
} }
if (meta_theme_earliest_version_with_button (info->button_type) >
info->theme->format_version)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Button function \"%s\" does not exist in this version (%d, need %d)"),
function,
info->theme->format_version,
meta_theme_earliest_version_with_button (info->button_type)
);
return;
}
info->button_state = meta_button_state_from_string (state); info->button_state = meta_button_state_from_string (state);
if (info->button_state == META_BUTTON_STATE_LAST) if (info->button_state == META_BUTTON_STATE_LAST)
{ {
@ -3421,8 +3572,9 @@ parse_style_set_element (GMarkupParseContext *context,
return; return;
} }
if (frame_state == META_FRAME_STATE_NORMAL) switch (frame_state)
{ {
case META_FRAME_STATE_NORMAL:
if (resize == NULL) if (resize == NULL)
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
@ -3440,8 +3592,32 @@ parse_style_set_element (GMarkupParseContext *context,
focus); focus);
return; return;
} }
}
break;
case META_FRAME_STATE_SHADED:
if (META_THEME_ALLOWS (info->theme, META_THEME_UNRESIZABLE_SHADED_STYLES))
{
if (resize == NULL)
/* In state="normal" we would complain here. But instead we accept
* not having a resize attribute and default to resize="both", since
* that most closely mimics what we did in v1, and thus people can
* upgrade a theme to v2 without as much hassle.
*/
frame_resize = META_FRAME_RESIZE_BOTH;
else else
{
frame_resize = meta_frame_resize_from_string (resize);
if (frame_resize == META_FRAME_RESIZE_LAST)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("\"%s\" is not a valid value for resize attribute"),
focus);
return;
}
}
}
else /* v1 theme */
{ {
if (resize != NULL) if (resize != NULL)
{ {
@ -3451,6 +3627,20 @@ parse_style_set_element (GMarkupParseContext *context,
return; return;
} }
/* resize="both" is equivalent to the old behaviour */
frame_resize = META_FRAME_RESIZE_BOTH;
}
break;
default:
if (resize != NULL)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Should not have \"resize\" attribute on <%s> element for maximized states"),
element_name);
return;
}
frame_resize = META_FRAME_RESIZE_LAST; frame_resize = META_FRAME_RESIZE_LAST;
} }
@ -3479,15 +3669,15 @@ parse_style_set_element (GMarkupParseContext *context,
info->style_set->maximized_styles[frame_focus] = frame_style; info->style_set->maximized_styles[frame_focus] = frame_style;
break; break;
case META_FRAME_STATE_SHADED: case META_FRAME_STATE_SHADED:
if (info->style_set->shaded_styles[frame_focus]) if (info->style_set->shaded_styles[frame_resize][frame_focus])
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Style has already been specified for state %s focus %s"), _("Style has already been specified for state %s resize %s focus %s"),
state, focus); state, resize, focus);
return; return;
} }
meta_frame_style_ref (frame_style); meta_frame_style_ref (frame_style);
info->style_set->shaded_styles[frame_focus] = frame_style; info->style_set->shaded_styles[frame_resize][frame_focus] = frame_style;
break; break;
case META_FRAME_STATE_MAXIMIZED_AND_SHADED: case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
if (info->style_set->maximized_and_shaded_styles[frame_focus]) if (info->style_set->maximized_and_shaded_styles[frame_focus])
@ -3650,6 +3840,7 @@ start_element_handler (GMarkupParseContext *context,
info->theme->name = g_strdup (info->theme_name); info->theme->name = g_strdup (info->theme_name);
info->theme->filename = g_strdup (info->theme_file); info->theme->filename = g_strdup (info->theme_file);
info->theme->dirname = g_strdup (info->theme_dir); info->theme->dirname = g_strdup (info->theme_dir);
info->theme->format_version = info->format_version;
push_state (info, STATE_THEME); push_state (info, STATE_THEME);
} }
@ -3762,6 +3953,11 @@ start_element_handler (GMarkupParseContext *context,
_("Element <%s> is not allowed inside a <%s> element"), _("Element <%s> is not allowed inside a <%s> element"),
element_name, "window"); element_name, "window");
break; break;
case STATE_FALLBACK:
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
_("Element <%s> is not allowed inside a <%s> element"),
element_name, "fallback");
break;
} }
} }
@ -3962,6 +4158,7 @@ end_element_handler (GMarkupParseContext *context,
g_assert (info->style); g_assert (info->style);
if (!meta_frame_style_validate (info->style, if (!meta_frame_style_validate (info->style,
info->theme->format_version,
error)) error))
{ {
add_context_to_error (error, context); add_context_to_error (error, context);
@ -4007,16 +4204,9 @@ end_element_handler (GMarkupParseContext *context,
break; break;
case STATE_MENU_ICON: case STATE_MENU_ICON:
g_assert (info->theme); g_assert (info->theme);
if (info->op_list == NULL) if (info->op_list != NULL)
{ {
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, meta_draw_op_list_unref (info->op_list);
_("No draw_ops provided for menu icon"));
}
else
{
g_assert (info->theme->menu_icons[info->menu_icon_type][info->menu_icon_state] == NULL);
info->theme->menu_icons[info->menu_icon_type][info->menu_icon_state] =
info->op_list;
info->op_list = NULL; info->op_list = NULL;
} }
pop_state (info); pop_state (info);
@ -4047,6 +4237,10 @@ end_element_handler (GMarkupParseContext *context,
pop_state (info); pop_state (info);
g_assert (peek_state (info) == STATE_THEME); g_assert (peek_state (info) == STATE_THEME);
break; break;
case STATE_FALLBACK:
pop_state (info);
g_assert (peek_state (info) == STATE_THEME);
break;
} }
} }
@ -4239,19 +4433,26 @@ text_handler (GMarkupParseContext *context,
case STATE_WINDOW: case STATE_WINDOW:
NO_TEXT ("window"); NO_TEXT ("window");
break; break;
case STATE_FALLBACK:
NO_TEXT ("fallback");
break;
} }
} }
/* We change the filename when we break the format, /* We were intending to put the version number
* so themes can work with various metacity versions * in the subdirectory name, but we ended up
* (note, this is obsolete now because we are versioning * using the filename instead. The "-1" survives
* the directory this file is inside, so oh well) * as a fossil.
*/ */
#define THEME_FILENAME "metacity-theme-1.xml"
/* now this is versioned, /usr/share/themes/NAME/THEME_SUBDIR/THEME_FILENAME */
#define THEME_SUBDIR "metacity-1" #define THEME_SUBDIR "metacity-1"
/* Highest version of the theme format to
* look out for.
*/
#define THEME_VERSION 2
#define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml"
MetaTheme* MetaTheme*
meta_theme_load (const char *theme_name, meta_theme_load (const char *theme_name,
GError **err) GError **err)
@ -4264,6 +4465,7 @@ meta_theme_load (const char *theme_name,
char *theme_file; char *theme_file;
char *theme_dir; char *theme_dir;
MetaTheme *retval; MetaTheme *retval;
guint version;
text = NULL; text = NULL;
length = 0; length = 0;
@ -4275,11 +4477,14 @@ meta_theme_load (const char *theme_name,
if (meta_is_debugging ()) if (meta_is_debugging ())
{ {
gchar *theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT,
THEME_VERSION);
/* Try in themes in our source tree */ /* Try in themes in our source tree */
theme_dir = g_build_filename ("./themes", theme_name, NULL); theme_dir = g_build_filename ("./themes", theme_name, NULL);
theme_file = g_build_filename (theme_dir, theme_file = g_build_filename (theme_dir,
THEME_FILENAME, theme_filename,
NULL); NULL);
error = NULL; error = NULL;
@ -4295,12 +4500,19 @@ meta_theme_load (const char *theme_name,
g_free (theme_file); g_free (theme_file);
theme_file = NULL; theme_file = NULL;
} }
version = THEME_VERSION;
g_free (theme_filename);
} }
/* We try all supported versions from current to oldest */
for (version = THEME_VERSION; (version > 0) && (text == NULL); version--)
{
gchar *theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT,
version);
/* We try in home dir, then system dir for themes */ /* We try in home dir, then system dir for themes */
if (text == NULL)
{
theme_dir = g_build_filename (g_get_home_dir (), theme_dir = g_build_filename (g_get_home_dir (),
".themes", ".themes",
theme_name, theme_name,
@ -4308,7 +4520,7 @@ meta_theme_load (const char *theme_name,
NULL); NULL);
theme_file = g_build_filename (theme_dir, theme_file = g_build_filename (theme_dir,
THEME_FILENAME, theme_filename,
NULL); NULL);
error = NULL; error = NULL;
@ -4324,7 +4536,6 @@ meta_theme_load (const char *theme_name,
g_free (theme_file); g_free (theme_file);
theme_file = NULL; theme_file = NULL;
} }
}
if (text == NULL) if (text == NULL)
{ {
@ -4335,7 +4546,7 @@ meta_theme_load (const char *theme_name,
NULL); NULL);
theme_file = g_build_filename (theme_dir, theme_file = g_build_filename (theme_dir,
THEME_FILENAME, theme_filename,
NULL); NULL);
error = NULL; error = NULL;
@ -4344,19 +4555,30 @@ meta_theme_load (const char *theme_name,
&length, &length,
&error)) &error))
{ {
meta_warning (_("Failed to read theme from file %s: %s\n"), meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
theme_file, error->message); theme_file, error->message);
g_propagate_error (err, error); g_error_free (error);
g_free (theme_file);
g_free (theme_dir); g_free (theme_dir);
g_free (theme_file);
theme_file = NULL;
}
}
g_free (theme_filename);
}
if (text == NULL)
{
g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED,
_("Failed to find a valid file for theme %s\n"),
theme_name);
return NULL; /* all fallbacks failed */ return NULL; /* all fallbacks failed */
} }
}
g_assert (text);
meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file); meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file);
parse_info_init (&info); parse_info_init (&info);
info.theme_name = theme_name; info.theme_name = theme_name;
@ -4364,6 +4586,8 @@ meta_theme_load (const char *theme_name,
info.theme_file = theme_file; info.theme_file = theme_file;
info.theme_dir = theme_dir; info.theme_dir = theme_dir;
info.format_version = version + 1;
context = g_markup_parse_context_new (&metacity_theme_parser, context = g_markup_parse_context_new (&metacity_theme_parser,
0, &info, NULL); 0, &info, NULL);
@ -4386,6 +4610,8 @@ meta_theme_load (const char *theme_name,
g_markup_parse_context_free (context); g_markup_parse_context_free (context);
g_free (text); g_free (text);
info.theme->format_version = info.format_version;
if (error) if (error)
{ {
g_propagate_error (err, error); g_propagate_error (err, error);

View File

@ -27,6 +27,8 @@
#include "util.h" #include "util.h"
#include "gradient.h" #include "gradient.h"
#include <gtk/gtkwidget.h> #include <gtk/gtkwidget.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkicontheme.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
@ -394,8 +396,51 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout,
static MetaButtonSpace* static MetaButtonSpace*
rect_for_function (MetaFrameGeometry *fgeom, rect_for_function (MetaFrameGeometry *fgeom,
MetaFrameFlags flags, MetaFrameFlags flags,
MetaButtonFunction function) MetaButtonFunction function,
MetaTheme *theme)
{ {
/* Firstly, check version-specific things. */
if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS))
{
switch (function)
{
case META_BUTTON_FUNCTION_SHADE:
if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
return &fgeom->shade_rect;
else
return NULL;
case META_BUTTON_FUNCTION_ABOVE:
if (!(flags & META_FRAME_ABOVE))
return &fgeom->above_rect;
else
return NULL;
case META_BUTTON_FUNCTION_STICK:
if (!(flags & META_FRAME_STUCK))
return &fgeom->stick_rect;
else
return NULL;
case META_BUTTON_FUNCTION_UNSHADE:
if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
return &fgeom->unshade_rect;
else
return NULL;
case META_BUTTON_FUNCTION_UNABOVE:
if (flags & META_FRAME_ABOVE)
return &fgeom->unabove_rect;
else
return NULL;
case META_BUTTON_FUNCTION_UNSTICK:
if (flags & META_FRAME_STUCK)
return &fgeom->unstick_rect;
default:
/* just go on to the next switch block */;
}
}
/* now consider the buttons which exist in all versions */
switch (function) switch (function)
{ {
case META_BUTTON_FUNCTION_MENU: case META_BUTTON_FUNCTION_MENU:
@ -418,6 +463,19 @@ rect_for_function (MetaFrameGeometry *fgeom,
return &fgeom->close_rect; return &fgeom->close_rect;
else else
return NULL; return NULL;
case META_BUTTON_FUNCTION_STICK:
case META_BUTTON_FUNCTION_SHADE:
case META_BUTTON_FUNCTION_ABOVE:
case META_BUTTON_FUNCTION_UNSTICK:
case META_BUTTON_FUNCTION_UNSHADE:
case META_BUTTON_FUNCTION_UNABOVE:
/* we are being asked for a >v1 button which hasn't been handled yet,
* so obviously we're not in a theme which supports that version.
* therefore, we don't show the button. return NULL and all will
* be well.
*/
return NULL;
case META_BUTTON_FUNCTION_LAST: case META_BUTTON_FUNCTION_LAST:
return NULL; return NULL;
} }
@ -468,7 +526,8 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
int client_width, int client_width,
int client_height, int client_height,
const MetaButtonLayout *button_layout, const MetaButtonLayout *button_layout,
MetaFrameGeometry *fgeom) MetaFrameGeometry *fgeom,
MetaTheme *theme)
{ {
int i, n_left, n_right; int i, n_left, n_right;
int x; int x;
@ -544,18 +603,20 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
right_func_rects[i] = NULL; right_func_rects[i] = NULL;
/* Try to fill in rects */ /* Try to fill in rects */
if (button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST) if (button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST && !layout->hide_buttons)
{ {
left_func_rects[n_left] = rect_for_function (fgeom, flags, left_func_rects[n_left] = rect_for_function (fgeom, flags,
button_layout->left_buttons[i]); button_layout->left_buttons[i],
theme);
if (left_func_rects[n_left] != NULL) if (left_func_rects[n_left] != NULL)
++n_left; ++n_left;
} }
if (button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST) if (button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST && !layout->hide_buttons)
{ {
right_func_rects[n_right] = rect_for_function (fgeom, flags, right_func_rects[n_right] = rect_for_function (fgeom, flags,
button_layout->right_buttons[i]); button_layout->right_buttons[i],
theme);
if (right_func_rects[n_right] != NULL) if (right_func_rects[n_right] != NULL)
++n_right; ++n_right;
} }
@ -610,10 +671,28 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
break; /* Everything fits, bail out */ break; /* Everything fits, bail out */
/* Otherwise we need to shave out a button. Shave /* Otherwise we need to shave out a button. Shave
* min, max, close, then menu (menu is most useful); * above, stick, shade, min, max, close, then menu (menu is most useful);
* prefer the default button locations. * prefer the default button locations.
*/ */
if (strip_button (left_func_rects, left_bg_rects, if (strip_button (left_func_rects, left_bg_rects,
&n_left, &fgeom->above_rect))
continue;
else if (strip_button (right_func_rects, right_bg_rects,
&n_right, &fgeom->above_rect))
continue;
else if (strip_button (left_func_rects, left_bg_rects,
&n_left, &fgeom->stick_rect))
continue;
else if (strip_button (right_func_rects, right_bg_rects,
&n_right, &fgeom->stick_rect))
continue;
else if (strip_button (left_func_rects, left_bg_rects,
&n_left, &fgeom->shade_rect))
continue;
else if (strip_button (right_func_rects, right_bg_rects,
&n_right, &fgeom->shade_rect))
continue;
else if (strip_button (left_func_rects, left_bg_rects,
&n_left, &fgeom->min_rect)) &n_left, &fgeom->min_rect))
continue; continue;
else if (strip_button (right_func_rects, right_bg_rects, else if (strip_button (right_func_rects, right_bg_rects,
@ -751,20 +830,20 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
else else
min_size_for_rounding = 5; min_size_for_rounding = 5;
fgeom->top_left_corner_rounded = FALSE; fgeom->top_left_corner_rounded_radius = 0;
fgeom->top_right_corner_rounded = FALSE; fgeom->top_right_corner_rounded_radius = 0;
fgeom->bottom_left_corner_rounded = FALSE; fgeom->bottom_left_corner_rounded_radius = 0;
fgeom->bottom_right_corner_rounded = FALSE; fgeom->bottom_right_corner_rounded_radius = 0;
if (fgeom->top_height + fgeom->left_width >= min_size_for_rounding) if (fgeom->top_height + fgeom->left_width >= min_size_for_rounding)
fgeom->top_left_corner_rounded = layout->top_left_corner_rounded; fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
if (fgeom->top_height + fgeom->right_width >= min_size_for_rounding) if (fgeom->top_height + fgeom->right_width >= min_size_for_rounding)
fgeom->top_right_corner_rounded = layout->top_right_corner_rounded; fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
if (fgeom->bottom_height + fgeom->left_width >= min_size_for_rounding) if (fgeom->bottom_height + fgeom->left_width >= min_size_for_rounding)
fgeom->bottom_left_corner_rounded = layout->bottom_left_corner_rounded; fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
if (fgeom->bottom_height + fgeom->right_width >= min_size_for_rounding) if (fgeom->bottom_height + fgeom->right_width >= min_size_for_rounding)
fgeom->bottom_right_corner_rounded = layout->bottom_right_corner_rounded; fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
} }
MetaGradientSpec* MetaGradientSpec*
@ -3743,6 +3822,9 @@ meta_frame_style_new (MetaFrameStyle *parent)
style->refcount = 1; style->refcount = 1;
/* Default alpha is fully opaque */
style->window_background_alpha = 255;
style->parent = parent; style->parent = parent;
if (parent) if (parent)
meta_frame_style_ref (parent); meta_frame_style_ref (parent);
@ -3790,6 +3872,9 @@ meta_frame_style_unref (MetaFrameStyle *style)
if (style->layout) if (style->layout)
meta_frame_layout_unref (style->layout); meta_frame_layout_unref (style->layout);
if (style->window_background_color)
meta_color_spec_free (style->window_background_color);
/* we hold a reference to any parent style */ /* we hold a reference to any parent style */
if (style->parent) if (style->parent)
meta_frame_style_unref (style->parent); meta_frame_style_unref (style->parent);
@ -3841,6 +3926,7 @@ get_button (MetaFrameStyle *style,
gboolean gboolean
meta_frame_style_validate (MetaFrameStyle *style, meta_frame_style_validate (MetaFrameStyle *style,
guint current_theme_version,
GError **error) GError **error)
{ {
int i, j; int i, j;
@ -3855,7 +3941,9 @@ meta_frame_style_validate (MetaFrameStyle *style,
{ {
for (j = 0; j < META_BUTTON_STATE_LAST; j++) for (j = 0; j < META_BUTTON_STATE_LAST; j++)
{ {
if (get_button (style, i, j) == NULL) if (get_button (style, i, j) == NULL &&
meta_theme_earliest_version_with_button (i) <= current_theme_version
)
{ {
g_set_error (error, META_THEME_ERROR, g_set_error (error, META_THEME_ERROR,
META_THEME_ERROR_FAILED, META_THEME_ERROR_FAILED,
@ -3907,6 +3995,30 @@ button_rect (MetaButtonType type,
*rect = fgeom->close_rect.visible; *rect = fgeom->close_rect.visible;
break; break;
case META_BUTTON_TYPE_SHADE:
*rect = fgeom->shade_rect.visible;
break;
case META_BUTTON_TYPE_UNSHADE:
*rect = fgeom->unshade_rect.visible;
break;
case META_BUTTON_TYPE_ABOVE:
*rect = fgeom->above_rect.visible;
break;
case META_BUTTON_TYPE_UNABOVE:
*rect = fgeom->unabove_rect.visible;
break;
case META_BUTTON_TYPE_STICK:
*rect = fgeom->stick_rect.visible;
break;
case META_BUTTON_TYPE_UNSTICK:
*rect = fgeom->unstick_rect.visible;
break;
case META_BUTTON_TYPE_MAXIMIZE: case META_BUTTON_TYPE_MAXIMIZE:
*rect = fgeom->max_rect.visible; *rect = fgeom->max_rect.visible;
break; break;
@ -4218,10 +4330,12 @@ meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
int i; int i;
for (i = 0; i < META_FRAME_RESIZE_LAST; i++) for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
{
free_focus_styles (style_set->normal_styles[i]); free_focus_styles (style_set->normal_styles[i]);
free_focus_styles (style_set->shaded_styles[i]);
}
free_focus_styles (style_set->maximized_styles); free_focus_styles (style_set->maximized_styles);
free_focus_styles (style_set->shaded_styles);
free_focus_styles (style_set->maximized_and_shaded_styles); free_focus_styles (style_set->maximized_and_shaded_styles);
if (style_set->parent) if (style_set->parent)
@ -4243,8 +4357,14 @@ get_style (MetaFrameStyleSet *style_set,
style = NULL; style = NULL;
if (state == META_FRAME_STATE_NORMAL) switch (state)
{ {
case META_FRAME_STATE_NORMAL:
case META_FRAME_STATE_SHADED:
{
if (state == META_FRAME_STATE_SHADED)
style = style_set->shaded_styles[resize][focus];
else
style = style_set->normal_styles[resize][focus]; style = style_set->normal_styles[resize][focus];
/* Try parent if we failed here */ /* Try parent if we failed here */
@ -4256,7 +4376,8 @@ get_style (MetaFrameStyleSet *style_set,
resize != META_FRAME_RESIZE_BOTH) resize != META_FRAME_RESIZE_BOTH)
style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus); style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
} }
else break;
default:
{ {
MetaFrameStyle **styles; MetaFrameStyle **styles;
@ -4264,9 +4385,6 @@ get_style (MetaFrameStyleSet *style_set,
switch (state) switch (state)
{ {
case META_FRAME_STATE_SHADED:
styles = style_set->shaded_styles;
break;
case META_FRAME_STATE_MAXIMIZED: case META_FRAME_STATE_MAXIMIZED:
styles = style_set->maximized_styles; styles = style_set->maximized_styles;
break; break;
@ -4274,6 +4392,7 @@ get_style (MetaFrameStyleSet *style_set,
styles = style_set->maximized_and_shaded_styles; styles = style_set->maximized_and_shaded_styles;
break; break;
case META_FRAME_STATE_NORMAL: case META_FRAME_STATE_NORMAL:
case META_FRAME_STATE_SHADED:
case META_FRAME_STATE_LAST: case META_FRAME_STATE_LAST:
g_assert_not_reached (); g_assert_not_reached ();
break; break;
@ -4285,6 +4404,7 @@ get_style (MetaFrameStyleSet *style_set,
if (style == NULL && style_set->parent) if (style == NULL && style_set->parent)
style = get_style (style_set->parent, state, resize, focus); style = get_style (style_set->parent, state, resize, focus);
} }
}
return style; return style;
} }
@ -4430,17 +4550,6 @@ meta_theme_new (void)
} }
static void
free_menu_ops (MetaDrawOpList *op_lists[META_MENU_ICON_TYPE_LAST][N_GTK_STATES])
{
int i, j;
for (i = 0; i < META_MENU_ICON_TYPE_LAST; i++)
for (j = 0; j < N_GTK_STATES; j++)
if (op_lists[i][j])
meta_draw_op_list_unref (op_lists[i][j]);
}
void void
meta_theme_free (MetaTheme *theme) meta_theme_free (MetaTheme *theme)
{ {
@ -4476,34 +4585,15 @@ meta_theme_free (MetaTheme *theme)
if (theme->style_sets_by_type[i]) if (theme->style_sets_by_type[i])
meta_frame_style_set_unref (theme->style_sets_by_type[i]); meta_frame_style_set_unref (theme->style_sets_by_type[i]);
free_menu_ops (theme->menu_icons);
DEBUG_FILL_STRUCT (theme); DEBUG_FILL_STRUCT (theme);
g_free (theme); g_free (theme);
} }
static MetaDrawOpList*
get_menu_icon (MetaTheme *theme,
MetaMenuIconType type,
GtkStateType state)
{
MetaDrawOpList *op_list;
op_list = theme->menu_icons[type][state];
/* We fall back to normal if other states aren't found */
if (op_list == NULL &&
state != GTK_STATE_NORMAL)
return get_menu_icon (theme, type, GTK_STATE_NORMAL);
return op_list;
}
gboolean gboolean
meta_theme_validate (MetaTheme *theme, meta_theme_validate (MetaTheme *theme,
GError **error) GError **error)
{ {
int i, j; int i;
g_return_val_if_fail (theme != NULL, FALSE); g_return_val_if_fail (theme != NULL, FALSE);
@ -4558,24 +4648,13 @@ meta_theme_validate (MetaTheme *theme,
return FALSE; return FALSE;
} }
for (i = 0; i < META_MENU_ICON_TYPE_LAST; i++)
for (j = 0; j < N_GTK_STATES; j++)
if (get_menu_icon (theme, i, j) == NULL)
{
g_set_error (error, META_THEME_ERROR,
META_THEME_ERROR_FAILED,
_("<menu_icon function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this theme"),
meta_menu_icon_type_to_string (i),
meta_gtk_state_to_string (j));
return FALSE;
}
return TRUE; return TRUE;
} }
GdkPixbuf* GdkPixbuf*
meta_theme_load_image (MetaTheme *theme, meta_theme_load_image (MetaTheme *theme,
const char *filename, const char *filename,
guint size_of_theme_icons,
GError **error) GError **error)
{ {
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
@ -4585,8 +4664,21 @@ meta_theme_load_image (MetaTheme *theme,
if (pixbuf == NULL) if (pixbuf == NULL)
{ {
char *full_path;
if (g_str_has_prefix (filename, "theme:") &&
META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES))
{
pixbuf = gtk_icon_theme_load_icon (
gtk_icon_theme_get_default (),
filename+6,
size_of_theme_icons,
0,
error);
if (pixbuf == NULL) return NULL;
}
else
{
char *full_path;
full_path = g_build_filename (theme->dirname, filename, NULL); full_path = g_build_filename (theme->dirname, filename, NULL);
pixbuf = gdk_pixbuf_new_from_file (full_path, error); pixbuf = gdk_pixbuf_new_from_file (full_path, error);
@ -4597,7 +4689,7 @@ meta_theme_load_image (MetaTheme *theme,
} }
g_free (full_path); g_free (full_path);
}
g_hash_table_replace (theme->images_by_filename, g_hash_table_replace (theme->images_by_filename,
g_strdup (filename), g_strdup (filename),
pixbuf); pixbuf);
@ -4749,7 +4841,8 @@ meta_theme_draw_frame (MetaTheme *theme,
flags, flags,
client_width, client_height, client_width, client_height,
button_layout, button_layout,
&fgeom); &fgeom,
theme);
meta_frame_style_draw (style, meta_frame_style_draw (style,
widget, widget,
@ -4764,37 +4857,6 @@ meta_theme_draw_frame (MetaTheme *theme,
mini_icon, icon); mini_icon, icon);
} }
void
meta_theme_draw_menu_icon (MetaTheme *theme,
GtkWidget *widget,
GdkDrawable *drawable,
const GdkRectangle *clip,
MetaRectangle offset_rect,
MetaMenuIconType type)
{
MetaDrawInfo info;
MetaDrawOpList *op_list;
g_return_if_fail (type < META_BUTTON_TYPE_LAST);
op_list = get_menu_icon (theme, type,
GTK_WIDGET_STATE (widget));
info.mini_icon = NULL;
info.icon = NULL;
info.title_layout = NULL;
info.title_layout_width = 0;
info.title_layout_height = 0;
info.fgeom = NULL;
meta_draw_op_list_draw (op_list,
widget,
drawable,
clip,
&info,
offset_rect);
}
void void
meta_theme_get_frame_borders (MetaTheme *theme, meta_theme_get_frame_borders (MetaTheme *theme,
MetaFrameType type, MetaFrameType type,
@ -4856,7 +4918,8 @@ meta_theme_calc_geometry (MetaTheme *theme,
flags, flags,
client_width, client_height, client_width, client_height,
button_layout, button_layout,
fgeom); fgeom,
theme);
} }
MetaFrameLayout* MetaFrameLayout*
@ -5054,6 +5117,68 @@ meta_theme_lookup_float_constant (MetaTheme *theme,
} }
} }
gboolean
meta_theme_define_color_constant (MetaTheme *theme,
const char *name,
const char *value,
GError **error)
{
if (theme->color_constants == NULL)
theme->color_constants = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
if (!first_uppercase (name))
{
g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
_("User-defined constants must begin with a capital letter; \"%s\" does not"),
name);
return FALSE;
}
if (g_hash_table_lookup_extended (theme->color_constants, name, NULL, NULL))
{
g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
_("Constant \"%s\" has already been defined"),
name);
return FALSE;
}
g_hash_table_insert (theme->color_constants,
g_strdup (name),
g_strdup (value));
return TRUE;
}
gboolean
meta_theme_lookup_color_constant (MetaTheme *theme,
const char *name,
char **value)
{
char *result;
*value = NULL;
if (theme->color_constants == NULL)
return FALSE;
result = g_hash_table_lookup (theme->color_constants, name);
if (result)
{
*value = result;
return TRUE;
}
else
{
return FALSE;
}
}
PangoFontDescription* PangoFontDescription*
meta_gtk_widget_get_font_desc (GtkWidget *widget, meta_gtk_widget_get_font_desc (GtkWidget *widget,
double scale, double scale,
@ -5176,8 +5301,24 @@ meta_button_state_to_string (MetaButtonState state)
} }
MetaButtonType MetaButtonType
meta_button_type_from_string (const char *str) meta_button_type_from_string (const char *str, MetaTheme *theme)
{ {
if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS))
{
if (strcmp ("shade", str) == 0)
return META_BUTTON_TYPE_SHADE;
else if (strcmp ("above", str) == 0)
return META_BUTTON_TYPE_ABOVE;
else if (strcmp ("stick", str) == 0)
return META_BUTTON_TYPE_STICK;
else if (strcmp ("unshade", str) == 0)
return META_BUTTON_TYPE_UNSHADE;
else if (strcmp ("unabove", str) == 0)
return META_BUTTON_TYPE_UNABOVE;
else if (strcmp ("unstick", str) == 0)
return META_BUTTON_TYPE_UNSTICK;
}
if (strcmp ("close", str) == 0) if (strcmp ("close", str) == 0)
return META_BUTTON_TYPE_CLOSE; return META_BUTTON_TYPE_CLOSE;
else if (strcmp ("maximize", str) == 0) else if (strcmp ("maximize", str) == 0)
@ -5213,6 +5354,18 @@ meta_button_type_to_string (MetaButtonType type)
return "maximize"; return "maximize";
case META_BUTTON_TYPE_MINIMIZE: case META_BUTTON_TYPE_MINIMIZE:
return "minimize"; return "minimize";
case META_BUTTON_TYPE_SHADE:
return "shade";
case META_BUTTON_TYPE_ABOVE:
return "above";
case META_BUTTON_TYPE_STICK:
return "stick";
case META_BUTTON_TYPE_UNSHADE:
return "unshade";
case META_BUTTON_TYPE_UNABOVE:
return "unabove";
case META_BUTTON_TYPE_UNSTICK:
return "unstick";
case META_BUTTON_TYPE_MENU: case META_BUTTON_TYPE_MENU:
return "menu"; return "menu";
case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND: case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
@ -5234,41 +5387,6 @@ meta_button_type_to_string (MetaButtonType type)
return "<unknown>"; return "<unknown>";
} }
MetaMenuIconType
meta_menu_icon_type_from_string (const char *str)
{
if (strcmp ("close", str) == 0)
return META_MENU_ICON_TYPE_CLOSE;
else if (strcmp ("maximize", str) == 0)
return META_MENU_ICON_TYPE_MAXIMIZE;
else if (strcmp ("minimize", str) == 0)
return META_MENU_ICON_TYPE_MINIMIZE;
else if (strcmp ("unmaximize", str) == 0)
return META_MENU_ICON_TYPE_UNMAXIMIZE;
else
return META_MENU_ICON_TYPE_LAST;
}
const char*
meta_menu_icon_type_to_string (MetaMenuIconType type)
{
switch (type)
{
case META_MENU_ICON_TYPE_CLOSE:
return "close";
case META_MENU_ICON_TYPE_MAXIMIZE:
return "maximize";
case META_MENU_ICON_TYPE_MINIMIZE:
return "minimize";
case META_MENU_ICON_TYPE_UNMAXIMIZE:
return "unmaximize";
case META_MENU_ICON_TYPE_LAST:
break;
}
return "<unknown>";
}
MetaFramePiece MetaFramePiece
meta_frame_piece_from_string (const char *str) meta_frame_piece_from_string (const char *str)
{ {
@ -6044,3 +6162,34 @@ draw_bg_gradient_composite (const MetaTextureSpec *bg,
} }
} }
#endif #endif
guint
meta_theme_earliest_version_with_button (MetaButtonType type)
{
switch (type)
{
case META_BUTTON_TYPE_CLOSE:
case META_BUTTON_TYPE_MAXIMIZE:
case META_BUTTON_TYPE_MINIMIZE:
case META_BUTTON_TYPE_MENU:
case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
return 1;
case META_BUTTON_TYPE_SHADE:
case META_BUTTON_TYPE_ABOVE:
case META_BUTTON_TYPE_STICK:
case META_BUTTON_TYPE_UNSHADE:
case META_BUTTON_TYPE_UNABOVE:
case META_BUTTON_TYPE_UNSTICK:
return 2;
default:
meta_warning("Unknown button %d\n", type);
return 1;
}
}

View File

@ -100,11 +100,14 @@ struct _MetaFrameLayout
/* Whether title text will be displayed */ /* Whether title text will be displayed */
guint has_title : 1; guint has_title : 1;
/* Whether we should hide the buttons */
guint hide_buttons : 1;
/* Round corners */ /* Round corners */
guint top_left_corner_rounded : 1; guint top_left_corner_rounded_radius;
guint top_right_corner_rounded : 1; guint top_right_corner_rounded_radius;
guint bottom_left_corner_rounded : 1; guint bottom_left_corner_rounded_radius;
guint bottom_right_corner_rounded : 1; guint bottom_right_corner_rounded_radius;
}; };
struct _MetaButtonSpace struct _MetaButtonSpace
@ -145,6 +148,12 @@ struct _MetaFrameGeometry
MetaButtonSpace max_rect; MetaButtonSpace max_rect;
MetaButtonSpace min_rect; MetaButtonSpace min_rect;
MetaButtonSpace menu_rect; MetaButtonSpace menu_rect;
MetaButtonSpace shade_rect;
MetaButtonSpace above_rect;
MetaButtonSpace stick_rect;
MetaButtonSpace unshade_rect;
MetaButtonSpace unabove_rect;
MetaButtonSpace unstick_rect;
#define MAX_MIDDLE_BACKGROUNDS (MAX_BUTTONS_PER_CORNER - 2) #define MAX_MIDDLE_BACKGROUNDS (MAX_BUTTONS_PER_CORNER - 2)
GdkRectangle left_left_background; GdkRectangle left_left_background;
@ -156,10 +165,10 @@ struct _MetaFrameGeometry
/* End of button rects (if changed adjust memset hack) */ /* End of button rects (if changed adjust memset hack) */
/* Round corners */ /* Round corners */
guint top_left_corner_rounded : 1; guint top_left_corner_rounded_radius;
guint top_right_corner_rounded : 1; guint top_right_corner_rounded_radius;
guint bottom_left_corner_rounded : 1; guint bottom_left_corner_rounded_radius;
guint bottom_right_corner_rounded : 1; guint bottom_right_corner_rounded_radius;
}; };
typedef enum typedef enum
@ -438,6 +447,12 @@ typedef enum
META_BUTTON_TYPE_MAXIMIZE, META_BUTTON_TYPE_MAXIMIZE,
META_BUTTON_TYPE_MINIMIZE, META_BUTTON_TYPE_MINIMIZE,
META_BUTTON_TYPE_MENU, META_BUTTON_TYPE_MENU,
META_BUTTON_TYPE_SHADE,
META_BUTTON_TYPE_ABOVE,
META_BUTTON_TYPE_STICK,
META_BUTTON_TYPE_UNSHADE,
META_BUTTON_TYPE_UNABOVE,
META_BUTTON_TYPE_UNSTICK,
META_BUTTON_TYPE_LAST META_BUTTON_TYPE_LAST
} MetaButtonType; } MetaButtonType;
@ -503,6 +518,9 @@ struct _MetaFrameStyle
MetaDrawOpList *buttons[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST]; MetaDrawOpList *buttons[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST];
MetaDrawOpList *pieces[META_FRAME_PIECE_LAST]; MetaDrawOpList *pieces[META_FRAME_PIECE_LAST];
MetaFrameLayout *layout; MetaFrameLayout *layout;
MetaColorSpec *window_background_color; /* can be NULL to use the standard
GTK theme engine */
guint8 window_background_alpha; /* 0=transparent; 255=opaque */
}; };
/* Kinds of frame... /* Kinds of frame...
@ -552,7 +570,7 @@ struct _MetaFrameStyleSet
MetaFrameStyleSet *parent; MetaFrameStyleSet *parent;
MetaFrameStyle *normal_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST]; MetaFrameStyle *normal_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST];
MetaFrameStyle *maximized_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *maximized_styles[META_FRAME_FOCUS_LAST];
MetaFrameStyle *shaded_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *shaded_styles[META_FRAME_RESIZE_LAST][META_FRAME_FOCUS_LAST];
MetaFrameStyle *maximized_and_shaded_styles[META_FRAME_FOCUS_LAST]; MetaFrameStyle *maximized_and_shaded_styles[META_FRAME_FOCUS_LAST];
}; };
@ -566,16 +584,19 @@ struct _MetaTheme
char *copyright; char *copyright;
char *date; char *date;
char *description; char *description;
guint format_version;
GHashTable *integer_constants; GHashTable *integer_constants;
GHashTable *float_constants; GHashTable *float_constants;
GHashTable *color_constants;
GHashTable *images_by_filename; GHashTable *images_by_filename;
GHashTable *layouts_by_name; GHashTable *layouts_by_name;
GHashTable *draw_op_lists_by_name; GHashTable *draw_op_lists_by_name;
GHashTable *styles_by_name; GHashTable *styles_by_name;
GHashTable *style_sets_by_name; GHashTable *style_sets_by_name;
MetaFrameStyleSet *style_sets_by_type[META_FRAME_TYPE_LAST]; MetaFrameStyleSet *style_sets_by_type[META_FRAME_TYPE_LAST];
MetaDrawOpList *menu_icons[META_MENU_ICON_TYPE_LAST][N_GTK_STATES];
GdkPixbuf *fallback_icon, *fallback_mini_icon;
}; };
struct _MetaPositionExprEnv struct _MetaPositionExprEnv
@ -616,7 +637,8 @@ void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout
int client_width, int client_width,
int client_height, int client_height,
const MetaButtonLayout *button_layout, const MetaButtonLayout *button_layout,
MetaFrameGeometry *fgeom); MetaFrameGeometry *fgeom,
MetaTheme *theme);
gboolean meta_frame_layout_validate (const MetaFrameLayout *layout, gboolean meta_frame_layout_validate (const MetaFrameLayout *layout,
GError **error); GError **error);
@ -703,6 +725,7 @@ void meta_frame_style_draw (MetaFrameStyle *style,
gboolean meta_frame_style_validate (MetaFrameStyle *style, gboolean meta_frame_style_validate (MetaFrameStyle *style,
guint current_theme_version,
GError **error); GError **error);
MetaFrameStyleSet* meta_frame_style_set_new (MetaFrameStyleSet *parent); MetaFrameStyleSet* meta_frame_style_set_new (MetaFrameStyleSet *parent);
@ -722,6 +745,7 @@ gboolean meta_theme_validate (MetaTheme *theme,
GError **error); GError **error);
GdkPixbuf* meta_theme_load_image (MetaTheme *theme, GdkPixbuf* meta_theme_load_image (MetaTheme *theme,
const char *filename, const char *filename,
guint size_of_theme_icons,
GError **error); GError **error);
MetaFrameStyle* meta_theme_get_frame_style (MetaTheme *theme, MetaFrameStyle* meta_theme_get_frame_style (MetaTheme *theme,
@ -749,13 +773,6 @@ void meta_theme_draw_frame (MetaTheme *theme,
GdkPixbuf *mini_icon, GdkPixbuf *mini_icon,
GdkPixbuf *icon); GdkPixbuf *icon);
void meta_theme_draw_menu_icon (MetaTheme *theme,
GtkWidget *widget,
GdkDrawable *drawable,
const GdkRectangle *clip,
MetaRectangle offset_rect,
MetaMenuIconType type);
void meta_theme_get_frame_borders (MetaTheme *theme, void meta_theme_get_frame_borders (MetaTheme *theme,
MetaFrameType type, MetaFrameType type,
int text_height, int text_height,
@ -808,6 +825,14 @@ gboolean meta_theme_lookup_float_constant (MetaTheme *theme,
const char *name, const char *name,
double *value); double *value);
gboolean meta_theme_define_color_constant (MetaTheme *theme,
const char *name,
const char *value,
GError **error);
gboolean meta_theme_lookup_color_constant (MetaTheme *theme,
const char *name,
char **value);
char* meta_theme_replace_constants (MetaTheme *theme, char* meta_theme_replace_constants (MetaTheme *theme,
const char *expr, const char *expr,
GError **err); GError **err);
@ -826,10 +851,9 @@ MetaGtkColorComponent meta_color_component_from_string (const char *s
const char* meta_color_component_to_string (MetaGtkColorComponent component); const char* meta_color_component_to_string (MetaGtkColorComponent component);
MetaButtonState meta_button_state_from_string (const char *str); MetaButtonState meta_button_state_from_string (const char *str);
const char* meta_button_state_to_string (MetaButtonState state); const char* meta_button_state_to_string (MetaButtonState state);
MetaButtonType meta_button_type_from_string (const char *str); MetaButtonType meta_button_type_from_string (const char *str,
MetaTheme *theme);
const char* meta_button_type_to_string (MetaButtonType type); const char* meta_button_type_to_string (MetaButtonType type);
MetaMenuIconType meta_menu_icon_type_from_string (const char *str);
const char* meta_menu_icon_type_to_string (MetaMenuIconType type);
MetaFramePiece meta_frame_piece_from_string (const char *str); MetaFramePiece meta_frame_piece_from_string (const char *str);
const char* meta_frame_piece_to_string (MetaFramePiece piece); const char* meta_frame_piece_to_string (MetaFramePiece piece);
MetaFrameState meta_frame_state_from_string (const char *str); MetaFrameState meta_frame_state_from_string (const char *str);
@ -851,5 +875,19 @@ const char* meta_gtk_arrow_to_string (GtkArrowType a
MetaImageFillType meta_image_fill_type_from_string (const char *str); MetaImageFillType meta_image_fill_type_from_string (const char *str);
const char* meta_image_fill_type_to_string (MetaImageFillType fill_type); const char* meta_image_fill_type_to_string (MetaImageFillType fill_type);
guint meta_theme_earliest_version_with_button (MetaButtonType type);
#define META_THEME_ALLOWS(theme, feature) (theme->format_version >= feature)
/* What version of the theme file format were various features introduced in? */
#define META_THEME_SHADE_STICK_ABOVE_BUTTONS 2
#define META_THEME_UBIQUITOUS_CONSTANTS 2
#define META_THEME_VARIED_ROUND_CORNERS 2
#define META_THEME_IMAGES_FROM_ICON_THEMES 2
#define META_THEME_UNRESIZABLE_SHADED_STYLES 2
#define META_THEME_DEGREES_IN_ARCS 2
#define META_THEME_HIDDEN_BUTTONS 2
#define META_THEME_COLOR_CONSTANTS 2
#define META_THEME_FRAME_BACKGROUNDS 2
#endif #endif

View File

@ -30,6 +30,7 @@
#include "menu.h" #include "menu.h"
#include "core.h" #include "core.h"
#include "theme.h" #include "theme.h"
#include "iconcache.h"
#include "inlinepixbufs.h" #include "inlinepixbufs.h"
@ -736,6 +737,7 @@ meta_ui_set_current_theme (const char *name,
gboolean force_reload) gboolean force_reload)
{ {
meta_theme_set_current (name, force_reload); meta_theme_set_current (name, force_reload);
meta_invalidate_default_icons ();
} }
gboolean gboolean

View File

@ -110,7 +110,6 @@ static void meta_window_flush_calc_showing (MetaWindow *window);
static void meta_window_unqueue_move_resize (MetaWindow *window); static void meta_window_unqueue_move_resize (MetaWindow *window);
static void meta_window_update_icon_now (MetaWindow *window);
static void meta_window_unqueue_update_icon (MetaWindow *window); static void meta_window_unqueue_update_icon (MetaWindow *window);
static gboolean queue_calc_showing_func (MetaWindow *window, static gboolean queue_calc_showing_func (MetaWindow *window,
@ -5484,7 +5483,7 @@ redraw_icon (MetaWindow *window)
meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow); meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow);
} }
static void void
meta_window_update_icon_now (MetaWindow *window) meta_window_update_icon_now (MetaWindow *window)
{ {
GdkPixbuf *icon; GdkPixbuf *icon;

View File

@ -607,4 +607,7 @@ void meta_window_set_user_time (MetaWindow *window,
void meta_window_set_demands_attention (MetaWindow *window); void meta_window_set_demands_attention (MetaWindow *window);
void meta_window_unset_demands_attention (MetaWindow *window); void meta_window_unset_demands_attention (MetaWindow *window);
void meta_window_update_icon_now (MetaWindow *window);
#endif #endif