summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 e47448b..377b988 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 e5602d8..7a53aa7 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 32ce973..832e0b3 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 6d6da14..1f0f182 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 467e36b..922443d 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 c5827dc..a2971de 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 1d674ea..c4ad8bf 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 5c8ac19..939a089 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 1cb73a6..7a2ad7f 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 49c30b8..9b6c4a5 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 c500491..3690a79 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 1013c2b..68db8e7 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 0bdd062..702344f 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 f817dce..005842e 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 4a16a58..dbbe698 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 2f46f64..2cba817 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 ff4b944..e33f3e0 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