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

« back to all changes in this revision

Viewing changes to src/ui/theme-parser.c

  • Committer: Package Import Robot
  • Author(s): Dmitry Shachnev
  • Date: 2014-11-18 18:13:01 UTC
  • mfrom: (1.4.1) (2.5.4 sid)
  • mto: This revision was merged to the branch mainline in revision 135.
  • Revision ID: package-import@ubuntu.com-20141118181301-cgqtucqg732irm9x
* Merge with Debian unstable, remaining changes:
  - 05_raise_on_click_for_click_mode.patch:
    Force raise on click option.
  - 22_fix_above_tab_switching.patch:
    For Above_Tab, don't compare keysym (fixes group switching).
  - debian/metacity-common.links:
    Show keybindings in Unity control center.
  - Use Ubuntu Desktop team Vcs fields.
* Drop all other patches, they were needed only for Unity 2D.
* New upstream bugfix release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <string.h>
26
26
#include <stdlib.h>
27
27
 
 
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
 
28
44
typedef enum
29
45
{
30
46
  STATE_START,
79
95
 
80
96
typedef struct
81
97
{
 
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. */
82
101
  GSList *states;
 
102
  GSList *required_versions;
83
103
 
84
104
  const char *theme_name;       /* name of theme (directory it's in) */
85
 
  char *theme_file;             /* theme filename */
86
 
  char *theme_dir;              /* dir the theme is inside */
 
105
  const char *theme_file;       /* theme filename */
 
106
  const char *theme_dir;        /* dir the theme is inside */
87
107
  MetaTheme *theme;             /* theme being parsed */
88
 
  guint format_version;         /* version of format of theme file */  
 
108
  guint format_version;         /* version of format of theme file */
89
109
  char *name;                   /* name of named thing being parsed */
90
110
  MetaFrameLayout *layout;      /* layout being parsed if any */
91
111
  MetaDrawOpList *op_list;      /* op list being parsed if any */
95
115
  MetaFramePiece piece;         /* position of piece being parsed */
96
116
  MetaButtonType button_type;   /* type of button/menuitem being parsed */
97
117
  MetaButtonState button_state; /* state of button being parsed */
 
118
  int skip_level;               /* depth of elements that we're ignoring */
98
119
} ParseInfo;
99
120
 
 
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
 
100
134
static void set_error (GError             **err,
101
135
                       GMarkupParseContext *context,
102
136
                       int                  error_domain,
234
268
  int line, ch;
235
269
  va_list args;
236
270
  char *str;
237
 
  
 
271
 
238
272
  g_markup_parse_context_get_position (context, &line, &ch);
239
273
 
240
274
  va_start (args, format);
271
305
{
272
306
  info->theme_file = NULL;
273
307
  info->states = g_slist_prepend (NULL, GINT_TO_POINTER (STATE_START));
 
308
  info->required_versions = NULL;
274
309
  info->theme = NULL;
275
310
  info->name = NULL;
276
311
  info->layout = NULL;
281
316
  info->piece = META_FRAME_PIECE_LAST;
282
317
  info->button_type = META_BUTTON_TYPE_LAST;
283
318
  info->button_state = META_BUTTON_STATE_LAST;
 
319
  info->skip_level = 0;
284
320
}
285
321
 
286
322
static void
287
323
parse_info_free (ParseInfo *info)
288
324
{
289
 
  g_free (info->theme_file);
290
 
  g_free (info->theme_dir);
291
 
 
292
325
  g_slist_free (info->states);
293
 
  
 
326
  g_slist_free (info->required_versions);
 
327
 
294
328
  if (info->theme)
295
329
    meta_theme_free (info->theme);
296
330
 
302
336
 
303
337
  if (info->op)
304
338
    meta_draw_op_free (info->op);
305
 
  
 
339
 
306
340
  if (info->style)
307
341
    meta_frame_style_unref (info->style);
308
342
 
321
355
pop_state (ParseInfo *info)
322
356
{
323
357
  g_return_if_fail (info->states != NULL);
324
 
  
 
358
 
325
359
  info->states = g_slist_remove (info->states, info->states->data);
326
360
}
327
361
 
333
367
  return GPOINTER_TO_INT (info->states->data);
334
368
}
335
369
 
 
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
 
336
395
#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
337
396
 
338
397
typedef struct
377
436
  if (attrs[0].required)
378
437
    attrs[0].name++; /* skip past it */
379
438
  *first_attribute_retloc = NULL;
380
 
  
 
439
 
381
440
  va_start (args, first_attribute_retloc);
382
441
 
383
442
  name = va_arg (args, const char*);
385
444
 
386
445
  while (name != NULL)
387
446
    {
388
 
      g_return_val_if_fail (retloc != NULL, FALSE);
 
447
      if (retloc == NULL)
 
448
        {
 
449
          retval = FALSE;
 
450
          goto out;
 
451
        }
389
452
 
390
453
      g_assert (n_attrs < MAX_ATTRS);
391
 
      
 
454
 
392
455
      attrs[n_attrs].name = name;
393
456
      attrs[n_attrs].retloc = retloc;
394
457
      attrs[n_attrs].required = attrs[n_attrs].name[0]=='!';
396
459
        attrs[n_attrs].name++; /* skip past it */
397
460
 
398
461
      n_attrs += 1;
399
 
      *retloc = NULL;      
 
462
      *retloc = NULL;
400
463
 
401
464
      name = va_arg (args, const char*);
402
465
      retloc = va_arg (args, const char**);
410
473
      int j;
411
474
      gboolean found;
412
475
 
 
476
      /* Can be present anywhere */
 
477
      if (strcmp (attribute_names[i], "version") == 0)
 
478
        {
 
479
          ++i;
 
480
          continue;
 
481
        }
 
482
 
413
483
      found = FALSE;
414
484
      j = 0;
415
485
      while (j < n_attrs)
420
490
 
421
491
              if (*retloc != NULL)
422
492
                {
423
 
                
 
493
 
424
494
                  set_error (error, context,
425
495
                             G_MARKUP_ERROR,
426
496
                             G_MARKUP_ERROR_PARSE,
444
514
        {
445
515
          g_warning ("It could have been %s.\n", attrs[j++].name);
446
516
        }
447
 
                  
 
517
 
448
518
          set_error (error, context,
449
519
                     G_MARKUP_ERROR,
450
520
                     G_MARKUP_ERROR_PARSE,
486
556
                     const char **attribute_values,
487
557
                     GError     **error)
488
558
{
489
 
  if (attribute_names[0] != NULL)
 
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)
490
566
    {
491
567
      set_error (error, context,
492
568
                 G_MARKUP_ERROR,
512
588
  int j;
513
589
 
514
590
  *val = 0;
515
 
  
 
591
 
516
592
  end = NULL;
517
 
  
 
593
 
518
594
  /* Is str a constant? */
519
595
 
520
596
  if (META_THEME_ALLOWS (theme, META_THEME_UBIQUITOUS_CONSTANTS) &&
564
640
                 l, MAX_REASONABLE);
565
641
      return FALSE;
566
642
    }
567
 
  
 
643
 
568
644
  *val = (int) l;
569
645
 
570
646
  return TRUE;
579
655
  char *end;
580
656
 
581
657
  *val = 0;
582
 
  
 
658
 
583
659
  end = NULL;
584
 
  
 
660
 
585
661
  *val = g_ascii_strtod (str, &end);
586
662
 
587
663
  if (end == NULL || end == str)
623
699
                 str);
624
700
      return FALSE;
625
701
    }
626
 
  
 
702
 
627
703
  return TRUE;
628
704
}
629
705
 
651
727
                      str);
652
728
           return FALSE;
653
729
         }
654
 
   
 
730
 
655
731
      result = parse_positive_integer (str, &tmp, context, theme, error);
656
732
 
657
733
      *val = tmp;
658
734
 
659
 
      return result;    
 
735
      return result;
660
736
    }
661
 
  
 
737
 
662
738
  return TRUE;
663
739
}
664
740
 
