~muktupavels/metacity/adwaita-icon-theme-lp-1414613

1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3
/* Metacity theme parsing */
4
5
/*
6
 * Copyright (C) 2001 Havoc Pennington
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License as
10
 * published by the Free Software Foundation; either version 2 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
19
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
20
 */
21
22
#include <config.h>
23
#include "theme-parser.h"
24
#include "util.h"
25
#include <string.h>
26
#include <stdlib.h>
27
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
28
/* We were intending to put the version number
29
 * in the subdirectory name, but we ended up
30
 * using the filename instead.  The "-1" survives
31
 * as a fossil.
32
 */
33
#define THEME_SUBDIR "metacity-1"
34
35
/* Highest version of the theme format to
36
 * look out for.
37
 */
38
#define THEME_MAJOR_VERSION 3
39
#define THEME_MINOR_VERSION 5
40
#define THEME_VERSION (1000 * THEME_MAJOR_VERSION + THEME_MINOR_VERSION)
41
42
#define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml"
43
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
44
typedef enum
45
{
46
  STATE_START,
47
  STATE_THEME,
48
  /* info section */
49
  STATE_INFO,
50
  STATE_NAME,
51
  STATE_AUTHOR,
52
  STATE_COPYRIGHT,
53
  STATE_DATE,
54
  STATE_DESCRIPTION,
55
  /* constants */
56
  STATE_CONSTANT,
57
  /* geometry */
58
  STATE_FRAME_GEOMETRY,
59
  STATE_DISTANCE,
60
  STATE_BORDER,
61
  STATE_ASPECT_RATIO,
62
  /* draw ops */
63
  STATE_DRAW_OPS,
64
  STATE_LINE,
65
  STATE_RECTANGLE,
66
  STATE_ARC,
67
  STATE_CLIP,
68
  STATE_TINT,
69
  STATE_GRADIENT,
70
  STATE_IMAGE,
71
  STATE_GTK_ARROW,
72
  STATE_GTK_BOX,
73
  STATE_GTK_VLINE,
74
  STATE_ICON,
75
  STATE_TITLE,
76
  STATE_INCLUDE, /* include another draw op list */
77
  STATE_TILE,    /* tile another draw op list */
78
  /* sub-parts of gradient */
79
  STATE_COLOR,
80
  /* frame style */
81
  STATE_FRAME_STYLE,
82
  STATE_PIECE,
83
  STATE_BUTTON,
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
84
  STATE_SHADOW,
85
  STATE_PADDING,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
86
  /* style set */
87
  STATE_FRAME_STYLE_SET,
88
  STATE_FRAME,
89
  /* assigning style sets to windows */
90
  STATE_WINDOW,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
91
  /* things we don't use any more but we can still parse: */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
92
  STATE_MENU_ICON,
93
  STATE_FALLBACK
94
} ParseState;
95
96
typedef struct
97
{
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
98
  /* This two lists contain stacks of state and required version
99
   * (cast to pointers.) There is one list item for each currently
100
   * open element. */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
101
  GSList *states;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
102
  GSList *required_versions;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
103
104
  const char *theme_name;       /* name of theme (directory it's in) */
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
105
  const char *theme_file;       /* theme filename */
106
  const char *theme_dir;        /* dir the theme is inside */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
107
  MetaTheme *theme;             /* theme being parsed */
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
108
  guint format_version;         /* version of format of theme file */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
109
  char *name;                   /* name of named thing being parsed */
110
  MetaFrameLayout *layout;      /* layout being parsed if any */
111
  MetaDrawOpList *op_list;      /* op list being parsed if any */
112
  MetaDrawOp *op;               /* op being parsed if any */
113
  MetaFrameStyle *style;        /* frame style being parsed if any */
114
  MetaFrameStyleSet *style_set; /* frame style set being parsed if any */
115
  MetaFramePiece piece;         /* position of piece being parsed */
116
  MetaButtonType button_type;   /* type of button/menuitem being parsed */
117
  MetaButtonState button_state; /* state of button being parsed */
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
118
  int skip_level;               /* depth of elements that we're ignoring */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
119
} ParseInfo;
120
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
121
typedef enum {
122
  THEME_PARSE_ERROR_TOO_OLD,
123
  THEME_PARSE_ERROR_TOO_FAILED
124
 } ThemeParseError;
125
126
static GQuark
127
theme_parse_error_quark (void)
128
{
129
  return g_quark_from_static_string ("theme-parse-error-quark");
130
}
131
132
#define THEME_PARSE_ERROR (theme_parse_error_quark ())
133
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
134
static void set_error (GError             **err,
135
                       GMarkupParseContext *context,
136
                       int                  error_domain,
137
                       int                  error_code,
138
                       const char          *format,
139
                       ...) G_GNUC_PRINTF (5, 6);
140
141
static void add_context_to_error (GError             **err,
142
                                  GMarkupParseContext *context);
143
144
static void       parse_info_init (ParseInfo *info);
145
static void       parse_info_free (ParseInfo *info);
146
147
static void       push_state (ParseInfo  *info,
148
                              ParseState  state);
149
static void       pop_state  (ParseInfo  *info);
150
static ParseState peek_state (ParseInfo  *info);
151
152
153
static void parse_toplevel_element  (GMarkupParseContext  *context,
154
                                     const gchar          *element_name,
155
                                     const gchar         **attribute_names,
156
                                     const gchar         **attribute_values,
157
                                     ParseInfo            *info,
158
                                     GError              **error);
159
static void parse_info_element      (GMarkupParseContext  *context,
160
                                     const gchar          *element_name,
161
                                     const gchar         **attribute_names,
162
                                     const gchar         **attribute_values,
163
                                     ParseInfo            *info,
164
                                     GError              **error);
165
static void parse_geometry_element  (GMarkupParseContext  *context,
166
                                     const gchar          *element_name,
167
                                     const gchar         **attribute_names,
168
                                     const gchar         **attribute_values,
169
                                     ParseInfo            *info,
170
                                     GError              **error);
171
static void parse_draw_op_element   (GMarkupParseContext  *context,
172
                                     const gchar          *element_name,
173
                                     const gchar         **attribute_names,
174
                                     const gchar         **attribute_values,
175
                                     ParseInfo            *info,
176
                                     GError              **error);
177
static void parse_gradient_element  (GMarkupParseContext  *context,
178
                                     const gchar          *element_name,
179
                                     const gchar         **attribute_names,
180
                                     const gchar         **attribute_values,
181
                                     ParseInfo            *info,
182
                                     GError              **error);
183
static void parse_style_element     (GMarkupParseContext  *context,
184
                                     const gchar          *element_name,
185
                                     const gchar         **attribute_names,
186
                                     const gchar         **attribute_values,
187
                                     ParseInfo            *info,
188
                                     GError              **error);
189
static void parse_style_set_element (GMarkupParseContext  *context,
190
                                     const gchar          *element_name,
191
                                     const gchar         **attribute_names,
192
                                     const gchar         **attribute_values,
193
                                     ParseInfo            *info,
194
                                     GError              **error);
195
196
static void parse_piece_element     (GMarkupParseContext  *context,
197
                                     const gchar          *element_name,
198
                                     const gchar         **attribute_names,
199
                                     const gchar         **attribute_values,
200
                                     ParseInfo            *info,
201
                                     GError              **error);
202
203
static void parse_button_element    (GMarkupParseContext  *context,
204
                                     const gchar          *element_name,
205
                                     const gchar         **attribute_names,
206
                                     const gchar         **attribute_values,
207
                                     ParseInfo            *info,
208
                                     GError              **error);
209
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
210
static void parse_shadow_element    (GMarkupParseContext  *context,
211
                                     const gchar          *element_name,
212
                                     const gchar         **attribute_names,
213
                                     const gchar         **attribute_values,
214
                                     ParseInfo            *info,
215
                                     GError              **error);
216
217
static void parse_padding_element   (GMarkupParseContext  *context,
218
                                     const gchar          *element_name,
219
                                     const gchar         **attribute_names,
220
                                     const gchar         **attribute_values,
221
                                     ParseInfo            *info,
222
                                     GError              **error);
223
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
224
static void parse_menu_icon_element (GMarkupParseContext  *context,
225
                                     const gchar          *element_name,
226
                                     const gchar         **attribute_names,
227
                                     const gchar         **attribute_values,
228
                                     ParseInfo            *info,
229
                                     GError              **error);
230
231
static void start_element_handler (GMarkupParseContext  *context,
232
                                   const gchar          *element_name,
233
                                   const gchar         **attribute_names,
234
                                   const gchar         **attribute_values,
235
                                   gpointer              user_data,
236
                                   GError              **error);
237
static void end_element_handler   (GMarkupParseContext  *context,
238
                                   const gchar          *element_name,
239
                                   gpointer              user_data,
240
                                   GError              **error);
241
static void text_handler          (GMarkupParseContext  *context,
242
                                   const gchar          *text,
243
                                   gsize                 text_len,
244
                                   gpointer              user_data,
245
                                   GError              **error);
246
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
247
/* Translators: This means that an attribute which should have been found
248
 * on an XML element was not in fact found.
249
 */
250
#define ATTRIBUTE_NOT_FOUND _("No \"%s\" attribute on element <%s>")
251
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
252
static GMarkupParser metacity_theme_parser = {
253
  start_element_handler,
254
  end_element_handler,
255
  text_handler,
256
  NULL,
257
  NULL
258
};
259
260
static void
261
set_error (GError             **err,
262
           GMarkupParseContext *context,
263
           int                  error_domain,
264
           int                  error_code,
265
           const char          *format,
266
           ...)
267
{
268
  int line, ch;
269
  va_list args;
270
  char *str;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
271
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
272
  g_markup_parse_context_get_position (context, &line, &ch);
273
274
  va_start (args, format);
275
  str = g_strdup_vprintf (format, args);
276
  va_end (args);
277
278
  g_set_error (err, error_domain, error_code,
279
               _("Line %d character %d: %s"),
280
               line, ch, str);
281
282
  g_free (str);
283
}
284
285
static void
286
add_context_to_error (GError             **err,
287
                      GMarkupParseContext *context)
288
{
289
  int line, ch;
290
  char *str;
291
292
  if (err == NULL || *err == NULL)
293
    return;
294
295
  g_markup_parse_context_get_position (context, &line, &ch);
296
297
  str = g_strdup_printf (_("Line %d character %d: %s"),
298
                         line, ch, (*err)->message);
299
  g_free ((*err)->message);
300
  (*err)->message = str;
301
}
302
303
static void
304
parse_info_init (ParseInfo *info)
305
{
306
  info->theme_file = NULL;
307
  info->states = g_slist_prepend (NULL, GINT_TO_POINTER (STATE_START));
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
308
  info->required_versions = NULL;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
309
  info->theme = NULL;
310
  info->name = NULL;
311
  info->layout = NULL;
312
  info->op_list = NULL;
313
  info->op = NULL;
314
  info->style = NULL;
315
  info->style_set = NULL;
316
  info->piece = META_FRAME_PIECE_LAST;
317
  info->button_type = META_BUTTON_TYPE_LAST;
318
  info->button_state = META_BUTTON_STATE_LAST;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
319
  info->skip_level = 0;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
320
}
321
322
static void
323
parse_info_free (ParseInfo *info)
324
{
325
  g_slist_free (info->states);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
326
  g_slist_free (info->required_versions);
327
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
328
  if (info->theme)
329
    meta_theme_free (info->theme);
330
331
  if (info->layout)
332
    meta_frame_layout_unref (info->layout);
333
334
  if (info->op_list)
335
    meta_draw_op_list_unref (info->op_list);
336
337
  if (info->op)
338
    meta_draw_op_free (info->op);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
339
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
340
  if (info->style)
341
    meta_frame_style_unref (info->style);
342
343
  if (info->style_set)
344
    meta_frame_style_set_unref (info->style_set);
345
}
346
347
static void
348
push_state (ParseInfo  *info,
349
            ParseState  state)
350
{
351
  info->states = g_slist_prepend (info->states, GINT_TO_POINTER (state));
352
}
353
354
static void
355
pop_state (ParseInfo *info)
356
{
357
  g_return_if_fail (info->states != NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
358
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
359
  info->states = g_slist_remove (info->states, info->states->data);
360
}
361
362
static ParseState
363
peek_state (ParseInfo *info)
364
{
365
  g_return_val_if_fail (info->states != NULL, STATE_START);
366
367
  return GPOINTER_TO_INT (info->states->data);
368
}
369
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
370
static void
371
push_required_version (ParseInfo *info,
372
                       int        version)
373
{
374
  info->required_versions = g_slist_prepend (info->required_versions,
375
  GINT_TO_POINTER (version));
376
}
377
378
static void
379
pop_required_version (ParseInfo *info)
380
{
381
  g_return_if_fail (info->required_versions != NULL);
382
383
  info->required_versions = g_slist_delete_link (info->required_versions, info->required_versions);
384
}
385
386
static int
387
peek_required_version (ParseInfo *info)
388
{
389
  if (info->required_versions)
390
    return GPOINTER_TO_INT (info->required_versions->data);
391
  else
392
    return info->format_version;
393
}
394
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
395
#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
396
397
typedef struct
398
{
399
  const char  *name;
400
  const char **retloc;
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
401
  gboolean required;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
402
} LocateAttr;
403
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
404
/* Attribute names can have a leading '!' to indicate that they are
405
 * required.
406
 */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
407
static gboolean
408
locate_attributes (GMarkupParseContext *context,
409
                   const char  *element_name,
410
                   const char **attribute_names,
411
                   const char **attribute_values,
412
                   GError     **error,
413
                   const char  *first_attribute_name,
414
                   const char **first_attribute_retloc,
415
                   ...)
416
{
417
  va_list args;
418
  const char *name;
419
  const char **retloc;
420
  int n_attrs;
421
#define MAX_ATTRS 24
422
  LocateAttr attrs[MAX_ATTRS];
423
  gboolean retval;
424
  int i;
425
426
  g_return_val_if_fail (first_attribute_name != NULL, FALSE);
427
  g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
428
429
  retval = TRUE;
430
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
431
  /* FIXME: duplicated code; refactor loop */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
432
  n_attrs = 1;
433
  attrs[0].name = first_attribute_name;
434
  attrs[0].retloc = first_attribute_retloc;
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
435
  attrs[0].required = attrs[0].name[0]=='!';
436
  if (attrs[0].required)
437
    attrs[0].name++; /* skip past it */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
438
  *first_attribute_retloc = NULL;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
439
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
440
  va_start (args, first_attribute_retloc);
441
442
  name = va_arg (args, const char*);
443
  retloc = va_arg (args, const char**);
444
445
  while (name != NULL)
446
    {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
447
      if (retloc == NULL)
448
        {
449
          retval = FALSE;
450
          goto out;
451
        }
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
452
453
      g_assert (n_attrs < MAX_ATTRS);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
454
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
455
      attrs[n_attrs].name = name;
456
      attrs[n_attrs].retloc = retloc;
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
457
      attrs[n_attrs].required = attrs[n_attrs].name[0]=='!';
458
      if (attrs[n_attrs].required)
459
        attrs[n_attrs].name++; /* skip past it */
460
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
461
      n_attrs += 1;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
462
      *retloc = NULL;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
463
464
      name = va_arg (args, const char*);
465
      retloc = va_arg (args, const char**);
466
    }
467
468
  va_end (args);
469
470
  i = 0;
471
  while (attribute_names[i])
472
    {
473
      int j;
474
      gboolean found;
475
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
476
      /* Can be present anywhere */
477
      if (strcmp (attribute_names[i], "version") == 0)
478
        {
479
          ++i;
480
          continue;
481
        }
482
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
483
      found = FALSE;
484
      j = 0;
485
      while (j < n_attrs)
486
        {
487
          if (strcmp (attrs[j].name, attribute_names[i]) == 0)
488
            {
489
              retloc = attrs[j].retloc;
490
491
              if (*retloc != NULL)
492
                {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
493
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
494
                  set_error (error, context,
495
                             G_MARKUP_ERROR,
496
                             G_MARKUP_ERROR_PARSE,
497
                             _("Attribute \"%s\" repeated twice on the same <%s> element"),
498
                             attrs[j].name, element_name);
499
                  retval = FALSE;
500
                  goto out;
501
                }
502
503
              *retloc = attribute_values[i];
504
              found = TRUE;
505
            }
506
507
          ++j;
508
        }
509
510
      if (!found)
511
        {
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
512
      j = 0;
513
      while (j < n_attrs)
514
        {
515
          g_warning ("It could have been %s.\n", attrs[j++].name);
516
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
517
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
518
          set_error (error, context,
519
                     G_MARKUP_ERROR,
520
                     G_MARKUP_ERROR_PARSE,
521
                     _("Attribute \"%s\" is invalid on <%s> element in this context"),
522
                     attribute_names[i], element_name);
523
          retval = FALSE;
524
          goto out;
525
        }
526
527
      ++i;
528
    }
529
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
530
    /* Did we catch them all? */
531
    i = 0;
532
    while (i < n_attrs)
533
      {
534
        if (attrs[i].required && *(attrs[i].retloc)==NULL)
535
          {
536
            set_error (error, context,
537
                       G_MARKUP_ERROR,
538
                       G_MARKUP_ERROR_PARSE,
539
                       ATTRIBUTE_NOT_FOUND,
540
                       attrs[i].name, element_name);
541
            retval = FALSE;
542
            goto out;
543
          }
544
545
        ++i;
546
      }
547
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
548
 out:
549
  return retval;
550
}
551
552
static gboolean
553
check_no_attributes (GMarkupParseContext *context,
554
                     const char  *element_name,
555
                     const char **attribute_names,
556
                     const char **attribute_values,
557
                     GError     **error)
558
{
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
559
  int i = 0;
560
561
  /* Can be present anywhere */
562
  if (attribute_names[0] && strcmp (attribute_names[i], "version") == 0)
563
    i++;
564
565
  if (attribute_names[i] != NULL)
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
566
    {
567
      set_error (error, context,
568
                 G_MARKUP_ERROR,
569
                 G_MARKUP_ERROR_PARSE,
570
                 _("Attribute \"%s\" is invalid on <%s> element in this context"),
571
                 attribute_names[0], element_name);
572
      return FALSE;
573
    }
574
575
  return TRUE;
576
}
577
578
#define MAX_REASONABLE 4096
579
static gboolean
580
parse_positive_integer (const char          *str,
581
                        int                 *val,
582
                        GMarkupParseContext *context,
583
                        MetaTheme           *theme,
584
                        GError             **error)
585
{
586
  char *end;
587
  long l;
588
  int j;
589
590
  *val = 0;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
591
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
592
  end = NULL;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
593
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
594
  /* Is str a constant? */
595
596
  if (META_THEME_ALLOWS (theme, META_THEME_UBIQUITOUS_CONSTANTS) &&
597
      meta_theme_lookup_int_constant (theme, str, &j))
598
    {
599
      /* Yes. */
600
      l = j;
601
    }
602
  else
603
    {
604
      /* No. Let's try parsing it instead. */
605
606
      l = strtol (str, &end, 10);
607
608
      if (end == NULL || end == str)
609
      {
610
        set_error (error, context, G_MARKUP_ERROR,
611
                   G_MARKUP_ERROR_PARSE,
612
                   _("Could not parse \"%s\" as an integer"),
613
                   str);
614
        return FALSE;
615
      }
616
617
    if (*end != '\0')
618
      {
619
        set_error (error, context, G_MARKUP_ERROR,
620
                   G_MARKUP_ERROR_PARSE,
621
                   _("Did not understand trailing characters \"%s\" in string \"%s\""),
622
                   end, str);
623
        return FALSE;
624
      }
625
    }
626
627
  if (l < 0)
628
    {
629
      set_error (error, context, G_MARKUP_ERROR,
630
                 G_MARKUP_ERROR_PARSE,
631
                 _("Integer %ld must be positive"), l);
632
      return FALSE;
633
    }
634
635
  if (l > MAX_REASONABLE)
636
    {
637
      set_error (error, context, G_MARKUP_ERROR,
638
                 G_MARKUP_ERROR_PARSE,
639
                 _("Integer %ld is too large, current max is %d"),
640
                 l, MAX_REASONABLE);
641
      return FALSE;
642
    }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
643
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
644
  *val = (int) l;
645
646
  return TRUE;
647
}
648
649
static gboolean
650
parse_double (const char          *str,
651
              double              *val,
652
              GMarkupParseContext *context,
653
              GError             **error)
654
{
655
  char *end;
656
657
  *val = 0;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
658
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
659
  end = NULL;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
660
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
661
  *val = g_ascii_strtod (str, &end);
662
663
  if (end == NULL || end == str)
664
    {
665
      set_error (error, context, G_MARKUP_ERROR,
666
                 G_MARKUP_ERROR_PARSE,
667
                 _("Could not parse \"%s\" as a floating point number"),
668
                 str);
669
      return FALSE;
670
    }
671
672
  if (*end != '\0')
673
    {
674
      set_error (error, context, G_MARKUP_ERROR,
675
                 G_MARKUP_ERROR_PARSE,
676
                 _("Did not understand trailing characters \"%s\" in string \"%s\""),
677
                 end, str);
678
      return FALSE;
679
    }
680
681
  return TRUE;
682
}
683
684
static gboolean
685
parse_boolean (const char          *str,
686
               gboolean            *val,
687
               GMarkupParseContext *context,
688
               GError             **error)
689
{
690
  if (strcmp ("true", str) == 0)
691
    *val = TRUE;
692
  else if (strcmp ("false", str) == 0)
693
    *val = FALSE;
694
  else
695
    {
696
      set_error (error, context, G_MARKUP_ERROR,
697
                 G_MARKUP_ERROR_PARSE,
698
                 _("Boolean values must be \"true\" or \"false\" not \"%s\""),
699
                 str);
700
      return FALSE;
701
    }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
702
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
703
  return TRUE;
704
}
705
706
static gboolean
707
parse_rounding (const char          *str,
708
                guint               *val,
709
                GMarkupParseContext *context,
710
                MetaTheme           *theme,
711
                GError             **error)
712
{
713
  if (strcmp ("true", str) == 0)
714
    *val = 5; /* historical "true" value */
715
  else if (strcmp ("false", str) == 0)
716
    *val = 0;
717
  else
718
    {
719
      int tmp;
720
      gboolean result;
721
       if (!META_THEME_ALLOWS (theme, META_THEME_VARIED_ROUND_CORNERS))
722
         {
723
           /* Not known in this version, so bail. */
724
           set_error (error, context, G_MARKUP_ERROR,
725
                      G_MARKUP_ERROR_PARSE,
726
                      _("Boolean values must be \"true\" or \"false\" not \"%s\""),
727
                      str);
728
           return FALSE;
729
         }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
730
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
731
      result = parse_positive_integer (str, &tmp, context, theme, error);
732
733
      *val = tmp;
734
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
735
      return result;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
736
    }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
737
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
738
  return TRUE;
739
}
740
741
static gboolean
742
parse_angle (const char          *str,
743
             double              *val,
744
             GMarkupParseContext *context,
745
             GError             **error)
746
{
747
  if (!parse_double (str, val, context, error))
748
    return FALSE;
749
750
  if (*val < (0.0 - 1e6) || *val > (360.0 + 1e6))
751
    {
752
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
753
                 _("Angle must be between 0.0 and 360.0, was %g\n"),
754
                 *val);
755
      return FALSE;
756
    }
757
758
  return TRUE;
759
}
760
761
static gboolean
762
parse_alpha (const char             *str,
763
             MetaAlphaGradientSpec **spec_ret,
764
             GMarkupParseContext    *context,
765
             GError                **error)
766
{
767
  char **split;
768
  int i;
769
  int n_alphas;
770
  MetaAlphaGradientSpec *spec;
771
772
  *spec_ret = NULL;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
773
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
774
  split = g_strsplit (str, ":", -1);
775
776
  i = 0;
777
  while (split[i])
778
    ++i;
779
780
  if (i == 0)
781
    {
782
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
783
                 _("Could not parse \"%s\" as a floating point number"),
784
                 str);
785
786
      g_strfreev (split);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
787
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
788
      return FALSE;
789
    }
790
791
  n_alphas = i;
792
793
  /* FIXME allow specifying horizontal/vertical/diagonal in theme format,
794
   * once we implement vertical/diagonal in gradient.c
795
   */
796
  spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL,
797
                                       n_alphas);
