00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025 #include "theme-parser.h"
00026 #include "util.h"
00027 #include <string.h>
00028 #include <stdlib.h>
00029
00030 typedef enum
00031 {
00032 STATE_START,
00033 STATE_THEME,
00034
00035 STATE_INFO,
00036 STATE_NAME,
00037 STATE_AUTHOR,
00038 STATE_COPYRIGHT,
00039 STATE_DATE,
00040 STATE_DESCRIPTION,
00041
00042 STATE_CONSTANT,
00043
00044 STATE_FRAME_GEOMETRY,
00045 STATE_DISTANCE,
00046 STATE_BORDER,
00047 STATE_ASPECT_RATIO,
00048
00049 STATE_DRAW_OPS,
00050 STATE_LINE,
00051 STATE_RECTANGLE,
00052 STATE_ARC,
00053 STATE_CLIP,
00054 STATE_TINT,
00055 STATE_GRADIENT,
00056 STATE_IMAGE,
00057 STATE_GTK_ARROW,
00058 STATE_GTK_BOX,
00059 STATE_GTK_VLINE,
00060 STATE_ICON,
00061 STATE_TITLE,
00062 STATE_INCLUDE,
00063 STATE_TILE,
00064
00065 STATE_COLOR,
00066
00067 STATE_FRAME_STYLE,
00068 STATE_PIECE,
00069 STATE_BUTTON,
00070
00071 STATE_FRAME_STYLE_SET,
00072 STATE_FRAME,
00073
00074 STATE_WINDOW,
00075
00076 STATE_MENU_ICON,
00077
00078 STATE_FALLBACK
00079 } ParseState;
00080
00081 typedef struct
00082 {
00083 GSList *states;
00084
00085 const char *theme_name;
00086 char *theme_file;
00087 char *theme_dir;
00088 MetaTheme *theme;
00089 guint format_version;
00090 char *name;
00091 MetaFrameLayout *layout;
00092 MetaDrawOpList *op_list;
00093 MetaDrawOp *op;
00094 MetaFrameStyle *style;
00095 MetaFrameStyleSet *style_set;
00096 MetaFramePiece piece;
00097 MetaButtonType button_type;
00098 MetaButtonState button_state;
00099 } ParseInfo;
00100
00101 static void set_error (GError **err,
00102 GMarkupParseContext *context,
00103 int error_domain,
00104 int error_code,
00105 const char *format,
00106 ...) G_GNUC_PRINTF (5, 6);
00107
00108 static void add_context_to_error (GError **err,
00109 GMarkupParseContext *context);
00110
00111 static void parse_info_init (ParseInfo *info);
00112 static void parse_info_free (ParseInfo *info);
00113
00114 static void push_state (ParseInfo *info,
00115 ParseState state);
00116 static void pop_state (ParseInfo *info);
00117 static ParseState peek_state (ParseInfo *info);
00118
00119
00120 static void parse_toplevel_element (GMarkupParseContext *context,
00121 const gchar *element_name,
00122 const gchar **attribute_names,
00123 const gchar **attribute_values,
00124 ParseInfo *info,
00125 GError **error);
00126 static void parse_info_element (GMarkupParseContext *context,
00127 const gchar *element_name,
00128 const gchar **attribute_names,
00129 const gchar **attribute_values,
00130 ParseInfo *info,
00131 GError **error);
00132 static void parse_geometry_element (GMarkupParseContext *context,
00133 const gchar *element_name,
00134 const gchar **attribute_names,
00135 const gchar **attribute_values,
00136 ParseInfo *info,
00137 GError **error);
00138 static void parse_draw_op_element (GMarkupParseContext *context,
00139 const gchar *element_name,
00140 const gchar **attribute_names,
00141 const gchar **attribute_values,
00142 ParseInfo *info,
00143 GError **error);
00144 static void parse_gradient_element (GMarkupParseContext *context,
00145 const gchar *element_name,
00146 const gchar **attribute_names,
00147 const gchar **attribute_values,
00148 ParseInfo *info,
00149 GError **error);
00150 static void parse_style_element (GMarkupParseContext *context,
00151 const gchar *element_name,
00152 const gchar **attribute_names,
00153 const gchar **attribute_values,
00154 ParseInfo *info,
00155 GError **error);
00156 static void parse_style_set_element (GMarkupParseContext *context,
00157 const gchar *element_name,
00158 const gchar **attribute_names,
00159 const gchar **attribute_values,
00160 ParseInfo *info,
00161 GError **error);
00162
00163 static void parse_piece_element (GMarkupParseContext *context,
00164 const gchar *element_name,
00165 const gchar **attribute_names,
00166 const gchar **attribute_values,
00167 ParseInfo *info,
00168 GError **error);
00169
00170 static void parse_button_element (GMarkupParseContext *context,
00171 const gchar *element_name,
00172 const gchar **attribute_names,
00173 const gchar **attribute_values,
00174 ParseInfo *info,
00175 GError **error);
00176
00177 static void parse_menu_icon_element (GMarkupParseContext *context,
00178 const gchar *element_name,
00179 const gchar **attribute_names,
00180 const gchar **attribute_values,
00181 ParseInfo *info,
00182 GError **error);
00183
00184 static void start_element_handler (GMarkupParseContext *context,
00185 const gchar *element_name,
00186 const gchar **attribute_names,
00187 const gchar **attribute_values,
00188 gpointer user_data,
00189 GError **error);
00190 static void end_element_handler (GMarkupParseContext *context,
00191 const gchar *element_name,
00192 gpointer user_data,
00193 GError **error);
00194 static void text_handler (GMarkupParseContext *context,
00195 const gchar *text,
00196 gsize text_len,
00197 gpointer user_data,
00198 GError **error);
00199
00200 static GMarkupParser metacity_theme_parser = {
00201 start_element_handler,
00202 end_element_handler,
00203 text_handler,
00204 NULL,
00205 NULL
00206 };
00207
00208 static void
00209 set_error (GError **err,
00210 GMarkupParseContext *context,
00211 int error_domain,
00212 int error_code,
00213 const char *format,
00214 ...)
00215 {
00216 int line, ch;
00217 va_list args;
00218 char *str;
00219
00220 g_markup_parse_context_get_position (context, &line, &ch);
00221
00222 va_start (args, format);
00223 str = g_strdup_vprintf (format, args);
00224 va_end (args);
00225
00226 g_set_error (err, error_domain, error_code,
00227 _("Line %d character %d: %s"),
00228 line, ch, str);
00229
00230 g_free (str);
00231 }
00232
00233 static void
00234 add_context_to_error (GError **err,
00235 GMarkupParseContext *context)
00236 {
00237 int line, ch;
00238 char *str;
00239
00240 if (err == NULL || *err == NULL)
00241 return;
00242
00243 g_markup_parse_context_get_position (context, &line, &ch);
00244
00245 str = g_strdup_printf (_("Line %d character %d: %s"),
00246 line, ch, (*err)->message);
00247 g_free ((*err)->message);
00248 (*err)->message = str;
00249 }
00250
00251 static void
00252 parse_info_init (ParseInfo *info)
00253 {
00254 info->theme_file = NULL;
00255 info->states = g_slist_prepend (NULL, GINT_TO_POINTER (STATE_START));
00256 info->theme = NULL;
00257 info->name = NULL;
00258 info->layout = NULL;
00259 info->op_list = NULL;
00260 info->op = NULL;
00261 info->style = NULL;
00262 info->style_set = NULL;
00263 info->piece = META_FRAME_PIECE_LAST;
00264 info->button_type = META_BUTTON_TYPE_LAST;
00265 info->button_state = META_BUTTON_STATE_LAST;
00266 }
00267
00268 static void
00269 parse_info_free (ParseInfo *info)
00270 {
00271 g_free (info->theme_file);
00272 g_free (info->theme_dir);
00273
00274 g_slist_free (info->states);
00275
00276 if (info->theme)
00277 meta_theme_free (info->theme);
00278
00279 if (info->layout)
00280 meta_frame_layout_unref (info->layout);
00281
00282 if (info->op_list)
00283 meta_draw_op_list_unref (info->op_list);
00284
00285 if (info->op)
00286 meta_draw_op_free (info->op);
00287
00288 if (info->style)
00289 meta_frame_style_unref (info->style);
00290
00291 if (info->style_set)
00292 meta_frame_style_set_unref (info->style_set);
00293 }
00294
00295 static void
00296 push_state (ParseInfo *info,
00297 ParseState state)
00298 {
00299 info->states = g_slist_prepend (info->states, GINT_TO_POINTER (state));
00300 }
00301
00302 static void
00303 pop_state (ParseInfo *info)
00304 {
00305 g_return_if_fail (info->states != NULL);
00306
00307 info->states = g_slist_remove (info->states, info->states->data);
00308 }
00309
00310 static ParseState
00311 peek_state (ParseInfo *info)
00312 {
00313 g_return_val_if_fail (info->states != NULL, STATE_START);
00314
00315 return GPOINTER_TO_INT (info->states->data);
00316 }
00317
00318 #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
00319
00320 typedef struct
00321 {
00322 const char *name;
00323 const char **retloc;
00324 } LocateAttr;
00325
00326 static gboolean
00327 locate_attributes (GMarkupParseContext *context,
00328 const char *element_name,
00329 const char **attribute_names,
00330 const char **attribute_values,
00331 GError **error,
00332 const char *first_attribute_name,
00333 const char **first_attribute_retloc,
00334 ...)
00335 {
00336 va_list args;
00337 const char *name;
00338 const char **retloc;
00339 int n_attrs;
00340 #define MAX_ATTRS 24
00341 LocateAttr attrs[MAX_ATTRS];
00342 gboolean retval;
00343 int i;
00344
00345 g_return_val_if_fail (first_attribute_name != NULL, FALSE);
00346 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
00347
00348 retval = TRUE;
00349
00350 n_attrs = 1;
00351 attrs[0].name = first_attribute_name;
00352 attrs[0].retloc = first_attribute_retloc;
00353 *first_attribute_retloc = NULL;
00354
00355 va_start (args, first_attribute_retloc);
00356
00357 name = va_arg (args, const char*);
00358 retloc = va_arg (args, const char**);
00359
00360 while (name != NULL)
00361 {
00362 g_return_val_if_fail (retloc != NULL, FALSE);
00363
00364 g_assert (n_attrs < MAX_ATTRS);
00365
00366 attrs[n_attrs].name = name;
00367 attrs[n_attrs].retloc = retloc;
00368 n_attrs += 1;
00369 *retloc = NULL;
00370
00371 name = va_arg (args, const char*);
00372 retloc = va_arg (args, const char**);
00373 }
00374
00375 va_end (args);
00376
00377 i = 0;
00378 while (attribute_names[i])
00379 {
00380 int j;
00381 gboolean found;
00382
00383 found = FALSE;
00384 j = 0;
00385 while (j < n_attrs)
00386 {
00387 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
00388 {
00389 retloc = attrs[j].retloc;
00390
00391 if (*retloc != NULL)
00392 {
00393 set_error (error, context,
00394 G_MARKUP_ERROR,
00395 G_MARKUP_ERROR_PARSE,
00396 _("Attribute \"%s\" repeated twice on the same <%s> element"),
00397 attrs[j].name, element_name);
00398 retval = FALSE;
00399 goto out;
00400 }
00401
00402 *retloc = attribute_values[i];
00403 found = TRUE;
00404 }
00405
00406 ++j;
00407 }
00408
00409 if (!found)
00410 {
00411 set_error (error, context,
00412 G_MARKUP_ERROR,
00413 G_MARKUP_ERROR_PARSE,
00414 _("Attribute \"%s\" is invalid on <%s> element in this context"),
00415 attribute_names[i], element_name);
00416 retval = FALSE;
00417 goto out;
00418 }
00419
00420 ++i;
00421 }
00422
00423 out:
00424 return retval;
00425 }
00426
00427 static gboolean
00428 check_no_attributes (GMarkupParseContext *context,
00429 const char *element_name,
00430 const char **attribute_names,
00431 const char **attribute_values,
00432 GError **error)
00433 {
00434 if (attribute_names[0] != NULL)
00435 {
00436 set_error (error, context,
00437 G_MARKUP_ERROR,
00438 G_MARKUP_ERROR_PARSE,
00439 _("Attribute \"%s\" is invalid on <%s> element in this context"),
00440 attribute_names[0], element_name);
00441 return FALSE;
00442 }
00443
00444 return TRUE;
00445 }
00446
00447 #define MAX_REASONABLE 4096
00448 static gboolean
00449 parse_positive_integer (const char *str,
00450 int *val,
00451 GMarkupParseContext *context,
00452 MetaTheme *theme,
00453 GError **error)
00454 {
00455 char *end;
00456 long l;
00457 int j;
00458
00459 *val = 0;
00460
00461 end = NULL;
00462
00463
00464
00465 if (META_THEME_ALLOWS (theme, META_THEME_UBIQUITOUS_CONSTANTS) &&
00466 meta_theme_lookup_int_constant (theme, str, &j))
00467 {
00468
00469 l = j;
00470 }
00471 else
00472 {
00473
00474
00475 l = strtol (str, &end, 10);
00476
00477 if (end == NULL || end == str)
00478 {
00479 set_error (error, context, G_MARKUP_ERROR,
00480 G_MARKUP_ERROR_PARSE,
00481 _("Could not parse \"%s\" as an integer"),
00482 str);
00483 return FALSE;
00484 }
00485
00486 if (*end != '\0')
00487 {
00488 set_error (error, context, G_MARKUP_ERROR,
00489 G_MARKUP_ERROR_PARSE,
00490 _("Did not understand trailing characters \"%s\" in string \"%s\""),
00491 end, str);
00492 return FALSE;
00493 }
00494 }
00495
00496 if (l < 0)
00497 {
00498 set_error (error, context, G_MARKUP_ERROR,
00499 G_MARKUP_ERROR_PARSE,
00500 _("Integer %ld must be positive"), l);
00501 return FALSE;
00502 }
00503
00504 if (l > MAX_REASONABLE)
00505 {
00506 set_error (error, context, G_MARKUP_ERROR,
00507 G_MARKUP_ERROR_PARSE,
00508 _("Integer %ld is too large, current max is %d"),
00509 l, MAX_REASONABLE);
00510 return FALSE;
00511 }
00512
00513 *val = (int) l;
00514
00515 return TRUE;
00516 }
00517
00518 static gboolean
00519 parse_double (const char *str,
00520 double *val,
00521 GMarkupParseContext *context,
00522 GError **error)
00523 {
00524 char *end;
00525
00526 *val = 0;
00527
00528 end = NULL;
00529
00530 *val = g_ascii_strtod (str, &end);
00531
00532 if (end == NULL || end == str)
00533 {
00534 set_error (error, context, G_MARKUP_ERROR,
00535 G_MARKUP_ERROR_PARSE,
00536 _("Could not parse \"%s\" as a floating point number"),
00537 str);
00538 return FALSE;
00539 }
00540
00541 if (*end != '\0')
00542 {
00543 set_error (error, context, G_MARKUP_ERROR,
00544 G_MARKUP_ERROR_PARSE,
00545 _("Did not understand trailing characters \"%s\" in string \"%s\""),
00546 end, str);
00547 return FALSE;
00548 }
00549
00550 return TRUE;
00551 }
00552
00553 static gboolean
00554 parse_boolean (const char *str,
00555 gboolean *val,
00556 GMarkupParseContext *context,
00557 GError **error)
00558 {
00559 if (strcmp ("true", str) == 0)
00560 *val = TRUE;
00561 else if (strcmp ("false", str) == 0)
00562 *val = FALSE;
00563 else
00564 {
00565 set_error (error, context, G_MARKUP_ERROR,
00566 G_MARKUP_ERROR_PARSE,
00567 _("Boolean values must be \"true\" or \"false\" not \"%s\""),
00568 str);
00569 return FALSE;
00570 }
00571
00572 return TRUE;
00573 }
00574
00575 static gboolean
00576 parse_rounding (const char *str,
00577 guint *val,
00578 GMarkupParseContext *context,
00579 MetaTheme *theme,
00580 GError **error)
00581 {
00582 if (strcmp ("true", str) == 0)
00583 *val = 5;
00584 else if (strcmp ("false", str) == 0)
00585 *val = 0;
00586 else
00587 {
00588 int tmp;
00589 gboolean result;
00590 if (!META_THEME_ALLOWS (theme, META_THEME_VARIED_ROUND_CORNERS))
00591 {
00592
00593 set_error (error, context, G_MARKUP_ERROR,
00594 G_MARKUP_ERROR_PARSE,
00595 _("Boolean values must be \"true\" or \"false\" not \"%s\""),
00596 str);
00597 return FALSE;
00598 }
00599
00600 result = parse_positive_integer (str, &tmp, context, theme, error);
00601
00602 *val = tmp;
00603
00604 return result;
00605 }
00606
00607 return TRUE;
00608 }
00609
00610 static gboolean
00611 parse_angle (const char *str,
00612 double *val,
00613 GMarkupParseContext *context,
00614 GError **error)
00615 {
00616 if (!parse_double (str, val, context, error))
00617 return FALSE;
00618
00619 if (*val < (0.0 - 1e6) || *val > (360.0 + 1e6))
00620 {
00621 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00622 _("Angle must be between 0.0 and 360.0, was %g\n"),
00623 *val);
00624 return FALSE;
00625 }
00626
00627 return TRUE;
00628 }
00629
00630 static gboolean
00631 parse_alpha (const char *str,
00632 MetaAlphaGradientSpec **spec_ret,
00633 GMarkupParseContext *context,
00634 GError **error)
00635 {
00636 char **split;
00637 int i;
00638 int n_alphas;
00639 MetaAlphaGradientSpec *spec;
00640
00641 *spec_ret = NULL;
00642
00643 split = g_strsplit (str, ":", -1);
00644
00645 i = 0;
00646 while (split[i])
00647 ++i;
00648
00649 if (i == 0)
00650 {
00651 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00652 _("Could not parse \"%s\" as a floating point number"),
00653 str);
00654
00655 g_strfreev (split);
00656
00657 return FALSE;
00658 }
00659
00660 n_alphas = i;
00661
00662
00663
00664
00665 spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL,
00666 n_alphas);
00667
00668 i = 0;
00669 while (i < n_alphas)
00670 {
00671 double v;
00672
00673 if (!parse_double (split[i], &v, context, error))
00674 {
00675
00676 g_strfreev (split);
00677 meta_alpha_gradient_spec_free (spec);
00678
00679 return FALSE;
00680 }
00681
00682 if (v < (0.0 - 1e-6) || v > (1.0 + 1e-6))
00683 {
00684 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00685 _("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"),
00686 v);
00687
00688 g_strfreev (split);
00689 meta_alpha_gradient_spec_free (spec);
00690
00691 return FALSE;
00692 }
00693
00694 spec->alphas[i] = (unsigned char) (v * 255);
00695
00696 ++i;
00697 }
00698
00699 g_strfreev (split);
00700
00701 *spec_ret = spec;
00702
00703 return TRUE;
00704 }
00705
00706 static MetaColorSpec*
00707 parse_color (MetaTheme *theme,
00708 const char *str,
00709 GError **err)
00710 {
00711 char* referent;
00712
00713 if (META_THEME_ALLOWS (theme, META_THEME_COLOR_CONSTANTS) &&
00714 meta_theme_lookup_color_constant (theme, str, &referent))
00715 {
00716 if (referent)
00717 return meta_color_spec_new_from_string (referent, err);
00718
00719
00720 }
00721
00722 return meta_color_spec_new_from_string (str, err);
00723 }
00724
00725 static gboolean
00726 parse_title_scale (const char *str,
00727 double *val,
00728 GMarkupParseContext *context,
00729 GError **error)
00730 {
00731 double factor;
00732
00733 if (strcmp (str, "xx-small") == 0)
00734 factor = PANGO_SCALE_XX_SMALL;
00735 else if (strcmp (str, "x-small") == 0)
00736 factor = PANGO_SCALE_X_SMALL;
00737 else if (strcmp (str, "small") == 0)
00738 factor = PANGO_SCALE_SMALL;
00739 else if (strcmp (str, "medium") == 0)
00740 factor = PANGO_SCALE_MEDIUM;
00741 else if (strcmp (str, "large") == 0)
00742 factor = PANGO_SCALE_LARGE;
00743 else if (strcmp (str, "x-large") == 0)
00744 factor = PANGO_SCALE_X_LARGE;
00745 else if (strcmp (str, "xx-large") == 0)
00746 factor = PANGO_SCALE_XX_LARGE;
00747 else
00748 {
00749 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00750 _("Invalid title scale \"%s\" (must be one of xx-small,x-small,small,medium,large,x-large,xx-large)\n"),
00751 str);
00752 return FALSE;
00753 }
00754
00755 *val = factor;
00756
00757 return TRUE;
00758 }
00759
00760 static void
00761 parse_toplevel_element (GMarkupParseContext *context,
00762 const gchar *element_name,
00763 const gchar **attribute_names,
00764 const gchar **attribute_values,
00765 ParseInfo *info,
00766 GError **error)
00767 {
00768 g_return_if_fail (peek_state (info) == STATE_THEME);
00769
00770 if (ELEMENT_IS ("info"))
00771 {
00772 if (!check_no_attributes (context, element_name,
00773 attribute_names, attribute_values,
00774 error))
00775 return;
00776
00777 push_state (info, STATE_INFO);
00778 }
00779 else if (ELEMENT_IS ("constant"))
00780 {
00781 const char *name;
00782 const char *value;
00783 int ival = 0;
00784 double dval = 0.0;
00785
00786 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
00787 error,
00788 "name", &name, "value", &value,
00789 NULL))
00790 return;
00791
00792 if (name == NULL)
00793 {
00794 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00795 _("No \"%s\" attribute on <%s> element"),
00796 "name", element_name);
00797 return;
00798 }
00799
00800 if (value == NULL)
00801 {
00802 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00803 _("No \"%s\" attribute on <%s> element"),
00804 "value", element_name);
00805 return;
00806 }
00807
00808 if (strchr (value, '.') && parse_double (value, &dval, context, error))
00809 {
00810 g_clear_error (error);
00811
00812 if (!meta_theme_define_float_constant (info->theme,
00813 name,
00814 dval,
00815 error))
00816 {
00817 add_context_to_error (error, context);
00818 return;
00819 }
00820 }
00821 else if (parse_positive_integer (value, &ival, context, info->theme, error))
00822 {
00823 g_clear_error (error);
00824
00825 if (!meta_theme_define_int_constant (info->theme,
00826 name,
00827 ival,
00828 error))
00829 {
00830 add_context_to_error (error, context);
00831 return;
00832 }
00833 }
00834 else
00835 {
00836 g_clear_error (error);
00837
00838 if (!meta_theme_define_color_constant (info->theme,
00839 name,
00840 value,
00841 error))
00842 {
00843 add_context_to_error (error, context);
00844 return;
00845 }
00846 }
00847
00848 push_state (info, STATE_CONSTANT);
00849 }
00850 else if (ELEMENT_IS ("frame_geometry"))
00851 {
00852 const char *name = NULL;
00853 const char *parent = NULL;
00854 const char *has_title = NULL;
00855 const char *title_scale = NULL;
00856 const char *rounded_top_left = NULL;
00857 const char *rounded_top_right = NULL;
00858 const char *rounded_bottom_left = NULL;
00859 const char *rounded_bottom_right = NULL;
00860 const char *hide_buttons = NULL;
00861 gboolean has_title_val;
00862 guint rounded_top_left_val;
00863 guint rounded_top_right_val;
00864 guint rounded_bottom_left_val;
00865 guint rounded_bottom_right_val;
00866 gboolean hide_buttons_val;
00867 double title_scale_val;
00868 MetaFrameLayout *parent_layout;
00869
00870 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
00871 error,
00872 "name", &name, "parent", &parent,
00873 "has_title", &has_title, "title_scale", &title_scale,
00874 "rounded_top_left", &rounded_top_left,
00875 "rounded_top_right", &rounded_top_right,
00876 "rounded_bottom_left", &rounded_bottom_left,
00877 "rounded_bottom_right", &rounded_bottom_right,
00878 "hide_buttons", &hide_buttons,
00879 NULL))
00880 return;
00881
00882 if (name == NULL)
00883 {
00884 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00885 _("No \"%s\" attribute on <%s> element"),
00886 "name", element_name);
00887 return;
00888 }
00889
00890 has_title_val = TRUE;
00891 if (has_title && !parse_boolean (has_title, &has_title_val, context, error))
00892 return;
00893
00894 hide_buttons_val = FALSE;
00895 if (hide_buttons && !parse_boolean (hide_buttons, &hide_buttons_val, context, error))
00896 return;
00897
00898 rounded_top_left_val = 0;
00899 rounded_top_right_val = 0;
00900 rounded_bottom_left_val = 0;
00901 rounded_bottom_right_val = 0;
00902
00903 if (rounded_top_left && !parse_rounding (rounded_top_left, &rounded_top_left_val, context, info->theme, error))
00904 return;
00905 if (rounded_top_right && !parse_rounding (rounded_top_right, &rounded_top_right_val, context, info->theme, error))
00906 return;
00907 if (rounded_bottom_left && !parse_rounding (rounded_bottom_left, &rounded_bottom_left_val, context, info->theme, error))
00908 return;
00909 if (rounded_bottom_right && !parse_rounding (rounded_bottom_right, &rounded_bottom_right_val, context, info->theme, error))
00910 return;
00911
00912 title_scale_val = 1.0;
00913 if (title_scale && !parse_title_scale (title_scale, &title_scale_val, context, error))
00914 return;
00915
00916 if (meta_theme_lookup_layout (info->theme, name))
00917 {
00918 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00919 _("<%s> name \"%s\" used a second time"),
00920 element_name, name);
00921 return;
00922 }
00923
00924 parent_layout = NULL;
00925 if (parent)
00926 {
00927 parent_layout = meta_theme_lookup_layout (info->theme, parent);
00928 if (parent_layout == NULL)
00929 {
00930 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00931 _("<%s> parent \"%s\" has not been defined"),
00932 element_name, parent);
00933 return;
00934 }
00935 }
00936
00937 g_assert (info->layout == NULL);
00938
00939 if (parent_layout)
00940 info->layout = meta_frame_layout_copy (parent_layout);
00941 else
00942 info->layout = meta_frame_layout_new ();
00943
00944 if (has_title)
00945 info->layout->has_title = has_title_val;
00946
00947 if (META_THEME_ALLOWS (info->theme, META_THEME_HIDDEN_BUTTONS) && hide_buttons_val)
00948 info->layout->hide_buttons = hide_buttons_val;
00949
00950 if (title_scale)
00951 info->layout->title_scale = title_scale_val;
00952
00953 if (rounded_top_left)
00954 info->layout->top_left_corner_rounded_radius = rounded_top_left_val;
00955
00956 if (rounded_top_right)
00957 info->layout->top_right_corner_rounded_radius = rounded_top_right_val;
00958
00959 if (rounded_bottom_left)
00960 info->layout->bottom_left_corner_rounded_radius = rounded_bottom_left_val;
00961
00962 if (rounded_bottom_right)
00963 info->layout->bottom_right_corner_rounded_radius = rounded_bottom_right_val;
00964
00965 meta_theme_insert_layout (info->theme, name, info->layout);
00966
00967 push_state (info, STATE_FRAME_GEOMETRY);
00968 }
00969 else if (ELEMENT_IS ("draw_ops"))
00970 {
00971 const char *name = NULL;
00972
00973 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
00974 error,
00975 "name", &name,
00976 NULL))
00977 return;
00978
00979 if (name == NULL)
00980 {
00981 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00982 _("No \"%s\" attribute on <%s> element"),
00983 "name", element_name);
00984 return;
00985 }
00986
00987 if (meta_theme_lookup_draw_op_list (info->theme, name))
00988 {
00989 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
00990 _("<%s> name \"%s\" used a second time"),
00991 element_name, name);
00992 return;
00993 }
00994
00995 g_assert (info->op_list == NULL);
00996 info->op_list = meta_draw_op_list_new (2);
00997
00998 meta_theme_insert_draw_op_list (info->theme, name, info->op_list);
00999
01000 push_state (info, STATE_DRAW_OPS);
01001 }
01002 else if (ELEMENT_IS ("frame_style"))
01003 {
01004 const char *name = NULL;
01005 const char *parent = NULL;
01006 const char *geometry = NULL;
01007 const char *background = NULL;
01008 const char *alpha = NULL;
01009 MetaFrameStyle *parent_style;
01010 MetaFrameLayout *layout;
01011
01012 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01013 error,
01014 "name", &name, "parent", &parent,
01015 "geometry", &geometry,
01016 "background", &background,
01017 "alpha", &alpha,
01018 NULL))
01019 return;
01020
01021 if (name == NULL)
01022 {
01023 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01024 _("No \"%s\" attribute on <%s> element"),
01025 "name", element_name);
01026 return;
01027 }
01028
01029 if (meta_theme_lookup_style (info->theme, name))
01030 {
01031 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01032 _("<%s> name \"%s\" used a second time"),
01033 element_name, name);
01034 return;
01035 }
01036
01037 parent_style = NULL;
01038 if (parent)
01039 {
01040 parent_style = meta_theme_lookup_style (info->theme, parent);
01041 if (parent_style == NULL)
01042 {
01043 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01044 _("<%s> parent \"%s\" has not been defined"),
01045 element_name, parent);
01046 return;
01047 }
01048 }
01049
01050 layout = NULL;
01051 if (geometry)
01052 {
01053 layout = meta_theme_lookup_layout (info->theme, geometry);
01054 if (layout == NULL)
01055 {
01056 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01057 _("<%s> geometry \"%s\" has not been defined"),
01058 element_name, geometry);
01059 return;
01060 }
01061 }
01062 else if (parent_style)
01063 {
01064 layout = parent_style->layout;
01065 }
01066
01067 if (layout == NULL)
01068 {
01069 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01070 _("<%s> must specify either a geometry or a parent that has a geometry"),
01071 element_name);
01072 return;
01073 }
01074
01075 g_assert (info->style == NULL);
01076
01077 info->style = meta_frame_style_new (parent_style);
01078 g_assert (info->style->layout == NULL);
01079 meta_frame_layout_ref (layout);
01080 info->style->layout = layout;
01081
01082 if (background != NULL && META_THEME_ALLOWS (info->theme, META_THEME_FRAME_BACKGROUNDS))
01083 {
01084 info->style->window_background_color = meta_color_spec_new_from_string (background, error);
01085 if (!info->style->window_background_color)
01086 return;
01087
01088 if (alpha != NULL)
01089 {
01090
01091 gboolean success;
01092 MetaAlphaGradientSpec *alpha_vector;
01093
01094 g_clear_error (error);
01095
01096
01097
01098
01099 success = parse_alpha (alpha, &alpha_vector, context, error);
01100 if (!success)
01101 return;
01102
01103
01104 info->style->window_background_alpha = alpha_vector->alphas[0];
01105
01106 meta_alpha_gradient_spec_free (alpha_vector);
01107 }
01108 }
01109 else if (alpha != NULL)
01110 {
01111 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01112 _("You must specify a background for an alpha value to be meaningful"));
01113 return;
01114 }
01115
01116 meta_theme_insert_style (info->theme, name, info->style);
01117
01118 push_state (info, STATE_FRAME_STYLE);
01119 }
01120 else if (ELEMENT_IS ("frame_style_set"))
01121 {
01122 const char *name = NULL;
01123 const char *parent = NULL;
01124 MetaFrameStyleSet *parent_set;
01125
01126 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01127 error,
01128 "name", &name, "parent", &parent,
01129 NULL))
01130 return;
01131
01132 if (name == NULL)
01133 {
01134 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01135 _("No \"%s\" attribute on <%s> element"),
01136 "name", element_name);
01137 return;
01138 }
01139
01140 if (meta_theme_lookup_style_set (info->theme, name))
01141 {
01142 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01143 _("<%s> name \"%s\" used a second time"),
01144 element_name, name);
01145 return;
01146 }
01147
01148 parent_set = NULL;
01149 if (parent)
01150 {
01151 parent_set = meta_theme_lookup_style_set (info->theme, parent);
01152 if (parent_set == NULL)
01153 {
01154 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01155 _("<%s> parent \"%s\" has not been defined"),
01156 element_name, parent);
01157 return;
01158 }
01159 }
01160
01161 g_assert (info->style_set == NULL);
01162
01163 info->style_set = meta_frame_style_set_new (parent_set);
01164
01165 meta_theme_insert_style_set (info->theme, name, info->style_set);
01166
01167 push_state (info, STATE_FRAME_STYLE_SET);
01168 }
01169 else if (ELEMENT_IS ("window"))
01170 {
01171 const char *type_name = NULL;
01172 const char *style_set_name = NULL;
01173 MetaFrameStyleSet *style_set;
01174 MetaFrameType type;
01175
01176 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01177 error,
01178 "type", &type_name, "style_set", &style_set_name,
01179 NULL))
01180 return;
01181
01182 if (type_name == NULL)
01183 {
01184 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01185 _("No \"%s\" attribute on <%s> element"),
01186 "type", element_name);
01187 return;
01188 }
01189
01190 if (style_set_name == NULL)
01191 {
01192 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01193 _("No \"%s\" attribute on <%s> element"),
01194 "style_set", element_name);
01195 return;
01196 }
01197
01198 type = meta_frame_type_from_string (type_name);
01199
01200 if (type == META_FRAME_TYPE_LAST)
01201 {
01202 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01203 _("Unknown type \"%s\" on <%s> element"),
01204 type_name, element_name);
01205 return;
01206 }
01207
01208 style_set = meta_theme_lookup_style_set (info->theme,
01209 style_set_name);
01210
01211 if (style_set == NULL)
01212 {
01213 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01214 _("Unknown style_set \"%s\" on <%s> element"),
01215 style_set_name, element_name);
01216 return;
01217 }
01218
01219 if (info->theme->style_sets_by_type[type] != NULL)
01220 {
01221 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01222 _("Window type \"%s\" has already been assigned a style set"),
01223 type_name);
01224 return;
01225 }
01226
01227 meta_frame_style_set_ref (style_set);
01228 info->theme->style_sets_by_type[type] = style_set;
01229
01230 push_state (info, STATE_WINDOW);
01231 }
01232 else if (ELEMENT_IS ("menu_icon"))
01233 {
01234
01235
01236
01237 g_assert (info->op_list == NULL);
01238
01239 push_state (info, STATE_MENU_ICON);
01240 }
01241 else if (ELEMENT_IS ("fallback"))
01242 {
01243 const char *icon = NULL;
01244 const char *mini_icon = NULL;
01245
01246 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01247 error,
01248 "icon", &icon,
01249 "mini_icon", &mini_icon,
01250 NULL))
01251 return;
01252
01253 if (icon)
01254 {
01255 if (info->theme->fallback_icon != NULL)
01256 {
01257 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01258 _("Theme already has a fallback icon"));
01259 return;
01260 }
01261
01262 info->theme->fallback_icon = meta_theme_load_image(info->theme, icon, 64, error);
01263 }
01264
01265 if (mini_icon)
01266 {
01267 if (info->theme->fallback_mini_icon != NULL)
01268 {
01269 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01270 _("Theme already has a fallback mini_icon"));
01271 return;
01272 }
01273
01274 info->theme->fallback_mini_icon = meta_theme_load_image(info->theme, mini_icon, 16, error);
01275 }
01276
01277 push_state (info, STATE_FALLBACK);
01278 }
01279 else
01280 {
01281 set_error (error, context,
01282 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01283 _("Element <%s> is not allowed below <%s>"),
01284 element_name, "metacity_theme");
01285 }
01286 }
01287
01288 static void
01289 parse_info_element (GMarkupParseContext *context,
01290 const gchar *element_name,
01291 const gchar **attribute_names,
01292 const gchar **attribute_values,
01293 ParseInfo *info,
01294 GError **error)
01295 {
01296 g_return_if_fail (peek_state (info) == STATE_INFO);
01297
01298 if (ELEMENT_IS ("name"))
01299 {
01300 if (!check_no_attributes (context, element_name,
01301 attribute_names, attribute_values,
01302 error))
01303 return;
01304
01305 push_state (info, STATE_NAME);
01306 }
01307 else if (ELEMENT_IS ("author"))
01308 {
01309 if (!check_no_attributes (context, element_name,
01310 attribute_names, attribute_values,
01311 error))
01312 return;
01313
01314 push_state (info, STATE_AUTHOR);
01315 }
01316 else if (ELEMENT_IS ("copyright"))
01317 {
01318 if (!check_no_attributes (context, element_name,
01319 attribute_names, attribute_values,
01320 error))
01321 return;
01322
01323 push_state (info, STATE_COPYRIGHT);
01324 }
01325 else if (ELEMENT_IS ("description"))
01326 {
01327 if (!check_no_attributes (context, element_name,
01328 attribute_names, attribute_values,
01329 error))
01330 return;
01331
01332 push_state (info, STATE_DESCRIPTION);
01333 }
01334 else if (ELEMENT_IS ("date"))
01335 {
01336 if (!check_no_attributes (context, element_name,
01337 attribute_names, attribute_values,
01338 error))
01339 return;
01340
01341 push_state (info, STATE_DATE);
01342 }
01343 else
01344 {
01345 set_error (error, context,
01346 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01347 _("Element <%s> is not allowed below <%s>"),
01348 element_name, "info");
01349 }
01350 }
01351
01352 static void
01353 parse_distance (GMarkupParseContext *context,
01354 const gchar *element_name,
01355 const gchar **attribute_names,
01356 const gchar **attribute_values,
01357 ParseInfo *info,
01358 GError **error)
01359 {
01360 const char *name;
01361 const char *value;
01362 int val;
01363
01364 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01365 error,
01366 "name", &name, "value", &value,
01367 NULL))
01368 return;
01369
01370 if (name == NULL)
01371 {
01372 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01373 _("No \"name\" attribute on element <%s>"), element_name);
01374 return;
01375 }
01376
01377 if (value == NULL)
01378 {
01379 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01380 _("No \"value\" attribute on element <%s>"), element_name);
01381 return;
01382 }
01383
01384 val = 0;
01385 if (!parse_positive_integer (value, &val, context, info->theme, error))
01386 return;
01387
01388 g_assert (val >= 0);
01389 g_assert (info->layout);
01390
01391 if (strcmp (name, "left_width") == 0)
01392 info->layout->left_width = val;
01393 else if (strcmp (name, "right_width") == 0)
01394 info->layout->right_width = val;
01395 else if (strcmp (name, "bottom_height") == 0)
01396 info->layout->bottom_height = val;
01397 else if (strcmp (name, "title_vertical_pad") == 0)
01398 info->layout->title_vertical_pad = val;
01399 else if (strcmp (name, "right_titlebar_edge") == 0)
01400 info->layout->right_titlebar_edge = val;
01401 else if (strcmp (name, "left_titlebar_edge") == 0)
01402 info->layout->left_titlebar_edge = val;
01403 else if (strcmp (name, "button_width") == 0)
01404 {
01405 info->layout->button_width = val;
01406
01407 if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST ||
01408 info->layout->button_sizing == META_BUTTON_SIZING_FIXED))
01409 {
01410 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01411 _("Cannot specify both button_width/button_height and aspect ratio for buttons"));
01412 return;
01413 }
01414
01415 info->layout->button_sizing = META_BUTTON_SIZING_FIXED;
01416 }
01417 else if (strcmp (name, "button_height") == 0)
01418 {
01419 info->layout->button_height = val;
01420
01421 if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST ||
01422 info->layout->button_sizing == META_BUTTON_SIZING_FIXED))
01423 {
01424 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01425 _("Cannot specify both button_width/button_height and aspect ratio for buttons"));
01426 return;
01427 }
01428
01429 info->layout->button_sizing = META_BUTTON_SIZING_FIXED;
01430 }
01431 else
01432 {
01433 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01434 _("Distance \"%s\" is unknown"), name);
01435 return;
01436 }
01437 }
01438
01439 static void
01440 parse_aspect_ratio (GMarkupParseContext *context,
01441 const gchar *element_name,
01442 const gchar **attribute_names,
01443 const gchar **attribute_values,
01444 ParseInfo *info,
01445 GError **error)
01446 {
01447 const char *name;
01448 const char *value;
01449 double val;
01450
01451 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01452 error,
01453 "name", &name, "value", &value,
01454 NULL))
01455 return;
01456
01457 if (name == NULL)
01458 {
01459 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01460 _("No \"name\" attribute on element <%s>"), element_name);
01461 return;
01462 }
01463
01464 if (value == NULL)
01465 {
01466 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01467 _("No \"value\" attribute on element <%s>"), element_name);
01468 return;
01469 }
01470
01471 val = 0;
01472 if (!parse_double (value, &val, context, error))
01473 return;
01474
01475 g_assert (info->layout);
01476
01477 if (strcmp (name, "button") == 0)
01478 {
01479 info->layout->button_aspect = val;
01480
01481 if (info->layout->button_sizing != META_BUTTON_SIZING_LAST)
01482 {
01483 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01484 _("Cannot specify both button_width/button_height and aspect ratio for buttons"));
01485 return;
01486 }
01487
01488 info->layout->button_sizing = META_BUTTON_SIZING_ASPECT;
01489 }
01490 else
01491 {
01492 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01493 _("Aspect ratio \"%s\" is unknown"), name);
01494 return;
01495 }
01496 }
01497
01498 static void
01499 parse_border (GMarkupParseContext *context,
01500 const gchar *element_name,
01501 const gchar **attribute_names,
01502 const gchar **attribute_values,
01503 ParseInfo *info,
01504 GError **error)
01505 {
01506 const char *name;
01507 const char *top;
01508 const char *bottom;
01509 const char *left;
01510 const char *right;
01511 int top_val;
01512 int bottom_val;
01513 int left_val;
01514 int right_val;
01515 GtkBorder *border;
01516
01517 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01518 error,
01519 "name", &name,
01520 "top", &top,
01521 "bottom", &bottom,
01522 "left", &left,
01523 "right", &right,
01524 NULL))
01525 return;
01526
01527 if (name == NULL)
01528 {
01529 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01530 _("No \"name\" attribute on element <%s>"), element_name);
01531 return;
01532 }
01533
01534 if (top == NULL)
01535 {
01536 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01537 _("No \"top\" attribute on element <%s>"), element_name);
01538 return;
01539 }
01540
01541 if (bottom == NULL)
01542 {
01543 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01544 _("No \"bottom\" attribute on element <%s>"), element_name);
01545 return;
01546 }
01547
01548 if (left == NULL)
01549 {
01550 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01551 _("No \"left\" attribute on element <%s>"), element_name);
01552 return;
01553 }
01554
01555 if (right == NULL)
01556 {
01557 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01558 _("No \"right\" attribute on element <%s>"), element_name);
01559 return;
01560 }
01561
01562 top_val = 0;
01563 if (!parse_positive_integer (top, &top_val, context, info->theme, error))
01564 return;
01565
01566 bottom_val = 0;
01567 if (!parse_positive_integer (bottom, &bottom_val, context, info->theme, error))
01568 return;
01569
01570 left_val = 0;
01571 if (!parse_positive_integer (left, &left_val, context, info->theme, error))
01572 return;
01573
01574 right_val = 0;
01575 if (!parse_positive_integer (right, &right_val, context, info->theme, error))
01576 return;
01577
01578 g_assert (info->layout);
01579
01580 border = NULL;
01581
01582 if (strcmp (name, "title_border") == 0)
01583 border = &info->layout->title_border;
01584 else if (strcmp (name, "button_border") == 0)
01585 border = &info->layout->button_border;
01586
01587 if (border == NULL)
01588 {
01589 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01590 _("Border \"%s\" is unknown"), name);
01591 return;
01592 }
01593
01594 border->top = top_val;
01595 border->bottom = bottom_val;
01596 border->left = left_val;
01597 border->right = right_val;
01598 }
01599
01600 static void
01601 parse_geometry_element (GMarkupParseContext *context,
01602 const gchar *element_name,
01603 const gchar **attribute_names,
01604 const gchar **attribute_values,
01605 ParseInfo *info,
01606 GError **error)
01607 {
01608 g_return_if_fail (peek_state (info) == STATE_FRAME_GEOMETRY);
01609
01610 if (ELEMENT_IS ("distance"))
01611 {
01612 parse_distance (context, element_name,
01613 attribute_names, attribute_values,
01614 info, error);
01615 push_state (info, STATE_DISTANCE);
01616 }
01617 else if (ELEMENT_IS ("border"))
01618 {
01619 parse_border (context, element_name,
01620 attribute_names, attribute_values,
01621 info, error);
01622 push_state (info, STATE_BORDER);
01623 }
01624 else if (ELEMENT_IS ("aspect_ratio"))
01625 {
01626 parse_aspect_ratio (context, element_name,
01627 attribute_names, attribute_values,
01628 info, error);
01629
01630 push_state (info, STATE_ASPECT_RATIO);
01631 }
01632 else
01633 {
01634 set_error (error, context,
01635 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01636 _("Element <%s> is not allowed below <%s>"),
01637 element_name, "frame_geometry");
01638 }
01639 }
01640
01641 #if 0
01642 static gboolean
01643 check_expression (PosToken *tokens,
01644 int n_tokens,
01645 gboolean has_object,
01646 MetaTheme *theme,
01647 GMarkupParseContext *context,
01648 GError **error)
01649 {
01650 MetaPositionExprEnv env;
01651 int x, y;
01652
01653
01654
01655
01656
01657
01658 env.rect = meta_rect (0, 0, 0, 0);
01659 if (has_object)
01660 {
01661 env.object_width = 0;
01662 env.object_height = 0;
01663 }
01664 else
01665 {
01666 env.object_width = -1;
01667 env.object_height = -1;
01668 }
01669
01670 env.left_width = 0;
01671 env.right_width = 0;
01672 env.top_height = 0;
01673 env.bottom_height = 0;
01674 env.title_width = 0;
01675 env.title_height = 0;
01676
01677 env.icon_width = 0;
01678 env.icon_height = 0;
01679 env.mini_icon_width = 0;
01680 env.mini_icon_height = 0;
01681 env.theme = theme;
01682
01683 if (!meta_parse_position_expression (tokens, n_tokens,
01684 &env,
01685 &x, &y,
01686 error))
01687 {
01688 add_context_to_error (error, context);
01689 return FALSE;
01690 }
01691
01692 return TRUE;
01693 }
01694 #endif
01695
01696 static void
01697 parse_draw_op_element (GMarkupParseContext *context,
01698 const gchar *element_name,
01699 const gchar **attribute_names,
01700 const gchar **attribute_values,
01701 ParseInfo *info,
01702 GError **error)
01703 {
01704 g_return_if_fail (peek_state (info) == STATE_DRAW_OPS);
01705
01706 if (ELEMENT_IS ("line"))
01707 {
01708 MetaDrawOp *op;
01709 const char *color;
01710 const char *x1;
01711 const char *y1;
01712 const char *x2;
01713 const char *y2;
01714 const char *dash_on_length;
01715 const char *dash_off_length;
01716 const char *width;
01717 MetaColorSpec *color_spec;
01718 int dash_on_val;
01719 int dash_off_val;
01720 int width_val;
01721
01722 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01723 error,
01724 "color", &color,
01725 "x1", &x1, "y1", &y1,
01726 "x2", &x2, "y2", &y2,
01727 "dash_on_length", &dash_on_length,
01728 "dash_off_length", &dash_off_length,
01729 "width", &width,
01730 NULL))
01731 return;
01732
01733 if (color == NULL)
01734 {
01735 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01736 _("No \"color\" attribute on element <%s>"), element_name);
01737 return;
01738 }
01739
01740 if (x1 == NULL)
01741 {
01742 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01743 _("No \"x1\" attribute on element <%s>"), element_name);
01744 return;
01745 }
01746
01747 if (y1 == NULL)
01748 {
01749 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01750 _("No \"y1\" attribute on element <%s>"), element_name);
01751 return;
01752 }
01753
01754 if (x2 == NULL)
01755 {
01756 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01757 _("No \"x2\" attribute on element <%s>"), element_name);
01758 return;
01759 }
01760
01761 if (y2 == NULL)
01762 {
01763 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01764 _("No \"y2\" attribute on element <%s>"), element_name);
01765 return;
01766 }
01767
01768 #if 0
01769 if (!check_expression (x1, FALSE, info->theme, context, error))
01770 return;
01771
01772 if (!check_expression (y1, FALSE, info->theme, context, error))
01773 return;
01774
01775 if (!check_expression (x2, FALSE, info->theme, context, error))
01776 return;
01777
01778 if (!check_expression (y2, FALSE, info->theme, context, error))
01779 return;
01780 #endif
01781
01782 dash_on_val = 0;
01783 if (dash_on_length &&
01784 !parse_positive_integer (dash_on_length, &dash_on_val, context, info->theme, error))
01785 return;
01786
01787 dash_off_val = 0;
01788 if (dash_off_length &&
01789 !parse_positive_integer (dash_off_length, &dash_off_val, context, info->theme, error))
01790 return;
01791
01792 width_val = 0;
01793 if (width &&
01794 !parse_positive_integer (width, &width_val, context, info->theme, error))
01795 return;
01796
01797
01798
01799
01800 color_spec = parse_color (info->theme, color, error);
01801 if (color_spec == NULL)
01802 {
01803 add_context_to_error (error, context);
01804 return;
01805 }
01806
01807 op = meta_draw_op_new (META_DRAW_LINE);
01808
01809 op->data.line.color_spec = color_spec;
01810
01811 op->data.line.x1 = meta_draw_spec_new (info->theme, x1, NULL);
01812 op->data.line.y1 = meta_draw_spec_new (info->theme, y1, NULL);
01813 op->data.line.x2 = meta_draw_spec_new (info->theme, x2, NULL);
01814 op->data.line.y2 = meta_draw_spec_new (info->theme, y2, NULL);
01815
01816 op->data.line.width = width_val;
01817 op->data.line.dash_on_length = dash_on_val;
01818 op->data.line.dash_off_length = dash_off_val;
01819
01820 g_assert (info->op_list);
01821
01822 meta_draw_op_list_append (info->op_list, op);
01823
01824 push_state (info, STATE_LINE);
01825 }
01826 else if (ELEMENT_IS ("rectangle"))
01827 {
01828 MetaDrawOp *op;
01829 const char *color;
01830 const char *x;
01831 const char *y;
01832 const char *width;
01833 const char *height;
01834 const char *filled;
01835 gboolean filled_val;
01836 MetaColorSpec *color_spec;
01837
01838 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01839 error,
01840 "color", &color,
01841 "x", &x, "y", &y,
01842 "width", &width, "height", &height,
01843 "filled", &filled,
01844 NULL))
01845 return;
01846
01847 if (color == NULL)
01848 {
01849 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01850 _("No \"color\" attribute on element <%s>"), element_name);
01851 return;
01852 }
01853
01854 if (x == NULL)
01855 {
01856 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01857 _("No \"x\" attribute on element <%s>"), element_name);
01858 return;
01859 }
01860
01861 if (y == NULL)
01862 {
01863 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01864 _("No \"y\" attribute on element <%s>"), element_name);
01865 return;
01866 }
01867
01868 if (width == NULL)
01869 {
01870 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01871 _("No \"width\" attribute on element <%s>"), element_name);
01872 return;
01873 }
01874
01875 if (height == NULL)
01876 {
01877 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01878 _("No \"height\" attribute on element <%s>"), element_name);
01879 return;
01880 }
01881
01882 #if 0
01883 if (!check_expression (x, FALSE, info->theme, context, error))
01884 return;
01885
01886 if (!check_expression (y, FALSE, info->theme, context, error))
01887 return;
01888
01889 if (!check_expression (width, FALSE, info->theme, context, error))
01890 return;
01891
01892 if (!check_expression (height, FALSE, info->theme, context, error))
01893 return;
01894 #endif
01895
01896 filled_val = FALSE;
01897 if (filled && !parse_boolean (filled, &filled_val, context, error))
01898 return;
01899
01900
01901
01902
01903 color_spec = parse_color (info->theme, color, error);
01904 if (color_spec == NULL)
01905 {
01906 add_context_to_error (error, context);
01907 return;
01908 }
01909
01910 op = meta_draw_op_new (META_DRAW_RECTANGLE);
01911
01912 op->data.rectangle.color_spec = color_spec;
01913 op->data.rectangle.x = meta_draw_spec_new (info->theme, x, NULL);
01914 op->data.rectangle.y = meta_draw_spec_new (info->theme, y, NULL);
01915 op->data.rectangle.width = meta_draw_spec_new (info->theme, width, NULL);
01916 op->data.rectangle.height = meta_draw_spec_new (info->theme,
01917 height, NULL);
01918
01919 op->data.rectangle.filled = filled_val;
01920
01921 g_assert (info->op_list);
01922
01923 meta_draw_op_list_append (info->op_list, op);
01924
01925 push_state (info, STATE_RECTANGLE);
01926 }
01927 else if (ELEMENT_IS ("arc"))
01928 {
01929 MetaDrawOp *op;
01930 const char *color;
01931 const char *x;
01932 const char *y;
01933 const char *width;
01934 const char *height;
01935 const char *filled;
01936 const char *start_angle;
01937 const char *extent_angle;
01938 const char *from;
01939 const char *to;
01940 gboolean filled_val;
01941 double start_angle_val;
01942 double extent_angle_val;
01943 MetaColorSpec *color_spec;
01944
01945 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
01946 error,
01947 "color", &color,
01948 "x", &x, "y", &y,
01949 "width", &width, "height", &height,
01950 "filled", &filled,
01951 "start_angle", &start_angle,
01952 "extent_angle", &extent_angle,
01953 "from", &from,
01954 "to", &to,
01955 NULL))
01956 return;
01957
01958 if (color == NULL)
01959 {
01960 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01961 _("No \"color\" attribute on element <%s>"), element_name);
01962 return;
01963 }
01964
01965 if (x == NULL)
01966 {
01967 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01968 _("No \"x\" attribute on element <%s>"), element_name);
01969 return;
01970 }
01971
01972 if (y == NULL)
01973 {
01974 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01975 _("No \"y\" attribute on element <%s>"), element_name);
01976 return;
01977 }
01978
01979 if (width == NULL)
01980 {
01981 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01982 _("No \"width\" attribute on element <%s>"), element_name);
01983 return;
01984 }
01985
01986 if (height == NULL)
01987 {
01988 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01989 _("No \"height\" attribute on element <%s>"), element_name);
01990 return;
01991 }
01992
01993 if (META_THEME_ALLOWS (info->theme, META_THEME_DEGREES_IN_ARCS) )
01994 {
01995 if (start_angle == NULL && from == NULL)
01996 {
01997 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
01998 _("No \"start_angle\" or \"from\" attribute on element <%s>"), element_name);
01999 return;
02000 }
02001
02002 if (extent_angle == NULL && to == NULL)
02003 {
02004 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02005 _("No \"extent_angle\" or \"to\" attribute on element <%s>"), element_name);
02006 return;
02007 }
02008 }
02009 else
02010 {
02011 if (start_angle == NULL)
02012 {
02013 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02014 _("No \"start_angle\" attribute on element <%s>"), element_name);
02015 return;
02016 }
02017
02018 if (extent_angle == NULL)
02019 {
02020 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02021 _("No \"extent_angle\" attribute on element <%s>"), element_name);
02022 return;
02023 }
02024 }
02025
02026 #if 0
02027 if (!check_expression (x, FALSE, info->theme, context, error))
02028 return;
02029
02030 if (!check_expression (y, FALSE, info->theme, context, error))
02031 return;
02032
02033 if (!check_expression (width, FALSE, info->theme, context, error))
02034 return;
02035
02036 if (!check_expression (height, FALSE, info->theme, context, error))
02037 return;
02038 #endif
02039
02040 if (start_angle == NULL)
02041 {
02042 if (!parse_angle (from, &start_angle_val, context, error))
02043 return;
02044
02045 start_angle_val = (180-start_angle_val)/360.0;
02046 }
02047 else
02048 {
02049 if (!parse_angle (start_angle, &start_angle_val, context, error))
02050 return;
02051 }
02052
02053 if (extent_angle == NULL)
02054 {
02055 if (!parse_angle (to, &extent_angle_val, context, error))
02056 return;
02057
02058 extent_angle_val = ((180-extent_angle_val)/360.0) - start_angle_val;
02059 }
02060 else
02061 {
02062 if (!parse_angle (extent_angle, &extent_angle_val, context, error))
02063 return;
02064 }
02065
02066 filled_val = FALSE;
02067 if (filled && !parse_boolean (filled, &filled_val, context, error))
02068 return;
02069
02070
02071
02072
02073 color_spec = parse_color (info->theme, color, error);
02074 if (color_spec == NULL)
02075 {
02076 add_context_to_error (error, context);
02077 return;
02078 }
02079
02080 op = meta_draw_op_new (META_DRAW_ARC);
02081
02082 op->data.arc.color_spec = color_spec;
02083
02084 op->data.arc.x = meta_draw_spec_new (info->theme, x, NULL);
02085 op->data.arc.y = meta_draw_spec_new (info->theme, y, NULL);
02086 op->data.arc.width = meta_draw_spec_new (info->theme, width, NULL);
02087 op->data.arc.height = meta_draw_spec_new (info->theme, height, NULL);
02088
02089 op->data.arc.filled = filled_val;
02090 op->data.arc.start_angle = start_angle_val;
02091 op->data.arc.extent_angle = extent_angle_val;
02092
02093 g_assert (info->op_list);
02094
02095 meta_draw_op_list_append (info->op_list, op);
02096
02097 push_state (info, STATE_ARC);
02098 }
02099 else if (ELEMENT_IS ("clip"))
02100 {
02101 MetaDrawOp *op;
02102 const char *x;
02103 const char *y;
02104 const char *width;
02105 const char *height;
02106
02107 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
02108 error,
02109 "x", &x, "y", &y,
02110 "width", &width, "height", &height,
02111 NULL))
02112 return;
02113
02114 if (x == NULL)
02115 {
02116 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02117 _("No \"x\" attribute on element <%s>"), element_name);
02118 return;
02119 }
02120
02121 if (y == NULL)
02122 {
02123 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02124 _("No \"y\" attribute on element <%s>"), element_name);
02125 return;
02126 }
02127
02128 if (width == NULL)
02129 {
02130 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02131 _("No \"width\" attribute on element <%s>"), element_name);
02132 return;
02133 }
02134
02135 if (height == NULL)
02136 {
02137 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02138 _("No \"height\" attribute on element <%s>"), element_name);
02139 return;
02140 }
02141
02142 #if 0
02143 if (!check_expression (x, FALSE, info->theme, context, error))
02144 return;
02145
02146 if (!check_expression (y, FALSE, info->theme, context, error))
02147 return;
02148
02149 if (!check_expression (width, FALSE, info->theme, context, error))
02150 return;
02151
02152 if (!check_expression (height, FALSE, info->theme, context, error))
02153 return;
02154 #endif
02155 op = meta_draw_op_new (META_DRAW_CLIP);
02156
02157 op->data.clip.x = meta_draw_spec_new (info->theme, x, NULL);
02158 op->data.clip.y = meta_draw_spec_new (info->theme, y, NULL);
02159 op->data.clip.width = meta_draw_spec_new (info->theme, width, NULL);
02160 op->data.clip.height = meta_draw_spec_new (info->theme, height, NULL);
02161
02162 g_assert (info->op_list);
02163
02164 meta_draw_op_list_append (info->op_list, op);
02165
02166 push_state (info, STATE_CLIP);
02167 }
02168 else if (ELEMENT_IS ("tint"))
02169 {
02170 MetaDrawOp *op;
02171 const char *color;
02172 const char *x;
02173 const char *y;
02174 const char *width;
02175 const char *height;
02176 const char *alpha;
02177 MetaAlphaGradientSpec *alpha_spec;
02178 MetaColorSpec *color_spec;
02179
02180 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
02181 error,
02182 "color", &color,
02183 "x", &x, "y", &y,
02184 "width", &width, "height", &height,
02185 "alpha", &alpha,
02186 NULL))
02187 return;
02188
02189 if (color == NULL)
02190 {
02191 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02192 _("No \"color\" attribute on element <%s>"), element_name);
02193 return;
02194 }
02195
02196 if (x == NULL)
02197 {
02198 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02199 _("No \"x\" attribute on element <%s>"), element_name);
02200 return;
02201 }
02202
02203 if (y == NULL)
02204 {
02205 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02206 _("No \"y\" attribute on element <%s>"), element_name);
02207 return;
02208 }
02209
02210 if (width == NULL)
02211 {
02212 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02213 _("No \"width\" attribute on element <%s>"), element_name);
02214 return;
02215 }
02216
02217 if (height == NULL)
02218 {
02219 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02220 _("No \"height\" attribute on element <%s>"), element_name);
02221 return;
02222 }
02223
02224 if (alpha == NULL)
02225 {
02226 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02227 _("No \"alpha\" attribute on element <%s>"), element_name);
02228 return;
02229 }
02230 #if 0
02231 if (!check_expression (x, FALSE, info->theme, context, error))
02232 return;
02233
02234 if (!check_expression (y, FALSE, info->theme, context, error))
02235 return;
02236
02237 if (!check_expression (width, FALSE, info->theme, context, error))
02238 return;
02239
02240 if (!check_expression (height, FALSE, info->theme, context, error))
02241 return;
02242 #endif
02243 alpha_spec = NULL;
02244 if (!parse_alpha (alpha, &alpha_spec, context, error))
02245 return;
02246
02247
02248
02249
02250 color_spec = parse_color (info->theme, color, error);
02251 if (color_spec == NULL)
02252 {
02253 if (alpha_spec)
02254 meta_alpha_gradient_spec_free (alpha_spec);
02255
02256 add_context_to_error (error, context);
02257 return;
02258 }
02259
02260 op = meta_draw_op_new (META_DRAW_TINT);
02261
02262 op->data.tint.color_spec = color_spec;
02263 op->data.tint.alpha_spec = alpha_spec;
02264
02265 op->data.tint.x = meta_draw_spec_new (info->theme, x, NULL);
02266 op->data.tint.y = meta_draw_spec_new (info->theme, y, NULL);
02267 op->data.tint.width = meta_draw_spec_new (info->theme, width, NULL);
02268 op->data.tint.height = meta_draw_spec_new (info->theme, height, NULL);
02269
02270 g_assert (info->op_list);
02271
02272 meta_draw_op_list_append (info->op_list, op);
02273
02274 push_state (info, STATE_TINT);
02275 }
02276 else if (ELEMENT_IS ("gradient"))
02277 {
02278 const char *x;
02279 const char *y;
02280 const char *width;
02281 const char *height;
02282 const char *type;
02283 const char *alpha;
02284 MetaAlphaGradientSpec *alpha_spec;
02285 MetaGradientType type_val;
02286
02287 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
02288 error,
02289 "type", &type,
02290 "x", &x, "y", &y,
02291 "width", &width, "height", &height,
02292 "alpha", &alpha,
02293 NULL))
02294 return;
02295
02296 if (type == NULL)
02297 {
02298 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02299 _("No \"type\" attribute on element <%s>"), element_name);
02300 return;
02301 }
02302
02303 if (x == NULL)
02304 {
02305 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02306 _("No \"x\" attribute on element <%s>"), element_name);
02307 return;
02308 }
02309
02310 if (y == NULL)
02311 {
02312 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02313 _("No \"y\" attribute on element <%s>"), element_name);
02314 return;
02315 }
02316
02317 if (width == NULL)
02318 {
02319 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02320 _("No \"width\" attribute on element <%s>"), element_name);
02321 return;
02322 }
02323
02324 if (height == NULL)
02325 {
02326 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02327 _("No \"height\" attribute on element <%s>"), element_name);
02328 return;
02329 }
02330
02331 #if 0
02332 if (!check_expression (x, FALSE, info->theme, context, error))
02333 return;
02334
02335 if (!check_expression (y, FALSE, info->theme, context, error))
02336 return;
02337
02338 if (!check_expression (width, FALSE, info->theme, context, error))
02339 return;
02340
02341 if (!check_expression (height, FALSE, info->theme, context, error))
02342 return;
02343 #endif
02344
02345 type_val = meta_gradient_type_from_string (type);
02346 if (type_val == META_GRADIENT_LAST)
02347 {
02348 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02349 _("Did not understand value \"%s\" for type of gradient"),
02350 type);
02351 return;
02352 }
02353
02354 alpha_spec = NULL;
02355 if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
02356 return;
02357
02358 g_assert (info->op == NULL);
02359 info->op = meta_draw_op_new (META_DRAW_GRADIENT);
02360
02361 info->op->data.gradient.x = meta_draw_spec_new (info->theme, x, NULL);
02362 info->op->data.gradient.y = meta_draw_spec_new (info->theme, y, NULL);
02363 info->op->data.gradient.width = meta_draw_spec_new (info->theme,
02364 width, NULL);
02365 info->op->data.gradient.height = meta_draw_spec_new (info->theme,
02366 height, NULL);
02367
02368 info->op->data.gradient.gradient_spec = meta_gradient_spec_new (type_val);
02369
02370 info->op->data.gradient.alpha_spec = alpha_spec;
02371
02372 push_state (info, STATE_GRADIENT);
02373
02374
02375 }
02376 else if (ELEMENT_IS ("image"))
02377 {
02378 MetaDrawOp *op;
02379 const char *filename;
02380 const char *x;
02381 const char *y;
02382 const char *width;
02383 const char *height;
02384 const char *alpha;
02385 const char *colorize;
02386 const char *fill_type;
02387 MetaAlphaGradientSpec *alpha_spec;
02388 GdkPixbuf *pixbuf;
02389 MetaColorSpec *colorize_spec = NULL;
02390 MetaImageFillType fill_type_val;
02391 int h, w, c;
02392 int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride;
02393 guchar *pixbuf_pixels;
02394
02395 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
02396 error,
02397 "x", &x, "y", &y,
02398 "width", &width, "height", &height,
02399 "alpha", &alpha, "filename", &filename,
02400 "colorize", &colorize,
02401 "fill_type", &fill_type,
02402 NULL))
02403 return;
02404
02405 if (x == NULL)
02406 {
02407 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02408 _("No \"x\" attribute on element <%s>"), element_name);
02409 return;
02410 }
02411
02412 if (y == NULL)
02413 {
02414 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02415 _("No \"y\" attribute on element <%s>"), element_name);
02416 return;
02417 }
02418
02419 if (width == NULL)
02420 {
02421 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02422 _("No \"width\" attribute on element <%s>"), element_name);
02423 return;
02424 }
02425
02426 if (height == NULL)
02427 {
02428 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02429 _("No \"height\" attribute on element <%s>"), element_name);
02430 return;
02431 }
02432
02433 if (filename == NULL)
02434 {
02435 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02436 _("No \"filename\" attribute on element <%s>"), element_name);
02437 return;
02438 }
02439 #if 0
02440 if (!check_expression (x, TRUE, info->theme, context, error))
02441 return;
02442
02443 if (!check_expression (y, TRUE, info->theme, context, error))
02444 return;
02445
02446 if (!check_expression (width, TRUE, info->theme, context, error))
02447 return;
02448
02449 if (!check_expression (height, TRUE, info->theme, context, error))
02450 return;
02451 #endif
02452 fill_type_val = META_IMAGE_FILL_SCALE;
02453 if (fill_type)
02454 {
02455 fill_type_val = meta_image_fill_type_from_string (fill_type);
02456
02457 if (((int) fill_type_val) == -1)
02458 {
02459 set_error (error, context, G_MARKUP_ERROR,
02460 G_MARKUP_ERROR_PARSE,
02461 _("Did not understand fill type \"%s\" for <%s> element"),
02462 fill_type, element_name);
02463 }
02464 }
02465
02466
02467
02468
02469
02470
02471
02472 pixbuf = meta_theme_load_image (info->theme, filename, 64, error);
02473
02474 if (pixbuf == NULL)
02475 {
02476 add_context_to_error (error, context);
02477 return;
02478 }
02479
02480 if (colorize)
02481 {
02482 colorize_spec = parse_color (info->theme, colorize, error);
02483
02484 if (colorize_spec == NULL)
02485 {
02486 add_context_to_error (error, context);
02487 g_object_unref (G_OBJECT (pixbuf));
02488 return;
02489 }
02490 }
02491
02492 alpha_spec = NULL;
02493 if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
02494 {
02495 g_object_unref (G_OBJECT (pixbuf));
02496 return;
02497 }
02498
02499 op = meta_draw_op_new (META_DRAW_IMAGE);
02500
02501 op->data.image.pixbuf = pixbuf;
02502 op->data.image.colorize_spec = colorize_spec;
02503
02504 op->data.image.x = meta_draw_spec_new (info->theme, x, NULL);
02505 op->data.image.y = meta_draw_spec_new (info->theme, y, NULL);
02506 op->data.image.width = meta_draw_spec_new (info->theme, width, NULL);
02507 op->data.image.height = meta_draw_spec_new (info->theme, height, NULL);
02508
02509 op->data.image.alpha_spec = alpha_spec;
02510 op->data.image.fill_type = fill_type_val;
02511
02512
02513 pixbuf_n_channels = gdk_pixbuf_get_n_channels(pixbuf);
02514 pixbuf_width = gdk_pixbuf_get_width(pixbuf);
02515 pixbuf_height = gdk_pixbuf_get_height(pixbuf);
02516 pixbuf_rowstride = gdk_pixbuf_get_rowstride(pixbuf);
02517 pixbuf_pixels = gdk_pixbuf_get_pixels(pixbuf);
02518
02519
02520 for (h = 0; h < pixbuf_height; h++)
02521 {
02522 for (w = 1; w < pixbuf_width; w++)
02523 {
02524 for (c = 0; c < pixbuf_n_channels; c++)
02525 {
02526 if (pixbuf_pixels[(h * pixbuf_rowstride) + c] !=
02527 pixbuf_pixels[(h * pixbuf_rowstride) + w + c])
02528 break;
02529 }
02530 if (c < pixbuf_n_channels)
02531 break;
02532 }
02533 if (w < pixbuf_width)
02534 break;
02535 }
02536
02537 if (h >= pixbuf_height)
02538 {
02539 op->data.image.horizontal_stripes = TRUE;
02540 }
02541 else
02542 {
02543 op->data.image.horizontal_stripes = FALSE;
02544 }
02545
02546
02547 for (w = 0; w < pixbuf_width; w++)
02548 {
02549 for (h = 1; h < pixbuf_height; h++)
02550 {
02551 for (c = 0; c < pixbuf_n_channels; c++)
02552 {
02553 if (pixbuf_pixels[w + c] !=
02554 pixbuf_pixels[(h * pixbuf_rowstride) + w + c])
02555 break;
02556 }
02557 if (c < pixbuf_n_channels)
02558 break;
02559 }
02560 if (h < pixbuf_height)
02561 break;
02562 }
02563
02564 if (w >= pixbuf_width)
02565 {
02566 op->data.image.vertical_stripes = TRUE;
02567 }
02568 else
02569 {
02570 op->data.image.vertical_stripes = FALSE;
02571 }
02572
02573 g_assert (info->op_list);
02574
02575 meta_draw_op_list_append (info->op_list, op);
02576
02577 push_state (info, STATE_IMAGE);
02578 }
02579 else if (ELEMENT_IS ("gtk_arrow"))
02580 {
02581 MetaDrawOp *op;
02582 const char *state;
02583 const char *shadow;
02584 const char *arrow;
02585 const char *x;
02586 const char *y;
02587 const char *width;
02588 const char *height;
02589 const char *filled;
02590 gboolean filled_val;
02591 GtkStateType state_val;
02592 GtkShadowType shadow_val;
02593 GtkArrowType arrow_val;
02594
02595 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
02596 error,
02597 "state", &state,
02598 "shadow", &shadow,
02599 "arrow", &arrow,
02600 "x", &x, "y", &y,
02601 "width", &width, "height", &height,
02602 "filled", &filled,
02603 NULL))
02604 return;
02605
02606 if (state == NULL)
02607 {
02608 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02609 _("No \"state\" attribute on element <%s>"), element_name);
02610 return;
02611 }
02612
02613 if (shadow == NULL)
02614 {
02615 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02616 _("No \"shadow\" attribute on element <%s>"), element_name);
02617 return;
02618 }
02619
02620 if (arrow == NULL)
02621 {
02622 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02623 _("No \"arrow\" attribute on element <%s>"), element_name);
02624 return;
02625 }
02626
02627 if (x == NULL)
02628 {
02629 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02630 _("No \"x\" attribute on element <%s>"), element_name);
02631 return;
02632 }
02633
02634 if (y == NULL)
02635 {
02636 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02637 _("No \"y\" attribute on element <%s>"), element_name);
02638 return;
02639 }
02640
02641 if (width == NULL)
02642 {
02643 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02644 _("No \"width\" attribute on element <%s>"), element_name);
02645 return;
02646 }
02647
02648 if (height == NULL)
02649 {
02650 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02651 _("No \"height\" attribute on element <%s>"), element_name);
02652 return;
02653 }
02654 #if 0
02655 if (!check_expression (x, FALSE, info->theme, context, error))
02656 return;
02657
02658 if (!check_expression (y, FALSE, info->theme, context, error))
02659 return;
02660
02661 if (!check_expression (width, FALSE, info->theme, context, error))
02662 return;
02663
02664 if (!check_expression (height, FALSE, info->theme, context, error))
02665 return;
02666 #endif
02667 filled_val = TRUE;
02668 if (filled && !parse_boolean (filled, &filled_val, context, error))
02669 return;
02670
02671 state_val = meta_gtk_state_from_string (state);
02672 if (((int) state_val) == -1)
02673 {
02674 set_error (error, context, G_MARKUP_ERROR,
02675 G_MARKUP_ERROR_PARSE,
02676 _("Did not understand state \"%s\" for <%s> element"),
02677 state, element_name);
02678 return;
02679 }
02680
02681 shadow_val = meta_gtk_shadow_from_string (shadow);
02682 if (((int) shadow_val) == -1)
02683 {
02684 set_error (error, context, G_MARKUP_ERROR,
02685 G_MARKUP_ERROR_PARSE,
02686 _("Did not understand shadow \"%s\" for <%s> element"),
02687 shadow, element_name);
02688 return;
02689 }
02690
02691 arrow_val = meta_gtk_arrow_from_string (arrow);
02692 if (((int) arrow_val) == -1)
02693 {
02694 set_error (error, context, G_MARKUP_ERROR,
02695 G_MARKUP_ERROR_PARSE,
02696 _("Did not understand arrow \"%s\" for <%s> element"),
02697 arrow, element_name);
02698 return;
02699 }
02700
02701 op = meta_draw_op_new (META_DRAW_GTK_ARROW);
02702
02703 op->data.gtk_arrow.x = meta_draw_spec_new (info->theme, x, NULL);
02704 op->data.gtk_arrow.y = meta_draw_spec_new (info->theme, y, NULL);
02705 op->data.gtk_arrow.width = meta_draw_spec_new (info->theme, width, NULL);
02706 op->data.gtk_arrow.height = meta_draw_spec_new (info->theme,
02707 height, NULL);
02708
02709 op->data.gtk_arrow.filled = filled_val;
02710 op->data.gtk_arrow.state = state_val;
02711 op->data.gtk_arrow.shadow = shadow_val;
02712 op->data.gtk_arrow.arrow = arrow_val;
02713
02714 g_assert (info->op_list);
02715
02716 meta_draw_op_list_append (info->op_list, op);
02717
02718 push_state (info, STATE_GTK_ARROW);
02719 }
02720 else if (ELEMENT_IS ("gtk_box"))
02721 {
02722 MetaDrawOp *op;
02723 const char *state;
02724 const char *shadow;
02725 const char *x;
02726 const char *y;
02727 const char *width;
02728 const char *height;
02729 GtkStateType state_val;
02730 GtkShadowType shadow_val;
02731
02732 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
02733 error,
02734 "state", &state,
02735 "shadow", &shadow,
02736 "x", &x, "y", &y,
02737 "width", &width, "height", &height,
02738 NULL))
02739 return;
02740
02741 if (state == NULL)
02742 {
02743 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02744 _("No \"state\" attribute on element <%s>"), element_name);
02745 return;
02746 }
02747
02748 if (shadow == NULL)
02749 {
02750 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02751 _("No \"shadow\" attribute on element <%s>"), element_name);
02752 return;
02753 }
02754
02755 if (x == NULL)
02756 {
02757 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02758 _("No \"x\" attribute on element <%s>"), element_name);
02759 return;
02760 }
02761
02762 if (y == NULL)
02763 {
02764 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02765 _("No \"y\" attribute on element <%s>"), element_name);
02766 return;
02767 }
02768
02769 if (width == NULL)
02770 {
02771 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02772 _("No \"width\" attribute on element <%s>"), element_name);
02773 return;
02774 }
02775
02776 if (height == NULL)
02777 {
02778 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02779 _("No \"height\" attribute on element <%s>"), element_name);
02780 return;
02781 }
02782 #if 0
02783 if (!check_expression (x, FALSE, info->theme, context, error))
02784 return;
02785
02786 if (!check_expression (y, FALSE, info->theme, context, error))
02787 return;
02788
02789 if (!check_expression (width, FALSE, info->theme, context, error))
02790 return;
02791
02792 if (!check_expression (height, FALSE, info->theme, context, error))
02793 return;
02794 #endif
02795 state_val = meta_gtk_state_from_string (state);
02796 if (((int) state_val) == -1)
02797 {
02798 set_error (error, context, G_MARKUP_ERROR,
02799 G_MARKUP_ERROR_PARSE,
02800 _("Did not understand state \"%s\" for <%s> element"),
02801 state, element_name);
02802 return;
02803 }
02804
02805 shadow_val = meta_gtk_shadow_from_string (shadow);
02806 if (((int) shadow_val) == -1)
02807 {
02808 set_error (error, context, G_MARKUP_ERROR,
02809 G_MARKUP_ERROR_PARSE,
02810 _("Did not understand shadow \"%s\" for <%s> element"),
02811 shadow, element_name);
02812 return;
02813 }
02814
02815 op = meta_draw_op_new (META_DRAW_GTK_BOX);
02816
02817 op->data.gtk_box.x = meta_draw_spec_new (info->theme, x, NULL);
02818 op->data.gtk_box.y = meta_draw_spec_new (info->theme, y, NULL);
02819 op->data.gtk_box.width = meta_draw_spec_new (info->theme, width, NULL);
02820 op->data.gtk_box.height = meta_draw_spec_new (info->theme, height, NULL);
02821
02822 op->data.gtk_box.state = state_val;
02823 op->data.gtk_box.shadow = shadow_val;
02824
02825 g_assert (info->op_list);
02826
02827 meta_draw_op_list_append (info->op_list, op);
02828
02829 push_state (info, STATE_GTK_BOX);
02830 }
02831 else if (ELEMENT_IS ("gtk_vline"))
02832 {
02833 MetaDrawOp *op;
02834 const char *state;
02835 const char *x;
02836 const char *y1;
02837 const char *y2;
02838 GtkStateType state_val;
02839
02840 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
02841 error,
02842 "state", &state,
02843 "x", &x, "y1", &y1, "y2", &y2,
02844 NULL))
02845 return;
02846
02847 if (state == NULL)
02848 {
02849 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02850 _("No \"state\" attribute on element <%s>"), element_name);
02851 return;
02852 }
02853
02854 if (x == NULL)
02855 {
02856 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02857 _("No \"x\" attribute on element <%s>"), element_name);
02858 return;
02859 }
02860
02861 if (y1 == NULL)
02862 {
02863 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02864 _("No \"y1\" attribute on element <%s>"), element_name);
02865 return;
02866 }
02867
02868 if (y2 == NULL)
02869 {
02870 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02871 _("No \"y2\" attribute on element <%s>"), element_name);
02872 return;
02873 }
02874
02875 #if 0
02876 if (!check_expression (x, FALSE, info->theme, context, error))
02877 return;
02878
02879 if (!check_expression (y1, FALSE, info->theme, context, error))
02880 return;
02881
02882 if (!check_expression (y2, FALSE, info->theme, context, error))
02883 return;
02884 #endif
02885
02886 state_val = meta_gtk_state_from_string (state);
02887 if (((int) state_val) == -1)
02888 {
02889 set_error (error, context, G_MARKUP_ERROR,
02890 G_MARKUP_ERROR_PARSE,
02891 _("Did not understand state \"%s\" for <%s> element"),
02892 state, element_name);
02893 return;
02894 }
02895
02896 op = meta_draw_op_new (META_DRAW_GTK_VLINE);
02897
02898 op->data.gtk_vline.x = meta_draw_spec_new (info->theme, x, NULL);
02899 op->data.gtk_vline.y1 = meta_draw_spec_new (info->theme, y1, NULL);
02900 op->data.gtk_vline.y2 = meta_draw_spec_new (info->theme, y2, NULL);
02901
02902 op->data.gtk_vline.state = state_val;
02903
02904 g_assert (info->op_list);
02905
02906 meta_draw_op_list_append (info->op_list, op);
02907
02908 push_state (info, STATE_GTK_VLINE);
02909 }
02910 else if (ELEMENT_IS ("icon"))
02911 {
02912 MetaDrawOp *op;
02913 const char *x;
02914 const char *y;
02915 const char *width;
02916 const char *height;
02917 const char *alpha;
02918 const char *fill_type;
02919 MetaAlphaGradientSpec *alpha_spec;
02920 MetaImageFillType fill_type_val;
02921
02922 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
02923 error,
02924 "x", &x, "y", &y,
02925 "width", &width, "height", &height,
02926 "alpha", &alpha,
02927 "fill_type", &fill_type,
02928 NULL))
02929 return;
02930
02931 if (x == NULL)
02932 {
02933 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02934 _("No \"x\" attribute on element <%s>"), element_name);
02935 return;
02936 }
02937
02938 if (y == NULL)
02939 {
02940 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02941 _("No \"y\" attribute on element <%s>"), element_name);
02942 return;
02943 }
02944
02945 if (width == NULL)
02946 {
02947 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02948 _("No \"width\" attribute on element <%s>"), element_name);
02949 return;
02950 }
02951
02952 if (height == NULL)
02953 {
02954 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
02955 _("No \"height\" attribute on element <%s>"), element_name);
02956 return;
02957 }
02958 #if 0
02959 if (!check_expression (x, FALSE, info->theme, context, error))
02960 return;
02961
02962 if (!check_expression (y, FALSE, info->theme, context, error))
02963 return;
02964
02965 if (!check_expression (width, FALSE, info->theme, context, error))
02966 return;
02967
02968 if (!check_expression (height, FALSE, info->theme, context, error))
02969 return;
02970 #endif
02971 fill_type_val = META_IMAGE_FILL_SCALE;
02972 if (fill_type)
02973 {
02974 fill_type_val = meta_image_fill_type_from_string (fill_type);
02975
02976 if (((int) fill_type_val) == -1)
02977 {
02978 set_error (error, context, G_MARKUP_ERROR,
02979 G_MARKUP_ERROR_PARSE,
02980 _("Did not understand fill type \"%s\" for <%s> element"),
02981 fill_type, element_name);
02982 }
02983 }
02984
02985 alpha_spec = NULL;
02986 if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
02987 return;
02988
02989 op = meta_draw_op_new (META_DRAW_ICON);
02990
02991 op->data.icon.x = meta_draw_spec_new (info->theme, x, NULL);
02992 op->data.icon.y = meta_draw_spec_new (info->theme, y, NULL);
02993 op->data.icon.width = meta_draw_spec_new (info->theme, width, NULL);
02994 op->data.icon.height = meta_draw_spec_new (info->theme, height, NULL);
02995
02996 op->data.icon.alpha_spec = alpha_spec;
02997 op->data.icon.fill_type = fill_type_val;
02998
02999 g_assert (info->op_list);
03000
03001 meta_draw_op_list_append (info->op_list, op);
03002
03003 push_state (info, STATE_ICON);
03004 }
03005 else if (ELEMENT_IS ("title"))
03006 {
03007 MetaDrawOp *op;
03008 const char *color;
03009 const char *x;
03010 const char *y;
03011 MetaColorSpec *color_spec;
03012
03013 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
03014 error,
03015 "color", &color,
03016 "x", &x, "y", &y,
03017 NULL))
03018 return;
03019
03020 if (color == NULL)
03021 {
03022 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03023 _("No \"color\" attribute on element <%s>"), element_name);
03024 return;
03025 }
03026
03027 if (x == NULL)
03028 {
03029 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03030 _("No \"x\" attribute on element <%s>"), element_name);
03031 return;
03032 }
03033
03034 if (y == NULL)
03035 {
03036 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03037 _("No \"y\" attribute on element <%s>"), element_name);
03038 return;
03039 }
03040
03041 #if 0
03042 if (!check_expression (x, FALSE, info->theme, context, error))
03043 return;
03044
03045 if (!check_expression (y, FALSE, info->theme, context, error))
03046 return;
03047 #endif
03048
03049
03050
03051
03052 color_spec = parse_color (info->theme, color, error);
03053 if (color_spec == NULL)
03054 {
03055 add_context_to_error (error, context);
03056 return;
03057 }
03058
03059 op = meta_draw_op_new (META_DRAW_TITLE);
03060
03061 op->data.title.color_spec = color_spec;
03062
03063 op->data.title.x = meta_draw_spec_new (info->theme, x, NULL);
03064 op->data.title.y = meta_draw_spec_new (info->theme, y, NULL);
03065
03066 g_assert (info->op_list);
03067
03068 meta_draw_op_list_append (info->op_list, op);
03069
03070 push_state (info, STATE_TITLE);
03071 }
03072 else if (ELEMENT_IS ("include"))
03073 {
03074 MetaDrawOp *op;
03075 const char *name;
03076 const char *x;
03077 const char *y;
03078 const char *width;
03079 const char *height;
03080 MetaDrawOpList *op_list;
03081
03082 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
03083 error,
03084 "x", &x, "y", &y,
03085 "width", &width, "height", &height,
03086 "name", &name,
03087 NULL))
03088 return;
03089
03090 if (name == NULL)
03091 {
03092 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03093 _("No \"%s\" attribute on <%s> element"), "name", element_name);
03094 return;
03095 }
03096
03097
03098
03099
03100 #if 0
03101 if (x && !check_expression (x, FALSE, info->theme, context, error))
03102 return;
03103
03104 if (y && !check_expression (y, FALSE, info->theme, context, error))
03105 return;
03106
03107 if (width && !check_expression (width, FALSE, info->theme, context, error))
03108 return;
03109
03110 if (height && !check_expression (height, FALSE, info->theme, context, error))
03111 return;
03112 #endif
03113
03114 op_list = meta_theme_lookup_draw_op_list (info->theme,
03115 name);
03116 if (op_list == NULL)
03117 {
03118 set_error (error, context, G_MARKUP_ERROR,
03119 G_MARKUP_ERROR_PARSE,
03120 _("No <draw_ops> called \"%s\" has been defined"),
03121 name);
03122 return;
03123 }
03124
03125 g_assert (info->op_list);
03126
03127 if (op_list == info->op_list ||
03128 meta_draw_op_list_contains (op_list, info->op_list))
03129 {
03130 set_error (error, context, G_MARKUP_ERROR,
03131 G_MARKUP_ERROR_PARSE,
03132 _("Including draw_ops \"%s\" here would create a circular reference"),
03133 name);
03134 return;
03135 }
03136
03137 op = meta_draw_op_new (META_DRAW_OP_LIST);
03138
03139 meta_draw_op_list_ref (op_list);
03140 op->data.op_list.op_list = op_list;
03141
03142 op->data.op_list.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL);
03143 op->data.op_list.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL);
03144 op->data.op_list.width = meta_draw_spec_new (info->theme,
03145 width ? width : "width",
03146 NULL);
03147 op->data.op_list.height = meta_draw_spec_new (info->theme,
03148 height ? height : "height",
03149 NULL);
03150
03151 meta_draw_op_list_append (info->op_list, op);
03152
03153 push_state (info, STATE_INCLUDE);
03154 }
03155 else if (ELEMENT_IS ("tile"))
03156 {
03157 MetaDrawOp *op;
03158 const char *name;
03159 const char *x;
03160 const char *y;
03161 const char *width;
03162 const char *height;
03163 const char *tile_xoffset;
03164 const char *tile_yoffset;
03165 const char *tile_width;
03166 const char *tile_height;
03167 MetaDrawOpList *op_list;
03168
03169 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
03170 error,
03171 "x", &x, "y", &y,
03172 "width", &width, "height", &height,
03173 "name", &name,
03174 "tile_xoffset", &tile_xoffset,
03175 "tile_yoffset", &tile_yoffset,
03176 "tile_width", &tile_width,
03177 "tile_height", &tile_height,
03178 NULL))
03179 return;
03180
03181 if (name == NULL)
03182 {
03183 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03184 _("No \"%s\" attribute on <%s> element"), "name", element_name);
03185 return;
03186 }
03187
03188 if (tile_width == NULL)
03189 {
03190 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03191 _("No \"%s\" attribute on <%s> element"), "tile_width", element_name);
03192 return;
03193 }
03194
03195 if (tile_height == NULL)
03196 {
03197 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03198 _("No \"%s\" attribute on <%s> element"), "tile_height", element_name);
03199 return;
03200 }
03201
03202
03203 #if 0
03204 if (tile_xoffset && !check_expression (tile_xoffset, FALSE, info->theme, context, error))
03205 return;
03206
03207 if (tile_yoffset && !check_expression (tile_yoffset, FALSE, info->theme, context, error))
03208 return;
03209
03210
03211
03212
03213 if (x && !check_expression (x, FALSE, info->theme, context, error))
03214 return;
03215
03216 if (y && !check_expression (y, FALSE, info->theme, context, error))
03217 return;
03218
03219 if (width && !check_expression (width, FALSE, info->theme, context, error))
03220 return;
03221
03222 if (height && !check_expression (height, FALSE, info->theme, context, error))
03223 return;
03224
03225 if (!check_expression (tile_width, FALSE, info->theme, context, error))
03226 return;
03227
03228 if (!check_expression (tile_height, FALSE, info->theme, context, error))
03229 return;
03230 #endif
03231 op_list = meta_theme_lookup_draw_op_list (info->theme,
03232 name);
03233 if (op_list == NULL)
03234 {
03235 set_error (error, context, G_MARKUP_ERROR,
03236 G_MARKUP_ERROR_PARSE,
03237 _("No <draw_ops> called \"%s\" has been defined"),
03238 name);
03239 return;
03240 }
03241
03242 g_assert (info->op_list);
03243
03244 if (op_list == info->op_list ||
03245 meta_draw_op_list_contains (op_list, info->op_list))
03246 {
03247 set_error (error, context, G_MARKUP_ERROR,
03248 G_MARKUP_ERROR_PARSE,
03249 _("Including draw_ops \"%s\" here would create a circular reference"),
03250 name);
03251 return;
03252 }
03253
03254 op = meta_draw_op_new (META_DRAW_TILE);
03255
03256 meta_draw_op_list_ref (op_list);
03257
03258 op->data.tile.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL);
03259 op->data.tile.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL);
03260 op->data.tile.width = meta_draw_spec_new (info->theme,
03261 width ? width : "width",
03262 NULL);
03263 op->data.tile.height = meta_draw_spec_new (info->theme,
03264 height ? height : "height",
03265 NULL);
03266 op->data.tile.tile_xoffset = meta_draw_spec_new (info->theme,
03267 tile_xoffset ? tile_xoffset : "0",
03268 NULL);
03269 op->data.tile.tile_yoffset = meta_draw_spec_new (info->theme,
03270 tile_yoffset ? tile_yoffset : "0",
03271 NULL);
03272 op->data.tile.tile_width = meta_draw_spec_new (info->theme, tile_width, NULL);
03273 op->data.tile.tile_height = meta_draw_spec_new (info->theme, tile_height, NULL);
03274
03275 op->data.tile.op_list = op_list;
03276
03277 meta_draw_op_list_append (info->op_list, op);
03278
03279 push_state (info, STATE_TILE);
03280 }
03281 else
03282 {
03283 set_error (error, context,
03284 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03285 _("Element <%s> is not allowed below <%s>"),
03286 element_name, "draw_ops");
03287 }
03288 }
03289
03290 static void
03291 parse_gradient_element (GMarkupParseContext *context,
03292 const gchar *element_name,
03293 const gchar **attribute_names,
03294 const gchar **attribute_values,
03295 ParseInfo *info,
03296 GError **error)
03297 {
03298 g_return_if_fail (peek_state (info) == STATE_GRADIENT);
03299
03300 if (ELEMENT_IS ("color"))
03301 {
03302 const char *value = NULL;
03303 MetaColorSpec *color_spec;
03304
03305 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
03306 error,
03307 "value", &value,
03308 NULL))
03309 return;
03310
03311 if (value == NULL)
03312 {
03313 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03314 _("No \"value\" attribute on <%s> element"),
03315 element_name);
03316 return;
03317 }
03318
03319 color_spec = parse_color (info->theme, value, error);
03320 if (color_spec == NULL)
03321 {
03322 add_context_to_error (error, context);
03323 return;
03324 }
03325
03326 g_assert (info->op);
03327 g_assert (info->op->type == META_DRAW_GRADIENT);
03328 g_assert (info->op->data.gradient.gradient_spec != NULL);
03329 info->op->data.gradient.gradient_spec->color_specs =
03330 g_slist_append (info->op->data.gradient.gradient_spec->color_specs,
03331 color_spec);
03332
03333 push_state (info, STATE_COLOR);
03334 }
03335 else
03336 {
03337 set_error (error, context,
03338 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03339 _("Element <%s> is not allowed below <%s>"),
03340 element_name, "gradient");
03341 }
03342 }
03343
03344 static void
03345 parse_style_element (GMarkupParseContext *context,
03346 const gchar *element_name,
03347 const gchar **attribute_names,
03348 const gchar **attribute_values,
03349 ParseInfo *info,
03350 GError **error)
03351 {
03352 g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE);
03353
03354 g_assert (info->style);
03355
03356 if (ELEMENT_IS ("piece"))
03357 {
03358 const char *position = NULL;
03359 const char *draw_ops = NULL;
03360
03361 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
03362 error,
03363 "position", &position,
03364 "draw_ops", &draw_ops,
03365 NULL))
03366 return;
03367
03368 if (position == NULL)
03369 {
03370 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03371 _("No \"position\" attribute on <%s> element"),
03372 element_name);
03373 return;
03374 }
03375
03376 info->piece = meta_frame_piece_from_string (position);
03377 if (info->piece == META_FRAME_PIECE_LAST)
03378 {
03379 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03380 _("Unknown position \"%s\" for frame piece"),
03381 position);
03382 return;
03383 }
03384
03385 if (info->style->pieces[info->piece] != NULL)
03386 {
03387 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03388 _("Frame style already has a piece at position %s"),
03389 position);
03390 return;
03391 }
03392
03393 g_assert (info->op_list == NULL);
03394
03395 if (draw_ops)
03396 {
03397 MetaDrawOpList *op_list;
03398
03399 op_list = meta_theme_lookup_draw_op_list (info->theme,
03400 draw_ops);
03401
03402 if (op_list == NULL)
03403 {
03404 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03405 _("No <draw_ops> with the name \"%s\" has been defined"),
03406 draw_ops);
03407 return;
03408 }
03409
03410 meta_draw_op_list_ref (op_list);
03411 info->op_list = op_list;
03412 }
03413
03414 push_state (info, STATE_PIECE);
03415 }
03416 else if (ELEMENT_IS ("button"))
03417 {
03418 const char *function = NULL;
03419 const char *state = NULL;
03420 const char *draw_ops = NULL;
03421
03422 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
03423 error,
03424 "function", &function,
03425 "state", &state,
03426 "draw_ops", &draw_ops,
03427 NULL))
03428 return;
03429
03430 if (function == NULL)
03431 {
03432 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03433 _("No \"function\" attribute on <%s> element"),
03434 element_name);
03435 return;
03436 }
03437
03438 if (state == NULL)
03439 {
03440 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03441 _("No \"state\" attribute on <%s> element"),
03442 element_name);
03443 return;
03444 }
03445
03446 info->button_type = meta_button_type_from_string (function, info->theme);
03447 if (info->button_type == META_BUTTON_TYPE_LAST)
03448 {
03449 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03450 _("Unknown function \"%s\" for button"),
03451 function);
03452 return;
03453 }
03454
03455 if (meta_theme_earliest_version_with_button (info->button_type) >
03456 info->theme->format_version)
03457 {
03458 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03459 _("Button function \"%s\" does not exist in this version (%d, need %d)"),
03460 function,
03461 info->theme->format_version,
03462 meta_theme_earliest_version_with_button (info->button_type)
03463 );
03464 return;
03465 }
03466
03467 info->button_state = meta_button_state_from_string (state);
03468 if (info->button_state == META_BUTTON_STATE_LAST)
03469 {
03470 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03471 _("Unknown state \"%s\" for button"),
03472 state);
03473 return;
03474 }
03475
03476 if (info->style->buttons[info->button_type][info->button_state] != NULL)
03477 {
03478 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03479 _("Frame style already has a button for function %s state %s"),
03480 function, state);
03481 return;
03482 }
03483
03484 g_assert (info->op_list == NULL);
03485
03486 if (draw_ops)
03487 {
03488 MetaDrawOpList *op_list;
03489
03490 op_list = meta_theme_lookup_draw_op_list (info->theme,
03491 draw_ops);
03492
03493 if (op_list == NULL)
03494 {
03495 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03496 _("No <draw_ops> with the name \"%s\" has been defined"),
03497 draw_ops);
03498 return;
03499 }
03500
03501 meta_draw_op_list_ref (op_list);
03502 info->op_list = op_list;
03503 }
03504
03505 push_state (info, STATE_BUTTON);
03506 }
03507 else
03508 {
03509 set_error (error, context,
03510 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03511 _("Element <%s> is not allowed below <%s>"),
03512 element_name, "frame_style");
03513 }
03514 }
03515
03516 static void
03517 parse_style_set_element (GMarkupParseContext *context,
03518 const gchar *element_name,
03519 const gchar **attribute_names,
03520 const gchar **attribute_values,
03521 ParseInfo *info,
03522 GError **error)
03523 {
03524 g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE_SET);
03525
03526 if (ELEMENT_IS ("frame"))
03527 {
03528 const char *focus = NULL;
03529 const char *state = NULL;
03530 const char *resize = NULL;
03531 const char *style = NULL;
03532 MetaFrameFocus frame_focus;
03533 MetaFrameState frame_state;
03534 MetaFrameResize frame_resize;
03535 MetaFrameStyle *frame_style;
03536
03537 if (!locate_attributes (context, element_name, attribute_names, attribute_values,
03538 error,
03539 "focus", &focus,
03540 "state", &state,
03541 "resize", &resize,
03542 "style", &style,
03543 NULL))
03544 return;
03545
03546 if (focus == NULL)
03547 {
03548 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03549 _("No \"focus\" attribute on <%s> element"),
03550 element_name);
03551 return;
03552 }
03553
03554 if (state == NULL)
03555 {
03556 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03557 _("No \"state\" attribute on <%s> element"),
03558 element_name);
03559 return;
03560 }
03561
03562 if (style == NULL)
03563 {
03564 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03565 _("No \"style\" attribute on <%s> element"),
03566 element_name);
03567 return;
03568 }
03569
03570 frame_focus = meta_frame_focus_from_string (focus);
03571 if (frame_focus == META_FRAME_FOCUS_LAST)
03572 {
03573 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03574 _("\"%s\" is not a valid value for focus attribute"),
03575 focus);
03576 return;
03577 }
03578
03579 frame_state = meta_frame_state_from_string (state);
03580 if (frame_state == META_FRAME_STATE_LAST)
03581 {
03582 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03583 _("\"%s\" is not a valid value for state attribute"),
03584 focus);
03585 return;
03586 }
03587
03588 frame_style = meta_theme_lookup_style (info->theme, style);
03589
03590 if (frame_style == NULL)
03591 {
03592 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03593 _("A style called \"%s\" has not been defined"),
03594 style);
03595 return;
03596 }
03597
03598 switch (frame_state)
03599 {
03600 case META_FRAME_STATE_NORMAL:
03601 if (resize == NULL)
03602 {
03603 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03604 _("No \"resize\" attribute on <%s> element"),
03605 element_name);
03606 return;
03607 }
03608
03609
03610 frame_resize = meta_frame_resize_from_string (resize);
03611 if (frame_resize == META_FRAME_RESIZE_LAST)
03612 {
03613 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03614 _("\"%s\" is not a valid value for resize attribute"),
03615 focus);
03616 return;
03617 }
03618
03619 break;
03620
03621 case META_FRAME_STATE_SHADED:
03622 if (META_THEME_ALLOWS (info->theme, META_THEME_UNRESIZABLE_SHADED_STYLES))
03623 {
03624 if (resize == NULL)
03625
03626
03627
03628
03629
03630 frame_resize = META_FRAME_RESIZE_BOTH;
03631 else
03632 {
03633 frame_resize = meta_frame_resize_from_string (resize);
03634 if (frame_resize == META_FRAME_RESIZE_LAST)
03635 {
03636 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03637 _("\"%s\" is not a valid value for resize attribute"),
03638 focus);
03639 return;
03640 }
03641 }
03642 }
03643 else
03644 {
03645 if (resize != NULL)
03646 {
03647 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03648 _("Should not have \"resize\" attribute on <%s> element for maximized/shaded states"),
03649 element_name);
03650 return;
03651 }
03652
03653
03654 frame_resize = META_FRAME_RESIZE_BOTH;
03655 }
03656 break;
03657
03658 default:
03659 if (resize != NULL)
03660 {
03661 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03662 _("Should not have \"resize\" attribute on <%s> element for maximized states"),
03663 element_name);
03664 return;
03665 }
03666
03667 frame_resize = META_FRAME_RESIZE_LAST;
03668 }
03669
03670 switch (frame_state)
03671 {
03672 case META_FRAME_STATE_NORMAL:
03673 if (info->style_set->normal_styles[frame_resize][frame_focus])
03674 {
03675 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03676 _("Style has already been specified for state %s resize %s focus %s"),
03677 state, resize, focus);
03678 return;
03679 }
03680 meta_frame_style_ref (frame_style);
03681 info->style_set->normal_styles[frame_resize][frame_focus] = frame_style;
03682 break;
03683 case META_FRAME_STATE_MAXIMIZED:
03684 if (info->style_set->maximized_styles[frame_focus])
03685 {
03686 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03687 _("Style has already been specified for state %s focus %s"),
03688 state, focus);
03689 return;
03690 }
03691 meta_frame_style_ref (frame_style);
03692 info->style_set->maximized_styles[frame_focus] = frame_style;
03693 break;
03694 case META_FRAME_STATE_SHADED:
03695 if (info->style_set->shaded_styles[frame_resize][frame_focus])
03696 {
03697 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03698 _("Style has already been specified for state %s resize %s focus %s"),
03699 state, resize, focus);
03700 return;
03701 }
03702 meta_frame_style_ref (frame_style);
03703 info->style_set->shaded_styles[frame_resize][frame_focus] = frame_style;
03704 break;
03705 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
03706 if (info->style_set->maximized_and_shaded_styles[frame_focus])
03707 {
03708 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03709 _("Style has already been specified for state %s focus %s"),
03710 state, focus);
03711 return;
03712 }
03713 meta_frame_style_ref (frame_style);
03714 info->style_set->maximized_and_shaded_styles[frame_focus] = frame_style;
03715 break;
03716 case META_FRAME_STATE_LAST:
03717 g_assert_not_reached ();
03718 break;
03719 }
03720
03721 push_state (info, STATE_FRAME);
03722 }
03723 else
03724 {
03725 set_error (error, context,
03726 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03727 _("Element <%s> is not allowed below <%s>"),
03728 element_name, "frame_style_set");
03729 }
03730 }
03731
03732 static void
03733 parse_piece_element (GMarkupParseContext *context,
03734 const gchar *element_name,
03735 const gchar **attribute_names,
03736 const gchar **attribute_values,
03737 ParseInfo *info,
03738 GError **error)
03739 {
03740 g_return_if_fail (peek_state (info) == STATE_PIECE);
03741
03742 if (ELEMENT_IS ("draw_ops"))
03743 {
03744 if (info->op_list)
03745 {
03746 set_error (error, context,
03747 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03748 _("Can't have a two draw_ops for a <piece> element (theme specified a draw_ops attribute and also a <draw_ops> element, or specified two elements)"));
03749 return;
03750 }
03751
03752 if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
03753 error))
03754 return;
03755
03756 g_assert (info->op_list == NULL);
03757 info->op_list = meta_draw_op_list_new (2);
03758
03759 push_state (info, STATE_DRAW_OPS);
03760 }
03761 else
03762 {
03763 set_error (error, context,
03764 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03765 _("Element <%s> is not allowed below <%s>"),
03766 element_name, "piece");
03767 }
03768 }
03769
03770 static void
03771 parse_button_element (GMarkupParseContext *context,
03772 const gchar *element_name,
03773 const gchar **attribute_names,
03774 const gchar **attribute_values,
03775 ParseInfo *info,
03776 GError **error)
03777 {
03778 g_return_if_fail (peek_state (info) == STATE_BUTTON);
03779
03780 if (ELEMENT_IS ("draw_ops"))
03781 {
03782 if (info->op_list)
03783 {
03784 set_error (error, context,
03785 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03786 _("Can't have a two draw_ops for a <button> element (theme specified a draw_ops attribute and also a <draw_ops> element, or specified two elements)"));
03787 return;
03788 }
03789
03790 if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
03791 error))
03792 return;
03793
03794 g_assert (info->op_list == NULL);
03795 info->op_list = meta_draw_op_list_new (2);
03796
03797 push_state (info, STATE_DRAW_OPS);
03798 }
03799 else
03800 {
03801 set_error (error, context,
03802 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03803 _("Element <%s> is not allowed below <%s>"),
03804 element_name, "button");
03805 }
03806 }
03807
03808 static void
03809 parse_menu_icon_element (GMarkupParseContext *context,
03810 const gchar *element_name,
03811 const gchar **attribute_names,
03812 const gchar **attribute_values,
03813 ParseInfo *info,
03814 GError **error)
03815 {
03816 g_return_if_fail (peek_state (info) == STATE_MENU_ICON);
03817
03818 if (ELEMENT_IS ("draw_ops"))
03819 {
03820 if (info->op_list)
03821 {
03822 set_error (error, context,
03823 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03824 _("Can't have a two draw_ops for a <menu_icon> element (theme specified a draw_ops attribute and also a <draw_ops> element, or specified two elements)"));
03825 return;
03826 }
03827
03828 if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
03829 error))
03830 return;
03831
03832 g_assert (info->op_list == NULL);
03833 info->op_list = meta_draw_op_list_new (2);
03834
03835 push_state (info, STATE_DRAW_OPS);
03836 }
03837 else
03838 {
03839 set_error (error, context,
03840 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03841 _("Element <%s> is not allowed below <%s>"),
03842 element_name, "menu_icon");
03843 }
03844 }
03845
03846
03847 static void
03848 start_element_handler (GMarkupParseContext *context,
03849 const gchar *element_name,
03850 const gchar **attribute_names,
03851 const gchar **attribute_values,
03852 gpointer user_data,
03853 GError **error)
03854 {
03855 ParseInfo *info = user_data;
03856
03857 switch (peek_state (info))
03858 {
03859 case STATE_START:
03860 if (strcmp (element_name, "metacity_theme") == 0)
03861 {
03862 info->theme = meta_theme_new ();
03863 info->theme->name = g_strdup (info->theme_name);
03864 info->theme->filename = g_strdup (info->theme_file);
03865 info->theme->dirname = g_strdup (info->theme_dir);
03866 info->theme->format_version = info->format_version;
03867
03868 push_state (info, STATE_THEME);
03869 }
03870 else
03871 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03872 _("Outermost element in theme must be <metacity_theme> not <%s>"),
03873 element_name);
03874 break;
03875
03876 case STATE_THEME:
03877 parse_toplevel_element (context, element_name,
03878 attribute_names, attribute_values,
03879 info, error);
03880 break;
03881 case STATE_INFO:
03882 parse_info_element (context, element_name,
03883 attribute_names, attribute_values,
03884 info, error);
03885 break;
03886 case STATE_NAME:
03887 case STATE_AUTHOR:
03888 case STATE_COPYRIGHT:
03889 case STATE_DATE:
03890 case STATE_DESCRIPTION:
03891 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03892 _("Element <%s> is not allowed inside a name/author/date/description element"),
03893 element_name);
03894 break;
03895 case STATE_CONSTANT:
03896 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03897 _("Element <%s> is not allowed inside a <constant> element"),
03898 element_name);
03899 break;
03900 case STATE_FRAME_GEOMETRY:
03901 parse_geometry_element (context, element_name,
03902 attribute_names, attribute_values,
03903 info, error);
03904 break;
03905 case STATE_DISTANCE:
03906 case STATE_BORDER:
03907 case STATE_ASPECT_RATIO:
03908 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03909 _("Element <%s> is not allowed inside a distance/border/aspect_ratio element"),
03910 element_name);
03911 break;
03912 case STATE_DRAW_OPS:
03913 parse_draw_op_element (context, element_name,
03914 attribute_names, attribute_values,
03915 info, error);
03916 break;
03917 case STATE_LINE:
03918 case STATE_RECTANGLE:
03919 case STATE_ARC:
03920 case STATE_CLIP:
03921 case STATE_TINT:
03922 case STATE_IMAGE:
03923 case STATE_GTK_ARROW:
03924 case STATE_GTK_BOX:
03925 case STATE_GTK_VLINE:
03926 case STATE_ICON:
03927 case STATE_TITLE:
03928 case STATE_INCLUDE:
03929 case STATE_TILE:
03930 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03931 _("Element <%s> is not allowed inside a draw operation element"),
03932 element_name);
03933 break;
03934 case STATE_GRADIENT:
03935 parse_gradient_element (context, element_name,
03936 attribute_names, attribute_values,
03937 info, error);
03938 break;
03939 case STATE_COLOR:
03940 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03941 _("Element <%s> is not allowed inside a <%s> element"),
03942 element_name, "color");
03943 break;
03944 case STATE_FRAME_STYLE:
03945 parse_style_element (context, element_name,
03946 attribute_names, attribute_values,
03947 info, error);
03948 break;
03949 case STATE_PIECE:
03950 parse_piece_element (context, element_name,
03951 attribute_names, attribute_values,
03952 info, error);
03953 break;
03954 case STATE_BUTTON:
03955 parse_button_element (context, element_name,
03956 attribute_names, attribute_values,
03957 info, error);
03958 break;
03959 case STATE_MENU_ICON:
03960 parse_menu_icon_element (context, element_name,
03961 attribute_names, attribute_values,
03962 info, error);
03963 break;
03964 case STATE_FRAME_STYLE_SET:
03965 parse_style_set_element (context, element_name,
03966 attribute_names, attribute_values,
03967 info, error);
03968 break;
03969 case STATE_FRAME:
03970 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03971 _("Element <%s> is not allowed inside a <%s> element"),
03972 element_name, "frame");
03973 break;
03974 case STATE_WINDOW:
03975 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03976 _("Element <%s> is not allowed inside a <%s> element"),
03977 element_name, "window");
03978 break;
03979 case STATE_FALLBACK:
03980 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
03981 _("Element <%s> is not allowed inside a <%s> element"),
03982 element_name, "fallback");
03983 break;
03984 }
03985 }
03986
03987 static void
03988 end_element_handler (GMarkupParseContext *context,
03989 const gchar *element_name,
03990 gpointer user_data,
03991 GError **error)
03992 {
03993 ParseInfo *info = user_data;
03994
03995 switch (peek_state (info))
03996 {
03997 case STATE_START:
03998 break;
03999 case STATE_THEME:
04000 g_assert (info->theme);
04001
04002 if (!meta_theme_validate (info->theme, error))
04003 {
04004 add_context_to_error (error, context);
04005 meta_theme_free (info->theme);
04006 info->theme = NULL;
04007 }
04008
04009 pop_state (info);
04010 g_assert (peek_state (info) == STATE_START);
04011 break;
04012 case STATE_INFO:
04013 pop_state (info);
04014 g_assert (peek_state (info) == STATE_THEME);
04015 break;
04016 case STATE_NAME:
04017 pop_state (info);
04018 g_assert (peek_state (info) == STATE_INFO);
04019 break;
04020 case STATE_AUTHOR:
04021 pop_state (info);
04022 g_assert (peek_state (info) == STATE_INFO);
04023 break;
04024 case STATE_COPYRIGHT:
04025 pop_state (info);
04026 g_assert (peek_state (info) == STATE_INFO);
04027 break;
04028 case STATE_DATE:
04029 pop_state (info);
04030 g_assert (peek_state (info) == STATE_INFO);
04031 break;
04032 case STATE_DESCRIPTION:
04033 pop_state (info);
04034 g_assert (peek_state (info) == STATE_INFO);
04035 break;
04036 case STATE_CONSTANT:
04037 pop_state (info);
04038 g_assert (peek_state (info) == STATE_THEME);
04039 break;
04040 case STATE_FRAME_GEOMETRY:
04041 g_assert (info->layout);
04042
04043 if (!meta_frame_layout_validate (info->layout,
04044 error))
04045 {
04046 add_context_to_error (error, context);
04047 }
04048
04049
04050
04051
04052 meta_frame_layout_unref (info->layout);
04053 info->layout = NULL;
04054 pop_state (info);
04055 g_assert (peek_state (info) == STATE_THEME);
04056 break;
04057 case STATE_DISTANCE:
04058 pop_state (info);
04059 g_assert (peek_state (info) == STATE_FRAME_GEOMETRY);
04060 break;
04061 case STATE_BORDER:
04062 pop_state (info);
04063 g_assert (peek_state (info) == STATE_FRAME_GEOMETRY);
04064 break;
04065 case STATE_ASPECT_RATIO:
04066 pop_state (info);
04067 g_assert (peek_state (info) == STATE_FRAME_GEOMETRY);
04068 break;
04069 case STATE_DRAW_OPS:
04070 {
04071 g_assert (info->op_list);
04072
04073 if (!meta_draw_op_list_validate (info->op_list,
04074 error))
04075 {
04076 add_context_to_error (error, context);
04077 meta_draw_op_list_unref (info->op_list);
04078 info->op_list = NULL;
04079 }
04080
04081 pop_state (info);
04082
04083 switch (peek_state (info))
04084 {
04085 case STATE_BUTTON:
04086 case STATE_PIECE:
04087 case STATE_MENU_ICON:
04088
04089
04090
04091 g_assert (info->op_list);
04092 break;
04093 case STATE_THEME:
04094 g_assert (info->op_list);
04095 meta_draw_op_list_unref (info->op_list);
04096 info->op_list = NULL;
04097 break;
04098 default:
04099
04100 g_assert_not_reached ();
04101 break;
04102 }
04103 }
04104 break;
04105 case STATE_LINE:
04106 pop_state (info);
04107 g_assert (peek_state (info) == STATE_DRAW_OPS);
04108 break;
04109 case STATE_RECTANGLE:
04110 pop_state (info);
04111 g_assert (peek_state (info) == STATE_DRAW_OPS);
04112 break;
04113 case STATE_ARC:
04114 pop_state (info);
04115 g_assert (peek_state (info) == STATE_DRAW_OPS);
04116 break;
04117 case STATE_CLIP:
04118 pop_state (info);
04119 g_assert (peek_state (info) == STATE_DRAW_OPS);
04120 break;
04121 case STATE_TINT:
04122 pop_state (info);
04123 g_assert (peek_state (info) == STATE_DRAW_OPS);
04124 break;
04125 case STATE_GRADIENT:
04126 g_assert (info->op);
04127 g_assert (info->op->type == META_DRAW_GRADIENT);
04128 if (!meta_gradient_spec_validate (info->op->data.gradient.gradient_spec,
04129 error))
04130 {
04131 add_context_to_error (error, context);
04132 meta_draw_op_free (info->op);
04133 info->op = NULL;
04134 }
04135 else
04136 {
04137 g_assert (info->op_list);
04138 meta_draw_op_list_append (info->op_list, info->op);
04139 info->op = NULL;
04140 }
04141 pop_state (info);
04142 g_assert (peek_state (info) == STATE_DRAW_OPS);
04143 break;
04144 case STATE_IMAGE:
04145 pop_state (info);
04146 g_assert (peek_state (info) == STATE_DRAW_OPS);
04147 break;
04148 case STATE_GTK_ARROW:
04149 pop_state (info);
04150 g_assert (peek_state (info) == STATE_DRAW_OPS);
04151 break;
04152 case STATE_GTK_BOX:
04153 pop_state (info);
04154 g_assert (peek_state (info) == STATE_DRAW_OPS);
04155 break;
04156 case STATE_GTK_VLINE:
04157 pop_state (info);
04158 g_assert (peek_state (info) == STATE_DRAW_OPS);
04159 break;
04160 case STATE_ICON:
04161 pop_state (info);
04162 g_assert (peek_state (info) == STATE_DRAW_OPS);
04163 break;
04164 case STATE_TITLE:
04165 pop_state (info);
04166 g_assert (peek_state (info) == STATE_DRAW_OPS);
04167 break;
04168 case STATE_INCLUDE:
04169 pop_state (info);
04170 g_assert (peek_state (info) == STATE_DRAW_OPS);
04171 break;
04172 case STATE_TILE:
04173 pop_state (info);
04174 g_assert (peek_state (info) == STATE_DRAW_OPS);
04175 break;
04176 case STATE_COLOR:
04177 pop_state (info);
04178 g_assert (peek_state (info) == STATE_GRADIENT);
04179 break;
04180 case STATE_FRAME_STYLE:
04181 g_assert (info->style);
04182
04183 if (!meta_frame_style_validate (info->style,
04184 info->theme->format_version,
04185 error))
04186 {
04187 add_context_to_error (error, context);
04188 }
04189
04190
04191
04192
04193 meta_frame_style_unref (info->style);
04194 info->style = NULL;
04195 pop_state (info);
04196 g_assert (peek_state (info) == STATE_THEME);
04197 break;
04198 case STATE_PIECE:
04199 g_assert (info->style);
04200 if (info->op_list == NULL)
04201 {
04202 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
04203 _("No draw_ops provided for frame piece"));
04204 }
04205 else
04206 {
04207 info->style->pieces[info->piece] = info->op_list;
04208 info->op_list = NULL;
04209 }
04210 pop_state (info);
04211 g_assert (peek_state (info) == STATE_FRAME_STYLE);
04212 break;
04213 case STATE_BUTTON:
04214 g_assert (info->style);
04215 if (info->op_list == NULL)
04216 {
04217 set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
04218 _("No draw_ops provided for button"));
04219 }
04220 else
04221 {
04222 info->style->buttons[info->button_type][info->button_state] =
04223 info->op_list;
04224 info->op_list = NULL;
04225 }
04226 pop_state (info);
04227 break;
04228 case STATE_MENU_ICON:
04229 g_assert (info->theme);
04230 if (info->op_list != NULL)
04231 {
04232 meta_draw_op_list_unref (info->op_list);
04233 info->op_list = NULL;
04234 }
04235 pop_state (info);
04236 g_assert (peek_state (info) == STATE_THEME);
04237 break;
04238 case STATE_FRAME_STYLE_SET:
04239 g_assert (info->style_set);
04240
04241 if (!meta_frame_style_set_validate (info->style_set,
04242 error))
04243 {
04244 add_context_to_error (error, context);
04245 }
04246
04247
04248
04249
04250 meta_frame_style_set_unref (info->style_set);
04251 info->style_set = NULL;
04252 pop_state (info);
04253 g_assert (peek_state (info) == STATE_THEME);
04254 break;
04255 case STATE_FRAME:
04256 pop_state (info);
04257 g_assert (peek_state (info) == STATE_FRAME_STYLE_SET);
04258 break;
04259 case STATE_WINDOW:
04260 pop_state (info);
04261 g_assert (peek_state (info) == STATE_THEME);
04262 break;
04263 case STATE_FALLBACK:
04264 pop_state (info);
04265 g_assert (peek_state (info) == STATE_THEME);
04266 break;
04267 }
04268 }
04269
04270 #define NO_TEXT(element_name) set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, _("No text is allowed inside element <%s>"), element_name)
04271
04272 static gboolean
04273 all_whitespace (const char *text,
04274 int text_len)
04275 {
04276 const char *p;
04277 const char *end;
04278
04279 p = text;
04280 end = text + text_len;
04281
04282 while (p != end)
04283 {
04284 if (!g_ascii_isspace (*p))
04285 return FALSE;
04286
04287 p = g_utf8_next_char (p);
04288 }
04289
04290 return TRUE;
04291 }
04292
04293 static void
04294 text_handler (GMarkupParseContext *context,
04295 const gchar *text,
04296 gsize text_len,
04297 gpointer user_data,
04298 GError **error)
04299 {
04300 ParseInfo *info = user_data;
04301
04302 if (all_whitespace (text, text_len))
04303 return;
04304
04305
04306
04307
04308
04309 switch (peek_state (info))
04310 {
04311 case STATE_START:
04312 g_assert_not_reached ();
04313 break;
04314 case STATE_THEME:
04315 NO_TEXT ("metacity_theme");
04316 break;
04317 case STATE_INFO:
04318 NO_TEXT ("info");
04319 break;
04320 case STATE_NAME:
04321 if (info->theme->readable_name != NULL)
04322 {
04323 set_error (error, context, G_MARKUP_ERROR,
04324 G_MARKUP_ERROR_PARSE,
04325 _("<name> specified twice for this theme"));
04326 return;
04327 }
04328
04329 info->theme->readable_name = g_strndup (text, text_len);
04330 break;
04331 case STATE_AUTHOR:
04332 if (info->theme->author != NULL)
04333 {
04334 set_error (error, context, G_MARKUP_ERROR,
04335 G_MARKUP_ERROR_PARSE,
04336 _("<author> specified twice for this theme"));
04337 return;
04338 }
04339
04340 info->theme->author = g_strndup (text, text_len);
04341 break;
04342 case STATE_COPYRIGHT:
04343 if (info->theme->copyright != NULL)
04344 {
04345 set_error (error, context, G_MARKUP_ERROR,
04346 G_MARKUP_ERROR_PARSE,
04347 _("<copyright> specified twice for this theme"));
04348 return;
04349 }
04350
04351 info->theme->copyright = g_strndup (text, text_len);
04352 break;
04353 case STATE_DATE:
04354 if (info->theme->date != NULL)
04355 {
04356 set_error (error, context, G_MARKUP_ERROR,
04357 G_MARKUP_ERROR_PARSE,
04358 _("<date> specified twice for this theme"));
04359 return;
04360 }
04361
04362 info->theme->date = g_strndup (text, text_len);
04363 break;
04364 case STATE_DESCRIPTION:
04365 if (info->theme->description != NULL)
04366 {
04367 set_error (error, context, G_MARKUP_ERROR,
04368 G_MARKUP_ERROR_PARSE,
04369 _("<description> specified twice for this theme"));
04370 return;
04371 }
04372
04373 info->theme->description = g_strndup (text, text_len);
04374 break;
04375 case STATE_CONSTANT:
04376 NO_TEXT ("constant");
04377 break;
04378 case STATE_FRAME_GEOMETRY:
04379 NO_TEXT ("frame_geometry");
04380 break;
04381 case STATE_DISTANCE:
04382 NO_TEXT ("distance");
04383 break;
04384 case STATE_BORDER:
04385 NO_TEXT ("border");
04386 break;
04387 case STATE_ASPECT_RATIO:
04388 NO_TEXT ("aspect_ratio");
04389 break;
04390 case STATE_DRAW_OPS:
04391 NO_TEXT ("draw_ops");
04392 break;
04393 case STATE_LINE:
04394 NO_TEXT ("line");
04395 break;
04396 case STATE_RECTANGLE:
04397 NO_TEXT ("rectangle");
04398 break;
04399 case STATE_ARC:
04400 NO_TEXT ("arc");
04401 break;
04402 case STATE_CLIP:
04403 NO_TEXT ("clip");
04404 break;
04405 case STATE_TINT:
04406 NO_TEXT ("tint");
04407 break;
04408 case STATE_GRADIENT:
04409 NO_TEXT ("gradient");
04410 break;
04411 case STATE_IMAGE:
04412 NO_TEXT ("image");
04413 break;
04414 case STATE_GTK_ARROW:
04415 NO_TEXT ("gtk_arrow");
04416 break;
04417 case STATE_GTK_BOX:
04418 NO_TEXT ("gtk_box");
04419 break;
04420 case STATE_GTK_VLINE:
04421 NO_TEXT ("gtk_vline");
04422 break;
04423 case STATE_ICON:
04424 NO_TEXT ("icon");
04425 break;
04426 case STATE_TITLE:
04427 NO_TEXT ("title");
04428 break;
04429 case STATE_INCLUDE:
04430 NO_TEXT ("include");
04431 break;
04432 case STATE_TILE:
04433 NO_TEXT ("tile");
04434 break;
04435 case STATE_COLOR:
04436 NO_TEXT ("color");
04437 break;
04438 case STATE_FRAME_STYLE:
04439 NO_TEXT ("frame_style");
04440 break;
04441 case STATE_PIECE:
04442 NO_TEXT ("piece");
04443 break;
04444 case STATE_BUTTON:
04445 NO_TEXT ("button");
04446 break;
04447 case STATE_MENU_ICON:
04448 NO_TEXT ("menu_icon");
04449 break;
04450 case STATE_FRAME_STYLE_SET:
04451 NO_TEXT ("frame_style_set");
04452 break;
04453 case STATE_FRAME:
04454 NO_TEXT ("frame");
04455 break;
04456 case STATE_WINDOW:
04457 NO_TEXT ("window");
04458 break;
04459 case STATE_FALLBACK:
04460 NO_TEXT ("fallback");
04461 break;
04462 }
04463 }
04464
04465
04466
04467
04468
04469
04470 #define THEME_SUBDIR "metacity-1"
04471
04472
04473
04474
04475 #define THEME_VERSION 2
04476
04477 #define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml"
04478
04479 MetaTheme*
04480 meta_theme_load (const char *theme_name,
04481 GError **err)
04482 {
04483 GMarkupParseContext *context;
04484 GError *error;
04485 ParseInfo info;
04486 char *text;
04487 gsize length;
04488 char *theme_file;
04489 char *theme_dir;
04490 MetaTheme *retval;
04491 guint version;
04492 const gchar* const* xdg_data_dirs;
04493 int i;
04494
04495 text = NULL;
04496 length = 0;
04497 retval = NULL;
04498 context = NULL;
04499
04500 theme_dir = NULL;
04501 theme_file = NULL;
04502
04503 if (meta_is_debugging ())
04504 {
04505 gchar *theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT,
04506 THEME_VERSION);
04507
04508
04509 theme_dir = g_build_filename ("./themes", theme_name, NULL);
04510
04511 theme_file = g_build_filename (theme_dir,
04512 theme_filename,
04513 NULL);
04514
04515 error = NULL;
04516 if (!g_file_get_contents (theme_file,
04517 &text,
04518 &length,
04519 &error))
04520 {
04521 meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
04522 theme_file, error->message);
04523 g_error_free (error);
04524 g_free (theme_dir);
04525 g_free (theme_file);
04526 theme_file = NULL;
04527 }
04528 version = THEME_VERSION;
04529
04530 g_free (theme_filename);
04531 }
04532
04533
04534 for (version = THEME_VERSION; (version > 0) && (text == NULL); version--)
04535 {
04536 gchar *theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT,
04537 version);
04538
04539
04540
04541
04542 theme_dir = g_build_filename (g_get_home_dir (),
04543 ".themes",
04544 theme_name,
04545 THEME_SUBDIR,
04546 NULL);
04547
04548 theme_file = g_build_filename (theme_dir,
04549 theme_filename,
04550 NULL);
04551
04552 error = NULL;
04553 if (!g_file_get_contents (theme_file,
04554 &text,
04555 &length,
04556 &error))
04557 {
04558 meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
04559 theme_file, error->message);
04560 g_error_free (error);
04561 g_free (theme_dir);
04562 g_free (theme_file);
04563 theme_file = NULL;
04564 }
04565
04566
04567 xdg_data_dirs = g_get_system_data_dirs();
04568 for(i = 0; xdg_data_dirs[i] != NULL; i++)
04569 {
04570 if (text == NULL)
04571 {
04572 theme_dir = g_build_filename (xdg_data_dirs[i],
04573 "themes",
04574 theme_name,
04575 THEME_SUBDIR,
04576 NULL);
04577
04578 theme_file = g_build_filename (theme_dir,
04579 theme_filename,
04580 NULL);
04581
04582 error = NULL;
04583 if (!g_file_get_contents (theme_file,
04584 &text,
04585 &length,
04586 &error))
04587 {
04588 meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
04589 theme_file, error->message);
04590 g_error_free (error);
04591 g_free (theme_dir);
04592 g_free (theme_file);
04593 theme_file = NULL;
04594 }
04595 else
04596 {
04597 break;
04598 }
04599 }
04600 }
04601
04602
04603 if (text == NULL)
04604 {
04605 theme_dir = g_build_filename (METACITY_DATADIR,
04606 "themes",
04607 theme_name,
04608 THEME_SUBDIR,
04609 NULL);
04610
04611 theme_file = g_build_filename (theme_dir,
04612 theme_filename,
04613 NULL);
04614
04615 error = NULL;
04616 if (!g_file_get_contents (theme_file,
04617 &text,
04618 &length,
04619 &error))
04620 {
04621 meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
04622 theme_file, error->message);
04623 g_error_free (error);
04624 g_free (theme_dir);
04625 g_free (theme_file);
04626 theme_file = NULL;
04627 }
04628 }
04629
04630 g_free (theme_filename);
04631 }
04632
04633 if (text == NULL)
04634 {
04635 g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED,
04636 _("Failed to find a valid file for theme %s\n"),
04637 theme_name);
04638
04639 return NULL;
04640 }
04641
04642 meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file);
04643
04644
04645 parse_info_init (&info);
04646 info.theme_name = theme_name;
04647
04648
04649 info.theme_file = theme_file;
04650 info.theme_dir = theme_dir;
04651
04652 info.format_version = version + 1;
04653
04654 context = g_markup_parse_context_new (&metacity_theme_parser,
04655 0, &info, NULL);
04656
04657 error = NULL;
04658 if (!g_markup_parse_context_parse (context,
04659 text,
04660 length,
04661 &error))
04662 goto out;
04663
04664 error = NULL;
04665 if (!g_markup_parse_context_end_parse (context, &error))
04666 goto out;
04667
04668 goto out;
04669
04670 out:
04671
04672 if (context)
04673 g_markup_parse_context_free (context);
04674 g_free (text);
04675
04676 if (info.theme)
04677 info.theme->format_version = info.format_version;
04678
04679 if (error)
04680 {
04681 g_propagate_error (err, error);
04682 }
04683 else if (info.theme)
04684 {
04685
04686 retval = info.theme;
04687 info.theme = NULL;
04688 }
04689 else
04690 {
04691 g_set_error (err, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
04692 _("Theme file %s did not contain a root <metacity_theme> element"),
04693 info.theme_file);
04694 }
04695
04696 parse_info_free (&info);
04697
04698 return retval;
04699 }