summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas James Alexander Thurman <tthurman@src.gnome.org>2006-10-07 16:56:47 +0000
committerThomas James Alexander Thurman <tthurman@src.gnome.org>2006-10-07 16:56:47 +0000
commit90359a5346afdf3aa5a6629f290f9a1499c6a7c3 (patch)
treedee3d86b68e889ddaf1b8aa5775d038b990ace9e
parent9e341dd4d8afc4ad54bc87bf2015316b570234ee (diff)
downloadmetacity-90359a5346afdf3aa5a6629f290f9a1499c6a7c3.tar.gz
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)
-rw-r--r--ChangeLog164
-rw-r--r--src/common.h17
-rw-r--r--src/core.c70
-rw-r--r--src/core.h10
-rw-r--r--src/frame.c3
-rw-r--r--src/frames.c411
-rw-r--r--src/frames.h6
-rw-r--r--src/iconcache.c38
-rw-r--r--src/iconcache.h13
-rw-r--r--src/main.c2
-rw-r--r--src/prefs.c46
-rw-r--r--src/theme-parser.c618
-rw-r--r--src/theme.c499
-rw-r--r--src/theme.h80
-rw-r--r--src/ui.c2
-rw-r--r--src/window.c3
-rw-r--r--src/window.h3
17 files changed, 1466 insertions, 519 deletions
diff --git a/ChangeLog b/ChangeLog
index e47448ba..377b988f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
* src/metacity-dialog.c (kill_window_question): Be nice to
diff --git a/src/common.h b/src/common.h
index e5602d82..7a53aa7d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -46,7 +46,8 @@ typedef enum
META_FRAME_ALLOWS_SHADE = 1 << 10,
META_FRAME_ALLOWS_MOVE = 1 << 11,
META_FRAME_FULLSCREEN = 1 << 12,
- META_FRAME_IS_FLASHING = 1 << 13
+ META_FRAME_IS_FLASHING = 1 << 13,
+ META_FRAME_ABOVE = 1 << 14
} MetaFrameFlags;
typedef enum
@@ -131,7 +132,13 @@ typedef enum
META_GRAB_OP_CLICKING_MAXIMIZE,
META_GRAB_OP_CLICKING_UNMAXIMIZE,
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;
typedef enum
@@ -226,6 +233,12 @@ typedef enum
META_BUTTON_FUNCTION_MINIMIZE,
META_BUTTON_FUNCTION_MAXIMIZE,
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
} MetaButtonFunction;
diff --git a/src/core.c b/src/core.c
index 32ce9732..832e0b3e 100644
--- a/src/core.c
+++ b/src/core.c
@@ -29,6 +29,17 @@
#include "workspace.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 *
get_window (Display *xdisplay,
Window frame_xwindow)
@@ -63,6 +74,19 @@ meta_core_get_client_size (Display *xdisplay,
}
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
meta_core_titlebar_is_onscreen (Display *xdisplay,
Window frame_xwindow)
{
@@ -369,6 +393,24 @@ meta_core_unstick (Display *xdisplay,
}
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
meta_core_stick (Display *xdisplay,
Window frame_xwindow)
{
@@ -712,3 +754,31 @@ meta_core_increment_event_serial (Display *xdisplay)
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);
+ }
+}
+
diff --git a/src/core.h b/src/core.h
index 6d6da141..1f0f1825 100644
--- a/src/core.h
+++ b/src/core.h
@@ -37,6 +37,10 @@ void meta_core_get_client_size (Display *xdisplay,
gboolean meta_core_titlebar_is_onscreen (Display *xdisplay,
Window frame_xwindow);
+gboolean meta_core_window_has_frame (Display *xdisplay,
+ Window frame_xwindow);
+
+
Window meta_core_get_client_xwindow (Display *xdisplay,
Window frame_xwindow);
@@ -106,6 +110,10 @@ void meta_core_unstick (Display *xdisplay,
Window frame_xwindow);
void meta_core_stick (Display *xdisplay,
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,
Window frame_xwindow,
int new_workspace);
@@ -175,6 +183,8 @@ void meta_core_increment_event_serial (Display *display);
int meta_ui_get_last_event_serial (Display *xdisplay);
+void meta_invalidate_default_icons (void);
+
#endif
diff --git a/src/frame.c b/src/frame.c
index 467e36b3..922443d3 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -279,6 +279,9 @@ meta_frame_get_flags (MetaFrame *frame)
if (frame->is_flashing)
flags |= META_FRAME_IS_FLASHING;
+ if (frame->window->wm_state_above)
+ flags |= META_FRAME_ABOVE;
+
return flags;
}
diff --git a/src/frames.c b/src/frames.c
index c5827dc1..a2971dec 100644
--- a/src/frames.c
+++ b/src/frames.c
@@ -24,6 +24,7 @@
*/
#include <config.h>
+#include <math.h>
#include "boxes.h"
#include "frames.h"
#include "util.h"
@@ -757,10 +758,10 @@ meta_frames_apply_shapes (MetaFrames *frames,
meta_frames_calc_geometry (frames, frame, &fgeom);
- if (!(fgeom.top_left_corner_rounded ||
- fgeom.top_right_corner_rounded ||
- fgeom.bottom_left_corner_rounded ||
- fgeom.bottom_right_corner_rounded ||
+ if (!(fgeom.top_left_corner_rounded_radius != 0 ||
+ fgeom.top_right_corner_rounded_radius != 0 ||
+ fgeom.bottom_left_corner_rounded_radius != 0 ||
+ fgeom.bottom_right_corner_rounded_radius != 0 ||
window_has_shape))
{
if (frame->shape_applied)
@@ -785,102 +786,72 @@ meta_frames_apply_shapes (MetaFrames *frames,
corners_xregion = XCreateRegion ();
- if (fgeom.top_left_corner_rounded)
+ if (fgeom.top_left_corner_rounded_radius != 0)
{
- xrect.x = 0;
- xrect.y = 0;
- xrect.width = 5;
- xrect.height = 1;
-
- XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+ const int radius = fgeom.top_left_corner_rounded_radius;
+ int i;
- 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);
+ for (i=0; i<radius; i++)
+ {
+ const int width = 1 + (radius - floor(sqrt(radius*radius - (radius-i)*(radius-i))));
+ xrect.x = 0;
+ xrect.y = i;
+ xrect.width = width;
+ xrect.height = 1;
+
+ 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;
- xrect.y = 0;
- xrect.width = 5;
- xrect.height = 1;
-
- XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+ const int radius = fgeom.top_right_corner_rounded_radius;
+ int i;
- 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);
+ 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;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+ }
}
- if (fgeom.bottom_left_corner_rounded)
+ if (fgeom.bottom_left_corner_rounded_radius != 0)
{
- xrect.x = 0;
- xrect.y = new_window_height - 1;
- xrect.width = 5;
- xrect.height = 1;
-
- 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);
+ 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.y = new_window_height - i;
+ xrect.width = width;
+ xrect.height = 1;
+
+ 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;
- xrect.y = new_window_height - 1;
- xrect.width = 5;
- xrect.height = 1;
-
- 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);
+ const int radius = fgeom.bottom_right_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 = new_window_width - width;
+ xrect.y = new_window_height - i;
+ xrect.width = width;
+ xrect.height = 1;
+
+ XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+ }
}
window_xregion = XCreateRegion ();
@@ -1102,6 +1073,24 @@ show_tip_now (MetaFrames *frames)
case META_FRAME_CONTROL_UNMAXIMIZE:
tiptext = _("Unmaximize Window");
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:
break;
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_MINIMIZE ||
control == META_FRAME_CONTROL_DELETE ||
+ control == META_FRAME_CONTROL_SHADE ||
+ control == META_FRAME_CONTROL_UNSHADE ||
+ control == META_FRAME_CONTROL_ABOVE ||
+ control == META_FRAME_CONTROL_UNABOVE ||
+ control == META_FRAME_CONTROL_STICK ||
+ control == META_FRAME_CONTROL_UNSTICK ||
control == META_FRAME_CONTROL_MENU))
{
MetaGrabOp op = META_GRAB_OP_NONE;
@@ -1329,6 +1324,24 @@ meta_frames_button_press_event (GtkWidget *widget,
case META_FRAME_CONTROL_MENU:
op = META_GRAB_OP_CLICKING_MENU;
break;
+ case META_FRAME_CONTROL_SHADE:
+ op = META_GRAB_OP_CLICKING_SHADE;
+ break;
+ case META_FRAME_CONTROL_UNSHADE:
+ op = META_GRAB_OP_CLICKING_UNSHADE;
+ break;
+ case META_FRAME_CONTROL_ABOVE:
+ op = META_GRAB_OP_CLICKING_ABOVE;
+ break;
+ case META_FRAME_CONTROL_UNABOVE:
+ op = META_GRAB_OP_CLICKING_UNABOVE;
+ break;
+ case META_FRAME_CONTROL_STICK:
+ op = META_GRAB_OP_CLICKING_STICK;
+ break;
+ case META_FRAME_CONTROL_UNSTICK:
+ op = META_GRAB_OP_CLICKING_UNSTICK;
+ break;
default:
g_assert_not_reached ();
break;
@@ -1567,6 +1580,48 @@ meta_frames_button_release_event (GtkWidget *widget,
meta_core_end_grab_op (gdk_display, event->time);
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:
break;
}
@@ -1590,6 +1645,7 @@ meta_frames_update_prelit_control (MetaFrames *frames,
MetaFrameControl old_control;
MetaCursor cursor;
+
meta_verbose ("Updating prelit control from %u to %u\n",
frame->prelit_control, control);
@@ -1613,6 +1669,18 @@ meta_frames_update_prelit_control (MetaFrames *frames,
break;
case META_FRAME_CONTROL_UNMAXIMIZE:
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:
cursor = META_CURSOR_SE_RESIZE;
break;
@@ -1650,6 +1718,12 @@ meta_frames_update_prelit_control (MetaFrames *frames,
case META_FRAME_CONTROL_MINIMIZE:
case META_FRAME_CONTROL_MAXIMIZE:
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:
/* leave control set */
break;
@@ -1698,6 +1772,12 @@ meta_frames_motion_notify_event (GtkWidget *widget,
case META_GRAB_OP_CLICKING_MINIMIZE:
case META_GRAB_OP_CLICKING_MAXIMIZE:
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;
int x, y;
@@ -1716,8 +1796,20 @@ meta_frames_motion_notify_event (GtkWidget *widget,
grab_op == META_GRAB_OP_CLICKING_MINIMIZE) ||
(control == META_FRAME_CONTROL_MAXIMIZE &&
(grab_op == META_GRAB_OP_CLICKING_MAXIMIZE ||
- grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE))))
- control = META_FRAME_CONTROL_NONE;
+ 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;
/* Update prelit control and cursor */
meta_frames_update_prelit_control (frames, frame, control);
@@ -2097,6 +2189,42 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
else
button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
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:
if (grab_op == META_GRAB_OP_CLICKING_DELETE)
button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED;
@@ -2182,17 +2310,52 @@ static void
meta_frames_set_window_background (MetaFrames *frames,
MetaUIFrame *frame)
{
- gtk_style_set_background (GTK_WIDGET (frames)->style,
- frame->window, GTK_STATE_NORMAL);
+ MetaFrameFlags flags;
+ MetaFrameType type;
+ MetaFrameStyle *style;
+ gboolean frame_exists;
-#if 0
- /* This is what we want for transparent background */
- {
- col.pixel = 0;
- gdk_window_set_background (window, &col);
- }
-#endif
-}
+ 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,
+ frame->window, GTK_STATE_NORMAL);
+ }
+ }
static gboolean
meta_frames_enter_notify_event (GtkWidget *widget,
@@ -2259,6 +2422,24 @@ control_rect (MetaFrameControl control,
case META_FRAME_CONTROL_UNMAXIMIZE:
rect = &fgeom->max_rect.visible;
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:
break;
case META_FRAME_CONTROL_RESIZE_S:
@@ -2336,6 +2517,36 @@ get_control (MetaFrames *frames,
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,
* in case of overlap.
*/
diff --git a/src/frames.h b/src/frames.h
index 1d674eab..c4ad8bfb 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -38,6 +38,12 @@ typedef enum
META_FRAME_CONTROL_MINIMIZE,
META_FRAME_CONTROL_MAXIMIZE,
META_FRAME_CONTROL_UNMAXIMIZE,
+ META_FRAME_CONTROL_SHADE,
+ META_FRAME_CONTROL_UNSHADE,
+ META_FRAME_CONTROL_ABOVE,
+ META_FRAME_CONTROL_UNABOVE,
+ META_FRAME_CONTROL_STICK,
+ META_FRAME_CONTROL_UNSTICK,
META_FRAME_CONTROL_RESIZE_SE,
META_FRAME_CONTROL_RESIZE_S,
META_FRAME_CONTROL_RESIZE_SW,
diff --git a/src/iconcache.c b/src/iconcache.c
index 5c8ac19f..939a0895 100644
--- a/src/iconcache.c
+++ b/src/iconcache.c
@@ -25,6 +25,7 @@
#include "iconcache.h"
#include "ui.h"
#include "errors.h"
+#include "theme.h"
#include <X11/Xatom.h>
@@ -499,19 +500,6 @@ get_kwm_win_icon (MetaDisplay *display,
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
meta_icon_cache_init (MetaIconCache *icon_cache)
{
@@ -830,13 +818,23 @@ meta_read_icons (MetaScreen *screen,
if (icon_cache->want_fallback &&
icon_cache->origin < USING_FALLBACK_ICON)
{
- get_fallback_icons (screen,
- iconp,
- ideal_width,
- ideal_height,
- mini_iconp,
- ideal_mini_width,
- ideal_mini_height);
+ MetaTheme *theme = meta_theme_get_current ();
+
+ if (theme->fallback_icon == NULL || theme->fallback_mini_icon == NULL)
+ {
+ get_fallback_icons (screen,
+ iconp,
+ ideal_width,
+ ideal_height,
+ mini_iconp,
+ ideal_mini_width,
+ 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,
*iconp, *mini_iconp);
diff --git a/src/iconcache.h b/src/iconcache.h
index 1cb73a65..7a2ad7f3 100644
--- a/src/iconcache.h
+++ b/src/iconcache.h
@@ -28,6 +28,19 @@
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
{
int origin;
diff --git a/src/main.c b/src/main.c
index 49c30b8f..9b6c4a5c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -365,7 +365,7 @@ main (int argc, char **argv)
}
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");
/* Connect to SM as late as possible - but before managing display,
diff --git a/src/prefs.c b/src/prefs.c
index c5004911..3690a798 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -1381,10 +1381,42 @@ button_function_from_string (const char *str)
return META_BUTTON_FUNCTION_MAXIMIZE;
else if (strcmp (str, "close") == 0)
return META_BUTTON_FUNCTION_CLOSE;
- else
+ 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
+ /* don't know; give up */
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
update_button_layout (const char *value)
{
@@ -1435,6 +1467,11 @@ update_button_layout (const char *value)
new_layout.left_buttons[i] = f;
used[f] = TRUE;
++i;
+
+ f = button_opposite_function (f);
+
+ if (f != META_BUTTON_FUNCTION_LAST)
+ new_layout.left_buttons[i++] = f;
}
else
{
@@ -1473,7 +1510,12 @@ update_button_layout (const char *value)
new_layout.right_buttons[i] = f;
used[f] = TRUE;
++i;
- }
+
+ f = button_opposite_function (f);
+
+ if (f != META_BUTTON_FUNCTION_LAST)
+ new_layout.right_buttons[i++] = f;
+ }
else
{
meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
diff --git a/src/theme-parser.c b/src/theme-parser.c
index 1013c2b8..68db8e79 100644
--- a/src/theme-parser.c
+++ b/src/theme-parser.c
@@ -73,7 +73,9 @@ typedef enum
/* assigning style sets to windows */
STATE_WINDOW,
/* and menu icons */
- STATE_MENU_ICON
+ STATE_MENU_ICON,
+ /* fallback icons */
+ STATE_FALLBACK
} ParseState;
typedef struct
@@ -84,6 +86,7 @@ typedef struct
char *theme_file; /* theme filename */
char *theme_dir; /* dir the theme is inside */
MetaTheme *theme; /* theme being parsed */
+ guint format_version; /* version of format of theme file */
char *name; /* name of named thing being parsed */
MetaFrameLayout *layout; /* layout 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 */
MetaButtonType button_type; /* type of button/menuitem 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;
static void set_error (GError **err,
@@ -451,33 +452,48 @@ static gboolean
parse_positive_integer (const char *str,
int *val,
GMarkupParseContext *context,
+ MetaTheme *theme,
GError **error)
{
char *end;
long l;
+ int j;
*val = 0;
end = NULL;
- l = strtol (str, &end, 10);
+ /* Is str a constant? */
- if (end == NULL || end == str)
+ if (META_THEME_ALLOWS (theme, META_THEME_UBIQUITOUS_CONSTANTS) &&
+ meta_theme_lookup_int_constant (theme, str, &j))
{
- set_error (error, context, G_MARKUP_ERROR,
- G_MARKUP_ERROR_PARSE,
- _("Could not parse \"%s\" as an integer"),
- str);
- return FALSE;
+ /* Yes. */
+ l = j;
}
-
- if (*end != '\0')
+ else
{
- set_error (error, context, G_MARKUP_ERROR,
- G_MARKUP_ERROR_PARSE,
- _("Did not understand trailing characters \"%s\" in string \"%s\""),
- end, str);
- return FALSE;
+ /* No. Let's try parsing it instead. */
+
+ l = strtol (str, &end, 10);
+
+ if (end == NULL || end == str)
+ {
+ set_error (error, context, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Could not parse \"%s\" as an integer"),
+ str);
+ return FALSE;
+ }
+
+ if (*end != '\0')
+ {
+ set_error (error, context, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Did not understand trailing characters \"%s\" in string \"%s\""),
+ end, str);
+ return FALSE;
+ }
}
if (l < 0)
@@ -560,6 +576,41 @@ parse_boolean (const char *str,
}
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
parse_angle (const char *str,
double *val,
GMarkupParseContext *context,
@@ -624,17 +675,14 @@ parse_alpha (const char *str,
if (!parse_double (split[i], &v, context, error))
{
- set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- _("Could not parse \"%s\" as a floating point number"),
- split[i]);
-
+ /* clear up, but don't set error: it was set by parse_double */
g_strfreev (split);
meta_alpha_gradient_spec_free (spec);
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,
_("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;
}
+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
parse_title_scale (const char *str,
double *val,
@@ -716,8 +783,8 @@ parse_toplevel_element (GMarkupParseContext *context,
{
const char *name;
const char *value;
- int ival;
- double dval;
+ int ival = 0;
+ double dval = 0.0;
if (!locate_attributes (context, element_name, attribute_names, attribute_values,
error,
@@ -741,11 +808,9 @@ parse_toplevel_element (GMarkupParseContext *context,
return;
}
- if (strchr (value, '.'))
+ if (strchr (value, '.') && parse_double (value, &dval, context, error))
{
- dval = 0.0;
- if (!parse_double (value, &dval, context, error))
- return;
+ g_clear_error (error);
if (!meta_theme_define_float_constant (info->theme,
name,
@@ -756,11 +821,9 @@ parse_toplevel_element (GMarkupParseContext *context,
return;
}
}
- else
+ else if (parse_positive_integer (value, &ival, context, info->theme, error))
{
- ival = 0;
- if (!parse_positive_integer (value, &ival, context, error))
- return;
+ g_clear_error (error);
if (!meta_theme_define_int_constant (info->theme,
name,
@@ -771,6 +834,19 @@ parse_toplevel_element (GMarkupParseContext *context,
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);
}
@@ -784,11 +860,13 @@ parse_toplevel_element (GMarkupParseContext *context,
const char *rounded_top_right = NULL;
const char *rounded_bottom_left = NULL;
const char *rounded_bottom_right = NULL;
+ const char *hide_buttons = NULL;
gboolean has_title_val;
- gboolean rounded_top_left_val;
- gboolean rounded_top_right_val;
- gboolean rounded_bottom_left_val;
- gboolean rounded_bottom_right_val;
+ guint rounded_top_left_val;
+ guint rounded_top_right_val;
+ guint rounded_bottom_left_val;
+ guint rounded_bottom_right_val;
+ gboolean hide_buttons_val;
double title_scale_val;
MetaFrameLayout *parent_layout;
@@ -800,6 +878,7 @@ parse_toplevel_element (GMarkupParseContext *context,
"rounded_top_right", &rounded_top_right,
"rounded_bottom_left", &rounded_bottom_left,
"rounded_bottom_right", &rounded_bottom_right,
+ "hide_buttons", &hide_buttons,
NULL))
return;
@@ -815,18 +894,22 @@ parse_toplevel_element (GMarkupParseContext *context,
if (has_title && !parse_boolean (has_title, &has_title_val, context, error))
return;
- rounded_top_left_val = FALSE;
- rounded_top_right_val = FALSE;
- rounded_bottom_left_val = FALSE;
- rounded_bottom_right_val = FALSE;
+ hide_buttons_val = FALSE;
+ if (hide_buttons && !parse_boolean (hide_buttons, &hide_buttons_val, context, error))
+ return;
+
+ 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_boolean (rounded_top_left, &rounded_top_left_val, context, error))
+ if (rounded_top_left && !parse_rounding (rounded_top_left, &rounded_top_left_val, context, info->theme, error))
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;
- 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;
- 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;
title_scale_val = 1.0;
@@ -864,20 +947,23 @@ parse_toplevel_element (GMarkupParseContext *context,
if (has_title) /* only if explicit, otherwise inherit */
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)
info->layout->title_scale = title_scale_val;
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)
- 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)
- 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)
- 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);
@@ -921,6 +1007,8 @@ parse_toplevel_element (GMarkupParseContext *context,
const char *name = NULL;
const char *parent = NULL;
const char *geometry = NULL;
+ const char *background = NULL;
+ const char *alpha = NULL;
MetaFrameStyle *parent_style;
MetaFrameLayout *layout;
@@ -928,6 +1016,8 @@ parse_toplevel_element (GMarkupParseContext *context,
error,
"name", &name, "parent", &parent,
"geometry", &geometry,
+ "background", &background,
+ "alpha", &alpha,
NULL))
return;
@@ -992,6 +1082,40 @@ parse_toplevel_element (GMarkupParseContext *context,
meta_frame_layout_ref (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);
push_state (info, STATE_FRAME_STYLE);
@@ -1110,84 +1234,52 @@ parse_toplevel_element (GMarkupParseContext *context,
}
else if (ELEMENT_IS ("menu_icon"))
{
- const char *function = NULL;
- const char *state = NULL;
- const char *draw_ops = NULL;
+ /* Not supported any more, but we have to parse it if they include it,
+ * for backwards compatibility.
+ */
+ 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,
error,
- "function", &function,
- "state", &state,
- "draw_ops", &draw_ops,
+ "icon", &icon,
+ "mini_icon", &mini_icon,
NULL))
return;
- if (function == NULL)
- {
- set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- _("No \"%s\" attribute on <%s> element"),
- "function", element_name);
- return;
- }
-
- if (state == NULL)
- {
- set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- _("No \"%s\" attribute on <%s> element"),
- "state", element_name);
- return;
- }
-
- info->menu_icon_type = meta_menu_icon_type_from_string (function);
- if (info->menu_icon_type == META_BUTTON_TYPE_LAST)
+ if (icon)
{
- set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- _("Unknown function \"%s\" for menu icon"),
- function);
- return;
- }
+ if (info->theme->fallback_icon != NULL)
+ {
+ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ _("Theme already has a fallback icon"));
+ return;
+ }
- info->menu_icon_state = meta_gtk_state_from_string (state);
- 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;
+ info->theme->fallback_icon = meta_theme_load_image(info->theme, icon, 64, error);
}
- g_assert (info->op_list == NULL);
-
- if (draw_ops)
+ if (mini_icon)
{
- MetaDrawOpList *op_list;
-
- op_list = meta_theme_lookup_draw_op_list (info->theme,
- draw_ops);
-
- if (op_list == NULL)
+ if (info->theme->fallback_mini_icon != NULL)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- _("No <draw_ops> with the name \"%s\" has been defined"),
- draw_ops);
+ _("Theme already has a fallback mini_icon"));
return;
}
- meta_draw_op_list_ref (op_list);
- info->op_list = op_list;
+ info->theme->fallback_mini_icon = meta_theme_load_image(info->theme, mini_icon, 16, error);
}
- push_state (info, STATE_MENU_ICON);
+ push_state (info, STATE_FALLBACK);
}
- else
+ else
{
set_error (error, context,
G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
@@ -1293,7 +1385,7 @@ parse_distance (GMarkupParseContext *context,
}
val = 0;
- if (!parse_positive_integer (value, &val, context, error))
+ if (!parse_positive_integer (value, &val, context, info->theme, error))
return;
g_assert (val >= 0); /* yeah, "non-negative" not "positive" get over it */
@@ -1471,19 +1563,19 @@ parse_border (GMarkupParseContext *context,
}
top_val = 0;
- if (!parse_positive_integer (top, &top_val, context, error))
+ if (!parse_positive_integer (top, &top_val, context, info->theme, error))
return;
bottom_val = 0;
- if (!parse_positive_integer (bottom, &bottom_val, context, error))
+ if (!parse_positive_integer (bottom, &bottom_val, context, info->theme, error))
return;
left_val = 0;
- if (!parse_positive_integer (left, &left_val, context, error))
+ if (!parse_positive_integer (left, &left_val, context, info->theme, error))
return;
right_val = 0;
- if (!parse_positive_integer (right, &right_val, context, error))
+ if (!parse_positive_integer (right, &right_val, context, info->theme, error))
return;
g_assert (info->layout);
@@ -1697,23 +1789,23 @@ parse_draw_op_element (GMarkupParseContext *context,
dash_on_val = 0;
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;
dash_off_val = 0;
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;
width_val = 0;
if (width &&
- !parse_positive_integer (width, &width_val, context, error))
+ !parse_positive_integer (width, &width_val, context, info->theme, error))
return;
/* Check last so we don't have to free it when other
* stuff fails
*/
- color_spec = meta_color_spec_new_from_string (color, error);
+ color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL)
{
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
* stuff fails
*/
- color_spec = meta_color_spec_new_from_string (color, error);
+ color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL)
{
add_context_to_error (error, context);
@@ -1845,6 +1937,8 @@ parse_draw_op_element (GMarkupParseContext *context,
const char *filled;
const char *start_angle;
const char *extent_angle;
+ const char *from;
+ const char *to;
gboolean filled_val;
double start_angle_val;
double extent_angle_val;
@@ -1858,6 +1952,8 @@ parse_draw_op_element (GMarkupParseContext *context,
"filled", &filled,
"start_angle", &start_angle,
"extent_angle", &extent_angle,
+ "from", &from,
+ "to", &to,
NULL))
return;
@@ -1896,20 +1992,40 @@ parse_draw_op_element (GMarkupParseContext *context,
return;
}
- if (start_angle == NULL)
+ if (META_THEME_ALLOWS (info->theme, META_THEME_DEGREES_IN_ARCS) )
{
- set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- _("No \"start_angle\" attribute on element <%s>"), element_name);
- return;
- }
+ 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)
+ 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
{
- set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- _("No \"extent_angle\" attribute on element <%s>"), element_name);
- return;
+ if (start_angle == NULL)
+ {
+ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ _("No \"start_angle\" attribute on element <%s>"), element_name);
+ return;
+ }
+
+ if (extent_angle == NULL)
+ {
+ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ _("No \"extent_angle\" attribute on element <%s>"), element_name);
+ return;
+ }
}
-
+
+
if (!check_expression (x, FALSE, info->theme, context, error))
return;
@@ -1922,12 +2038,32 @@ parse_draw_op_element (GMarkupParseContext *context,
if (!check_expression (height, FALSE, info->theme, context, error))
return;
- if (!parse_angle (start_angle, &start_angle_val, context, error))
- return;
-
- if (!parse_angle (extent_angle, &extent_angle_val, context, error))
- return;
+ if (start_angle == NULL)
+ {
+ if (!parse_angle (from, &start_angle_val, context, error))
+ 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))
+ return;
+ }
+
filled_val = FALSE;
if (filled && !parse_boolean (filled, &filled_val, context, error))
return;
@@ -1935,7 +2071,7 @@ parse_draw_op_element (GMarkupParseContext *context,
/* Check last so we don't have to free it when other
* stuff fails
*/
- color_spec = meta_color_spec_new_from_string (color, error);
+ color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL)
{
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
* 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 (alpha_spec)
@@ -2254,7 +2390,7 @@ parse_draw_op_element (GMarkupParseContext *context,
"x", &x, "y", &y,
"width", &width, "height", &height,
"alpha", &alpha, "filename", &filename,
- "colorize", &colorize,
+ "colorize", &colorize,
"fill_type", &fill_type,
NULL))
return;
@@ -2321,9 +2457,12 @@ parse_draw_op_element (GMarkupParseContext *context,
}
/* 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)
{
@@ -2333,7 +2472,7 @@ parse_draw_op_element (GMarkupParseContext *context,
if (colorize)
{
- colorize_spec = meta_color_spec_new_from_string (colorize, error);
+ colorize_spec = parse_color (info->theme, colorize, error);
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
* stuff fails
*/
- color_spec = meta_color_spec_new_from_string (color, error);
+ color_spec = parse_color (info->theme, color, error);
if (color_spec == NULL)
{
add_context_to_error (error, context);
@@ -3154,7 +3293,7 @@ parse_gradient_element (GMarkupParseContext *context,
return;
}
- color_spec = meta_color_spec_new_from_string (value, error);
+ color_spec = parse_color (info->theme, value, error);
if (color_spec == NULL)
{
add_context_to_error (error, context);
@@ -3281,7 +3420,7 @@ parse_style_element (GMarkupParseContext *context,
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)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
@@ -3290,6 +3429,18 @@ parse_style_element (GMarkupParseContext *context,
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);
if (info->button_state == META_BUTTON_STATE_LAST)
{
@@ -3421,8 +3572,9 @@ parse_style_set_element (GMarkupParseContext *context,
return;
}
- if (frame_state == META_FRAME_STATE_NORMAL)
+ switch (frame_state)
{
+ case META_FRAME_STATE_NORMAL:
if (resize == NULL)
{
set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
@@ -3440,13 +3592,51 @@ parse_style_set_element (GMarkupParseContext *context,
focus);
return;
}
- }
- else
- {
+
+ 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
+ {
+ 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)
+ {
+ set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ _("Should not have \"resize\" attribute on <%s> element for maximized/shaded states"),
+ element_name);
+ 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/shaded states"),
+ _("Should not have \"resize\" attribute on <%s> element for maximized states"),
element_name);
return;
}
@@ -3479,15 +3669,15 @@ parse_style_set_element (GMarkupParseContext *context,
info->style_set->maximized_styles[frame_focus] = frame_style;
break;
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,
- _("Style has already been specified for state %s focus %s"),
- state, focus);
+ _("Style has already been specified for state %s resize %s focus %s"),
+ state, resize, focus);
return;
}
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;
case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
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->filename = g_strdup (info->theme_file);
info->theme->dirname = g_strdup (info->theme_dir);
+ info->theme->format_version = info->format_version;
push_state (info, STATE_THEME);
}
@@ -3762,6 +3953,11 @@ start_element_handler (GMarkupParseContext *context,
_("Element <%s> is not allowed inside a <%s> element"),
element_name, "window");
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);
if (!meta_frame_style_validate (info->style,
+ info->theme->format_version,
error))
{
add_context_to_error (error, context);
@@ -4007,16 +4204,9 @@ end_element_handler (GMarkupParseContext *context,
break;
case STATE_MENU_ICON:
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,
- _("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;
+ meta_draw_op_list_unref (info->op_list);
info->op_list = NULL;
}
pop_state (info);
@@ -4047,6 +4237,10 @@ end_element_handler (GMarkupParseContext *context,
pop_state (info);
g_assert (peek_state (info) == STATE_THEME);
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:
NO_TEXT ("window");
break;
+ case STATE_FALLBACK:
+ NO_TEXT ("fallback");
+ break;
}
}
-/* We change the filename when we break the format,
- * so themes can work with various metacity versions
- * (note, this is obsolete now because we are versioning
- * the directory this file is inside, so oh well)
+/* We were intending to put the version number
+ * in the subdirectory name, but we ended up
+ * using the filename instead. The "-1" survives
+ * 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"
+/* Highest version of the theme format to
+ * look out for.
+ */
+#define THEME_VERSION 2
+
+#define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml"
+
MetaTheme*
meta_theme_load (const char *theme_name,
GError **err)
@@ -4264,6 +4465,7 @@ meta_theme_load (const char *theme_name,
char *theme_file;
char *theme_dir;
MetaTheme *retval;
+ guint version;
text = NULL;
length = 0;
@@ -4275,11 +4477,14 @@ meta_theme_load (const char *theme_name,
if (meta_is_debugging ())
{
+ gchar *theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT,
+ THEME_VERSION);
+
/* Try in themes in our source tree */
theme_dir = g_build_filename ("./themes", theme_name, NULL);
theme_file = g_build_filename (theme_dir,
- THEME_FILENAME,
+ theme_filename,
NULL);
error = NULL;
@@ -4295,12 +4500,19 @@ meta_theme_load (const char *theme_name,
g_free (theme_file);
theme_file = NULL;
}
+ version = THEME_VERSION;
+
+ g_free (theme_filename);
}
- /* We try in home dir, then system dir for themes */
-
- if (text == NULL)
+ /* 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 */
+
theme_dir = g_build_filename (g_get_home_dir (),
".themes",
theme_name,
@@ -4308,7 +4520,7 @@ meta_theme_load (const char *theme_name,
NULL);
theme_file = g_build_filename (theme_dir,
- THEME_FILENAME,
+ theme_filename,
NULL);
error = NULL;
@@ -4324,45 +4536,57 @@ meta_theme_load (const char *theme_name,
g_free (theme_file);
theme_file = NULL;
}
- }
- if (text == NULL)
- {
- theme_dir = g_build_filename (METACITY_DATADIR,
- "themes",
- theme_name,
- THEME_SUBDIR,
- NULL);
+ if (text == NULL)
+ {
+ theme_dir = g_build_filename (METACITY_DATADIR,
+ "themes",
+ theme_name,
+ THEME_SUBDIR,
+ NULL);
- theme_file = g_build_filename (theme_dir,
- THEME_FILENAME,
- NULL);
+ theme_file = g_build_filename (theme_dir,
+ theme_filename,
+ NULL);
- error = NULL;
- if (!g_file_get_contents (theme_file,
- &text,
- &length,
- &error))
- {
- meta_warning (_("Failed to read theme from file %s: %s\n"),
- theme_file, error->message);
- g_propagate_error (err, error);
- g_free (theme_file);
- g_free (theme_dir);
- return NULL; /* all fallbacks failed */
+ error = NULL;
+ if (!g_file_get_contents (theme_file,
+ &text,
+ &length,
+ &error))
+ {
+ meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
+ theme_file, error->message);
+ g_error_free (error);
+ g_free (theme_dir);
+ g_free (theme_file);
+ theme_file = NULL;
+ }
}
+
+ g_free (theme_filename);
}
- g_assert (text);
+ 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 */
+ }
meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file);
+
parse_info_init (&info);
info.theme_name = theme_name;
/* pass ownership to info so we free it with the info */
info.theme_file = theme_file;
info.theme_dir = theme_dir;
+
+ info.format_version = version + 1;
context = g_markup_parse_context_new (&metacity_theme_parser,
0, &info, NULL);
@@ -4385,7 +4609,9 @@ meta_theme_load (const char *theme_name,
if (context)
g_markup_parse_context_free (context);
g_free (text);
-
+
+ info.theme->format_version = info.format_version;
+
if (error)
{
g_propagate_error (err, error);
diff --git a/src/theme.c b/src/theme.c
index 0bdd0628..702344f1 100644
--- a/src/theme.c
+++ b/src/theme.c
@@ -27,6 +27,8 @@
#include "util.h"
#include "gradient.h"
#include <gtk/gtkwidget.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkicontheme.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
@@ -394,8 +396,51 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout,
static MetaButtonSpace*
rect_for_function (MetaFrameGeometry *fgeom,
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)
{
case META_BUTTON_FUNCTION_MENU:
@@ -418,6 +463,19 @@ rect_for_function (MetaFrameGeometry *fgeom,
return &fgeom->close_rect;
else
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:
return NULL;
}
@@ -468,7 +526,8 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
int client_width,
int client_height,
const MetaButtonLayout *button_layout,
- MetaFrameGeometry *fgeom)
+ MetaFrameGeometry *fgeom,
+ MetaTheme *theme)
{
int i, n_left, n_right;
int x;
@@ -544,18 +603,20 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
right_func_rects[i] = NULL;
/* 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,
- button_layout->left_buttons[i]);
+ button_layout->left_buttons[i],
+ theme);
if (left_func_rects[n_left] != NULL)
++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,
- button_layout->right_buttons[i]);
+ button_layout->right_buttons[i],
+ theme);
if (right_func_rects[n_right] != NULL)
++n_right;
}
@@ -610,10 +671,28 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
break; /* Everything fits, bail out */
/* 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.
*/
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))
continue;
else if (strip_button (right_func_rects, right_bg_rects,
@@ -751,20 +830,20 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
else
min_size_for_rounding = 5;
- fgeom->top_left_corner_rounded = FALSE;
- fgeom->top_right_corner_rounded = FALSE;
- fgeom->bottom_left_corner_rounded = FALSE;
- fgeom->bottom_right_corner_rounded = FALSE;
+ fgeom->top_left_corner_rounded_radius = 0;
+ fgeom->top_right_corner_rounded_radius = 0;
+ fgeom->bottom_left_corner_rounded_radius = 0;
+ fgeom->bottom_right_corner_rounded_radius = 0;
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)
- 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)
- 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)
- fgeom->bottom_right_corner_rounded = layout->bottom_right_corner_rounded;
+ fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
}
MetaGradientSpec*
@@ -3743,6 +3822,9 @@ meta_frame_style_new (MetaFrameStyle *parent)
style->refcount = 1;
+ /* Default alpha is fully opaque */
+ style->window_background_alpha = 255;
+
style->parent = parent;
if (parent)
meta_frame_style_ref (parent);
@@ -3790,6 +3872,9 @@ meta_frame_style_unref (MetaFrameStyle *style)
if (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 */
if (style->parent)
meta_frame_style_unref (style->parent);
@@ -3841,6 +3926,7 @@ get_button (MetaFrameStyle *style,
gboolean
meta_frame_style_validate (MetaFrameStyle *style,
+ guint current_theme_version,
GError **error)
{
int i, j;
@@ -3855,7 +3941,9 @@ meta_frame_style_validate (MetaFrameStyle *style,
{
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,
META_THEME_ERROR_FAILED,
@@ -3907,6 +3995,30 @@ button_rect (MetaButtonType type,
*rect = fgeom->close_rect.visible;
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:
*rect = fgeom->max_rect.visible;
break;
@@ -4218,10 +4330,12 @@ meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
int 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->shaded_styles);
free_focus_styles (style_set->maximized_and_shaded_styles);
if (style_set->parent)
@@ -4243,47 +4357,53 @@ get_style (MetaFrameStyleSet *style_set,
style = NULL;
- if (state == META_FRAME_STATE_NORMAL)
+ switch (state)
{
- style = style_set->normal_styles[resize][focus];
+ 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];
- /* Try parent if we failed here */
- if (style == NULL && style_set->parent)
- style = get_style (style_set->parent, state, resize, focus);
+ /* Try parent if we failed here */
+ if (style == NULL && style_set->parent)
+ style = get_style (style_set->parent, state, resize, focus);
- /* Allow people to omit the vert/horz/none resize modes */
- if (style == NULL &&
- resize != META_FRAME_RESIZE_BOTH)
- style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
- }
- else
- {
- MetaFrameStyle **styles;
+ /* Allow people to omit the vert/horz/none resize modes */
+ if (style == NULL &&
+ resize != META_FRAME_RESIZE_BOTH)
+ style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
+ }
+ break;
+ default:
+ {
+ MetaFrameStyle **styles;
- styles = NULL;
+ styles = NULL;
- switch (state)
- {
- case META_FRAME_STATE_SHADED:
- styles = style_set->shaded_styles;
- break;
- case META_FRAME_STATE_MAXIMIZED:
- styles = style_set->maximized_styles;
- break;
- case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
- styles = style_set->maximized_and_shaded_styles;
- break;
- case META_FRAME_STATE_NORMAL:
- case META_FRAME_STATE_LAST:
- g_assert_not_reached ();
- break;
- }
+ switch (state)
+ {
+ case META_FRAME_STATE_MAXIMIZED:
+ styles = style_set->maximized_styles;
+ break;
+ case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
+ styles = style_set->maximized_and_shaded_styles;
+ break;
+ case META_FRAME_STATE_NORMAL:
+ case META_FRAME_STATE_SHADED:
+ case META_FRAME_STATE_LAST:
+ g_assert_not_reached ();
+ break;
+ }
- style = styles[focus];
+ style = styles[focus];
- /* Try parent if we failed here */
- if (style == NULL && style_set->parent)
- style = get_style (style_set->parent, state, resize, focus);
+ /* Try parent if we failed here */
+ if (style == NULL && style_set->parent)
+ style = get_style (style_set->parent, state, resize, focus);
+ }
}
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
meta_theme_free (MetaTheme *theme)
{
@@ -4476,34 +4585,15 @@ meta_theme_free (MetaTheme *theme)
if (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);
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
meta_theme_validate (MetaTheme *theme,
GError **error)
{
- int i, j;
+ int i;
g_return_val_if_fail (theme != NULL, FALSE);
@@ -4558,24 +4648,13 @@ meta_theme_validate (MetaTheme *theme,
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;
}
GdkPixbuf*
meta_theme_load_image (MetaTheme *theme,
const char *filename,
+ guint size_of_theme_icons,
GError **error)
{
GdkPixbuf *pixbuf;
@@ -4585,19 +4664,32 @@ meta_theme_load_image (MetaTheme *theme,
if (pixbuf == NULL)
{
- char *full_path;
-
- full_path = g_build_filename (theme->dirname, filename, NULL);
-
- pixbuf = gdk_pixbuf_new_from_file (full_path, error);
- if (pixbuf == NULL)
+
+ if (g_str_has_prefix (filename, "theme:") &&
+ META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES))
{
- g_free (full_path);
- return NULL;
- }
+ 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);
- g_free (full_path);
+ pixbuf = gdk_pixbuf_new_from_file (full_path, error);
+ if (pixbuf == NULL)
+ {
+ g_free (full_path);
+ return NULL;
+ }
+ g_free (full_path);
+ }
g_hash_table_replace (theme->images_by_filename,
g_strdup (filename),
pixbuf);
@@ -4749,7 +4841,8 @@ meta_theme_draw_frame (MetaTheme *theme,
flags,
client_width, client_height,
button_layout,
- &fgeom);
+ &fgeom,
+ theme);
meta_frame_style_draw (style,
widget,
@@ -4765,37 +4858,6 @@ meta_theme_draw_frame (MetaTheme *theme,
}
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
meta_theme_get_frame_borders (MetaTheme *theme,
MetaFrameType type,
int text_height,
@@ -4856,7 +4918,8 @@ meta_theme_calc_geometry (MetaTheme *theme,
flags,
client_width, client_height,
button_layout,
- fgeom);
+ fgeom,
+ theme);
}
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*
meta_gtk_widget_get_font_desc (GtkWidget *widget,
double scale,
@@ -5176,8 +5301,24 @@ meta_button_state_to_string (MetaButtonState state)
}
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)
return META_BUTTON_TYPE_CLOSE;
else if (strcmp ("maximize", str) == 0)
@@ -5213,7 +5354,19 @@ meta_button_type_to_string (MetaButtonType type)
return "maximize";
case META_BUTTON_TYPE_MINIMIZE:
return "minimize";
- case META_BUTTON_TYPE_MENU:
+ 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:
return "menu";
case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
return "left_left_background";
@@ -5234,41 +5387,6 @@ meta_button_type_to_string (MetaButtonType type)
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
meta_frame_piece_from_string (const char *str)
{
@@ -6044,3 +6162,34 @@ draw_bg_gradient_composite (const MetaTextureSpec *bg,
}
}
#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;
+ }
+}
diff --git a/src/theme.h b/src/theme.h
index f817dce4..005842ec 100644
--- a/src/theme.h
+++ b/src/theme.h
@@ -100,11 +100,14 @@ struct _MetaFrameLayout
/* Whether title text will be displayed */
guint has_title : 1;
+ /* Whether we should hide the buttons */
+ guint hide_buttons : 1;
+
/* Round corners */
- guint top_left_corner_rounded : 1;
- guint top_right_corner_rounded : 1;
- guint bottom_left_corner_rounded : 1;
- guint bottom_right_corner_rounded : 1;
+ guint top_left_corner_rounded_radius;
+ guint top_right_corner_rounded_radius;
+ guint bottom_left_corner_rounded_radius;
+ guint bottom_right_corner_rounded_radius;
};
struct _MetaButtonSpace
@@ -145,6 +148,12 @@ struct _MetaFrameGeometry
MetaButtonSpace max_rect;
MetaButtonSpace min_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)
GdkRectangle left_left_background;
@@ -156,10 +165,10 @@ struct _MetaFrameGeometry
/* End of button rects (if changed adjust memset hack) */
/* Round corners */
- guint top_left_corner_rounded : 1;
- guint top_right_corner_rounded : 1;
- guint bottom_left_corner_rounded : 1;
- guint bottom_right_corner_rounded : 1;
+ guint top_left_corner_rounded_radius;
+ guint top_right_corner_rounded_radius;
+ guint bottom_left_corner_rounded_radius;
+ guint bottom_right_corner_rounded_radius;
};
typedef enum
@@ -438,6 +447,12 @@ typedef enum
META_BUTTON_TYPE_MAXIMIZE,
META_BUTTON_TYPE_MINIMIZE,
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
} MetaButtonType;
@@ -503,6 +518,9 @@ struct _MetaFrameStyle
MetaDrawOpList *buttons[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST];
MetaDrawOpList *pieces[META_FRAME_PIECE_LAST];
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...
@@ -552,7 +570,7 @@ struct _MetaFrameStyleSet
MetaFrameStyleSet *parent;
MetaFrameStyle *normal_styles[META_FRAME_RESIZE_LAST][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];
};
@@ -566,16 +584,19 @@ struct _MetaTheme
char *copyright;
char *date;
char *description;
+ guint format_version;
GHashTable *integer_constants;
GHashTable *float_constants;
+ GHashTable *color_constants;
GHashTable *images_by_filename;
GHashTable *layouts_by_name;
GHashTable *draw_op_lists_by_name;
GHashTable *styles_by_name;
GHashTable *style_sets_by_name;
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
@@ -616,7 +637,8 @@ void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout
int client_width,
int client_height,
const MetaButtonLayout *button_layout,
- MetaFrameGeometry *fgeom);
+ MetaFrameGeometry *fgeom,
+ MetaTheme *theme);
gboolean meta_frame_layout_validate (const MetaFrameLayout *layout,
GError **error);
@@ -703,6 +725,7 @@ void meta_frame_style_draw (MetaFrameStyle *style,
gboolean meta_frame_style_validate (MetaFrameStyle *style,
+ guint current_theme_version,
GError **error);
MetaFrameStyleSet* meta_frame_style_set_new (MetaFrameStyleSet *parent);
@@ -722,6 +745,7 @@ gboolean meta_theme_validate (MetaTheme *theme,
GError **error);
GdkPixbuf* meta_theme_load_image (MetaTheme *theme,
const char *filename,
+ guint size_of_theme_icons,
GError **error);
MetaFrameStyle* meta_theme_get_frame_style (MetaTheme *theme,
@@ -749,13 +773,6 @@ void meta_theme_draw_frame (MetaTheme *theme,
GdkPixbuf *mini_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,
MetaFrameType type,
int text_height,
@@ -808,6 +825,14 @@ gboolean meta_theme_lookup_float_constant (MetaTheme *theme,
const char *name,
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,
const char *expr,
GError **err);
@@ -826,10 +851,9 @@ MetaGtkColorComponent meta_color_component_from_string (const char *s
const char* meta_color_component_to_string (MetaGtkColorComponent component);
MetaButtonState meta_button_state_from_string (const char *str);
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);
-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);
const char* meta_frame_piece_to_string (MetaFramePiece piece);
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);
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
diff --git a/src/ui.c b/src/ui.c
index 4a16a580..dbbe698d 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -30,6 +30,7 @@
#include "menu.h"
#include "core.h"
#include "theme.h"
+#include "iconcache.h"
#include "inlinepixbufs.h"
@@ -736,6 +737,7 @@ meta_ui_set_current_theme (const char *name,
gboolean force_reload)
{
meta_theme_set_current (name, force_reload);
+ meta_invalidate_default_icons ();
}
gboolean
diff --git a/src/window.c b/src/window.c
index 2f46f640..2cba8178 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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_update_icon_now (MetaWindow *window);
static void meta_window_unqueue_update_icon (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);
}
-static void
+void
meta_window_update_icon_now (MetaWindow *window)
{
GdkPixbuf *icon;
diff --git a/src/window.h b/src/window.h
index ff4b944b..e33f3e0d 100644
--- a/src/window.h
+++ b/src/window.h
@@ -607,4 +607,7 @@ void meta_window_set_user_time (MetaWindow *window,
void meta_window_set_demands_attention (MetaWindow *window);
void meta_window_unset_demands_attention (MetaWindow *window);
+
+void meta_window_update_icon_now (MetaWindow *window);
+
#endif