798
799
  i = 0;
800
  while (i < n_alphas)
801
    {
802
      double v;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
803
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
804
      if (!parse_double (split[i], &v, context, error))
805
        {
806
          /* clear up, but don't set error: it was set by parse_double */
807
          g_strfreev (split);
808
          meta_alpha_gradient_spec_free (spec);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
809
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
810
          return FALSE;
811
        }
812
813
      if (v < (0.0 - 1e-6) || v > (1.0 + 1e-6))
814
        {
815
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
816
                     _("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"),
817
                     v);
818
819
          g_strfreev (split);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
820
          meta_alpha_gradient_spec_free (spec);
821
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
822
          return FALSE;
823
        }
824
825
      spec->alphas[i] = (unsigned char) (v * 255);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
826
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
827
      ++i;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
828
    }
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
829
830
  g_strfreev (split);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
831
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
832
  *spec_ret = spec;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
833
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
834
  return TRUE;
835
}
836
837
static MetaColorSpec*
838
parse_color (MetaTheme *theme,
839
             const char        *str,
840
             GError           **err)
841
{
842
  char* referent;
843
844
  if (META_THEME_ALLOWS (theme, META_THEME_COLOR_CONSTANTS) &&
845
      meta_theme_lookup_color_constant (theme, str, &referent))
846
    {
847
      if (referent)
848
        return meta_color_spec_new_from_string (referent, err);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
849
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
850
      /* no need to free referent: it's a pointer into the actual hash table */
851
    }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
852
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
853
  return meta_color_spec_new_from_string (str, err);
854
}
855
856
static gboolean
857
parse_title_scale (const char          *str,
858
                   double              *val,
859
                   GMarkupParseContext *context,
860
                   GError             **error)
861
{
862
  double factor;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
863
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
864
  if (strcmp (str, "xx-small") == 0)
865
    factor = PANGO_SCALE_XX_SMALL;
866
  else if (strcmp (str, "x-small") == 0)
867
    factor = PANGO_SCALE_X_SMALL;
868
  else if (strcmp (str, "small") == 0)
869
    factor = PANGO_SCALE_SMALL;
870
  else if (strcmp (str, "medium") == 0)
871
    factor = PANGO_SCALE_MEDIUM;
872
  else if (strcmp (str, "large") == 0)
873
    factor = PANGO_SCALE_LARGE;
874
  else if (strcmp (str, "x-large") == 0)
875
    factor = PANGO_SCALE_X_LARGE;
876
  else if (strcmp (str, "xx-large") == 0)
877
    factor = PANGO_SCALE_XX_LARGE;
878
  else
879
    {
880
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
881
                 _("Invalid title scale \"%s\" (must be one of xx-small,x-small,small,medium,large,x-large,xx-large)\n"),
882
                 str);
883
      return FALSE;
884
    }
885
886
  *val = factor;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
887
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
888
  return TRUE;
889
}
890
891
static void
892
parse_toplevel_element (GMarkupParseContext  *context,
893
                        const gchar          *element_name,
894
                        const gchar         **attribute_names,
895
                        const gchar         **attribute_values,
896
                        ParseInfo            *info,
897
                        GError              **error)
898
{
899
  g_return_if_fail (peek_state (info) == STATE_THEME);
900
901
  if (ELEMENT_IS ("info"))
902
    {
903
      if (!check_no_attributes (context, element_name,
904
                                attribute_names, attribute_values,
905
                                error))
906
        return;
907
908
      push_state (info, STATE_INFO);
909
    }
910
  else if (ELEMENT_IS ("constant"))
911
    {
912
      const char *name;
913
      const char *value;
914
      int ival = 0;
915
      double dval = 0.0;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
916
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
917
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
918
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
919
                              "!name", &name, "!value", &value,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
920
                              NULL))
921
        return;
922
1.2.62 by Rico Tzschichholz
Import upstream version 2.34.0
923
      /* We don't know how a a constant is going to be used, so we have guess its
924
       * type from its contents:
925
       *
926
       *  - Starts like a number and contains a '.': float constant
927
       *  - Starts like a number and doesn't contain a '.': int constant
928
       *  - Starts with anything else: a color constant.
929
       *    (colors always start with # or a letter)
930
       */
931
      if (value[0] == '.' || value[0] == '+' || value[0] == '-' || (value[0] >= '0' && value[0] <= '9'))
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
932
        {
1.2.62 by Rico Tzschichholz
Import upstream version 2.34.0
933
          if (strchr (value, '.'))
934
            {
935
              if (!parse_double (value, &dval, context, error))
936
                return;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
937
1.2.62 by Rico Tzschichholz
Import upstream version 2.34.0
938
              if (!meta_theme_define_float_constant (info->theme,
939
                                                     name,
940
                                                     dval,
941
                                                     error))
942
                {
943
                  add_context_to_error (error, context);
944
                  return;
945
                }
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
946
            }
1.2.62 by Rico Tzschichholz
Import upstream version 2.34.0
947
          else
948
            {
949
              if (!parse_positive_integer (value, &ival, context, info->theme, error))
950
                return;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
951
1.2.62 by Rico Tzschichholz
Import upstream version 2.34.0
952
              if (!meta_theme_define_int_constant (info->theme,
953
                                                   name,
954
                                                   ival,
955
                                                   error))
956
                {
957
                  add_context_to_error (error, context);
958
                  return;
959
                }
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
960
            }
961
        }
962
      else
963
        {
964
          if (!meta_theme_define_color_constant (info->theme,
965
                                                 name,
966
                                                 value,
967
                                                 error))
968
            {
969
              add_context_to_error (error, context);
970
              return;
971
            }
972
        }
973
974
      push_state (info, STATE_CONSTANT);
975
    }
976
  else if (ELEMENT_IS ("frame_geometry"))
977
    {
978
      const char *name = NULL;
979
      const char *parent = NULL;
980
      const char *has_title = NULL;
981
      const char *title_scale = NULL;
982
      const char *rounded_top_left = NULL;
983
      const char *rounded_top_right = NULL;
984
      const char *rounded_bottom_left = NULL;
985
      const char *rounded_bottom_right = NULL;
986
      const char *hide_buttons = NULL;
987
      gboolean has_title_val;
988
      guint rounded_top_left_val;
989
      guint rounded_top_right_val;
990
      guint rounded_bottom_left_val;
991
      guint rounded_bottom_right_val;
992
      gboolean hide_buttons_val;
993
      double title_scale_val;
994
      MetaFrameLayout *parent_layout;
995
996
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
997
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
998
                              "!name", &name, "parent", &parent,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
999
                              "has_title", &has_title, "title_scale", &title_scale,
1000
                              "rounded_top_left", &rounded_top_left,
1001
                              "rounded_top_right", &rounded_top_right,
1002
                              "rounded_bottom_left", &rounded_bottom_left,
1003
                              "rounded_bottom_right", &rounded_bottom_right,
1004
                              "hide_buttons", &hide_buttons,
1005
                              NULL))
1006
        return;
1007
1008
      has_title_val = TRUE;
1009
      if (has_title && !parse_boolean (has_title, &has_title_val, context, error))
1010
        return;
1011
1012
      hide_buttons_val = FALSE;
1013
      if (hide_buttons && !parse_boolean (hide_buttons, &hide_buttons_val, context, error))
1014
        return;
1015
1016
      rounded_top_left_val = 0;
1017
      rounded_top_right_val = 0;
1018
      rounded_bottom_left_val = 0;
1019
      rounded_bottom_right_val = 0;
1020
1021
      if (rounded_top_left && !parse_rounding (rounded_top_left, &rounded_top_left_val, context, info->theme, error))
1022
        return;
1023
      if (rounded_top_right && !parse_rounding (rounded_top_right, &rounded_top_right_val, context, info->theme, error))
1024
        return;
1025
      if (rounded_bottom_left && !parse_rounding (rounded_bottom_left, &rounded_bottom_left_val, context, info->theme, error))
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1026
        return;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1027
      if (rounded_bottom_right && !parse_rounding (rounded_bottom_right, &rounded_bottom_right_val, context, info->theme, error))
1028
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1029
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1030
      title_scale_val = 1.0;
1031
      if (title_scale && !parse_title_scale (title_scale, &title_scale_val, context, error))
1032
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1033
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1034
      if (meta_theme_lookup_layout (info->theme, name))
1035
        {
1036
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1037
                     _("<%s> name \"%s\" used a second time"),
1038
                     element_name, name);
1039
          return;
1040
        }
1041
1042
      parent_layout = NULL;
1043
      if (parent)
1044
        {
1045
          parent_layout = meta_theme_lookup_layout (info->theme, parent);
1046
          if (parent_layout == NULL)
1047
            {
1048
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1049
                         _("<%s> parent \"%s\" has not been defined"),
1050
                         element_name, parent);
1051
              return;
1052
            }
1053
        }
1054
1055
      g_assert (info->layout == NULL);
1056
1057
      if (parent_layout)
1058
        info->layout = meta_frame_layout_copy (parent_layout);
1059
      else
1060
        info->layout = meta_frame_layout_new ();
1061
1062
      if (has_title) /* only if explicit, otherwise inherit */
1063
        info->layout->has_title = has_title_val;
1064
1065
      if (META_THEME_ALLOWS (info->theme, META_THEME_HIDDEN_BUTTONS) && hide_buttons_val)
1066
          info->layout->hide_buttons = hide_buttons_val;
1067
1068
      if (title_scale)
1069
	info->layout->title_scale = title_scale_val;
1070
1071
      if (rounded_top_left)
1072
        info->layout->top_left_corner_rounded_radius = rounded_top_left_val;
1073
1074
      if (rounded_top_right)
1075
        info->layout->top_right_corner_rounded_radius = rounded_top_right_val;
1076
1077
      if (rounded_bottom_left)
1078
        info->layout->bottom_left_corner_rounded_radius = rounded_bottom_left_val;
1079
1080
      if (rounded_bottom_right)
1081
        info->layout->bottom_right_corner_rounded_radius = rounded_bottom_right_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1082
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1083
      meta_theme_insert_layout (info->theme, name, info->layout);
1084
1085
      push_state (info, STATE_FRAME_GEOMETRY);
1086
    }
1087
  else if (ELEMENT_IS ("draw_ops"))
1088
    {
1089
      const char *name = NULL;
1090
1091
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1092
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1093
                              "!name", &name,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1094
                              NULL))
1095
        return;
1096
1097
      if (meta_theme_lookup_draw_op_list (info->theme, name))
1098
        {
1099
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1100
                     _("<%s> name \"%s\" used a second time"),
1101
                     element_name, name);
1102
          return;
1103
        }
1104
1105
      g_assert (info->op_list == NULL);
1106
      info->op_list = meta_draw_op_list_new (2);
1107
1108
      meta_theme_insert_draw_op_list (info->theme, name, info->op_list);
1109
1110
      push_state (info, STATE_DRAW_OPS);
1111
    }
1112
  else if (ELEMENT_IS ("frame_style"))
1113
    {
1114
      const char *name = NULL;
1115
      const char *parent = NULL;
1116
      const char *geometry = NULL;
1117
      const char *background = NULL;
1118
      const char *alpha = NULL;
1119
      MetaFrameStyle *parent_style;
1120
      MetaFrameLayout *layout;
1121
1122
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1123
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1124
                              "!name", &name, "parent", &parent,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1125
                              "geometry", &geometry,
1126
                              "background", &background,
1127
                              "alpha", &alpha,
1128
                              NULL))
1129
        return;
1130
1131
      if (meta_theme_lookup_style (info->theme, name))
1132
        {
1133
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1134
                     _("<%s> name \"%s\" used a second time"),
1135
                     element_name, name);
1136
          return;
1137
        }
1138
1139
      parent_style = NULL;
1140
      if (parent)
1141
        {
1142
          parent_style = meta_theme_lookup_style (info->theme, parent);
1143
          if (parent_style == NULL)
1144
            {
1145
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1146
                         _("<%s> parent \"%s\" has not been defined"),
1147
                         element_name, parent);
1148
              return;
1149
            }
1150
        }
1151
1152
      layout = NULL;
1153
      if (geometry)
1154
        {
1155
          layout = meta_theme_lookup_layout (info->theme, geometry);
1156
          if (layout == NULL)
1157
            {
1158
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1159
                         _("<%s> geometry \"%s\" has not been defined"),
1160
                         element_name, geometry);
1161
              return;
1162
            }