694
770
  MetaAlphaGradientSpec *spec;
695
771
 
696
772
  *spec_ret = NULL;
697
 
  
 
773
 
698
774
  split = g_strsplit (str, ":", -1);
699
775
 
700
776
  i = 0;
708
784
                 str);
709
785
 
710
786
      g_strfreev (split);
711
 
      
 
787
 
712
788
      return FALSE;
713
789
    }
714
790
 
724
800
  while (i < n_alphas)
725
801
    {
726
802
      double v;
727
 
      
 
803
 
728
804
      if (!parse_double (split[i], &v, context, error))
729
805
        {
730
806
          /* clear up, but don't set error: it was set by parse_double */
731
807
          g_strfreev (split);
732
808
          meta_alpha_gradient_spec_free (spec);
733
 
          
 
809
 
734
810
          return FALSE;
735
811
        }
736
812
 
741
817
                     v);
742
818
 
743
819
          g_strfreev (split);
744
 
          meta_alpha_gradient_spec_free (spec);          
745
 
          
 
820
          meta_alpha_gradient_spec_free (spec);
 
821
 
746
822
          return FALSE;
747
823
        }
748
824
 
749
825
      spec->alphas[i] = (unsigned char) (v * 255);
750
 
      
 
826
 
751
827
      ++i;
752
 
    }  
 
828
    }
753
829
 
754
830
  g_strfreev (split);
755
 
  
 
831
 
756
832
  *spec_ret = spec;
757
 
  
 
833
 
758
834
  return TRUE;
759
835
}
760
836
 
770
846
    {
771
847
      if (referent)
772
848
        return meta_color_spec_new_from_string (referent, err);
773
 
      
 
849
 
774
850
      /* no need to free referent: it's a pointer into the actual hash table */
775
851
    }
776
 
  
 
852
 
777
853
  return meta_color_spec_new_from_string (str, err);
778
854
}
779
855
 
784
860
                   GError             **error)
785
861
{
786
862
  double factor;
787
 
  
 
863
 
788
864
  if (strcmp (str, "xx-small") == 0)
789
865
    factor = PANGO_SCALE_XX_SMALL;
790
866
  else if (strcmp (str, "x-small") == 0)
808
884
    }
809
885
 
810
886
  *val = factor;
811
 
  
 
887
 
812
888
  return TRUE;
813
889
}
814
890
 
837
913
      const char *value;
838
914
      int ival = 0;
839
915
      double dval = 0.0;
840
 
      
 
916
 
841
917
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
842
918
                              error,
843
919
                              "!name", &name, "!value", &value,
947
1023
      if (rounded_top_right && !parse_rounding (rounded_top_right, &rounded_top_right_val, context, info->theme, error))
948
1024
        return;
949
1025
      if (rounded_bottom_left && !parse_rounding (rounded_bottom_left, &rounded_bottom_left_val, context, info->theme, error))
950
 
        return;      
 
1026
        return;
951
1027
      if (rounded_bottom_right && !parse_rounding (rounded_bottom_right, &rounded_bottom_right_val, context, info->theme, error))
952
1028
        return;
953
 
      
 
1029
 
954
1030
      title_scale_val = 1.0;
955
1031
      if (title_scale && !parse_title_scale (title_scale, &title_scale_val, context, error))
956
1032
        return;
957
 
      
 
1033
 
958
1034
      if (meta_theme_lookup_layout (info->theme, name))
959
1035
        {
960
1036
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1003
1079
 
1004
1080
      if (rounded_bottom_right)
1005
1081
        info->layout->bottom_right_corner_rounded_radius = rounded_bottom_right_val;
1006
 
      
 
1082
 
1007
1083
      meta_theme_insert_layout (info->theme, name, info->layout);
1008
1084
 
1009
1085
      push_state (info, STATE_FRAME_GEOMETRY);
1113
1189
 
1114
1190
          if (alpha != NULL)
1115
1191
            {
1116
 
            
 
1192
 
1117
1193
               gboolean success;
1118
1194
               MetaAlphaGradientSpec *alpha_vector;
1119
 
               
 
1195
 
1120
1196
               g_clear_error (error);
1121
1197
               /* fortunately, we already have a routine to parse alpha values,
1122
1198
                * though it produces a vector of them, which is a superset of
1123
1199
                * what we want.
1124
1200
                */
1125
 
               success = parse_alpha (alpha, &alpha_vector, context, error); 
 
1201
               success = parse_alpha (alpha, &alpha_vector, context, error);
1126
1202
               if (!success)
1127
1203
                 return;
1128
1204
 
1199
1275
 
1200
1276
      type = meta_frame_type_from_string (type_name);
1201
1277
 
1202
 
      if (type == META_FRAME_TYPE_LAST)
 
1278
      if (type == META_FRAME_TYPE_LAST ||
 
1279
         (type == META_FRAME_TYPE_ATTACHED && peek_required_version (info) < 3002))
1203
1280
        {
1204
1281
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1205
1282
                     _("Unknown type \"%s\" on <%s> element"),
1237
1314
       * for backwards compatibility.
1238
1315
       */
1239
1316
      g_assert (info->op_list == NULL);
1240
 
      
 
1317
 
1241
1318
      push_state (info, STATE_MENU_ICON);
1242
1319
    }
1243
1320
  else if (ELEMENT_IS ("fallback"))
1331
1408
  const char *name;
1332
1409
  const char *value;
1333
1410
  int val;
1334
 
  
 
1411
 
1335
1412
  if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1336
1413
                          error,
1337
1414
                          "!name", &name, "!value", &value,
1360
1437
  else if (strcmp (name, "button_width") == 0)
1361
1438
    {
1362
1439
      info->layout->button_width = val;
1363
 
            
 
1440
 
1364
1441
      if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST ||
1365
1442
            info->layout->button_sizing == META_BUTTON_SIZING_FIXED))
1366
1443
        {
1367
1444
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1368
1445
                     _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons"));
1369
 
          return;      
 
1446
          return;
1370
1447
        }
1371
1448
 
1372
1449
      info->layout->button_sizing = META_BUTTON_SIZING_FIXED;
1374
1451
  else if (strcmp (name, "button_height") == 0)
1375
1452
    {
1376
1453
      info->layout->button_height = val;
1377
 
      
 
1454
 
1378
1455
      if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST ||
1379
1456
            info->layout->button_sizing == META_BUTTON_SIZING_FIXED))
1380
1457
        {
1381
1458
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
1382
1459
                     _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons"));
1383
 
          return;      
 
1460
          return;
1384
1461
        }
1385
1462
 
1386
1463
      info->layout->button_sizing = META_BUTTON_SIZING_FIXED;
1404
1481
  const char *name;
1405
1482
  const char *value;
1406
1483
  double val;
1407
 
  
 
1484
 
1408
1485
  if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1409
1486
                          error,
1410
1487
                          "!name", &name, "!value", &value,
1416
1493
    return;
1417
1494
 
1418
1495
  g_assert (info->layout);
1419
 
  
 
1496
 
1420
1497
  if (strcmp (name, "button") == 0)
1421
1498
    {
1422
1499
      info->layout->button_aspect = val;
1427
1504
                     _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons"));
1428
1505
          return;
1429
1506
        }
1430
 
      
 
1507
 
1431
1508
      info->layout->button_sizing = META_BUTTON_SIZING_ASPECT;
1432
1509
    }
1433
1510
  else
1456
1533
  int left_val;
1457
1534
  int right_val;
1458
1535
  GtkBorder *border;
1459
 
  
 
1536
 
1460
1537
  if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1461
1538
                          error,
1462
1539
                          "!name", &name,
1466
1543
                          "!right", &right,
1467
1544
                          NULL))
1468
1545
    return;
1469
 
  
 
1546
 
1470
1547
  top_val = 0;
1471
1548
  if (!parse_positive_integer (top, &top_val, context, info->theme, error))
1472
1549
    return;
1482
1559
  right_val = 0;
1483
1560
  if (!parse_positive_integer (right, &right_val, context, info->theme, error))
