all repos — tint2 @ 822b149419fa148f600220038c323d1f9d25a01a

fork of the tint2 desktop panel for my custom setup - only minimized windows across all desktops for the taskbar

Gradients: work in progress
o9000 mrovi9000@gmail.com
commit

822b149419fa148f600220038c323d1f9d25a01a

parent

edc5a02efe1859e278ae0b57df51c6295b86b4ee

M CMakeLists.txtCMakeLists.txt

@@ -121,6 +121,8 @@ src/util/common.c

src/util/strnatcmp.c src/util/timer.c src/util/cache.c + src/util/color.c + src/util/gradient.c src/util/window.c ) if( ENABLE_BATTERY )
M src/config.csrc/config.c

@@ -231,10 +231,6 @@ if (strcmp(key, "rounded") == 0) {

// 'rounded' is the first parameter => alloc a new background if (backgrounds->len > 0) { Background *bg = &g_array_index(backgrounds, Background, backgrounds->len - 1); - if (!read_bg_color2) - memcpy(&bg->fill_color2, &bg->fill_color, sizeof(Color)); - if (!read_bg_gradient) - bg->gradient = 0; if (!read_bg_color_hover) memcpy(&bg->fill_color_hover, &bg->fill_color, sizeof(Color)); if (!read_border_color_hover)

@@ -277,19 +273,6 @@ if (value2)

bg->fill_color.alpha = (atoi(value2) / 100.0); else bg->fill_color.alpha = 0.5; - } else if (strcmp(key, "background_color2") == 0) { - Background* bg = &g_array_index(backgrounds, Background, backgrounds->len-1); - extract_values(value, &value1, &value2, &value3); - get_color (value1, bg->fill_color2.rgb); - if (value2) - bg->fill_color2.alpha = (atoi (value2) / 100.0); - else - bg->fill_color2.alpha = 0.5; - read_bg_color2 = 1; - } else if (strcmp(key, "gradient") == 0) { - Background *bg = &g_array_index(backgrounds, Background, backgrounds->len-1); - bg->gradient = atoi(value); - read_bg_gradient = 1; } else if (strcmp(key, "border_color") == 0) { Background *bg = &g_array_index(backgrounds, Background, backgrounds->len - 1); extract_values(value, &value1, &value2, &value3);

@@ -336,6 +319,131 @@ bg->border_color_pressed.alpha = 0.5;

read_border_color_press = 1; } + /* Gradients */ + else if (strcmp(key, "gradient") == 0) { + // Create a new gradient + GradientClass g; + init_gradient(&g, gradient_type_from_string(value)); + g_array_append_val(gradients, g); + } else if (strcmp(key, "start_color") == 0) { + GradientClass *g = &g_array_index(gradients, GradientClass, gradients->len - 1); + extract_values(value, &value1, &value2, &value3); + get_color(value1, g->start_color.rgb); + if (value2) + g->start_color.alpha = (atoi(value2) / 100.0); + else + g->start_color.alpha = 0.5; + } else if (strcmp(key, "end_color") == 0) { + GradientClass *g = &g_array_index(gradients, GradientClass, gradients->len - 1); + extract_values(value, &value1, &value2, &value3); + get_color(value1, g->end_color.rgb); + if (value2) + g->end_color.alpha = (atoi(value2) / 100.0); + else + g->end_color.alpha = 0.5; + } else if (strcmp(key, "color_stop") == 0) { + 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); + get_color(value2, color_stop->color.rgb); + if (value3) + color_stop->color.alpha = (atoi(value2) / 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) { + fprintf(stderr, RED "Control points can only be specified for linear and radial gradients: line %s = %s" RESET "\n", key, value); + } else { + Offset *offset = offset_from_string(value); + if (!offset) { + fprintf(stderr, RED "Invalid value: line %s = %s" RESET "\n", key, value); + } else { + g->from.offsets_x = g_list_append(g->from.offsets_x, offset); + } + } + } else if (strcmp(key, "from_offset_y") == 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 { + Offset *offset = offset_from_string(value); + if (!offset) { + fprintf(stderr, RED "Invalid value: line %s = %s" RESET "\n", key, value); + } else { + g->from.offsets_y = g_list_append(g->from.offsets_y, offset); + } + } + } else if (strcmp(key, "from_offset_r") == 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 if (g->type == GRADIENT_LINEAR) { + fprintf(stderr, RED "Invalid parameter for linear gradient: line %s = %s" RESET "\n", key, value); + } else { + Offset *offset = offset_from_string(value); + if (!offset) { + fprintf(stderr, RED "Invalid value: line %s = %s" RESET "\n", key, value); + } else { + g->from.offsets_r = g_list_append(g->from.offsets_r, offset); + } + } + } else if (strcmp(key, "to_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) { + fprintf(stderr, RED "Control points can only be specified for linear and radial gradients: line %s = %s" RESET "\n", key, value); + } else { + Offset *offset = offset_from_string(value); + if (!offset) { + fprintf(stderr, RED "Invalid value: line %s = %s" RESET "\n", key, value); + } else { + g->to.offsets_x = g_list_append(g->to.offsets_x, offset); + } + } + } else if (strcmp(key, "to_offset_y") == 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 { + Offset *offset = offset_from_string(value); + if (!offset) { + fprintf(stderr, RED "Invalid value: line %s = %s" RESET "\n", key, value); + } else { + g->to.offsets_y = g_list_append(g->to.offsets_y, offset); + } + } + } else if (strcmp(key, "to_offset_r") == 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 if (g->type == GRADIENT_LINEAR) { + fprintf(stderr, RED "Invalid parameter for linear gradient: line %s = %s" RESET "\n", key, value); + } else { + Offset *offset = offset_from_string(value); + if (!offset) { + fprintf(stderr, RED "Invalid value: line %s = %s" RESET "\n", key, value); + } else { + g->to.offsets_r = g_list_append(g->to.offsets_r, offset); + } + } + } + /* Panel */ else if (strcmp(key, "panel_monitor") == 0) { panel_config.monitor = config_get_monitor(value);

@@ -442,6 +550,11 @@ else if (strcmp(key, "panel_background_id") == 0) {

int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; panel_config.area.bg = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "panel_gradient_id") == 0) { + 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)); } else if (strcmp(key, "wm_menu") == 0) wm_menu = atoi(value); else if (strcmp(key, "panel_dock") == 0)