1163
        }
1164
      else if (parent_style)
1165
        {
1166
          layout = parent_style->layout;
1167
        }
1168
1169
      if (layout == NULL)
1170
        {
1171
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1172
                     _("<%s> must specify either a geometry or a parent that has a geometry"),
1173
                     element_name);
1174
          return;
1175
        }
1176
1177
      g_assert (info->style == NULL);
1178
1179
      info->style = meta_frame_style_new (parent_style);
1180
      g_assert (info->style->layout == NULL);
1181
      meta_frame_layout_ref (layout);
1182
      info->style->layout = layout;
1183
1184
      if (background != NULL && META_THEME_ALLOWS (info->theme, META_THEME_FRAME_BACKGROUNDS))
1185
        {
1186
          info->style->window_background_color = meta_color_spec_new_from_string (background, error);
1187
          if (!info->style->window_background_color)
1188
            return;
1189
1190
          if (alpha != NULL)
1191
            {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1192
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1193
               gboolean success;
1194
               MetaAlphaGradientSpec *alpha_vector;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1195
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1196
               g_clear_error (error);
1197
               /* fortunately, we already have a routine to parse alpha values,
1198
                * though it produces a vector of them, which is a superset of
1199
                * what we want.
1200
                */
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1201
               success = parse_alpha (alpha, &alpha_vector, context, error);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1202
               if (!success)
1203
                 return;
1204
1205
               /* alpha_vector->alphas must contain at least one element */
1206
               info->style->window_background_alpha = alpha_vector->alphas[0];
1207
1208
               meta_alpha_gradient_spec_free (alpha_vector);
1209
            }
1210
        }
1211
      else if (alpha != NULL)
1212
        {
1213
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1214
                     _("You must specify a background for an alpha value to be meaningful"));
1215
          return;
1216
        }
1217
1218
      meta_theme_insert_style (info->theme, name, info->style);
1219
1220
      push_state (info, STATE_FRAME_STYLE);
1221
    }
1222
  else if (ELEMENT_IS ("frame_style_set"))
1223
    {
1224
      const char *name = NULL;
1225
      const char *parent = NULL;
1226
      MetaFrameStyleSet *parent_set;
1227
1228
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1229
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1230
                              "!name", &name, "parent", &parent,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1231
                              NULL))
1232
        return;
1233
1234
      if (meta_theme_lookup_style_set (info->theme, name))
1235
        {
1236
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1237
                     _("<%s> name \"%s\" used a second time"),
1238
                     element_name, name);
1239
          return;
1240
        }
1241
1242
      parent_set = NULL;
1243
      if (parent)
1244
        {
1245
          parent_set = meta_theme_lookup_style_set (info->theme, parent);
1246
          if (parent_set == NULL)
1247
            {
1248
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1249
                         _("<%s> parent \"%s\" has not been defined"),
1250
                         element_name, parent);
1251
              return;
1252
            }
1253
        }
1254
1255
      g_assert (info->style_set == NULL);
1256
1257
      info->style_set = meta_frame_style_set_new (parent_set);
1258
1259
      meta_theme_insert_style_set (info->theme, name, info->style_set);
1260
1261
      push_state (info, STATE_FRAME_STYLE_SET);
1262
    }
1263
  else if (ELEMENT_IS ("window"))
1264
    {
1265
      const char *type_name = NULL;
1266
      const char *style_set_name = NULL;
1267
      MetaFrameStyleSet *style_set;
1268
      MetaFrameType type;
1269
1270
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1271
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1272
                              "!type", &type_name, "!style_set", &style_set_name,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1273
                              NULL))
1274
        return;
1275
1276
      type = meta_frame_type_from_string (type_name);
1277
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1278
      if (type == META_FRAME_TYPE_LAST ||
1279
         (type == META_FRAME_TYPE_ATTACHED && peek_required_version (info) < 3002))
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1280
        {
1281
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1282
                     _("Unknown type \"%s\" on <%s> element"),
1283
                     type_name, element_name);
1284
          return;
1285
        }
1286
1287
      style_set = meta_theme_lookup_style_set (info->theme,
1288
                                               style_set_name);
1289
1290
      if (style_set == NULL)
1291
        {
1292
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1293
                     _("Unknown style_set \"%s\" on <%s> element"),
1294
                     style_set_name, element_name);
1295
          return;
1296
        }
1297
1298
      if (info->theme->style_sets_by_type[type] != NULL)
1299
        {
1300
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1301
                     _("Window type \"%s\" has already been assigned a style set"),
1302
                     type_name);
1303
          return;
1304
        }
1305
1306
      meta_frame_style_set_ref (style_set);
1307
      info->theme->style_sets_by_type[type] = style_set;
1308
1309
      push_state (info, STATE_WINDOW);
1310
    }
1311
  else if (ELEMENT_IS ("menu_icon"))
1312
    {
1313
      /* Not supported any more, but we have to parse it if they include it,
1314
       * for backwards compatibility.
1315
       */
1316
      g_assert (info->op_list == NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1317
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1318
      push_state (info, STATE_MENU_ICON);
1319
    }
1320
  else if (ELEMENT_IS ("fallback"))
1321
    {
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1322
      /* Not supported any more, but we have to parse it if they include it,
1323
       * for backwards compatibility.
1324
       */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1325
      push_state (info, STATE_FALLBACK);
1326
    }
1327
   else
1328
    {
1329
      set_error (error, context,
1330
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1331
                 _("Element <%s> is not allowed below <%s>"),
1332
                 element_name, "metacity_theme");
1333
    }
1334
}
1335
1336
static void
1337
parse_info_element (GMarkupParseContext  *context,
1338
                    const gchar          *element_name,
1339
                    const gchar         **attribute_names,
1340
                    const gchar         **attribute_values,
1341
                    ParseInfo            *info,
1342
                    GError              **error)
1343
{
1344
  g_return_if_fail (peek_state (info) == STATE_INFO);
1345
1346
  if (ELEMENT_IS ("name"))
1347
    {
1348
      if (!check_no_attributes (context, element_name,
1349
                                attribute_names, attribute_values,
1350
                                error))
1351
        return;
1352
1353
      push_state (info, STATE_NAME);
1354
    }
1355
  else if (ELEMENT_IS ("author"))
1356
    {
1357
      if (!check_no_attributes (context, element_name,
1358
                                attribute_names, attribute_values,
1359
                                error))
1360
        return;
1361
1362
      push_state (info, STATE_AUTHOR);
1363
    }
1364
  else if (ELEMENT_IS ("copyright"))
1365
    {
1366
      if (!check_no_attributes (context, element_name,
1367
                                attribute_names, attribute_values,
1368
                                error))
1369
        return;
1370
1371
      push_state (info, STATE_COPYRIGHT);
1372
    }
1373
  else if (ELEMENT_IS ("description"))
1374
    {
1375
      if (!check_no_attributes (context, element_name,
1376
                                attribute_names, attribute_values,
1377
                                error))
1378
        return;
1379
1380
      push_state (info, STATE_DESCRIPTION);
1381
    }
1382
  else if (ELEMENT_IS ("date"))
1383
    {
1384
      if (!check_no_attributes (context, element_name,
1385
                                attribute_names, attribute_values,
1386
                                error))
1387
        return;
1388
1389
      push_state (info, STATE_DATE);
1390
    }
1391
  else
1392
    {
1393
      set_error (error, context,
1394
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1395
                 _("Element <%s> is not allowed below <%s>"),
1396
                 element_name, "info");
1397
    }
1398
}
1399
1400
static void
1401
parse_distance (GMarkupParseContext  *context,
1402
                const gchar          *element_name,
1403
                const gchar         **attribute_names,
1404
                const gchar         **attribute_values,
1405
                ParseInfo            *info,
1406
                GError              **error)
1407
{
1408
  const char *name;
1409
  const char *value;
1410
  int val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1411
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1412
  if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1413
                          error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1414
                          "!name", &name, "!value", &value,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1415
                          NULL))
1416
    return;
1417
1418
  val = 0;
1419
  if (!parse_positive_integer (value, &val, context, info->theme, error))
1420
    return;
1421
1422
  g_assert (val >= 0); /* yeah, "non-negative" not "positive" get over it */
1423
  g_assert (info->layout);
1424
1425
  if (strcmp (name, "left_width") == 0)
1426
    info->layout->left_width = val;
1427
  else if (strcmp (name, "right_width") == 0)
1428
    info->layout->right_width = val;
1429
  else if (strcmp (name, "bottom_height") == 0)
1430
    info->layout->bottom_height = val;
1431
  else if (strcmp (name, "title_vertical_pad") == 0)
1432
    info->layout->title_vertical_pad = val;
1433
  else if (strcmp (name, "right_titlebar_edge") == 0)
1434
    info->layout->right_titlebar_edge = val;
1435
  else if (strcmp (name, "left_titlebar_edge") == 0)
1436
    info->layout->left_titlebar_edge = val;
1437
  else if (strcmp (name, "button_width") == 0)
1438
    {
1439
      info->layout->button_width = val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1440
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1441
      if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST ||
1442
            info->layout->button_sizing == META_BUTTON_SIZING_FIXED))
1443
        {
1444
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1.2.48 by Pedro Fragoso
Import upstream version 2.25.8
1445
                     _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons"));
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1446
          return;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1447
        }
1448
1449
      info->layout->button_sizing = META_BUTTON_SIZING_FIXED;
1450
    }
1451
  else if (strcmp (name, "button_height") == 0)
1452
    {
1453
      info->layout->button_height = val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1454
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1455
      if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST ||
1456
            info->layout->button_sizing == META_BUTTON_SIZING_FIXED))
1457
        {
1458
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1.2.48 by Pedro Fragoso
Import upstream version 2.25.8
1459
                     _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons"));
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1460
          return;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1461
        }
1462
1463
      info->layout->button_sizing = META_BUTTON_SIZING_FIXED;
1464
    }
1465
  else
1466
    {
1467
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1468
                 _("Distance \"%s\" is unknown"), name);
1469
      return;
1470
    }
1471
}
1472
1473
static void
1474
parse_aspect_ratio (GMarkupParseContext  *context,
1475
                    const gchar          *element_name,
1476
                    const gchar         **attribute_names,
1477
                    const gchar         **attribute_values,
1478
                    ParseInfo            *info,
1479
                    GError              **error)
1480
{
1481
  const char *name;
1482
  const char *value;
1483
  double val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1484
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1485
  if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1486
                          error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1487
                          "!name", &name, "!value", &value,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1488
                          NULL))
1489
    return;
1490
1491
  val = 0;
1492
  if (!parse_double (value, &val, context, error))
1493
    return;
1494
1495
  g_assert (info->layout);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1496
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1497
  if (strcmp (name, "button") == 0)
1498
    {
1499
      info->layout->button_aspect = val;
1500
1501
      if (info->layout->button_sizing != META_BUTTON_SIZING_LAST)
1502
        {
1503
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1.2.48 by Pedro Fragoso
Import upstream version 2.25.8
1504
                     _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons"));
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1505
          return;
1506
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1507
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1508
      info->layout->button_sizing = META_BUTTON_SIZING_ASPECT;
1509
    }
1510
  else
1511
    {
1512
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1513
                 _("Aspect ratio \"%s\" is unknown"), name);
1514
      return;
1515
    }
1516
}
1517
1518
static void
1519
parse_border (GMarkupParseContext  *context,
1520
              const gchar          *element_name,
1521
              const gchar         **attribute_names,
1522
              const gchar         **attribute_values,
1523
              ParseInfo            *info,
1524
              GError              **error)
1525
{
1526
  const char *name;
1527
  const char *top;
1528
  const char *bottom;
1529
  const char *left;
1530
  const char *right;
1531
  int top_val;
1532
  int bottom_val;
1533
  int left_val;
1534
  int right_val;
1535
  GtkBorder *border;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1536
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1537
  if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1538
                          error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1539
                          "!name", &name,
1540
                          "!top", &top,
1541
                          "!bottom", &bottom,
1542
                          "!left", &left,
1543
                          "!right", &right,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1544
                          NULL))
1545
    return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1546
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1547
  top_val = 0;
1548
  if (!parse_positive_integer (top, &top_val, context, info->theme, error))
1549
    return;
1550
1551
  bottom_val = 0;
1552
  if (!parse_positive_integer (bottom, &bottom_val, context, info->theme, error))
1553
    return;
1554
1555
  left_val = 0;
1556
  if (!parse_positive_integer (left, &left_val, context, info->theme, error))
1557
    return;
1558
1559
  right_val = 0;
1560
  if (!parse_positive_integer (right, &right_val, context, info->theme, error))
1561
    return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1562
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1563
  g_assert (info->layout);
1564
1565
  border = NULL;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1566
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1567
  if (strcmp (name, "title_border") == 0)
1568
    border = &info->layout->title_border;
1569
  else if (strcmp (name, "button_border") == 0)
1570
    border = &info->layout->button_border;
1571
1572
  if (border == NULL)
1573
    {
1574
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1575
                 _("Border \"%s\" is unknown"), name);
1576
      return;
1577
    }
1578
1579
  border->top = top_val;
1580
  border->bottom = bottom_val;
1581
  border->left = left_val;
1582
  border->right = right_val;
1583
}
1584
1585
static void
1586
parse_geometry_element (GMarkupParseContext  *context,
1587
                        const gchar          *element_name,
1588
                        const gchar         **attribute_names,
1589
                        const gchar         **attribute_values,
1590
                        ParseInfo            *info,
1591
                        GError              **error)
1592
{
1593
  g_return_if_fail (peek_state (info) == STATE_FRAME_GEOMETRY);
1594
1595
  if (ELEMENT_IS ("distance"))
1596
    {
1597
      parse_distance (context, element_name,
1598
                      attribute_names, attribute_values,
1599
                      info, error);
1600
      push_state (info, STATE_DISTANCE);
1601
    }
1602
  else if (ELEMENT_IS ("border"))
1603
    {
1604
      parse_border (context, element_name,
1605
                    attribute_names, attribute_values,
1606
                    info, error);
1607
      push_state (info, STATE_BORDER);
1608
    }
1609
  else if (ELEMENT_IS ("aspect_ratio"))
1610
    {
1611
      parse_aspect_ratio (context, element_name,
1612
                          attribute_names, attribute_values,
1613
                          info, error);
1614
1615
      push_state (info, STATE_ASPECT_RATIO);
1616
    }
1617
  else
1618
    {
1619
      set_error (error, context,
1620
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1621
                 _("Element <%s> is not allowed below <%s>"),
1622
                 element_name, "frame_geometry");
1623
    }
1624
}
1625
1626
#if 0
1627
static gboolean
1628
check_expression (PosToken            *tokens,
1629
                  int                  n_tokens,
1630
                  gboolean             has_object,
1631
                  MetaTheme           *theme,
1632
                  GMarkupParseContext *context,
1633
                  GError             **error)
1634
{
1635
  MetaPositionExprEnv env;
1636
  int x, y;
1637
1638
  /* We set it all to 0 to try and catch divide-by-zero screwups.
1639
   * it's possible we should instead guarantee that widths and heights
1640
   * are at least 1.
1641
   */
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1642
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1643
  env.rect = meta_rect (0, 0, 0, 0);
1644
  if (has_object)
1645
    {
1646
      env.object_width = 0;
1647
      env.object_height = 0;
1648
    }
1649
  else
1650
    {
1651
      env.object_width = -1;
1652
      env.object_height = -1;
1653
    }
1654
1655
  env.left_width = 0;
1656
  env.right_width = 0;
1657
  env.top_height = 0;
1658
  env.bottom_height = 0;
1659
  env.title_width = 0;
1660
  env.title_height = 0;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1661
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1662
  env.icon_width = 0;
1663
  env.icon_height = 0;
1664
  env.mini_icon_width = 0;
1665
  env.mini_icon_height = 0;
1666
  env.theme = theme;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1667
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1668
  if (!meta_parse_position_expression (tokens, n_tokens,
1669
                                       &env,
1670
                                       &x, &y,
1671
                                       error))
1672
    {
1673
      add_context_to_error (error, context);
1674
      return FALSE;
1675
    }
1676
1677
  return TRUE;
1678
}
1679
#endif
1680
1681
static void
1682
parse_draw_op_element (GMarkupParseContext  *context,
1683
                       const gchar          *element_name,
1684
                       const gchar         **attribute_names,
1685
                       const gchar         **attribute_values,
1686
                       ParseInfo            *info,
1687
                       GError              **error)
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1688
{
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1689
  g_return_if_fail (peek_state (info) == STATE_DRAW_OPS);
1690
1691
  if (ELEMENT_IS ("line"))
1692
    {
1693
      MetaDrawOp *op;
1694
      const char *color;
1695
      const char *x1;
1696
      const char *y1;
1697
      const char *x2;
1698
      const char *y2;
1699
      const char *dash_on_length;
1700
      const char *dash_off_length;
1701
      const char *width;
1702
      MetaColorSpec *color_spec;
1703
      int dash_on_val;
1704
      int dash_off_val;
1705
      int width_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1706
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1707
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1708
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1709
                              "!color", &color,
1710
                              "!x1", &x1, "!y1", &y1,
1711
                              "!x2", &x2, "!y2", &y2,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1712
                              "dash_on_length", &dash_on_length,
1713
                              "dash_off_length", &dash_off_length,
1714
                              "width", &width,
1715
                              NULL))
1716
        return;
1717
1718
#if 0
1719
      if (!check_expression (x1, FALSE, info->theme, context, error))
1720
        return;
1721
1722
      if (!check_expression (y1, FALSE, info->theme, context, error))
1723
        return;
1724
1725
      if (!check_expression (x2, FALSE, info->theme, context, error))
1726
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1727
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1728
      if (!check_expression (y2, FALSE, info->theme, context, error))
1729
        return;
1730
#endif
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1731
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1732
      dash_on_val = 0;
1733
      if (dash_on_length &&
1734
          !parse_positive_integer (dash_on_length, &dash_on_val, context, info->theme, error))
1735
        return;
1736
1737
      dash_off_val = 0;
1738
      if (dash_off_length &&
1739
          !parse_positive_integer (dash_off_length, &dash_off_val, context, info->theme, error))
1740
        return;
1741
1742
      width_val = 0;
1743
      if (width &&
1744
          !parse_positive_integer (width, &width_val, context, info->theme, error))