1484
1561
    return;
1485
 
  
 
1562
 
1486
1563
  g_assert (info->layout);
1487
1564
 
1488
1565
  border = NULL;
1489
 
  
 
1566
 
1490
1567
  if (strcmp (name, "title_border") == 0)
1491
1568
    border = &info->layout->title_border;
1492
1569
  else if (strcmp (name, "button_border") == 0)
1562
1639
   * it's possible we should instead guarantee that widths and heights
1563
1640
   * are at least 1.
1564
1641
   */
1565
 
  
 
1642
 
1566
1643
  env.rect = meta_rect (0, 0, 0, 0);
1567
1644
  if (has_object)
1568
1645
    {
1581
1658
  env.bottom_height = 0;
1582
1659
  env.title_width = 0;
1583
1660
  env.title_height = 0;
1584
 
  
 
1661
 
1585
1662
  env.icon_width = 0;
1586
1663
  env.icon_height = 0;
1587
1664
  env.mini_icon_width = 0;
1588
1665
  env.mini_icon_height = 0;
1589
1666
  env.theme = theme;
1590
 
  
 
1667
 
1591
1668
  if (!meta_parse_position_expression (tokens, n_tokens,
1592
1669
                                       &env,
1593
1670
                                       &x, &y,
1608
1685
                       const gchar         **attribute_values,
1609
1686
                       ParseInfo            *info,
1610
1687
                       GError              **error)
1611
 
{  
 
1688
{
1612
1689
  g_return_if_fail (peek_state (info) == STATE_DRAW_OPS);
1613
1690
 
1614
1691
  if (ELEMENT_IS ("line"))
1626
1703
      int dash_on_val;
1627
1704
      int dash_off_val;
1628
1705
      int width_val;
1629
 
      
 
1706
 
1630
1707
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1631
1708
                              error,
1632
1709
                              "!color", &color,
1647
1724
 
1648
1725
      if (!check_expression (x2, FALSE, info->theme, context, error))
1649
1726
        return;
1650
 
      
 
1727
 
1651
1728
      if (!check_expression (y2, FALSE, info->theme, context, error))
1652
1729
        return;
1653
1730
#endif
1654
 
 
 
1731
 
1655
1732
      dash_on_val = 0;
1656
1733
      if (dash_on_length &&
1657
1734
          !parse_positive_integer (dash_on_length, &dash_on_val, context, info->theme, error))
1676
1753
          add_context_to_error (error, context);
1677
1754
          return;
1678
1755
        }
1679
 
      
 
1756
 
1680
1757
      op = meta_draw_op_new (META_DRAW_LINE);
1681
1758
 
1682
1759
      op->data.line.color_spec = color_spec;
1699
1776
      op->data.line.dash_off_length = dash_off_val;
1700
1777
 
1701
1778
      g_assert (info->op_list);
1702
 
      
 
1779
 
1703
1780
      meta_draw_op_list_append (info->op_list, op);
1704
1781
 
1705
1782
      push_state (info, STATE_LINE);
1715
1792
      const char *filled;
1716
1793
      gboolean filled_val;
1717
1794
      MetaColorSpec *color_spec;
1718
 
      
 
1795
 
1719
1796
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1720
1797
                              error,
1721
1798
                              "!color", &color,
1734
1811
 
1735
1812
      if (!check_expression (width, FALSE, info->theme, context, error))
1736
1813
        return;
1737
 
      
 
1814
 
1738
1815
      if (!check_expression (height, FALSE, info->theme, context, error))
1739
1816
        return;
1740
1817
#endif
1742
1819
      filled_val = FALSE;
1743
1820
      if (filled && !parse_boolean (filled, &filled_val, context, error))
1744
1821
        return;
1745
 
      
 
1822
 
1746
1823
      /* Check last so we don't have to free it when other
1747
1824
       * stuff fails
1748
1825
       */
1752
1829
          add_context_to_error (error, context);
1753
1830
          return;
1754
1831
        }
1755
 
      
 
1832
 
1756
1833
      op = meta_draw_op_new (META_DRAW_RECTANGLE);
1757
1834
 
1758
1835
      op->data.rectangle.color_spec = color_spec;
1759
1836
      op->data.rectangle.x = meta_draw_spec_new (info->theme, x, NULL);
1760
1837
      op->data.rectangle.y = meta_draw_spec_new (info->theme, y, NULL);
1761
1838
      op->data.rectangle.width = meta_draw_spec_new (info->theme, width, NULL);
1762
 
      op->data.rectangle.height = meta_draw_spec_new (info->theme, 
 
1839
      op->data.rectangle.height = meta_draw_spec_new (info->theme,
1763
1840
                                                      height, NULL);
1764
1841
 
1765
1842
      op->data.rectangle.filled = filled_val;
1766
1843
 
1767
1844
      g_assert (info->op_list);
1768
 
      
 
1845
 
1769
1846
      meta_draw_op_list_append (info->op_list, op);
1770
1847
 
1771
1848
      push_state (info, STATE_RECTANGLE);
1787
1864
      double start_angle_val;
1788
1865
      double extent_angle_val;
1789
1866
      MetaColorSpec *color_spec;
1790
 
      
 
1867
 
1791
1868
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1792
1869
                              error,
1793
1870
                              "!color", &color,
1834
1911
            }
1835
1912
        }
1836
1913
 
1837
 
#if 0     
 
1914
#if 0
1838
1915
      if (!check_expression (x, FALSE, info->theme, context, error))
1839
1916
        return;
1840
1917
 
1843
1920
 
1844
1921
      if (!check_expression (width, FALSE, info->theme, context, error))
1845
1922
        return;
1846
 
      
 
1923
 
1847
1924
      if (!check_expression (height, FALSE, info->theme, context, error))
1848
1925
        return;
1849
1926
#endif
1852
1929
        {
1853
1930
          if (!parse_angle (from, &start_angle_val, context, error))
1854
1931
            return;
1855
 
          
 
1932
 
1856
1933
          start_angle_val = (180-start_angle_val)/360.0;
1857
1934
        }
1858
1935
      else
1860
1937
          if (!parse_angle (start_angle, &start_angle_val, context, error))
1861
1938
            return;
1862
1939
        }
1863
 
      
 
1940
 
1864
1941
      if (extent_angle == NULL)
1865
1942
        {
1866
1943
          if (!parse_angle (to, &extent_angle_val, context, error))
1867
1944
            return;
1868
 
          
 
1945
 
1869
1946
          extent_angle_val = ((180-extent_angle_val)/360.0) - start_angle_val;
1870
1947
        }
1871
1948
      else
1873
1950
           if (!parse_angle (extent_angle, &extent_angle_val, context, error))
1874
1951
             return;
1875
1952
        }
1876
 
     
 
1953
 
1877
1954
      filled_val = FALSE;
1878
1955
      if (filled && !parse_boolean (filled, &filled_val, context, error))
1879
1956
        return;
1880
 
      
 
1957
 
1881
1958
      /* Check last so we don't have to free it when other
1882
1959
       * stuff fails
1883
1960
       */
1887
1964
          add_context_to_error (error, context);
1888
1965
          return;
1889
1966
        }
1890
 
      
 
1967
 
1891
1968
      op = meta_draw_op_new (META_DRAW_ARC);
1892
1969
 
1893
1970
      op->data.arc.color_spec = color_spec;
1900
1977
      op->data.arc.filled = filled_val;
1901
1978
      op->data.arc.start_angle = start_angle_val;
1902
1979
      op->data.arc.extent_angle = extent_angle_val;
1903
 
      
 
1980
 
1904
1981
      g_assert (info->op_list);
1905
 
      
 
1982
 
1906
1983
      meta_draw_op_list_append (info->op_list, op);
1907
1984
 
1908
1985
      push_state (info, STATE_ARC);
1914
1991
      const char *y;
1915
1992
      const char *width;
1916
1993
      const char *height;
1917
 
      
 
1994
 
1918
1995
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1919
1996
                              error,
