rofi  1.5.1
theme.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2013-2017 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 
28 #define G_LOG_DOMAIN "Theme"
29 
30 #include "config.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <string.h>
35 // GFile stuff.
36 #include <gio/gio.h>
37 #include "theme.h"
38 #include "theme-parser.h"
39 #include "helper.h"
40 #include "settings.h"
41 #include "widgets/textbox.h"
42 #include "view.h"
43 #include "rofi.h"
44 #include "rofi-types.h"
45 
46 void yyerror ( YYLTYPE *yylloc, const char *, const char * );
47 static gboolean distance_compare ( RofiDistance d, RofiDistance e )
48 {
49  return d.type == e.type && d.distance == e.distance && d.style == e.style;
50 }
51 
53 {
54  for ( unsigned int i = 0; i < base->num_widgets; i++ ) {
55  if ( g_strcmp0 ( base->widgets[i]->name, name ) == 0 ) {
56  return base->widgets[i];
57  }
58  }
59 
60  base->widgets = g_realloc ( base->widgets, sizeof ( ThemeWidget* ) * ( base->num_widgets + 1 ) );
61  base->widgets[base->num_widgets] = g_slice_new0 ( ThemeWidget );
62  ThemeWidget *retv = base->widgets[base->num_widgets];
63  retv->parent = base;
64  retv->name = g_strdup ( name );
65  base->num_widgets++;
66  return retv;
67 }
72 {
73  Property *retv = g_slice_new0 ( Property );
74  retv->type = type;
75  return retv;
76 }
78 {
80  retv->name = g_strdup ( p->name );
81 
82  switch ( p->type )
83  {
84  case P_STRING:
85  retv->value.s = g_strdup ( p->value.s );
86  break;
87  case P_LIST:
88  retv->value.list = g_list_copy_deep ( p->value.list, (GCopyFunc) g_strdup, NULL );
89  break;
90  case P_LINK:
91  retv->value.link.name = g_strdup ( p->value.link.name );
92  retv->value.link.ref = NULL;
93  break;
94  default:
95  retv->value = p->value;
96  }
97  return retv;
98 }
99 
101 {
102  if ( p == NULL ) {
103  return;
104  }
105  g_free ( p->name );
106  if ( p->type == P_STRING ) {
107  g_free ( p->value.s );
108  }
109  else if ( p->type == P_LINK ) {
110  g_free ( p->value.link.name );
111  }
112  g_slice_free ( Property, p );
113 }
114 
115 void rofi_theme_reset ( void )
116 {
118  rofi_theme = g_slice_new0 ( ThemeWidget );
119  rofi_theme->name = g_strdup ( "Root" );
120 }
121 
123 {
124  if ( widget == NULL ) {
125  return;
126  }
127  if ( widget->properties ) {
128  g_hash_table_destroy ( widget->properties );
129  widget->properties = NULL;
130  }
131  for ( unsigned int i = 0; i < widget->num_widgets; i++ ) {
132  rofi_theme_free ( widget->widgets[i] );
133  }
134  g_free ( widget->widgets );
135  g_free ( widget->name );
136  g_slice_free ( ThemeWidget, widget );
137 }
138 
142 inline static void printf_double ( double d )
143 {
144  char buf[G_ASCII_DTOSTR_BUF_SIZE];
145  g_ascii_formatd ( buf, G_ASCII_DTOSTR_BUF_SIZE, "%.4lf", d );
146  fputs ( buf, stdout );
147 }
149 {
150  if ( d.type == ROFI_PU_PX ) {
151  printf ( "%upx ", (unsigned int) d.distance );
152  }
153  else if ( d.type == ROFI_PU_PERCENT ) {
154  printf_double ( d.distance );
155  fputs ( "%% ", stdout );
156  }
157  else {
158  printf_double ( d.distance );
159  fputs ( "em ", stdout );
160  }
161  if ( d.style == ROFI_HL_DASH ) {
162  printf ( "dash " );
163  }
164 }
166 const char * const WindowLocationStr[9] = {
167  "center",
168  "northwest",
169  "north",
170  "northeast",
171  "east",
172  "southeast",
173  "south",
174  "southwest",
175  "west"
176 };
177 
178 static void rofi_theme_print_property_index ( size_t pnl, int depth, Property *p )
179 {
180  int pl = strlen ( p->name );
181  printf ( "%*s%s:%*s ", depth, "", p->name, (int) pnl - pl, "" );
182  switch ( p->type )
183  {
184  case P_LIST:
185  printf ( "[ " );
186  for ( GList *iter = p->value.list; iter != NULL; iter = g_list_next ( iter ) ) {
187  printf ( "%s", (char *) ( iter->data ) );
188  if ( iter->next != NULL ) {
189  printf ( "," );
190  }
191  }
192  printf ( " ];" );
193  break;
194  case P_ORIENTATION:
195  printf ( "%s;", ( p->value.i == ROFI_ORIENTATION_HORIZONTAL ) ? "horizontal" : "vertical" );
196  break;
197  case P_HIGHLIGHT:
198  if ( p->value.highlight.style & ROFI_HL_BOLD ) {
199  printf ( "bold " );
200  }
201  if ( p->value.highlight.style & ROFI_HL_UNDERLINE ) {
202  printf ( "underline " );
203  }
205  printf ( "strikethrough " );
206  }
207  if ( p->value.highlight.style & ROFI_HL_ITALIC ) {
208  printf ( "italic " );
209  }
210  if ( p->value.highlight.style & ROFI_HL_COLOR ) {
211  printf ( "rgba ( %.0f, %.0f, %.0f, %.0f %% )",
212  ( p->value.highlight.color.red * 255.0 ),
213  ( p->value.highlight.color.green * 255.0 ),
214  ( p->value.highlight.color.blue * 255.0 ),
215  ( p->value.highlight.color.alpha * 100.0 ) );
216  }
217  printf ( ";" );
218  break;
219  case P_POSITION:
220  printf ( "%s;", WindowLocationStr[p->value.i] );
221  break;
222  case P_STRING:
223  printf ( "\"%s\";", p->value.s );
224  break;
225  case P_INTEGER:
226  printf ( "%d;", p->value.i );
227  break;
228  case P_DOUBLE:
229  printf ( "%.2f;", p->value.f );
230  break;
231  case P_BOOLEAN:
232  printf ( "%s;", p->value.b ? "true" : "false" );
233  break;
234  case P_COLOR:
235  printf ( "rgba ( %.0f, %.0f, %.0f, %.0f %% );",
236  ( p->value.color.red * 255.0 ),
237  ( p->value.color.green * 255.0 ),
238  ( p->value.color.blue * 255.0 ),
239  ( p->value.color.alpha * 100.0 ) );
240  break;
241  case P_PADDING:
246  }
247  else if ( distance_compare ( p->value.padding.top, p->value.padding.bottom ) &&
251  }
252  else if ( !distance_compare ( p->value.padding.top, p->value.padding.bottom ) &&
257  }
258  else {
263  }
264  printf ( ";" );
265  break;
266  case P_LINK:
267  printf ( "%s;", p->value.link.name );
268  break;
269  case P_INHERIT:
270  printf ( "inherit;" );
271  break;
272  default:
273  break;
274  }
275  putchar ( '\n' );
276 }
277 
279 {
280  GHashTableIter iter;
281  gpointer key, value;
282  if ( widget->properties ) {
283  int index = 0;
284  GList *list = NULL;
285  ThemeWidget *w = widget;
286  while ( w ) {
287  if ( g_strcmp0 ( w->name, "Root" ) == 0 ) {
288  break;
289  }
290  list = g_list_prepend ( list, w->name );
291  w = w->parent;
292  }
293  if ( g_list_length ( list ) > 0 ) {
294  index = 4;
295  for ( GList *iter = g_list_first ( list ); iter != NULL; iter = g_list_next ( iter ) ) {
296  char *name = (char *) iter->data;
297  fputs ( name, stdout );
298  if ( iter->prev == NULL && iter->next ) {
299  putchar ( ' ' );
300  }
301  else if ( iter->next ) {
302  putchar ( '.' );
303  }
304  }
305  printf ( " {\n" );
306  }
307  else {
308  index = 4;
309  printf ( "* {\n" );
310  }
311  size_t property_name_length = 0;
312  g_hash_table_iter_init ( &iter, widget->properties );
313  while ( g_hash_table_iter_next ( &iter, &key, &value ) ) {
314  Property *p = (Property *) value;
315  property_name_length = MAX ( strlen ( p->name ), property_name_length );
316  }
317  g_hash_table_iter_init ( &iter, widget->properties );
318  while ( g_hash_table_iter_next ( &iter, &key, &value ) ) {
319  Property *p = (Property *) value;
320  rofi_theme_print_property_index ( property_name_length, index, p );
321  }
322  printf ( "}\n" );
323  g_list_free ( list );
324  }
325  for ( unsigned int i = 0; i < widget->num_widgets; i++ ) {
326  rofi_theme_print_index ( widget->widgets[i] );
327  }
328 }
330 {
331  if ( widget != NULL ) {
332  printf ( "/**\n * rofi -dump-theme output.\n * Rofi version: %s\n **/\n", PACKAGE_VERSION );
334  }
335 }
336 
340 int yyparse ();
341 
345 void yylex_destroy ( void );
346 
350 extern FILE* yyin;
351 
359 void yyerror ( YYLTYPE *yylloc, const char *what, const char* s )
360 {
361  char *what_esc = what ? g_markup_escape_text ( what, -1 ) : g_strdup ( "" );
362  GString *str = g_string_new ( "" );
363  g_string_printf ( str, "<big><b>Error while parsing theme:</b></big> <i>%s</i>\n", what_esc );
364  g_free ( what_esc );
365  char *esc = g_markup_escape_text ( s, -1 );
366  g_string_append_printf ( str, "\tParser error: <span size=\"smaller\" style=\"italic\">%s</span>\n", esc );
367  g_free ( esc );
368  if ( yylloc->filename != NULL ) {
369  g_string_append_printf ( str, "\tLocation: line %d column %d to line %d column %d.\n" \
370  "\tFile '%s'\n", yylloc->first_line, yylloc->first_column, yylloc->last_line, yylloc->last_column, yylloc->filename );
371  }
372  else {
373  g_string_append_printf ( str, "\tLocation: line %d column %d to line %d column %d\n", yylloc->first_line, yylloc->first_column, yylloc->last_line, yylloc->last_column );
374  }
375  g_log ( "Parser", G_LOG_LEVEL_DEBUG, "Failed to parse theme:\n%s", str->str );
376  rofi_add_error_message ( str );
377 }
378 
379 static void rofi_theme_copy_property_int ( G_GNUC_UNUSED gpointer key, gpointer value, gpointer user_data )
380 {
381  GHashTable *table = (GHashTable *) user_data;
382  Property *p = rofi_theme_property_copy ( (Property *) value );
383  g_hash_table_replace ( table, p->name, p );
384 }
386 {
387  if ( table == NULL ) {
388  return;
389  }
390  if ( widget->properties == NULL ) {
391  widget->properties = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, (GDestroyNotify) rofi_theme_property_free );
392  }
393  g_hash_table_foreach ( table, rofi_theme_copy_property_int, widget->properties );
394 }
395 
400 static inline ThemeWidget *rofi_theme_find_single ( ThemeWidget *widget, const char *name )
401 {
402  for ( unsigned int j = 0; widget && j < widget->num_widgets; j++ ) {
403  if ( g_strcmp0 ( widget->widgets[j]->name, name ) == 0 ) {
404  return widget->widgets[j];
405  }
406  }
407  return widget;
408 }
409 
410 static ThemeWidget *rofi_theme_find ( ThemeWidget *widget, const char *name, const gboolean exact )
411 {
412  if ( widget == NULL || name == NULL ) {
413  return widget;
414  }
415  char *tname = g_strdup ( name );
416  char *saveptr = NULL;
417  int found = TRUE;
418  for ( const char *iter = strtok_r ( tname, ".", &saveptr ); iter != NULL; iter = strtok_r ( NULL, ".", &saveptr ) ) {
419  found = FALSE;
421  if ( f != widget ) {
422  widget = f;
423  found = TRUE;
424  }
425  else if ( exact ) {
426  break;
427  }
428  }
429  g_free ( tname );
430  if ( !exact || found ) {
431  return widget;
432  }
433  else {
434  return NULL;
435  }
436 }
437 
439 {
440  // Set name, remove '@' prefix.
441  const char *name = p->value.link.name + 1;
442  if ( depth > 20 ) {
443  g_warning ( "Found more then 20 redirects for property. Stopping." );
444  p->value.link.ref = p;
445  return;
446  }
447 
448  if ( rofi_theme->properties && g_hash_table_contains ( rofi_theme->properties, name ) ) {
449  Property *pr = g_hash_table_lookup ( rofi_theme->properties, name );
450  if ( pr->type == P_LINK ) {
451  if ( pr->value.link.ref == NULL ) {
453  }
454  if ( pr->value.link.ref != pr ) {
455  p->value.link.ref = pr->value.link.ref;
456  return;
457  }
458  }
459  else {
460  p->value.link.ref = pr;
461  return;
462  }
463  }
464 
465  // No found, set ref to self.
466  p->value.link.ref = p;
467 }
468 
469 Property *rofi_theme_find_property ( ThemeWidget *widget, PropertyType type, const char *property, gboolean exact )
470 {
471  while ( widget ) {
472  if ( widget->properties && g_hash_table_contains ( widget->properties, property ) ) {
473  Property *p = g_hash_table_lookup ( widget->properties, property );
474  if ( p->type == P_INHERIT ) {
475  return p;
476  }
477  if ( p->type == P_LINK ) {
478  if ( p->value.link.ref == NULL ) {
479  // Resolve link.
481  }
482  if ( p->value.link.ref != NULL && p->value.link.ref->type == type ) {
483  return p->value.link.ref;
484  }
485  }
486  if ( p->type == type ) {
487  return p;
488  }
489  // RofiPadding and integer can be converted.
490  if ( p->type == P_INTEGER && type == P_PADDING ) {
491  return p;
492  }
493  g_debug ( "Found property: '%s' on '%s', but type %s does not match expected type %s.",
494  property, widget->name,
496  PropertyTypeName[type]
497  );
498  }
499  if ( exact ) {
500  return NULL;
501  }
502  // Fall back to defaults.
503  widget = widget->parent;
504  }
505  return NULL;
506 }
507 ThemeWidget *rofi_theme_find_widget ( const char *name, const char *state, gboolean exact )
508 {
509  // First find exact match based on name.
511  widget = rofi_theme_find ( widget, state, exact );
512 
513  return widget;
514 }
515 
516 int rofi_theme_get_position ( const widget *widget, const char *property, int def )
517 {
519  Property *p = rofi_theme_find_property ( wid, P_POSITION, property, FALSE );
520  if ( p ) {
521  if ( p->type == P_INHERIT ) {
522  if ( widget->parent ) {
523  return rofi_theme_get_position ( widget->parent, property, def );
524  }
525  return def;
526  }
527  return p->value.i;
528  }
529  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
530  return def;
531 }
532 
533 int rofi_theme_get_integer ( const widget *widget, const char *property, int def )
534 {
536  Property *p = rofi_theme_find_property ( wid, P_INTEGER, property, FALSE );
537  if ( p ) {
538  if ( p->type == P_INHERIT ) {
539  if ( widget->parent ) {
540  return rofi_theme_get_integer ( widget->parent, property, def );
541  }
542  return def;
543  }
544  return p->value.i;
545  }
546  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
547  return def;
548 }
549 RofiDistance rofi_theme_get_distance ( const widget *widget, const char *property, int def )
550 {
552  Property *p = rofi_theme_find_property ( wid, P_PADDING, property, FALSE );
553  if ( p ) {
554  if ( p->type == P_INHERIT ) {
555  if ( widget->parent ) {
556  return rofi_theme_get_distance ( widget->parent, property, def );
557  }
558  return (RofiDistance){ def, ROFI_PU_PX, ROFI_HL_SOLID };
559  }
560  if ( p->type == P_INTEGER ) {
561  return (RofiDistance){ p->value.i, ROFI_PU_PX, ROFI_HL_SOLID };
562  }
563  else {
564  return p->value.padding.left;
565  }
566  }
567  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
568  return (RofiDistance){ def, ROFI_PU_PX, ROFI_HL_SOLID };
569 }
570 
571 int rofi_theme_get_boolean ( const widget *widget, const char *property, int def )
572 {
574  Property *p = rofi_theme_find_property ( wid, P_BOOLEAN, property, FALSE );
575  if ( p ) {
576  if ( p->type == P_INHERIT ) {
577  if ( widget->parent ) {
578  return rofi_theme_get_boolean ( widget->parent, property, def );
579  }
580  return def;
581  }
582  return p->value.b;
583  }
584  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
585  return def;
586 }
588 {
590  Property *p = rofi_theme_find_property ( wid, P_ORIENTATION, property, FALSE );
591  if ( p ) {
592  if ( p->type == P_INHERIT ) {
593  if ( widget->parent ) {
594  return rofi_theme_get_orientation ( widget->parent, property, def );
595  }
596  return def;
597  }
598  return p->value.b;
599  }
600  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
601  return def;
602 }
603 
604 const char *rofi_theme_get_string ( const widget *widget, const char *property, const char *def )
605 {
607  Property *p = rofi_theme_find_property ( wid, P_STRING, property, FALSE );
608  if ( p ) {
609  if ( p->type == P_INHERIT ) {
610  if ( widget->parent ) {
611  return rofi_theme_get_string ( widget->parent, property, def );
612  }
613  return def;
614  }
615  return p->value.s;
616  }
617  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
618  return def;
619 }
620 double rofi_theme_get_double ( const widget *widget, const char *property, double def )
621 {
623  Property *p = rofi_theme_find_property ( wid, P_DOUBLE, property, FALSE );
624  if ( p ) {
625  if ( p->type == P_INHERIT ) {
626  if ( widget->parent ) {
627  return rofi_theme_get_double ( widget->parent, property, def );
628  }
629  return def;
630  }
631  return p->value.f;
632  }
633  // Fallback to integer if double is not found.
634  p = rofi_theme_find_property ( wid, P_INTEGER, property, FALSE );
635  if ( p ) {
636  if ( p->type == P_INHERIT ) {
637  if ( widget->parent ) {
638  return rofi_theme_get_double ( widget->parent, property, def );
639  }
640  return def;
641  }
642  return (double)p->value.i;
643  }
644  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
645  return def;
646 }
647 void rofi_theme_get_color ( const widget *widget, const char *property, cairo_t *d )
648 {
650  Property *p = rofi_theme_find_property ( wid, P_COLOR, property, FALSE );
651  if ( p ) {
652  if ( p->type == P_INHERIT ) {
653  if ( widget->parent ) {
654  rofi_theme_get_color ( widget->parent, property, d );
655  }
656  return;
657  }
658  cairo_set_source_rgba ( d,
659  p->value.color.red,
660  p->value.color.green,
661  p->value.color.blue,
662  p->value.color.alpha
663  );
664  }
665  else {
666  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
667  }
668 }
669 RofiPadding rofi_theme_get_padding ( const widget *widget, const char *property, RofiPadding pad )
670 {
672  Property *p = rofi_theme_find_property ( wid, P_PADDING, property, FALSE );
673  if ( p ) {
674  if ( p->type == P_INHERIT ) {
675  if ( widget->parent ) {
676  return rofi_theme_get_padding ( widget->parent, property, pad );
677  }
678  return pad;
679  }
680  if ( p->type == P_PADDING ) {
681  pad = p->value.padding;
682  }
683  else {
685  return (RofiPadding){ d, d, d, d };
686  }
687  }
688  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
689  return pad;
690 }
691 
692 GList *rofi_theme_get_list ( const widget *widget, const char * property, const char *defaults )
693 {
695  Property *p = rofi_theme_find_property ( wid2, P_LIST, property, TRUE );
696  if ( p ) {
697  if ( p->type == P_INHERIT ) {
698  if ( widget->parent ) {
699  return rofi_theme_get_list ( widget->parent, property, defaults );
700  }
701  }
702  else if ( p->type == P_LIST ) {
703  return g_list_copy_deep ( p->value.list, (GCopyFunc) g_strdup, NULL );
704  }
705  }
706  char **r = defaults ? g_strsplit ( defaults, ",", 0 ) : NULL;
707  if ( r ) {
708  GList *l = NULL;
709  for ( int i = 0; r[i] != NULL; i++ ) {
710  l = g_list_append ( l, r[i] );
711  }
712  g_free ( r );
713  return l;
714  }
715  return NULL;
716 }
717 
719 {
721  Property *p = rofi_theme_find_property ( wid, P_HIGHLIGHT, property, FALSE );
722  if ( p ) {
723  if ( p->type == P_INHERIT ) {
724  if ( widget->parent ) {
725  return rofi_theme_get_highlight ( widget->parent, property, th );
726  }
727  return th;
728  }
729  return p->value.highlight;
730  }
731  g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
732  return th;
733 }
734 
736 {
737  if ( d.type == ROFI_PU_EM ) {
739  }
740  else if ( d.type == ROFI_PU_CH ) {
741  return d.distance * textbox_get_estimated_ch ();
742  }
743  else if ( d.type == ROFI_PU_PERCENT ) {
744  if ( ori == ROFI_ORIENTATION_VERTICAL ) {
745  int height = 0;
746  rofi_view_get_current_monitor ( NULL, &height );
747  return ( d.distance * height ) / ( 100.0 );
748  }
749  else {
750  int width = 0;
751  rofi_view_get_current_monitor ( &width, NULL );
752  return ( d.distance * width ) / ( 100.0 );
753  }
754  }
755  return d.distance;
756 }
757 
758 void distance_get_linestyle ( RofiDistance d, cairo_t *draw )
759 {
760  if ( d.style == ROFI_HL_DASH ) {
761  const double dashes[1] = { 4 };
762  cairo_set_dash ( draw, dashes, 1, 0.0 );
763  }
764  else {
765  cairo_set_dash ( draw, NULL, 0, 0.0 );
766  }
767 }
768 
769 gboolean rofi_theme_is_empty ( void )
770 {
771  if ( rofi_theme == NULL ) {
772  return TRUE;
773  }
774  if ( rofi_theme->properties == NULL && rofi_theme->num_widgets == 0 ) {
775  return TRUE;
776  }
777 
778  return FALSE;
779 }
780 
781 #ifdef THEME_CONVERTER
782 
783 static char * rofi_theme_convert_color ( char *col )
784 {
785  char *r = g_strstrip ( col );
786  if ( *r == '#' && strlen ( r ) == 9 ) {
787  char a1 = r[1];
788  char a2 = r[2];
789  r[1] = r[3];
790  r[2] = r[4];
791  r[3] = r[5];
792  r[4] = r[6];
793  r[5] = r[7];
794  r[6] = r[8];
795  r[7] = a1;
796  r[8] = a2;
797  }
798 
799  return r;
800 }
801 void rofi_theme_convert_old ( void )
802 {
803  {
804  char *str = g_strdup_printf ( "#window { border: %d; padding: %d;}", config.menu_bw, config.padding );
805  rofi_theme_parse_string ( str );
806  g_free ( str );
807  }
808  if ( config.color_window ) {
809  char **retv = g_strsplit ( config.color_window, ",", -1 );
810  const char * const conf[] = {
811  "* { background: %s; }",
812  "* { border-color: %s; }",
813  "* { separatorcolor: %s; }"
814  };
815  for ( int i = 0; retv && i < 3 && retv[i]; i++ ) {
816  char *str = g_strdup_printf ( conf[i], rofi_theme_convert_color ( retv[i] ) );
817  rofi_theme_parse_string ( str );
818  g_free ( str );
819  }
820  g_strfreev ( retv );
821  }
822  if ( config.color_normal ) {
823  char **retv = g_strsplit ( config.color_normal, ",", -1 );
824  const char * const conf[] = {
825  "* { normal-background: %s; }",
826  "* { foreground: %s; normal-foreground: @foreground; alternate-normal-foreground: @foreground; }",
827  "* { alternate-normal-background: %s; }",
828  "* { selected-normal-background: %s; }",
829  "* { selected-normal-foreground: %s; }"
830  };
831  for ( int i = 0; retv && retv[i] && i < 5; i++ ) {
832  char *str = g_strdup_printf ( conf[i], rofi_theme_convert_color ( retv[i] ) );
833  rofi_theme_parse_string ( str );
834  g_free ( str );
835  }
836  g_strfreev ( retv );
837  }
838  if ( config.color_urgent ) {
839  char **retv = g_strsplit ( config.color_urgent, ",", -1 );
840  const char * const conf[] = {
841  "* { urgent-background: %s; }",
842  "* { urgent-foreground: %s; alternate-urgent-foreground: @urgent-foreground;}",
843  "* { alternate-urgent-background: %s; }",
844  "* { selected-urgent-background: %s; }",
845  "* { selected-urgent-foreground: %s; }"
846  };
847  for ( int i = 0; retv && retv[i] && i < 5; i++ ) {
848  char *str = g_strdup_printf ( conf[i], rofi_theme_convert_color ( retv[i] ) );
849  rofi_theme_parse_string ( str );
850  g_free ( str );
851  }
852  g_strfreev ( retv );
853  }
854  if ( config.color_active ) {
855  char **retv = g_strsplit ( config.color_active, ",", -1 );
856  const char * const conf[] = {
857  "* { active-background: %s; }",
858  "* { active-foreground: %s; alternate-active-foreground: @active-foreground;}",
859  "* { alternate-active-background: %s; }",
860  "* { selected-active-background: %s; }",
861  "* { selected-active-foreground: %s; }"
862  };
863  for ( int i = 0; retv && retv[i] && i < 5; i++ ) {
864  char *str = g_strdup_printf ( conf[i], rofi_theme_convert_color ( retv[i] ) );
865  rofi_theme_parse_string ( str );
866  g_free ( str );
867  }
868  g_strfreev ( retv );
869  }
870 
871  if ( config.separator_style != NULL ) {
872  if ( g_strcmp0 ( config.separator_style, "none" ) == 0 ) {
873  const char *const str = "#listview { border: 0px; }";
874  rofi_theme_parse_string ( str );
875  const char *const str2 = "#sidebar { border: 0px; }";
876  rofi_theme_parse_string ( str2 );
877  const char *const str3 = "#message { border: 0px; }";
878  rofi_theme_parse_string ( str3 );
879  }
880  else if ( g_strcmp0 ( config.separator_style, "solid" ) == 0 ) {
881  const char *const str = "#listview { border: 2px solid 0px 0px 0px; }";
882  rofi_theme_parse_string ( str );
883  const char *const str2 = "#sidebar { border: 2px solid 0px 0px 0px; }";
884  rofi_theme_parse_string ( str2 );
885  const char *const str3 = "#message { border: 2px solid 0px 0px 0px; }";
886  rofi_theme_parse_string ( str3 );
887  } /* dash is default */
888  }
889  /* Line Margin */
890  {
891  char *str = g_strdup_printf ( "#listview { spacing: %dpx;}", config.line_margin );
892  rofi_theme_parse_string ( str );
893  g_free ( str );
894  }
895  /* Line Padding */
896  {
897  char *str = g_strdup_printf ( "#element, inputbar, message { padding: %dpx;}", config.line_padding );
898  rofi_theme_parse_string ( str );
899  g_free ( str );
900  }
901  if ( config.hide_scrollbar ) {
902  const char *str = "#listview { scrollbar: false; }";
903  rofi_theme_parse_string ( str );
904  }
905  else {
906  const char *str = "#listview { scrollbar: true; }";
907  rofi_theme_parse_string ( str );
908  char *str2 = g_strdup_printf ( "#scrollbar { handle-width: %dpx; }", config.scrollbar_width );
909  rofi_theme_parse_string ( str2 );
910  g_free ( str2 );
911  }
912  if ( config.fake_transparency ) {
913  char *str = g_strdup_printf ( "#window { transparency: \"%s\"; }", config.fake_background );
914  rofi_theme_parse_string ( str );
915  g_free ( str );
916  }
917 }
918 #endif // THEME_CONVERTER
919 
920 char * rofi_theme_parse_prepare_file ( const char *file, const char *parent_file )
921 {
922  char *filename = rofi_expand_path ( file );
923  // If no absolute path specified, expand it.
924  if ( parent_file != NULL && !g_path_is_absolute ( filename ) ) {
925  char *basedir = g_path_get_dirname ( parent_file );
926  char *path = g_build_filename ( basedir, filename, NULL );
927  g_free ( filename );
928  filename = path;
929  g_free ( basedir );
930  }
931  GFile *gf = g_file_new_for_path ( filename );
932  g_free ( filename );
933  filename = g_file_get_path ( gf );
934  g_object_unref ( gf );
935 
936  return filename;
937 }
xcb_depth_t * depth
Definition: xcb.c:90
static void rofi_theme_print_property_index(size_t pnl, int depth, Property *p)
Definition: theme.c:178
void rofi_theme_free(ThemeWidget *widget)
Definition: theme.c:122
GList * rofi_theme_get_list(const widget *widget, const char *property, const char *defaults)
Definition: theme.c:692
void rofi_view_get_current_monitor(int *width, int *height)
Definition: view.c:134
ThemeWidget * rofi_theme_find_or_create_name(ThemeWidget *base, const char *name)
Definition: theme.c:52
unsigned int fake_transparency
Definition: settings.h:146
double distance
Definition: rofi-types.h:95
void rofi_theme_get_color(const widget *widget, const char *property, cairo_t *d)
Definition: theme.c:647
void rofi_theme_widget_add_properties(ThemeWidget *widget, GHashTable *table)
Definition: theme.c:385
RofiDistance bottom
Definition: rofi-types.h:133
double blue
Definition: rofi-types.h:121
Property * rofi_theme_property_copy(Property *p)
Definition: theme.c:77
ThemeWidget * rofi_theme_find_widget(const char *name, const char *state, gboolean exact)
Definition: theme.c:507
unsigned int padding
Definition: settings.h:96
static void printf_double(double d)
Definition: theme.c:142
RofiPadding padding
Definition: rofi-types.h:192
int yyparse()
unsigned int menu_bw
Definition: settings.h:55
char * rofi_theme_parse_prepare_file(const char *file, const char *parent_file)
Definition: theme.c:920
ThemeColor color
Definition: rofi-types.h:190
Property * rofi_theme_find_property(ThemeWidget *widget, PropertyType type, const char *property, gboolean exact)
Definition: theme.c:469
const char * rofi_theme_get_string(const widget *widget, const char *property, const char *def)
Definition: theme.c:604
double green
Definition: rofi-types.h:119
RofiHighlightStyle style
Definition: rofi-types.h:143
struct ThemeWidget ** widgets
Definition: theme.h:44
struct _widget * parent
double red
Definition: rofi-types.h:117
unsigned int scrollbar_width
Definition: settings.h:152
double rofi_theme_get_double(const widget *widget, const char *property, double def)
Definition: theme.c:620
RofiPadding rofi_theme_get_padding(const widget *widget, const char *property, RofiPadding pad)
Definition: theme.c:669
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition: theme.c:571
char * color_normal
Definition: settings.h:66
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition: theme.c:549
PropertyValue value
Definition: rofi-types.h:217
struct Property * ref
Definition: rofi-types.h:199
char * name
char * fake_background
Definition: settings.h:154
struct PropertyValue::@3 link
static void rofi_theme_print_distance(RofiDistance d)
Definition: theme.c:148
PropertyType type
Definition: rofi-types.h:215
void rofi_theme_property_free(Property *p)
Definition: theme.c:100
RofiHighlightColorStyle rofi_theme_get_highlight(widget *widget, const char *property, RofiHighlightColorStyle th)
Definition: theme.c:718
unsigned int num_widgets
Definition: theme.h:43
static void rofi_theme_resolve_link_property(Property *p, int depth)
Definition: theme.c:438
void yyerror(YYLTYPE *yylloc, const char *, const char *)
Definition: theme.c:359
gboolean b
Definition: rofi-types.h:188
Property * rofi_theme_property_create(PropertyType type)
Definition: theme.c:71
double textbox_get_estimated_ch(void)
Definition: textbox.c:904
RofiDistance right
Definition: rofi-types.h:132
char * name
Definition: rofi-types.h:213
struct _widget widget
Definition: widget.h:51
RofiLineStyle style
Definition: rofi-types.h:99
void rofi_theme_reset(void)
Definition: theme.c:115
RofiOrientation
Definition: rofi-types.h:105
char * color_window
Definition: settings.h:69
void rofi_add_error_message(GString *str)
Definition: rofi.c:86
char * rofi_expand_path(const char *input)
Definition: helper.c:669
void rofi_theme_print(ThemeWidget *widget)
Definition: theme.c:329
struct ThemeWidget * parent
Definition: theme.h:48
static void rofi_theme_print_index(ThemeWidget *widget)
Definition: theme.c:278
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition: theme.c:735
const char *const WindowLocationStr[9]
Definition: theme.c:166
double alpha
Definition: rofi-types.h:123
char * color_active
Definition: settings.h:67
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition: theme.c:587
char * separator_style
Definition: settings.h:140
ThemeWidget * rofi_theme
unsigned int hide_scrollbar
Definition: settings.h:142
const char *const PropertyTypeName[P_NUM_TYPES]
Definition: rofi-types.c:6
char * color_urgent
Definition: settings.h:68
GList * list
Definition: rofi-types.h:204
static void rofi_theme_copy_property_int(G_GNUC_UNUSED gpointer key, gpointer value, gpointer user_data)
Definition: theme.c:379
const char * state
int rofi_theme_get_position(const widget *widget, const char *property, int def)
Definition: theme.c:516
GHashTable * properties
Definition: theme.h:46
RofiHighlightColorStyle highlight
Definition: rofi-types.h:202
static ThemeWidget * rofi_theme_find(ThemeWidget *widget, const char *name, const gboolean exact)
Definition: theme.c:410
unsigned int line_margin
Definition: settings.h:135
Settings config
static gboolean distance_compare(RofiDistance d, RofiDistance e)
Definition: theme.c:47
static ThemeWidget * rofi_theme_find_single(ThemeWidget *widget, const char *name)
Definition: theme.c:400
double textbox_get_estimated_char_height(void)
Definition: textbox.c:883
void yylex_destroy(void)
PropertyType
Definition: rofi-types.h:10
RofiPixelUnit type
Definition: rofi-types.h:97
int rofi_theme_get_integer(const widget *widget, const char *property, int def)
Definition: theme.c:533
RofiDistance left
Definition: rofi-types.h:134
gboolean rofi_theme_parse_string(const char *string)
gboolean rofi_theme_is_empty(void)
Definition: theme.c:769
unsigned int line_padding
Definition: settings.h:136
void distance_get_linestyle(RofiDistance d, cairo_t *draw)
Definition: theme.c:758
char * name
Definition: theme.h:41
RofiDistance top
Definition: rofi-types.h:131
FILE * yyin