1745
        return;
1746
1747
      /* Check last so we don't have to free it when other
1748
       * stuff fails
1749
       */
1750
      color_spec = parse_color (info->theme, color, error);
1751
      if (color_spec == NULL)
1752
        {
1753
          add_context_to_error (error, context);
1754
          return;
1755
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1756
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1757
      op = meta_draw_op_new (META_DRAW_LINE);
1758
1759
      op->data.line.color_spec = color_spec;
1760
1761
      op->data.line.x1 = meta_draw_spec_new (info->theme, x1, NULL);
1762
      op->data.line.y1 = meta_draw_spec_new (info->theme, y1, NULL);
1.2.54 by Robert Ancell
Import upstream version 2.27.0
1763
1764
      if (strcmp(x1, x2)==0)
1765
        op->data.line.x2 = NULL;
1766
      else
1767
        op->data.line.x2 = meta_draw_spec_new (info->theme, x2, NULL);
1768
1769
      if (strcmp(y1, y2)==0)
1770
        op->data.line.y2 = NULL;
1771
      else
1772
        op->data.line.y2 = meta_draw_spec_new (info->theme, y2, NULL);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1773
1774
      op->data.line.width = width_val;
1775
      op->data.line.dash_on_length = dash_on_val;
1776
      op->data.line.dash_off_length = dash_off_val;
1777
1778
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1779
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1780
      meta_draw_op_list_append (info->op_list, op);
1781
1782
      push_state (info, STATE_LINE);
1783
    }
1784
  else if (ELEMENT_IS ("rectangle"))
1785
    {
1786
      MetaDrawOp *op;
1787
      const char *color;
1788
      const char *x;
1789
      const char *y;
1790
      const char *width;
1791
      const char *height;
1792
      const char *filled;
1793
      gboolean filled_val;
1794
      MetaColorSpec *color_spec;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1795
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1796
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1797
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1798
                              "!color", &color,
1799
                              "!x", &x, "!y", &y,
1800
                              "!width", &width, "!height", &height,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1801
                              "filled", &filled,
1802
                              NULL))
1803
        return;
1804
1805
#if 0
1806
      if (!check_expression (x, FALSE, info->theme, context, error))
1807
        return;
1808
1809
      if (!check_expression (y, FALSE, info->theme, context, error))
1810
        return;
1811
1812
      if (!check_expression (width, FALSE, info->theme, context, error))
1813
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1814
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1815
      if (!check_expression (height, FALSE, info->theme, context, error))
1816
        return;
1817
#endif
1818
1819
      filled_val = FALSE;
1820
      if (filled && !parse_boolean (filled, &filled_val, context, error))
1821
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1822
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1823
      /* Check last so we don't have to free it when other
1824
       * stuff fails
1825
       */
1826
      color_spec = parse_color (info->theme, color, error);
1827
      if (color_spec == NULL)
1828
        {
1829
          add_context_to_error (error, context);
1830
          return;
1831
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1832
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1833
      op = meta_draw_op_new (META_DRAW_RECTANGLE);
1834
1835
      op->data.rectangle.color_spec = color_spec;
1836
      op->data.rectangle.x = meta_draw_spec_new (info->theme, x, NULL);
1837
      op->data.rectangle.y = meta_draw_spec_new (info->theme, y, NULL);
1838
      op->data.rectangle.width = meta_draw_spec_new (info->theme, width, NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1839
      op->data.rectangle.height = meta_draw_spec_new (info->theme,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1840
                                                      height, NULL);
1841
1842
      op->data.rectangle.filled = filled_val;
1843
1844
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1845
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1846
      meta_draw_op_list_append (info->op_list, op);
1847
1848
      push_state (info, STATE_RECTANGLE);
1849
    }
1850
  else if (ELEMENT_IS ("arc"))
1851
    {
1852
      MetaDrawOp *op;
1853
      const char *color;
1854
      const char *x;
1855
      const char *y;
1856
      const char *width;
1857
      const char *height;
1858
      const char *filled;
1859
      const char *start_angle;
1860
      const char *extent_angle;
1861
      const char *from;
1862
      const char *to;
1863
      gboolean filled_val;
1864
      double start_angle_val;
1865
      double extent_angle_val;
1866
      MetaColorSpec *color_spec;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1867
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1868
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1869
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1870
                              "!color", &color,
1871
                              "!x", &x, "!y", &y,
1872
                              "!width", &width, "!height", &height,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1873
                              "filled", &filled,
1874
                              "start_angle", &start_angle,
1875
                              "extent_angle", &extent_angle,
1876
                              "from", &from,
1877
                              "to", &to,
1878
                              NULL))
1879
        return;
1880
1881
      if (META_THEME_ALLOWS (info->theme, META_THEME_DEGREES_IN_ARCS) )
1882
        {
1883
          if (start_angle == NULL && from == NULL)
1884
            {
1885
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1886
                         _("No \"start_angle\" or \"from\" attribute on element <%s>"), element_name);
1887
              return;
1888
            }
1889
1890
          if (extent_angle == NULL && to == NULL)
1891
            {
1892
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1893
                         _("No \"extent_angle\" or \"to\" attribute on element <%s>"), element_name);
1894
              return;
1895
            }
1896
        }
1897
      else
1898
        {
1899
          if (start_angle == NULL)
1900
            {
1901
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1902
                         ATTRIBUTE_NOT_FOUND, "start_angle", element_name);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1903
              return;
1904
            }
1905
1906
          if (extent_angle == NULL)
1907
            {
1908
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1909
                         ATTRIBUTE_NOT_FOUND, "extent_angle", element_name);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1910
              return;
1911
            }
1912
        }
1913
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1914
#if 0
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1915
      if (!check_expression (x, FALSE, info->theme, context, error))
1916
        return;
1917
1918
      if (!check_expression (y, FALSE, info->theme, context, error))
1919
        return;
1920
1921
      if (!check_expression (width, FALSE, info->theme, context, error))
1922
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1923
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1924
      if (!check_expression (height, FALSE, info->theme, context, error))
1925
        return;
1926
#endif
1927
1928
      if (start_angle == NULL)
1929
        {
1930
          if (!parse_angle (from, &start_angle_val, context, error))
1931
            return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1932
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1933
          start_angle_val = (180-start_angle_val)/360.0;
1934
        }
1935
      else
1936
        {
1937
          if (!parse_angle (start_angle, &start_angle_val, context, error))
1938
            return;
1939
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1940
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1941
      if (extent_angle == NULL)
1942
        {
1943
          if (!parse_angle (to, &extent_angle_val, context, error))
1944
            return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1945
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1946
          extent_angle_val = ((180-extent_angle_val)/360.0) - start_angle_val;
1947
        }
1948
      else
1949
        {
1950
           if (!parse_angle (extent_angle, &extent_angle_val, context, error))
1951
             return;
1952
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1953
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1954
      filled_val = FALSE;
1955
      if (filled && !parse_boolean (filled, &filled_val, context, error))
1956
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1957
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1958
      /* Check last so we don't have to free it when other
1959
       * stuff fails
1960
       */
1961
      color_spec = parse_color (info->theme, color, error);
1962
      if (color_spec == NULL)
1963
        {
1964
          add_context_to_error (error, context);
1965
          return;
1966
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1967
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1968
      op = meta_draw_op_new (META_DRAW_ARC);
1969
1970
      op->data.arc.color_spec = color_spec;
1971
1972
      op->data.arc.x = meta_draw_spec_new (info->theme, x, NULL);
1973
      op->data.arc.y = meta_draw_spec_new (info->theme, y, NULL);
1974
      op->data.arc.width = meta_draw_spec_new (info->theme, width, NULL);
1975
      op->data.arc.height = meta_draw_spec_new (info->theme, height, NULL);
1976
1977
      op->data.arc.filled = filled_val;
1978
      op->data.arc.start_angle = start_angle_val;
1979
      op->data.arc.extent_angle = extent_angle_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1980
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1981
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1982
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1983
      meta_draw_op_list_append (info->op_list, op);
1984
1985
      push_state (info, STATE_ARC);
1986
    }
1987
  else if (ELEMENT_IS ("clip"))
1988
    {
1989
      MetaDrawOp *op;
1990
      const char *x;
1991
      const char *y;
1992
      const char *width;
1993
      const char *height;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
1994
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1995
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1996
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
1997
                              "!x", &x, "!y", &y,
1998
                              "!width", &width, "!height", &height,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
1999
                              NULL))
2000
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2001
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2002
#if 0
2003
      if (!check_expression (x, FALSE, info->theme, context, error))
2004
        return;
2005
2006
      if (!check_expression (y, FALSE, info->theme, context, error))
2007
        return;
2008
2009
      if (!check_expression (width, FALSE, info->theme, context, error))
2010
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2011
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2012
      if (!check_expression (height, FALSE, info->theme, context, error))
2013
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2014
#endif
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2015
      op = meta_draw_op_new (META_DRAW_CLIP);
2016
2017
      op->data.clip.x = meta_draw_spec_new (info->theme, x, NULL);
2018
      op->data.clip.y = meta_draw_spec_new (info->theme, y, NULL);
2019
      op->data.clip.width = meta_draw_spec_new (info->theme, width, NULL);
2020
      op->data.clip.height = meta_draw_spec_new (info->theme, height, NULL);
2021
2022
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2023
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2024
      meta_draw_op_list_append (info->op_list, op);
2025
2026
      push_state (info, STATE_CLIP);
2027
    }
2028
  else if (ELEMENT_IS ("tint"))
2029
    {
2030
      MetaDrawOp *op;
2031
      const char *color;
2032
      const char *x;
2033
      const char *y;
2034
      const char *width;
2035
      const char *height;
2036
      const char *alpha;
2037
      MetaAlphaGradientSpec *alpha_spec;
2038
      MetaColorSpec *color_spec;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2039
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2040
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2041
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2042
                              "!color", &color,
2043
                              "!x", &x, "!y", &y,
2044
                              "!width", &width, "!height", &height,
2045
                              "!alpha", &alpha,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2046
                              NULL))
2047
        return;
2048
2049
#if 0
2050
      if (!check_expression (x, FALSE, info->theme, context, error))
2051
        return;
2052
2053
      if (!check_expression (y, FALSE, info->theme, context, error))
2054
        return;
2055
2056
      if (!check_expression (width, FALSE, info->theme, context, error))
2057
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2058
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2059
      if (!check_expression (height, FALSE, info->theme, context, error))
2060
        return;
2061
#endif
2062
      alpha_spec = NULL;
2063
      if (!parse_alpha (alpha, &alpha_spec, context, error))
2064
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2065
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2066
      /* Check last so we don't have to free it when other
2067
       * stuff fails
2068
       */
2069
      color_spec = parse_color (info->theme, color, error);
2070
      if (color_spec == NULL)
2071
        {
2072
          if (alpha_spec)
2073
            meta_alpha_gradient_spec_free (alpha_spec);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2074
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2075
          add_context_to_error (error, context);
2076
          return;
2077
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2078
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2079
      op = meta_draw_op_new (META_DRAW_TINT);
2080
2081
      op->data.tint.color_spec = color_spec;
2082
      op->data.tint.alpha_spec = alpha_spec;
2083
2084
      op->data.tint.x = meta_draw_spec_new (info->theme, x, NULL);
2085
      op->data.tint.y = meta_draw_spec_new (info->theme, y, NULL);
2086
      op->data.tint.width = meta_draw_spec_new (info->theme, width, NULL);
2087
      op->data.tint.height = meta_draw_spec_new (info->theme, height, NULL);
2088
2089
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2090
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2091
      meta_draw_op_list_append (info->op_list, op);
2092
2093
      push_state (info, STATE_TINT);
2094
    }
2095
  else if (ELEMENT_IS ("gradient"))
2096
    {
2097
      const char *x;
2098
      const char *y;
2099
      const char *width;
2100
      const char *height;
2101
      const char *type;
2102
      const char *alpha;
2103
      MetaAlphaGradientSpec *alpha_spec;
2104
      MetaGradientType type_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2105
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2106
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2107
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2108
                              "!type", &type,
2109
                              "!x", &x, "!y", &y,
2110
                              "!width", &width, "!height", &height,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2111
                              "alpha", &alpha,
2112
                              NULL))
2113
        return;
2114
2115
#if 0
2116
      if (!check_expression (x, FALSE, info->theme, context, error))
2117
        return;
2118
2119
      if (!check_expression (y, FALSE, info->theme, context, error))
2120
        return;
2121
2122
      if (!check_expression (width, FALSE, info->theme, context, error))
2123
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2124
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2125
      if (!check_expression (height, FALSE, info->theme, context, error))
2126
        return;
2127
#endif
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2128
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2129
      type_val = meta_gradient_type_from_string (type);
2130
      if (type_val == META_GRADIENT_LAST)
2131
        {
2132
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2133
                     _("Did not understand value \"%s\" for type of gradient"),
2134
                     type);
2135
          return;
2136
        }
2137
2138
      alpha_spec = NULL;
2139
      if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
2140
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2141
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2142
      g_assert (info->op == NULL);
2143
      info->op = meta_draw_op_new (META_DRAW_GRADIENT);
2144
2145
      info->op->data.gradient.x = meta_draw_spec_new (info->theme, x, NULL);
2146
      info->op->data.gradient.y = meta_draw_spec_new (info->theme, y, NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2147
      info->op->data.gradient.width = meta_draw_spec_new (info->theme,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2148
                                                        width, NULL);
2149
      info->op->data.gradient.height = meta_draw_spec_new (info->theme,
2150
                                                         height, NULL);
2151
2152
      info->op->data.gradient.gradient_spec = meta_gradient_spec_new (type_val);
2153
2154
      info->op->data.gradient.alpha_spec = alpha_spec;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2155
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2156
      push_state (info, STATE_GRADIENT);
2157
2158
      /* op gets appended on close tag */
2159
    }
2160
  else if (ELEMENT_IS ("image"))
2161
    {
2162
      MetaDrawOp *op;
2163
      const char *filename;
2164
      const char *x;
2165
      const char *y;
2166
      const char *width;
2167
      const char *height;
2168
      const char *alpha;
2169
      const char *colorize;
2170
      const char *fill_type;
2171
      MetaAlphaGradientSpec *alpha_spec;
2172
      GdkPixbuf *pixbuf;
2173
      MetaColorSpec *colorize_spec = NULL;
2174
      MetaImageFillType fill_type_val;
2175
      int h, w, c;
2176
      int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride;
2177
      guchar *pixbuf_pixels;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2178
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2179
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2180
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2181
                              "!x", &x, "!y", &y,
2182
                              "!width", &width, "!height", &height,
2183
                              "alpha", &alpha, "!filename", &filename,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2184
                              "colorize", &colorize,
2185
                              "fill_type", &fill_type,
2186
                              NULL))
2187
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2188
2189
#if 0
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2190
      if (!check_expression (x, TRUE, info->theme, context, error))
2191
        return;
2192
2193
      if (!check_expression (y, TRUE, info->theme, context, error))
2194
        return;
2195
2196
      if (!check_expression (width, TRUE, info->theme, context, error))
2197
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2198
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2199
      if (!check_expression (height, TRUE, info->theme, context, error))
2200
        return;
2201
#endif
2202
      fill_type_val = META_IMAGE_FILL_SCALE;
2203
      if (fill_type)