1920
1997
                              "!x", &x, "!y", &y,
1921
1998
                              "!width", &width, "!height", &height,
1922
1999
                              NULL))
1923
2000
        return;
1924
 
      
 
2001
 
1925
2002
#if 0
1926
2003
      if (!check_expression (x, FALSE, info->theme, context, error))
1927
2004
        return;
1931
2008
 
1932
2009
      if (!check_expression (width, FALSE, info->theme, context, error))
1933
2010
        return;
1934
 
      
 
2011
 
1935
2012
      if (!check_expression (height, FALSE, info->theme, context, error))
1936
2013
        return;
1937
 
#endif 
 
2014
#endif
1938
2015
      op = meta_draw_op_new (META_DRAW_CLIP);
1939
2016
 
1940
2017
      op->data.clip.x = meta_draw_spec_new (info->theme, x, NULL);
1943
2020
      op->data.clip.height = meta_draw_spec_new (info->theme, height, NULL);
1944
2021
 
1945
2022
      g_assert (info->op_list);
1946
 
      
 
2023
 
1947
2024
      meta_draw_op_list_append (info->op_list, op);
1948
2025
 
1949
2026
      push_state (info, STATE_CLIP);
1959
2036
      const char *alpha;
1960
2037
      MetaAlphaGradientSpec *alpha_spec;
1961
2038
      MetaColorSpec *color_spec;
1962
 
      
 
2039
 
1963
2040
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
1964
2041
                              error,
1965
2042
                              "!color", &color,
1978
2055
 
1979
2056
      if (!check_expression (width, FALSE, info->theme, context, error))
1980
2057
        return;
1981
 
      
 
2058
 
1982
2059
      if (!check_expression (height, FALSE, info->theme, context, error))
1983
2060
        return;
1984
2061
#endif
1985
2062
      alpha_spec = NULL;
1986
2063
      if (!parse_alpha (alpha, &alpha_spec, context, error))
1987
2064
        return;
1988
 
      
 
2065
 
1989
2066
      /* Check last so we don't have to free it when other
1990
2067
       * stuff fails
1991
2068
       */
1994
2071
        {
1995
2072
          if (alpha_spec)
1996
2073
            meta_alpha_gradient_spec_free (alpha_spec);
1997
 
          
 
2074
 
1998
2075
          add_context_to_error (error, context);
1999
2076
          return;
2000
2077
        }
2001
 
      
 
2078
 
2002
2079
      op = meta_draw_op_new (META_DRAW_TINT);
2003
2080
 
2004
2081
      op->data.tint.color_spec = color_spec;
2010
2087
      op->data.tint.height = meta_draw_spec_new (info->theme, height, NULL);
2011
2088
 
2012
2089
      g_assert (info->op_list);
2013
 
      
 
2090
 
2014
2091
      meta_draw_op_list_append (info->op_list, op);
2015
2092
 
2016
2093
      push_state (info, STATE_TINT);
2025
2102
      const char *alpha;
2026
2103
      MetaAlphaGradientSpec *alpha_spec;
2027
2104
      MetaGradientType type_val;
2028
 
      
 
2105
 
2029
2106
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2030
2107
                              error,
2031
2108
                              "!type", &type,
2044
2121
 
2045
2122
      if (!check_expression (width, FALSE, info->theme, context, error))
2046
2123
        return;
2047
 
      
 
2124
 
2048
2125
      if (!check_expression (height, FALSE, info->theme, context, error))
2049
2126
        return;
2050
2127
#endif
2051
 
  
 
2128
 
2052
2129
      type_val = meta_gradient_type_from_string (type);
2053
2130
      if (type_val == META_GRADIENT_LAST)
2054
2131
        {
2061
2138
      alpha_spec = NULL;
2062
2139
      if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
2063
2140
        return;
2064
 
      
 
2141
 
2065
2142
      g_assert (info->op == NULL);
2066
2143
      info->op = meta_draw_op_new (META_DRAW_GRADIENT);
2067
2144
 
2068
2145
      info->op->data.gradient.x = meta_draw_spec_new (info->theme, x, NULL);
2069
2146
      info->op->data.gradient.y = meta_draw_spec_new (info->theme, y, NULL);
2070
 
      info->op->data.gradient.width = meta_draw_spec_new (info->theme, 
 
2147
      info->op->data.gradient.width = meta_draw_spec_new (info->theme,
2071
2148
                                                        width, NULL);
2072
2149
      info->op->data.gradient.height = meta_draw_spec_new (info->theme,
2073
2150
                                                         height, NULL);
2075
2152
      info->op->data.gradient.gradient_spec = meta_gradient_spec_new (type_val);
2076
2153
 
2077
2154
      info->op->data.gradient.alpha_spec = alpha_spec;
2078
 
      
 
2155
 
2079
2156
      push_state (info, STATE_GRADIENT);
2080
2157
 
2081
2158
      /* op gets appended on close tag */
2098
2175
      int h, w, c;
2099
2176
      int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride;
2100
2177
      guchar *pixbuf_pixels;
2101
 
      
 
2178
 
2102
2179
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2103
2180
                              error,
2104
2181
                              "!x", &x, "!y", &y,
2108
2185
                              "fill_type", &fill_type,
2109
2186
                              NULL))
2110
2187
        return;
2111
 
      
2112
 
#if 0      
 
2188
 
 
2189
#if 0
2113
2190
      if (!check_expression (x, TRUE, info->theme, context, error))
2114
2191
        return;
2115
2192
 
2118
2195
 
2119
2196
      if (!check_expression (width, TRUE, info->theme, context, error))
2120
2197
        return;
2121
 
      
 
2198
 
2122
2199
      if (!check_expression (height, TRUE, info->theme, context, error))
2123
2200
        return;
2124
2201
#endif
2126
2203
      if (fill_type)
2127
2204
        {
2128
2205
          fill_type_val = meta_image_fill_type_from_string (fill_type);
2129
 
          
 
2206
 
2130
2207
          if (((int) fill_type_val) == -1)
2131
2208
            {
2132
2209
              set_error (error, context, G_MARKUP_ERROR,
2135
2212
                         fill_type, element_name);
2136
2213
            }
2137
2214
        }
2138
 
      
 
2215
 
2139
2216
      /* Check last so we don't have to free it when other
2140
2217
       * stuff fails.
2141
2218
       *
2153
2230
      if (colorize)
2154
2231
        {
2155
2232
          colorize_spec = parse_color (info->theme, colorize, error);
2156
 
          
 
2233
 
2157
2234
          if (colorize_spec == NULL)
2158
2235
            {
2159
2236
              add_context_to_error (error, context);
2168
2245
          g_object_unref (G_OBJECT (pixbuf));
2169
2246
          return;
2170
2247
        }
2171
 
      
 
2248
 
2172
2249
      op = meta_draw_op_new (META_DRAW_IMAGE);
2173
2250
 
2174
2251
      op->data.image.pixbuf = pixbuf;
2181
2258
 
2182
2259
      op->data.image.alpha_spec = alpha_spec;
2183
2260
      op->data.image.fill_type = fill_type_val;
2184
 
      
 
2261
 
2185
2262
      /* Check for vertical & horizontal stripes */
2186
2263
      pixbuf_n_channels = gdk_pixbuf_get_n_channels(pixbuf);
2187
2264
      pixbuf_width = gdk_pixbuf_get_width(pixbuf);
2209
2286
 
2210
2287
      if (h >= pixbuf_height)
2211
2288
        {
2212
 
          op->data.image.horizontal_stripes = TRUE; 
 
2289
          op->data.image.horizontal_stripes = TRUE;
2213
2290
        }
2214
2291
      else
2215
2292
        {
2216
 
          op->data.image.horizontal_stripes = FALSE; 
 
2293
          op->data.image.horizontal_stripes = FALSE;
2217
2294
        }
2218
2295
 
2219
2296
      /* Check for vertical stripes */
2236
2313
 
2237
2314
      if (w >= pixbuf_width)
