rofi/source/theme.c

329 lines
9.7 KiB
C
Raw Normal View History

2016-12-09 18:49:49 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "theme.h"
2016-12-12 15:55:31 +00:00
#include "lexer/theme-parser.h"
2016-12-28 11:21:42 +00:00
#include "helper.h"
2016-12-31 22:27:17 +00:00
#include "widgets/textbox.h"
2016-12-12 15:55:31 +00:00
void yyerror ( YYLTYPE *ylloc, const char *);
2016-12-09 18:49:49 +00:00
Widget *rofi_theme_find_or_create_class ( Widget *base, const char *class )
{
for ( unsigned int i = 0; i < base->num_widgets;i++){
if ( g_strcmp0(base->widgets[i]->name, class) == 0 ){
return base->widgets[i];
2016-12-12 15:55:31 +00:00
}
2016-12-09 18:49:49 +00:00
}
base->widgets = g_realloc ( base->widgets, sizeof(Widget*)*(base->num_widgets+1));
base->widgets[base->num_widgets] = g_malloc0(sizeof(Widget));
Widget *retv = base->widgets[base->num_widgets];
retv->parent = base;
retv->name = g_strdup(class);
base->num_widgets++;
return retv;
}
/**
* Properties
*/
Property *rofi_theme_property_create ( PropertyType type )
{
Property *retv = g_malloc0 ( sizeof(Property) );
retv->type = type;
return retv;
}
void rofi_theme_property_free ( Property *p )
{
if ( p == NULL ) {
return;
}
g_free ( p->name );
if ( p->type == P_STRING ) {
g_free ( p->value.s );
}
g_free(p);
}
void rofi_theme_free ( Widget *widget )
{
if ( widget == NULL ){
return;
}
if ( widget->properties ) {
g_hash_table_destroy ( widget->properties );
}
for ( unsigned int i = 0; i < widget->num_widgets; i++ ){
rofi_theme_free ( widget->widgets[i] );
2016-12-09 18:49:49 +00:00
}
g_free ( widget->widgets );
g_free ( widget->name );
g_free ( widget );
}
/**
* print
*/
static void rofi_theme_print_property_index ( int depth, Property *p )
{
printf("%*s %s: ", depth, "", p->name );
switch ( p->type )
{
case P_STRING:
printf("\"%s\"", p->value.s);
2016-12-09 18:49:49 +00:00
break;
case P_INTEGER:
printf("%d", p->value.i);
2016-12-09 18:49:49 +00:00
break;
2016-12-09 21:16:31 +00:00
case P_DOUBLE:
2016-12-09 18:49:49 +00:00
printf("%.2f", p->value.f);
break;
case P_BOOLEAN:
printf("%s", p->value.b?"true":"false");
break;
case P_COLOR:
2016-12-10 18:48:44 +00:00
printf("#%02X%02X%02X%02X",
(unsigned char)(p->value.color.alpha*255.0),
(unsigned char)(p->value.color.red*255.0),
(unsigned char)(p->value.color.green*255.0),
(unsigned char)(p->value.color.blue*255.0));
2016-12-09 18:49:49 +00:00
break;
2016-12-31 21:47:22 +00:00
case P_PADDING:
2016-12-31 22:27:17 +00:00
printf("%f%s %f%s %f%s %f%s",
2016-12-31 21:47:22 +00:00
p->value.padding.left.distance,
p->value.padding.left.type == PW_PX? "px":"em",
p->value.padding.right.distance,
p->value.padding.right.type == PW_PX? "px":"em",
p->value.padding.top.distance,
p->value.padding.top.type == PW_PX? "px":"em",
p->value.padding.bottom.distance,
p->value.padding.bottom.type == PW_PX? "px":"em"
);
2016-12-09 18:49:49 +00:00
}
putchar ( '\n' );
}
static void rofi_theme_print_index ( int depth, Widget *widget )
{
printf ( "%*sName: %s \n", depth, "", widget->name );
GHashTableIter iter;
gpointer key, value;
if ( widget->properties ){
g_hash_table_iter_init (&iter, widget->properties);
while (g_hash_table_iter_next (&iter, &key, &value))
{
Property *p = (Property*)value;
rofi_theme_print_property_index ( depth, p );
}
}
for ( unsigned int i = 0; i < widget->num_widgets;i++){
rofi_theme_print_index ( depth+2, widget->widgets[i] );
}
}
void rofi_theme_print ( Widget *widget )
{
rofi_theme_print_index ( 0, widget);
}
2016-12-19 14:50:35 +00:00
int yyparse();
void yylex_destroy( void );
2016-12-09 18:49:49 +00:00
extern FILE* yyin;
extern Widget *rofi_theme;
2016-12-12 15:55:31 +00:00
void yyerror(YYLTYPE *yylloc, const char* s) {
2016-12-09 21:16:31 +00:00
fprintf(stderr, "Parse error: %s\n", s);
2016-12-12 15:55:31 +00:00
fprintf(stderr, "From line %d column %d to line %d column %d\n", yylloc->first_line, yylloc->first_column, yylloc->last_line, yylloc->last_column);
2016-12-09 21:16:31 +00:00
exit(EXIT_FAILURE);
}
static gboolean rofi_theme_steal_property_int ( gpointer key, gpointer value, gpointer user_data)
{
GHashTable *table = (GHashTable*)user_data;
g_hash_table_replace ( table, key, value);
return TRUE;
}
void rofi_theme_widget_add_properties ( Widget *widget, GHashTable *table )
{
if ( table == NULL ) {
return;
}
if ( widget->properties == NULL ){
widget->properties = table;
return;
}
g_hash_table_foreach_steal ( table, rofi_theme_steal_property_int, widget->properties );
g_hash_table_destroy ( table );
}
2016-12-09 21:16:31 +00:00
/**
* Public API
*/
2016-12-09 18:49:49 +00:00
void rofi_theme_parse_file ( const char *file )
{
2016-12-28 11:21:42 +00:00
char *filename = rofi_expand_path ( file );
yyin = fopen ( filename, "rb");
2016-12-09 18:49:49 +00:00
if ( yyin == NULL ){
2016-12-28 11:21:42 +00:00
fprintf(stderr, "Failed to open file: %s: '%s'\n", filename, strerror ( errno ) );
g_free(filename);
2016-12-09 18:49:49 +00:00
return;
}
while ( yyparse() );
2016-12-19 14:50:35 +00:00
yylex_destroy();
2016-12-28 11:21:42 +00:00
g_free(filename);
2016-12-09 18:49:49 +00:00
}
2016-12-15 08:46:42 +00:00
static Widget *rofi_theme_find_single ( Widget *widget, const char *name)
{
for ( unsigned int j = 0; j < widget->num_widgets;j++){
if ( g_strcmp0(widget->widgets[j]->name, name ) == 0 ){
return widget->widgets[j];
}
}
return widget;
}
2016-12-09 18:49:49 +00:00
2016-12-20 08:17:19 +00:00
static Widget *rofi_theme_find ( Widget *widget , const char *name, const gboolean exact )
2016-12-09 21:16:31 +00:00
{
2016-12-20 08:17:19 +00:00
if ( widget == NULL || name == NULL ) {
2016-12-12 08:11:57 +00:00
return widget;
}
2016-12-09 21:16:31 +00:00
char **names = g_strsplit ( name, "." , 0 );
int found = TRUE;
for ( unsigned int i = 0; found && names && names[i]; i++ ){
found = FALSE;
2016-12-15 08:46:42 +00:00
Widget *f = rofi_theme_find_single ( widget, names[i]);
if ( f != widget ){
widget = f;
found = TRUE;
2016-12-09 21:16:31 +00:00
}
}
2016-12-09 21:16:31 +00:00
g_strfreev(names);
2016-12-20 08:17:19 +00:00
if ( !exact || found ){
return widget;
} else {
return NULL;
}
2016-12-09 21:16:31 +00:00
}
static Property *rofi_theme_find_property ( Widget *widget, PropertyType type, const char *property )
{
while ( widget ) {
if ( widget->properties && g_hash_table_contains ( widget->properties, property) ) {
Property *p = g_hash_table_lookup ( widget->properties, property);
if ( p->type == type ){
return p;
}
}
2016-12-09 21:16:31 +00:00
widget = widget->parent;
}
return NULL;
}
2016-12-20 08:17:19 +00:00
static Widget *rofi_theme_find_widget ( const char *wclass, const char *name, const char *state )
2016-12-09 21:16:31 +00:00
{
2016-12-20 08:17:19 +00:00
// First find exact match based on name.
Widget *widget = rofi_theme_find ( rofi_theme, name, TRUE );
widget = rofi_theme_find ( widget, state, TRUE );
if ( widget == NULL ){
// Fall back to class
2016-12-20 08:17:19 +00:00
widget = rofi_theme_find ( rofi_theme, wclass, TRUE);
widget = rofi_theme_find ( widget, state, TRUE );
}
2016-12-20 08:17:19 +00:00
if ( widget == NULL ){
// Fuzzy finder
2016-12-20 09:27:23 +00:00
widget = rofi_theme_find ( rofi_theme, name, FALSE );
2016-12-20 08:17:19 +00:00
if ( widget == rofi_theme ){
widget = rofi_theme_find ( widget, wclass, FALSE );
}
widget = rofi_theme_find ( widget, state, FALSE );
}
return widget;
}
int rofi_theme_get_integer ( const char *wclass, const char *name, const char *state, const char *property, int def )
{
Widget *widget = rofi_theme_find_widget ( wclass, name, state );
2016-12-09 21:16:31 +00:00
Property *p = rofi_theme_find_property ( widget, P_INTEGER, property );
if ( p ){
return p->value.i;
}
return def;
}
2016-12-31 22:27:17 +00:00
Distance rofi_theme_get_distance ( const char *wclass, const char *name, const char *state, const char *property, int def )
{
Widget *widget = rofi_theme_find_widget ( wclass, name, state );
Property *p = rofi_theme_find_property ( widget, P_PADDING, property );
if ( p ){
return p->value.padding.left;
}
// Fall back to px if no metric is given.
p = rofi_theme_find_property ( widget, P_INTEGER, property );
if ( p ){
return (Distance){(double)p->value.i, PW_PX};
}
2016-12-31 22:27:17 +00:00
return (Distance){def, PW_PX};
}
2016-12-09 21:16:31 +00:00
int rofi_theme_get_boolean ( const char *wclass, const char *name, const char *state, const char *property, int def )
2016-12-09 21:16:31 +00:00
{
2016-12-20 08:17:19 +00:00
Widget *widget = rofi_theme_find_widget ( wclass, name, state );
2016-12-09 21:16:31 +00:00
Property *p = rofi_theme_find_property ( widget, P_BOOLEAN, property );
if ( p ){
return p->value.b;
}
return def;
}
char *rofi_theme_get_string ( const char *wclass, const char *name, const char *state, const char *property, char *def )
2016-12-09 21:16:31 +00:00
{
2016-12-20 08:17:19 +00:00
Widget *widget = rofi_theme_find_widget ( wclass, name, state );
2016-12-09 21:16:31 +00:00
Property *p = rofi_theme_find_property ( widget, P_STRING, property );
if ( p ){
return p->value.s;
}
return def;
}
double rofi_theme_get_double ( const char *wclass, const char *name, const char *state, const char *property, double def )
2016-12-09 21:16:31 +00:00
{
2016-12-20 08:17:19 +00:00
Widget *widget = rofi_theme_find_widget ( wclass, name, state );
2016-12-09 21:16:31 +00:00
Property *p = rofi_theme_find_property ( widget, P_DOUBLE, property );
if ( p ){
return p->value.b;
}
return def;
2016-12-09 18:49:49 +00:00
}
void rofi_theme_get_color ( const char *wclass, const char *name, const char *state, const char *property, cairo_t *d)
2016-12-11 11:19:46 +00:00
{
2016-12-20 08:17:19 +00:00
Widget *widget = rofi_theme_find_widget ( wclass, name, state );
2016-12-11 11:19:46 +00:00
Property *p = rofi_theme_find_property ( widget, P_COLOR, property );
if ( p ){
cairo_set_source_rgba ( d,
p->value.color.red,
p->value.color.green,
p->value.color.blue,
p->value.color.alpha
);
}
}
2016-12-27 21:19:15 +00:00
Padding rofi_theme_get_padding ( const char *wclass, const char *name, const char *state, const char *property, Padding pad )
{
Widget *widget = rofi_theme_find_widget ( wclass, name, state );
Property *p = rofi_theme_find_property ( widget, P_PADDING, property );
2016-12-27 21:19:15 +00:00
if ( p ){
pad = p->value.padding;
2016-12-27 21:19:15 +00:00
}
return pad;
}
2016-12-31 22:27:17 +00:00
int distance_get_pixel ( Distance d )
{
if ( d.type == PW_EM ){
return d.distance*textbox_get_estimated_char_height();
}
return d.distance;
}