2204
        {
2205
          fill_type_val = meta_image_fill_type_from_string (fill_type);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2206
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2207
          if (((int) fill_type_val) == -1)
2208
            {
2209
              set_error (error, context, G_MARKUP_ERROR,
2210
                         G_MARKUP_ERROR_PARSE,
2211
                         _("Did not understand fill type \"%s\" for <%s> element"),
2212
                         fill_type, element_name);
2213
            }
2214
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2215
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2216
      /* Check last so we don't have to free it when other
2217
       * stuff fails.
2218
       *
2219
       * If it's a theme image, ask for it at 64px, which is
2220
       * the largest possible. We scale it anyway.
2221
       */
2222
      pixbuf = meta_theme_load_image (info->theme, filename, 64, error);
2223
2224
      if (pixbuf == NULL)
2225
        {
2226
          add_context_to_error (error, context);
2227
          return;
2228
        }
2229
2230
      if (colorize)
2231
        {
2232
          colorize_spec = parse_color (info->theme, colorize, error);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2233
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2234
          if (colorize_spec == NULL)
2235
            {
2236
              add_context_to_error (error, context);
2237
              g_object_unref (G_OBJECT (pixbuf));
2238
              return;
2239
            }
2240
        }
2241
2242
      alpha_spec = NULL;
2243
      if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
2244
        {
2245
          g_object_unref (G_OBJECT (pixbuf));
2246
          return;
2247
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2248
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2249
      op = meta_draw_op_new (META_DRAW_IMAGE);
2250
2251
      op->data.image.pixbuf = pixbuf;
2252
      op->data.image.colorize_spec = colorize_spec;
2253
2254
      op->data.image.x = meta_draw_spec_new (info->theme, x, NULL);
2255
      op->data.image.y = meta_draw_spec_new (info->theme, y, NULL);
2256
      op->data.image.width = meta_draw_spec_new (info->theme, width, NULL);
2257
      op->data.image.height = meta_draw_spec_new (info->theme, height, NULL);
2258
2259
      op->data.image.alpha_spec = alpha_spec;
2260
      op->data.image.fill_type = fill_type_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2261
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2262
      /* Check for vertical & horizontal stripes */
2263
      pixbuf_n_channels = gdk_pixbuf_get_n_channels(pixbuf);
2264
      pixbuf_width = gdk_pixbuf_get_width(pixbuf);
2265
      pixbuf_height = gdk_pixbuf_get_height(pixbuf);
2266
      pixbuf_rowstride = gdk_pixbuf_get_rowstride(pixbuf);
2267
      pixbuf_pixels = gdk_pixbuf_get_pixels(pixbuf);
2268
2269
      /* Check for horizontal stripes */
2270
      for (h = 0; h < pixbuf_height; h++)
2271
        {
2272
          for (w = 1; w < pixbuf_width; w++)
2273
            {
2274
              for (c = 0; c < pixbuf_n_channels; c++)
2275
                {
2276
                  if (pixbuf_pixels[(h * pixbuf_rowstride) + c] !=
2277
                      pixbuf_pixels[(h * pixbuf_rowstride) + w + c])
2278
                    break;
2279
                }
2280
              if (c < pixbuf_n_channels)
2281
                break;
2282
            }
2283
          if (w < pixbuf_width)
2284
            break;
2285
        }
2286
2287
      if (h >= pixbuf_height)
2288
        {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2289
          op->data.image.horizontal_stripes = TRUE;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2290
        }
2291
      else
2292
        {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2293
          op->data.image.horizontal_stripes = FALSE;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2294
        }
2295
2296
      /* Check for vertical stripes */
2297
      for (w = 0; w < pixbuf_width; w++)
2298
        {
2299
          for (h = 1; h < pixbuf_height; h++)
2300
            {
2301
              for (c = 0; c < pixbuf_n_channels; c++)
2302
                {
2303
                  if (pixbuf_pixels[w + c] !=
2304
                      pixbuf_pixels[(h * pixbuf_rowstride) + w + c])
2305
                    break;
2306
                }
2307
              if (c < pixbuf_n_channels)
2308
                break;
2309
            }
2310
          if (h < pixbuf_height)
2311
            break;
2312
        }
2313
2314
      if (w >= pixbuf_width)
2315
        {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2316
          op->data.image.vertical_stripes = TRUE;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2317
        }
2318
      else
2319
        {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2320
          op->data.image.vertical_stripes = FALSE;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2321
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2322
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2323
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2324
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2325
      meta_draw_op_list_append (info->op_list, op);
2326
2327
      push_state (info, STATE_IMAGE);
2328
    }
2329
  else if (ELEMENT_IS ("gtk_arrow"))
2330
    {
2331
      MetaDrawOp *op;
2332
      const char *state;
2333
      const char *shadow;
2334
      const char *arrow;
2335
      const char *x;
2336
      const char *y;
2337
      const char *width;
2338
      const char *height;
2339
      const char *filled;
2340
      gboolean filled_val;
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
2341
      GtkStateFlags state_val;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2342
      GtkShadowType shadow_val;
2343
      GtkArrowType arrow_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2344
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2345
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2346
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2347
                              "!state", &state,
2348
                              "!shadow", &shadow,
2349
                              "!arrow", &arrow,
2350
                              "!x", &x, "!y", &y,
2351
                              "!width", &width, "!height", &height,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2352
                              "filled", &filled,
2353
                              NULL))
2354
        return;
2355
2356
#if 0
2357
      if (!check_expression (x, FALSE, info->theme, context, error))
2358
        return;
2359
2360
      if (!check_expression (y, FALSE, info->theme, context, error))
2361
        return;
2362
2363
      if (!check_expression (width, FALSE, info->theme, context, error))
2364
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2365
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2366
      if (!check_expression (height, FALSE, info->theme, context, error))
2367
        return;
2368
#endif
2369
      filled_val = TRUE;
2370
      if (filled && !parse_boolean (filled, &filled_val, context, error))
2371
        return;
2372
2373
      state_val = meta_gtk_state_from_string (state);
2374
      if (((int) state_val) == -1)
2375
        {
2376
          set_error (error, context, G_MARKUP_ERROR,
2377
                     G_MARKUP_ERROR_PARSE,
2378
                     _("Did not understand state \"%s\" for <%s> element"),
2379
                     state, element_name);
2380
          return;
2381
        }
2382
2383
      shadow_val = meta_gtk_shadow_from_string (shadow);
2384
      if (((int) shadow_val) == -1)
2385
        {
2386
          set_error (error, context, G_MARKUP_ERROR,
2387
                     G_MARKUP_ERROR_PARSE,
2388
                     _("Did not understand shadow \"%s\" for <%s> element"),
2389
                     shadow, element_name);
2390
          return;
2391
        }
2392
2393
      arrow_val = meta_gtk_arrow_from_string (arrow);
2394
      if (((int) arrow_val) == -1)
2395
        {
2396
          set_error (error, context, G_MARKUP_ERROR,
2397
                     G_MARKUP_ERROR_PARSE,
2398
                     _("Did not understand arrow \"%s\" for <%s> element"),
2399
                     arrow, element_name);
2400
          return;
2401
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2402
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2403
      op = meta_draw_op_new (META_DRAW_GTK_ARROW);
2404
2405
      op->data.gtk_arrow.x = meta_draw_spec_new (info->theme, x, NULL);
2406
      op->data.gtk_arrow.y = meta_draw_spec_new (info->theme, y, NULL);
2407
      op->data.gtk_arrow.width = meta_draw_spec_new (info->theme, width, NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2408
      op->data.gtk_arrow.height = meta_draw_spec_new (info->theme,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2409
                                                      height, NULL);
2410
2411
      op->data.gtk_arrow.filled = filled_val;
2412
      op->data.gtk_arrow.state = state_val;
2413
      op->data.gtk_arrow.shadow = shadow_val;
2414
      op->data.gtk_arrow.arrow = arrow_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2415
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2416
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2417
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2418
      meta_draw_op_list_append (info->op_list, op);
2419
2420
      push_state (info, STATE_GTK_ARROW);
2421
    }
2422
  else if (ELEMENT_IS ("gtk_box"))
2423
    {
2424
      MetaDrawOp *op;
2425
      const char *state;
2426
      const char *shadow;
2427
      const char *x;
2428
      const char *y;
2429
      const char *width;
2430
      const char *height;
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
2431
      GtkStateFlags state_val;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2432
      GtkShadowType shadow_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2433
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2434
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2435
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2436
                              "!state", &state,
2437
                              "!shadow", &shadow,
2438
                              "!x", &x, "!y", &y,
2439
                              "!width", &width, "!height", &height,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2440
                              NULL))
2441
        return;
2442
2443
#if 0
2444
      if (!check_expression (x, FALSE, info->theme, context, error))
2445
        return;
2446
2447
      if (!check_expression (y, FALSE, info->theme, context, error))
2448
        return;
2449
2450
      if (!check_expression (width, FALSE, info->theme, context, error))
2451
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2452
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2453
      if (!check_expression (height, FALSE, info->theme, context, error))
2454
        return;
2455
#endif
2456
      state_val = meta_gtk_state_from_string (state);
2457
      if (((int) state_val) == -1)
2458
        {
2459
          set_error (error, context, G_MARKUP_ERROR,
2460
                     G_MARKUP_ERROR_PARSE,
2461
                     _("Did not understand state \"%s\" for <%s> element"),
2462
                     state, element_name);
2463
          return;
2464
        }
2465
2466
      shadow_val = meta_gtk_shadow_from_string (shadow);
2467
      if (((int) shadow_val) == -1)
2468
        {
2469
          set_error (error, context, G_MARKUP_ERROR,
2470
                     G_MARKUP_ERROR_PARSE,
2471
                     _("Did not understand shadow \"%s\" for <%s> element"),
2472
                     shadow, element_name);
2473
          return;
2474
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2475
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2476
      op = meta_draw_op_new (META_DRAW_GTK_BOX);
2477
2478
      op->data.gtk_box.x = meta_draw_spec_new (info->theme, x, NULL);
2479
      op->data.gtk_box.y = meta_draw_spec_new (info->theme, y, NULL);
2480
      op->data.gtk_box.width = meta_draw_spec_new (info->theme, width, NULL);
2481
      op->data.gtk_box.height = meta_draw_spec_new (info->theme, height, NULL);
2482
2483
      op->data.gtk_box.state = state_val;
2484
      op->data.gtk_box.shadow = shadow_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2485
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2486
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2487
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2488
      meta_draw_op_list_append (info->op_list, op);
2489
2490
      push_state (info, STATE_GTK_BOX);
2491
    }
2492
  else if (ELEMENT_IS ("gtk_vline"))
2493
    {
2494
      MetaDrawOp *op;
2495
      const char *state;
2496
      const char *x;
2497
      const char *y1;
2498
      const char *y2;
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
2499
      GtkStateFlags state_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2500
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2501
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2502
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2503
                              "!state", &state,
2504
                              "!x", &x, "!y1", &y1, "!y2", &y2,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2505
                              NULL))
2506
        return;
2507
2508
#if 0
2509
      if (!check_expression (x, FALSE, info->theme, context, error))
2510
        return;
2511
2512
      if (!check_expression (y1, FALSE, info->theme, context, error))
2513
        return;
2514
2515
      if (!check_expression (y2, FALSE, info->theme, context, error))
2516
        return;
2517
#endif
2518
2519
      state_val = meta_gtk_state_from_string (state);
2520
      if (((int) state_val) == -1)
2521
        {
2522
          set_error (error, context, G_MARKUP_ERROR,
2523
                     G_MARKUP_ERROR_PARSE,
2524
                     _("Did not understand state \"%s\" for <%s> element"),
2525
                     state, element_name);
2526
          return;
2527
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2528
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2529
      op = meta_draw_op_new (META_DRAW_GTK_VLINE);
2530
2531
      op->data.gtk_vline.x = meta_draw_spec_new (info->theme, x, NULL);
2532
      op->data.gtk_vline.y1 = meta_draw_spec_new (info->theme, y1, NULL);
2533
      op->data.gtk_vline.y2 = meta_draw_spec_new (info->theme, y2, NULL);
2534
2535
      op->data.gtk_vline.state = state_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2536
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2537
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2538
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2539
      meta_draw_op_list_append (info->op_list, op);
2540
2541
      push_state (info, STATE_GTK_VLINE);
2542
    }
2543
  else if (ELEMENT_IS ("icon"))
2544
    {
2545
      MetaDrawOp *op;
2546
      const char *x;
2547
      const char *y;
2548
      const char *width;
2549
      const char *height;
2550
      const char *alpha;
2551
      const char *fill_type;
2552
      MetaAlphaGradientSpec *alpha_spec;
2553
      MetaImageFillType fill_type_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2554
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2555
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2556
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2557
                              "!x", &x, "!y", &y,
2558
                              "!width", &width, "!height", &height,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2559
                              "alpha", &alpha,
2560
                              "fill_type", &fill_type,
2561
                              NULL))
2562
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2563
2564
#if 0
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2565
      if (!check_expression (x, FALSE, info->theme, context, error))
2566
        return;
2567
2568
      if (!check_expression (y, FALSE, info->theme, context, error))
2569
        return;
2570
2571
      if (!check_expression (width, FALSE, info->theme, context, error))
2572
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2573
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2574
      if (!check_expression (height, FALSE, info->theme, context, error))
2575
        return;
2576
#endif
2577
      fill_type_val = META_IMAGE_FILL_SCALE;
2578
      if (fill_type)
2579
        {
2580
          fill_type_val = meta_image_fill_type_from_string (fill_type);
2581
2582
          if (((int) fill_type_val) == -1)
2583
            {
2584
              set_error (error, context, G_MARKUP_ERROR,
2585
                         G_MARKUP_ERROR_PARSE,
2586
                         _("Did not understand fill type \"%s\" for <%s> element"),
2587
                         fill_type, element_name);
2588
            }
2589
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2590
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2591
      alpha_spec = NULL;
2592
      if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
2593
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2594
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2595
      op = meta_draw_op_new (META_DRAW_ICON);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2596
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2597
      op->data.icon.x = meta_draw_spec_new (info->theme, x, NULL);
2598
      op->data.icon.y = meta_draw_spec_new (info->theme, y, NULL);
2599
      op->data.icon.width = meta_draw_spec_new (info->theme, width, NULL);
2600
      op->data.icon.height = meta_draw_spec_new (info->theme, height, NULL);
2601
2602
      op->data.icon.alpha_spec = alpha_spec;
2603
      op->data.icon.fill_type = fill_type_val;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2604
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2605
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2606
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2607
      meta_draw_op_list_append (info->op_list, op);
2608
2609
      push_state (info, STATE_ICON);
2610
    }
2611
  else if (ELEMENT_IS ("title"))
2612
    {
2613
      MetaDrawOp *op;
2614
      const char *color;
2615
      const char *x;
2616
      const char *y;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2617
      const char *ellipsize_width;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2618
      MetaColorSpec *color_spec;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2619
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2620
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2621
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2622
                              "!color", &color,
2623
                              "!x", &x, "!y", &y,
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2624
                              "ellipsize_width", &ellipsize_width,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2625
                              NULL))
2626
        return;
2627
2628
#if 0
2629
      if (!check_expression (x, FALSE, info->theme, context, error))
2630
        return;
2631
2632
      if (!check_expression (y, FALSE, info->theme, context, error))
2633
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2634
2635
      if (!check_expression (ellipsize_width, FALSE, info->theme, context, error))
2636
        return;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2637
#endif
2638
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2639
      if (ellipsize_width && peek_required_version (info) < 3001)
2640
        {
2641
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2642
                     ATTRIBUTE_NOT_FOUND, "ellipsize_width", element_name);
2643
          return;
2644
        }
2645
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2646
      /* Check last so we don't have to free it when other
2647
       * stuff fails
2648
       */
2649
      color_spec = parse_color (info->theme, color, error);
2650
      if (color_spec == NULL)
2651
        {
2652
          add_context_to_error (error, context);
2653
          return;
2654
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2655
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2656
      op = meta_draw_op_new (META_DRAW_TITLE);
2657
2658
      op->data.title.color_spec = color_spec;
2659
2660
      op->data.title.x = meta_draw_spec_new (info->theme, x, NULL);
2661
      op->data.title.y = meta_draw_spec_new (info->theme, y, NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2662
      if (ellipsize_width)
2663
        op->data.title.ellipsize_width = meta_draw_spec_new (info->theme, ellipsize_width, NULL);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2664
2665
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2666
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2667
      meta_draw_op_list_append (info->op_list, op);
2668
2669
      push_state (info, STATE_TITLE);
2670
    }
2671
  else if (ELEMENT_IS ("include"))
2672
    {
2673
      MetaDrawOp *op;
2674
      const char *name;
2675
      const char *x;
2676
      const char *y;
2677
      const char *width;
2678
      const char *height;
2679
      MetaDrawOpList *op_list;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2680
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2681
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2682
                              error,
2683
                              "x", &x, "y", &y,
2684
                              "width", &width, "height", &height,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2685
                              "!name", &name,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2686
                              NULL))
2687
        return;
2688
2689
      /* x/y/width/height default to 0,0,width,height - should
2690
       * probably do this for all the draw ops
2691
       */
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2692
#if 0
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2693
      if (x && !check_expression (x, FALSE, info->theme, context, error))
2694
        return;
2695
2696
      if (y && !check_expression (y, FALSE, info->theme, context, error))
2697
        return;
2698
2699
      if (width && !check_expression (width, FALSE, info->theme, context, error))
2700
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2701
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2702
      if (height && !check_expression (height, FALSE, info->theme, context, error))
2703
        return;
2704
#endif
2705
2706
      op_list = meta_theme_lookup_draw_op_list (info->theme,
2707
                                                name);
2708
      if (op_list == NULL)
2709
        {
2710
          set_error (error, context, G_MARKUP_ERROR,
2711
                     G_MARKUP_ERROR_PARSE,
2712
                     _("No <draw_ops> called \"%s\" has been defined"),
2713
                     name);
2714
          return;
2715
        }
2716
2717
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2718
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2719
      if (op_list == info->op_list ||
2720
          meta_draw_op_list_contains (op_list, info->op_list))
2721
        {
2722
          set_error (error, context, G_MARKUP_ERROR,
2723
                     G_MARKUP_ERROR_PARSE,
2724
                     _("Including draw_ops \"%s\" here would create a circular reference"),
2725
                     name);
2726
          return;
2727
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2728
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2729
      op = meta_draw_op_new (META_DRAW_OP_LIST);
2730
2731
      meta_draw_op_list_ref (op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2732
      op->data.op_list.op_list = op_list;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2733
2734
      op->data.op_list.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL);
2735
      op->data.op_list.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2736
      op->data.op_list.width = meta_draw_spec_new (info->theme,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2737
                                                   width ? width : "width",
2738
                                                   NULL);
2739
      op->data.op_list.height = meta_draw_spec_new (info->theme,
2740
                                                    height ? height : "height",
2741
                                                    NULL);
2742
2743
      meta_draw_op_list_append (info->op_list, op);
2744
2745
      push_state (info, STATE_INCLUDE);
2746
    }
2747
  else if (ELEMENT_IS ("tile"))
2748
    {
2749
      MetaDrawOp *op;
2750
      const char *name;
2751
      const char *x;
2752
      const char *y;
2753
      const char *width;
2754
      const char *height;
2755
      const char *tile_xoffset;
2756
      const char *tile_yoffset;
2757
      const char *tile_width;
2758
      const char *tile_height;
2759
      MetaDrawOpList *op_list;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2760
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2761
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2762
                              error,
2763
                              "x", &x, "y", &y,
2764
                              "width", &width, "height", &height,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2765
                              "!name", &name,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2766
                              "tile_xoffset", &tile_xoffset,
2767
                              "tile_yoffset", &tile_yoffset,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2768
                              "!tile_width", &tile_width,
2769
                              "!tile_height", &tile_height,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2770
                              NULL))
2771
        return;
2772
2773
      /* These default to 0 */
2774
#if 0
2775
      if (tile_xoffset && !check_expression (tile_xoffset, FALSE, info->theme, context, error))
2776
        return;
2777
2778
      if (tile_yoffset && !check_expression (tile_yoffset, FALSE, info->theme, context, error))
2779
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2780
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2781
      /* x/y/width/height default to 0,0,width,height - should
2782
       * probably do this for all the draw ops
2783
       */
2784
      if (x && !check_expression (x, FALSE, info->theme, context, error))
2785
        return;
2786
2787
      if (y && !check_expression (y, FALSE, info->theme, context, error))
2788
        return;
2789
2790
      if (width && !check_expression (width, FALSE, info->theme, context, error))
2791
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2792
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2793
      if (height && !check_expression (height, FALSE, info->theme, context, error))
2794
        return;
2795
2796
      if (!check_expression (tile_width, FALSE, info->theme, context, error))
2797
        return;
2798
2799
      if (!check_expression (tile_height, FALSE, info->theme, context, error))
2800
        return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2801
#endif
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2802
      op_list = meta_theme_lookup_draw_op_list (info->theme,
2803
                                                name);
2804
      if (op_list == NULL)
2805
        {
2806
          set_error (error, context, G_MARKUP_ERROR,
2807
                     G_MARKUP_ERROR_PARSE,
2808
                     _("No <draw_ops> called \"%s\" has been defined"),
2809
                     name);
2810
          return;
2811
        }