@@ -544,6 +657,13 @@ #ifdef ENABLE_BATTERY

int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; panel_config.battery.area.bg = &g_array_index(backgrounds, Background, id); +#endif + } else if (strcmp(key, "battery_gradient_id") == 0) { +#ifdef ENABLE_BATTERY + 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)); #endif } else if (strcmp(key, "battery_hide") == 0) { #ifdef ENABLE_BATTERY

@@ -565,6 +685,12 @@ Separator *separator = get_or_create_last_separator();

int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; separator->area.bg = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "separator_gradient_id") == 0) { + Separator *separator = get_or_create_last_separator(); + 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)); } else if (strcmp(key, "separator_color") == 0) { Separator *separator = get_or_create_last_separator(); extract_values(value, &value1, &value2, &value3);

@@ -657,6 +783,12 @@ Execp *execp = get_or_create_last_execp();

int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; execp->backend->bg = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "execp_gradient_id") == 0) { + Execp *execp = get_or_create_last_execp(); + 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)); } else if (strcmp(key, "execp_centered") == 0) { Execp *execp = get_or_create_last_execp(); execp->backend->centered = atoi(value);

@@ -753,6 +885,11 @@ } else if (strcmp(key, "clock_background_id") == 0) {

int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; panel_config.clock.area.bg = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "clock_gradient_id") == 0) { + 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)); } else if (strcmp(key, "clock_tooltip") == 0) { if (strlen(value) > 0) time_tooltip_format = strdup(value);

@@ -794,13 +931,23 @@ panel_config.g_taskbar.area.paddingx = atoi(value3);

} else if (strcmp(key, "taskbar_background_id") == 0) { int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; - panel_config.g_taskbar.background[TASKBAR_NORMAL] = &g_array_index(backgrounds, Background, id); + panel_config.g_taskbar.area.bg = &g_array_index(backgrounds, Background, id); if (panel_config.g_taskbar.background[TASKBAR_ACTIVE] == 0) panel_config.g_taskbar.background[TASKBAR_ACTIVE] = panel_config.g_taskbar.background[TASKBAR_NORMAL]; + } else if (strcmp(key, "taskbar_gradient_id") == 0) { + int id = atoi(value); + id = (id < gradients->len && id >= 0) ? id : -1; + if (id >= 0) + panel_config.g_taskbar.gradient[TASKBAR_NORMAL] = g_list_append(panel_config.g_taskbar.gradient[TASKBAR_NORMAL], &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "taskbar_active_background_id") == 0) { int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; panel_config.g_taskbar.background[TASKBAR_ACTIVE] = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "taskbar_active_gradient_id") == 0) { + int id = atoi(value); + id = (id < gradients->len && id >= 0) ? id : -1; + if (id >= 0) + panel_config.g_taskbar.gradient[TASKBAR_ACTIVE] = g_list_append(panel_config.g_taskbar.gradient[TASKBAR_ACTIVE], &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "taskbar_name") == 0) { taskbarname_enabled = atoi(value); } else if (strcmp(key, "taskbar_name_padding") == 0) {

@@ -815,10 +962,20 @@ panel_config.g_taskbar.background_name[TASKBAR_NORMAL] = &g_array_index(backgrounds, Background, id);

if (panel_config.g_taskbar.background_name[TASKBAR_ACTIVE] == 0) panel_config.g_taskbar.background_name[TASKBAR_ACTIVE] = panel_config.g_taskbar.background_name[TASKBAR_NORMAL]; + } else if (strcmp(key, "taskbar_name_gradient_id") == 0) { + int id = atoi(value); + id = (id < gradients->len && id >= 0) ? id : -1; + if (id >= 0) + panel_config.g_taskbar.gradient_name[TASKBAR_NORMAL] = g_list_append(panel_config.g_taskbar.gradient_name[TASKBAR_NORMAL], &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "taskbar_name_active_background_id") == 0) { int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; panel_config.g_taskbar.background_name[TASKBAR_ACTIVE] = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "taskbar_name_active_gradient_id") == 0) { + int id = atoi(value); + id = (id < gradients->len && id >= 0) ? id : -1; + if (id >= 0) + panel_config.g_taskbar.gradient_name[TASKBAR_ACTIVE] = g_list_append(panel_config.g_taskbar.gradient_name[TASKBAR_ACTIVE], &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "taskbar_name_font") == 0) { panel_config.taskbarname_font_desc = pango_font_description_from_string(value); panel_config.taskbarname_has_font = TRUE;

@@ -930,6 +1087,17 @@ panel_config.g_task.config_background_mask |= (1 << status);

if (status == TASK_NORMAL) panel_config.g_task.area.bg = panel_config.g_task.background[TASK_NORMAL]; } + } else if (g_regex_match_simple("task.*_gradient_id", key, 0, 0)) { + gchar **split = g_regex_split_simple("_", key, 0, 0); + int status = g_strv_length(split) == 3 ? TASK_NORMAL : get_task_status(split[1]); + g_strfreev(split); + if (status >= 0) { + int id = atoi(value); + id = (id < gradients->len && id >= 0) ? id : -1; + if (id >= 0) { + panel_config.g_task.gradient[status] = g_list_append(panel_config.g_task.gradient[status], &g_array_index(gradients, GradientClass, id)); + } + } } // "tooltip" is deprecated but here for backwards compatibility else if (strcmp(key, "task_tooltip") == 0 || strcmp(key, "tooltip") == 0)