2238
2315
        {
2239
 
          op->data.image.vertical_stripes = TRUE; 
 
2316
          op->data.image.vertical_stripes = TRUE;
2240
2317
        }
2241
2318
      else
2242
2319
        {
2243
 
          op->data.image.vertical_stripes = FALSE; 
 
2320
          op->data.image.vertical_stripes = FALSE;
2244
2321
        }
2245
 
      
 
2322
 
2246
2323
      g_assert (info->op_list);
2247
 
      
 
2324
 
2248
2325
      meta_draw_op_list_append (info->op_list, op);
2249
2326
 
2250
2327
      push_state (info, STATE_IMAGE);
2264
2341
      GtkStateFlags state_val;
2265
2342
      GtkShadowType shadow_val;
2266
2343
      GtkArrowType arrow_val;
2267
 
      
 
2344
 
2268
2345
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2269
2346
                              error,
2270
2347
                              "!state", &state,
2285
2362
 
2286
2363
      if (!check_expression (width, FALSE, info->theme, context, error))
2287
2364
        return;
2288
 
      
 
2365
 
2289
2366
      if (!check_expression (height, FALSE, info->theme, context, error))
2290
2367
        return;
2291
2368
#endif
2322
2399
                     arrow, element_name);
2323
2400
          return;
2324
2401
        }
2325
 
      
 
2402
 
2326
2403
      op = meta_draw_op_new (META_DRAW_GTK_ARROW);
2327
2404
 
2328
2405
      op->data.gtk_arrow.x = meta_draw_spec_new (info->theme, x, NULL);
2329
2406
      op->data.gtk_arrow.y = meta_draw_spec_new (info->theme, y, NULL);
2330
2407
      op->data.gtk_arrow.width = meta_draw_spec_new (info->theme, width, NULL);
2331
 
      op->data.gtk_arrow.height = meta_draw_spec_new (info->theme, 
 
2408
      op->data.gtk_arrow.height = meta_draw_spec_new (info->theme,
2332
2409
                                                      height, NULL);
2333
2410
 
2334
2411
      op->data.gtk_arrow.filled = filled_val;
2335
2412
      op->data.gtk_arrow.state = state_val;
2336
2413
      op->data.gtk_arrow.shadow = shadow_val;
2337
2414
      op->data.gtk_arrow.arrow = arrow_val;
2338
 
      
 
2415
 
2339
2416
      g_assert (info->op_list);
2340
 
      
 
2417
 
2341
2418
      meta_draw_op_list_append (info->op_list, op);
2342
2419
 
2343
2420
      push_state (info, STATE_GTK_ARROW);
2353
2430
      const char *height;
2354
2431
      GtkStateFlags state_val;
2355
2432
      GtkShadowType shadow_val;
2356
 
      
 
2433
 
2357
2434
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2358
2435
                              error,
2359
2436
                              "!state", &state,
2372
2449
 
2373
2450
      if (!check_expression (width, FALSE, info->theme, context, error))
2374
2451
        return;
2375
 
      
 
2452
 
2376
2453
      if (!check_expression (height, FALSE, info->theme, context, error))
2377
2454
        return;
2378
2455
#endif
2395
2472
                     shadow, element_name);
2396
2473
          return;
2397
2474
        }
2398
 
      
 
2475
 
2399
2476
      op = meta_draw_op_new (META_DRAW_GTK_BOX);
2400
2477
 
2401
2478
      op->data.gtk_box.x = meta_draw_spec_new (info->theme, x, NULL);
2405
2482
 
2406
2483
      op->data.gtk_box.state = state_val;
2407
2484
      op->data.gtk_box.shadow = shadow_val;
2408
 
      
 
2485
 
2409
2486
      g_assert (info->op_list);
2410
 
      
 
2487
 
2411
2488
      meta_draw_op_list_append (info->op_list, op);
2412
2489
 
2413
2490
      push_state (info, STATE_GTK_BOX);
2420
2497
      const char *y1;
2421
2498
      const char *y2;
2422
2499
      GtkStateFlags state_val;
2423
 
      
 
2500
 
2424
2501
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2425
2502
                              error,
2426
2503
                              "!state", &state,
2448
2525
                     state, element_name);
2449
2526
          return;
2450
2527
        }
2451
 
      
 
2528
 
2452
2529
      op = meta_draw_op_new (META_DRAW_GTK_VLINE);
2453
2530
 
2454
2531
      op->data.gtk_vline.x = meta_draw_spec_new (info->theme, x, NULL);
2456
2533
      op->data.gtk_vline.y2 = meta_draw_spec_new (info->theme, y2, NULL);
2457
2534
 
2458
2535
      op->data.gtk_vline.state = state_val;
2459
 
      
 
2536
 
2460
2537
      g_assert (info->op_list);
2461
 
      
 
2538
 
2462
2539
      meta_draw_op_list_append (info->op_list, op);
2463
2540
 
2464
2541
      push_state (info, STATE_GTK_VLINE);
2474
2551
      const char *fill_type;
2475
2552
      MetaAlphaGradientSpec *alpha_spec;
2476
2553
      MetaImageFillType fill_type_val;
2477
 
      
 
2554
 
2478
2555
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2479
2556
                              error,
2480
2557
                              "!x", &x, "!y", &y,
2483
2560
                              "fill_type", &fill_type,
2484
2561
                              NULL))
2485
2562
        return;
2486
 
      
2487
 
#if 0      
 
2563
 
 
2564
#if 0
2488
2565
      if (!check_expression (x, FALSE, info->theme, context, error))
2489
2566
        return;
2490
2567
 
2493
2570
 
2494
2571
      if (!check_expression (width, FALSE, info->theme, context, error))
2495
2572
        return;
2496
 
      
 
2573
 
2497
2574
      if (!check_expression (height, FALSE, info->theme, context, error))
2498
2575
        return;
2499
2576
#endif
2510
2587
                         fill_type, element_name);
2511
2588
            }
2512
2589
        }
2513
 
      
 
2590
 
2514
2591
      alpha_spec = NULL;
2515
2592
      if (alpha && !parse_alpha (alpha, &alpha_spec, context, error))
2516
2593
        return;
2517
 
      
 
2594
 
2518
2595
      op = meta_draw_op_new (META_DRAW_ICON);
2519
 
      
 
2596
 
2520
2597
      op->data.icon.x = meta_draw_spec_new (info->theme, x, NULL);
2521
2598
      op->data.icon.y = meta_draw_spec_new (info->theme, y, NULL);
2522
2599
      op->data.icon.width = meta_draw_spec_new (info->theme, width, NULL);
2524
2601
 
2525
2602
      op->data.icon.alpha_spec = alpha_spec;
2526
2603
      op->data.icon.fill_type = fill_type_val;
2527
 
      
 
2604
 
2528
2605
      g_assert (info->op_list);
2529
 
      
 
2606
 
2530
2607
      meta_draw_op_list_append (info->op_list, op);
2531
2608
 
2532
2609
      push_state (info, STATE_ICON);
2537
2614
      const char *color;
2538
2615
      const char *x;
2539
2616
      const char *y;
 
2617
      const char *ellipsize_width;
2540
2618
      MetaColorSpec *color_spec;
2541
 
      
 
2619
 
2542
2620
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2543
2621
                              error,
2544
2622
                              "!color", &color,
2545
2623
                              "!x", &x, "!y", &y,
 
2624
                              "ellipsize_width", &ellipsize_width,
2546
2625
                              NULL))
2547
2626
        return;
2548
2627
 
2552
2631
 
2553
2632
      if (!check_expression (y, FALSE, info->theme, context, error))
2554
2633
        return;
 
2634
 
 
2635
      if (!check_expression (ellipsize_width, FALSE, info->theme, context, error))
 
2636
        return;
2555
2637
#endif
2556
2638
 
 
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
 
2557
2646
      /* Check last so we don't have to free it when other
2558
2647
       * stuff fails
2559
2648
       */
2563
2652
          add_context_to_error (error, context);
2564
2653
          return;
