diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a36dc0..4bf8df2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,7 +194,7 @@ endif( ENABLE_TINT2CONF ) if( ENABLE_ASAN ) SET(ASAN_C_FLAGS " -O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -Wshadow") - SET(ASAN_L_FLAGS " -O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic ") + SET(ASAN_L_FLAGS " -O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -fuse-ld=gold ") else() SET(ASAN_C_FLAGS "") SET(ASAN_L_FLAGS "") diff --git a/src/battery/battery.c b/src/battery/battery.c index 6cc6051..c9cb7b6 100644 --- a/src/battery/battery.c +++ b/src/battery/battery.c @@ -164,6 +164,7 @@ void init_battery_panel(void *p) battery->area.has_mouse_press_effect = battery->area.has_mouse_over_effect; if (battery_tooltip_enabled) battery->area._get_tooltip_text = battery_get_tooltip; + init_area_gradients(&battery->area); } void battery_init_fonts() diff --git a/src/clock/clock.c b/src/clock/clock.c index 868f228..1524287 100644 --- a/src/clock/clock.c +++ b/src/clock/clock.c @@ -196,6 +196,7 @@ void init_clock_panel(void *p) clock->area.resize_needed = 1; clock->area.on_screen = TRUE; + init_area_gradients(&clock->area); if (time_tooltip_format) { clock->area._get_tooltip_text = clock_get_tooltip; diff --git a/src/config.c b/src/config.c index 98ca619..c009e56 100644 --- a/src/config.c +++ b/src/config.c @@ -71,8 +71,6 @@ char *snapshot_path; // detect if it's an old config file (==1) static gboolean new_config_file; -static gboolean read_bg_color2; -static gboolean read_bg_gradient; static gboolean read_bg_color_hover; static gboolean read_border_color_hover; static gboolean read_bg_color_press; @@ -244,12 +242,10 @@ void add_entry(char *key, char *value) init_background(&bg); bg.border.radius = atoi(value); g_array_append_val(backgrounds, bg); - read_bg_color2 = 0; - read_bg_gradient = 0; - read_bg_color_hover = 0; - read_border_color_hover = 0; - read_bg_color_press = 0; - read_border_color_press = 0; + read_bg_color_hover = FALSE; + read_border_color_hover = FALSE; + read_bg_color_press = FALSE; + read_border_color_press = FALSE; } else if (strcmp(key, "border_width") == 0) { g_array_index(backgrounds, Background, backgrounds->len - 1).border.width = atoi(value); } else if (strcmp(key, "border_sides") == 0) { @@ -345,27 +341,13 @@ void add_entry(char *key, char *value) GradientClass *g = &g_array_index(gradients, GradientClass, gradients->len - 1); extract_values(value, &value1, &value2, &value3); ColorStop *color_stop = (ColorStop *) calloc(1, sizeof(ColorStop)); - color_stop->offset = atof(value1); + color_stop->offset = atof(value1) / 100.0; get_color(value2, color_stop->color.rgb); if (value3) - color_stop->color.alpha = (atoi(value2) / 100.0); + color_stop->color.alpha = (atoi(value3) / 100.0); else color_stop->color.alpha = 0.5; g->extra_color_stops = g_list_append(g->extra_color_stops, color_stop); - } else if (strcmp(key, "from_origin") == 0) { - GradientClass *g = &g_array_index(gradients, GradientClass, gradients->len - 1); - if (g->type == GRADIENT_HORIZONTAL || g->type == GRADIENT_VERTICAL || g->type == GRADIENT_CENTERED) { - fprintf(stderr, RED "Control points can only be specified for linear and radial gradients: line %s = %s" RESET "\n", key, value); - } else { - g->from.origin = origin_from_string(value); - } - } else if (strcmp(key, "to_origin") == 0) { - GradientClass *g = &g_array_index(gradients, GradientClass, gradients->len - 1); - if (g->type == GRADIENT_HORIZONTAL || g->type == GRADIENT_VERTICAL || g->type == GRADIENT_CENTERED) { - fprintf(stderr, RED "Control points can only be specified for linear and radial gradients: line %s = %s" RESET "\n", key, value); - } else { - g->to.origin = origin_from_string(value); - } } else if (strcmp(key, "from_offset_x") == 0) { GradientClass *g = &g_array_index(gradients, GradientClass, gradients->len - 1); if (g->type == GRADIENT_HORIZONTAL || g->type == GRADIENT_VERTICAL || g->type == GRADIENT_CENTERED) { @@ -554,7 +536,7 @@ void add_entry(char *key, char *value) int id = atoi(value); id = (id < gradients->len && id >= 0) ? id : -1; if (id >= 0) - panel_config.area.gradients = g_list_append(panel_config.area.gradients, &g_array_index(backgrounds, Background, id)); + panel_config.area.gradients = g_list_append(panel_config.area.gradients, &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "wm_menu") == 0) wm_menu = atoi(value); else if (strcmp(key, "panel_dock") == 0) @@ -663,7 +645,7 @@ void add_entry(char *key, char *value) int id = atoi(value); id = (id < gradients->len && id >= 0) ? id : -1; if (id >= 0) - panel_config.battery.area.gradients = g_list_append(panel_config.battery.area.gradients, &g_array_index(backgrounds, Background, id)); + panel_config.battery.area.gradients = g_list_append(panel_config.battery.area.gradients, &g_array_index(gradients, GradientClass, id)); #endif } else if (strcmp(key, "battery_hide") == 0) { #ifdef ENABLE_BATTERY @@ -690,7 +672,7 @@ void add_entry(char *key, char *value) int id = atoi(value); id = (id < gradients->len && id >= 0) ? id : -1; if (id >= 0) - separator->area.gradients = g_list_append(separator->area.gradients, &g_array_index(backgrounds, Background, id)); + separator->area.gradients = g_list_append(separator->area.gradients, &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "separator_color") == 0) { Separator *separator = get_or_create_last_separator(); extract_values(value, &value1, &value2, &value3); @@ -788,7 +770,7 @@ void add_entry(char *key, char *value) int id = atoi(value); id = (id < gradients->len && id >= 0) ? id : -1; if (id >= 0) - execp->area.gradients = g_list_append(execp->area.gradients, &g_array_index(backgrounds, Background, id)); + execp->area.gradients = g_list_append(execp->area.gradients, &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "execp_centered") == 0) { Execp *execp = get_or_create_last_execp(); execp->backend->centered = atoi(value); @@ -889,7 +871,7 @@ void add_entry(char *key, char *value) int id = atoi(value); id = (id < gradients->len && id >= 0) ? id : -1; if (id >= 0) - panel_config.clock.area.gradients = g_list_append(panel_config.clock.area.gradients, &g_array_index(backgrounds, Background, id)); + panel_config.clock.area.gradients = g_list_append(panel_config.clock.area.gradients, &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "clock_tooltip") == 0) { if (strlen(value) > 0) time_tooltip_format = strdup(value); @@ -1175,7 +1157,7 @@ void add_entry(char *key, char *value) int id = atoi(value); id = (id < gradients->len && id >= 0) ? id : -1; if (id >= 0) - launcher_icon_gradient = &g_array_index(gradients, GradientClass, id); + launcher_icon_gradients = g_list_append(launcher_icon_gradients, &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "launcher_icon_size") == 0) { launcher_max_icon_size = atoi(value); } else if (strcmp(key, "launcher_item_app") == 0) { diff --git a/src/execplugin/execplugin.c b/src/execplugin/execplugin.c index 86259aa..581d098 100644 --- a/src/execplugin/execplugin.c +++ b/src/execplugin/execplugin.c @@ -182,6 +182,7 @@ void init_execp_panel(void *p) execp->area.resize_needed = TRUE; execp->area.on_screen = TRUE; + init_area_gradients(&execp->area); if (!execp->backend->timer) execp->backend->timer = add_timeout(10, 0, execp_timer_callback, execp, &execp->backend->timer); diff --git a/src/launcher/launcher.c b/src/launcher/launcher.c index 79a44bb..31642dd 100644 --- a/src/launcher/launcher.c +++ b/src/launcher/launcher.c @@ -53,7 +53,7 @@ char *icon_theme_name_xsettings; int launcher_icon_theme_override; int startup_notifications; Background *launcher_icon_bg; -GradientClass *launcher_icon_gradient; +GList *launcher_icon_gradients; Imlib_Image scale_icon(Imlib_Image original, int icon_size); void free_icon(Imlib_Image icon); @@ -76,6 +76,7 @@ void default_launcher() launcher_icon_theme_override = 0; startup_notifications = 0; launcher_icon_bg = NULL; + launcher_icon_gradients = NULL; } void init_launcher() @@ -107,6 +108,7 @@ void init_launcher_panel(void *p) launcher->area.on_screen = TRUE; panel_refresh = TRUE; + init_area_gradients(&launcher->area); launcher_load_themes(launcher); launcher_load_icons(launcher); @@ -422,16 +424,20 @@ void launcher_load_icons(Launcher *launcher) { // Load apps (.desktop style launcher items) GSList *app = launcher->list_apps; + int index = 0; while (app != NULL) { - LauncherIcon *launcherIcon = calloc(1, sizeof(LauncherIcon)); + index++; + LauncherIcon *launcherIcon = (LauncherIcon *)calloc(1, sizeof(LauncherIcon)); launcherIcon->area.panel = launcher->area.panel; launcherIcon->area._draw_foreground = draw_launcher_icon; launcherIcon->area.size_mode = LAYOUT_FIXED; launcherIcon->area._resize = NULL; + sprintf(launcherIcon->area.name, "LauncherIcon %d", index); launcherIcon->area.resize_needed = 0; launcherIcon->area.has_mouse_over_effect = panel_config.mouse_effects; launcherIcon->area.has_mouse_press_effect = launcherIcon->area.has_mouse_over_effect; launcherIcon->area.bg = launcher_icon_bg; + launcherIcon->area.gradients = launcher_icon_gradients; launcherIcon->area.on_screen = TRUE; launcherIcon->area._on_change_layout = launcher_icon_on_change_layout; launcherIcon->area._dump_geometry = launcher_icon_dump_geometry; @@ -444,6 +450,7 @@ void launcher_load_icons(Launcher *launcher) add_area(&launcherIcon->area, (Area *)launcher); launcher->list_icons = g_slist_append(launcher->list_icons, launcherIcon); launcher_reload_icon(launcher, launcherIcon); + init_area_gradients(&launcherIcon->area); app = g_slist_next(app); } } diff --git a/src/launcher/launcher.h b/src/launcher/launcher.h index 0185eff..c3652ec 100644 --- a/src/launcher/launcher.h +++ b/src/launcher/launcher.h @@ -46,7 +46,7 @@ extern char *icon_theme_name_config; extern int launcher_icon_theme_override; extern int startup_notifications; extern Background *launcher_icon_bg; -extern GradientClass *launcher_icon_gradient; +extern GList *launcher_icon_gradients; // default global data void default_launcher(); diff --git a/src/panel.c b/src/panel.c index 8652d88..d34e6d7 100644 --- a/src/panel.c +++ b/src/panel.c @@ -56,6 +56,7 @@ gboolean panel_refresh; gboolean task_dragged; char *panel_window_name = NULL; gboolean debug_geometry; +gboolean debug_gradients; gboolean panel_autohide; int panel_autohide_show_timeout; @@ -115,6 +116,9 @@ void default_panel() Background transparent_bg; init_background(&transparent_bg); g_array_append_val(backgrounds, transparent_bg); + GradientClass transparent_gradient; + init_gradient(&transparent_gradient, GRADIENT_VERTICAL); + g_array_append_val(gradients, transparent_gradient); } void cleanup_panel() @@ -215,6 +219,7 @@ void init_panel() p->area._clear = panel_clear_background; p->separator_list = NULL; init_panel_size_and_position(p); + init_area_gradients(&p->area); // add children according to panel_items for (int k = 0; k < strlen(panel_items_order); k++) { if (panel_items_order[k] == 'L') diff --git a/src/separator/separator.c b/src/separator/separator.c index c005dd9..7912d1e 100644 --- a/src/separator/separator.c +++ b/src/separator/separator.c @@ -84,6 +84,7 @@ void init_separator_panel(void *p) separator->area.on_screen = TRUE; separator->area._resize = resize_separator; separator->area._draw_foreground = draw_separator; + init_area_gradients(&separator->area); } } diff --git a/src/systray/systraybar.c b/src/systray/systraybar.c index 6c907b4..dac23ed 100644 --- a/src/systray/systraybar.c +++ b/src/systray/systraybar.c @@ -123,6 +123,7 @@ void init_systray_panel(void *p) show(&systray.area); schedule_redraw(&systray.area); refresh_systray = TRUE; + init_area_gradients(&systray.area); } gboolean resize_systray(void *obj) @@ -1500,9 +1501,9 @@ void refresh_systray_icons() } } -gboolean systray_on_monitor(int i_monitor, int num_panels) +gboolean systray_on_monitor(int i_monitor, int n_panels) { - return (i_monitor == systray_monitor) || (i_monitor == 0 && (systray_monitor >= num_panels || systray_monitor < 0)); + return (i_monitor == systray_monitor) || (i_monitor == 0 && (systray_monitor >= n_panels || systray_monitor < 0)); } TrayWindow *systray_find_icon(Window win) diff --git a/src/taskbar/task.c b/src/taskbar/task.c index 67cf169..490d887 100644 --- a/src/taskbar/task.c +++ b/src/taskbar/task.c @@ -595,6 +595,9 @@ void set_task_state(Task *task, TaskState state) Task *task1 = g_ptr_array_index(task_buttons, i); task1->current_state = state; task1->area.bg = panels[0].g_task.background[state]; + free_area_gradients(&task1->area); + task1->area.gradients = panels[0].g_task.gradient[state]; + init_area_gradients(&task1->area); schedule_redraw(&task1->area); if (state == TASK_ACTIVE && g_slist_find(urgent_list, task1)) del_urgent(task1); diff --git a/src/taskbar/taskbar.c b/src/taskbar/taskbar.c index 43b26d4..501fff4 100644 --- a/src/taskbar/taskbar.c +++ b/src/taskbar/taskbar.c @@ -304,10 +304,18 @@ void init_taskbar_panel(void *p) taskbar = &panel->taskbar[j]; memcpy(&taskbar->area, &panel->g_taskbar.area, sizeof(Area)); taskbar->desktop = j; - if (j == server.desktop) + if (j == server.desktop) { taskbar->area.bg = panel->g_taskbar.background[TASKBAR_ACTIVE]; - else + free_area_gradients(&taskbar->area); + taskbar->area.gradients = panel->g_taskbar.gradient[TASKBAR_ACTIVE]; + init_area_gradients(&taskbar->area); + } else { taskbar->area.bg = panel->g_taskbar.background[TASKBAR_NORMAL]; + free_area_gradients(&taskbar->area); + taskbar->area.gradients = panel->g_taskbar.gradient[TASKBAR_NORMAL]; + init_area_gradients(&taskbar->area); + } + } init_taskbarname_panel(panel); } @@ -478,8 +486,15 @@ void update_all_taskbars_visibility() void set_taskbar_state(Taskbar *taskbar, TaskbarState state) { taskbar->area.bg = panels[0].g_taskbar.background[state]; + free_area_gradients(&taskbar->area); + taskbar->area.gradients = panels[0].g_taskbar.gradient[state]; + init_area_gradients(&taskbar->area); + if (taskbarname_enabled) { taskbar->bar_name.area.bg = panels[0].g_taskbar.background_name[state]; + free_area_gradients(&taskbar->bar_name.area); + taskbar->bar_name.area.gradients = panels[0].g_taskbar.gradient_name[state]; + init_area_gradients(&taskbar->bar_name.area); } update_taskbar_visibility(taskbar); diff --git a/src/taskbar/taskbarname.c b/src/taskbar/taskbarname.c index a8248cf..6a76416 100644 --- a/src/taskbar/taskbarname.c +++ b/src/taskbar/taskbarname.c @@ -60,10 +60,13 @@ void init_taskbarname_panel(void *p) taskbar->bar_name.area.parent = taskbar; taskbar->bar_name.area.has_mouse_over_effect = panel_config.mouse_effects; taskbar->bar_name.area.has_mouse_press_effect = panel_config.mouse_effects; - if (j == server.desktop) + if (j == server.desktop) { taskbar->bar_name.area.bg = panel->g_taskbar.background_name[TASKBAR_ACTIVE]; - else + taskbar->bar_name.area.gradients = panel->g_taskbar.gradient_name[TASKBAR_ACTIVE]; + } else { taskbar->bar_name.area.bg = panel->g_taskbar.background_name[TASKBAR_NORMAL]; + taskbar->bar_name.area.gradients = panel->g_taskbar.gradient_name[TASKBAR_NORMAL]; + } // use desktop number if name is missing if (l) { @@ -75,6 +78,7 @@ void init_taskbarname_panel(void *p) // append the name at the beginning of taskbar taskbar->area.children = g_list_append(taskbar->area.children, &taskbar->bar_name); + init_area_gradients(&taskbar->bar_name.area); } for (l = list; l; l = l->next) diff --git a/src/tint.c b/src/tint.c index dab4da4..433be2b 100644 --- a/src/tint.c +++ b/src/tint.c @@ -375,6 +375,7 @@ void init(int argc, char *argv[]) #endif debug_geometry = getenv("DEBUG_GEOMETRY") != NULL; + debug_gradients = getenv("DEBUG_GRADIENTS") != NULL; } static int sigchild_pipe_valid = FALSE; diff --git a/src/util/area.c b/src/util/area.c index 2e2e960..d3c739e 100644 --- a/src/util/area.c +++ b/src/util/area.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -481,21 +482,19 @@ void draw_background(Area *a, cairo_t *c) a->bg->border.radius - a->bg->border.width / 1.571); cairo_fill(c); - - /* - cairo_pattern_t *cairo_gradient_pattern; - - if (area_has_gradient_fill(a)) { - cairo_gradient_pattern = cairo_pattern_create_linear(0.0, 0.0, 0.0, a->height - top_bottom_border_width(a)); - cairo_pattern_add_color_stop_rgba(cairo_gradient_pattern, 0.1, a->bg->fill_color.rgb[0], - a->bg->fill_color.rgb[1], a->bg->fill_color.rgb[2], a->bg->fill_color.alpha); - cairo_pattern_add_color_stop_rgba(cairo_gradient_pattern, 0.9, a->bg->fill_color2.rgb[0], - a->bg->fill_color2.rgb[1], a->bg->fill_color2.rgb[2], a->bg->fill_color2.alpha); - cairo_set_source(c, cairo_gradient_pattern); - } else - if (area_has_gradient_fill(a)) - cairo_pattern_destroy(cairo_gradient_pattern); - */ + } + for (GList *l = a->gradient_instances; l; l = l->next) { + GradientInstance *gi = (GradientInstance *)l->data; + if (!gi->pattern) + update_gradient(gi); + cairo_set_source(c, gi->pattern); + draw_rect(c, + left_border_width(a), + top_border_width(a), + a->width - left_right_border_width(a), + a->height - top_bottom_border_width(a), + a->bg->border.radius - a->bg->border.width / 1.571); + cairo_fill(c); } if (a->bg->border.width > 0) { @@ -537,6 +536,8 @@ void remove_area(Area *a) Area *area = (Area *)a; Area *parent = (Area *)area->parent; + free_area_gradients(a); + if (parent) { parent->children = g_list_remove(parent->children, area); parent->resize_needed = TRUE; @@ -560,7 +561,6 @@ void add_area(Area *a, Area *parent) schedule_redraw(parent); panel_refresh = TRUE; } - init_area_gradients(a); } void free_area(Area *a) @@ -846,86 +846,80 @@ void area_dump_geometry(Area *area, int indent) } } -void instantiate_gradient_offsets(Area *area, GradientInstance *gi, GList *offsets, GList **offset_instances) +Area *compute_element_area(Area *area, Element element) +{ + if (element == ELEMENT_SELF) + return area; + if (element == ELEMENT_PARENT) + return (Area *)area->parent; + if (element == ELEMENT_PANEL) + return (Area *)area->panel; + g_assert_not_reached(); + return area; +} + +void instantiate_gradient_offsets(GradientInstance *gi, GList *offsets) { for (GList *l = offsets; l; l = l->next) { Offset *offset = (Offset *)l->data; - OffsetInstance *offset_instance = (OffsetInstance *)calloc(1, sizeof(OffsetInstance)); - offset_instance->constant = offset->constant; - if (offset_instance->constant) { - offset_instance->constant_value = offset->constant_value; - } else { - offset_instance->variable = offset->variable; - offset_instance->multiplier = offset->multiplier; - if (offset->variable_element == ORIGIN_ELEMENT) - offset_instance->variable_element = area; - else if (offset->variable_element == ORIGIN_PARENT) - offset_instance->variable_element = area->parent ? (Area *)area->parent : area; - else if (offset->variable_element == ORIGIN_PANEL) - offset_instance->variable_element = (Area *)area->panel; - else if (offset->variable_element == ORIGIN_SCREEN) - // TODO - offset_instance->variable_element = (Area *)area->panel; - else if (offset->variable_element == ORIGIN_DESKTOP) - // TODO - offset_instance->variable_element = (Area *)area->panel; - else - g_assert_not_reached(); - *offset_instances = g_list_append(*offset_instances, offset_instance); - offset_instance->variable_element->dependent_gradients = - g_list_append(offset_instance->variable_element->dependent_gradients, gi); - gi->gradient_dependencies = g_list_append(gi->gradient_dependencies, offset_instance->variable_element); + if (!offset->constant) { + Area *element_area = compute_element_area(gi->area, offset->element); + element_area->dependent_gradients = g_list_append(element_area->dependent_gradients, gi); } } } -void free_gradient_offsets(GradientInstance *gi, GList **offset_instances) +void free_gradient_offsets(GradientInstance *gi, GList **offsets) { - for (GList *l = *offset_instances; l; l = l->next) { - OffsetInstance *offset_instance = (OffsetInstance *)l->data; - if (!offset_instance->constant) { - offset_instance->variable_element->dependent_gradients = - g_list_remove_all(offset_instance->variable_element->dependent_gradients, gi); - gi->gradient_dependencies = g_list_remove_all(gi->gradient_dependencies, offset_instance->variable_element); + for (GList *l = *offsets; l; l = l->next) { + Offset *offset = (Offset *)l->data; + if (!offset->constant) { + Area *element_area = compute_element_area(gi->area, offset->element); + element_area->dependent_gradients = g_list_remove_all(element_area->dependent_gradients, gi); } } - g_list_free_full(*offset_instances, free); } -void instantiate_gradient_point(Area *area, - GradientInstance *gi, - ControlPoint *control, - ControlPointInstance *control_instance) +void instantiate_gradient_point(GradientInstance *gi, ControlPoint *control) { - instantiate_gradient_offsets(area, gi, control->offsets_x, &control_instance->offsets_x); - instantiate_gradient_offsets(area, gi, control->offsets_y, &control_instance->offsets_y); - instantiate_gradient_offsets(area, gi, control->offsets_r, &control_instance->offsets_r); + instantiate_gradient_offsets(gi, control->offsets_x); + instantiate_gradient_offsets(gi, control->offsets_y); + instantiate_gradient_offsets(gi, control->offsets_r); } -void free_gradient_point(GradientInstance *gi, ControlPointInstance *control_instance) +void free_gradient_point(GradientInstance *gi, ControlPoint *control) { - free_gradient_offsets(gi, &control_instance->offsets_x); - free_gradient_offsets(gi, &control_instance->offsets_y); - free_gradient_offsets(gi, &control_instance->offsets_r); + free_gradient_offsets(gi, &control->offsets_x); + free_gradient_offsets(gi, &control->offsets_y); + free_gradient_offsets(gi, &control->offsets_r); } void instantiate_gradient(Area *area, GradientClass *g, GradientInstance *gi) { - gi->gradient_class = g; + g_assert_nonnull(area); + g_assert_nonnull(g); gi->area = area; - gi->from.origin = area; - instantiate_gradient_point(area, gi, &g->from, &gi->from); - instantiate_gradient_point(area, gi, &g->to, &gi->to); + gi->gradient_class = g; + instantiate_gradient_point(gi, &g->from); + instantiate_gradient_point(gi, &g->to); } void free_gradient(GradientInstance *gi) { - free_gradient_point(gi, &gi->from); - free_gradient_point(gi, &gi->to); + if (gi->pattern) { + cairo_pattern_destroy(gi->pattern); + gi->pattern = NULL; + } + free_gradient_point(gi, &gi->gradient_class->from); + free_gradient_point(gi, &gi->gradient_class->to); + gi->gradient_class = NULL; } void init_area_gradients(Area *area) { + g_assert_null(area->gradient_instances); + if (debug_gradients) + fprintf(stderr, "Initializing gradients for area %s\n", area->name); for (GList *l = area->gradients; l; l = l->next) { GradientClass *g = (GradientClass *)l->data; GradientInstance *gi = (GradientInstance *)calloc(1, sizeof(GradientInstance)); @@ -936,14 +930,170 @@ void init_area_gradients(Area *area) void free_area_gradients(Area *area) { + if (debug_gradients) + fprintf(stderr, "Freeing gradients for area %s\n", area->name); for (GList *l = area->gradient_instances; l; l = l->next) { GradientInstance *gi = (GradientInstance *)l->data; free_gradient(gi); } g_list_free_full(area->gradient_instances, free); + area->gradient_instances = NULL; + g_assert_null(area->dependent_gradients); +} + +double compute_control_point_offset(Area *area, Offset *offset) +{ + if (offset->constant) + return offset->constant_value; + + Area *element_area = compute_element_area(area, offset->element); + Area *parent_area = ((Area *)area->parent); + g_assert_nonnull(element_area); + g_assert_nonnull(parent_area); + + double width = element_area->width; + double height = element_area->height; + double radius = sqrt(element_area->width * element_area->width + element_area->height * element_area->height) / 2.0; + + double left, top; + if (offset->element == ELEMENT_SELF) { + left = 0; + top = 0; + } else if (offset->element == ELEMENT_PARENT) { + left = parent_area->posx - area->posx; + top = parent_area->posy - area->posy; + } else if (offset->element == ELEMENT_PANEL) { + left = 0 - area->posx; + top = 0 - area->posy; + } + + double right = left + width; + double bottom = top + height; + double center_x = left + 0.5 * width; + double center_y = top + 0.5 * height; + + if (offset->variable == SIZE_WIDTH) + return width * offset->multiplier; + if (offset->variable == SIZE_HEIGHT) + return height * offset->multiplier; + if (offset->variable == SIZE_RADIUS) + return radius * offset->multiplier; + if (offset->variable == SIZE_LEFT) + return left * offset->multiplier; + if (offset->variable == SIZE_RIGHT) + return right * offset->multiplier; + if (offset->variable == SIZE_TOP) + return top * offset->multiplier; + if (offset->variable == SIZE_BOTTOM) + return bottom * offset->multiplier; + if (offset->variable == SIZE_CENTERX) + return center_x * offset->multiplier; + if (offset->variable == SIZE_CENTERY) + return center_y * offset->multiplier; + + g_assert_not_reached(); + return 0; +} + +double compute_control_point_offsets(GradientInstance *gi, GList *offsets) +{ + double result = 0; + for (GList *l = offsets; l; l = l->next) { + Offset *offset = (Offset *)l->data; + result += compute_control_point_offset(gi->area, offset); + } + return result; +} + +void compute_control_point(GradientInstance *gi, ControlPoint *control, double *x, double *y, double *r) +{ + *x = compute_control_point_offsets(gi, control->offsets_x); + *y = compute_control_point_offsets(gi, control->offsets_y); + *r = compute_control_point_offsets(gi, control->offsets_r); } void update_gradient(GradientInstance *gi) { - // TODO + if (gi->pattern) { + return; + cairo_pattern_destroy(gi->pattern); + gi->pattern = NULL; + } + schedule_redraw(gi->area); + double from_x, from_y, from_r; + compute_control_point(gi, &gi->gradient_class->from, &from_x, &from_y, &from_r); + double to_x, to_y, to_r; + compute_control_point(gi, &gi->gradient_class->to, &to_x, &to_y, &to_r); + if (gi->gradient_class->type == GRADIENT_VERTICAL || gi->gradient_class->type == GRADIENT_HORIZONTAL || + gi->gradient_class->type == GRADIENT_LINEAR) { + gi->pattern = cairo_pattern_create_linear(from_x, from_y, to_x, to_y); + if (debug_gradients) + fprintf(stderr, + "Creating linear gradient for area %s: %f %f, %f %f\n", + gi->area->name, + from_x, + from_y, + to_x, + to_y); + } else if (gi->gradient_class->type == GRADIENT_CENTERED || gi->gradient_class->type == GRADIENT_RADIAL) { + gi->pattern = cairo_pattern_create_radial(from_x, from_y, from_r, to_x, to_y, to_r); + if (debug_gradients) + fprintf(stderr, + "Creating radial gradient for area %s: %f %f %f, %f %f %f\n", + gi->area->name, + from_x, + from_y, + from_r, + to_x, + to_y, + to_r); + } else { + g_assert_not_reached(); + } + if (debug_gradients) + fprintf(stderr, + "Adding color stop at offset %f: %f %f %f %f\n", + 0.0, + gi->gradient_class->start_color.rgb[0], + gi->gradient_class->start_color.rgb[1], + gi->gradient_class->start_color.rgb[2], + gi->gradient_class->start_color.alpha); + cairo_pattern_add_color_stop_rgba(gi->pattern, + 0, + gi->gradient_class->start_color.rgb[0], + gi->gradient_class->start_color.rgb[1], + gi->gradient_class->start_color.rgb[2], + gi->gradient_class->start_color.alpha); + for (GList *l = gi->gradient_class->extra_color_stops; l; l = l->next) { + ColorStop *color_stop = (ColorStop *)l->data; + if (debug_gradients) + fprintf(stderr, + "Adding color stop at offset %f: %f %f %f %f\n", + color_stop->offset, + color_stop->color.rgb[0], + color_stop->color.rgb[1], + color_stop->color.rgb[2], + color_stop->color.alpha); + cairo_pattern_add_color_stop_rgba(gi->pattern, + color_stop->offset, + color_stop->color.rgb[0], + color_stop->color.rgb[1], + color_stop->color.rgb[2], + color_stop->color.alpha); + } + if (debug_gradients) + fprintf(stderr, + "Adding color stop at offset %f: %f %f %f %f\n", + 1.0, + gi->gradient_class->end_color.rgb[0], + gi->gradient_class->end_color.rgb[1], + gi->gradient_class->end_color.rgb[2], + gi->gradient_class->end_color.alpha); + cairo_pattern_add_color_stop_rgba(gi->pattern, + 1.0, + gi->gradient_class->end_color.rgb[0], + gi->gradient_class->end_color.rgb[1], + gi->gradient_class->end_color.rgb[2], + gi->gradient_class->end_color.alpha); + schedule_redraw(gi->area); } diff --git a/src/util/common.c b/src/util/common.c index fb000c2..ebe40d1 100644 --- a/src/util/common.c +++ b/src/util/common.c @@ -199,101 +199,44 @@ void get_color(char *hex, double *rgb) rgb[2] = (b / 255.0); } -void extract_values(const char *value, char **value1, char **value2, char **value3) +void extract_values(const char *str, char **value1, char **value2, char **value3) { - char *value0 = strdup(value); - char *b = 0, *c = 0; - - if (*value1) - free(*value1); - if (*value2) - free(*value2); - if (*value3) - free(*value3); - - if ((b = strchr(value0, ' '))) { - b[0] = '\0'; - b++; - } else { - *value2 = 0; - *value3 = 0; - } - *value1 = strdup(value0); - g_strstrip(*value1); - - if (b) { - if ((c = strchr(b, ' '))) { - c[0] = '\0'; - c++; - } else { - c = 0; - *value3 = 0; + *value1 = NULL; + *value2 = NULL; + *value3 = NULL; + char **tokens = g_strsplit(str, " ", 3); + if (tokens[0]) { + *value1 = strdup(tokens[0]); + if (tokens[1]) { + *value2 = strdup(tokens[1]); + if (tokens[2]) { + *value3 = strdup(tokens[2]); + } } - *value2 = strdup(b); - g_strstrip(*value2); } - - if (c) { - *value3 = strdup(c); - g_strstrip(*value3); - } - - free(value0); + g_strfreev(tokens); } -void extract_values_4(const char *value, char **value1, char **value2, char **value3, char **value4) +void extract_values_4(const char *str, char **value1, char **value2, char **value3, char **value4) { - char *value0 = strdup(value); - char *b = 0, *c = 0, *d; - - if (*value1) - free(*value1); - if (*value2) - free(*value2); - if (*value3) - free(*value3); - if (*value4) - free(*value4); - - if ((b = strchr(value0, ' '))) { - b[0] = '\0'; - b++; - } else { - *value2 = 0; - *value3 = 0; - *value4 = 0; - } - *value1 = strdup(value0); - g_strstrip(*value1); - - if (b) { - if ((c = strchr(b, ' '))) { - c[0] = '\0'; - c++; - } else { - c = 0; - *value3 = 0; - *value4 = 0; + *value1 = NULL; + *value2 = NULL; + *value3 = NULL; + *value4 = NULL; + char **tokens = g_strsplit(str, " ", 4); + if (tokens[0]) { + *value1 = strdup(tokens[0]); + if (tokens[1]) { + *value2 = strdup(tokens[1]); + if (tokens[2]) { + *value3 = strdup(tokens[2]); + if (tokens[3]) { + *value4 = strdup(tokens[3]); + } + } } - *value2 = strdup(b); - g_strstrip(*value2); } - - if (c) { - if ((d = strchr(c, ' '))) { - d[0] = '\0'; - d++; - } else { - d = 0; - *value4 = 0; - } - *value3 = strdup(c); - g_strstrip(*value3); - - *value4 = strdup(d); - g_strstrip(*value4); - } - free(value0); + g_strfreev(tokens); } void adjust_asb(DATA32 *data, int w, int h, float alpha_adjust, float satur_adjust, float bright_adjust) diff --git a/src/util/gradient.c b/src/util/gradient.c index 6266179..30ae0e6 100644 --- a/src/util/gradient.c +++ b/src/util/gradient.c @@ -48,38 +48,30 @@ GradientType gradient_type_from_string(const char *str) return GRADIENT_VERTICAL; } -gboolean read_origin_from_string(const char *str, Origin *element) +gboolean read_element_from_string(const char *str, Element *element) { - if (g_str_equal(str, "element")) { - *element = ORIGIN_ELEMENT; + if (g_str_equal(str, "self")) { + *element = ELEMENT_SELF; return TRUE; } if (g_str_equal(str, "parent")) { - *element = ORIGIN_PARENT; + *element = ELEMENT_PARENT; return TRUE; } if (g_str_equal(str, "panel")) { - *element = ORIGIN_PANEL; - return TRUE; - } - if (g_str_equal(str, "screen")) { - *element = ORIGIN_SCREEN; - return TRUE; - } - if (g_str_equal(str, "desktop")) { - *element = ORIGIN_DESKTOP; + *element = ELEMENT_PANEL; return TRUE; } return FALSE; } -Origin origin_from_string(const char *str) +Element element_from_string(const char *str) { - Origin result; - if (read_origin_from_string(str, &result)) + Element result; + if (read_element_from_string(str, &result)) return result; fprintf(stderr, RED "Invalid origin type: %s" RESET "\n", str); - return ORIGIN_ELEMENT; + return ELEMENT_SELF; } gboolean read_size_from_string(const char *str, SizeVariable *variable) @@ -92,6 +84,10 @@ gboolean read_size_from_string(const char *str, SizeVariable *variable) *variable = SIZE_HEIGHT; return TRUE; } + if (g_str_equal(str, "radius")) { + *variable = SIZE_RADIUS; + return TRUE; + } if (g_str_equal(str, "left")) { *variable = SIZE_LEFT; return TRUE; @@ -108,24 +104,24 @@ gboolean read_size_from_string(const char *str, SizeVariable *variable) *variable = SIZE_BOTTOM; return TRUE; } - if (g_str_equal(str, "center")) { - *variable = SIZE_CENTER; + if (g_str_equal(str, "centerx")) { + *variable = SIZE_CENTERX; return TRUE; } - if (g_str_equal(str, "radius")) { - *variable = SIZE_RADIUS; + if (g_str_equal(str, "centery")) { + *variable = SIZE_CENTERY; return TRUE; } return FALSE; } gboolean read_size_variable_from_string(const char *str, - Origin *variable_element, + Element *variable_element, SizeVariable *variable, double *multiplier) { if (read_size_from_string(str, variable)) { - *variable_element = ORIGIN_ELEMENT; + *variable_element = ELEMENT_SELF; *multiplier = 1; return TRUE; } @@ -133,8 +129,8 @@ gboolean read_size_variable_from_string(const char *str, char *value1 = 0, *value2 = 0, *value3 = 0, *value4 = 0; extract_values_4(str, &value1, &value2, &value3, &value4); - if (value1 && value2 && !value3) { - if (read_origin_from_string(value1, variable_element) && read_size_from_string(value2, variable)) { + if (value1 && !value2) { + if (read_size_from_string(value1, variable)) { *multiplier = 1; if (value1) free(value1); @@ -148,8 +144,38 @@ gboolean read_size_variable_from_string(const char *str, } } + if (value1 && value2 && !value3) { + if (read_element_from_string(value1, variable_element) && read_size_from_string(value2, variable)) { + *multiplier = 1; + if (value1) + free(value1); + if (value2) + free(value2); + if (value3) + free(value3); + if (value4) + free(value4); + return TRUE; + } + } + + if (value1 && value2 && value3 && !value4) { + if (read_size_from_string(value1, variable) && g_str_equal(value2, "*") && + read_double_with_percent(value3, multiplier)) { + if (value1) + free(value1); + if (value2) + free(value2); + if (value3) + free(value3); + if (value4) + free(value4); + return TRUE; + } + } + if (value1 && value2 && value3 && value4) { - if (read_origin_from_string(value1, variable_element) && read_size_from_string(value2, variable) && + if (read_element_from_string(value1, variable_element) && read_size_from_string(value2, variable) && g_str_equal(value3, "*") && read_double_with_percent(value4, multiplier)) { if (value1) free(value1); @@ -178,18 +204,21 @@ gboolean read_size_variable_from_string(const char *str, Offset *offset_from_string(const char *str) { Offset *offset = (Offset *)calloc(1, sizeof(Offset)); - // number ? if (read_double(str, &offset->constant_value)) { offset->constant = TRUE; return offset; } - // SIZE ? offset->constant = FALSE; - - if (read_size_variable_from_string(str, &offset->variable_element, &offset->variable, &offset->multiplier)) { + if (read_size_variable_from_string(str, &offset->element, &offset->variable, &offset->multiplier)) { + if (debug_gradients) + fprintf(stderr, + "Read offset '%s' as: %d %d %f\n", + str, + offset->element, + offset->variable, + offset->multiplier); return offset; } - free(offset); return NULL; } @@ -199,63 +228,61 @@ void init_gradient(GradientClass *g, GradientType type) memset(g, 0, sizeof(*g)); g->type = type; if (g->type == GRADIENT_VERTICAL) { - g->from.origin = ORIGIN_ELEMENT; Offset *offset_top = (Offset *)calloc(1, sizeof(Offset)); offset_top->constant = TRUE; offset_top->constant_value = 0; g->from.offsets_y = g_list_append(g->from.offsets_y, offset_top); Offset *offset_bottom = (Offset *)calloc(1, sizeof(Offset)); offset_bottom->constant = FALSE; - offset_bottom->variable_element = ORIGIN_ELEMENT; + offset_bottom->element = ELEMENT_SELF; offset_bottom->variable = SIZE_HEIGHT; offset_bottom->multiplier = 1.0; - g->from.offsets_y = g_list_append(g->from.offsets_y, offset_bottom); + g->to.offsets_y = g_list_append(g->to.offsets_y, offset_bottom); } else if (g->type == GRADIENT_HORIZONTAL) { - g->from.origin = ORIGIN_ELEMENT; Offset *offset_left = (Offset *)calloc(1, sizeof(Offset)); offset_left->constant = TRUE; offset_left->constant_value = 0; g->from.offsets_x = g_list_append(g->from.offsets_x, offset_left); Offset *offset_right = (Offset *)calloc(1, sizeof(Offset)); offset_right->constant = FALSE; - offset_right->variable_element = ORIGIN_ELEMENT; + offset_right->element = ELEMENT_SELF; offset_right->variable = SIZE_WIDTH; offset_right->multiplier = 1.0; - g->from.offsets_x = g_list_append(g->from.offsets_x, offset_right); + g->to.offsets_x = g_list_append(g->to.offsets_x, offset_right); } else if (g->type == GRADIENT_CENTERED) { - g->from.origin = ORIGIN_ELEMENT; + // from Offset *offset_center_x = (Offset *)calloc(1, sizeof(Offset)); offset_center_x->constant = FALSE; - offset_center_x->variable_element = ORIGIN_ELEMENT; - offset_center_x->variable = SIZE_CENTER; + offset_center_x->element = ELEMENT_SELF; + offset_center_x->variable = SIZE_CENTERX; offset_center_x->multiplier = 1.0; g->from.offsets_x = g_list_append(g->from.offsets_x, offset_center_x); Offset *offset_center_y = (Offset *)calloc(1, sizeof(Offset)); offset_center_y->constant = FALSE; - offset_center_y->variable_element = ORIGIN_ELEMENT; - offset_center_y->variable = SIZE_CENTER; + offset_center_y->element = ELEMENT_SELF; + offset_center_y->variable = SIZE_CENTERY; offset_center_y->multiplier = 1.0; g->from.offsets_y = g_list_append(g->from.offsets_y, offset_center_y); Offset *offset_center_r = (Offset *)calloc(1, sizeof(Offset)); - offset_center_x->constant = TRUE; - offset_center_x->constant_value = 0; + offset_center_r->constant = TRUE; + offset_center_r->constant_value = 0; g->from.offsets_r = g_list_append(g->from.offsets_r, offset_center_r); - g->to.origin = ORIGIN_ELEMENT; + // to offset_center_x = (Offset *)calloc(1, sizeof(Offset)); offset_center_x->constant = FALSE; - offset_center_x->variable_element = ORIGIN_ELEMENT; - offset_center_x->variable = SIZE_CENTER; + offset_center_x->element = ELEMENT_SELF; + offset_center_x->variable = SIZE_CENTERX; offset_center_x->multiplier = 1.0; g->to.offsets_x = g_list_append(g->to.offsets_x, offset_center_x); offset_center_y = (Offset *)calloc(1, sizeof(Offset)); offset_center_y->constant = FALSE; - offset_center_y->variable_element = ORIGIN_ELEMENT; - offset_center_y->variable = SIZE_CENTER; + offset_center_y->element = ELEMENT_SELF; + offset_center_y->variable = SIZE_CENTERY; offset_center_y->multiplier = 1.0; g->to.offsets_y = g_list_append(g->to.offsets_y, offset_center_y); offset_center_r = (Offset *)calloc(1, sizeof(Offset)); offset_center_r->constant = FALSE; - offset_center_r->variable_element = ORIGIN_ELEMENT; + offset_center_r->element = ELEMENT_SELF; offset_center_r->variable = SIZE_RADIUS; offset_center_r->multiplier = 1.0; g->to.offsets_r = g_list_append(g->to.offsets_r, offset_center_r); @@ -275,4 +302,5 @@ void cleanup_gradient(GradientClass *g) g_list_free_full(g->to.offsets_x, free); g_list_free_full(g->to.offsets_y, free); g_list_free_full(g->to.offsets_r, free); + bzero(g, sizeof(*g)); } diff --git a/src/util/gradient.h b/src/util/gradient.h index fff9f6e..ae62fc8 100644 --- a/src/util/gradient.h +++ b/src/util/gradient.h @@ -23,23 +23,22 @@ typedef struct ColorStop { double offset; } ColorStop; -typedef enum Origin { - ORIGIN_ELEMENT = 0, - ORIGIN_PARENT, - ORIGIN_PANEL, - ORIGIN_SCREEN, - ORIGIN_DESKTOP -} Origin; +typedef enum Element { + ELEMENT_SELF = 0, + ELEMENT_PARENT, + ELEMENT_PANEL +} Element; typedef enum SizeVariable { SIZE_WIDTH = 0, SIZE_HEIGHT, + SIZE_RADIUS, SIZE_LEFT, SIZE_RIGHT, SIZE_TOP, SIZE_BOTTOM, - SIZE_CENTER, - SIZE_RADIUS + SIZE_CENTERX, + SIZE_CENTERY } SizeVariable; typedef struct Offset { @@ -47,13 +46,12 @@ typedef struct Offset { // if constant == true double constant_value; // else - Origin variable_element; + Element element; SizeVariable variable; double multiplier; } Offset; typedef struct ControlPoint { - Origin origin; // Each element is an Offset GList *offsets_x; GList *offsets_y; @@ -72,7 +70,7 @@ typedef struct GradientClass { } GradientClass; GradientType gradient_type_from_string(const char *str); -Origin origin_from_string(const char *str); +Element element_from_string(const char *str); Offset *offset_from_string(const char *str); void init_gradient(GradientClass *g, GradientType type); void cleanup_gradient(GradientClass *g); @@ -83,33 +81,12 @@ void cleanup_gradient(GradientClass *g); struct Area; typedef struct Area Area; -typedef struct OffsetInstance { - gboolean constant; - // if constant == true - double constant_value; - // else - Area *variable_element; - SizeVariable variable; - double multiplier; -} OffsetInstance; - -typedef struct ControlPointInstance { - Area *origin; - // Each element is an OffsetInstance - GList *offsets_x; - GList *offsets_y; - GList *offsets_r; -} ControlPointInstance; - typedef struct GradientInstance { GradientClass *gradient_class; Area *area; - ControlPointInstance from; - ControlPointInstance to; cairo_pattern_t *pattern; - // Each element is an Area whose geometry is used to compute this gradient - // TODO why do we need it? - GList *gradient_dependencies; } GradientInstance; +extern gboolean debug_gradients; + #endif // GRADIENT_H