@@ -957,6 +1125,11 @@ } else if (strcmp(key, "systray_background_id") == 0) {

int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; systray.area.bg = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "systray_gradient_id") == 0) { + int id = atoi(value); + id = (id < gradients->len && id >= 0) ? id : -1; + if (id >= 0) + systray.area.gradients = g_list_append(systray.area.gradients, &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "systray_sort") == 0) { if (strcmp(value, "descending") == 0) systray.sort = SYSTRAY_SORT_DESCENDING;

@@ -989,10 +1162,20 @@ } else if (strcmp(key, "launcher_background_id") == 0) {

int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; panel_config.launcher.area.bg = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "launcher_gradient_id") == 0) { + int id = atoi(value); + id = (id < gradients->len && id >= 0) ? id : -1; + if (id >= 0) + panel_config.launcher.area.gradients = g_list_append(panel_config.launcher.area.gradients, &g_array_index(gradients, GradientClass, id)); } else if (strcmp(key, "launcher_icon_background_id") == 0) { int id = atoi(value); id = (id < backgrounds->len && id >= 0) ? id : 0; launcher_icon_bg = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "launcher_icon_gradient_id") == 0) { + int id = atoi(value); + id = (id < gradients->len && id >= 0) ? id : -1; + if (id >= 0) + launcher_icon_gradient = &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) {

@@ -1175,10 +1358,6 @@ }