2812
2813
      g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2814
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2815
      if (op_list == info->op_list ||
2816
          meta_draw_op_list_contains (op_list, info->op_list))
2817
        {
2818
          set_error (error, context, G_MARKUP_ERROR,
2819
                     G_MARKUP_ERROR_PARSE,
2820
                     _("Including draw_ops \"%s\" here would create a circular reference"),
2821
                     name);
2822
          return;
2823
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2824
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2825
      op = meta_draw_op_new (META_DRAW_TILE);
2826
2827
      meta_draw_op_list_ref (op_list);
2828
2829
      op->data.tile.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL);
2830
      op->data.tile.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL);
2831
      op->data.tile.width = meta_draw_spec_new (info->theme,
2832
                                                width ? width : "width",
2833
                                                NULL);
2834
      op->data.tile.height = meta_draw_spec_new (info->theme,
2835
                                                 height ? height : "height",
2836
                                                 NULL);
2837
      op->data.tile.tile_xoffset = meta_draw_spec_new (info->theme,
2838
                                                       tile_xoffset ? tile_xoffset : "0",
2839
                                                       NULL);
2840
      op->data.tile.tile_yoffset = meta_draw_spec_new (info->theme,
2841
                                                       tile_yoffset ? tile_yoffset : "0",
2842
                                                       NULL);
2843
      op->data.tile.tile_width = meta_draw_spec_new (info->theme, tile_width, NULL);
2844
      op->data.tile.tile_height = meta_draw_spec_new (info->theme, tile_height, NULL);
2845
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2846
      op->data.tile.op_list = op_list;
2847
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2848
      meta_draw_op_list_append (info->op_list, op);
2849
2850
      push_state (info, STATE_TILE);
2851
    }
2852
  else
2853
    {
2854
      set_error (error, context,
2855
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2856
                 _("Element <%s> is not allowed below <%s>"),
2857
                 element_name, "draw_ops");
2858
    }
2859
}
2860
2861
static void
2862
parse_gradient_element (GMarkupParseContext  *context,
2863
                        const gchar          *element_name,
2864
                        const gchar         **attribute_names,
2865
                        const gchar         **attribute_values,
2866
                        ParseInfo            *info,
2867
                        GError              **error)
2868
{
2869
  g_return_if_fail (peek_state (info) == STATE_GRADIENT);
2870
2871
  if (ELEMENT_IS ("color"))
2872
    {
2873
      const char *value = NULL;
2874
      MetaColorSpec *color_spec;
2875
2876
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2877
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2878
                              "!value", &value,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2879
                              NULL))
2880
        return;
2881
2882
      color_spec = parse_color (info->theme, value, error);
2883
      if (color_spec == NULL)
2884
        {
2885
          add_context_to_error (error, context);
2886
          return;
2887
        }
2888
2889
      g_assert (info->op);
2890
      g_assert (info->op->type == META_DRAW_GRADIENT);
2891
      g_assert (info->op->data.gradient.gradient_spec != NULL);
2892
      info->op->data.gradient.gradient_spec->color_specs =
2893
        g_slist_append (info->op->data.gradient.gradient_spec->color_specs,
2894
                        color_spec);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2895
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2896
      push_state (info, STATE_COLOR);
2897
    }
2898
  else
2899
    {
2900
      set_error (error, context,
2901
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2902
                 _("Element <%s> is not allowed below <%s>"),
2903
                 element_name, "gradient");
2904
    }
2905
}
2906
2907
static void
2908
parse_style_element (GMarkupParseContext  *context,
2909
                     const gchar          *element_name,
2910
                     const gchar         **attribute_names,
2911
                     const gchar         **attribute_values,
2912
                     ParseInfo            *info,
2913
                     GError              **error)
2914
{
2915
  g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE);
2916
2917
  g_assert (info->style);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2918
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2919
  if (ELEMENT_IS ("piece"))
2920
    {
2921
      const char *position = NULL;
2922
      const char *draw_ops = NULL;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2923
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2924
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2925
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2926
                              "!position", &position,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2927
                              "draw_ops", &draw_ops,
2928
                              NULL))
2929
        return;
2930
2931
      info->piece = meta_frame_piece_from_string (position);
2932
      if (info->piece == META_FRAME_PIECE_LAST)
2933
        {
2934
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2935
                     _("Unknown position \"%s\" for frame piece"),
2936
                     position);
2937
          return;
2938
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2939
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2940
      if (info->style->pieces[info->piece] != NULL)
2941
        {
2942
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2943
                     _("Frame style already has a piece at position %s"),
2944
                     position);
2945
          return;
2946
        }
2947
2948
      g_assert (info->op_list == NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2949
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2950
      if (draw_ops)
2951
        {
2952
          MetaDrawOpList *op_list;
2953
2954
          op_list = meta_theme_lookup_draw_op_list (info->theme,
2955
                                                    draw_ops);
2956
2957
          if (op_list == NULL)
2958
            {
2959
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2960
                         _("No <draw_ops> with the name \"%s\" has been defined"),
2961
                         draw_ops);
2962
              return;
2963
            }
2964
2965
          meta_draw_op_list_ref (op_list);
2966
          info->op_list = op_list;
2967
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2968
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2969
      push_state (info, STATE_PIECE);
2970
    }
2971
  else if (ELEMENT_IS ("button"))
2972
    {
2973
      const char *function = NULL;
2974
      const char *state = NULL;
2975
      const char *draw_ops = NULL;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2976
      gint required_version;
2977
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2978
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2979
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
2980
                              "!function", &function,
2981
                              "!state", &state,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2982
                              "draw_ops", &draw_ops,
2983
                              NULL))
2984
        return;
2985
2986
      info->button_type = meta_button_type_from_string (function, info->theme);
2987
      if (info->button_type == META_BUTTON_TYPE_LAST)
2988
        {
2989
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2990
                     _("Unknown function \"%s\" for button"),
2991
                     function);
2992
          return;
2993
        }
2994
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2995
      required_version = peek_required_version (info);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2996
      if (meta_theme_earliest_version_with_button (info->button_type) >
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
2997
          (guint)required_version)
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
2998
        {
2999
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3000
                     _("Button function \"%s\" does not exist in this version (%d, need %d)"),
3001
                     function,
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3002
                     required_version,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3003
                     meta_theme_earliest_version_with_button (info->button_type)
3004
                     );
3005
          return;
3006
        }
3007
3008
      info->button_state = meta_button_state_from_string (state);
3009
      if (info->button_state == META_BUTTON_STATE_LAST)
3010
        {
3011
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3012
                     _("Unknown state \"%s\" for button"),
3013
                     state);
3014
          return;
3015
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3016
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3017
      if (info->style->buttons[info->button_type][info->button_state] != NULL)
3018
        {
3019
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3020
                     _("Frame style already has a button for function %s state %s"),
3021
                     function, state);
3022
          return;
3023
        }
3024
3025
      g_assert (info->op_list == NULL);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3026
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3027
      if (draw_ops)
3028
        {
3029
          MetaDrawOpList *op_list;
3030
3031
          op_list = meta_theme_lookup_draw_op_list (info->theme,
3032
                                                    draw_ops);
3033
3034
          if (op_list == NULL)
3035
            {
3036
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3037
                         _("No <draw_ops> with the name \"%s\" has been defined"),
3038
                         draw_ops);
3039
              return;
3040
            }
3041
3042
          meta_draw_op_list_ref (op_list);
3043
          info->op_list = op_list;
3044
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3045
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3046
      push_state (info, STATE_BUTTON);
3047
    }
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
3048
  else if (ELEMENT_IS ("shadow"))
3049
    {
3050
      const char *shadow_radius = NULL;
3051
      const char *shadow_opacity = NULL;
3052
      const char *shadow_color = NULL;
3053
      const char *shadow_x_offset = NULL;
3054
      const char *shadow_y_offset = NULL;
3055
      double shadow_radius_v, shadow_opacity_v;
3056
      int    shadow_x_offset_v, shadow_y_offset_v;
3057
      MetaColorSpec *shadow_color_v;
3058
3059
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
3060
                              error,
3061
                              "radius", &shadow_radius,
3062
                              "opacity", &shadow_opacity,
3063
                              "color", &shadow_color,
3064
                              "x_offset", &shadow_x_offset,
3065
                              "y_offset", &shadow_y_offset,
3066
                              NULL))
3067
        return;
3068
3069
      parse_double (shadow_radius, &shadow_radius_v, context, error);
3070
      parse_double (shadow_opacity, &shadow_opacity_v, context, error);
3071
      parse_positive_integer (shadow_x_offset, &shadow_x_offset_v, context, info->theme, error);
3072
      parse_positive_integer (shadow_y_offset, &shadow_y_offset_v, context, info->theme, error);
3073
      shadow_color_v = parse_color (info->theme, shadow_color, error);
3074
3075
      if (!info->style->shadow_properties)
3076
        info->style->shadow_properties = meta_shadow_properties_new ();
3077
3078
      info->style->shadow_properties->shadow_radius = shadow_radius_v;
3079
      info->style->shadow_properties->shadow_opacity = shadow_opacity_v;
3080
      info->style->shadow_properties->shadow_x_offset = shadow_x_offset_v;
3081
      info->style->shadow_properties->shadow_y_offset = shadow_y_offset_v;
3082
      info->style->shadow_properties->shadow_color = shadow_color_v;
3083
3084
      push_state (info, STATE_SHADOW);
3085
    }
3086
  else if (ELEMENT_IS ("padding"))
3087
    {
3088
      const char *left = NULL;
3089
      const char *bottom = NULL;
3090
      const char *right = NULL;
3091
      int        left_v, right_v, bottom_v;
3092
3093
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
3094
                              error,
3095
                              "left", &left,
3096
                              "right", &right,
3097
                              "bottom", &bottom,
3098
                              NULL))
3099
        return;
3100
3101
      parse_positive_integer (left, &left_v, context, info->theme, error);
3102
      parse_positive_integer (right, &right_v, context, info->theme, error);
3103
      parse_positive_integer (bottom, &bottom_v, context, info->theme, error);
3104
3105
      if (!info->style->invisible_grab_area_properties)
3106
        info->style->invisible_grab_area_properties = meta_invisible_grab_area_properties_new ();
3107
3108
      info->style->invisible_grab_area_properties->left = left_v;
3109
      info->style->invisible_grab_area_properties->right = right_v;
3110
      info->style->invisible_grab_area_properties->bottom = bottom_v;
3111
3112
      push_state (info, STATE_PADDING);
3113
    }
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3114
  else
3115
    {
3116
      set_error (error, context,
3117
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3118
                 _("Element <%s> is not allowed below <%s>"),
3119
                 element_name, "frame_style");
3120
    }
3121
}
3122
3123
static void
3124
parse_style_set_element (GMarkupParseContext  *context,
3125
                         const gchar          *element_name,
3126
                         const gchar         **attribute_names,
3127
                         const gchar         **attribute_values,
3128
                         ParseInfo            *info,
3129
                         GError              **error)
3130
{
3131
  g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE_SET);
3132
3133
  if (ELEMENT_IS ("frame"))
3134
    {
3135
      const char *focus = NULL;
3136
      const char *state = NULL;
3137
      const char *resize = NULL;
3138
      const char *style = NULL;
3139
      MetaFrameFocus frame_focus;
3140
      MetaFrameState frame_state;
3141
      MetaFrameResize frame_resize;
3142
      MetaFrameStyle *frame_style;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3143
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3144
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
3145
                              error,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
3146
                              "!focus", &focus,
3147
                              "!state", &state,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3148
                              "resize", &resize,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
3149
                              "!style", &style,
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3150
                              NULL))
3151
        return;
3152
3153
      frame_focus = meta_frame_focus_from_string (focus);
3154
      if (frame_focus == META_FRAME_FOCUS_LAST)
3155
        {
3156
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3157
                     _("\"%s\" is not a valid value for focus attribute"),
3158
                     focus);
3159
          return;
3160
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3161
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3162
      frame_state = meta_frame_state_from_string (state);
3163
      if (frame_state == META_FRAME_STATE_LAST)
3164
        {
3165
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3166
                     _("\"%s\" is not a valid value for state attribute"),
3167
                     focus);
3168
          return;
3169
        }
3170
3171
      frame_style = meta_theme_lookup_style (info->theme, style);
3172
3173
      if (frame_style == NULL)
3174
        {
3175
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3176
                     _("A style called \"%s\" has not been defined"),
3177
                     style);
3178
          return;
3179
        }
3180
3181
      switch (frame_state)
3182
        {
3183
        case META_FRAME_STATE_NORMAL:
3184
          if (resize == NULL)
3185
            {
3186
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1.2.47 by Pedro Fragoso
Import upstream version 2.25.5
3187
                         ATTRIBUTE_NOT_FOUND,
3188
                         "resize", element_name);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3189
              return;
3190
            }
3191
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3192
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3193
          frame_resize = meta_frame_resize_from_string (resize);
3194
          if (frame_resize == META_FRAME_RESIZE_LAST)
3195
            {
3196
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3197
                         _("\"%s\" is not a valid value for resize attribute"),
3198
                         focus);
3199
              return;
3200
            }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3201
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3202
          break;
3203
3204
        case META_FRAME_STATE_SHADED:
3205
          if (META_THEME_ALLOWS (info->theme, META_THEME_UNRESIZABLE_SHADED_STYLES))
3206
            {
3207
              if (resize == NULL)
3208
                /* In state="normal" we would complain here. But instead we accept
3209
                 * not having a resize attribute and default to resize="both", since
3210
                 * that most closely mimics what we did in v1, and thus people can
3211
                 * upgrade a theme to v2 without as much hassle.
3212
                 */
3213
                frame_resize = META_FRAME_RESIZE_BOTH;
3214
              else
3215
                {
3216
                  frame_resize = meta_frame_resize_from_string (resize);
3217
                  if (frame_resize == META_FRAME_RESIZE_LAST)
3218
                    {
3219
                      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3220
                                 _("\"%s\" is not a valid value for resize attribute"),
3221
                                 focus);
3222
                      return;
3223
                    }
3224
                }
3225
            }
3226
          else /* v1 theme */
3227
            {
3228
              if (resize != NULL)
3229
                {
3230
                  set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3231
                       _("Should not have \"resize\" attribute on <%s> element for maximized/shaded states"),
3232
                      element_name);
3233
                  return;
3234
                }
3235
3236
              /* resize="both" is equivalent to the old behaviour */
3237
              frame_resize = META_FRAME_RESIZE_BOTH;
3238
            }
3239
          break;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3240
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3241
        default:
3242
          if (resize != NULL)
3243
            {
3244
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3245
                         _("Should not have \"resize\" attribute on <%s> element for maximized states"),
3246
                         element_name);
3247
              return;
3248
            }
3249
3250
          frame_resize = META_FRAME_RESIZE_LAST;
3251
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3252
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3253
      switch (frame_state)
3254
        {
3255
        case META_FRAME_STATE_NORMAL:
3256
          if (info->style_set->normal_styles[frame_resize][frame_focus])
3257
            {
3258
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3259
                         _("Style has already been specified for state %s resize %s focus %s"),
3260
                         state, resize, focus);
3261
              return;
3262
            }
3263
          meta_frame_style_ref (frame_style);
3264
          info->style_set->normal_styles[frame_resize][frame_focus] = frame_style;
3265
          break;
3266
        case META_FRAME_STATE_MAXIMIZED:
3267
          if (info->style_set->maximized_styles[frame_focus])
3268
            {
3269
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3270
                         _("Style has already been specified for state %s focus %s"),
3271
                         state, focus);
3272
              return;
3273
            }
3274
          meta_frame_style_ref (frame_style);
3275
          info->style_set->maximized_styles[frame_focus] = frame_style;
3276
          break;
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
3277
        case META_FRAME_STATE_TILED_LEFT:
3278
          if (info->style_set->tiled_left_styles[frame_focus])
3279
            {
3280
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3281
                         _("Style has already been specified for state %s focus %s"),
3282
                         state, focus);
3283
              return;
3284
            }
3285
          meta_frame_style_ref (frame_style);
3286
          info->style_set->tiled_left_styles[frame_focus] = frame_style;
3287
          break;
3288
        case META_FRAME_STATE_TILED_RIGHT:
3289
          if (info->style_set->tiled_right_styles[frame_focus])
3290
            {
3291
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3292
                         _("Style has already been specified for state %s focus %s"),
3293
                         state, focus);
3294
              return;
3295
            }
3296
          meta_frame_style_ref (frame_style);
3297
          info->style_set->tiled_right_styles[frame_focus] = frame_style;
3298
          break;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3299
        case META_FRAME_STATE_SHADED:
3300
          if (info->style_set->shaded_styles[frame_resize][frame_focus])
3301
            {
3302
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3303
                         _("Style has already been specified for state %s resize %s focus %s"),
3304
                         state, resize, focus);
3305
              return;
3306
            }
3307
          meta_frame_style_ref (frame_style);
3308
          info->style_set->shaded_styles[frame_resize][frame_focus] = frame_style;
3309
          break;
3310
        case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
3311
          if (info->style_set->maximized_and_shaded_styles[frame_focus])
3312
            {
3313
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3314
                         _("Style has already been specified for state %s focus %s"),
3315
                         state, focus);
3316
              return;
3317
            }
3318
          meta_frame_style_ref (frame_style);
3319
          info->style_set->maximized_and_shaded_styles[frame_focus] = frame_style;
3320
          break;
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
3321
        case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
3322
          if (info->style_set->tiled_left_and_shaded_styles[frame_focus])
3323
            {
3324
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3325
                         _("Style has already been specified for state %s focus %s"),
3326
                         state, focus);
3327
              return;
3328
            }
3329
          meta_frame_style_ref (frame_style);
3330
          info->style_set->tiled_left_and_shaded_styles[frame_focus] = frame_style;
3331
          break;
3332
        case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
3333
          if (info->style_set->tiled_right_and_shaded_styles[frame_focus])
3334
            {
3335
              set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3336
                         _("Style has already been specified for state %s focus %s"),
3337
                         state, focus);
3338
              return;
3339
            }
3340
          meta_frame_style_ref (frame_style);
3341
          info->style_set->tiled_right_and_shaded_styles[frame_focus] = frame_style;
3342
          break;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3343
        case META_FRAME_STATE_LAST:
3344
          g_assert_not_reached ();
3345
          break;
3346
        }