2565
2654
        }
2566
 
      
 
2655
 
2567
2656
      op = meta_draw_op_new (META_DRAW_TITLE);
2568
2657
 
2569
2658
      op->data.title.color_spec = color_spec;
2570
2659
 
2571
2660
      op->data.title.x = meta_draw_spec_new (info->theme, x, NULL);
2572
2661
      op->data.title.y = meta_draw_spec_new (info->theme, y, NULL);
 
2662
      if (ellipsize_width)
 
2663
        op->data.title.ellipsize_width = meta_draw_spec_new (info->theme, ellipsize_width, NULL);
2573
2664
 
2574
2665
      g_assert (info->op_list);
2575
 
      
 
2666
 
2576
2667
      meta_draw_op_list_append (info->op_list, op);
2577
2668
 
2578
2669
      push_state (info, STATE_TITLE);
2586
2677
      const char *width;
2587
2678
      const char *height;
2588
2679
      MetaDrawOpList *op_list;
2589
 
      
 
2680
 
2590
2681
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2591
2682
                              error,
2592
2683
                              "x", &x, "y", &y,
2598
2689
      /* x/y/width/height default to 0,0,width,height - should
2599
2690
       * probably do this for all the draw ops
2600
2691
       */
2601
 
#if 0      
 
2692
#if 0
2602
2693
      if (x && !check_expression (x, FALSE, info->theme, context, error))
2603
2694
        return;
2604
2695
 
2607
2698
 
2608
2699
      if (width && !check_expression (width, FALSE, info->theme, context, error))
2609
2700
        return;
2610
 
      
 
2701
 
2611
2702
      if (height && !check_expression (height, FALSE, info->theme, context, error))
2612
2703
        return;
2613
2704
#endif
2624
2715
        }
2625
2716
 
2626
2717
      g_assert (info->op_list);
2627
 
      
 
2718
 
2628
2719
      if (op_list == info->op_list ||
2629
2720
          meta_draw_op_list_contains (op_list, info->op_list))
2630
2721
        {
2634
2725
                     name);
2635
2726
          return;
2636
2727
        }
2637
 
      
 
2728
 
2638
2729
      op = meta_draw_op_new (META_DRAW_OP_LIST);
2639
2730
 
2640
2731
      meta_draw_op_list_ref (op_list);
2641
 
      op->data.op_list.op_list = op_list;      
 
2732
      op->data.op_list.op_list = op_list;
2642
2733
 
2643
2734
      op->data.op_list.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL);
2644
2735
      op->data.op_list.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL);
2645
 
      op->data.op_list.width = meta_draw_spec_new (info->theme, 
 
2736
      op->data.op_list.width = meta_draw_spec_new (info->theme,
2646
2737
                                                   width ? width : "width",
2647
2738
                                                   NULL);
2648
2739
      op->data.op_list.height = meta_draw_spec_new (info->theme,
2666
2757
      const char *tile_width;
2667
2758
      const char *tile_height;
2668
2759
      MetaDrawOpList *op_list;
2669
 
      
 
2760
 
2670
2761
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2671
2762
                              error,
2672
2763
                              "x", &x, "y", &y,
2686
2777
 
2687
2778
      if (tile_yoffset && !check_expression (tile_yoffset, FALSE, info->theme, context, error))
2688
2779
        return;
2689
 
      
 
2780
 
2690
2781
      /* x/y/width/height default to 0,0,width,height - should
2691
2782
       * probably do this for all the draw ops
2692
2783
       */
2698
2789
 
2699
2790
      if (width && !check_expression (width, FALSE, info->theme, context, error))
2700
2791
        return;
2701
 
      
 
2792
 
2702
2793
      if (height && !check_expression (height, FALSE, info->theme, context, error))
2703
2794
        return;
2704
2795
 
2707
2798
 
2708
2799
      if (!check_expression (tile_height, FALSE, info->theme, context, error))
2709
2800
        return;
2710
 
#endif 
 
2801
#endif
2711
2802
      op_list = meta_theme_lookup_draw_op_list (info->theme,
2712
2803
                                                name);
2713
2804
      if (op_list == NULL)
2720
2811
        }
2721
2812
 
2722
2813
      g_assert (info->op_list);
2723
 
      
 
2814
 
2724
2815
      if (op_list == info->op_list ||
2725
2816
          meta_draw_op_list_contains (op_list, info->op_list))
2726
2817
        {
2730
2821
                     name);
2731
2822
          return;
2732
2823
        }
2733
 
      
 
2824
 
2734
2825
      op = meta_draw_op_new (META_DRAW_TILE);
2735
2826
 
2736
2827
      meta_draw_op_list_ref (op_list);
2752
2843
      op->data.tile.tile_width = meta_draw_spec_new (info->theme, tile_width, NULL);
2753
2844
      op->data.tile.tile_height = meta_draw_spec_new (info->theme, tile_height, NULL);
2754
2845
 
2755
 
      op->data.tile.op_list = op_list;      
2756
 
      
 
2846
      op->data.tile.op_list = op_list;
 
2847
 
2757
2848
      meta_draw_op_list_append (info->op_list, op);
2758
2849
 
2759
2850
      push_state (info, STATE_TILE);
2801
2892
      info->op->data.gradient.gradient_spec->color_specs =
2802
2893
        g_slist_append (info->op->data.gradient.gradient_spec->color_specs,
2803
2894
                        color_spec);
2804
 
      
 
2895
 
2805
2896
      push_state (info, STATE_COLOR);
2806
2897
    }
2807
2898
  else
2824
2915
  g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE);
2825
2916
 
2826
2917
  g_assert (info->style);
2827
 
  
 
2918
 
2828
2919
  if (ELEMENT_IS ("piece"))
2829
2920
    {
2830
2921
      const char *position = NULL;
2831
2922
      const char *draw_ops = NULL;
2832
 
      
 
2923
 
2833
2924
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2834
2925
                              error,
2835
2926
                              "!position", &position,
2845
2936
                     position);
2846
2937
          return;
2847
2938
        }
2848
 
      
 
2939
 
2849
2940
      if (info->style->pieces[info->piece] != NULL)
2850
2941
        {
2851
2942
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2855
2946
        }
2856
2947
 
2857
2948
      g_assert (info->op_list == NULL);
2858
 
      
 
2949
 
2859
2950
      if (draw_ops)
2860
2951
        {
2861
2952
          MetaDrawOpList *op_list;
2874
2965
          meta_draw_op_list_ref (op_list);
2875
2966
          info->op_list = op_list;
2876
2967
        }
2877
 
      
 
2968
 
2878
2969
      push_state (info, STATE_PIECE);
2879
2970
    }
2880
2971
  else if (ELEMENT_IS ("button"))
2882
2973
      const char *function = NULL;
2883
2974
      const char *state = NULL;
2884
2975
      const char *draw_ops = NULL;
2885
 
      
 
2976
      gint required_version;
 
2977
 
2886
2978
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
2887
2979
                              error,
2888
2980
                              "!function", &function,
2900
2992
          return;
2901
2993
        }
2902
2994
 
 
2995
      required_version = peek_required_version (info);
2903
2996
      if (meta_theme_earliest_version_with_button (info->button_type) >
2904
 
          info->theme->format_version)
 
2997
          (guint)required_version)
2905
2998
        {
2906
2999
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2907
3000
                     _("Button function \"%s\" does not exist in this version (%d, need %d)"),
2908
3001
                     function,
2909
 
                     info->theme->format_version,
 
3002
                     required_version,
2910
3003
                     meta_theme_earliest_version_with_button (info->button_type)
2911
3004
                     );
2912
3005
          return;
2920
3013
                     state);
2921
3014
          return;
2922
3015
        }
2923
 
      
 
3016
 
2924
3017
      if (info->style->buttons[info->button_type][info->button_state] != NULL)
2925
3018
        {
2926
3019
          set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2930
3023
        }
2931
3024
 
2932
3025
      g_assert (info->op_list == NULL);
2933
 
      
 
3026
 