if (backgrounds->len > 0) { Background *bg = &g_array_index(backgrounds, Background, backgrounds->len - 1); - if (!read_bg_color2) - memcpy(&bg->fill_color2, &bg->fill_color, sizeof(Color)); - if (!read_bg_gradient) - bg->gradient = 0; if (!read_bg_color_hover) memcpy(&bg->fill_color_hover, &bg->fill_color, sizeof(Color)); if (!read_border_color_hover)
M src/launcher/launcher.csrc/launcher/launcher.c

@@ -53,6 +53,7 @@ char *icon_theme_name_xsettings;

int launcher_icon_theme_override; int startup_notifications; Background *launcher_icon_bg; +GradientClass *launcher_icon_gradient; Imlib_Image scale_icon(Imlib_Image original, int icon_size); void free_icon(Imlib_Image icon);
M src/launcher/launcher.hsrc/launcher/launcher.h

@@ -46,6 +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; // default global data void default_launcher();
M src/panel.csrc/panel.c

@@ -73,6 +73,7 @@ Panel *panels;

int num_panels; GArray *backgrounds; +GArray *gradients; Imlib_Image default_icon; char *default_font = NULL;

@@ -98,6 +99,7 @@ wm_menu = FALSE;

max_tick_urgent = 14; mouse_left = TOGGLE_ICONIFY; backgrounds = g_array_new(0, 0, sizeof(Background)); + gradients = g_array_new(0, 0, sizeof(GradientClass)); memset(&panel_config, 0, sizeof(Panel)); snprintf(panel_config.area.name, sizeof(panel_config.area.name), "Panel");

@@ -145,8 +147,14 @@ panel_window_name = NULL;

free(panels); panels = NULL; if (backgrounds) - g_array_free(backgrounds, 1); + g_array_free(backgrounds, TRUE); backgrounds = NULL; + if (gradients) { + for (guint i = 0; i < gradients->len; i++) + cleanup_gradient(&g_array_index(gradients, GradientClass, i)); + g_array_free(gradients, TRUE); + } + gradients = NULL; pango_font_description_free(panel_config.g_task.font_desc); panel_config.g_task.font_desc = NULL; pango_font_description_free(panel_config.taskbarname_font_desc);

@@ -961,6 +969,7 @@ {

relayout(&panel->area); if (debug_geometry) area_dump_geometry(&panel->area, 0); + update_dependent_gradients(&panel->area); draw_tree(&panel->area); }
M src/panel.hsrc/panel.h

@@ -83,6 +83,7 @@ extern Strut panel_strut_policy;

extern char *panel_items_order; extern int max_tick_urgent; extern GArray *backgrounds; +extern GArray *gradients; extern Imlib_Image default_icon; #define DEFAULT_FONT "sans 10" extern char *default_font;
M src/taskbar/task.hsrc/taskbar/task.h

@@ -36,6 +36,7 @@ int saturation[TASK_STATE_COUNT];

int brightness[TASK_STATE_COUNT]; int config_asb_mask; Background *background[TASK_STATE_COUNT]; + GList *gradient[TASK_STATE_COUNT]; int config_background_mask; // starting position for text ~ task_padding + task_border + icon_size double text_posx, text_height;
M src/taskbar/taskbar.hsrc/taskbar/taskbar.h

@@ -43,6 +43,8 @@ Area area;

Area area_name; Background *background[TASKBAR_STATE_COUNT]; Background *background_name[TASKBAR_STATE_COUNT]; + GList *gradient[TASKBAR_STATE_COUNT]; + GList *gradient_name[TASKBAR_STATE_COUNT]; } GlobalTaskbar; extern gboolean taskbar_enabled;
M src/util/area.csrc/util/area.c