3347
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3348
      push_state (info, STATE_FRAME);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3349
    }
3350
  else
3351
    {
3352
      set_error (error, context,
3353
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3354
                 _("Element <%s> is not allowed below <%s>"),
3355
                 element_name, "frame_style_set");
3356
    }
3357
}
3358
3359
static void
3360
parse_piece_element (GMarkupParseContext  *context,
3361
                     const gchar          *element_name,
3362
                     const gchar         **attribute_names,
3363
                     const gchar         **attribute_values,
3364
                     ParseInfo            *info,
3365
                     GError              **error)
3366
{
3367
  g_return_if_fail (peek_state (info) == STATE_PIECE);
3368
3369
  if (ELEMENT_IS ("draw_ops"))
3370
    {
3371
      if (info->op_list)
3372
        {
3373
          set_error (error, context,
3374
                     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3375
                     _("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)"));
3376
          return;
3377
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3378
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3379
      if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
3380
                                error))
3381
        return;
3382
3383
      g_assert (info->op_list == NULL);
3384
      info->op_list = meta_draw_op_list_new (2);
3385
3386
      push_state (info, STATE_DRAW_OPS);
3387
    }
3388
  else
3389
    {
3390
      set_error (error, context,
3391
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3392
                 _("Element <%s> is not allowed below <%s>"),
3393
                 element_name, "piece");
3394
    }
3395
}
3396
3397
static void
3398
parse_button_element (GMarkupParseContext  *context,
3399
                      const gchar          *element_name,
3400
                      const gchar         **attribute_names,
3401
                      const gchar         **attribute_values,
3402
                      ParseInfo            *info,
3403
                      GError              **error)
3404
{
3405
  g_return_if_fail (peek_state (info) == STATE_BUTTON);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3406
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3407
  if (ELEMENT_IS ("draw_ops"))
3408
    {
3409
      if (info->op_list)
3410
        {
3411
          set_error (error, context,
3412
                     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3413
                     _("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)"));
3414
          return;
3415
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3416
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3417
      if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
3418
                                error))
3419
        return;
3420
3421
      g_assert (info->op_list == NULL);
3422
      info->op_list = meta_draw_op_list_new (2);
3423
3424
      push_state (info, STATE_DRAW_OPS);
3425
    }
3426
  else
3427
    {
3428
      set_error (error, context,
3429
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3430
                 _("Element <%s> is not allowed below <%s>"),
3431
                 element_name, "button");
3432
    }
3433
}
3434
3435
static void
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
3436
parse_shadow_element (GMarkupParseContext  *context,
3437
                      const gchar          *element_name,
3438
                      const gchar         **attribute_names,
3439
                      const gchar         **attribute_values,
3440
                      ParseInfo            *info,
3441
                      GError              **error)
3442
{
3443
  g_return_if_fail (peek_state (info) == STATE_SHADOW);
3444
3445
  set_error (error, context,
3446
             G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3447
             _("Element <%s> is not allowed below <%s>"),
3448
             element_name, "shadow");
3449
}
3450
3451
static void
3452
parse_padding_element (GMarkupParseContext  *context,
3453
                      const gchar          *element_name,
3454
                      const gchar         **attribute_names,
3455
                      const gchar         **attribute_values,
3456
                      ParseInfo            *info,
3457
                      GError              **error)
3458
{
3459
  g_return_if_fail (peek_state (info) == STATE_PADDING);
3460
3461
  set_error (error, context,
3462
             G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3463
             _("Element <%s> is not allowed below <%s>"),
3464
             element_name, "padding");
3465
}
3466
3467
static void
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3468
parse_menu_icon_element (GMarkupParseContext  *context,
3469
                         const gchar          *element_name,
3470
                         const gchar         **attribute_names,
3471
                         const gchar         **attribute_values,
3472
                         ParseInfo            *info,
3473
                         GError              **error)
3474
{
3475
  g_return_if_fail (peek_state (info) == STATE_MENU_ICON);
3476
3477
  if (ELEMENT_IS ("draw_ops"))
3478
    {
3479
      if (info->op_list)
3480
        {
3481
          set_error (error, context,
3482
                     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3483
                     _("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)"));
3484
          return;
3485
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3486
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3487
      if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
3488
                                error))
3489
        return;
3490
3491
      g_assert (info->op_list == NULL);
3492
      info->op_list = meta_draw_op_list_new (2);
3493
3494
      push_state (info, STATE_DRAW_OPS);
3495
    }
3496
  else
3497
    {
3498
      set_error (error, context,
3499
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3500
                 _("Element <%s> is not allowed below <%s>"),
3501
                 element_name, "menu_icon");
3502
    }
3503
}
3504
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3505
static const char *
3506
find_version (const char **attribute_names,
3507
              const char **attribute_values)
3508
{
3509
  int i;
3510
3511
  for (i = 0; attribute_names[i]; i++)
3512
    {
3513
      if (strcmp (attribute_names[i], "version") == 0)
3514
        return attribute_values[i];
3515
    }
3516
3517
  return NULL;
3518
}
3519
3520
/* Returns whether the version element was successfully parsed.
3521
 * If successfully parsed, then two additional items are returned:
3522
 *
3523
 * satisfied:        whether this version of Mutter meets the version check
3524
 * minimum_required: minimum version of theme format required by version check
3525
 */
3526
static gboolean
3527
check_version (GMarkupParseContext *context,
3528
               const char          *version_str,
3529
               gboolean            *satisfied,
3530
               guint               *minimum_required,
3531
               GError             **error)
3532
{
3533
  static GRegex *version_regex;
3534
  GMatchInfo *info;
3535
  char *comparison_str, *major_str, *minor_str;
3536
  guint version;
3537
3538
  *minimum_required = 0;
3539
3540
  if (!version_regex)
3541
    version_regex = g_regex_new ("^\\s*([<>]=?)\\s*(\\d+)(\\.\\d+)?\\s*$", 0, 0, NULL);
3542
3543
  if (!g_regex_match (version_regex, version_str, 0, &info))
3544
    {
3545
      g_match_info_free (info);
3546
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3547
                 _("Bad version specification '%s'"), version_str);
3548
      return FALSE;
3549
    }
3550
3551
  comparison_str = g_match_info_fetch (info, 1);
3552
  major_str = g_match_info_fetch (info, 2);
3553
  minor_str = g_match_info_fetch (info, 3);
3554
3555
  version = 1000 * atoi (major_str);
3556
  /* might get NULL, see: https://bugzilla.gnome.org/review?bug=588217 */
3557
  if (minor_str && minor_str[0])
3558
    version += atoi (minor_str + 1);
3559
3560
  if (comparison_str[0] == '<')
3561
    {
3562
      if (comparison_str[1] == '=')
3563
        *satisfied = THEME_VERSION <= version;
3564
      else
3565
        *satisfied = THEME_VERSION < version;
3566
   }
3567
  else
3568
   {
3569
     if (comparison_str[1] == '=')
3570
       {
3571
         *satisfied = THEME_VERSION >= version;
3572
         *minimum_required = version;
3573
       }
3574
     else
3575
       {
3576
         *satisfied = THEME_VERSION > version;
3577
         *minimum_required = version + 1;
3578
       }
3579
   }
3580
3581
  g_free (comparison_str);
3582
  g_free (major_str);
3583
  g_free (minor_str);
3584
  g_match_info_free (info);
3585
3586
  return TRUE;
3587
}
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3588
3589
static void
3590
start_element_handler (GMarkupParseContext *context,
3591
                       const gchar         *element_name,
3592
                       const gchar        **attribute_names,
3593
                       const gchar        **attribute_values,
3594
                       gpointer             user_data,
3595
                       GError             **error)
3596
{
3597
  ParseInfo *info = user_data;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3598
  const char *version;
3599
  guint required_version = 0;
3600
3601
  if (info->skip_level > 0)
3602
    {
3603
      info->skip_level++;
3604
      return;
3605
    }
3606
3607
  required_version = peek_required_version (info);
3608
3609
  version = find_version (attribute_names, attribute_values);
3610
  if (version != NULL)
3611
    {
3612
      gboolean satisfied;
3613
      guint element_required;
3614
3615
      if (required_version < 3000)
3616
        {
3617
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3618
                     _("\"version\" attribute cannot be used in metacity-theme-1.xml or metacity-theme-2.xml"));
3619
          return;
3620
        }
3621
3622
      if (!check_version (context, version, &satisfied, &element_required, error))
3623
        return;
3624
3625
      /* Two different ways of handling an unsatisfied version check:
3626
       * for the toplevel element of a file, we throw an error back so
3627
       * that the controlling code can go ahead and look for an
3628
       * alternate metacity-theme-1.xml or metacity-theme-2.xml; for
3629
       * other elements we just silently skip the element and children.
3630
       */
3631
      if (peek_state (info) == STATE_START)
3632
        {
3633
          if (satisfied)
3634
            {
3635
              if (element_required > info->format_version)
3636
                info->format_version = element_required;
3637
            }
3638
          else
3639
            {
3640
              set_error (error, context, THEME_PARSE_ERROR, THEME_PARSE_ERROR_TOO_OLD,
3641
                         _("Theme requires version %s but latest supported theme version is %d.%d"),
3642
                         version, THEME_VERSION, THEME_MINOR_VERSION);
3643
              return;
3644
            }
3645
        }
3646
      else if (!satisfied)
3647
        {
3648
          info->skip_level = 1;
3649
          return;
3650
        }
3651
3652
      if (element_required > required_version)
3653
        required_version = element_required;
3654
    }
3655
3656
  push_required_version (info, required_version);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3657
3658
  switch (peek_state (info))
3659
    {
3660
    case STATE_START:
3661
      if (strcmp (element_name, "metacity_theme") == 0)
3662
        {
3663
          info->theme = meta_theme_new ();
3664
          info->theme->name = g_strdup (info->theme_name);
3665
          info->theme->filename = g_strdup (info->theme_file);
3666
          info->theme->dirname = g_strdup (info->theme_dir);
3667
          info->theme->format_version = info->format_version;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3668
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3669
          push_state (info, STATE_THEME);
3670
        }
3671
      else
3672
        set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3673
                   _("Outermost element in theme must be <metacity_theme> not <%s>"),
3674
                   element_name);
3675
      break;
3676
3677
    case STATE_THEME:
3678
      parse_toplevel_element (context, element_name,
3679
                              attribute_names, attribute_values,
3680
                              info, error);
3681
      break;
3682
    case STATE_INFO:
3683
      parse_info_element (context, element_name,
3684
                          attribute_names, attribute_values,
3685
                          info, error);
3686
      break;
3687
    case STATE_NAME:
3688
    case STATE_AUTHOR:
3689
    case STATE_COPYRIGHT:
3690
    case STATE_DATE:
3691
    case STATE_DESCRIPTION:
3692
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3693
                 _("Element <%s> is not allowed inside a name/author/date/description element"),
3694
                 element_name);
3695
      break;
3696
    case STATE_CONSTANT:
3697
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3698
                 _("Element <%s> is not allowed inside a <constant> element"),
3699
                 element_name);
3700
      break;
3701
    case STATE_FRAME_GEOMETRY:
3702
      parse_geometry_element (context, element_name,
3703
                              attribute_names, attribute_values,
3704
                              info, error);
3705
      break;
3706
    case STATE_DISTANCE:
3707
    case STATE_BORDER:
3708
    case STATE_ASPECT_RATIO:
3709
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3710
                 _("Element <%s> is not allowed inside a distance/border/aspect_ratio element"),
3711
                 element_name);
3712
      break;
3713
    case STATE_DRAW_OPS:
3714
      parse_draw_op_element (context, element_name,
3715
                             attribute_names, attribute_values,
3716
                             info, error);
3717
      break;
3718
    case STATE_LINE:
3719
    case STATE_RECTANGLE:
3720
    case STATE_ARC:
3721
    case STATE_CLIP:
3722
    case STATE_TINT:
3723
    case STATE_IMAGE:
3724
    case STATE_GTK_ARROW:
3725
    case STATE_GTK_BOX:
3726
    case STATE_GTK_VLINE:
3727
    case STATE_ICON:
3728
    case STATE_TITLE:
3729
    case STATE_INCLUDE:
3730
    case STATE_TILE:
3731
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3732
                 _("Element <%s> is not allowed inside a draw operation element"),
3733
                 element_name);
3734
      break;
3735
    case STATE_GRADIENT:
3736
      parse_gradient_element (context, element_name,
3737
                              attribute_names, attribute_values,
3738
                              info, error);
3739
      break;
3740
    case STATE_COLOR:
3741
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3742
                 _("Element <%s> is not allowed inside a <%s> element"),
3743
                 element_name, "color");
3744
      break;
3745
    case STATE_FRAME_STYLE:
3746
      parse_style_element (context, element_name,
3747
                           attribute_names, attribute_values,
3748
                           info, error);
3749
      break;
3750
    case STATE_PIECE:
3751
      parse_piece_element (context, element_name,
3752
                           attribute_names, attribute_values,
3753
                           info, error);
3754
      break;
3755
    case STATE_BUTTON:
3756
      parse_button_element (context, element_name,
3757
                            attribute_names, attribute_values,
3758
                            info, error);
3759
      break;
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
3760
    case STATE_SHADOW:
3761
       parse_shadow_element (context, element_name,
3762
                             attribute_names, attribute_values,
3763
                             info, error);
3764
       break;
3765
    case STATE_PADDING:
3766
       parse_padding_element (context, element_name,
3767
                              attribute_names, attribute_values,
3768
                              info, error);
3769
       break;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3770
    case STATE_MENU_ICON:
3771
      parse_menu_icon_element (context, element_name,
3772
                               attribute_names, attribute_values,
3773
                               info, error);
3774
      break;
3775
    case STATE_FRAME_STYLE_SET:
3776
      parse_style_set_element (context, element_name,
3777
                               attribute_names, attribute_values,
3778
                               info, error);
3779
      break;
3780
    case STATE_FRAME:
3781
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3782
                 _("Element <%s> is not allowed inside a <%s> element"),
3783
                 element_name, "frame");
3784
      break;
3785
    case STATE_WINDOW:
3786
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3787
                 _("Element <%s> is not allowed inside a <%s> element"),
3788
                 element_name, "window");
3789
      break;
3790
    case STATE_FALLBACK:
3791
      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
3792
                 _("Element <%s> is not allowed inside a <%s> element"),
3793
                 element_name, "fallback");
3794
      break;
3795
    }
3796
}
3797
3798
static void
3799
end_element_handler (GMarkupParseContext *context,
3800
                     const gchar         *element_name,
3801
                     gpointer             user_data,
3802
                     GError             **error)
3803
{
3804
  ParseInfo *info = user_data;
3805
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3806
  if (info->skip_level > 0)
3807
    {
3808
      info->skip_level--;
3809
      return;
3810
    }
3811
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3812
  switch (peek_state (info))
3813
    {
3814
    case STATE_START:
3815
      break;
3816
    case STATE_THEME:
3817
      g_assert (info->theme);
3818
3819
      if (!meta_theme_validate (info->theme, error))
3820
        {
3821
          add_context_to_error (error, context);
3822
          meta_theme_free (info->theme);
3823
          info->theme = NULL;
3824
        }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3825
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3826
      pop_state (info);
3827
      g_assert (peek_state (info) == STATE_START);
3828
      break;
3829
    case STATE_INFO:
3830
      pop_state (info);
3831
      g_assert (peek_state (info) == STATE_THEME);
3832
      break;
3833
    case STATE_NAME:
3834
      pop_state (info);
3835
      g_assert (peek_state (info) == STATE_INFO);
3836
      break;
3837
    case STATE_AUTHOR:
3838
      pop_state (info);
3839
      g_assert (peek_state (info) == STATE_INFO);
3840
      break;
3841
    case STATE_COPYRIGHT:
3842
      pop_state (info);
3843
      g_assert (peek_state (info) == STATE_INFO);
3844
      break;
3845
    case STATE_DATE:
3846
      pop_state (info);
3847
      g_assert (peek_state (info) == STATE_INFO);
3848
      break;
3849
    case STATE_DESCRIPTION:
3850
      pop_state (info);
3851
      g_assert (peek_state (info) == STATE_INFO);
3852
      break;
3853
    case STATE_CONSTANT:
3854
      pop_state (info);
3855
      g_assert (peek_state (info) == STATE_THEME);
3856
      break;
3857
    case STATE_FRAME_GEOMETRY:
3858
      g_assert (info->layout);
3859
3860
      if (!meta_frame_layout_validate (info->layout,
3861
                                       error))
3862
        {
3863
          add_context_to_error (error, context);
3864
        }
3865
3866
      /* layout will already be stored in the theme under
3867
       * its name
3868
       */
3869
      meta_frame_layout_unref (info->layout);
3870
      info->layout = NULL;
3871
      pop_state (info);
3872
      g_assert (peek_state (info) == STATE_THEME);
3873
      break;
3874
    case STATE_DISTANCE:
3875
      pop_state (info);
3876
      g_assert (peek_state (info) == STATE_FRAME_GEOMETRY);
3877
      break;
3878
    case STATE_BORDER:
3879
      pop_state (info);
3880
      g_assert (peek_state (info) == STATE_FRAME_GEOMETRY);
3881
      break;
3882
    case STATE_ASPECT_RATIO:
3883
      pop_state (info);
3884
      g_assert (peek_state (info) == STATE_FRAME_GEOMETRY);
3885
      break;
3886
    case STATE_DRAW_OPS:
3887
      {
3888
        g_assert (info->op_list);
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
3889
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
3890
        if (!meta_draw_op_list_validate (info->op_list,
3891
                                         error))
3892
          {
3893
            add_context_to_error (error, context);
3894
            meta_draw_op_list_unref (info->op_list);
3895
            info->op_list = NULL;
3896
          }
3897
3898
        pop_state (info);
3899
3900
        switch (peek_state (info))
3901
          {
3902
          case STATE_BUTTON:
3903
          case STATE_PIECE:
3904
          case STATE_MENU_ICON:
3905
            /* Leave info->op_list to be picked up
3906
             * when these elements are closed
3907
             */
3908
            g_assert (info->op_list);
3909
            break;
3910
          case STATE_THEME:
3911
            g_assert (info->op_list);
3912
            meta_draw_op_list_unref (info->op_list);
3913
            info->op_list = NULL;
3914
            break;
3915
          default:
3916
            /* Op list can't occur in other contexts */
3917
            g_assert_not_reached ();
3918
            break;
3919
          }
3920
      }
3921
      break;
3922
    case STATE_LINE:
3923
      pop_state (info);
3924
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3925
      break;
3926
    case STATE_RECTANGLE:
3927
      pop_state (info);
3928
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3929
      break;
3930
    case STATE_ARC:
3931
      pop_state (info);
3932
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3933
      break;
3934
    case STATE_CLIP:
3935
      pop_state (info);
3936
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3937
      break;
3938
    case STATE_TINT:
3939
      pop_state (info);
3940
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3941
      break;
3942
    case STATE_GRADIENT:
3943
      g_assert (info->op);
3944
      g_assert (info->op->type == META_DRAW_GRADIENT);
3945
      if (!meta_gradient_spec_validate (info->op->data.gradient.gradient_spec,
3946
                                        error))
3947
        {
3948
          add_context_to_error (error, context);
3949
          meta_draw_op_free (info->op);
3950
          info->op = NULL;
3951
        }
3952
      else
3953
        {
3954
          g_assert (info->op_list);
3955
          meta_draw_op_list_append (info->op_list, info->op);
3956
          info->op = NULL;
3957
        }
3958
      pop_state (info);
3959
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3960
      break;
3961
    case STATE_IMAGE:
3962
      pop_state (info);
3963
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3964
      break;
3965
    case STATE_GTK_ARROW:
3966
      pop_state (info);
3967
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3968
      break;
3969
    case STATE_GTK_BOX:
3970
      pop_state (info);
3971
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3972
      break;
3973
    case STATE_GTK_VLINE:
3974
      pop_state (info);
3975
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3976
      break;
3977
    case STATE_ICON:
3978
      pop_state (info);
3979
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3980
      break;
3981
    case STATE_TITLE:
3982
      pop_state (info);
3983
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3984
      break;
3985
    case STATE_INCLUDE:
3986
      pop_state (info);
3987
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3988
      break;
3989
    case STATE_TILE:
3990
      pop_state (info);
3991
      g_assert (peek_state (info) == STATE_DRAW_OPS);
3992
      break;
3993
    case STATE_COLOR:
3994
      pop_state (info);
3995
      g_assert (peek_state (info) == STATE_GRADIENT);
3996
      break;
3997
    case STATE_FRAME_STYLE:
3998
      g_assert (info->style);
3999
4000
      if (!meta_frame_style_validate (info->style,
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4001
                                      peek_required_version (info),
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4002
                                      error))
4003
        {
4004
          add_context_to_error (error, context);
4005
        }
4006
4007
      /* Frame style is in the theme hash table and a ref
4008
       * is held there
4009
       */
4010
      meta_frame_style_unref (info->style);
4011
      info->style = NULL;
4012
      pop_state (info);
4013
      g_assert (peek_state (info) == STATE_THEME);
4014
      break;
4015
    case STATE_PIECE:
4016
      g_assert (info->style);
4017
      if (info->op_list == NULL)
4018
        {
4019
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
4020
                     _("No draw_ops provided for frame piece"));
4021
        }
4022
      else
4023
        {
4024
          info->style->pieces[info->piece] = info->op_list;
4025
          info->op_list = NULL;
4026
        }
4027
      pop_state (info);
4028
      g_assert (peek_state (info) == STATE_FRAME_STYLE);
4029
      break;
4030
    case STATE_BUTTON:
4031
      g_assert (info->style);
4032
      if (info->op_list == NULL)
4033
        {
4034
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
4035
                     _("No draw_ops provided for button"));
4036
        }