2934
3027
      if (draw_ops)
2935
3028
        {
2936
3029
          MetaDrawOpList *op_list;
2949
3042
          meta_draw_op_list_ref (op_list);
2950
3043
          info->op_list = op_list;
2951
3044
        }
2952
 
      
 
3045
 
2953
3046
      push_state (info, STATE_BUTTON);
2954
3047
    }
2955
3048
  else if (ELEMENT_IS ("shadow"))
3047
3140
      MetaFrameState frame_state;
3048
3141
      MetaFrameResize frame_resize;
3049
3142
      MetaFrameStyle *frame_style;
3050
 
      
 
3143
 
3051
3144
      if (!locate_attributes (context, element_name, attribute_names, attribute_values,
3052
3145
                              error,
3053
3146
                              "!focus", &focus,
3065
3158
                     focus);
3066
3159
          return;
3067
3160
        }
3068
 
      
 
3161
 
3069
3162
      frame_state = meta_frame_state_from_string (state);
3070
3163
      if (frame_state == META_FRAME_STATE_LAST)
3071
3164
        {
3096
3189
              return;
3097
3190
            }
3098
3191
 
3099
 
          
 
3192
 
3100
3193
          frame_resize = meta_frame_resize_from_string (resize);
3101
3194
          if (frame_resize == META_FRAME_RESIZE_LAST)
3102
3195
            {
3105
3198
                         focus);
3106
3199
              return;
3107
3200
            }
3108
 
          
 
3201
 
3109
3202
          break;
3110
3203
 
3111
3204
        case META_FRAME_STATE_SHADED:
3144
3237
              frame_resize = META_FRAME_RESIZE_BOTH;
3145
3238
            }
3146
3239
          break;
3147
 
          
 
3240
 
3148
3241
        default:
3149
3242
          if (resize != NULL)
3150
3243
            {
3156
3249
 
3157
3250
          frame_resize = META_FRAME_RESIZE_LAST;
3158
3251
        }
3159
 
      
 
3252
 
3160
3253
      switch (frame_state)
3161
3254
        {
3162
3255
        case META_FRAME_STATE_NORMAL:
3252
3345
          break;
3253
3346
        }
3254
3347
 
3255
 
      push_state (info, STATE_FRAME);      
 
3348
      push_state (info, STATE_FRAME);
3256
3349
    }
3257
3350
  else
3258
3351
    {
3282
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)"));
3283
3376
          return;
3284
3377
        }
3285
 
            
 
3378
 
3286
3379
      if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
3287
3380
                                error))
3288
3381
        return;
3310
3403
                      GError              **error)
3311
3404
{
3312
3405
  g_return_if_fail (peek_state (info) == STATE_BUTTON);
3313
 
  
 
3406
 
3314
3407
  if (ELEMENT_IS ("draw_ops"))
3315
3408
    {
3316
3409
      if (info->op_list)
3320
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)"));
3321
3414
          return;
3322
3415
        }
3323
 
            
 
3416
 
3324
3417
      if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
3325
3418
                                error))
3326
3419
        return;
3390
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)"));
3391
3484
          return;
3392
3485
        }
3393
 
            
 
3486
 
3394
3487
      if (!check_no_attributes (context, element_name, attribute_names, attribute_values,
3395
3488
                                error))
3396
3489
        return;
3409
3502
    }
3410
3503
}
3411
3504
 
 
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
}
3412
3588
 
3413
3589
static void
3414
3590
start_element_handler (GMarkupParseContext *context,
3419
3595
                       GError             **error)
3420
3596
{
3421
3597
  ParseInfo *info = user_data;
 
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);
3422
3657
 
3423
3658
  switch (peek_state (info))
3424
3659
    {
3430
3665
          info->theme->filename = g_strdup (info->theme_file);
3431
3666
          info->theme->dirname = g_strdup (info->theme_dir);
3432
3667
          info->theme->format_version = info->format_version;
3433
 
          
 
3668
 
3434
3669
          push_state (info, STATE_THEME);
3435
3670
        }
3436
3671
      else
3568
3803
{
3569
3804
  ParseInfo *info = user_data;
3570
3805
 
 
3806
  if (info->skip_level > 0)
 
3807
    {
 
3808
      info->skip_level--;
 
3809
      return;
 
3810
    }
 
3811
 
3571
3812
  switch (peek_state (info))
3572
3813
    {
3573
3814
    case STATE_START:
3581
3822
          meta_theme_free (info->theme);
3582
3823
          info->theme = NULL;
3583
3824
        }
3584
 
      
 
3825
 
3585
3826
      pop_state (info);
3586
3827
      g_assert (peek_state (info) == STATE_START);
3587
3828
      break;
3645
3886
    case STATE_DRAW_OPS:
3646
3887
      {
3647
3888
        g_assert (info->op_list);
3648
 
        
 
3889
 
3649
3890
        if (!meta_draw_op_list_validate (info->op_list,
3650
3891
                                         error))
3651
3892
          {
3757
3998
      g_assert (info->style);
3758
3999
 
3759
4000
      if (!meta_frame_style_validate (info->style,
3760
 
                                      info->theme->format_version,
 
4001
                                      peek_required_version (info),
3761
4002
                                      error))
3762
4003
        {
3763
4004
          add_context_to_error (error, context);
3849
4090
      g_assert (peek_state (info) == STATE_THEME);
3850
4091
      break;
3851
4092
    }
 
4093
 
 
4094
  pop_required_version (info);
3852
4095
}
3853
4096
 
3854
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)
3859
4102
{
3860
4103
  const char *p;
3861
4104
  const char *end;
3862
 
  
 
4105
 
3863
4106
  p = text;
3864
4107
  end = text + text_len;
3865
 
  
 
4108
 
3866
4109
  while (p != end)
3867
4110
    {
3868
4111
      if (!g_ascii_isspace (*p))
3883
4126
{
3884
4127
  ParseInfo *info = user_data;
3885
4128
 
 
4129
  if (info->skip_level > 0)
 
4130
    return;
 
4131
 
3886
4132
  if (all_whitespace (text, text_len))
3887
4133
    return;
3888
 
  
 
4134
 
3889
4135
  /* FIXME http://bugzilla.gnome.org/show_bug.cgi?id=70448 would
3890
4136
   * allow a nice cleanup here.
3891
4137
   */
4057
4303
    }
4058
4304
}
4059
4305
 
4060
 
/* We were intending to put the version number
4061
 
 * in the subdirectory name, but we ended up
4062
 
 * using the filename instead.  The "-1" survives
4063
 
 * as a fossil.
4064
 
 */
4065
 
#define THEME_SUBDIR "metacity-1"
4066
 
 
4067
 
/* Highest version of the theme format to
4068
 
 * look out for.
4069
 
 */
4070
 
#define THEME_VERSION 2
4071
 
 
4072
 
#define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml"
4073
 
 
4074
 
MetaTheme*
4075
 
meta_theme_load (const char *theme_name,
4076
 
                 GError    **err)
 
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)
4077
4322
{
4078
4323
  GMarkupParseContext *context;
4079
 
  GError *error;
4080
4324
  ParseInfo info;
4081
4325
  char *text;
4082
4326
  gsize length;
 
4327
  char *theme_filename;
4083
4328
  char *theme_file;
 
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;
4084
4399
  char *theme_dir;
4085
4400
  MetaTheme *retval;
4086
 
  guint version;
4087
4401
  const gchar* const* xdg_data_dirs;
 
4402
  int major_version;
4088
4403
  int i;
4089
4404
 
4090
 
  text = NULL;
4091
 
  length = 0;
4092
4405
  retval = NULL;
4093
 
  context = NULL;
4094
 
  
4095
 
  theme_dir = NULL;
4096
 
  theme_file = NULL;
4097
 
  
 
4406
 
4098
4407
  if (meta_is_debugging ())
4099
4408
    {
4100
 
      gchar *theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT,
4101
 
                                               THEME_VERSION);
4102
 
 
4103
 
      /* Try in themes in our source tree */
4104
 
      theme_dir = g_build_filename ("./themes", theme_name, NULL);
4105
 
      
4106
 
      theme_file = g_build_filename (theme_dir,
4107
 
                                     theme_filename,
4108
 
                                     NULL);
4109
 
      
4110
 
      error = NULL;
4111
 
      if (!g_file_get_contents (theme_file,
4112
 
                                &text,
4113
 
                                &length,
4114
 
                                &error))
 
4409
      /* We try all supported major versions from current to oldest */
 
4410
      for (major_version = THEME_MAJOR_VERSION; (major_version > 0); major_version--)
4115
4411
        {
4116
 
          meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
4117
 
                      theme_file, error->message);
4118
 
          g_error_free (error);
4119
 
          g_free (theme_dir);
4120
 
          g_free (theme_file);
4121
 
          theme_file = NULL;
 
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;
4122
4417
        }
4123
 
      version = THEME_VERSION;
4124
 
 
4125
 
      g_free (theme_filename);
4126
4418
    }