@@ -381,6 +381,20 @@ parent->resize_needed = TRUE;

a->resize_needed = TRUE; } +void update_dependent_gradients(Area *a) +{ + if (!a->on_screen) + return; + if (a->_changed) { + for (GList *l = a->dependent_gradients; l; l = l->next) { + GradientInstance *gi = (GradientInstance *)l->data; + update_gradient(gi); + } + } + for (GList *l = a->children; l; l = l->next) + update_dependent_gradients((Area *)l->data); +} + void draw(Area *a) { if (a->_changed) {

@@ -439,17 +453,8 @@

void draw_background(Area *a, cairo_t *c) { if ((a->bg->fill_color.alpha > 0.0) || - (panel_config.mouse_effects && (a->has_mouse_over_effect || a->has_mouse_press_effect)) || - (area_has_gradient_fill(a))) { - - 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 (a->mouse_state == MOUSE_OVER) + (panel_config.mouse_effects && (a->has_mouse_over_effect || a->has_mouse_press_effect))) { + if (a->mouse_state == MOUSE_OVER) cairo_set_source_rgba(c, a->bg->fill_color_hover.rgb[0], a->bg->fill_color_hover.rgb[1],

@@ -476,8 +481,21 @@ a->height - top_bottom_border_width(a),

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); + cairo_pattern_destroy(cairo_gradient_pattern); + */ } if (a->bg->border.width > 0) {

@@ -542,6 +560,7 @@ parent->resize_needed = TRUE;

schedule_redraw(parent); panel_refresh = TRUE; } + init_area_gradients(a); } void free_area(Area *a)

@@ -570,6 +589,7 @@ }

if (mouse_over_area == a) { mouse_over_area = NULL; } + free_area_gradients(a); } void mouse_over(Area *area, int pressed)

@@ -802,20 +822,20 @@ area->posy,