4037
      else
4038
        {
4039
          info->style->buttons[info->button_type][info->button_state] =
4040
            info->op_list;
4041
          info->op_list = NULL;
4042
        }
4043
      pop_state (info);
4044
      break;
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
4045
    case STATE_SHADOW:
4046
      g_assert (info->style);
4047
      pop_state (info);
4048
      break;
4049
    case STATE_PADDING:
4050
      g_assert (info->style);
4051
      pop_state (info);
4052
      break;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4053
    case STATE_MENU_ICON:
4054
      g_assert (info->theme);
4055
      if (info->op_list != NULL)
4056
        {
4057
          meta_draw_op_list_unref (info->op_list);
4058
          info->op_list = NULL;
4059
        }
4060
      pop_state (info);
4061
      g_assert (peek_state (info) == STATE_THEME);
4062
      break;
4063
    case STATE_FRAME_STYLE_SET:
4064
      g_assert (info->style_set);
4065
4066
      if (!meta_frame_style_set_validate (info->style_set,
4067
                                          error))
4068
        {
4069
          add_context_to_error (error, context);
4070
        }
4071
4072
      /* Style set is in the theme hash table and a reference
4073
       * is held there.
4074
       */
4075
      meta_frame_style_set_unref (info->style_set);
4076
      info->style_set = NULL;
4077
      pop_state (info);
4078
      g_assert (peek_state (info) == STATE_THEME);
4079
      break;
4080
    case STATE_FRAME:
4081
      pop_state (info);
4082
      g_assert (peek_state (info) == STATE_FRAME_STYLE_SET);
4083
      break;
4084
    case STATE_WINDOW:
4085
      pop_state (info);
4086
      g_assert (peek_state (info) == STATE_THEME);
4087
      break;
4088
    case STATE_FALLBACK:
4089
      pop_state (info);
4090
      g_assert (peek_state (info) == STATE_THEME);
4091
      break;
4092
    }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4093
4094
  pop_required_version (info);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4095
}
4096
4097
#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)
4098
4099
static gboolean
4100
all_whitespace (const char *text,
4101
                int         text_len)
4102
{
4103
  const char *p;
4104
  const char *end;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4105
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4106
  p = text;
4107
  end = text + text_len;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4108
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4109
  while (p != end)
4110
    {
4111
      if (!g_ascii_isspace (*p))
4112
        return FALSE;
4113
4114
      p = g_utf8_next_char (p);
4115
    }
4116
4117
  return TRUE;
4118
}
4119
4120
static void
4121
text_handler (GMarkupParseContext *context,
4122
              const gchar         *text,
4123
              gsize                text_len,
4124
              gpointer             user_data,
4125
              GError             **error)
4126
{
4127
  ParseInfo *info = user_data;
4128
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4129
  if (info->skip_level > 0)
4130
    return;
4131
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4132
  if (all_whitespace (text, text_len))
4133
    return;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4134
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4135
  /* FIXME http://bugzilla.gnome.org/show_bug.cgi?id=70448 would
4136
   * allow a nice cleanup here.
4137
   */
4138
4139
  switch (peek_state (info))
4140
    {
4141
    case STATE_START:
4142
      g_assert_not_reached (); /* gmarkup shouldn't do this */
4143
      break;
4144
    case STATE_THEME:
4145
      NO_TEXT ("metacity_theme");
4146
      break;
4147
    case STATE_INFO:
4148
      NO_TEXT ("info");
4149
      break;
4150
    case STATE_NAME:
4151
      if (info->theme->readable_name != NULL)
4152
        {
4153
          set_error (error, context, G_MARKUP_ERROR,
4154
                     G_MARKUP_ERROR_PARSE,
1.2.54 by Robert Ancell
Import upstream version 2.27.0
4155
                     _("<%s> specified twice for this theme"),
4156
                     "name");
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4157
          return;
4158
        }
4159
4160
      info->theme->readable_name = g_strndup (text, text_len);
4161
      break;
4162
    case STATE_AUTHOR:
4163
      if (info->theme->author != NULL)
4164
        {
4165
          set_error (error, context, G_MARKUP_ERROR,
4166
                     G_MARKUP_ERROR_PARSE,
1.2.54 by Robert Ancell
Import upstream version 2.27.0
4167
                     _("<%s> specified twice for this theme"),
4168
                     "author");
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4169
          return;
4170
        }
4171
4172
      info->theme->author = g_strndup (text, text_len);
4173
      break;
4174
    case STATE_COPYRIGHT:
4175
      if (info->theme->copyright != NULL)
4176
        {
4177
          set_error (error, context, G_MARKUP_ERROR,
4178
                     G_MARKUP_ERROR_PARSE,
1.2.54 by Robert Ancell
Import upstream version 2.27.0
4179
                     _("<%s> specified twice for this theme"),
4180
                     "copyright");
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4181
          return;
4182
        }
4183
4184
      info->theme->copyright = g_strndup (text, text_len);
4185
      break;
4186
    case STATE_DATE:
4187
      if (info->theme->date != NULL)
4188
        {
4189
          set_error (error, context, G_MARKUP_ERROR,
4190
                     G_MARKUP_ERROR_PARSE,
1.2.54 by Robert Ancell
Import upstream version 2.27.0
4191
                     _("<%s> specified twice for this theme"),
4192
                     "date");
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4193
          return;
4194
        }
4195
4196
      info->theme->date = g_strndup (text, text_len);
4197
      break;
4198
    case STATE_DESCRIPTION:
4199
      if (info->theme->description != NULL)
4200
        {
4201
          set_error (error, context, G_MARKUP_ERROR,
4202
                     G_MARKUP_ERROR_PARSE,
1.2.54 by Robert Ancell
Import upstream version 2.27.0
4203
                     _("<%s> specified twice for this theme"),
4204
                     "description");
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4205
          return;
4206
        }
4207
4208
      info->theme->description = g_strndup (text, text_len);
4209
      break;
4210
    case STATE_CONSTANT:
4211
      NO_TEXT ("constant");
4212
      break;
4213
    case STATE_FRAME_GEOMETRY:
4214
      NO_TEXT ("frame_geometry");
4215
      break;
4216
    case STATE_DISTANCE:
4217
      NO_TEXT ("distance");
4218
      break;
4219
    case STATE_BORDER:
4220
      NO_TEXT ("border");
4221
      break;
4222
    case STATE_ASPECT_RATIO:
4223
      NO_TEXT ("aspect_ratio");
4224
      break;
4225
    case STATE_DRAW_OPS:
4226
      NO_TEXT ("draw_ops");
4227
      break;
4228
    case STATE_LINE:
4229
      NO_TEXT ("line");
4230
      break;
4231
    case STATE_RECTANGLE:
4232
      NO_TEXT ("rectangle");
4233
      break;
4234
    case STATE_ARC:
4235
      NO_TEXT ("arc");
4236
      break;
4237
    case STATE_CLIP:
4238
      NO_TEXT ("clip");
4239
      break;
4240
    case STATE_TINT:
4241
      NO_TEXT ("tint");
4242
      break;
4243
    case STATE_GRADIENT:
4244
      NO_TEXT ("gradient");
4245
      break;
4246
    case STATE_IMAGE:
4247
      NO_TEXT ("image");
4248
      break;
4249
    case STATE_GTK_ARROW:
4250
      NO_TEXT ("gtk_arrow");
4251
      break;
4252
    case STATE_GTK_BOX:
4253
      NO_TEXT ("gtk_box");
4254
      break;
4255
    case STATE_GTK_VLINE:
4256
      NO_TEXT ("gtk_vline");
4257
      break;
4258
    case STATE_ICON:
4259
      NO_TEXT ("icon");
4260
      break;
4261
    case STATE_TITLE:
4262
      NO_TEXT ("title");
4263
      break;
4264
    case STATE_INCLUDE:
4265
      NO_TEXT ("include");
4266
      break;
4267
    case STATE_TILE:
4268
      NO_TEXT ("tile");
4269
      break;
4270
    case STATE_COLOR:
4271
      NO_TEXT ("color");
4272
      break;
4273
    case STATE_FRAME_STYLE:
4274
      NO_TEXT ("frame_style");
4275
      break;
4276
    case STATE_PIECE:
4277
      NO_TEXT ("piece");
4278
      break;
4279
    case STATE_BUTTON:
4280
      NO_TEXT ("button");
4281
      break;
1.2.68 by Dmitry Shachnev
Import upstream version 3.12.0
4282
    case STATE_SHADOW:
4283
      NO_TEXT ("shadow");
4284
      break;
4285
    case STATE_PADDING:
4286
      NO_TEXT ("padding");
4287
      break;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4288
    case STATE_MENU_ICON:
4289
      NO_TEXT ("menu_icon");
4290
      break;
4291
    case STATE_FRAME_STYLE_SET:
4292
      NO_TEXT ("frame_style_set");
4293
      break;
4294
    case STATE_FRAME:
4295
      NO_TEXT ("frame");
4296
      break;
4297
    case STATE_WINDOW:
4298
      NO_TEXT ("window");
4299
      break;
4300
    case STATE_FALLBACK:
4301
      NO_TEXT ("fallback");
4302
      break;
4303
    }
4304
}
4305
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4306
/* If the theme is not-corrupt, keep looking for alternate versions
4307
 * in other locations we might be compatible with
4308
 */
4309
static gboolean
4310
theme_error_is_fatal (GError *error)
4311
{
4312
  return !(error->domain == G_FILE_ERROR ||
4313
          (error->domain == THEME_PARSE_ERROR &&
4314
           error->code == THEME_PARSE_ERROR_TOO_OLD));
4315
}
4316
4317
static MetaTheme *
4318
load_theme (const char *theme_dir,
4319
            const char *theme_name,
4320
            guint       major_version,
4321
            GError    **error)
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4322
{
4323
  GMarkupParseContext *context;
4324
  ParseInfo info;
4325
  char *text;
4326
  gsize length;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4327
  char *theme_filename;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4328
  char *theme_file;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4329
  MetaTheme *retval;
4330
4331
  g_return_val_if_fail (error && *error == NULL, NULL);
4332
4333
  text = NULL;
4334
  retval = NULL;
4335
  context = NULL;
4336
4337
  theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT, major_version);
4338
  theme_file = g_build_filename (theme_dir, theme_filename, NULL);
4339
4340
  if (!g_file_get_contents (theme_file, &text, &length, error))
4341
    goto out;
4342
4343
  meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file);
4344
4345
  parse_info_init (&info);
4346
4347
  info.theme_name = theme_name;
4348
  info.theme_file = theme_file;
4349
  info.theme_dir = theme_dir;
4350
4351
  info.format_version = 1000 * major_version;
4352
4353
  context = g_markup_parse_context_new (&metacity_theme_parser, 0, &info, NULL);
4354
4355
  if (!g_markup_parse_context_parse (context, text, length, error))
4356
    goto out;
4357
4358
  if (!g_markup_parse_context_end_parse (context, error))
4359
    goto out;
4360
4361
  retval = info.theme;
4362
  info.theme = NULL;
4363
4364
 out:
4365
  if (*error && !theme_error_is_fatal (*error))
4366
    meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
4367
                theme_file, (*error)->message);
4368
4369
  g_free (theme_filename);
4370
  g_free (theme_file);
4371
  g_free (text);
4372
4373
  if (context)
4374
    {
4375
      g_markup_parse_context_free (context);
4376
      parse_info_free (&info);
4377
    }
4378
4379
  return retval;
4380
}
4381
4382
static gboolean
4383
keep_trying (GError **error)
4384
{
4385
  if (*error && !theme_error_is_fatal (*error))
4386
    {
4387
      g_clear_error (error);
4388
      return TRUE;
4389
    }
4390
4391
  return FALSE;
4392
}
4393
4394
MetaTheme*
4395
meta_theme_load (const char  *theme_name,
4396
                 GError     **err)
4397
{
4398
  GError *error = NULL;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4399
  char *theme_dir;
4400
  MetaTheme *retval;
4401
  const gchar* const* xdg_data_dirs;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4402
  int major_version;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4403
  int i;
4404
4405
  retval = NULL;
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4406
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4407
  if (meta_is_debugging ())
4408
    {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4409
      /* We try all supported major versions from current to oldest */
4410
      for (major_version = THEME_MAJOR_VERSION; (major_version > 0); major_version--)
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4411
        {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4412
          theme_dir = g_build_filename ("./themes", theme_name, NULL);
4413
          retval = load_theme (theme_dir, theme_name, major_version, &error);
4414
4415
          if (!keep_trying (&error))
4416
            goto out;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4417
        }
4418
    }
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4419
4420
  /* We try all supported major versions from current to oldest */
4421
  for (major_version = THEME_MAJOR_VERSION; (major_version > 0); major_version--)
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4422
    {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4423
      /* We try first in XDG_USER_DATA_DIR, XDG_DATA_DIRS, then system dir for themes */
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4424
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4425
      /* Try XDG_USER_DATA_DIR first */
4426
      theme_dir = g_build_filename (g_get_user_data_dir(),
4427
                                    "themes",
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4428
                                    theme_name,
4429
                                    THEME_SUBDIR,
4430
                                    NULL);
4431
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4432
      retval = load_theme (theme_dir, theme_name, major_version, &error);
4433
      g_free (theme_dir);
4434
      if (!keep_trying (&error))
4435
        goto out;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4436
4437
      /* Try each XDG_DATA_DIRS for theme */
4438
      xdg_data_dirs = g_get_system_data_dirs();
4439
      for(i = 0; xdg_data_dirs[i] != NULL; i++)
4440
        {
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4441
          theme_dir = g_build_filename (xdg_data_dirs[i],
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4442
                                        "themes",
4443
                                        theme_name,
4444
                                        THEME_SUBDIR,
4445
                                        NULL);
4446
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4447
          retval = load_theme (theme_dir, theme_name, major_version, &error);
4448
          g_free (theme_dir);
4449
          if (!keep_trying (&error))
4450
            goto out;
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4451
        }
4452
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4453
      /* Look for themes in METACITY_DATADIR */
4454
      theme_dir = g_build_filename (METACITY_DATADIR,
4455
                                    "themes",
4456
                                    theme_name,
4457
                                    THEME_SUBDIR,
4458
                                    NULL);
4459
      retval = load_theme (theme_dir, theme_name, major_version, &error);
4460
      g_free (theme_dir);
4461
      if (!keep_trying (&error))
4462
        goto out;
4463
    }
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4464
4465
 out:
4466
1.2.69 by Dmitry Shachnev
Import upstream version 3.14.0
4467
  if (!error && !retval)
4468
    g_set_error (&error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
4469
                 _("Failed to find a valid file for theme %s\n"),
4470
                 theme_name);
1.2.37 by Pedro Fragoso
Import upstream version 2.21.8
4471
4472
  if (error)
4473
    {
4474
      g_propagate_error (err, error);
4475
    }
4476
4477
  return retval;
4478
}