rofi  1.7.5
theme.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2013-2022 Qball Cow <qball@gmpclient.org>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  */
27 
29 #define G_LOG_DOMAIN "Theme"
30 
31 #include "config.h"
32 #include <errno.h>
33 #include <math.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 // GFile stuff.
38 #include "helper.h"
39 #include "rofi-icon-fetcher.h"
40 #include "rofi-types.h"
41 #include "rofi.h"
42 #include "settings.h"
43 #include "theme-parser.h"
44 #include "theme.h"
45 #include "view.h"
46 #include "widgets/textbox.h"
47 #include <gio/gio.h>
48 
49 GList *parsed_config_files = NULL;
50 
52  g_list_free_full(parsed_config_files, g_free);
53  parsed_config_files = NULL;
54 }
55 
56 void rofi_theme_print_parsed_files(gboolean is_term) {
57  printf("\nParsed files:\n");
58  for (GList *iter = g_list_first(parsed_config_files); iter != NULL;
59  iter = g_list_next(iter)) {
60  printf("\t\u2022 %s%s%s\n", is_term ? color_bold : "",
61  (const char *)(iter->data), is_term ? color_reset : "");
62  }
63  printf("\n");
64 }
65 
66 void yyerror(YYLTYPE *yylloc, const char *, const char *);
68  // TODO UPDATE
69  return d.base.type == e.base.type && d.base.distance == e.base.distance &&
70  d.style == e.style;
71 }
72 
74  const char *name) {
75  for (unsigned int i = 0; i < base->num_widgets; i++) {
76  if (g_strcmp0(base->widgets[i]->name, name) == 0) {
77  return base->widgets[i];
78  }
79  }
80 
81  base->widgets =
82  g_realloc(base->widgets, sizeof(ThemeWidget *) * (base->num_widgets + 1));
83  base->widgets[base->num_widgets] = g_slice_new0(ThemeWidget);
84  ThemeWidget *retv = base->widgets[base->num_widgets];
85  retv->parent = base;
86  retv->name = g_strdup(name);
87  base->num_widgets++;
88  return retv;
89 }
94  Property *retv = g_slice_new0(Property);
95  retv->type = type;
96  return retv;
97 }
98 
99 static RofiDistanceUnit *
101  RofiDistanceUnit *retv = g_slice_new0(RofiDistanceUnit);
102  *retv = *unit;
103  if (unit->left) {
105  }
106  if (unit->right) {
108  }
109  return retv;
110 }
112  RofiDistance retv = distance;
113  if (distance.base.left) {
115  }
116  if (distance.base.right) {
117  retv.base.right =
119  }
120  return retv;
121 }
122 
124  G_GNUC_UNUSED void *data) {
126  retv->name = g_strdup(p->name);
127 
128  switch (p->type) {
129  case P_STRING:
130  retv->value.s = g_strdup(p->value.s);
131  break;
132  case P_LIST:
133  retv->value.list = g_list_copy_deep(
134  p->value.list, (GCopyFunc)rofi_theme_property_copy, NULL);
135  break;
136  case P_LINK:
137  retv->value.link.name = g_strdup(p->value.link.name);
138  retv->value.link.ref = NULL;
139  if (p->value.link.def_value) {
140  retv->value.link.def_value =
142  }
143  break;
144  case P_PADDING: {
145  retv->value = p->value;
146  retv->value.padding.top =
148  retv->value.padding.left =
150  retv->value.padding.bottom =
152  retv->value.padding.right =
154  break;
155  }
156  case P_IMAGE: {
157  retv->value = p->value;
158  retv->value.image.url = g_strdup(p->value.image.url);
159  retv->value.image.colors = NULL;
160  for (GList *l = g_list_first(p->value.image.colors); l;
161  l = g_list_next(l)) {
162  retv->value.image.colors = g_list_append(
163  retv->value.image.colors, g_memdup(l->data, sizeof(ThemeColor)));
164  }
165  break;
166  }
167  default:
168  retv->value = p->value;
169  }
170  return retv;
171 }
172 
174  if (unit->left) {
176  unit->left = NULL;
177  }
178  if (unit->right) {
180  unit->right = NULL;
181  }
182  g_slice_free(RofiDistanceUnit, unit);
183 }
185  if (distance->base.left) {
187  distance->base.left = NULL;
188  }
189  if (distance->base.right) {
191  distance->base.right = NULL;
192  }
193 }
194 
196  if (p == NULL) {
197  return;
198  }
199  g_free(p->name);
200  if (p->type == P_STRING) {
201  g_free(p->value.s);
202  } else if (p->type == P_LIST) {
203  g_list_free_full(p->value.list, (GDestroyNotify)rofi_theme_property_free);
204  p->value.list = 0;
205  } else if (p->type == P_LINK) {
206  g_free(p->value.link.name);
207  if (p->value.link.def_value) {
209  }
210  } else if (p->type == P_PADDING) {
215  } else if (p->type == P_IMAGE) {
216  if (p->value.image.url) {
217  g_free(p->value.image.url);
218  }
219  if (p->value.image.colors) {
220  g_list_free_full(p->value.image.colors, g_free);
221  }
222  }
223  g_slice_free(Property, p);
224 }
225 
226 void rofi_theme_reset(void) {
228  rofi_theme = g_slice_new0(ThemeWidget);
229  rofi_theme->name = g_strdup("Root");
230 }
231 
233  if (widget == NULL) {
234  return;
235  }
236  if (widget->properties) {
237  g_hash_table_destroy(widget->properties);
238  widget->properties = NULL;
239  }
240  if (widget->media) {
241  g_slice_free(ThemeMedia, widget->media);
242  }
243  for (unsigned int i = 0; i < widget->num_widgets; i++) {
244  rofi_theme_free(widget->widgets[i]);
245  }
246  g_free(widget->widgets);
247  g_free(widget->name);
248  g_slice_free(ThemeWidget, widget);
249 }
250 
254 inline static void printf_double(double d) {
255  char buf[G_ASCII_DTOSTR_BUF_SIZE + 1] = {
256  0,
257  };
258  g_ascii_formatd(buf, G_ASCII_DTOSTR_BUF_SIZE, "%.4f", d);
259  fputs(buf, stdout);
260 }
261 
263  if (unit->modtype == ROFI_DISTANCE_MODIFIER_GROUP) {
264  fputs("( ", stdout);
265  }
266  if (unit->left) {
268  }
269 
270  if (unit->modtype == ROFI_DISTANCE_MODIFIER_ADD) {
271  fputs(" + ", stdout);
272  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_SUBTRACT) {
273  fputs(" - ", stdout);
274  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_DIVIDE) {
275  fputs(" / ", stdout);
276  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_MULTIPLY) {
277  fputs(" * ", stdout);
278  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_MODULO) {
279  fputs(" % ", stdout);
280  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_MIN) {
281  fputs(" min ", stdout);
282  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_MAX) {
283  fputs(" max ", stdout);
284  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_ROUND) {
285  fputs(" round ", stdout);
286  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_FLOOR) {
287  fputs(" floor ", stdout);
288  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_CEIL) {
289  fputs(" ceil ", stdout);
290  }
291  if (unit->right) {
293  }
294 
295  if (unit->modtype == ROFI_DISTANCE_MODIFIER_NONE) {
296  if (unit->type == ROFI_PU_PX) {
297  printf("%upx ", (unsigned int)unit->distance);
298  } else if (unit->type == ROFI_PU_MM) {
299  printf_double(unit->distance);
300  fputs("mm ", stdout);
301  } else if (unit->type == ROFI_PU_PERCENT) {
302  printf_double(unit->distance);
303  fputs("% ", stdout);
304  } else if (unit->type == ROFI_PU_CH) {
305  printf_double(unit->distance);
306  fputs("ch ", stdout);
307  } else {
308  printf_double(unit->distance);
309  fputs("em ", stdout);
310  }
311  }
312  if (unit->modtype == ROFI_DISTANCE_MODIFIER_GROUP) {
313  fputs(" )", stdout);
314  }
315 }
316 
317 static void rofi_theme_print_color(ThemeColor color) {
318  uint8_t r, g, b;
319  g = 255 * color.green;
320  r = 255 * color.red;
321  b = 255 * color.blue;
322  if (color.alpha < 0.00001) {
323  printf("transparent");
324  return;
325  }
326  for (uint32_t x = 0; x < num_CSSColors; x++) {
327  if (CSSColors[x].r == r && CSSColors[x].g == g && CSSColors[x].b == b) {
328  printf("%s", CSSColors[x].name);
329  if (color.alpha < 1) {
330  printf("/%.0f%%", color.alpha * 100.0);
331  }
332  return;
333  }
334  }
335  printf("rgba ( %.0f, %.0f, %.0f, %.0f %% )", (color.red * 255.0),
336  (color.green * 255.0), (color.blue * 255.0), (color.alpha * 100.0));
337 }
340  fputs("calc( ", stdout);
341  }
344  fputs(")", stdout);
345  }
346  if (d.style == ROFI_HL_DASH) {
347  printf("dash ");
348  }
349 }
351 const char *const RofiCursorTypeStr[3] = {
352  "default",
353  "pointer",
354  "text",
355 };
356 
358  switch (p->type) {
359  case P_LIST:
360  printf("[ ");
361  for (GList *iter = p->value.list; iter != NULL; iter = g_list_next(iter)) {
363  if (iter->next != NULL) {
364  printf(",");
365  }
366  }
367  printf(" ]");
368  break;
369  case P_ORIENTATION:
370  printf("%s", (p->value.i == ROFI_ORIENTATION_HORIZONTAL) ? "horizontal"
371  : "vertical");
372  break;
373  case P_CURSOR:
374  printf("%s", RofiCursorTypeStr[p->value.i]);
375  break;
376  case P_HIGHLIGHT:
377  if (p->value.highlight.style & ROFI_HL_BOLD) {
378  printf("bold ");
379  }
381  printf("underline ");
382  }
384  printf("strikethrough ");
385  }
386  if (p->value.highlight.style & ROFI_HL_ITALIC) {
387  printf("italic ");
388  }
390  printf("uppercase ");
391  }
393  printf("lowercase ");
394  }
396  printf("capitalize ");
397  }
398  if (p->value.highlight.style & ROFI_HL_COLOR) {
400  }
401  break;
402  case P_POSITION: {
403  switch (p->value.i) {
404  case WL_CENTER:
405  fputs("center", stdout);
406  break;
407  case WL_NORTH:
408  fputs("north", stdout);
409  break;
410  case WL_SOUTH:
411  fputs("south", stdout);
412  break;
413  case WL_WEST:
414  fputs("west", stdout);
415  break;
416  case WL_EAST:
417  fputs("east", stdout);
418  break;
419  case WL_NORTH | WL_EAST:
420  fputs("northeast", stdout);
421  break;
422  case WL_SOUTH | WL_EAST:
423  fputs("southeast", stdout);
424  break;
425  case WL_NORTH | WL_WEST:
426  fputs("northwest", stdout);
427  break;
428  case WL_SOUTH | WL_WEST:
429  fputs("southwest", stdout);
430  break;
431  }
432  break;
433  }
434  case P_STRING:
435  printf("\"%s\"", p->value.s);
436  break;
437  case P_INTEGER:
438  printf("%d", p->value.i);
439  break;
440  case P_DOUBLE: {
441  char sign = (p->value.f < 0);
442  int top = (int)fabs(p->value.f);
443  int bottom = (fabs(fmod(p->value.f, 1.0))) * 100;
444  printf("%s%d.%02d", sign ? "-" : "", top, bottom);
445  break;
446  }
447  case P_BOOLEAN:
448  printf("%s", p->value.b ? "true" : "false");
449  break;
450  case P_COLOR:
452  break;
453  case P_IMAGE: {
454  if (p->value.image.type == ROFI_IMAGE_URL) {
455  printf("url (\"%s\")", p->value.s);
456  } else if (p->value.image.type == ROFI_IMAGE_LINEAR_GRADIENT) {
457  printf("linear-gradient ( ");
458  guint length = g_list_length(p->value.image.colors);
459  guint index = 0;
460  for (GList *l = g_list_first(p->value.image.colors); l != NULL;
461  l = g_list_next(l)) {
462  ThemeColor *color = (ThemeColor *)l->data;
463  rofi_theme_print_color(*color);
464  index++;
465  if (index < length) {
466  printf(", ");
467  }
468  }
469  printf(")");
470  }
471 
472  break;
473  }
474  case P_PADDING:
479  } else if (distance_compare(p->value.padding.top,
480  p->value.padding.bottom) &&
482  p->value.padding.right)) {
485  } else if (!distance_compare(p->value.padding.top,
486  p->value.padding.bottom) &&
488  p->value.padding.right)) {
492  } else {
497  }
498  break;
499  case P_LINK:
500  if (p->value.link.def_value) {
501  printf("var( %s, ", p->value.link.name);
503  printf(")");
504  } else {
505  printf("var(%s)", p->value.link.name);
506  }
507  break;
508  case P_INHERIT:
509  printf("inherit");
510  break;
511  default:
512  break;
513  }
514 }
515 
516 static void rofi_theme_print_property_index(size_t pnl, int depth,
517  Property *p) {
518  int pl = strlen(p->name);
519  printf("%*s%s:%*s ", depth, "", p->name, (int)pnl - pl, "");
521  putchar(';');
522  putchar('\n');
523 }
524 
526  GHashTableIter iter;
527  gpointer key, value;
528 
529  if (widget->media) {
530  printf("%s {\n", widget->name);
531  for (unsigned int i = 0; i < widget->num_widgets; i++) {
532  rofi_theme_print_index(widget->widgets[i], index + 4);
533  }
534  printf("}\n");
535  } else {
536  if (widget->properties) {
537  GList *list = NULL;
538  ThemeWidget *w = widget;
539  while (w) {
540  if (g_strcmp0(w->name, "Root") == 0) {
541  break;
542  }
543  if (w->media) {
544  break;
545  }
546  list = g_list_prepend(list, w->name);
547  w = w->parent;
548  }
549  if (g_list_length(list) > 0) {
550  printf("%*s", index, "");
551  for (GList *citer = g_list_first(list); citer != NULL;
552  citer = g_list_next(citer)) {
553  char *name = (char *)citer->data;
554  fputs(name, stdout);
555  if (citer->prev == NULL && citer->next) {
556  putchar(' ');
557  } else if (citer->next) {
558  putchar('.');
559  }
560  }
561  printf(" {\n");
562  } else {
563  printf("%*s* {\n", index, "");
564  }
565  size_t property_name_length = 0;
566  g_hash_table_iter_init(&iter, widget->properties);
567  while (g_hash_table_iter_next(&iter, &key, &value)) {
568  Property *pv = (Property *)value;
569  property_name_length = MAX(strlen(pv->name), property_name_length);
570  }
571  g_hash_table_iter_init(&iter, widget->properties);
572  while (g_hash_table_iter_next(&iter, &key, &value)) {
573  Property *pv = (Property *)value;
574  rofi_theme_print_property_index(property_name_length, index + 4, pv);
575  }
576  printf("%*s}\n", index, "");
577  g_list_free(list);
578  }
579  for (unsigned int i = 0; i < widget->num_widgets; i++) {
580  rofi_theme_print_index(widget->widgets[i], index);
581  }
582  }
583 }
584 
586  if (widget != NULL) {
587  printf("/**\n * rofi -dump-theme output.\n * Rofi version: %s\n **/\n",
588  PACKAGE_VERSION);
590  }
591 }
592 
596 int yyparse();
597 
601 void yylex_destroy(void);
602 
606 extern FILE *yyin;
607 
615 void yyerror(YYLTYPE *yylloc, const char *what, const char *s) {
616  char *what_esc = what ? g_markup_escape_text(what, -1) : g_strdup("");
617  GString *str = g_string_new("");
618  g_string_printf(str,
619  "<big><b>Error while parsing theme:</b></big> <i>%s</i>\n",
620  what_esc);
621  g_free(what_esc);
622  char *esc = g_markup_escape_text(s, -1);
623  g_string_append_printf(
624  str,
625  "\tParser error: <span size=\"smaller\" style=\"italic\">%s</span>\n",
626  esc);
627  g_free(esc);
628  if (yylloc->filename != NULL) {
629  g_string_append_printf(
630  str,
631  "\tLocation: line %d column %d to line %d column %d.\n"
632  "\tFile '%s'\n",
633  yylloc->first_line, yylloc->first_column, yylloc->last_line,
634  yylloc->last_column, yylloc->filename);
635  } else {
636  g_string_append_printf(
637  str, "\tLocation: line %d column %d to line %d column %d\n",
638  yylloc->first_line, yylloc->first_column, yylloc->last_line,
639  yylloc->last_column);
640  }
641  g_log("Parser", G_LOG_LEVEL_DEBUG, "Failed to parse theme:\n%s", str->str);
643 }
644 
645 static void rofi_theme_copy_property_int(G_GNUC_UNUSED gpointer key,
646  gpointer value, gpointer user_data) {
647  GHashTable *table = (GHashTable *)user_data;
648  Property *p = rofi_theme_property_copy((Property *)value, NULL);
649  g_hash_table_replace(table, p->name, p);
650 }
652  if (table == NULL) {
653  return;
654  }
655  if (widget->properties == NULL) {
656  widget->properties =
657  g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
658  (GDestroyNotify)rofi_theme_property_free);
659  }
660  g_hash_table_foreach(table, rofi_theme_copy_property_int, widget->properties);
661 }
662 
668  const char *name) {
669  for (unsigned int j = 0; widget && j < widget->num_widgets; j++) {
670  if (g_strcmp0(widget->widgets[j]->name, name) == 0) {
671  return widget->widgets[j];
672  }
673  }
674  return widget;
675 }
676 
677 static ThemeWidget *rofi_theme_find(ThemeWidget *widget, const char *name,
678  const gboolean exact) {
679  if (widget == NULL || name == NULL) {
680  return widget;
681  }
682  char *tname = g_strdup(name);
683  char *saveptr = NULL;
684  int found = TRUE;
685  for (const char *iter = strtok_r(tname, ".", &saveptr); iter != NULL;
686  iter = strtok_r(NULL, ".", &saveptr)) {
687  found = FALSE;
689  if (f != widget) {
690  widget = f;
691  found = TRUE;
692  } else if (exact) {
693  break;
694  }
695  }
696  g_free(tname);
697  if (!exact || found) {
698  return widget;
699  }
700  return NULL;
701 }
702 
704  // Set name, remove '@' prefix.
705  const char *name = p->value.link.name; // + (*(p->value.link.name)== '@'?1:0;
706  g_info("Resolving link to %s", p->value.link.name);
707  if (depth > 20) {
708  g_warning("Found more then 20 redirects for property. Stopping.");
709  p->value.link.ref = p;
710  return;
711  }
712 
713  if (rofi_theme->properties &&
714  g_hash_table_contains(rofi_theme->properties, name)) {
715  Property *pr = g_hash_table_lookup(rofi_theme->properties, name);
716  g_info("Resolving link %s found: %s", p->value.link.name, pr->name);
717  if (pr->type == P_LINK) {
718  if (pr->value.link.ref == NULL) {
720  }
721  if (pr->value.link.ref != pr) {
722  p->value.link.ref = pr->value.link.ref;
723  return;
724  }
725  } else {
726  p->value.link.ref = pr;
727  return;
728  }
729  }
730  // No found and we have default value.
731  if (p->value.link.def_value) {
732  p->value.link.ref = p->value.link.def_value;
733  return;
734  }
735 
736  // No found, set ref to self.
737  p->value.link.ref = p;
738 }
739 
741  const char *property, gboolean exact) {
742  while (widget) {
743  if (widget->properties &&
744  g_hash_table_contains(widget->properties, property)) {
745  Property *p = g_hash_table_lookup(widget->properties, property);
746  if (p->type == P_INHERIT) {
747  return p;
748  }
749  if (p->type == P_LINK) {
750  if (p->value.link.ref == NULL) {
751  // Resolve link.
753  }
754  if (p->value.link.ref != NULL && p->value.link.ref->type == type) {
755  return p->value.link.ref;
756  }
757  }
758  if (p->type == type) {
759  return p;
760  }
761  // RofiPadding and integer can be converted.
762  if (p->type == P_INTEGER && type == P_PADDING) {
763  return p;
764  }
765  g_debug("Found property: '%s' on '%s', but type %s does not match "
766  "expected type %s.",
767  property, widget->name, PropertyTypeName[p->type],
768  PropertyTypeName[type]);
769  }
770  if (exact) {
771  return NULL;
772  }
773  // Fall back to defaults.
774  widget = widget->parent;
775  }
776  return NULL;
777 }
778 ThemeWidget *rofi_config_find_widget(const char *name, const char *state,
779  gboolean exact) {
780  // First find exact match based on name.
782  widget = rofi_theme_find(widget, state, exact);
783 
784  return widget;
785 }
786 ThemeWidget *rofi_theme_find_widget(const char *name, const char *state,
787  gboolean exact) {
788  // First find exact match based on name.
790  widget = rofi_theme_find(widget, state, exact);
791 
792  return widget;
793 }
794 
796  const char *property, int def) {
797  if (p) {
798  if (p->type == P_INHERIT) {
799  if (widget->parent) {
800  ThemeWidget *parent =
802  Property *pv =
803  rofi_theme_find_property(parent, P_POSITION, property, FALSE);
804  return rofi_theme_get_position_inside(pv, widget->parent, property,
805  def);
806  }
807  return def;
808  }
809  return p->value.i;
810  }
811  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
812  widget->state ? widget->state : "", property);
813  return def;
814 }
815 int rofi_theme_get_position(const widget *widget, const char *property,
816  int def) {
818  Property *p = rofi_theme_find_property(wid, P_POSITION, property, FALSE);
819  return rofi_theme_get_position_inside(p, widget, property, def);
820 }
822  const char *property, int def) {
823  if (p) {
824  if (p->type == P_INHERIT) {
825  if (widget->parent) {
826  ThemeWidget *parent =
828  Property *pv =
829  rofi_theme_find_property(parent, P_INTEGER, property, FALSE);
830  return rofi_theme_get_integer_inside(pv, widget->parent, property, def);
831  }
832  return def;
833  }
834  return p->value.i;
835  }
836  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
837  widget->state ? widget->state : "", property);
838  return def;
839 }
840 int rofi_theme_get_integer(const widget *widget, const char *property,
841  int def) {
843  Property *p = rofi_theme_find_property(wid, P_INTEGER, property, FALSE);
844  return (int)rofi_theme_get_integer_inside(p, widget, property, (double)def);
845 }
847  const widget *widget,
848  const char *property,
849  int def) {
850  if (p) {
851  if (p->type == P_INHERIT) {
852  if (widget->parent) {
853  ThemeWidget *parent =
855  Property *pv =
856  rofi_theme_find_property(parent, P_PADDING, property, FALSE);
857  return rofi_theme_get_distance_inside(pv, widget->parent, property,
858  def);
859  }
860  return (RofiDistance){
861  .base = {def, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},
862  .style = ROFI_HL_SOLID};
863  }
864  if (p->type == P_INTEGER) {
865  return (RofiDistance){.base = {p->value.i, ROFI_PU_PX,
866  ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},
867  .style = ROFI_HL_SOLID};
868  }
869  return p->value.padding.left;
870  }
871  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
872  widget->state ? widget->state : "", property);
873  return (RofiDistance){
874  .base = {def, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},
875  .style = ROFI_HL_SOLID};
876 }
877 RofiDistance rofi_theme_get_distance(const widget *widget, const char *property,
878  int def) {
880  Property *p = rofi_theme_find_property(wid, P_PADDING, property, FALSE);
881  return rofi_theme_get_distance_inside(p, widget, property, def);
882 }
883 
885  const char *property, int def) {
886  if (p) {
887  if (p->type == P_INHERIT) {
888  if (widget->parent) {
889  ThemeWidget *parent =
891  Property *pv =
892  rofi_theme_find_property(parent, P_BOOLEAN, property, FALSE);
893  return rofi_theme_get_boolean_inside(pv, widget->parent, property, def);
894  }
895  return def;
896  }
897  return p->value.b;
898  }
899  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
900  widget->state ? widget->state : "", property);
901  return def;
902 }
903 int rofi_theme_get_boolean(const widget *widget, const char *property,
904  int def) {
906  Property *p = rofi_theme_find_property(wid, P_BOOLEAN, property, FALSE);
907  return rofi_theme_get_boolean_inside(p, widget, property, def);
908 }
909 
911  const widget *widget,
912  const char *property,
913  RofiOrientation def) {
914  if (p) {
915  if (p->type == P_INHERIT) {
916  if (widget->parent) {
917  ThemeWidget *parent =
919  Property *pv =
920  rofi_theme_find_property(parent, P_ORIENTATION, property, FALSE);
921  return rofi_theme_get_orientation_inside(pv, widget->parent, property,
922  def);
923  }
924  return def;
925  }
926  return p->value.b;
927  }
928  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
929  widget->state ? widget->state : "", property);
930  return def;
931 }
933  const char *property,
934  RofiOrientation def) {
936  Property *p = rofi_theme_find_property(wid, P_ORIENTATION, property, FALSE);
937  return rofi_theme_get_orientation_inside(p, widget, property, def);
938 }
939 
941  const widget *widget,
942  const char *property,
943  RofiCursorType def) {
944  if (p) {
945  if (p->type == P_INHERIT) {
946  if (widget->parent) {
947  ThemeWidget *parent =
949  Property *pv =
950  rofi_theme_find_property(parent, P_CURSOR, property, FALSE);
951  return rofi_theme_get_cursor_type_inside(pv, widget->parent, property,
952  def);
953  }
954  return def;
955  }
956  return p->value.i;
957  }
958  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
959  widget->state ? widget->state : "", property);
960  return def;
961 }
963  const char *property,
964  RofiCursorType def) {
966  Property *p = rofi_theme_find_property(wid, P_CURSOR, property, FALSE);
967  return rofi_theme_get_cursor_type_inside(p, widget, property, def);
968 }
970  const widget *widget,
971  const char *property,
972  const char *def) {
973  if (p) {
974  if (p->type == P_INHERIT) {
975  if (widget->parent) {
976  ThemeWidget *parent =
978  Property *pv =
979  rofi_theme_find_property(parent, P_STRING, property, FALSE);
980  return rofi_theme_get_string_inside(pv, widget->parent, property, def);
981  }
982  return def;
983  }
984  return p->value.s;
985  }
986  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
987  widget->state ? widget->state : "", property);
988  return def;
989 }
990 const char *rofi_theme_get_string(const widget *widget, const char *property,
991  const char *def) {
993  Property *p = rofi_theme_find_property(wid, P_STRING, property, FALSE);
994  return rofi_theme_get_string_inside(p, widget, property, def);
995 }
996 
998  const widget *widget,
999  const char *property,
1000  double def) {
1001  if (p) {
1002  if (p->type == P_INHERIT) {
1003  if (widget->parent) {
1004  ThemeWidget *parent =
1006  Property *pv =
1007  rofi_theme_find_property(parent, P_INTEGER, property, FALSE);
1009  property, def);
1010  }
1011  return def;
1012  }
1013  return p->value.i;
1014  }
1015  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
1016  widget->state ? widget->state : "", property);
1017  return def;
1018 }
1019 static double rofi_theme_get_double_inside(const widget *orig, Property *p,
1020  const widget *widget,
1021  const char *property, double def) {
1022  if (p) {
1023  if (p->type == P_INHERIT) {
1024  if (widget->parent) {
1025  ThemeWidget *parent =
1027  Property *pv =
1028  rofi_theme_find_property(parent, P_DOUBLE, property, FALSE);
1029  return rofi_theme_get_double_inside(orig, pv, widget, property, def);
1030  }
1031  return def;
1032  }
1033  return p->value.f;
1034  }
1035  ThemeWidget *wid = rofi_theme_find_widget(orig->name, widget->state, FALSE);
1036  // Fallback to integer if double is not found.
1037  p = rofi_theme_find_property(wid, P_INTEGER, property, FALSE);
1038  return rofi_theme_get_double_integer_fb_inside(p, widget, property, def);
1039 }
1040 double rofi_theme_get_double(const widget *widget, const char *property,
1041  double def) {
1043  Property *p = rofi_theme_find_property(wid, P_DOUBLE, property, FALSE);
1044  return rofi_theme_get_double_inside(widget, p, widget, property, def);
1045 }
1047  const char *property, cairo_t *d) {
1048  if (p) {
1049  if (p->type == P_INHERIT) {
1050  if (widget->parent) {
1051  ThemeWidget *parent =
1053  Property *pv =
1054  rofi_theme_find_property(parent, P_COLOR, property, FALSE);
1055  rofi_theme_get_color_inside(widget->parent, pv, property, d);
1056  }
1057  return;
1058  }
1059  cairo_set_source_rgba(d, p->value.color.red, p->value.color.green,
1060  p->value.color.blue, p->value.color.alpha);
1061  } else {
1062  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
1063  widget->state ? widget->state : "", property);
1064  }
1065 }
1066 
1067 void rofi_theme_get_color(const widget *widget, const char *property,
1068  cairo_t *d) {
1070  Property *p = rofi_theme_find_property(wid, P_COLOR, property, FALSE);
1071  rofi_theme_get_color_inside(widget, p, property, d);
1072 }
1073 
1075  const char *property, cairo_t *d) {
1076  if (p) {
1077  if (p->type == P_INHERIT) {
1078  if (widget->parent) {
1079  ThemeWidget *parent =
1081  Property *pv =
1082  rofi_theme_find_property(parent, P_IMAGE, property, FALSE);
1083  return rofi_theme_get_image_inside(pv, widget->parent, property, d);
1084  }
1085  return FALSE;
1086  }
1087  if (p->value.image.type == ROFI_IMAGE_URL) {
1088  int wsize = -1;
1089  int hsize = -1;
1090  switch (p->value.image.scaling) {
1091  case ROFI_SCALE_BOTH:
1092  wsize = widget->w;
1093  hsize = widget->h;
1094  break;
1095  case ROFI_SCALE_WIDTH:
1096  wsize = widget->w;
1097  break;
1098  case ROFI_SCALE_HEIGHT:
1099  hsize = widget->h;
1100  break;
1101  case ROFI_SCALE_NONE:
1102  default:
1103  break;
1104  }
1105  if (p->value.image.surface_id == 0 || p->value.image.wsize != wsize ||
1106  p->value.image.hsize != hsize) {
1107  p->value.image.surface_id =
1108  rofi_icon_fetcher_query_advanced(p->value.image.url, wsize, hsize);
1109  p->value.image.wsize = wsize;
1110  p->value.image.hsize = hsize;
1111  }
1112  cairo_surface_t *img = rofi_icon_fetcher_get(p->value.image.surface_id);
1113 
1114  if (img != NULL) {
1115  cairo_pattern_t *pat = cairo_pattern_create_for_surface(img);
1116  cairo_pattern_set_extend(pat, CAIRO_EXTEND_REPEAT);
1117  cairo_set_source(d, pat);
1118  cairo_pattern_destroy(pat);
1119  return TRUE;
1120  }
1121  } else if (p->value.image.type == ROFI_IMAGE_LINEAR_GRADIENT) {
1122  cairo_pattern_t *pat = NULL;
1123  switch (p->value.image.dir) {
1124  case ROFI_DIRECTION_RIGHT:
1125  pat = cairo_pattern_create_linear(0.0, 0.0, widget->w, 0.0);
1126  break;
1127  case ROFI_DIRECTION_LEFT:
1128  pat = cairo_pattern_create_linear(widget->w, 0.0, 0.0, 0.0);
1129  break;
1130  case ROFI_DIRECTION_BOTTOM:
1131  pat = cairo_pattern_create_linear(0.0, 0.0, 0.0, widget->h);
1132  break;
1133  case ROFI_DIRECTION_TOP:
1134  pat = cairo_pattern_create_linear(0.0, widget->h, 0.0, 0.0);
1135  break;
1136  case ROFI_DIRECTION_ANGLE: {
1137  double offsety1 =
1138  sin(G_PI * 2 * p->value.image.angle) * (widget->h / 2.0);
1139  double offsetx1 =
1140  cos(G_PI * 2 * p->value.image.angle) * (widget->w / 2.0);
1141  pat = cairo_pattern_create_linear(
1142  widget->w / 2.0 - offsetx1, widget->h / 2.0 - offsety1,
1143  widget->w / 2.0 + offsetx1, widget->h / 2.0 + offsety1);
1144  break;
1145  }
1146  };
1147  guint length = g_list_length(p->value.image.colors);
1148  if (length > 1) {
1149  length--;
1150  guint color_index = 0;
1151  for (GList *l = g_list_first(p->value.image.colors); l != NULL;
1152  l = g_list_next(l)) {
1153  ThemeColor *c = (ThemeColor *)(l->data);
1154  cairo_pattern_add_color_stop_rgba(pat, (color_index) / (double)length,
1155  c->red, c->green, c->blue,
1156  c->alpha);
1157  color_index++;
1158  }
1159  cairo_set_source(d, pat);
1160  cairo_pattern_destroy(pat);
1161  return TRUE;
1162  }
1163  if (length == 1) {
1164  ThemeColor *c = (ThemeColor *)(p->value.image.colors->data);
1165  cairo_pattern_add_color_stop_rgba(pat, 0, c->red, c->green, c->blue,
1166  c->alpha);
1167  cairo_set_source(d, pat);
1168  cairo_pattern_destroy(pat);
1169  return TRUE;
1170  }
1171  }
1172  } else {
1173  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
1174  widget->state ? widget->state : "", property);
1175  }
1176  return FALSE;
1177 }
1178 gboolean rofi_theme_get_image(const widget *widget, const char *property,
1179  cairo_t *d) {
1181  Property *p = rofi_theme_find_property(wid, P_IMAGE, property, FALSE);
1182  return rofi_theme_get_image_inside(p, widget, property, d);
1183 }
1185  const widget *widget,
1186  const char *property,
1187  RofiPadding pad) {
1188  if (p) {
1189  if (p->type == P_INHERIT) {
1190  if (widget->parent) {
1191  ThemeWidget *parent =
1193  Property *pv =
1194  rofi_theme_find_property(parent, P_PADDING, property, FALSE);
1195  return rofi_theme_get_padding_inside(pv, widget->parent, property, pad);
1196  }
1197  return pad;
1198  }
1199  if (p->type == P_PADDING) {
1200  pad = p->value.padding;
1201  } else {
1202  RofiDistance d =
1203  (RofiDistance){.base = {p->value.i, ROFI_PU_PX,
1204  ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},
1205  .style = ROFI_HL_SOLID};
1206  return (RofiPadding){d, d, d, d};
1207  }
1208  }
1209  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
1210  widget->state ? widget->state : "", property);
1211  return pad;
1212 }
1213 RofiPadding rofi_theme_get_padding(const widget *widget, const char *property,
1214  RofiPadding pad) {
1216  Property *p = rofi_theme_find_property(wid, P_PADDING, property, FALSE);
1217  return rofi_theme_get_padding_inside(p, widget, property, pad);
1218 }
1219 
1221  const char *property,
1222  PropertyType child_type) {
1223  if (p) {
1224  if (p->type == P_INHERIT) {
1225  if (widget->parent) {
1226  ThemeWidget *parent =
1228  Property *pv =
1229  rofi_theme_find_property(parent, P_LIST, property, FALSE);
1230  return rofi_theme_get_list_inside(pv, widget->parent, property,
1231  child_type);
1232  }
1233  } else if (p->type == P_LIST) {
1234  return p->value.list;
1235  }
1236  }
1237  return NULL;
1238 }
1240  const char *property) {
1241  ThemeWidget *wid2 =
1243  Property *p = rofi_theme_find_property(wid2, P_LIST, property, FALSE);
1244  GList *list = rofi_theme_get_list_inside(p, widget, property, P_PADDING);
1245  GList *retv = NULL;
1246  for (GList *iter = g_list_first(list); iter != NULL;
1247  iter = g_list_next(iter)) {
1248  Property *prop = (Property *)(iter->data);
1249  if (prop->type == P_PADDING) {
1250  RofiDistance *pnew = g_new0(RofiDistance, 1);
1251  *pnew = prop->value.padding.left;
1252  retv = g_list_append(retv, pnew);
1253  } else if (prop->type == P_INTEGER) {
1254  RofiDistance *pnew = g_new0(RofiDistance, 1);
1255  RofiDistance d =
1256  (RofiDistance){.base = {prop->value.i, ROFI_PU_PX,
1257  ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},
1258  .style = ROFI_HL_SOLID};
1259  *pnew = d;
1260  retv = g_list_append(retv, pnew);
1261  } else {
1262  g_warning("Invalid type detected in list.");
1263  }
1264  }
1265  return retv;
1266 }
1267 GList *rofi_theme_get_list_strings(const widget *widget, const char *property) {
1268  ThemeWidget *wid2 =
1270  Property *p = rofi_theme_find_property(wid2, P_LIST, property, FALSE);
1271  GList *list = rofi_theme_get_list_inside(p, widget, property, P_STRING);
1272  GList *retv = NULL;
1273  for (GList *iter = g_list_first(list); iter != NULL;
1274  iter = g_list_next(iter)) {
1275  Property *prop = (Property *)(iter->data);
1276  if (prop->type == P_STRING) {
1277  retv = g_list_append(retv, g_strdup(prop->value.s));
1278  } else {
1279  g_warning("Invalid type detected in list.");
1280  }
1281  }
1282  return retv;
1283 }
1284 
1287  const char *property,
1289  if (p) {
1290  if (p->type == P_INHERIT) {
1291  if (widget->parent) {
1292  ThemeWidget *parent =
1294  Property *pv =
1295  rofi_theme_find_property(parent, P_HIGHLIGHT, property, FALSE);
1296  return rofi_theme_get_highlight_inside(pv, widget->parent, property,
1297  th);
1298  }
1299  return th;
1300  } else if (p->type == P_COLOR) {
1302  th.color = p->value.color;
1303  return th;
1304  }
1305 
1306  return p->value.highlight;
1307  } else {
1308  ThemeWidget *wid =
1310  Property *p2 = rofi_theme_find_property(wid, P_COLOR, property, FALSE);
1311  if (p2 != NULL) {
1312  return rofi_theme_get_highlight_inside(p2, widget, property, th);
1313  }
1314  return th;
1315  }
1316  g_debug("Theme entry: #%s %s property %s unset.", widget->name,
1317  widget->state ? widget->state : "", property);
1318  return th;
1319 }
1321  const char *property,
1324  Property *p = rofi_theme_find_property(wid, P_HIGHLIGHT, property, FALSE);
1325  if (p == NULL) {
1326  p = rofi_theme_find_property(wid, P_COLOR, property, FALSE);
1327  }
1328  return rofi_theme_get_highlight_inside(p, widget, property, th);
1329 }
1331  int val = unit->distance;
1332 
1333  if (unit->type == ROFI_PU_EM) {
1335  } else if (unit->type == ROFI_PU_CH) {
1336  val = unit->distance * textbox_get_estimated_ch();
1337  } else if (unit->type == ROFI_PU_PERCENT) {
1338  if (ori == ROFI_ORIENTATION_VERTICAL) {
1339  int height = 0;
1340  rofi_view_get_current_monitor(NULL, &height);
1341  val = (unit->distance * height) / (100.0);
1342  } else {
1343  int width = 0;
1344  rofi_view_get_current_monitor(&width, NULL);
1345  val = (unit->distance * width) / (100.0);
1346  }
1347  } else if (unit->type == ROFI_PU_MM) {
1348  val = unit->distance * config.dpi / 25.4;
1349  }
1350  return val;
1351 }
1352 
1354  RofiOrientation ori) {
1355  switch (unit->modtype) {
1357  return distance_unit_get_pixel(unit->left, ori);
1358  break;
1360  return distance_unit_get_pixel(unit->left, ori) +
1361  distance_unit_get_pixel(unit->right, ori);
1363  return distance_unit_get_pixel(unit->left, ori) -
1364  distance_unit_get_pixel(unit->right, ori);
1366  return distance_unit_get_pixel(unit->left, ori) *
1367  distance_unit_get_pixel(unit->right, ori);
1369  int a = distance_unit_get_pixel(unit->left, ori);
1370  int b = distance_unit_get_pixel(unit->right, ori);
1371  if (b != 0) {
1372  return a / b;
1373  }
1374  return a;
1375  }
1377  int a = distance_unit_get_pixel(unit->left, ori);
1378  int b = distance_unit_get_pixel(unit->right, ori);
1379  if (b != 0) {
1380  return a % b;
1381  }
1382  return 0;
1383  }
1385  int a = distance_unit_get_pixel(unit->left, ori);
1386  int b = distance_unit_get_pixel(unit->right, ori);
1387  return MIN(a, b);
1388  }
1390  int a = distance_unit_get_pixel(unit->left, ori);
1391  int b = distance_unit_get_pixel(unit->right, ori);
1392  return MAX(a, b);
1393  }
1395  double a = (double)distance_unit_get_pixel(unit->left, ori);
1396  double b = (double)distance_unit_get_pixel(unit->right, ori);
1397  return (int)(round(a / b) * b);
1398  }
1400  double a = (double)distance_unit_get_pixel(unit->left, ori);
1401  double b = (double)distance_unit_get_pixel(unit->right, ori);
1402  return (int)(ceil(a / b) * b);
1403  }
1405  double a = (double)distance_unit_get_pixel(unit->left, ori);
1406  double b = (double)distance_unit_get_pixel(unit->right, ori);
1407  return (int)(floor(a / b) * b);
1408  }
1409  default:
1410  break;
1411  }
1412  return get_pixels(unit, ori);
1413 }
1414 
1416  return distance_unit_get_pixel(&(d.base), ori);
1417 }
1418 
1419 void distance_get_linestyle(RofiDistance d, cairo_t *draw) {
1420  if (d.style == ROFI_HL_DASH) {
1421  const double dashes[1] = {4};
1422  cairo_set_dash(draw, dashes, 1, 0.0);
1423  } else {
1424  cairo_set_dash(draw, NULL, 0, 0.0);
1425  }
1426 }
1427 
1428 char *rofi_theme_parse_prepare_file(const char *file, const char *parent_file) {
1429  char *filename = rofi_expand_path(file);
1430  // If no absolute path specified, expand it.
1431  if (parent_file != NULL && !g_path_is_absolute(filename)) {
1432  char *basedir = g_path_get_dirname(parent_file);
1433  char *path = g_build_filename(basedir, filename, NULL);
1434  g_free(filename);
1435  filename = path;
1436  g_free(basedir);
1437  }
1438  GFile *gf = g_file_new_for_path(filename);
1439  parsed_config_files = g_list_append(parsed_config_files, filename);
1440  filename = g_file_get_path(gf);
1441  g_object_unref(gf);
1442 
1443  return filename;
1444 }
1445 
1447  g_assert(parent != NULL);
1448  g_assert(child != NULL);
1449 
1450  if (parent == rofi_theme && g_strcmp0(child->name, "*") == 0) {
1452  return;
1453  }
1454 
1455  ThemeWidget *w = rofi_theme_find_or_create_name(parent, child->name);
1456  if (child->media) {
1457  w->media = g_slice_new0(ThemeMedia);
1458  *(w->media) = *(child->media);
1459  }
1461  for (unsigned int i = 0; i < child->num_widgets; i++) {
1463  }
1464 }
1465 
1467  ThemeWidget *rwidget) {
1468  if (rwidget == NULL) {
1469  return;
1470  }
1471  unsigned int i = 0;
1472  // for (unsigned int i = 0; i < rwidget->num_widgets; i++) {
1473  while (i < rwidget->num_widgets) {
1474  ThemeWidget *widget = rwidget->widgets[i];
1475  if (widget->media != NULL) {
1476  rwidget->num_widgets--;
1477  for (unsigned x = i; x < rwidget->num_widgets; x++) {
1478  rwidget->widgets[x] = rwidget->widgets[x + 1];
1479  }
1480  rwidget->widgets[rwidget->num_widgets] = NULL;
1481  switch (widget->media->type) {
1483  int w = widget->media->value;
1484  if (mon.w >= w) {
1485  for (unsigned int x = 0; x < widget->num_widgets; x++) {
1486  rofi_theme_parse_merge_widgets(rwidget, widget->widgets[x]);
1487  }
1488  }
1489  break;
1490  }
1492  int w = widget->media->value;
1493  if (mon.w < w) {
1494  for (unsigned int x = 0; x < widget->num_widgets; x++) {
1495  rofi_theme_parse_merge_widgets(rwidget, widget->widgets[x]);
1496  }
1497  }
1498  break;
1499  }
1501  int h = widget->media->value;
1502  if (mon.h >= h) {
1503  for (unsigned int x = 0; x < widget->num_widgets; x++) {
1504  rofi_theme_parse_merge_widgets(rwidget, widget->widgets[x]);
1505  }
1506  } else {
1507  }
1508  break;
1509  }
1511  int h = widget->media->value;
1512  if (mon.h < h) {
1513  for (unsigned int x = 0; x < widget->num_widgets; x++) {
1514  rofi_theme_parse_merge_widgets(rwidget, widget->widgets[x]);
1515  }
1516  }
1517  break;
1518  }
1519  case THEME_MEDIA_TYPE_MON_ID: {
1520  if (mon.monitor_id == widget->media->value) {
1521  for (unsigned int x = 0; x < widget->num_widgets; x++) {
1522  rofi_theme_parse_merge_widgets(rwidget, widget->widgets[x]);
1523  }
1524  }
1525  break;
1526  }
1528  double r = widget->media->value;
1529  if ((mon.w / (double)mon.h) >= r) {
1530  for (unsigned int x = 0; x < widget->num_widgets; x++) {
1531  rofi_theme_parse_merge_widgets(rwidget, widget->widgets[x]);
1532  }
1533  }
1534  break;
1535  }
1537  double r = widget->media->value;
1538  if ((mon.w / (double)mon.h) < r) {
1539  for (unsigned int x = 0; x < widget->num_widgets; x++) {
1540  rofi_theme_parse_merge_widgets(rwidget, widget->widgets[x]);
1541  }
1542  }
1543  break;
1544  }
1545  case THEME_MEDIA_TYPE_BOOLEAN: {
1546  if (widget->media->boolv) {
1547  for (unsigned int x = 0; x < widget->num_widgets; x++) {
1548  rofi_theme_parse_merge_widgets(rwidget, widget->widgets[x]);
1549  }
1550  }
1551  break;
1552  }
1553 
1554  default: {
1555  break;
1556  }
1557  }
1559  // endif
1560  } else {
1562  i++;
1563  }
1564  }
1565 }
1566 
1568  GString *str = g_string_new(wid->name);
1569  for (ThemeWidget *i = wid->parent; i->parent != NULL; i = i->parent) {
1570  g_string_prepend_c(str, ' ');
1571  g_string_prepend(str, i->name);
1572  }
1573  char *retv = str->str;
1574  g_string_free(str, FALSE);
1575  return retv;
1576 }
1577 
1579  if (wid == NULL) {
1580  return;
1581  }
1582 
1583  for (unsigned int i = 0; i < wid->num_widgets; i++) {
1584  ThemeWidget *widget = wid->widgets[i];
1586  if (widget->properties == NULL) {
1587  continue;
1588  }
1589  GHashTableIter iter;
1590  gpointer key, value;
1591  g_hash_table_iter_init(&iter, widget->properties);
1592  while (g_hash_table_iter_next(&iter, &key, &value)) {
1593  Property *pv = (Property *)value;
1594  if (pv->type == P_LINK) {
1595  if (pv->value.link.ref == NULL) {
1597  if (pv->value.link.ref == pv) {
1599  GString *str = g_string_new(NULL);
1600  g_string_printf(str,
1601  "Validating the theme failed: the variable '%s' in "
1602  "`%s { %s: var(%s);}` failed to resolve.",
1603  pv->value.link.name, n, pv->name,
1604  pv->value.link.name);
1605 
1607  g_free(n);
1608  }
1609  }
1610  }
1611  }
1612  }
1613 }
1614 
1617 }
1618 
1620  workarea mon;
1621  monitor_active(&mon);
1623 }
1624 
1626  if (g_strcmp0(type, "monitor-id") == 0) {
1627  return THEME_MEDIA_TYPE_MON_ID;
1628  }
1629  if (g_strcmp0(type, "min-width") == 0) {
1631  }
1632  if (g_strcmp0(type, "min-height") == 0) {
1634  }
1635  if (g_strcmp0(type, "max-width") == 0) {
1637  }
1638  if (g_strcmp0(type, "max-height") == 0) {
1640  }
1641  if (g_strcmp0(type, "min-aspect-ratio") == 0) {
1643  }
1644  if (g_strcmp0(type, "max-aspect-ratio") == 0) {
1646  }
1647  if (g_strcmp0(type, "enabled") == 0) {
1648  return THEME_MEDIA_TYPE_BOOLEAN;
1649  }
1650  return THEME_MEDIA_TYPE_INVALID;
1651 }
1652 
1654  const widget *widget,
1655  const char *property) {
1656  if (p) {
1657  if (p->type == P_INHERIT) {
1658  if (widget->parent) {
1659  ThemeWidget *parent =
1661  Property *pp =
1662  rofi_theme_find_property(parent, P_STRING, property, FALSE);
1663  return rofi_theme_has_property_inside(pp, widget->parent, property);
1664  }
1665  return FALSE;
1666  }
1667  return TRUE;
1668  }
1669  return FALSE;
1670 }
1671 gboolean rofi_theme_has_property(const widget *widget, const char *property) {
1673  Property *p = rofi_theme_find_property(wid, P_STRING, property, FALSE);
1674  return rofi_theme_has_property_inside(p, widget, property);
1675 }
@ WL_CENTER
Definition: rofi-types.h:237
@ WL_SOUTH
Definition: rofi-types.h:243
@ WL_WEST
Definition: rofi-types.h:245
@ WL_NORTH
Definition: rofi-types.h:239
@ WL_EAST
Definition: rofi-types.h:241
const unsigned int num_CSSColors
Definition: css-colors.c:152
const CSSColor CSSColors[]
Definition: css-colors.c:2
char * rofi_expand_path(const char *input)
Definition: helper.c:740
uint32_t rofi_icon_fetcher_query_advanced(const char *name, const int wsize, const int hsize)
cairo_surface_t * rofi_icon_fetcher_get(const uint32_t uid)
#define color_reset
Definition: rofi.h:107
#define color_bold
Definition: rofi.h:109
void rofi_add_error_message(GString *str)
Definition: rofi.c:90
void rofi_add_warning_message(GString *str)
Definition: rofi.c:103
double textbox_get_estimated_char_height(void)
Definition: textbox.c:932
double textbox_get_estimated_ch(void)
Definition: textbox.c:946
void rofi_view_get_current_monitor(int *width, int *height)
Definition: view.c:144
struct _widget widget
Definition: widget.h:51
const char *const PropertyTypeName[P_NUM_TYPES]
Definition: rofi-types.c:6
@ ROFI_IMAGE_URL
Definition: rofi-types.h:172
@ ROFI_IMAGE_LINEAR_GRADIENT
Definition: rofi-types.h:172
@ ROFI_DIRECTION_LEFT
Definition: rofi-types.h:175
@ ROFI_DIRECTION_RIGHT
Definition: rofi-types.h:176
@ ROFI_DIRECTION_BOTTOM
Definition: rofi-types.h:178
@ ROFI_DIRECTION_TOP
Definition: rofi-types.h:177
@ ROFI_DIRECTION_ANGLE
Definition: rofi-types.h:179
PropertyType
Definition: rofi-types.h:10
@ P_INTEGER
Definition: rofi-types.h:12
@ P_INHERIT
Definition: rofi-types.h:40
@ P_HIGHLIGHT
Definition: rofi-types.h:32
@ P_LINK
Definition: rofi-types.h:28
@ P_IMAGE
Definition: rofi-types.h:24
@ P_PADDING
Definition: rofi-types.h:26
@ P_LIST
Definition: rofi-types.h:34
@ P_BOOLEAN
Definition: rofi-types.h:20
@ P_COLOR
Definition: rofi-types.h:22
@ P_CURSOR
Definition: rofi-types.h:38
@ P_DOUBLE
Definition: rofi-types.h:14
@ P_ORIENTATION
Definition: rofi-types.h:36
@ P_STRING
Definition: rofi-types.h:16
@ P_POSITION
Definition: rofi-types.h:30
@ ROFI_PU_EM
Definition: rofi-types.h:90
@ ROFI_PU_CH
Definition: rofi-types.h:94
@ ROFI_PU_PX
Definition: rofi-types.h:86
@ ROFI_PU_MM
Definition: rofi-types.h:88
@ ROFI_PU_PERCENT
Definition: rofi-types.h:92
RofiOrientation
Definition: rofi-types.h:141
@ ROFI_ORIENTATION_HORIZONTAL
Definition: rofi-types.h:143
@ ROFI_ORIENTATION_VERTICAL
Definition: rofi-types.h:142
@ ROFI_DISTANCE_MODIFIER_GROUP
Definition: rofi-types.h:107
@ ROFI_DISTANCE_MODIFIER_CEIL
Definition: rofi-types.h:112
@ ROFI_DISTANCE_MODIFIER_SUBTRACT
Definition: rofi-types.h:103
@ ROFI_DISTANCE_MODIFIER_MODULO
Definition: rofi-types.h:106
@ ROFI_DISTANCE_MODIFIER_FLOOR
Definition: rofi-types.h:111
@ ROFI_DISTANCE_MODIFIER_ROUND
Definition: rofi-types.h:110
@ ROFI_DISTANCE_MODIFIER_MULTIPLY
Definition: rofi-types.h:105
@ ROFI_DISTANCE_MODIFIER_MAX
Definition: rofi-types.h:109
@ ROFI_DISTANCE_MODIFIER_MIN
Definition: rofi-types.h:108
@ ROFI_DISTANCE_MODIFIER_DIVIDE
Definition: rofi-types.h:104
@ ROFI_DISTANCE_MODIFIER_ADD
Definition: rofi-types.h:102
@ ROFI_DISTANCE_MODIFIER_NONE
Definition: rofi-types.h:101
@ ROFI_HL_SOLID
Definition: rofi-types.h:76
@ ROFI_HL_DASH
Definition: rofi-types.h:78
@ ROFI_SCALE_HEIGHT
Definition: rofi-types.h:185
@ ROFI_SCALE_NONE
Definition: rofi-types.h:183
@ ROFI_SCALE_BOTH
Definition: rofi-types.h:184
@ ROFI_SCALE_WIDTH
Definition: rofi-types.h:186
RofiCursorType
Definition: rofi-types.h:149
@ ROFI_HL_UPPERCASE
Definition: rofi-types.h:66
@ ROFI_HL_STRIKETHROUGH
Definition: rofi-types.h:60
@ ROFI_HL_NONE
Definition: rofi-types.h:54
@ ROFI_HL_ITALIC
Definition: rofi-types.h:62
@ ROFI_HL_UNDERLINE
Definition: rofi-types.h:58
@ ROFI_HL_CAPITALIZE
Definition: rofi-types.h:70
@ ROFI_HL_BOLD
Definition: rofi-types.h:56
@ ROFI_HL_LOWERCASE
Definition: rofi-types.h:68
@ ROFI_HL_COLOR
Definition: rofi-types.h:64
Settings config
PropertyValue value
Definition: rofi-types.h:297
PropertyType type
Definition: rofi-types.h:295
char * name
Definition: rofi-types.h:293
RofiDistanceModifier modtype
Definition: rofi-types.h:122
RofiPixelUnit type
Definition: rofi-types.h:119
struct RofiDistanceUnit * right
Definition: rofi-types.h:128
struct RofiDistanceUnit * left
Definition: rofi-types.h:125
RofiDistanceUnit base
Definition: rofi-types.h:133
RofiLineStyle style
Definition: rofi-types.h:135
RofiHighlightStyle style
Definition: rofi-types.h:221
RofiDirection dir
Definition: rofi-types.h:196
RofiImageType type
Definition: rofi-types.h:190
double angle
Definition: rofi-types.h:197
uint32_t surface_id
Definition: rofi-types.h:202
char * url
Definition: rofi-types.h:191
RofiScaleType scaling
Definition: rofi-types.h:192
GList * colors
Definition: rofi-types.h:199
RofiDistance bottom
Definition: rofi-types.h:212
RofiDistance top
Definition: rofi-types.h:210
RofiDistance right
Definition: rofi-types.h:211
RofiDistance left
Definition: rofi-types.h:213
int dpi
Definition: settings.h:141
double blue
Definition: rofi-types.h:164
double green
Definition: rofi-types.h:162
double red
Definition: rofi-types.h:160
double alpha
Definition: rofi-types.h:166
struct ThemeWidget ** widgets
Definition: theme.h:76
struct ThemeWidget * parent
Definition: theme.h:82
ThemeMedia * media
Definition: theme.h:78
unsigned int num_widgets
Definition: theme.h:75
char * name
Definition: theme.h:73
GHashTable * properties
Definition: theme.h:80
const char * state
char * name
struct _widget * parent
WidgetType type
Definition: xcb.h:94
int w
Definition: xcb.h:104
int monitor_id
Definition: xcb.h:96
int h
Definition: xcb.h:106
RofiPadding rofi_theme_get_padding(const widget *widget, const char *property, RofiPadding pad)
Definition: theme.c:1213
gboolean rofi_theme_get_image(const widget *widget, const char *property, cairo_t *d)
Definition: theme.c:1178
Property * rofi_theme_property_copy(const Property *p, G_GNUC_UNUSED void *data)
Definition: theme.c:123
void rofi_theme_free_parsed_files(void)
Definition: theme.c:51
GList * parsed_config_files
Definition: theme.c:49
static void rofi_theme_print_property_index(size_t pnl, int depth, Property *p)
Definition: theme.c:516
const char *const RofiCursorTypeStr[3]
Definition: theme.c:351
static RofiDistanceUnit * rofi_theme_property_copy_distance_unit(RofiDistanceUnit *unit)
Definition: theme.c:100
static int distance_unit_get_pixel(RofiDistanceUnit *unit, RofiOrientation ori)
Definition: theme.c:1353
GList * rofi_theme_get_list_distance(const widget *widget, const char *property)
Definition: theme.c:1239
static void int_rofi_theme_print_property(Property *p)
Definition: theme.c:357
GList * rofi_theme_get_list_strings(const widget *widget, const char *property)
Definition: theme.c:1267
void rofi_theme_print_parsed_files(gboolean is_term)
Definition: theme.c:56
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition: theme.c:877
ThemeWidget * rofi_config_find_widget(const char *name, const char *state, gboolean exact)
Definition: theme.c:778
static char * rofi_theme_widget_get_name(ThemeWidget *wid)
Definition: theme.c:1567
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition: theme.c:903
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition: theme.c:1415
void rofi_theme_parse_process_links(void)
Definition: theme.c:1615
FILE * yyin
static RofiHighlightColorStyle rofi_theme_get_highlight_inside(Property *p, widget *widget, const char *property, RofiHighlightColorStyle th)
Definition: theme.c:1286
Property * rofi_theme_find_property(ThemeWidget *widget, PropertyType type, const char *property, gboolean exact)
Definition: theme.c:740
static void rofi_theme_parse_process_links_int(ThemeWidget *wid)
Definition: theme.c:1578
RofiCursorType rofi_theme_get_cursor_type(const widget *widget, const char *property, RofiCursorType def)
Definition: theme.c:962
void yylex_destroy(void)
ThemeWidget * rofi_theme_find_widget(const char *name, const char *state, gboolean exact)
Definition: theme.c:786
static int rofi_theme_get_integer_inside(Property *p, const widget *widget, const char *property, int def)
Definition: theme.c:821
static RofiDistance rofi_theme_get_distance_inside(Property *p, const widget *widget, const char *property, int def)
Definition: theme.c:846
static gboolean distance_compare(RofiDistance d, RofiDistance e)
Definition: theme.c:67
static void rofi_theme_get_color_inside(const widget *widget, Property *p, const char *property, cairo_t *d)
Definition: theme.c:1046
void rofi_theme_parse_process_conditionals(void)
Definition: theme.c:1619
void rofi_theme_get_color(const widget *widget, const char *property, cairo_t *d)
Definition: theme.c:1067
RofiHighlightColorStyle rofi_theme_get_highlight(widget *widget, const char *property, RofiHighlightColorStyle th)
Definition: theme.c:1320
static RofiCursorType rofi_theme_get_cursor_type_inside(Property *p, const widget *widget, const char *property, RofiCursorType def)
Definition: theme.c:940
static void rofi_theme_print_distance_unit(RofiDistanceUnit *unit)
Definition: theme.c:262
static void rofi_theme_copy_property_int(G_GNUC_UNUSED gpointer key, gpointer value, gpointer user_data)
Definition: theme.c:645
static void rofi_theme_distance_property_free(RofiDistance *distance)
Definition: theme.c:184
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition: theme.c:932
static int get_pixels(RofiDistanceUnit *unit, RofiOrientation ori)
Definition: theme.c:1330
Property * rofi_theme_property_create(PropertyType type)
Definition: theme.c:93
char * rofi_theme_parse_prepare_file(const char *file, const char *parent_file)
Definition: theme.c:1428
ThemeMediaType rofi_theme_parse_media_type(const char *type)
Definition: theme.c:1625
void rofi_theme_widget_add_properties(ThemeWidget *widget, GHashTable *table)
Definition: theme.c:651
static double rofi_theme_get_double_inside(const widget *orig, Property *p, const widget *widget, const char *property, double def)
Definition: theme.c:1019
static RofiOrientation rofi_theme_get_orientation_inside(Property *p, const widget *widget, const char *property, RofiOrientation def)
Definition: theme.c:910
double rofi_theme_get_double(const widget *widget, const char *property, double def)
Definition: theme.c:1040
static void rofi_theme_print_distance(RofiDistance d)
Definition: theme.c:338
int rofi_theme_get_integer(const widget *widget, const char *property, int def)
Definition: theme.c:840
void rofi_theme_print(ThemeWidget *widget)
Definition: theme.c:585
static gboolean rofi_theme_has_property_inside(Property *p, const widget *widget, const char *property)
Definition: theme.c:1653
static void printf_double(double d)
Definition: theme.c:254
gboolean rofi_theme_has_property(const widget *widget, const char *property)
Definition: theme.c:1671
void rofi_theme_reset(void)
Definition: theme.c:226
static int rofi_theme_get_position_inside(Property *p, const widget *widget, const char *property, int def)
Definition: theme.c:795
void rofi_theme_parse_merge_widgets(ThemeWidget *parent, ThemeWidget *child)
Definition: theme.c:1446
static void rofi_theme_distance_unit_property_free(RofiDistanceUnit *unit)
Definition: theme.c:173
static void rofi_theme_print_color(ThemeColor color)
Definition: theme.c:317
static ThemeWidget * rofi_theme_find_single(ThemeWidget *widget, const char *name)
Definition: theme.c:667
int yyparse()
int rofi_theme_get_position(const widget *widget, const char *property, int def)
Definition: theme.c:815
static void rofi_theme_resolve_link_property(Property *p, int depth)
Definition: theme.c:703
static void rofi_theme_parse_process_conditionals_int(workarea mon, ThemeWidget *rwidget)
Definition: theme.c:1466
void rofi_theme_print_index(ThemeWidget *widget, int index)
Definition: theme.c:525
void rofi_theme_free(ThemeWidget *widget)
Definition: theme.c:232
static const char * rofi_theme_get_string_inside(Property *p, const widget *widget, const char *property, const char *def)
Definition: theme.c:969
static GList * rofi_theme_get_list_inside(Property *p, const widget *widget, const char *property, PropertyType child_type)
Definition: theme.c:1220
ThemeWidget * rofi_theme_find_or_create_name(ThemeWidget *base, const char *name)
Definition: theme.c:73
static ThemeWidget * rofi_theme_find(ThemeWidget *widget, const char *name, const gboolean exact)
Definition: theme.c:677
static int rofi_theme_get_boolean_inside(Property *p, const widget *widget, const char *property, int def)
Definition: theme.c:884
void yyerror(YYLTYPE *yylloc, const char *, const char *)
Definition: theme.c:615
RofiDistance rofi_theme_property_copy_distance(RofiDistance const distance)
Definition: theme.c:111
void rofi_theme_property_free(Property *p)
Definition: theme.c:195
static RofiPadding rofi_theme_get_padding_inside(Property *p, const widget *widget, const char *property, RofiPadding pad)
Definition: theme.c:1184
const char * rofi_theme_get_string(const widget *widget, const char *property, const char *def)
Definition: theme.c:990
static gboolean rofi_theme_get_image_inside(Property *p, const widget *widget, const char *property, cairo_t *d)
Definition: theme.c:1074
void distance_get_linestyle(RofiDistance d, cairo_t *draw)
Definition: theme.c:1419
static double rofi_theme_get_double_integer_fb_inside(Property *p, const widget *widget, const char *property, double def)
Definition: theme.c:997
ThemeMediaType
Definition: theme.h:38
@ THEME_MEDIA_TYPE_MAX_HEIGHT
Definition: theme.h:46
@ THEME_MEDIA_TYPE_MON_ID
Definition: theme.h:48
@ THEME_MEDIA_TYPE_INVALID
Definition: theme.h:56
@ THEME_MEDIA_TYPE_MIN_WIDTH
Definition: theme.h:40
@ THEME_MEDIA_TYPE_MIN_ASPECT_RATIO
Definition: theme.h:50
@ THEME_MEDIA_TYPE_BOOLEAN
Definition: theme.h:54
@ THEME_MEDIA_TYPE_MAX_ASPECT_RATIO
Definition: theme.h:52
@ THEME_MEDIA_TYPE_MAX_WIDTH
Definition: theme.h:42
@ THEME_MEDIA_TYPE_MIN_HEIGHT
Definition: theme.h:44
ThemeWidget * rofi_theme
Definition: theme.h:93
struct _PropertyValue::@6 link
ThemeColor color
Definition: rofi-types.h:268
struct Property * ref
Definition: rofi-types.h:276
RofiHighlightColorStyle highlight
Definition: rofi-types.h:281
struct Property * def_value
Definition: rofi-types.h:278
GList * list
Definition: rofi-types.h:285
RofiImage image
Definition: rofi-types.h:283
gboolean b
Definition: rofi-types.h:266
RofiPadding padding
Definition: rofi-types.h:270
workarea mon
Definition: view.c:111
int monitor_active(workarea *mon)
Definition: xcb.c:992
xcb_depth_t * depth
Definition: xcb.c:96
ThemeWidget * rofi_configuration
Definition: xrmoptions.c:46