area->width, area->height); fprintf(stderr, - "%*sBorder: left = %d, right = %d, top = %d, bottom = %d\n", - indent, - "", - left_border_width(area), - right_border_width(area), - top_border_width(area), - bottom_border_width(area)); + "%*sBorder: left = %d, right = %d, top = %d, bottom = %d\n", + indent, + "", + left_border_width(area), + right_border_width(area), + top_border_width(area), + bottom_border_width(area)); fprintf(stderr, - "%*sPadding: left = right = %d, top = bottom = %d, spacing = %d\n", - indent, - "", - area->paddingxlr, - area->paddingy, - area->paddingx); + "%*sPadding: left = right = %d, top = bottom = %d, spacing = %d\n", + indent, + "", + area->paddingxlr, + area->paddingy, + area->paddingx); if (area->_dump_geometry) area->_dump_geometry(area, indent); if (area->children) {

@@ -826,17 +846,104 @@ area_dump_geometry((Area *)l->data, indent);

} } -gboolean area_has_gradient_fill(Area *area) +void instantiate_gradient_offsets(Area *area, GradientInstance *gi, GList *offsets, GList **offset_instances) +{ + 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); + } + } +} + +void free_gradient_offsets(GradientInstance *gi, GList **offset_instances) +{ + 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); + } + } + g_list_free_full(*offset_instances, free); +} + +void instantiate_gradient_point(Area *area, + GradientInstance *gi, + ControlPoint *control, + ControlPointInstance *control_instance) +{ + 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); +} + +void free_gradient_point(GradientInstance *gi, ControlPointInstance *control_instance) +{ + free_gradient_offsets(gi, &control_instance->offsets_x); + free_gradient_offsets(gi, &control_instance->offsets_y); + free_gradient_offsets(gi, &control_instance->offsets_r); +} + +void instantiate_gradient(Area *area, GradientClass *g, GradientInstance *gi) +{ + gi->gradient_class = 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); +} + +void free_gradient(GradientInstance *gi) { - if (!area->bg->gradient) - return FALSE; - else if ((area->bg->fill_color.alpha <= 0.0 ) && (area->bg->fill_color2.alpha <= 0.0)) - return FALSE; - else if ((area->bg->fill_color.rgb[0] == area->bg->fill_color2.rgb[0]) && - (area->bg->fill_color.rgb[1] == area->bg->fill_color2.rgb[1]) && - (area->bg->fill_color.rgb[2] == area->bg->fill_color2.rgb[2]) && - (area->bg->fill_color.alpha == area->bg->fill_color2.alpha)) - return FALSE; - else return TRUE; + free_gradient_point(gi, &gi->from); + free_gradient_point(gi, &gi->to); +} +void init_area_gradients(Area *area) +{ + for (GList *l = area->gradients; l; l = l->next) { + GradientClass *g = (GradientClass *)l->data; + GradientInstance *gi = (GradientInstance *)calloc(1, sizeof(GradientInstance)); + instantiate_gradient(area, g, gi); + area->gradient_instances = g_list_append(area->gradient_instances, gi); + } +} + +void free_area_gradients(Area *area) +{ + 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); +} + +void update_gradient(GradientInstance *gi) +{ + // TODO }
M src/util/area.hsrc/util/area.h

@@ -11,6 +11,9 @@ #include <X11/Xlib.h>

#include <cairo.h> #include <cairo-xlib.h> +#include "color.h" +#include "gradient.h" + // DATA ORGANISATION // // Areas in tint2 are similar to widgets in a GUI.

@@ -117,13 +120,6 @@ // Returns a copy of the tooltip to be displayed for this widget.

// The caller takes ownership of the pointer. // The Area's _get_tooltip_text member must point to this function. -typedef struct Color { - // Values are in [0, 1], with 0 meaning no intensity. - double rgb[3]; - // Values are in [0, 1], with 0 meaning fully transparent, 1 meaning fully opaque. - double alpha; -} Color; - typedef enum BorderMask { BORDER_TOP = 1 << 0, BORDER_BOTTOM = 1 << 1,

@@ -147,8 +143,6 @@

typedef struct Background { // Normal state Color fill_color; - Color fill_color2; - gboolean gradient; Border border; // On mouse hover Color fill_color_hover;

@@ -179,6 +173,12 @@ int posx, posy;

// Size, including borders int width, height; Background *bg; + // Each element is a pointer to a GradientClass (list can be empty), no ownership + GList *gradients; + // Each element is a GradientInstance attached to this Area (list can be empty) + GList *gradient_instances; + // Each element is a GradientInstance that depends on this Area's geometry (position or size) + GList *dependent_gradients; // List of children, each one a pointer to Area GList *children; // Pointer to the parent Area or NULL

@@ -311,11 +311,15 @@ // Useful so that a click at the edge of the screen is still handled by task buttons etc., even if technically

// they are outside the drawing area of the button. gboolean full_width_area_is_under_mouse(void *obj, int x, int y); +void init_area_gradients(Area *area); +void free_area_gradients(Area *area); + void area_dump_geometry(Area *area, int indent); void mouse_over(Area *area, int pressed); void mouse_out(); -gboolean area_has_gradient_fill(Area *area); +void update_gradient(GradientInstance *gi); +void update_dependent_gradients(Area *a); #endif
A src/util/color.c

@@ -0,0 +1,2 @@

+#include "color.h" +
A src/util/color.h

@@ -0,0 +1,11 @@

+#ifndef COLOR_H +#define COLOR_H + +typedef struct Color { + // Values are in [0, 1], with 0 meaning no intensity. + double rgb[3]; + // Values are in [0, 1], with 0 meaning fully transparent, 1 meaning fully opaque. + double alpha; +} Color; + +#endif // COLOR_H
M src/util/common.csrc/util/common.c

@@ -201,6 +201,7 @@ }

void extract_values(const char *value, char **value1, char **value2, char **value3) { + char *value0 = strdup(value); char *b = 0, *c = 0; if (*value1)

@@ -210,14 +211,14 @@ free(*value2);

if (*value3) free(*value3); - if ((b = strchr(value, ' '))) { + if ((b = strchr(value0, ' '))) { b[0] = '\0'; b++; } else { *value2 = 0; *value3 = 0; } - *value1 = strdup(value); + *value1 = strdup(value0); g_strstrip(*value1); if (b) {

@@ -236,6 +237,63 @@ if (c) {

*value3 = strdup(c); g_strstrip(*value3); } + + free(value0); +} + +void extract_values_4(const char *value, 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; + } + *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); } void adjust_asb(DATA32 *data, int w, int h, float alpha_adjust, float satur_adjust, float bright_adjust)
M src/util/common.hsrc/util/common.h

@@ -51,6 +51,7 @@ // Returns 1 if both key and value could be read, zero otherwise.

gboolean parse_line(const char *line, char **key, char **value); void extract_values(const char *value, char **value1, char **value2, char **value3); +void extract_values_4(const char *value, char **value1, char **value2, char **value3, char **value4); // Executes a command in a shell. void tint_exec(const char *command);
A src/util/gradient.c

@@ -0,0 +1,278 @@

+#include "gradient.h" + +#include <glib.h> +#include <stdlib.h> +#include <string.h> + +#include "common.h" + +gboolean read_double(const char *str, double *value) +{ + if (!str[0]) + return FALSE; + char *end; + *value = strtod(str, &end); + if (end[0]) + return FALSE; + return TRUE; +} + +gboolean read_double_with_percent(const char *str, double *value) +{ + if (!str[0]) + return FALSE; + char *end; + *value = strtod(str, &end); + if (end[0] == '%' && !end[1]) { + *value *= 0.01; + return TRUE; + } + if (end[0]) + return FALSE; + return TRUE; +} + +GradientType gradient_type_from_string(const char *str) +{ + if (g_str_equal(str, "horizontal")) + return GRADIENT_HORIZONTAL; + if (g_str_equal(str, "vertical")) + return GRADIENT_VERTICAL; + if (g_str_equal(str, "centered")) + return GRADIENT_CENTERED; + if (g_str_equal(str, "linear")) + return GRADIENT_LINEAR; + if (g_str_equal(str, "radial")) + return GRADIENT_RADIAL; + fprintf(stderr, RED "Invalid gradient type: %s" RESET "\n", str); + return GRADIENT_VERTICAL; +} + +gboolean read_origin_from_string(const char *str, Origin *element) +{ + if (g_str_equal(str, "element")) { + *element = ORIGIN_ELEMENT; + return TRUE; + } + if (g_str_equal(str, "parent")) { + *element = ORIGIN_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; + return TRUE; + } + return FALSE; +} + +Origin origin_from_string(const char *str) +{ + Origin result; + if (read_origin_from_string(str, &result)) + return result; + fprintf(stderr, RED "Invalid origin type: %s" RESET "\n", str); + return ORIGIN_ELEMENT; +} + +gboolean read_size_from_string(const char *str, SizeVariable *variable) +{ + if (g_str_equal(str, "width")) { + *variable = SIZE_WIDTH; + return TRUE; + } + if (g_str_equal(str, "height")) { + *variable = SIZE_HEIGHT; + return TRUE; + } + if (g_str_equal(str, "left")) { + *variable = SIZE_LEFT; + return TRUE; + } + if (g_str_equal(str, "right")) { + *variable = SIZE_RIGHT; + return TRUE; + } + if (g_str_equal(str, "top")) { + *variable = SIZE_TOP; + return TRUE; + } + if (g_str_equal(str, "bottom")) { + *variable = SIZE_BOTTOM; + return TRUE; + } + if (g_str_equal(str, "center")) { + *variable = SIZE_CENTER; + return TRUE; + } + if (g_str_equal(str, "radius")) { + *variable = SIZE_RADIUS; + return TRUE; + } + return FALSE; +} + +gboolean read_size_variable_from_string(const char *str, + Origin *variable_element, + SizeVariable *variable, + double *multiplier) +{ + if (read_size_from_string(str, variable)) { + *variable_element = ORIGIN_ELEMENT; + *multiplier = 1; + return TRUE; + } + + 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)) { + *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_origin_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); + if (value2) + free(value2); + if (value3) + free(value3); + if (value4) + free(value4); + return TRUE; + } + } + + if (value1) + free(value1); + if (value2) + free(value2); + if (value3) + free(value3); + if (value4) + free(value4); + + return FALSE; +} + +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)) { + return offset; + } + + free(offset); + return NULL; +} + +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->variable = SIZE_HEIGHT; + offset_bottom->multiplier = 1.0; + g->from.offsets_y = g_list_append(g->from.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->variable = SIZE_WIDTH; + offset_right->multiplier = 1.0; + g->from.offsets_x = g_list_append(g->from.offsets_x, offset_right); + } else if (g->type == GRADIENT_CENTERED) { + g->from.origin = ORIGIN_ELEMENT; + 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->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->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; + g->from.offsets_r = g_list_append(g->from.offsets_r, offset_center_r); + g->to.origin = ORIGIN_ELEMENT; + 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->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->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->variable = SIZE_RADIUS; + offset_center_r->multiplier = 1.0; + g->to.offsets_r = g_list_append(g->to.offsets_r, offset_center_r); + } else if (g->type == GRADIENT_LINEAR) { + // Nothing to do, the user has to add control points + } else if (g->type == GRADIENT_RADIAL) { + // Nothing to do, the user has to add control points + } +} + +void cleanup_gradient(GradientClass *g) +{ + g_list_free_full(g->extra_color_stops, free); + g_list_free_full(g->from.offsets_x, free); + g_list_free_full(g->from.offsets_y, free); + g_list_free_full(g->from.offsets_r, free); + 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); +}
A src/util/gradient.h

@@ -0,0 +1,115 @@

+#ifndef GRADIENT_H +#define GRADIENT_H + +#include <glib.h> +#include <cairo.h> + +#include "color.h" + +////////////////////////////////////////////////////////////////////// +// Gradient types read from config options, not associated to any area + +typedef enum GradientType { + GRADIENT_VERTICAL = 0, + GRADIENT_HORIZONTAL, + GRADIENT_CENTERED, + GRADIENT_LINEAR, + GRADIENT_RADIAL +} GradientType; + +typedef struct ColorStop { + Color color; + // offset in 0-1 + double offset; +} ColorStop; + +typedef enum Origin { + ORIGIN_ELEMENT = 0, + ORIGIN_PARENT, + ORIGIN_PANEL, + ORIGIN_SCREEN, + ORIGIN_DESKTOP +} Origin; + +typedef enum SizeVariable { + SIZE_WIDTH = 0, + SIZE_HEIGHT, + SIZE_LEFT, + SIZE_RIGHT, + SIZE_TOP, + SIZE_BOTTOM, + SIZE_CENTER, + SIZE_RADIUS +} SizeVariable; + +typedef struct Offset { + gboolean constant; + // if constant == true + double constant_value; + // else + Origin variable_element; + SizeVariable variable; + double multiplier; +} Offset; + +typedef struct ControlPoint { + Origin origin; + // Each element is an Offset + GList *offsets_x; + GList *offsets_y; + // Defined only for radial gradients + GList *offsets_r; +} ControlPoint; + +typedef struct GradientClass { + GradientType type; + Color start_color; + Color end_color; + // Each element is a ColorStop + GList *extra_color_stops; + ControlPoint from; + ControlPoint to; +} GradientClass; + +GradientType gradient_type_from_string(const char *str); +Origin origin_from_string(const char *str); +Offset *offset_from_string(const char *str); +void init_gradient(GradientClass *g, GradientType type); +void cleanup_gradient(GradientClass *g); + +///////////////////////////////////////// +// Gradient instances associated to Areas + +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; + +#endif // GRADIENT_H
M tint2.filestint2.files

@@ -210,3 +210,7 @@ themes/vertical-neutral-icons.tint2rc

doc/tint2.md src/separator/separator.c src/separator/separator.h +src/util/gradient.h +src/util/gradient.c +src/util/color.h +src/util/color.c