4127
 
  
4128
 
  /* We try all supported versions from current to oldest */
4129
 
  for (version = THEME_VERSION; (version > 0) && (text == NULL); version--)
 
4419
 
 
4420
  /* We try all supported major versions from current to oldest */
 
4421
  for (major_version = THEME_MAJOR_VERSION; (major_version > 0); major_version--)
4130
4422
    {
4131
 
      gchar *theme_filename = g_strdup_printf (METACITY_THEME_FILENAME_FORMAT,
4132
 
                                               version);
4133
 
      
4134
 
      /* We try first in home dir, XDG_DATA_DIRS, then system dir for themes */
 
4423
      /* We try first in XDG_USER_DATA_DIR, XDG_DATA_DIRS, then system dir for themes */
4135
4424
 
4136
 
      /* Try home dir for themes */
4137
 
      theme_dir = g_build_filename (g_get_home_dir (),
4138
 
                                    ".themes",
 
4425
      /* Try XDG_USER_DATA_DIR first */
 
4426
      theme_dir = g_build_filename (g_get_user_data_dir(),
 
4427
                                    "themes",
4139
4428
                                    theme_name,
4140
4429
                                    THEME_SUBDIR,
4141
4430
                                    NULL);
4142
 
      
4143
 
      theme_file = g_build_filename (theme_dir,
4144
 
                                     theme_filename,
4145
 
                                     NULL);
4146
4431
 
4147
 
      error = NULL;
4148
 
      if (!g_file_get_contents (theme_file,
4149
 
                                &text,
4150
 
                                &length,
4151
 
                                &error))
4152
 
        {
4153
 
          meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
4154
 
                      theme_file, error->message);
4155
 
          g_error_free (error);
4156
 
          g_free (theme_dir);
4157
 
          g_free (theme_file);
4158
 
          theme_file = NULL;
4159
 
        }
 
4432
      retval = load_theme (theme_dir, theme_name, major_version, &error);
 
4433
      g_free (theme_dir);
 
4434
      if (!keep_trying (&error))
 
4435
        goto out;
4160
4436
 
4161
4437
      /* Try each XDG_DATA_DIRS for theme */
4162
4438
      xdg_data_dirs = g_get_system_data_dirs();
4163
4439
      for(i = 0; xdg_data_dirs[i] != NULL; i++)
4164
4440
        {
4165
 
          if (text == NULL)
4166
 
            {
4167
 
              theme_dir = g_build_filename (xdg_data_dirs[i],
4168
 
                                            "themes",
4169
 
                                            theme_name,
4170
 
                                            THEME_SUBDIR,
4171
 
                                            NULL);
4172
 
 
4173
 
              theme_file = g_build_filename (theme_dir,
4174
 
                                             theme_filename,
4175
 
                                             NULL);
4176
 
 
4177
 
              error = NULL;
4178
 
              if (!g_file_get_contents (theme_file,
4179
 
                                        &text,
4180
 
                                        &length,
4181
 
                                        &error))
4182
 
                {
4183
 
                  meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
4184
 
                              theme_file, error->message);
4185
 
                  g_error_free (error);
4186
 
                  g_free (theme_dir);
4187
 
                  g_free (theme_file);
4188
 
                  theme_file = NULL;
4189
 
                }
4190
 
              else
4191
 
                {
4192
 
                  break;
4193
 
                }
4194
 
            }
4195
 
        }
4196
 
 
4197
 
      /* Look for themes in METACITY_DATADIR */
4198
 
      if (text == NULL)
4199
 
        {
4200
 
          theme_dir = g_build_filename (METACITY_DATADIR,
 
4441
          theme_dir = g_build_filename (xdg_data_dirs[i],
4201
4442
                                        "themes",
4202
4443
                                        theme_name,
4203
4444
                                        THEME_SUBDIR,
4204
4445
                                        NULL);
4205
 
      
4206
 
          theme_file = g_build_filename (theme_dir,
4207
 
                                         theme_filename,
4208
 
                                         NULL);
4209
4446
 
4210
 
          error = NULL;
4211
 
          if (!g_file_get_contents (theme_file,
4212
 
                                    &text,
4213
 
                                    &length,
4214
 
                                    &error))
4215
 
            {
4216
 
              meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n",
4217
 
                            theme_file, error->message);
4218
 
              g_error_free (error);
4219
 
              g_free (theme_dir);
4220
 
              g_free (theme_file);
4221
 
              theme_file = NULL;
4222
 
            }
 
4447
          retval = load_theme (theme_dir, theme_name, major_version, &error);
 
4448
          g_free (theme_dir);
 
4449
          if (!keep_trying (&error))
 
4450
            goto out;
4223
4451
        }
4224
4452
 
4225
 
      g_free (theme_filename);
4226
 
    }
4227
 
 
4228
 
  if (text == NULL)
4229
 
    {
4230
 
      g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED,
4231
 
          _("Failed to find a valid file for theme %s\n"),
4232
 
          theme_name);
4233
 
 
4234
 
      return NULL; /* all fallbacks failed */
4235
 
    }
4236
 
 
4237
 
  meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file);
4238
 
 
4239
 
 
4240
 
  parse_info_init (&info);
4241
 
  info.theme_name = theme_name;
4242
 
  
4243
 
  /* pass ownership to info so we free it with the info */
4244
 
  info.theme_file = theme_file;
4245
 
  info.theme_dir = theme_dir;
4246
 
 
4247
 
  info.format_version = version + 1;
4248
 
  
4249
 
  context = g_markup_parse_context_new (&metacity_theme_parser,
4250
 
                                        0, &info, NULL);
4251
 
 
4252
 
  error = NULL;
4253
 
  if (!g_markup_parse_context_parse (context,
4254
 
                                     text,
4255
 
                                     length,
4256
 
                                     &error))
4257
 
    goto out;
4258
 
 
4259
 
  error = NULL;
4260
 
  if (!g_markup_parse_context_end_parse (context, &error))
4261
 
    goto out;
4262
 
 
4263
 
  goto out;
 
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
    }
4264
4464
 
4265
4465
 out:
4266
4466
 
4267
 
  if (context)
4268
 
    g_markup_parse_context_free (context);
4269
 
  g_free (text);
4270
 
 
4271
 
  if (info.theme)
4272
 
    info.theme->format_version = info.format_version;
 
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);
4273
4471
 
4274
4472
  if (error)
4275
4473
    {
4276
4474
      g_propagate_error (err, error);
4277
4475
    }
4278
 
  else if (info.theme)
4279
 
    {
4280
 
      /* Steal theme from info */
4281
 
      retval = info.theme;
4282
 
      info.theme = NULL;
4283
 
    }
4284
 
  else
4285
 
    {
4286
 
      g_set_error (err, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
4287
 
                   _("Theme file %s did not contain a root <metacity_theme> element"),
4288
 
                   info.theme_file);
4289
 
    }
4290
 
 
4291
 
  parse_info_free (&info);
4292
4476
 
4293
4477
  return retval;
4294
4478
}