Changed indentation everywhere

This commit is contained in:
o9000
2017-04-13 14:07:23 +02:00
parent c1e5a7b172
commit affac4cfa6
68 changed files with 23280 additions and 22941 deletions

View File

@@ -56,7 +56,7 @@ char *battery_uwheel_command;
char *battery_dwheel_command; char *battery_dwheel_command;
gboolean battery_found; gboolean battery_found;
char *battery_sys_prefix = (char*)""; char *battery_sys_prefix = (char *)"";
void battery_init_fonts(); void battery_init_fonts();
char *battery_get_tooltip(void *obj); char *battery_get_tooltip(void *obj);
@@ -65,407 +65,397 @@ void battery_dump_geometry(void *obj, int indent);
void default_battery() void default_battery()
{ {
battery_enabled = FALSE; battery_enabled = FALSE;
battery_tooltip_enabled = TRUE; battery_tooltip_enabled = TRUE;
battery_found = FALSE; battery_found = FALSE;
percentage_hide = 101; percentage_hide = 101;
battery_low_cmd_sent = FALSE; battery_low_cmd_sent = FALSE;
battery_timeout = NULL; battery_timeout = NULL;
bat1_has_font = FALSE; bat1_has_font = FALSE;
bat1_font_desc = NULL; bat1_font_desc = NULL;
bat2_has_font = FALSE; bat2_has_font = FALSE;
bat2_font_desc = NULL; bat2_font_desc = NULL;
ac_connected_cmd = NULL; ac_connected_cmd = NULL;
ac_disconnected_cmd = NULL; ac_disconnected_cmd = NULL;
battery_low_cmd = NULL; battery_low_cmd = NULL;
battery_lclick_command = NULL; battery_lclick_command = NULL;
battery_mclick_command = NULL; battery_mclick_command = NULL;
battery_rclick_command = NULL; battery_rclick_command = NULL;
battery_uwheel_command = NULL; battery_uwheel_command = NULL;
battery_dwheel_command = NULL; battery_dwheel_command = NULL;
battery_state.percentage = 0; battery_state.percentage = 0;
battery_state.time.hours = 0; battery_state.time.hours = 0;
battery_state.time.minutes = 0; battery_state.time.minutes = 0;
battery_state.time.seconds = 0; battery_state.time.seconds = 0;
battery_state.state = BATTERY_UNKNOWN; battery_state.state = BATTERY_UNKNOWN;
} }
void cleanup_battery() void cleanup_battery()
{ {
pango_font_description_free(bat1_font_desc); pango_font_description_free(bat1_font_desc);
bat1_font_desc = NULL; bat1_font_desc = NULL;
pango_font_description_free(bat2_font_desc); pango_font_description_free(bat2_font_desc);
bat2_font_desc = NULL; bat2_font_desc = NULL;
free(battery_low_cmd); free(battery_low_cmd);
battery_low_cmd = NULL; battery_low_cmd = NULL;
free(battery_lclick_command); free(battery_lclick_command);
battery_lclick_command = NULL; battery_lclick_command = NULL;
free(battery_mclick_command); free(battery_mclick_command);
battery_mclick_command = NULL; battery_mclick_command = NULL;
free(battery_rclick_command); free(battery_rclick_command);
battery_rclick_command = NULL; battery_rclick_command = NULL;
free(battery_uwheel_command); free(battery_uwheel_command);
battery_uwheel_command = NULL; battery_uwheel_command = NULL;
free(battery_dwheel_command); free(battery_dwheel_command);
battery_dwheel_command = NULL; battery_dwheel_command = NULL;
free(ac_connected_cmd); free(ac_connected_cmd);
ac_connected_cmd = NULL; ac_connected_cmd = NULL;
free(ac_disconnected_cmd); free(ac_disconnected_cmd);
ac_disconnected_cmd = NULL; ac_disconnected_cmd = NULL;
stop_timeout(battery_timeout); stop_timeout(battery_timeout);
battery_timeout = NULL; battery_timeout = NULL;
battery_found = FALSE; battery_found = FALSE;
battery_os_free(); battery_os_free();
} }
void init_battery() void init_battery()
{ {
if (!battery_enabled) if (!battery_enabled)
return; return;
battery_found = battery_os_init(); battery_found = battery_os_init();
if (!battery_timeout) if (!battery_timeout)
battery_timeout = add_timeout(10, 30000, update_battery_tick, 0, &battery_timeout); battery_timeout = add_timeout(10, 30000, update_battery_tick, 0, &battery_timeout);
update_battery(); update_battery();
} }
void reinit_battery() void reinit_battery()
{ {
battery_os_free(); battery_os_free();
battery_found = battery_os_init(); battery_found = battery_os_init();
update_battery(); update_battery();
} }
void init_battery_panel(void *p) void init_battery_panel(void *p)
{ {
Panel *panel = (Panel *)p; Panel *panel = (Panel *)p;
Battery *battery = &panel->battery; Battery *battery = &panel->battery;
if (!battery_enabled) if (!battery_enabled)
return; return;
battery_init_fonts(); battery_init_fonts();
if (!battery->area.bg) if (!battery->area.bg)
battery->area.bg = &g_array_index(backgrounds, Background, 0); battery->area.bg = &g_array_index(backgrounds, Background, 0);
battery->area.parent = p; battery->area.parent = p;
battery->area.panel = p; battery->area.panel = p;
snprintf(battery->area.name, sizeof(battery->area.name), "Battery"); snprintf(battery->area.name, sizeof(battery->area.name), "Battery");
battery->area._draw_foreground = draw_battery; battery->area._draw_foreground = draw_battery;
battery->area.size_mode = LAYOUT_FIXED; battery->area.size_mode = LAYOUT_FIXED;
battery->area._resize = resize_battery; battery->area._resize = resize_battery;
battery->area._compute_desired_size = battery_compute_desired_size; battery->area._compute_desired_size = battery_compute_desired_size;
battery->area._is_under_mouse = full_width_area_is_under_mouse; battery->area._is_under_mouse = full_width_area_is_under_mouse;
battery->area.on_screen = TRUE; battery->area.on_screen = TRUE;
battery->area.resize_needed = 1; battery->area.resize_needed = 1;
battery->area.has_mouse_over_effect = battery->area.has_mouse_over_effect =
panel_config.mouse_effects && (battery_lclick_command || battery_mclick_command || battery_rclick_command || panel_config.mouse_effects && (battery_lclick_command || battery_mclick_command || battery_rclick_command ||
battery_uwheel_command || battery_dwheel_command); battery_uwheel_command || battery_dwheel_command);
battery->area.has_mouse_press_effect = battery->area.has_mouse_over_effect; battery->area.has_mouse_press_effect = battery->area.has_mouse_over_effect;
if (battery_tooltip_enabled) if (battery_tooltip_enabled)
battery->area._get_tooltip_text = battery_get_tooltip; battery->area._get_tooltip_text = battery_get_tooltip;
instantiate_area_gradients(&battery->area); instantiate_area_gradients(&battery->area);
} }
void battery_init_fonts() void battery_init_fonts()
{ {
if (!bat1_font_desc) { if (!bat1_font_desc) {
bat1_font_desc = pango_font_description_from_string(get_default_font()); bat1_font_desc = pango_font_description_from_string(get_default_font());
pango_font_description_set_size(bat1_font_desc, pango_font_description_get_size(bat1_font_desc) - PANGO_SCALE); pango_font_description_set_size(bat1_font_desc, pango_font_description_get_size(bat1_font_desc) - PANGO_SCALE);
} }
if (!bat2_font_desc) { if (!bat2_font_desc) {
bat2_font_desc = pango_font_description_from_string(get_default_font()); bat2_font_desc = pango_font_description_from_string(get_default_font());
pango_font_description_set_size(bat2_font_desc, pango_font_description_get_size(bat2_font_desc) - PANGO_SCALE); pango_font_description_set_size(bat2_font_desc, pango_font_description_get_size(bat2_font_desc) - PANGO_SCALE);
} }
} }
void battery_default_font_changed() void battery_default_font_changed()
{ {
if (!battery_enabled) if (!battery_enabled)
return; return;
if (bat1_has_font && bat2_has_font) if (bat1_has_font && bat2_has_font)
return; return;
if (!bat1_has_font) { if (!bat1_has_font) {
pango_font_description_free(bat1_font_desc); pango_font_description_free(bat1_font_desc);
bat1_font_desc = NULL; bat1_font_desc = NULL;
} }
if (!bat2_has_font) { if (!bat2_has_font) {
pango_font_description_free(bat2_font_desc); pango_font_description_free(bat2_font_desc);
bat2_font_desc = NULL; bat2_font_desc = NULL;
} }
battery_init_fonts(); battery_init_fonts();
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
panels[i].battery.area.resize_needed = TRUE; panels[i].battery.area.resize_needed = TRUE;
schedule_redraw(&panels[i].battery.area); schedule_redraw(&panels[i].battery.area);
} }
schedule_panel_redraw(); schedule_panel_redraw();
} }
void update_battery_tick(void *arg) void update_battery_tick(void *arg)
{ {
if (!battery_enabled) if (!battery_enabled)
return; return;
gboolean old_found = battery_found; gboolean old_found = battery_found;
int old_percentage = battery_state.percentage; int old_percentage = battery_state.percentage;
gboolean old_ac_connected = battery_state.ac_connected; gboolean old_ac_connected = battery_state.ac_connected;
int16_t old_hours = battery_state.time.hours; int16_t old_hours = battery_state.time.hours;
int8_t old_minutes = battery_state.time.minutes; int8_t old_minutes = battery_state.time.minutes;
if (!battery_found) { if (!battery_found) {
init_battery(); init_battery();
old_ac_connected = battery_state.ac_connected; old_ac_connected = battery_state.ac_connected;
} }
if (update_battery() != 0) { if (update_battery() != 0) {
// Try to reconfigure on failed update // Try to reconfigure on failed update
init_battery(); init_battery();
} }
if (old_ac_connected != battery_state.ac_connected) { if (old_ac_connected != battery_state.ac_connected) {
if (battery_state.ac_connected) if (battery_state.ac_connected)
tint_exec(ac_connected_cmd); tint_exec(ac_connected_cmd);
else else
tint_exec(ac_disconnected_cmd); tint_exec(ac_disconnected_cmd);
} }
if (battery_state.percentage < battery_low_status && battery_state.state == BATTERY_DISCHARGING && if (battery_state.percentage < battery_low_status && battery_state.state == BATTERY_DISCHARGING &&
!battery_low_cmd_sent) { !battery_low_cmd_sent) {
tint_exec(battery_low_cmd); tint_exec(battery_low_cmd);
battery_low_cmd_sent = TRUE; battery_low_cmd_sent = TRUE;
} }
if (battery_state.percentage > battery_low_status && battery_state.state == BATTERY_CHARGING && if (battery_state.percentage > battery_low_status && battery_state.state == BATTERY_CHARGING &&
battery_low_cmd_sent) { battery_low_cmd_sent) {
battery_low_cmd_sent = FALSE; battery_low_cmd_sent = FALSE;
} }
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
// Show/hide if needed // Show/hide if needed
if (!battery_found) { if (!battery_found) {
hide(&panels[i].battery.area); hide(&panels[i].battery.area);
} else { } else {
if (battery_state.percentage >= percentage_hide) if (battery_state.percentage >= percentage_hide)
hide(&panels[i].battery.area); hide(&panels[i].battery.area);
else else
show(&panels[i].battery.area); show(&panels[i].battery.area);
} }
// Redraw if needed // Redraw if needed
if (panels[i].battery.area.on_screen) { if (panels[i].battery.area.on_screen) {
if (old_found != battery_found || old_percentage != battery_state.percentage || if (old_found != battery_found || old_percentage != battery_state.percentage ||
old_hours != battery_state.time.hours || old_minutes != battery_state.time.minutes) { old_hours != battery_state.time.hours || old_minutes != battery_state.time.minutes) {
panels[i].battery.area.resize_needed = TRUE; panels[i].battery.area.resize_needed = TRUE;
schedule_panel_redraw(); schedule_panel_redraw();
} }
} }
} }
} }
int update_battery() int update_battery()
{ {
// Reset // Reset
battery_state.state = BATTERY_UNKNOWN; battery_state.state = BATTERY_UNKNOWN;
battery_state.percentage = 0; battery_state.percentage = 0;
battery_state.ac_connected = FALSE; battery_state.ac_connected = FALSE;
battery_state_set_time(&battery_state, 0); battery_state_set_time(&battery_state, 0);
int err = battery_os_update(&battery_state); int err = battery_os_update(&battery_state);
// Clamp percentage to 100 in case battery is misreporting that its current charge is more than its max // Clamp percentage to 100 in case battery is misreporting that its current charge is more than its max
if (battery_state.percentage > 100) { if (battery_state.percentage > 100) {
battery_state.percentage = 100; battery_state.percentage = 100;
} }
return err; return err;
} }
int battery_compute_desired_size(void *obj) int battery_compute_desired_size(void *obj)
{ {
Battery *battery = (Battery *)obj; Battery *battery = (Battery *)obj;
Panel *panel = (Panel *)battery->area.panel; Panel *panel = (Panel *)battery->area.panel;
int bat_percentage_height, bat_percentage_width, bat_percentage_height_ink; int bat_percentage_height, bat_percentage_width, bat_percentage_height_ink;
int bat_time_height, bat_time_width, bat_time_height_ink; int bat_time_height, bat_time_width, bat_time_height_ink;
snprintf(buf_bat_percentage, sizeof(buf_bat_percentage), "%d%%", battery_state.percentage); snprintf(buf_bat_percentage, sizeof(buf_bat_percentage), "%d%%", battery_state.percentage);
if (battery_state.state == BATTERY_FULL) { if (battery_state.state == BATTERY_FULL) {
strcpy(buf_bat_time, "Full"); strcpy(buf_bat_time, "Full");
} else { } else {
snprintf(buf_bat_time, sizeof(buf_bat_time), "%02d:%02d", battery_state.time.hours, battery_state.time.minutes); snprintf(buf_bat_time, sizeof(buf_bat_time), "%02d:%02d", battery_state.time.hours, battery_state.time.minutes);
} }
get_text_size2(bat1_font_desc, get_text_size2(bat1_font_desc,
&bat_percentage_height_ink, &bat_percentage_height_ink,
&bat_percentage_height, &bat_percentage_height,
&bat_percentage_width, &bat_percentage_width,
panel->area.height, panel->area.height,
panel->area.width, panel->area.width,
buf_bat_percentage, buf_bat_percentage,
strlen(buf_bat_percentage), strlen(buf_bat_percentage),
PANGO_WRAP_WORD_CHAR, PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE, PANGO_ELLIPSIZE_NONE,
FALSE); FALSE);
get_text_size2(bat2_font_desc, get_text_size2(bat2_font_desc,
&bat_time_height_ink, &bat_time_height_ink,
&bat_time_height, &bat_time_height,
&bat_time_width, &bat_time_width,
panel->area.height, panel->area.height,
panel->area.width, panel->area.width,
buf_bat_time, buf_bat_time,
strlen(buf_bat_time), strlen(buf_bat_time),
PANGO_WRAP_WORD_CHAR, PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE, PANGO_ELLIPSIZE_NONE,
FALSE); FALSE);
if (panel_horizontal) { if (panel_horizontal) {
int new_size = (bat_percentage_width > bat_time_width) ? bat_percentage_width : bat_time_width; int new_size = (bat_percentage_width > bat_time_width) ? bat_percentage_width : bat_time_width;
new_size += 2 * battery->area.paddingxlr + left_right_border_width(&battery->area); new_size += 2 * battery->area.paddingxlr + left_right_border_width(&battery->area);
return new_size; return new_size;
} else { } else {
int new_size = bat_percentage_height + bat_time_height + 2 * battery->area.paddingxlr + int new_size = bat_percentage_height + bat_time_height + 2 * battery->area.paddingxlr +
top_bottom_border_width(&battery->area); top_bottom_border_width(&battery->area);
return new_size; return new_size;
} }
} }
gboolean resize_battery(void *obj) gboolean resize_battery(void *obj)
{ {
Battery *battery = (Battery *)obj; Battery *battery = (Battery *)obj;
Panel *panel = (Panel *)battery->area.panel; Panel *panel = (Panel *)battery->area.panel;
int bat_percentage_height, bat_percentage_width, bat_percentage_height_ink; int bat_percentage_height, bat_percentage_width, bat_percentage_height_ink;
int bat_time_height, bat_time_width, bat_time_height_ink; int bat_time_height, bat_time_width, bat_time_height_ink;
int ret = 0; int ret = 0;
snprintf(buf_bat_percentage, sizeof(buf_bat_percentage), "%d%%", battery_state.percentage); snprintf(buf_bat_percentage, sizeof(buf_bat_percentage), "%d%%", battery_state.percentage);
if (battery_state.state == BATTERY_FULL) { if (battery_state.state == BATTERY_FULL) {
strcpy(buf_bat_time, "Full"); strcpy(buf_bat_time, "Full");
} else { } else {
snprintf(buf_bat_time, sizeof(buf_bat_time), "%02d:%02d", battery_state.time.hours, battery_state.time.minutes); snprintf(buf_bat_time, sizeof(buf_bat_time), "%02d:%02d", battery_state.time.hours, battery_state.time.minutes);
} }
get_text_size2(bat1_font_desc, get_text_size2(bat1_font_desc,
&bat_percentage_height_ink, &bat_percentage_height_ink,
&bat_percentage_height, &bat_percentage_height,
&bat_percentage_width, &bat_percentage_width,
panel->area.height, panel->area.height,
panel->area.width, panel->area.width,
buf_bat_percentage, buf_bat_percentage,
strlen(buf_bat_percentage), strlen(buf_bat_percentage),
PANGO_WRAP_WORD_CHAR, PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE, PANGO_ELLIPSIZE_NONE,
FALSE); FALSE);
get_text_size2(bat2_font_desc, get_text_size2(bat2_font_desc,
&bat_time_height_ink, &bat_time_height_ink,
&bat_time_height, &bat_time_height,
&bat_time_width, &bat_time_width,
panel->area.height, panel->area.height,
panel->area.width, panel->area.width,
buf_bat_time, buf_bat_time,
strlen(buf_bat_time), strlen(buf_bat_time),
PANGO_WRAP_WORD_CHAR, PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE, PANGO_ELLIPSIZE_NONE,
FALSE); FALSE);
if (panel_horizontal) { if (panel_horizontal) {
int new_size = (bat_percentage_width > bat_time_width) ? bat_percentage_width : bat_time_width; int new_size = (bat_percentage_width > bat_time_width) ? bat_percentage_width : bat_time_width;
new_size += 2 * battery->area.paddingxlr + left_right_border_width(&battery->area); new_size += 2 * battery->area.paddingxlr + left_right_border_width(&battery->area);
if (new_size > battery->area.width || new_size < battery->area.width - 2) { if (new_size > battery->area.width || new_size < battery->area.width - 2) {
// we try to limit the number of resize // we try to limit the number of resize
battery->area.width = new_size; battery->area.width = new_size;
battery->bat1_posy = (battery->area.height - bat_percentage_height - bat_time_height) / 2; battery->bat1_posy = (battery->area.height - bat_percentage_height - bat_time_height) / 2;
battery->bat2_posy = battery->bat1_posy + bat_percentage_height; battery->bat2_posy = battery->bat1_posy + bat_percentage_height;
ret = 1; ret = 1;
} }
} else { } else {
int new_size = bat_percentage_height + bat_time_height + 2 * battery->area.paddingxlr + int new_size = bat_percentage_height + bat_time_height + 2 * battery->area.paddingxlr +
top_bottom_border_width(&battery->area); top_bottom_border_width(&battery->area);
if (new_size > battery->area.height || new_size < battery->area.height - 2) { if (new_size > battery->area.height || new_size < battery->area.height - 2) {
battery->area.height = new_size; battery->area.height = new_size;
battery->bat1_posy = (battery->area.height - bat_percentage_height - bat_time_height - 2) / 2; battery->bat1_posy = (battery->area.height - bat_percentage_height - bat_time_height - 2) / 2;
battery->bat2_posy = battery->bat1_posy + bat_percentage_height + 2; battery->bat2_posy = battery->bat1_posy + bat_percentage_height + 2;
ret = 1; ret = 1;
} }
} }
schedule_redraw(&battery->area); schedule_redraw(&battery->area);
return ret; return ret;
} }
void draw_battery(void *obj, cairo_t *c) void draw_battery(void *obj, cairo_t *c)
{ {
Battery *battery = obj; Battery *battery = obj;
PangoLayout *layout = pango_cairo_create_layout(c); PangoLayout *layout = pango_cairo_create_layout(c);
pango_layout_set_font_description(layout, bat1_font_desc); pango_layout_set_font_description(layout, bat1_font_desc);
pango_layout_set_width(layout, battery->area.width * PANGO_SCALE); pango_layout_set_width(layout, battery->area.width * PANGO_SCALE);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_set_text(layout, buf_bat_percentage, strlen(buf_bat_percentage)); pango_layout_set_text(layout, buf_bat_percentage, strlen(buf_bat_percentage));
cairo_set_source_rgba(c, cairo_set_source_rgba(c,
battery->font_color.rgb[0], battery->font_color.rgb[0],
battery->font_color.rgb[1], battery->font_color.rgb[1],
battery->font_color.rgb[2], battery->font_color.rgb[2],
battery->font_color.alpha); battery->font_color.alpha);
pango_cairo_update_layout(c, layout); pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, battery->bat1_posy, &battery->font_color, ((Panel *)battery->area.panel)->font_shadow); draw_text(layout, c, 0, battery->bat1_posy, &battery->font_color, ((Panel *)battery->area.panel)->font_shadow);
pango_layout_set_font_description(layout, bat2_font_desc); pango_layout_set_font_description(layout, bat2_font_desc);
pango_layout_set_indent(layout, 0); pango_layout_set_indent(layout, 0);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_set_text(layout, buf_bat_time, strlen(buf_bat_time)); pango_layout_set_text(layout, buf_bat_time, strlen(buf_bat_time));
pango_layout_set_width(layout, battery->area.width * PANGO_SCALE); pango_layout_set_width(layout, battery->area.width * PANGO_SCALE);
pango_cairo_update_layout(c, layout); pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, battery->bat2_posy, &battery->font_color, ((Panel *)battery->area.panel)->font_shadow); draw_text(layout, c, 0, battery->bat2_posy, &battery->font_color, ((Panel *)battery->area.panel)->font_shadow);
pango_cairo_show_layout(c, layout); pango_cairo_show_layout(c, layout);
g_object_unref(layout); g_object_unref(layout);
} }
void battery_dump_geometry(void *obj, int indent) void battery_dump_geometry(void *obj, int indent)
{ {
Battery *battery = obj; Battery *battery = obj;
fprintf(stderr, fprintf(stderr, "%*sText 1: y = %d, text = %s\n", indent, "", battery->bat1_posy, buf_bat_percentage);
"%*sText 1: y = %d, text = %s\n", fprintf(stderr, "%*sText 2: y = %d, text = %s\n", indent, "", battery->bat2_posy, buf_bat_time);
indent,
"",
battery->bat1_posy,
buf_bat_percentage);
fprintf(stderr,
"%*sText 2: y = %d, text = %s\n",
indent,
"",
battery->bat2_posy,
buf_bat_time);
} }
char *battery_get_tooltip(void *obj) char *battery_get_tooltip(void *obj)
{ {
return battery_os_tooltip(); return battery_os_tooltip();
} }
void battery_action(int button) void battery_action(int button)
{ {
char *command = NULL; char *command = NULL;
switch (button) { switch (button) {
case 1: case 1:
command = battery_lclick_command; command = battery_lclick_command;
break; break;
case 2: case 2:
command = battery_mclick_command; command = battery_mclick_command;
break; break;
case 3: case 3:
command = battery_rclick_command; command = battery_rclick_command;
break; break;
case 4: case 4:
command = battery_uwheel_command; command = battery_uwheel_command;
break; break;
case 5: case 5:
command = battery_dwheel_command; command = battery_dwheel_command;
break; break;
} }
tint_exec(command); tint_exec(command);
} }

View File

@@ -17,30 +17,30 @@
#include "area.h" #include "area.h"
typedef struct Battery { typedef struct Battery {
Area area; Area area;
Color font_color; Color font_color;
int bat1_posy; int bat1_posy;
int bat2_posy; int bat2_posy;
} Battery; } Battery;
typedef enum ChargeState { typedef enum ChargeState {
BATTERY_UNKNOWN = 0, BATTERY_UNKNOWN = 0,
BATTERY_CHARGING, BATTERY_CHARGING,
BATTERY_DISCHARGING, BATTERY_DISCHARGING,
BATTERY_FULL, BATTERY_FULL,
} ChargeState; } ChargeState;
typedef struct BatteryTime { typedef struct BatteryTime {
int16_t hours; int16_t hours;
int8_t minutes; int8_t minutes;
int8_t seconds; int8_t seconds;
} BatteryTime; } BatteryTime;
typedef struct BatteryState { typedef struct BatteryState {
int percentage; int percentage;
BatteryTime time; BatteryTime time;
ChargeState state; ChargeState state;
gboolean ac_connected; gboolean ac_connected;
} BatteryState; } BatteryState;
extern struct BatteryState battery_state; extern struct BatteryState battery_state;
@@ -68,26 +68,26 @@ extern char *battery_sys_prefix;
static inline gchar *chargestate2str(ChargeState state) static inline gchar *chargestate2str(ChargeState state)
{ {
switch (state) { switch (state) {
case BATTERY_CHARGING: case BATTERY_CHARGING:
return "Charging"; return "Charging";
case BATTERY_DISCHARGING: case BATTERY_DISCHARGING:
return "Discharging"; return "Discharging";
case BATTERY_FULL: case BATTERY_FULL:
return "Full"; return "Full";
case BATTERY_UNKNOWN: case BATTERY_UNKNOWN:
default: default:
return "Unknown"; return "Unknown";
}; };
} }
static inline void battery_state_set_time(BatteryState *state, int seconds) static inline void battery_state_set_time(BatteryState *state, int seconds)
{ {
state->time.hours = seconds / 3600; state->time.hours = seconds / 3600;
seconds -= 3600 * state->time.hours; seconds -= 3600 * state->time.hours;
state->time.minutes = seconds / 60; state->time.minutes = seconds / 60;
seconds -= 60 * state->time.minutes; seconds -= 60 * state->time.minutes;
state->time.seconds = seconds; state->time.seconds = seconds;
} }
// default global data // default global data

View File

@@ -25,20 +25,20 @@
gboolean battery_os_init() gboolean battery_os_init()
{ {
return FALSE; return FALSE;
} }
void battery_os_free() void battery_os_free()
{ {
return; return;
} }
int battery_os_update(BatteryState *state) int battery_os_update(BatteryState *state)
{ {
return -1; return -1;
} }
char *battery_os_tooltip() char *battery_os_tooltip()
{ {
return strdup("Operating System not supported"); return strdup("Operating System not supported");
} }

View File

@@ -26,77 +26,77 @@
gboolean battery_os_init() gboolean battery_os_init()
{ {
int sysctl_out = 0; int sysctl_out = 0;
size_t len = sizeof(sysctl_out); size_t len = sizeof(sysctl_out);
return (sysctlbyname("hw.acpi.battery.state", &sysctl_out, &len, NULL, 0) == 0) || return (sysctlbyname("hw.acpi.battery.state", &sysctl_out, &len, NULL, 0) == 0) ||
(sysctlbyname("hw.acpi.battery.time", &sysctl_out, &len, NULL, 0) == 0) || (sysctlbyname("hw.acpi.battery.time", &sysctl_out, &len, NULL, 0) == 0) ||
(sysctlbyname("hw.acpi.battery.life", &sysctl_out, &len, NULL, 0) == 0); (sysctlbyname("hw.acpi.battery.life", &sysctl_out, &len, NULL, 0) == 0);
} }
void battery_os_free() void battery_os_free()
{ {
return; return;
} }
int battery_os_update(BatteryState *state) int battery_os_update(BatteryState *state)
{ {
int sysctl_out = 0; int sysctl_out = 0;
size_t len = sizeof(sysctl_out); size_t len = sizeof(sysctl_out);
gboolean err = 0; gboolean err = 0;
if (sysctlbyname("hw.acpi.battery.state", &sysctl_out, &len, NULL, 0) == 0) { if (sysctlbyname("hw.acpi.battery.state", &sysctl_out, &len, NULL, 0) == 0) {
switch (sysctl_out) { switch (sysctl_out) {
case 1: case 1:
state->state = BATTERY_DISCHARGING; state->state = BATTERY_DISCHARGING;
break; break;
case 2: case 2:
state->state = BATTERY_CHARGING; state->state = BATTERY_CHARGING;
break; break;
default: default:
state->state = BATTERY_FULL; state->state = BATTERY_FULL;
break; break;
} }
} else { } else {
fprintf(stderr, "power update: no such sysctl"); fprintf(stderr, "power update: no such sysctl");
err = -1; err = -1;
} }
if (sysctlbyname("hw.acpi.battery.time", &sysctl_out, &len, NULL, 0) == 0) if (sysctlbyname("hw.acpi.battery.time", &sysctl_out, &len, NULL, 0) == 0)
battery_state_set_time(state, sysctl_out * 60); battery_state_set_time(state, sysctl_out * 60);
else else
err = -1; err = -1;
if (sysctlbyname("hw.acpi.battery.life", &sysctl_out, &len, NULL, 0) == 0) if (sysctlbyname("hw.acpi.battery.life", &sysctl_out, &len, NULL, 0) == 0)
state->percentage = sysctl_out; state->percentage = sysctl_out;
else else
err = -1; err = -1;
if (sysctlbyname("hw.acpi.acline", &sysctl_out, &len, NULL, 0) == 0) if (sysctlbyname("hw.acpi.acline", &sysctl_out, &len, NULL, 0) == 0)
state->ac_connected = sysctl_out; state->ac_connected = sysctl_out;
return err; return err;
} }
char *battery_os_tooltip() char *battery_os_tooltip()
{ {
GString *tooltip = g_string_new(""); GString *tooltip = g_string_new("");
gchar *result; gchar *result;
g_string_append_printf(tooltip, "Battery\n"); g_string_append_printf(tooltip, "Battery\n");
gchar *state = (battery_state.state == BATTERY_UNKNOWN) ? "Level" : chargestate2str(battery_state.state); gchar *state = (battery_state.state == BATTERY_UNKNOWN) ? "Level" : chargestate2str(battery_state.state);
g_string_append_printf(tooltip, "\t%s: %d%%", state, battery_state.percentage); g_string_append_printf(tooltip, "\t%s: %d%%", state, battery_state.percentage);
g_string_append_c(tooltip, '\n'); g_string_append_c(tooltip, '\n');
g_string_append_printf(tooltip, "AC\n"); g_string_append_printf(tooltip, "AC\n");
g_string_append_printf(tooltip, battery_state.ac_connected ? "\tConnected" : "\tDisconnected"); g_string_append_printf(tooltip, battery_state.ac_connected ? "\tConnected" : "\tDisconnected");
result = tooltip->str; result = tooltip->str;
g_string_free(tooltip, FALSE); g_string_free(tooltip, FALSE);
return result; return result;
} }
#endif #endif

View File

@@ -26,513 +26,514 @@
#include "uevent.h" #include "uevent.h"
enum psy_type { enum psy_type {
PSY_UNKNOWN, PSY_UNKNOWN,
PSY_BATTERY, PSY_BATTERY,
PSY_MAINS, PSY_MAINS,
}; };
struct psy_battery { struct psy_battery {
/* generic properties */ /* generic properties */
gchar *name; gchar *name;
/* monotonic time, in microseconds */ /* monotonic time, in microseconds */
gint64 timestamp; gint64 timestamp;
/* sysfs files */ /* sysfs files */
gchar *path_present; gchar *path_present;
gchar *path_level_now; gchar *path_level_now;
gchar *path_level_full; gchar *path_level_full;
gchar *path_rate_now; gchar *path_rate_now;
gchar *path_status; gchar *path_status;
/* values */ /* values */
gboolean present; gboolean present;
gint level_now; gint level_now;
gint level_full; gint level_full;
gint rate_now; gint rate_now;
gchar unit; gchar unit;
ChargeState status; ChargeState status;
}; };
struct psy_mains { struct psy_mains {
/* generic properties */ /* generic properties */
gchar *name; gchar *name;
/* sysfs files */ /* sysfs files */
gchar *path_online; gchar *path_online;
/* values */ /* values */
gboolean online; gboolean online;
}; };
static void uevent_battery_update() static void uevent_battery_update()
{ {
update_battery_tick(NULL); update_battery_tick(NULL);
} }
static struct uevent_notify psy_change = {UEVENT_CHANGE, "power_supply", NULL, uevent_battery_update}; static struct uevent_notify psy_change = {UEVENT_CHANGE, "power_supply", NULL, uevent_battery_update};
static void uevent_battery_plug() static void uevent_battery_plug()
{ {
printf("reinitialize batteries after HW change\n"); printf("reinitialize batteries after HW change\n");
reinit_battery(); reinit_battery();
} }
static struct uevent_notify psy_plug = {UEVENT_ADD | UEVENT_REMOVE, "power_supply", NULL, uevent_battery_plug}; static struct uevent_notify psy_plug = {UEVENT_ADD | UEVENT_REMOVE, "power_supply", NULL, uevent_battery_plug};
#define RETURN_ON_ERROR(err) \ #define RETURN_ON_ERROR(err) \
if (err) { \ if (err) { \
g_error_free(err); \ g_error_free(err); \
fprintf(stderr, RED "%s:%d: errror" RESET "\n", __FILE__, __LINE__); \ fprintf(stderr, RED "%s:%d: errror" RESET "\n", __FILE__, __LINE__); \
return FALSE; \ return FALSE; \
} }
static GList *batteries = NULL; static GList *batteries = NULL;
static GList *mains = NULL; static GList *mains = NULL;
static guint8 level_to_percent(gint level_now, gint level_full) static guint8 level_to_percent(gint level_now, gint level_full)
{ {
return 0.5 + ((level_now <= level_full ? level_now : level_full) * 100.0) / level_full; return 0.5 + ((level_now <= level_full ? level_now : level_full) * 100.0) / level_full;
} }
static enum psy_type power_supply_get_type(const gchar *entryname) static enum psy_type power_supply_get_type(const gchar *entryname)
{ {
gchar *path_type = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "type", NULL); gchar *path_type = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "type", NULL);
GError *error = NULL; GError *error = NULL;
gchar *type; gchar *type;
gsize typelen; gsize typelen;
g_file_get_contents(path_type, &type, &typelen, &error); g_file_get_contents(path_type, &type, &typelen, &error);
g_free(path_type); g_free(path_type);
if (error) { if (error) {
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__); fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
g_error_free(error); g_error_free(error);
return PSY_UNKNOWN; return PSY_UNKNOWN;
} }
if (!g_strcmp0(type, "Battery\n")) { if (!g_strcmp0(type, "Battery\n")) {
g_free(type); g_free(type);
return PSY_BATTERY; return PSY_BATTERY;
} }
if (!g_strcmp0(type, "Mains\n")) { if (!g_strcmp0(type, "Mains\n")) {
g_free(type); g_free(type);
return PSY_MAINS; return PSY_MAINS;
} }
g_free(type); g_free(type);
return PSY_UNKNOWN; return PSY_UNKNOWN;
} }
static gboolean init_linux_battery(struct psy_battery *bat) static gboolean init_linux_battery(struct psy_battery *bat)
{ {
const gchar *entryname = bat->name; const gchar *entryname = bat->name;
bat->path_present = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "present", NULL); bat->path_present = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "present", NULL);
if (!g_file_test(bat->path_present, G_FILE_TEST_EXISTS)) { if (!g_file_test(bat->path_present, G_FILE_TEST_EXISTS)) {
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__); fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
goto err0; goto err0;
} }
bat->path_level_now = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "energy_now", NULL); bat->path_level_now =
bat->path_level_full = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "energy_now", NULL);
g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "energy_full", NULL); bat->path_level_full =
bat->path_rate_now = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "power_now", NULL); g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "energy_full", NULL);
bat->unit = 'W'; bat->path_rate_now = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "power_now", NULL);
bat->unit = 'W';
if (!g_file_test(bat->path_level_now, G_FILE_TEST_EXISTS) || if (!g_file_test(bat->path_level_now, G_FILE_TEST_EXISTS) ||
!g_file_test(bat->path_level_full, G_FILE_TEST_EXISTS) || !g_file_test(bat->path_level_full, G_FILE_TEST_EXISTS) ||
!g_file_test(bat->path_rate_now, G_FILE_TEST_EXISTS)) { !g_file_test(bat->path_rate_now, G_FILE_TEST_EXISTS)) {
g_free(bat->path_level_now); g_free(bat->path_level_now);
g_free(bat->path_level_full); g_free(bat->path_level_full);
g_free(bat->path_rate_now); g_free(bat->path_rate_now);
bat->path_level_now = bat->path_level_now =
g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "charge_now", NULL); g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "charge_now", NULL);
bat->path_level_full = bat->path_level_full =
g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "charge_full", NULL); g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "charge_full", NULL);
bat->path_rate_now = bat->path_rate_now =
g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "current_now", NULL); g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "current_now", NULL);
bat->unit = 'A'; bat->unit = 'A';
} }
if (!g_file_test(bat->path_level_now, G_FILE_TEST_EXISTS) || if (!g_file_test(bat->path_level_now, G_FILE_TEST_EXISTS) ||
!g_file_test(bat->path_level_full, G_FILE_TEST_EXISTS) || !g_file_test(bat->path_level_full, G_FILE_TEST_EXISTS) ||
!g_file_test(bat->path_rate_now, G_FILE_TEST_EXISTS)) { !g_file_test(bat->path_rate_now, G_FILE_TEST_EXISTS)) {
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__); fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
goto err1; goto err1;
} }
bat->path_status = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "status", NULL); bat->path_status = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "status", NULL);
if (!g_file_test(bat->path_status, G_FILE_TEST_EXISTS)) { if (!g_file_test(bat->path_status, G_FILE_TEST_EXISTS)) {
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__); fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
goto err2; goto err2;
} }
return TRUE; return TRUE;
err2: err2:
g_free(bat->path_status); g_free(bat->path_status);
err1: err1:
g_free(bat->path_level_now); g_free(bat->path_level_now);
g_free(bat->path_level_full); g_free(bat->path_level_full);
g_free(bat->path_rate_now); g_free(bat->path_rate_now);
err0: err0:
g_free(bat->path_present); g_free(bat->path_present);
return FALSE; return FALSE;
} }
static gboolean init_linux_mains(struct psy_mains *ac) static gboolean init_linux_mains(struct psy_mains *ac)
{ {
const gchar *entryname = ac->name; const gchar *entryname = ac->name;
ac->path_online = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "online", NULL); ac->path_online = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", entryname, "online", NULL);
if (!g_file_test(ac->path_online, G_FILE_TEST_EXISTS)) { if (!g_file_test(ac->path_online, G_FILE_TEST_EXISTS)) {
fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__); fprintf(stderr, RED "%s:%d: read failed" RESET "\n", __FILE__, __LINE__);
g_free(ac->path_online); g_free(ac->path_online);
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
static void psy_battery_free(gpointer data) static void psy_battery_free(gpointer data)
{ {
struct psy_battery *bat = data; struct psy_battery *bat = data;
g_free(bat->name); g_free(bat->name);
g_free(bat->path_status); g_free(bat->path_status);
g_free(bat->path_rate_now); g_free(bat->path_rate_now);
g_free(bat->path_level_full); g_free(bat->path_level_full);
g_free(bat->path_level_now); g_free(bat->path_level_now);
g_free(bat->path_present); g_free(bat->path_present);
g_free(bat); g_free(bat);
} }
static void psy_mains_free(gpointer data) static void psy_mains_free(gpointer data)
{ {
struct psy_mains *ac = data; struct psy_mains *ac = data;
g_free(ac->name); g_free(ac->name);
g_free(ac->path_online); g_free(ac->path_online);
g_free(ac); g_free(ac);
} }
void battery_os_free() void battery_os_free()
{ {
uevent_unregister_notifier(&psy_change); uevent_unregister_notifier(&psy_change);
uevent_unregister_notifier(&psy_plug); uevent_unregister_notifier(&psy_plug);
g_list_free_full(batteries, psy_battery_free); g_list_free_full(batteries, psy_battery_free);
batteries = NULL; batteries = NULL;
g_list_free_full(mains, psy_mains_free); g_list_free_full(mains, psy_mains_free);
mains = NULL; mains = NULL;
} }
static void add_battery(const char *entryname) static void add_battery(const char *entryname)
{ {
struct psy_battery *bat = g_malloc0(sizeof(*bat)); struct psy_battery *bat = g_malloc0(sizeof(*bat));
bat->name = g_strdup(entryname); bat->name = g_strdup(entryname);
if (init_linux_battery(bat)) { if (init_linux_battery(bat)) {
batteries = g_list_append(batteries, bat); batteries = g_list_append(batteries, bat);
fprintf(stdout, GREEN "Found battery \"%s\"" RESET "\n", bat->name); fprintf(stdout, GREEN "Found battery \"%s\"" RESET "\n", bat->name);
} else { } else {
g_free(bat); g_free(bat);
fprintf(stderr, RED "Failed to initialize battery \"%s\"" RESET "\n", entryname); fprintf(stderr, RED "Failed to initialize battery \"%s\"" RESET "\n", entryname);
} }
} }
static void add_mains(const char *entryname) static void add_mains(const char *entryname)
{ {
struct psy_mains *ac = g_malloc0(sizeof(*ac)); struct psy_mains *ac = g_malloc0(sizeof(*ac));
ac->name = g_strdup(entryname); ac->name = g_strdup(entryname);
if (init_linux_mains(ac)) { if (init_linux_mains(ac)) {
mains = g_list_append(mains, ac); mains = g_list_append(mains, ac);
fprintf(stdout, GREEN "Found mains \"%s\"" RESET "\n", ac->name); fprintf(stdout, GREEN "Found mains \"%s\"" RESET "\n", ac->name);
} else { } else {
g_free(ac); g_free(ac);
fprintf(stderr, RED "Failed to initialize mains \"%s\"" RESET "\n", entryname); fprintf(stderr, RED "Failed to initialize mains \"%s\"" RESET "\n", entryname);
} }
} }
gboolean battery_os_init() gboolean battery_os_init()
{ {
GDir *directory = 0; GDir *directory = 0;
GError *error = NULL; GError *error = NULL;
const char *entryname; const char *entryname;
battery_os_free(); battery_os_free();
gchar *dir_path = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", NULL); gchar *dir_path = g_build_filename(battery_sys_prefix, "/sys/class/power_supply", NULL);
directory = g_dir_open(dir_path, 0, &error); directory = g_dir_open(dir_path, 0, &error);
g_free(dir_path); g_free(dir_path);
RETURN_ON_ERROR(error); RETURN_ON_ERROR(error);
while ((entryname = g_dir_read_name(directory))) { while ((entryname = g_dir_read_name(directory))) {
fprintf(stderr, GREEN "Found power device %s" RESET "\n", entryname); fprintf(stderr, GREEN "Found power device %s" RESET "\n", entryname);
enum psy_type type = power_supply_get_type(entryname); enum psy_type type = power_supply_get_type(entryname);
switch (type) { switch (type) {
case PSY_BATTERY: case PSY_BATTERY:
add_battery(entryname); add_battery(entryname);
break; break;
case PSY_MAINS: case PSY_MAINS:
add_mains(entryname); add_mains(entryname);
break; break;
default: default:
break; break;
} }
} }
g_dir_close(directory); g_dir_close(directory);
uevent_register_notifier(&psy_change); uevent_register_notifier(&psy_change);
uevent_register_notifier(&psy_plug); uevent_register_notifier(&psy_plug);
return batteries != NULL; return batteries != NULL;
} }
static gint estimate_rate_usage(struct psy_battery *bat, gint old_level_now, gint64 old_timestamp) static gint estimate_rate_usage(struct psy_battery *bat, gint old_level_now, gint64 old_timestamp)
{ {
gint64 diff_level = ABS(bat->level_now - old_level_now); gint64 diff_level = ABS(bat->level_now - old_level_now);
gint64 diff_time = bat->timestamp - old_timestamp; gint64 diff_time = bat->timestamp - old_timestamp;
/* µW = (µWh * 3600) / (µs / 1000000) */ /* µW = (µWh * 3600) / (µs / 1000000) */
gint rate = diff_level * 3600 * 1000000 / MAX(1, diff_time); gint rate = diff_level * 3600 * 1000000 / MAX(1, diff_time);
return rate; return rate;
} }
static gboolean update_linux_battery(struct psy_battery *bat) static gboolean update_linux_battery(struct psy_battery *bat)
{ {
GError *error = NULL; GError *error = NULL;
gchar *data; gchar *data;
gsize datalen; gsize datalen;
gint64 old_timestamp = bat->timestamp; gint64 old_timestamp = bat->timestamp;
int old_level_now = bat->level_now; int old_level_now = bat->level_now;
gint old_rate_now = bat->rate_now; gint old_rate_now = bat->rate_now;
/* reset values */ /* reset values */
bat->present = 0; bat->present = 0;
bat->status = BATTERY_UNKNOWN; bat->status = BATTERY_UNKNOWN;
bat->level_now = 0; bat->level_now = 0;
bat->level_full = 0; bat->level_full = 0;
bat->rate_now = 0; bat->rate_now = 0;
bat->timestamp = g_get_monotonic_time(); bat->timestamp = g_get_monotonic_time();
/* present */ /* present */
g_file_get_contents(bat->path_present, &data, &datalen, &error); g_file_get_contents(bat->path_present, &data, &datalen, &error);
RETURN_ON_ERROR(error); RETURN_ON_ERROR(error);
bat->present = (atoi(data) == 1); bat->present = (atoi(data) == 1);
g_free(data); g_free(data);
/* we are done, if battery is not present */ /* we are done, if battery is not present */
if (!bat->present) if (!bat->present)
return TRUE; return TRUE;
/* status */ /* status */
bat->status = BATTERY_UNKNOWN; bat->status = BATTERY_UNKNOWN;
g_file_get_contents(bat->path_status, &data, &datalen, &error); g_file_get_contents(bat->path_status, &data, &datalen, &error);
RETURN_ON_ERROR(error); RETURN_ON_ERROR(error);
if (!g_strcmp0(data, "Charging\n")) { if (!g_strcmp0(data, "Charging\n")) {
bat->status = BATTERY_CHARGING; bat->status = BATTERY_CHARGING;
} else if (!g_strcmp0(data, "Discharging\n")) { } else if (!g_strcmp0(data, "Discharging\n")) {
bat->status = BATTERY_DISCHARGING; bat->status = BATTERY_DISCHARGING;
} else if (!g_strcmp0(data, "Full\n")) { } else if (!g_strcmp0(data, "Full\n")) {
bat->status = BATTERY_FULL; bat->status = BATTERY_FULL;
} }
g_free(data); g_free(data);
/* level now */ /* level now */
g_file_get_contents(bat->path_level_now, &data, &datalen, &error); g_file_get_contents(bat->path_level_now, &data, &datalen, &error);
RETURN_ON_ERROR(error); RETURN_ON_ERROR(error);
bat->level_now = atoi(data); bat->level_now = atoi(data);
g_free(data); g_free(data);
/* level full */ /* level full */
g_file_get_contents(bat->path_level_full, &data, &datalen, &error); g_file_get_contents(bat->path_level_full, &data, &datalen, &error);
RETURN_ON_ERROR(error); RETURN_ON_ERROR(error);
bat->level_full = atoi(data); bat->level_full = atoi(data);
g_free(data); g_free(data);
/* rate now */ /* rate now */
g_file_get_contents(bat->path_rate_now, &data, &datalen, &error); g_file_get_contents(bat->path_rate_now, &data, &datalen, &error);
if (g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NODEV)) { if (g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NODEV)) {
/* some hardware does not support reading current rate consumption */ /* some hardware does not support reading current rate consumption */
g_error_free(error); g_error_free(error);
bat->rate_now = estimate_rate_usage(bat, old_level_now, old_timestamp); bat->rate_now = estimate_rate_usage(bat, old_level_now, old_timestamp);
if (bat->rate_now == 0 && bat->status != BATTERY_FULL) { if (bat->rate_now == 0 && bat->status != BATTERY_FULL) {
/* If the hardware updates the level slower than our sampling period, /* If the hardware updates the level slower than our sampling period,
* we need to sample more rarely */ * we need to sample more rarely */
bat->rate_now = old_rate_now; bat->rate_now = old_rate_now;
bat->timestamp = old_timestamp; bat->timestamp = old_timestamp;
} }
} else if (error) { } else if (error) {
g_error_free(error); g_error_free(error);
return FALSE; return FALSE;
} else { } else {
bat->rate_now = atoi(data); bat->rate_now = atoi(data);
g_free(data); g_free(data);
} }
return TRUE; return TRUE;
} }
static gboolean update_linux_mains(struct psy_mains *ac) static gboolean update_linux_mains(struct psy_mains *ac)
{ {
GError *error = NULL; GError *error = NULL;
gchar *data; gchar *data;
gsize datalen; gsize datalen;
ac->online = FALSE; ac->online = FALSE;
/* online */ /* online */
g_file_get_contents(ac->path_online, &data, &datalen, &error); g_file_get_contents(ac->path_online, &data, &datalen, &error);
RETURN_ON_ERROR(error); RETURN_ON_ERROR(error);
ac->online = (atoi(data) == 1); ac->online = (atoi(data) == 1);
g_free(data); g_free(data);
return TRUE; return TRUE;
} }
int battery_os_update(BatteryState *state) int battery_os_update(BatteryState *state)
{ {
GList *l; GList *l;
gint64 total_level_now = 0; gint64 total_level_now = 0;
gint64 total_level_full = 0; gint64 total_level_full = 0;
gint64 total_rate_now = 0; gint64 total_rate_now = 0;
gint seconds = 0; gint seconds = 0;
gboolean charging = FALSE; gboolean charging = FALSE;
gboolean discharging = FALSE; gboolean discharging = FALSE;
gboolean full = FALSE; gboolean full = FALSE;
gboolean ac_connected = FALSE; gboolean ac_connected = FALSE;
for (l = batteries; l != NULL; l = l->next) { for (l = batteries; l != NULL; l = l->next) {
struct psy_battery *bat = l->data; struct psy_battery *bat = l->data;
update_linux_battery(bat); update_linux_battery(bat);
total_level_now += bat->level_now; total_level_now += bat->level_now;
total_level_full += bat->level_full; total_level_full += bat->level_full;
total_rate_now += bat->rate_now; total_rate_now += bat->rate_now;
charging |= (bat->status == BATTERY_CHARGING); charging |= (bat->status == BATTERY_CHARGING);
discharging |= (bat->status == BATTERY_DISCHARGING); discharging |= (bat->status == BATTERY_DISCHARGING);
full |= (bat->status == BATTERY_FULL); full |= (bat->status == BATTERY_FULL);
} }
for (l = mains; l != NULL; l = l->next) { for (l = mains; l != NULL; l = l->next) {
struct psy_mains *ac = l->data; struct psy_mains *ac = l->data;
update_linux_mains(ac); update_linux_mains(ac);
ac_connected |= (ac->online); ac_connected |= (ac->online);
} }
/* build global state */ /* build global state */
if (charging && !discharging) if (charging && !discharging)
state->state = BATTERY_CHARGING; state->state = BATTERY_CHARGING;
else if (!charging && discharging) else if (!charging && discharging)
state->state = BATTERY_DISCHARGING; state->state = BATTERY_DISCHARGING;
else if (!charging && !discharging && full) else if (!charging && !discharging && full)
state->state = BATTERY_FULL; state->state = BATTERY_FULL;
/* calculate seconds */ /* calculate seconds */
if (total_rate_now > 0) { if (total_rate_now > 0) {
if (state->state == BATTERY_CHARGING) if (state->state == BATTERY_CHARGING)
seconds = 3600 * (total_level_full - total_level_now) / total_rate_now; seconds = 3600 * (total_level_full - total_level_now) / total_rate_now;
else if (state->state == BATTERY_DISCHARGING) else if (state->state == BATTERY_DISCHARGING)
seconds = 3600 * total_level_now / total_rate_now; seconds = 3600 * total_level_now / total_rate_now;
seconds = MAX(0, seconds); seconds = MAX(0, seconds);
} }
battery_state_set_time(state, seconds); battery_state_set_time(state, seconds);
/* calculate percentage */ /* calculate percentage */
state->percentage = level_to_percent(total_level_now, total_level_full); state->percentage = level_to_percent(total_level_now, total_level_full);
/* AC state */ /* AC state */
state->ac_connected = ac_connected; state->ac_connected = ac_connected;
return 0; return 0;
} }
static gchar *level_human_readable(struct psy_battery *bat) static gchar *level_human_readable(struct psy_battery *bat)
{ {
gint now = bat->level_now; gint now = bat->level_now;
gint full = bat->level_full; gint full = bat->level_full;
if (full >= 1000000) { if (full >= 1000000) {
return g_strdup_printf("%d.%d / %d.%d %ch", return g_strdup_printf("%d.%d / %d.%d %ch",
now / 1000000, now / 1000000,
(now % 1000000) / 100000, (now % 1000000) / 100000,
full / 1000000, full / 1000000,
(full % 1000000) / 100000, (full % 1000000) / 100000,
bat->unit); bat->unit);
} else if (full >= 1000) { } else if (full >= 1000) {
return g_strdup_printf("%d.%d / %d.%d m%ch", return g_strdup_printf("%d.%d / %d.%d m%ch",
now / 1000, now / 1000,
(now % 1000) / 100, (now % 1000) / 100,
full / 1000, full / 1000,
(full % 1000) / 100, (full % 1000) / 100,
bat->unit); bat->unit);
} else { } else {
return g_strdup_printf("%d / %d µ%ch", now, full, bat->unit); return g_strdup_printf("%d / %d µ%ch", now, full, bat->unit);
} }
} }
static gchar *rate_human_readable(struct psy_battery *bat) static gchar *rate_human_readable(struct psy_battery *bat)
{ {
gint rate = bat->rate_now; gint rate = bat->rate_now;
gchar unit = bat->unit; gchar unit = bat->unit;
if (rate >= 1000000) { if (rate >= 1000000) {
return g_strdup_printf("%d.%d %c", rate / 1000000, (rate % 1000000) / 100000, unit); return g_strdup_printf("%d.%d %c", rate / 1000000, (rate % 1000000) / 100000, unit);
} else if (rate >= 1000) { } else if (rate >= 1000) {
return g_strdup_printf("%d.%d m%c", rate / 1000, (rate % 1000) / 100, unit); return g_strdup_printf("%d.%d m%c", rate / 1000, (rate % 1000) / 100, unit);
} else if (rate > 0) { } else if (rate > 0) {
return g_strdup_printf("%d µ%c", rate, unit); return g_strdup_printf("%d µ%c", rate, unit);
} else { } else {
return g_strdup_printf("0 %c", unit); return g_strdup_printf("0 %c", unit);
} }
} }
char *battery_os_tooltip() char *battery_os_tooltip()
{ {
GList *l; GList *l;
GString *tooltip = g_string_new(""); GString *tooltip = g_string_new("");
gchar *result; gchar *result;
for (l = batteries; l != NULL; l = l->next) { for (l = batteries; l != NULL; l = l->next) {
struct psy_battery *bat = l->data; struct psy_battery *bat = l->data;
if (tooltip->len) if (tooltip->len)
g_string_append_c(tooltip, '\n'); g_string_append_c(tooltip, '\n');
g_string_append_printf(tooltip, "%s\n", bat->name); g_string_append_printf(tooltip, "%s\n", bat->name);
if (!bat->present) { if (!bat->present) {
g_string_append_printf(tooltip, "\tnot connected"); g_string_append_printf(tooltip, "\tnot connected");
continue; continue;
} }
gchar *rate = rate_human_readable(bat); gchar *rate = rate_human_readable(bat);
gchar *level = level_human_readable(bat); gchar *level = level_human_readable(bat);
gchar *state = (bat->status == BATTERY_UNKNOWN) ? "energy" : chargestate2str(bat->status); gchar *state = (bat->status == BATTERY_UNKNOWN) ? "energy" : chargestate2str(bat->status);
guint8 percentage = level_to_percent(bat->level_now, bat->level_full); guint8 percentage = level_to_percent(bat->level_now, bat->level_full);
g_string_append_printf(tooltip, "\t%s: %s (%u %%)\n\trate: %s", state, level, percentage, rate); g_string_append_printf(tooltip, "\t%s: %s (%u %%)\n\trate: %s", state, level, percentage, rate);
g_free(rate); g_free(rate);
g_free(level); g_free(level);
} }
for (l = mains; l != NULL; l = l->next) { for (l = mains; l != NULL; l = l->next) {
struct psy_mains *ac = l->data; struct psy_mains *ac = l->data;
if (tooltip->len) if (tooltip->len)
g_string_append_c(tooltip, '\n'); g_string_append_c(tooltip, '\n');
g_string_append_printf(tooltip, "%s\n", ac->name); g_string_append_printf(tooltip, "%s\n", ac->name);
g_string_append_printf(tooltip, ac->online ? "\tConnected" : "\tDisconnected"); g_string_append_printf(tooltip, ac->online ? "\tConnected" : "\tDisconnected");
} }
result = tooltip->str; result = tooltip->str;
g_string_free(tooltip, FALSE); g_string_free(tooltip, FALSE);
return result; return result;
} }
#endif #endif

View File

@@ -31,78 +31,78 @@ int apm_fd = -1;
gboolean battery_os_init() gboolean battery_os_init()
{ {
if (apm_fd > 0) if (apm_fd > 0)
close(apm_fd); close(apm_fd);
apm_fd = open("/dev/apm", O_RDONLY); apm_fd = open("/dev/apm", O_RDONLY);
if (apm_fd < 0) { if (apm_fd < 0) {
warn("ERROR: battery applet cannot open /dev/apm."); warn("ERROR: battery applet cannot open /dev/apm.");
return FALSE; return FALSE;
} else { } else {
return TRUE; return TRUE;
} }
} }
void battery_os_free() void battery_os_free()
{ {
if ((apm_fd != -1) && (close(apm_fd) == -1)) if ((apm_fd != -1) && (close(apm_fd) == -1))
warn("cannot close /dev/apm"); warn("cannot close /dev/apm");
apm_fd = -1; apm_fd = -1;
} }
int battery_os_update(BatteryState *state) int battery_os_update(BatteryState *state)
{ {
struct apm_power_info info; struct apm_power_info info;
if (apm_fd > 0 && ioctl(apm_fd, APM_IOC_GETPOWER, &(info)) == 0) { if (apm_fd > 0 && ioctl(apm_fd, APM_IOC_GETPOWER, &(info)) == 0) {
// best attempt at mapping to Linux battery states // best attempt at mapping to Linux battery states
switch (info.battery_state) { switch (info.battery_state) {
case APM_BATT_CHARGING: case APM_BATT_CHARGING:
state->state = BATTERY_CHARGING; state->state = BATTERY_CHARGING;
break; break;
default: default:
state->state = BATTERY_DISCHARGING; state->state = BATTERY_DISCHARGING;
break; break;
} }
if (info.battery_life > 100) if (info.battery_life > 100)
info.battery_life = 100; info.battery_life = 100;
if (info.battery_life == 100) if (info.battery_life == 100)
state->state = BATTERY_FULL; state->state = BATTERY_FULL;
state->percentage = info.battery_life; state->percentage = info.battery_life;
if (info.minutes_left != -1) if (info.minutes_left != -1)
battery_state_set_time(state, info.minutes_left * 60); battery_state_set_time(state, info.minutes_left * 60);
state->ac_connected = info.ac_state == APM_AC_ON; state->ac_connected = info.ac_state == APM_AC_ON;
} else { } else {
warn("power update: APM_IOC_GETPOWER"); warn("power update: APM_IOC_GETPOWER");
return -1; return -1;
} }
return 0; return 0;
} }
char *battery_os_tooltip() char *battery_os_tooltip()
{ {
GString *tooltip = g_string_new(""); GString *tooltip = g_string_new("");
gchar *result; gchar *result;
g_string_append_printf(tooltip, "Battery\n"); g_string_append_printf(tooltip, "Battery\n");
gchar *state = (battery_state.state == BATTERY_UNKNOWN) ? "Level" : chargestate2str(battery_state.state); gchar *state = (battery_state.state == BATTERY_UNKNOWN) ? "Level" : chargestate2str(battery_state.state);
g_string_append_printf(tooltip, "\t%s: %d%%", state, battery_state.percentage); g_string_append_printf(tooltip, "\t%s: %d%%", state, battery_state.percentage);
g_string_append_c(tooltip, '\n'); g_string_append_c(tooltip, '\n');
g_string_append_printf(tooltip, "AC\n"); g_string_append_printf(tooltip, "AC\n");
g_string_append_printf(tooltip, battery_state.ac_connected ? "\tConnected" : "\tDisconnected"); g_string_append_printf(tooltip, battery_state.ac_connected ? "\tConnected" : "\tDisconnected");
result = tooltip->str; result = tooltip->str;
g_string_free(tooltip, FALSE); g_string_free(tooltip, FALSE);
return result; return result;
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -17,55 +17,56 @@
// backend's config and state variables. // backend's config and state variables.
typedef struct ButtonBackend { typedef struct ButtonBackend {
// Config: // Config:
char *icon_name; char *icon_name;
char *text; char *text;
char *tooltip; char *tooltip;
gboolean centered; gboolean centered;
int max_icon_size; int max_icon_size;
gboolean has_font; gboolean has_font;
PangoFontDescription *font_desc; PangoFontDescription *font_desc;
Color font_color; Color font_color;
char *lclick_command; char *lclick_command;
char *mclick_command; char *mclick_command;
char *rclick_command; char *rclick_command;
char *uwheel_command; char *uwheel_command;
char *dwheel_command; char *dwheel_command;
// paddingxlr = horizontal padding left/right // paddingxlr = horizontal padding left/right
// paddingx = horizontal padding between childs // paddingx = horizontal padding between childs
int paddingxlr, paddingx, paddingy; int paddingxlr, paddingx, paddingy;
Background *bg; Background *bg;
// List of Button which are frontends for this backend, one for each panel // List of Button which are frontends for this backend, one for each panel
GList *instances; GList *instances;
} ButtonBackend; } ButtonBackend;
typedef struct ButtonFrontend { typedef struct ButtonFrontend {
// Frontend state: // Frontend state:
Imlib_Image icon; Imlib_Image icon;
Imlib_Image icon_hover; Imlib_Image icon_hover;
Imlib_Image icon_pressed; Imlib_Image icon_pressed;
int icon_load_size; int icon_load_size;
int iconx; int iconx;
int icony; int icony;
int iconw; int iconw;
int iconh; int iconh;
int textx; int textx;
int texty; int texty;
int textw; int textw;
int texth; int texth;
} ButtonFrontend; } ButtonFrontend;
typedef struct Button { typedef struct Button {
Area area; Area area;
// All elements have the backend pointer set. However only backend elements have ownership. // All elements have the backend pointer set. However only backend elements have ownership.
ButtonBackend *backend; ButtonBackend *backend;
// Set only for frontend Button items. // Set only for frontend Button items.
ButtonFrontend *frontend; ButtonFrontend *frontend;
} Button; } Button;
// Called before the config is read and panel_config/panels are created. // Called before the config is read and panel_config/panels are created.
// Afterwards, the config parsing code creates the array of Button in panel_config and populates the configuration fields // Afterwards, the config parsing code creates the array of Button in panel_config and populates the configuration
// fields
// in the backend. // in the backend.
// Probably does nothing. // Probably does nothing.
void default_button(); void default_button();

View File

@@ -60,105 +60,105 @@ void clock_dump_geometry(void *obj, int indent);
void default_clock() void default_clock()
{ {
clock_enabled = 0; clock_enabled = 0;
clock_timeout = NULL; clock_timeout = NULL;
time1_format = NULL; time1_format = NULL;
time1_timezone = NULL; time1_timezone = NULL;
time2_format = NULL; time2_format = NULL;
time2_timezone = NULL; time2_timezone = NULL;
time_tooltip_format = NULL; time_tooltip_format = NULL;
time_tooltip_timezone = NULL; time_tooltip_timezone = NULL;
clock_lclick_command = NULL; clock_lclick_command = NULL;
clock_mclick_command = NULL; clock_mclick_command = NULL;
clock_rclick_command = NULL; clock_rclick_command = NULL;
clock_uwheel_command = NULL; clock_uwheel_command = NULL;
clock_dwheel_command = NULL; clock_dwheel_command = NULL;
time1_has_font = FALSE; time1_has_font = FALSE;
time1_font_desc = NULL; time1_font_desc = NULL;
time2_has_font = FALSE; time2_has_font = FALSE;
time2_font_desc = NULL; time2_font_desc = NULL;
} }
void cleanup_clock() void cleanup_clock()
{ {
pango_font_description_free(time1_font_desc); pango_font_description_free(time1_font_desc);
time1_font_desc = NULL; time1_font_desc = NULL;
pango_font_description_free(time2_font_desc); pango_font_description_free(time2_font_desc);
time2_font_desc = NULL; time2_font_desc = NULL;
free(time1_format); free(time1_format);
time1_format = NULL; time1_format = NULL;
free(time2_format); free(time2_format);
time2_format = NULL; time2_format = NULL;
free(time_tooltip_format); free(time_tooltip_format);
time_tooltip_format = NULL; time_tooltip_format = NULL;
free(time1_timezone); free(time1_timezone);
time1_timezone = NULL; time1_timezone = NULL;
free(time2_timezone); free(time2_timezone);
time2_timezone = NULL; time2_timezone = NULL;
free(time_tooltip_timezone); free(time_tooltip_timezone);
time_tooltip_timezone = NULL; time_tooltip_timezone = NULL;
free(clock_lclick_command); free(clock_lclick_command);
clock_lclick_command = NULL; clock_lclick_command = NULL;
free(clock_mclick_command); free(clock_mclick_command);
clock_mclick_command = NULL; clock_mclick_command = NULL;
free(clock_rclick_command); free(clock_rclick_command);
clock_rclick_command = NULL; clock_rclick_command = NULL;
free(clock_uwheel_command); free(clock_uwheel_command);
clock_uwheel_command = NULL; clock_uwheel_command = NULL;
free(clock_dwheel_command); free(clock_dwheel_command);
clock_dwheel_command = NULL; clock_dwheel_command = NULL;
stop_timeout(clock_timeout); stop_timeout(clock_timeout);
clock_timeout = NULL; clock_timeout = NULL;
} }
void update_clocks_sec(void *arg) void update_clocks_sec(void *arg)
{ {
gettimeofday(&time_clock, 0); gettimeofday(&time_clock, 0);
if (time1_format) { if (time1_format) {
for (int i = 0; i < num_panels; i++) for (int i = 0; i < num_panels; i++)
panels[i].clock.area.resize_needed = 1; panels[i].clock.area.resize_needed = 1;
} }
schedule_panel_redraw(); schedule_panel_redraw();
} }
void update_clocks_min(void *arg) void update_clocks_min(void *arg)
{ {
// remember old_sec because after suspend/hibernate the clock should be updated directly, and not // remember old_sec because after suspend/hibernate the clock should be updated directly, and not
// on next minute change // on next minute change
time_t old_sec = time_clock.tv_sec; time_t old_sec = time_clock.tv_sec;
gettimeofday(&time_clock, 0); gettimeofday(&time_clock, 0);
if (time_clock.tv_sec % 60 == 0 || time_clock.tv_sec - old_sec > 60) { if (time_clock.tv_sec % 60 == 0 || time_clock.tv_sec - old_sec > 60) {
if (time1_format) { if (time1_format) {
for (int i = 0; i < num_panels; i++) for (int i = 0; i < num_panels; i++)
panels[i].clock.area.resize_needed = 1; panels[i].clock.area.resize_needed = 1;
} }
schedule_panel_redraw(); schedule_panel_redraw();
} }
} }
struct tm *clock_gettime_for_tz(const char *timezone) struct tm *clock_gettime_for_tz(const char *timezone)
{ {
if (timezone) { if (timezone) {
const char *old_tz = getenv("TZ"); const char *old_tz = getenv("TZ");
setenv("TZ", timezone, 1); setenv("TZ", timezone, 1);
struct tm *result = localtime(&time_clock.tv_sec); struct tm *result = localtime(&time_clock.tv_sec);
if (old_tz) if (old_tz)
setenv("TZ", old_tz, 1); setenv("TZ", old_tz, 1);
else else
unsetenv("TZ"); unsetenv("TZ");
return result; return result;
} else { } else {
return localtime(&time_clock.tv_sec); return localtime(&time_clock.tv_sec);
} }
} }
gboolean time_format_needs_sec_ticks(char *time_format) gboolean time_format_needs_sec_ticks(char *time_format)
{ {
if (!time_format) if (!time_format)
return FALSE; return FALSE;
if (strchr(time_format, 'S') || strchr(time_format, 'T') || strchr(time_format, 'r')) if (strchr(time_format, 'S') || strchr(time_format, 'T') || strchr(time_format, 'r'))
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
void init_clock() void init_clock()
@@ -167,80 +167,80 @@ void init_clock()
void init_clock_panel(void *p) void init_clock_panel(void *p)
{ {
Panel *panel = (Panel *)p; Panel *panel = (Panel *)p;
Clock *clock = &panel->clock; Clock *clock = &panel->clock;
if (!clock_timeout) { if (!clock_timeout) {
if (time_format_needs_sec_ticks(time1_format) || time_format_needs_sec_ticks(time2_format)) { if (time_format_needs_sec_ticks(time1_format) || time_format_needs_sec_ticks(time2_format)) {
clock_timeout = add_timeout(10, 1000, update_clocks_sec, 0, &clock_timeout); clock_timeout = add_timeout(10, 1000, update_clocks_sec, 0, &clock_timeout);
} else { } else {
clock_timeout = add_timeout(10, 1000, update_clocks_min, 0, &clock_timeout); clock_timeout = add_timeout(10, 1000, update_clocks_min, 0, &clock_timeout);
} }
} }
if (!clock->area.bg) if (!clock->area.bg)
clock->area.bg = &g_array_index(backgrounds, Background, 0); clock->area.bg = &g_array_index(backgrounds, Background, 0);
clock_init_fonts(); clock_init_fonts();
clock->area.parent = p; clock->area.parent = p;
clock->area.panel = p; clock->area.panel = p;
snprintf(clock->area.name, sizeof(clock->area.name), "Clock"); snprintf(clock->area.name, sizeof(clock->area.name), "Clock");
clock->area._is_under_mouse = full_width_area_is_under_mouse; clock->area._is_under_mouse = full_width_area_is_under_mouse;
clock->area.has_mouse_press_effect = clock->area.has_mouse_over_effect = clock->area.has_mouse_press_effect = clock->area.has_mouse_over_effect =
panel_config.mouse_effects && (clock_lclick_command || clock_mclick_command || clock_rclick_command || panel_config.mouse_effects && (clock_lclick_command || clock_mclick_command || clock_rclick_command ||
clock_uwheel_command || clock_dwheel_command); clock_uwheel_command || clock_dwheel_command);
clock->area._draw_foreground = draw_clock; clock->area._draw_foreground = draw_clock;
clock->area.size_mode = LAYOUT_FIXED; clock->area.size_mode = LAYOUT_FIXED;
clock->area._resize = resize_clock; clock->area._resize = resize_clock;
clock->area._compute_desired_size = clock_compute_desired_size; clock->area._compute_desired_size = clock_compute_desired_size;
clock->area._dump_geometry = clock_dump_geometry; clock->area._dump_geometry = clock_dump_geometry;
// check consistency // check consistency
if (!time1_format) if (!time1_format)
return; return;
clock->area.resize_needed = 1; clock->area.resize_needed = 1;
clock->area.on_screen = TRUE; clock->area.on_screen = TRUE;
instantiate_area_gradients(&clock->area); instantiate_area_gradients(&clock->area);
if (time_tooltip_format) { if (time_tooltip_format) {
clock->area._get_tooltip_text = clock_get_tooltip; clock->area._get_tooltip_text = clock_get_tooltip;
strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone)); strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone));
} }
} }
void clock_init_fonts() void clock_init_fonts()
{ {
if (!time1_font_desc) { if (!time1_font_desc) {
time1_font_desc = pango_font_description_from_string(get_default_font()); time1_font_desc = pango_font_description_from_string(get_default_font());
pango_font_description_set_weight(time1_font_desc, PANGO_WEIGHT_BOLD); pango_font_description_set_weight(time1_font_desc, PANGO_WEIGHT_BOLD);
pango_font_description_set_size(time1_font_desc, pango_font_description_get_size(time1_font_desc)); pango_font_description_set_size(time1_font_desc, pango_font_description_get_size(time1_font_desc));
} }
if (!time2_font_desc) { if (!time2_font_desc) {
time2_font_desc = pango_font_description_from_string(get_default_font()); time2_font_desc = pango_font_description_from_string(get_default_font());
pango_font_description_set_size(time2_font_desc, pango_font_description_set_size(time2_font_desc,
pango_font_description_get_size(time2_font_desc) - PANGO_SCALE); pango_font_description_get_size(time2_font_desc) - PANGO_SCALE);
} }
} }
void clock_default_font_changed() void clock_default_font_changed()
{ {
if (!clock_enabled) if (!clock_enabled)
return; return;
if (time1_has_font && time2_has_font) if (time1_has_font && time2_has_font)
return; return;
if (!time1_has_font) { if (!time1_has_font) {
pango_font_description_free(time1_font_desc); pango_font_description_free(time1_font_desc);
time1_font_desc = NULL; time1_font_desc = NULL;
} }
if (!time2_has_font) { if (!time2_has_font) {
pango_font_description_free(time2_font_desc); pango_font_description_free(time2_font_desc);
time2_font_desc = NULL; time2_font_desc = NULL;
} }
clock_init_fonts(); clock_init_fonts();
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
panels[i].clock.area.resize_needed = TRUE; panels[i].clock.area.resize_needed = TRUE;
schedule_redraw(&panels[i].clock.area); schedule_redraw(&panels[i].clock.area);
} }
schedule_panel_redraw(); schedule_panel_redraw();
} }
void clock_compute_text_geometry(Panel *panel, void clock_compute_text_geometry(Panel *panel,
@@ -251,167 +251,167 @@ void clock_compute_text_geometry(Panel *panel,
int *date_height, int *date_height,
int *date_width) int *date_width)
{ {
*date_height = *date_width = 0; *date_height = *date_width = 0;
strftime(buf_time, sizeof(buf_time), time1_format, clock_gettime_for_tz(time1_timezone)); strftime(buf_time, sizeof(buf_time), time1_format, clock_gettime_for_tz(time1_timezone));
get_text_size2(time1_font_desc, get_text_size2(time1_font_desc,
time_height_ink, time_height_ink,
time_height, time_height,
time_width, time_width,
panel->area.height, panel->area.height,
panel->area.width, panel->area.width,
buf_time, buf_time,
strlen(buf_time), strlen(buf_time),
PANGO_WRAP_WORD_CHAR, PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE, PANGO_ELLIPSIZE_NONE,
FALSE); FALSE);
if (time2_format) { if (time2_format) {
strftime(buf_date, sizeof(buf_date), time2_format, clock_gettime_for_tz(time2_timezone)); strftime(buf_date, sizeof(buf_date), time2_format, clock_gettime_for_tz(time2_timezone));
get_text_size2(time2_font_desc, get_text_size2(time2_font_desc,
date_height_ink, date_height_ink,
date_height, date_height,
date_width, date_width,
panel->area.height, panel->area.height,
panel->area.width, panel->area.width,
buf_date, buf_date,
strlen(buf_date), strlen(buf_date),
PANGO_WRAP_WORD_CHAR, PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE, PANGO_ELLIPSIZE_NONE,
FALSE); FALSE);
} }
} }
int clock_compute_desired_size(void *obj) int clock_compute_desired_size(void *obj)
{ {
Clock *clock = (Clock *)obj; Clock *clock = (Clock *)obj;
Panel *panel = (Panel *)clock->area.panel; Panel *panel = (Panel *)clock->area.panel;
int time_height_ink, time_height, time_width, date_height_ink, date_height, date_width; int time_height_ink, time_height, time_width, date_height_ink, date_height, date_width;
clock_compute_text_geometry(panel, clock_compute_text_geometry(panel,
&time_height_ink, &time_height_ink,
&time_height, &time_height,
&time_width, &time_width,
&date_height_ink, &date_height_ink,
&date_height, &date_height,
&date_width); &date_width);
if (panel_horizontal) { if (panel_horizontal) {
int new_size = (time_width > date_width) ? time_width : date_width; int new_size = (time_width > date_width) ? time_width : date_width;
new_size += 2 * clock->area.paddingxlr + left_right_border_width(&clock->area); new_size += 2 * clock->area.paddingxlr + left_right_border_width(&clock->area);
return new_size; return new_size;
} else { } else {
int new_size = time_height + date_height + 2 * clock->area.paddingxlr + top_bottom_border_width(&clock->area); int new_size = time_height + date_height + 2 * clock->area.paddingxlr + top_bottom_border_width(&clock->area);
return new_size; return new_size;
} }
} }
gboolean resize_clock(void *obj) gboolean resize_clock(void *obj)
{ {
Clock *clock = (Clock *)obj; Clock *clock = (Clock *)obj;
Panel *panel = (Panel *)clock->area.panel; Panel *panel = (Panel *)clock->area.panel;
gboolean result = FALSE; gboolean result = FALSE;
schedule_redraw(&clock->area); schedule_redraw(&clock->area);
int time_height_ink, time_height, time_width, date_height_ink, date_height, date_width; int time_height_ink, time_height, time_width, date_height_ink, date_height, date_width;
clock_compute_text_geometry(panel, clock_compute_text_geometry(panel,
&time_height_ink, &time_height_ink,
&time_height, &time_height,
&time_width, &time_width,
&date_height_ink, &date_height_ink,
&date_height, &date_height,
&date_width); &date_width);
int new_size = clock_compute_desired_size(clock); int new_size = clock_compute_desired_size(clock);
if (panel_horizontal) { if (panel_horizontal) {
if (new_size > clock->area.width || new_size < (clock->area.width - 6)) { if (new_size > clock->area.width || new_size < (clock->area.width - 6)) {
// we try to limit the number of resizes // we try to limit the number of resizes
clock->area.width = new_size + 1; clock->area.width = new_size + 1;
clock->time1_posy = (clock->area.height - time_height) / 2; clock->time1_posy = (clock->area.height - time_height) / 2;
if (time2_format) { if (time2_format) {
clock->time1_posy -= (date_height) / 2; clock->time1_posy -= (date_height) / 2;
clock->time2_posy = clock->time1_posy + time_height; clock->time2_posy = clock->time1_posy + time_height;
} }
result = TRUE; result = TRUE;
} }
} else { } else {
if (new_size != clock->area.height) { if (new_size != clock->area.height) {
// we try to limit the number of resizes // we try to limit the number of resizes
clock->area.height = new_size; clock->area.height = new_size;
clock->time1_posy = (clock->area.height - time_height) / 2; clock->time1_posy = (clock->area.height - time_height) / 2;
if (time2_format) { if (time2_format) {
clock->time1_posy -= (date_height) / 2; clock->time1_posy -= (date_height) / 2;
clock->time2_posy = clock->time1_posy + time_height; clock->time2_posy = clock->time1_posy + time_height;
} }
result = TRUE; result = TRUE;
} }
} }
return result; return result;
} }
void draw_clock(void *obj, cairo_t *c) void draw_clock(void *obj, cairo_t *c)
{ {
Clock *clock = obj; Clock *clock = obj;
PangoLayout *layout = pango_cairo_create_layout(c); PangoLayout *layout = pango_cairo_create_layout(c);
pango_layout_set_font_description(layout, time1_font_desc); pango_layout_set_font_description(layout, time1_font_desc);
pango_layout_set_width(layout, clock->area.width * PANGO_SCALE); pango_layout_set_width(layout, clock->area.width * PANGO_SCALE);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_set_text(layout, buf_time, strlen(buf_time)); pango_layout_set_text(layout, buf_time, strlen(buf_time));
cairo_set_source_rgba(c, clock->font.rgb[0], clock->font.rgb[1], clock->font.rgb[2], clock->font.alpha); cairo_set_source_rgba(c, clock->font.rgb[0], clock->font.rgb[1], clock->font.rgb[2], clock->font.alpha);
pango_cairo_update_layout(c, layout); pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, clock->time1_posy, &clock->font, ((Panel *)clock->area.panel)->font_shadow); draw_text(layout, c, 0, clock->time1_posy, &clock->font, ((Panel *)clock->area.panel)->font_shadow);
if (time2_format) { if (time2_format) {
pango_layout_set_font_description(layout, time2_font_desc); pango_layout_set_font_description(layout, time2_font_desc);
pango_layout_set_indent(layout, 0); pango_layout_set_indent(layout, 0);
pango_layout_set_text(layout, buf_date, strlen(buf_date)); pango_layout_set_text(layout, buf_date, strlen(buf_date));
pango_layout_set_width(layout, clock->area.width * PANGO_SCALE); pango_layout_set_width(layout, clock->area.width * PANGO_SCALE);
pango_cairo_update_layout(c, layout); pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, clock->time2_posy, &clock->font, ((Panel *)clock->area.panel)->font_shadow); draw_text(layout, c, 0, clock->time2_posy, &clock->font, ((Panel *)clock->area.panel)->font_shadow);
} }
g_object_unref(layout); g_object_unref(layout);
} }
void clock_dump_geometry(void *obj, int indent) void clock_dump_geometry(void *obj, int indent)
{ {
Clock *clock = (Clock *)obj; Clock *clock = (Clock *)obj;
fprintf(stderr, "%*sText 1: y = %d, text = %s\n", indent, "", clock->time1_posy, buf_time); fprintf(stderr, "%*sText 1: y = %d, text = %s\n", indent, "", clock->time1_posy, buf_time);
if (time2_format) { if (time2_format) {
fprintf(stderr, "%*sText 2: y = %d, text = %s\n", indent, "", clock->time2_posy, buf_date); fprintf(stderr, "%*sText 2: y = %d, text = %s\n", indent, "", clock->time2_posy, buf_date);
} }
} }
char *clock_get_tooltip(void *obj) char *clock_get_tooltip(void *obj)
{ {
strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone)); strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone));
return strdup(buf_tooltip); return strdup(buf_tooltip);
} }
void clock_action(int button) void clock_action(int button)
{ {
char *command = NULL; char *command = NULL;
switch (button) { switch (button) {
case 1: case 1:
command = clock_lclick_command; command = clock_lclick_command;
break; break;
case 2: case 2:
command = clock_mclick_command; command = clock_mclick_command;
break; break;
case 3: case 3:
command = clock_rclick_command; command = clock_rclick_command;
break; break;
case 4: case 4:
command = clock_uwheel_command; command = clock_uwheel_command;
break; break;
case 5: case 5:
command = clock_dwheel_command; command = clock_dwheel_command;
break; break;
} }
tint_exec(command); tint_exec(command);
} }

View File

@@ -14,12 +14,12 @@
#include "area.h" #include "area.h"
typedef struct Clock { typedef struct Clock {
// always start with area // always start with area
Area area; Area area;
Color font; Color font;
int time1_posy; int time1_posy;
int time2_posy; int time2_posy;
} Clock; } Clock;
extern char *time1_format; extern char *time1_format;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -17,78 +17,78 @@
// backend's config and state variables. // backend's config and state variables.
typedef struct ExecpBackend { typedef struct ExecpBackend {
// Config: // Config:
// Command to execute at a specified interval // Command to execute at a specified interval
char *command; char *command;
// Interval in seconds // Interval in seconds
int interval; int interval;
// 1 if first line of output is an icon path // 1 if first line of output is an icon path
gboolean has_icon; gboolean has_icon;
gboolean cache_icon; gboolean cache_icon;
int icon_w; int icon_w;
int icon_h; int icon_h;
char *tooltip; char *tooltip;
gboolean centered; gboolean centered;
gboolean has_font; gboolean has_font;
PangoFontDescription *font_desc; PangoFontDescription *font_desc;
Color font_color; Color font_color;
int continuous; int continuous;
gboolean has_markup; gboolean has_markup;
char *lclick_command; char *lclick_command;
char *mclick_command; char *mclick_command;
char *rclick_command; char *rclick_command;
char *uwheel_command; char *uwheel_command;
char *dwheel_command; char *dwheel_command;
// paddingxlr = horizontal padding left/right // paddingxlr = horizontal padding left/right
// paddingx = horizontal padding between childs // paddingx = horizontal padding between childs
int paddingxlr, paddingx, paddingy; int paddingxlr, paddingx, paddingy;
Background *bg; Background *bg;
// Backend state: // Backend state:
timeout *timer; timeout *timer;
int child_pipe; int child_pipe;
pid_t child; pid_t child;
// Command output buffer // Command output buffer
char *buf_output; char *buf_output;
int buf_length; int buf_length;
int buf_capacity; int buf_capacity;
// Text extracted from the output buffer // Text extracted from the output buffer
char *text; char *text;
// Icon path extracted from the output buffer // Icon path extracted from the output buffer
char *icon_path; char *icon_path;
Imlib_Image icon; Imlib_Image icon;
char tooltip_text[512]; char tooltip_text[512];
// The time the last command was started // The time the last command was started
time_t last_update_start_time; time_t last_update_start_time;
// The time the last output was obtained // The time the last output was obtained
time_t last_update_finish_time; time_t last_update_finish_time;
// The time it took to execute last command // The time it took to execute last command
time_t last_update_duration; time_t last_update_duration;
// List of Execp which are frontends for this backend, one for each panel // List of Execp which are frontends for this backend, one for each panel
GList *instances; GList *instances;
GTree *cmd_pids; GTree *cmd_pids;
} ExecpBackend; } ExecpBackend;
typedef struct ExecpFrontend { typedef struct ExecpFrontend {
// Frontend state: // Frontend state:
int iconx; int iconx;
int icony; int icony;
int textx; int textx;
int texty; int texty;
int textw; int textw;
int texth; int texth;
} ExecpFrontend; } ExecpFrontend;
typedef struct Execp { typedef struct Execp {
Area area; Area area;
// All elements have the backend pointer set. However only backend elements have ownership. // All elements have the backend pointer set. However only backend elements have ownership.
ExecpBackend *backend; ExecpBackend *backend;
// Set only for frontend Execp items. // Set only for frontend Execp items.
ExecpFrontend *frontend; ExecpFrontend *frontend;
} Execp; } Execp;
// Called before the config is read and panel_config/panels are created. // Called before the config is read and panel_config/panels are created.

View File

@@ -34,93 +34,93 @@ int freespace_area_compute_desired_size(void *obj);
void init_freespace_panel(void *p) void init_freespace_panel(void *p)
{ {
Panel *panel = (Panel *)p; Panel *panel = (Panel *)p;
// Make sure this is only done once if there are multiple items // Make sure this is only done once if there are multiple items
if (panel->freespace_list) if (panel->freespace_list)
return; return;
for (size_t k = 0; k < strlen(panel_items_order); k++) { for (size_t k = 0; k < strlen(panel_items_order); k++) {
if (panel_items_order[k] == 'F') { if (panel_items_order[k] == 'F') {
FreeSpace *freespace = (FreeSpace *) calloc(1, sizeof(FreeSpace)); FreeSpace *freespace = (FreeSpace *)calloc(1, sizeof(FreeSpace));
panel->freespace_list = g_list_append(panel->freespace_list, freespace); panel->freespace_list = g_list_append(panel->freespace_list, freespace);
if (!freespace->area.bg) if (!freespace->area.bg)
freespace->area.bg = &g_array_index(backgrounds, Background, 0); freespace->area.bg = &g_array_index(backgrounds, Background, 0);
freespace->area.parent = p; freespace->area.parent = p;
freespace->area.panel = p; freespace->area.panel = p;
snprintf(freespace->area.name, sizeof(freespace->area.name), "Freespace"); snprintf(freespace->area.name, sizeof(freespace->area.name), "Freespace");
freespace->area.size_mode = LAYOUT_FIXED; freespace->area.size_mode = LAYOUT_FIXED;
freespace->area.resize_needed = 1; freespace->area.resize_needed = 1;
freespace->area.on_screen = TRUE; freespace->area.on_screen = TRUE;
freespace->area._resize = resize_freespace; freespace->area._resize = resize_freespace;
freespace->area._compute_desired_size = freespace_area_compute_desired_size; freespace->area._compute_desired_size = freespace_area_compute_desired_size;
} }
} }
} }
void cleanup_freespace(Panel *panel) void cleanup_freespace(Panel *panel)
{ {
if (panel->freespace_list) if (panel->freespace_list)
g_list_free_full(panel->freespace_list, free); g_list_free_full(panel->freespace_list, free);
panel->freespace_list = NULL; panel->freespace_list = NULL;
} }
int freespace_get_max_size(Panel *p) int freespace_get_max_size(Panel *p)
{ {
if (panel_shrink) if (panel_shrink)
return 0; return 0;
// Get space used by every element except the freespace // Get space used by every element except the freespace
int size = 0; int size = 0;
int spacers = 0; int spacers = 0;
for (GList *walk = p->area.children; walk; walk = g_list_next(walk)) { for (GList *walk = p->area.children; walk; walk = g_list_next(walk)) {
Area *a = (Area *)walk->data; Area *a = (Area *)walk->data;
if (!a->on_screen) if (!a->on_screen)
continue; continue;
if (a->_resize == resize_freespace) { if (a->_resize == resize_freespace) {
spacers++; spacers++;
continue; continue;
} }
if (panel_horizontal) if (panel_horizontal)
size += a->width + p->area.paddingx; size += a->width + p->area.paddingx;
else else
size += a->height + p->area.paddingy; size += a->height + p->area.paddingy;
} }
if (panel_horizontal) if (panel_horizontal)
size = p->area.width - size - left_right_border_width(&p->area) - p->area.paddingxlr; size = p->area.width - size - left_right_border_width(&p->area) - p->area.paddingxlr;
else else
size = p->area.height - size - top_bottom_border_width(&p->area) - p->area.paddingxlr; size = p->area.height - size - top_bottom_border_width(&p->area) - p->area.paddingxlr;
return size / spacers; return size / spacers;
} }
int freespace_area_compute_desired_size(void *obj) int freespace_area_compute_desired_size(void *obj)
{ {
FreeSpace *freespace = (FreeSpace *) obj; FreeSpace *freespace = (FreeSpace *)obj;
return freespace_get_max_size((Panel *)freespace->area.panel); return freespace_get_max_size((Panel *)freespace->area.panel);
} }
gboolean resize_freespace(void *obj) gboolean resize_freespace(void *obj)
{ {
FreeSpace *freespace = (FreeSpace *)obj; FreeSpace *freespace = (FreeSpace *)obj;
Panel *panel = (Panel *)freespace->area.panel; Panel *panel = (Panel *)freespace->area.panel;
if (!freespace->area.on_screen) if (!freespace->area.on_screen)
return FALSE; return FALSE;
int old_size = panel_horizontal ? freespace->area.width : freespace->area.height; int old_size = panel_horizontal ? freespace->area.width : freespace->area.height;
int size = freespace_get_max_size(panel); int size = freespace_get_max_size(panel);
if (old_size == size) if (old_size == size)
return FALSE; return FALSE;
if (panel_horizontal) { if (panel_horizontal) {
freespace->area.width = size; freespace->area.width = size;
} else { } else {
freespace->area.height = size; freespace->area.height = size;
} }
schedule_redraw(&freespace->area); schedule_redraw(&freespace->area);
schedule_panel_redraw(); schedule_panel_redraw();
return TRUE; return TRUE;
} }

View File

@@ -9,7 +9,7 @@
#include "area.h" #include "area.h"
typedef struct FreeSpace { typedef struct FreeSpace {
Area area; Area area;
} FreeSpace; } FreeSpace;
struct Panel; struct Panel;

View File

@@ -30,280 +30,280 @@
static gint compare_strings(gconstpointer a, gconstpointer b) static gint compare_strings(gconstpointer a, gconstpointer b)
{ {
return strnatcasecmp((const char *)a, (const char *)b); return strnatcasecmp((const char *)a, (const char *)b);
} }
int parse_dektop_line(char *line, char **key, char **value) int parse_dektop_line(char *line, char **key, char **value)
{ {
char *p; char *p;
int found = 0; int found = 0;
*key = line; *key = line;
for (p = line; *p; p++) { for (p = line; *p; p++) {
if (*p == '=') { if (*p == '=') {
*value = p + 1; *value = p + 1;
*p = 0; *p = 0;
found = 1; found = 1;
break; break;
} }
} }
if (!found) if (!found)
return 0; return 0;
if (found && (strlen(*key) == 0 || strlen(*value) == 0)) if (found && (strlen(*key) == 0 || strlen(*value) == 0))
return 0; return 0;
return 1; return 1;
} }
void expand_exec(DesktopEntry *entry, const char *path) void expand_exec(DesktopEntry *entry, const char *path)
{ {
// Expand % in exec // Expand % in exec
// %i -> --icon Icon // %i -> --icon Icon
// %c -> Name // %c -> Name
// %k -> path // %k -> path
if (entry->exec) { if (entry->exec) {
char *exec2 = calloc(strlen(entry->exec) + (entry->name ? strlen(entry->name) : 1) + char *exec2 = calloc(strlen(entry->exec) + (entry->name ? strlen(entry->name) : 1) +
(entry->icon ? strlen(entry->icon) : 1) + 100, (entry->icon ? strlen(entry->icon) : 1) + 100,
1); 1);
char *p, *q; char *p, *q;
// p will never point to an escaped char // p will never point to an escaped char
for (p = entry->exec, q = exec2; *p; p++, q++) { for (p = entry->exec, q = exec2; *p; p++, q++) {
*q = *p; // Copy *q = *p; // Copy
if (*p == '\\') { if (*p == '\\') {
p++, q++; p++, q++;
// Copy the escaped char // Copy the escaped char
if (*p == '%') // For % we delete the backslash, i.e. write % over it if (*p == '%') // For % we delete the backslash, i.e. write % over it
q--; q--;
*q = *p; *q = *p;
if (!*p) if (!*p)
break; break;
continue; continue;
} }
if (*p == '%') { if (*p == '%') {
p++; p++;
if (!*p) if (!*p)
break; break;
if (*p == 'i' && entry->icon != NULL) { if (*p == 'i' && entry->icon != NULL) {
sprintf(q, "--icon '%s'", entry->icon); sprintf(q, "--icon '%s'", entry->icon);
q += strlen("--icon ''"); q += strlen("--icon ''");
q += strlen(entry->icon); q += strlen(entry->icon);
q--; // To balance the q++ in the for q--; // To balance the q++ in the for
} else if (*p == 'c' && entry->name != NULL) { } else if (*p == 'c' && entry->name != NULL) {
sprintf(q, "'%s'", entry->name); sprintf(q, "'%s'", entry->name);
q += strlen("''"); q += strlen("''");
q += strlen(entry->name); q += strlen(entry->name);
q--; // To balance the q++ in the for q--; // To balance the q++ in the for
} else if (*p == 'c') { } else if (*p == 'c') {
sprintf(q, "'%s'", path); sprintf(q, "'%s'", path);
q += strlen("''"); q += strlen("''");
q += strlen(path); q += strlen(path);
q--; // To balance the q++ in the for q--; // To balance the q++ in the for
} else { } else {
// We don't care about other expansions // We don't care about other expansions
q--; // Delete the last % from q q--; // Delete the last % from q
} }
continue; continue;
} }
} }
*q = '\0'; *q = '\0';
free(entry->exec); free(entry->exec);
entry->exec = exec2; entry->exec = exec2;
} }
} }
gboolean read_desktop_file_full_path(const char *path, DesktopEntry *entry) gboolean read_desktop_file_full_path(const char *path, DesktopEntry *entry)
{ {
entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL; entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL;
entry->hidden_from_menus = FALSE; entry->hidden_from_menus = FALSE;
FILE *fp = fopen(path, "rt"); FILE *fp = fopen(path, "rt");
if (fp == NULL) { if (fp == NULL) {
fprintf(stderr, "Could not open file %s\n", path); fprintf(stderr, "Could not open file %s\n", path);
return FALSE; return FALSE;
} }
const gchar **languages = (const gchar **)g_get_language_names(); const gchar **languages = (const gchar **)g_get_language_names();
// lang_index is the index of the language for the best Name key in the language vector // lang_index is the index of the language for the best Name key in the language vector
// lang_index_default is a constant that encodes the Name key without a language // lang_index_default is a constant that encodes the Name key without a language
int lang_index_default = 1; int lang_index_default = 1;
#define LANG_DBG 0 #define LANG_DBG 0
if (LANG_DBG) if (LANG_DBG)
printf("Languages:"); printf("Languages:");
for (int i = 0; languages[i]; i++) { for (int i = 0; languages[i]; i++) {
lang_index_default = i + 1; lang_index_default = i + 1;
if (LANG_DBG) if (LANG_DBG)
printf(" %s", languages[i]); printf(" %s", languages[i]);
} }
if (LANG_DBG) if (LANG_DBG)
printf("\n"); printf("\n");
// we currently do not know about any Name key at all, so use an invalid index // we currently do not know about any Name key at all, so use an invalid index
int lang_index_name = lang_index_default + 1; int lang_index_name = lang_index_default + 1;
int lang_index_generic_name = lang_index_default + 1; int lang_index_generic_name = lang_index_default + 1;
gboolean inside_desktop_entry = 0; gboolean inside_desktop_entry = 0;
char *line = NULL; char *line = NULL;
size_t line_size; size_t line_size;
while (getline(&line, &line_size, fp) >= 0) { while (getline(&line, &line_size, fp) >= 0) {
int len = strlen(line); int len = strlen(line);
if (len == 0) if (len == 0)
continue; continue;
if (line[len - 1] == '\n') if (line[len - 1] == '\n')
line[len - 1] = '\0'; line[len - 1] = '\0';
if (line[0] == '[') { if (line[0] == '[') {
inside_desktop_entry = (strcmp(line, "[Desktop Entry]") == 0); inside_desktop_entry = (strcmp(line, "[Desktop Entry]") == 0);
} }
char *key, *value; char *key, *value;
if (inside_desktop_entry && parse_dektop_line(line, &key, &value)) { if (inside_desktop_entry && parse_dektop_line(line, &key, &value)) {
if (strstr(key, "Name") == key) { if (strstr(key, "Name") == key) {
if (strcmp(key, "Name") == 0 && lang_index_name > lang_index_default) { if (strcmp(key, "Name") == 0 && lang_index_name > lang_index_default) {
entry->name = strdup(value); entry->name = strdup(value);
lang_index_name = lang_index_default; lang_index_name = lang_index_default;
} else { } else {
for (int i = 0; languages[i] && i < lang_index_name; i++) { for (int i = 0; languages[i] && i < lang_index_name; i++) {
gchar *localized_key = g_strdup_printf("Name[%s]", languages[i]); gchar *localized_key = g_strdup_printf("Name[%s]", languages[i]);
if (strcmp(key, localized_key) == 0) { if (strcmp(key, localized_key) == 0) {
if (entry->name) if (entry->name)
free(entry->name); free(entry->name);
entry->name = strdup(value); entry->name = strdup(value);
lang_index_name = i; lang_index_name = i;
} }
g_free(localized_key); g_free(localized_key);
} }
} }
} else if (strstr(key, "GenericName") == key) { } else if (strstr(key, "GenericName") == key) {
if (strcmp(key, "GenericName") == 0 && lang_index_generic_name > lang_index_default) { if (strcmp(key, "GenericName") == 0 && lang_index_generic_name > lang_index_default) {
entry->generic_name = strdup(value); entry->generic_name = strdup(value);
lang_index_generic_name = lang_index_default; lang_index_generic_name = lang_index_default;
} else { } else {
for (int i = 0; languages[i] && i < lang_index_generic_name; i++) { for (int i = 0; languages[i] && i < lang_index_generic_name; i++) {
gchar *localized_key = g_strdup_printf("GenericName[%s]", languages[i]); gchar *localized_key = g_strdup_printf("GenericName[%s]", languages[i]);
if (strcmp(key, localized_key) == 0) { if (strcmp(key, localized_key) == 0) {
if (entry->generic_name) if (entry->generic_name)
free(entry->generic_name); free(entry->generic_name);
entry->generic_name = strdup(value); entry->generic_name = strdup(value);
lang_index_generic_name = i; lang_index_generic_name = i;
} }
g_free(localized_key); g_free(localized_key);
} }
} }
} else if (!entry->exec && strcmp(key, "Exec") == 0) { } else if (!entry->exec && strcmp(key, "Exec") == 0) {
entry->exec = strdup(value); entry->exec = strdup(value);
} else if (!entry->cwd && strcmp(key, "Path") == 0) { } else if (!entry->cwd && strcmp(key, "Path") == 0) {
entry->cwd = strdup(value); entry->cwd = strdup(value);
} else if (!entry->icon && strcmp(key, "Icon") == 0) { } else if (!entry->icon && strcmp(key, "Icon") == 0) {
entry->icon = strdup(value); entry->icon = strdup(value);
} else if (strcmp(key, "NoDisplay") == 0) { } else if (strcmp(key, "NoDisplay") == 0) {
entry->hidden_from_menus = strcasecmp(value, "true") == 0; entry->hidden_from_menus = strcasecmp(value, "true") == 0;
} }
} }
} }
fclose(fp); fclose(fp);
// From this point: // From this point:
// entry->name, entry->generic_name, entry->icon, entry->exec will never be empty strings (can be NULL though) // entry->name, entry->generic_name, entry->icon, entry->exec will never be empty strings (can be NULL though)
expand_exec(entry, entry->path); expand_exec(entry, entry->path);
free(line); free(line);
return entry->exec != NULL; return entry->exec != NULL;
} }
gboolean read_desktop_file_from_dir(const char *path, const char *file_name, DesktopEntry *entry) gboolean read_desktop_file_from_dir(const char *path, const char *file_name, DesktopEntry *entry)
{ {
gchar *full_path = g_build_filename(path, file_name, NULL); gchar *full_path = g_build_filename(path, file_name, NULL);
if (read_desktop_file_full_path(full_path, entry)) { if (read_desktop_file_full_path(full_path, entry)) {
g_free(full_path); g_free(full_path);
return TRUE; return TRUE;
} }
free_and_null(entry->name); free_and_null(entry->name);
free_and_null(entry->generic_name); free_and_null(entry->generic_name);
free_and_null(entry->icon); free_and_null(entry->icon);
free_and_null(entry->exec); free_and_null(entry->exec);
free_and_null(entry->cwd); free_and_null(entry->cwd);
GList *subdirs = NULL; GList *subdirs = NULL;
GDir *d = g_dir_open(path, 0, NULL); GDir *d = g_dir_open(path, 0, NULL);
if (d) { if (d) {
const gchar *name; const gchar *name;
while ((name = g_dir_read_name(d))) { while ((name = g_dir_read_name(d))) {
gchar *child = g_build_filename(path, name, NULL); gchar *child = g_build_filename(path, name, NULL);
if (g_file_test(child, G_FILE_TEST_IS_DIR)) { if (g_file_test(child, G_FILE_TEST_IS_DIR)) {
subdirs = g_list_append(subdirs, child); subdirs = g_list_append(subdirs, child);
} else { } else {
g_free(child); g_free(child);
} }
} }
g_dir_close(d); g_dir_close(d);
} }
subdirs = g_list_sort(subdirs, compare_strings); subdirs = g_list_sort(subdirs, compare_strings);
gboolean found = FALSE; gboolean found = FALSE;
for (GList *l = subdirs; l; l = g_list_next(l)) { for (GList *l = subdirs; l; l = g_list_next(l)) {
if (read_desktop_file_from_dir(l->data, file_name, entry)) { if (read_desktop_file_from_dir(l->data, file_name, entry)) {
found = TRUE; found = TRUE;
break; break;
} }
} }
for (GList *l = subdirs; l; l = g_list_next(l)) { for (GList *l = subdirs; l; l = g_list_next(l)) {
g_free(l->data); g_free(l->data);
} }
g_list_free(subdirs); g_list_free(subdirs);
g_free(full_path); g_free(full_path);
return found; return found;
} }
gboolean read_desktop_file(const char *path, DesktopEntry *entry) gboolean read_desktop_file(const char *path, DesktopEntry *entry)
{ {
entry->path = strdup(path); entry->path = strdup(path);
entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL; entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL;
if (strchr(path, '/')) if (strchr(path, '/'))
return read_desktop_file_full_path(path, entry); return read_desktop_file_full_path(path, entry);
for (const GSList *location = get_apps_locations(); location; location = g_slist_next(location)) { for (const GSList *location = get_apps_locations(); location; location = g_slist_next(location)) {
if (read_desktop_file_from_dir(location->data, path, entry)) if (read_desktop_file_from_dir(location->data, path, entry))
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
void free_desktop_entry(DesktopEntry *entry) void free_desktop_entry(DesktopEntry *entry)
{ {
free_and_null(entry->name); free_and_null(entry->name);
free_and_null(entry->generic_name); free_and_null(entry->generic_name);
free_and_null(entry->icon); free_and_null(entry->icon);
free_and_null(entry->exec); free_and_null(entry->exec);
free_and_null(entry->path); free_and_null(entry->path);
free_and_null(entry->cwd); free_and_null(entry->cwd);
} }
void test_read_desktop_file() void test_read_desktop_file()
{ {
fprintf(stdout, "\033[1;33m"); fprintf(stdout, "\033[1;33m");
DesktopEntry entry; DesktopEntry entry;
read_desktop_file("/usr/share/applications/firefox.desktop", &entry); read_desktop_file("/usr/share/applications/firefox.desktop", &entry);
printf("Name:%s GenericName:%s Icon:%s Exec:%s\n", entry.name, entry.generic_name, entry.icon, entry.exec); printf("Name:%s GenericName:%s Icon:%s Exec:%s\n", entry.name, entry.generic_name, entry.icon, entry.exec);
fprintf(stdout, "\033[0m"); fprintf(stdout, "\033[0m");
} }
GSList *apps_locations = NULL; GSList *apps_locations = NULL;
// Do not free the result. // Do not free the result.
const GSList *get_apps_locations() const GSList *get_apps_locations()
{ {
if (apps_locations) if (apps_locations)
return apps_locations; return apps_locations;
apps_locations = load_locations_from_env(apps_locations, "XDG_DATA_HOME", "applications", NULL); apps_locations = load_locations_from_env(apps_locations, "XDG_DATA_HOME", "applications", NULL);
apps_locations = apps_locations =
g_slist_append(apps_locations, g_build_filename(g_get_home_dir(), ".local/share/applications", NULL)); g_slist_append(apps_locations, g_build_filename(g_get_home_dir(), ".local/share/applications", NULL));
apps_locations = load_locations_from_env(apps_locations, "XDG_DATA_DIRS", "applications", NULL); apps_locations = load_locations_from_env(apps_locations, "XDG_DATA_DIRS", "applications", NULL);
apps_locations = g_slist_append(apps_locations, g_strdup("/usr/local/share/applications")); apps_locations = g_slist_append(apps_locations, g_strdup("/usr/local/share/applications"));
apps_locations = g_slist_append(apps_locations, g_strdup("/usr/share/applications")); apps_locations = g_slist_append(apps_locations, g_strdup("/usr/share/applications"));
apps_locations = g_slist_append(apps_locations, g_strdup("/opt/share/applications")); apps_locations = g_slist_append(apps_locations, g_strdup("/opt/share/applications"));
apps_locations = slist_remove_duplicates(apps_locations, g_str_equal, g_free); apps_locations = slist_remove_duplicates(apps_locations, g_str_equal, g_free);
return apps_locations; return apps_locations;
} }

View File

@@ -10,13 +10,13 @@
#include <glib.h> #include <glib.h>
typedef struct DesktopEntry { typedef struct DesktopEntry {
char *name; char *name;
char *generic_name; char *generic_name;
char *exec; char *exec;
char *icon; char *icon;
char *path; char *path;
char *cwd; char *cwd;
gboolean hidden_from_menus; gboolean hidden_from_menus;
} DesktopEntry; } DesktopEntry;
// Parses a line of the form "key = value". Modifies the line. // Parses a line of the form "key = value". Modifies the line.

File diff suppressed because it is too large Load Diff

View File

@@ -10,27 +10,27 @@
#include "cache.h" #include "cache.h"
typedef struct IconThemeWrapper { typedef struct IconThemeWrapper {
// The icon theme name for which this wrapper was created // The icon theme name for which this wrapper was created
char *icon_theme_name; char *icon_theme_name;
// List of IconTheme* // List of IconTheme*
GSList *themes; GSList *themes;
// Themes are loaded lazily when needed. // Themes are loaded lazily when needed.
gboolean _themes_loaded; gboolean _themes_loaded;
// List of IconTheme* // List of IconTheme*
GSList *themes_fallback; GSList *themes_fallback;
// Fallback themes are loaded lazily when needed. // Fallback themes are loaded lazily when needed.
gboolean _fallback_loaded; gboolean _fallback_loaded;
Cache _cache; Cache _cache;
// List of icon theme names that have been queued for loading. // List of icon theme names that have been queued for loading.
// Used to avoid loading the same theme twice, and to avoid cycles. // Used to avoid loading the same theme twice, and to avoid cycles.
GSList *_queued; GSList *_queued;
} IconThemeWrapper; } IconThemeWrapper;
typedef struct IconTheme { typedef struct IconTheme {
char *name; char *name;
char *description; char *description;
GSList *list_inherits; // each item is a char* (theme name) GSList *list_inherits; // each item is a char* (theme name)
GSList *list_directories; // each item is an IconThemeDir* GSList *list_directories; // each item is an IconThemeDir*
} IconTheme; } IconTheme;
// Parses a line of the form "key = value". Modifies the line. // Parses a line of the form "key = value". Modifies the line.

View File

@@ -67,18 +67,18 @@ int launcher_compute_desired_size(void *obj);
void default_launcher() void default_launcher()
{ {
launcher_enabled = 0; launcher_enabled = 0;
launcher_max_icon_size = 0; launcher_max_icon_size = 0;
launcher_tooltip_enabled = 0; launcher_tooltip_enabled = 0;
launcher_alpha = 100; launcher_alpha = 100;
launcher_saturation = 0; launcher_saturation = 0;
launcher_brightness = 0; launcher_brightness = 0;
icon_theme_name_config = NULL; icon_theme_name_config = NULL;
icon_theme_name_xsettings = NULL; icon_theme_name_xsettings = NULL;
launcher_icon_theme_override = 0; launcher_icon_theme_override = 0;
startup_notifications = 0; startup_notifications = 0;
launcher_icon_bg = NULL; launcher_icon_bg = NULL;
launcher_icon_gradients = NULL; launcher_icon_gradients = NULL;
} }
void init_launcher() void init_launcher()
@@ -87,97 +87,97 @@ void init_launcher()
void init_launcher_panel(void *p) void init_launcher_panel(void *p)
{ {
Panel *panel = (Panel *)p; Panel *panel = (Panel *)p;
Launcher *launcher = &panel->launcher; Launcher *launcher = &panel->launcher;
launcher->area.parent = p; launcher->area.parent = p;
launcher->area.panel = p; launcher->area.panel = p;
snprintf(launcher->area.name, sizeof(launcher->area.name), "Launcher"); snprintf(launcher->area.name, sizeof(launcher->area.name), "Launcher");
launcher->area._draw_foreground = NULL; launcher->area._draw_foreground = NULL;
launcher->area.size_mode = LAYOUT_FIXED; launcher->area.size_mode = LAYOUT_FIXED;
launcher->area._resize = resize_launcher; launcher->area._resize = resize_launcher;
launcher->area._compute_desired_size = launcher_compute_desired_size; launcher->area._compute_desired_size = launcher_compute_desired_size;
launcher->area.resize_needed = 1; launcher->area.resize_needed = 1;
schedule_redraw(&launcher->area); schedule_redraw(&launcher->area);
if (!launcher->area.bg) if (!launcher->area.bg)
launcher->area.bg = &g_array_index(backgrounds, Background, 0); launcher->area.bg = &g_array_index(backgrounds, Background, 0);
if (!launcher_icon_bg) if (!launcher_icon_bg)
launcher_icon_bg = &g_array_index(backgrounds, Background, 0); launcher_icon_bg = &g_array_index(backgrounds, Background, 0);
// check consistency // check consistency
if (launcher->list_apps == NULL) if (launcher->list_apps == NULL)
return; return;
// This will be recomputed on resize, we just initialize to a non-zero value // This will be recomputed on resize, we just initialize to a non-zero value
launcher->icon_size = launcher_max_icon_size > 0 ? launcher_max_icon_size : 24; launcher->icon_size = launcher_max_icon_size > 0 ? launcher_max_icon_size : 24;
launcher->area.on_screen = TRUE; launcher->area.on_screen = TRUE;
schedule_panel_redraw(); schedule_panel_redraw();
instantiate_area_gradients(&launcher->area); instantiate_area_gradients(&launcher->area);
load_icon_themes(); load_icon_themes();
launcher_load_icons(launcher); launcher_load_icons(launcher);
} }
void free_icon_themes() void free_icon_themes()
{ {
free_themes(icon_theme_wrapper); free_themes(icon_theme_wrapper);
icon_theme_wrapper = NULL; icon_theme_wrapper = NULL;
} }
void cleanup_launcher() void cleanup_launcher()
{ {
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
Panel *panel = &panels[i]; Panel *panel = &panels[i];
Launcher *launcher = &panel->launcher; Launcher *launcher = &panel->launcher;
cleanup_launcher_theme(launcher); cleanup_launcher_theme(launcher);
} }
for (GSList *l = panel_config.launcher.list_apps; l; l = l->next) { for (GSList *l = panel_config.launcher.list_apps; l; l = l->next) {
free(l->data); free(l->data);
} }
g_slist_free(panel_config.launcher.list_apps); g_slist_free(panel_config.launcher.list_apps);
panel_config.launcher.list_apps = NULL; panel_config.launcher.list_apps = NULL;
free(icon_theme_name_config); free(icon_theme_name_config);
icon_theme_name_config = NULL; icon_theme_name_config = NULL;
free(icon_theme_name_xsettings); free(icon_theme_name_xsettings);
icon_theme_name_xsettings = NULL; icon_theme_name_xsettings = NULL;
launcher_enabled = FALSE; launcher_enabled = FALSE;
} }
void cleanup_launcher_theme(Launcher *launcher) void cleanup_launcher_theme(Launcher *launcher)
{ {
free_area(&launcher->area); free_area(&launcher->area);
for (GSList *l = launcher->list_icons; l; l = l->next) { for (GSList *l = launcher->list_icons; l; l = l->next) {
LauncherIcon *launcherIcon = (LauncherIcon *)l->data; LauncherIcon *launcherIcon = (LauncherIcon *)l->data;
if (launcherIcon) { if (launcherIcon) {
free_icon(launcherIcon->image); free_icon(launcherIcon->image);
free_icon(launcherIcon->image_hover); free_icon(launcherIcon->image_hover);
free_icon(launcherIcon->image_pressed); free_icon(launcherIcon->image_pressed);
free(launcherIcon->icon_name); free(launcherIcon->icon_name);
free(launcherIcon->icon_path); free(launcherIcon->icon_path);
free(launcherIcon->cmd); free(launcherIcon->cmd);
g_free(launcherIcon->icon_tooltip); g_free(launcherIcon->icon_tooltip);
free(launcherIcon->config_path); free(launcherIcon->config_path);
} }
free(launcherIcon); free(launcherIcon);
} }
g_slist_free(launcher->list_icons); g_slist_free(launcher->list_icons);
launcher->list_icons = NULL; launcher->list_icons = NULL;
} }
int launcher_compute_icon_size(Launcher *launcher) int launcher_compute_icon_size(Launcher *launcher)
{ {
int icon_size = panel_horizontal ? launcher->area.height : launcher->area.width; int icon_size = panel_horizontal ? launcher->area.height : launcher->area.width;
icon_size = icon_size - MAX(left_right_border_width(&launcher->area), top_bottom_border_width(&launcher->area)) - icon_size = icon_size - MAX(left_right_border_width(&launcher->area), top_bottom_border_width(&launcher->area)) -
(2 * launcher->area.paddingy); (2 * launcher->area.paddingy);
if (launcher_max_icon_size > 0 && icon_size > launcher_max_icon_size) if (launcher_max_icon_size > 0 && icon_size > launcher_max_icon_size)
icon_size = launcher_max_icon_size; icon_size = launcher_max_icon_size;
return icon_size; return icon_size;
} }
void launcher_compute_geometry(Launcher *launcher, void launcher_compute_geometry(Launcher *launcher,
@@ -187,438 +187,436 @@ void launcher_compute_geometry(Launcher *launcher,
int *icons_per_row, int *icons_per_row,
int *margin) int *margin)
{ {
int count = 0; int count = 0;
for (GSList *l = launcher->list_icons; l; l = l->next) { for (GSList *l = launcher->list_icons; l; l = l->next) {
LauncherIcon *launcherIcon = (LauncherIcon *)l->data; LauncherIcon *launcherIcon = (LauncherIcon *)l->data;
if (launcherIcon->area.on_screen) if (launcherIcon->area.on_screen)
count++; count++;
} }
*icon_size = launcher_compute_icon_size(launcher); *icon_size = launcher_compute_icon_size(launcher);
*icons_per_column = 1; *icons_per_column = 1;
*icons_per_row = 1; *icons_per_row = 1;
*margin = 0; *margin = 0;
if (panel_horizontal) { if (panel_horizontal) {
if (!count) { if (!count) {
*size = 0; *size = 0;
} else { } else {
int height = launcher->area.height - top_bottom_border_width(&launcher->area) - 2 * launcher->area.paddingy; int height = launcher->area.height - top_bottom_border_width(&launcher->area) - 2 * launcher->area.paddingy;
// here icons_per_column always higher than 0 // here icons_per_column always higher than 0
*icons_per_column = (height + launcher->area.paddingx) / (*icon_size + launcher->area.paddingx); *icons_per_column = (height + launcher->area.paddingx) / (*icon_size + launcher->area.paddingx);
*margin = height - (*icons_per_column - 1) * (*icon_size + launcher->area.paddingx) - *icon_size; *margin = height - (*icons_per_column - 1) * (*icon_size + launcher->area.paddingx) - *icon_size;
*icons_per_row = count / *icons_per_column + (count % *icons_per_column != 0); *icons_per_row = count / *icons_per_column + (count % *icons_per_column != 0);
*size = left_right_border_width(&launcher->area) + 2 * launcher->area.paddingxlr + *size = left_right_border_width(&launcher->area) + 2 * launcher->area.paddingxlr +
(*icon_size * *icons_per_row) + ((*icons_per_row - 1) * launcher->area.paddingx); (*icon_size * *icons_per_row) + ((*icons_per_row - 1) * launcher->area.paddingx);
} }
} else { } else {
if (!count) { if (!count) {
*size = 0; *size = 0;
} else { } else {
int width = launcher->area.width - top_bottom_border_width(&launcher->area) - 2 * launcher->area.paddingy; int width = launcher->area.width - top_bottom_border_width(&launcher->area) - 2 * launcher->area.paddingy;
// here icons_per_row always higher than 0 // here icons_per_row always higher than 0
*icons_per_row = (width + launcher->area.paddingx) / (*icon_size + launcher->area.paddingx); *icons_per_row = (width + launcher->area.paddingx) / (*icon_size + launcher->area.paddingx);
*margin = width - (*icons_per_row - 1) * (*icon_size + launcher->area.paddingx) - *icon_size; *margin = width - (*icons_per_row - 1) * (*icon_size + launcher->area.paddingx) - *icon_size;
*icons_per_column = count / *icons_per_row + (count % *icons_per_row != 0); *icons_per_column = count / *icons_per_row + (count % *icons_per_row != 0);
*size = top_bottom_border_width(&launcher->area) + 2 * launcher->area.paddingxlr + *size = top_bottom_border_width(&launcher->area) + 2 * launcher->area.paddingxlr +
(*icon_size * *icons_per_column) + ((*icons_per_column - 1) * launcher->area.paddingx); (*icon_size * *icons_per_column) + ((*icons_per_column - 1) * launcher->area.paddingx);
} }
} }
} }
int launcher_compute_desired_size(void *obj) int launcher_compute_desired_size(void *obj)
{ {
Launcher *launcher = (Launcher *)obj; Launcher *launcher = (Launcher *)obj;
int size, icon_size, icons_per_column, icons_per_row, margin; int size, icon_size, icons_per_column, icons_per_row, margin;
launcher_compute_geometry(launcher, &size, &icon_size, &icons_per_column, &icons_per_row, &margin); launcher_compute_geometry(launcher, &size, &icon_size, &icons_per_column, &icons_per_row, &margin);
return size; return size;
} }
gboolean resize_launcher(void *obj) gboolean resize_launcher(void *obj)
{ {
Launcher *launcher = (Launcher *)obj; Launcher *launcher = (Launcher *)obj;
int size, icons_per_column, icons_per_row, margin; int size, icons_per_column, icons_per_row, margin;
launcher_compute_geometry(launcher, &size, &launcher->icon_size, &icons_per_column, &icons_per_row, &margin); launcher_compute_geometry(launcher, &size, &launcher->icon_size, &icons_per_column, &icons_per_row, &margin);
// Resize icons if necessary // Resize icons if necessary
for (GSList *l = launcher->list_icons; l; l = l->next) { for (GSList *l = launcher->list_icons; l; l = l->next) {
LauncherIcon *launcherIcon = (LauncherIcon *)l->data; LauncherIcon *launcherIcon = (LauncherIcon *)l->data;
if (launcherIcon->icon_size != launcher->icon_size || !launcherIcon->image) { if (launcherIcon->icon_size != launcher->icon_size || !launcherIcon->image) {
launcherIcon->icon_size = launcher->icon_size; launcherIcon->icon_size = launcher->icon_size;
launcherIcon->area.width = launcherIcon->icon_size; launcherIcon->area.width = launcherIcon->icon_size;
launcherIcon->area.height = launcherIcon->icon_size; launcherIcon->area.height = launcherIcon->icon_size;
launcher_reload_icon_image(launcher, launcherIcon); launcher_reload_icon_image(launcher, launcherIcon);
} }
} }
save_icon_cache(icon_theme_wrapper); save_icon_cache(icon_theme_wrapper);
int count = 0; int count = 0;
gboolean needs_repositioning = FALSE; gboolean needs_repositioning = FALSE;
for (GSList *l = launcher->list_icons; l; l = l->next) { for (GSList *l = launcher->list_icons; l; l = l->next) {
LauncherIcon *launcherIcon = (LauncherIcon *)l->data; LauncherIcon *launcherIcon = (LauncherIcon *)l->data;
if (launcherIcon->area.on_screen) { if (launcherIcon->area.on_screen) {
count++; count++;
if (launcherIcon->area.posx < 0 || launcherIcon->area.posy < 0) if (launcherIcon->area.posx < 0 || launcherIcon->area.posy < 0)
needs_repositioning = TRUE; needs_repositioning = TRUE;
} }
} }
if (!needs_repositioning) { if (!needs_repositioning) {
if (panel_horizontal) { if (panel_horizontal) {
if (launcher->area.width == size) if (launcher->area.width == size)
return FALSE; return FALSE;
launcher->area.width = size; launcher->area.width = size;
} else { } else {
if (launcher->area.height == size) if (launcher->area.height == size)
return FALSE; return FALSE;
launcher->area.height = size; launcher->area.height = size;
} }
} }
int posx, posy; int posx, posy;
int start; int start;
if (panel_horizontal) { if (panel_horizontal) {
posy = start = top_border_width(&launcher->area) + launcher->area.paddingy + margin / 2; posy = start = top_border_width(&launcher->area) + launcher->area.paddingy + margin / 2;
posx = left_border_width(&launcher->area) + launcher->area.paddingxlr; posx = left_border_width(&launcher->area) + launcher->area.paddingxlr;
} else { } else {
posx = start = left_border_width(&launcher->area) + launcher->area.paddingy + margin / 2; posx = start = left_border_width(&launcher->area) + launcher->area.paddingy + margin / 2;
posy = top_border_width(&launcher->area) + launcher->area.paddingxlr; posy = top_border_width(&launcher->area) + launcher->area.paddingxlr;
} }
int i = 0; int i = 0;
for (GSList *l = launcher->list_icons; l; l = l->next) { for (GSList *l = launcher->list_icons; l; l = l->next) {
LauncherIcon *launcherIcon = (LauncherIcon *)l->data; LauncherIcon *launcherIcon = (LauncherIcon *)l->data;
if (!launcherIcon->area.on_screen) if (!launcherIcon->area.on_screen)
continue; continue;
i++; i++;
launcherIcon->y = posy; launcherIcon->y = posy;
launcherIcon->x = posx; launcherIcon->x = posx;
launcher_icon_on_change_layout(launcherIcon); launcher_icon_on_change_layout(launcherIcon);
// printf("launcher %d : %d,%d\n", i, posx, posy); // printf("launcher %d : %d,%d\n", i, posx, posy);
if (panel_horizontal) { if (panel_horizontal) {
if (i % icons_per_column) { if (i % icons_per_column) {
posy += launcher->icon_size + launcher->area.paddingx; posy += launcher->icon_size + launcher->area.paddingx;
} else { } else {
posy = start; posy = start;
posx += (launcher->icon_size + launcher->area.paddingx); posx += (launcher->icon_size + launcher->area.paddingx);
} }
} else { } else {
if (i % icons_per_row) { if (i % icons_per_row) {
posx += launcher->icon_size + launcher->area.paddingx; posx += launcher->icon_size + launcher->area.paddingx;
} else { } else {
posx = start; posx = start;
posy += (launcher->icon_size + launcher->area.paddingx); posy += (launcher->icon_size + launcher->area.paddingx);
} }
} }
} }
if ((panel_horizontal && icons_per_column == 1) || (!panel_horizontal && icons_per_row == 1)) { if ((panel_horizontal && icons_per_column == 1) || (!panel_horizontal && icons_per_row == 1)) {
launcher->area._is_under_mouse = full_width_area_is_under_mouse; launcher->area._is_under_mouse = full_width_area_is_under_mouse;
for (GSList *l = launcher->list_icons; l; l = l->next) for (GSList *l = launcher->list_icons; l; l = l->next)
((LauncherIcon *)l->data)->area._is_under_mouse = full_width_area_is_under_mouse; ((LauncherIcon *)l->data)->area._is_under_mouse = full_width_area_is_under_mouse;
} else { } else {
launcher->area._is_under_mouse = NULL; launcher->area._is_under_mouse = NULL;
for (GSList *l = launcher->list_icons; l; l = l->next) for (GSList *l = launcher->list_icons; l; l = l->next)
((LauncherIcon *)l->data)->area._is_under_mouse = NULL; ((LauncherIcon *)l->data)->area._is_under_mouse = NULL;
} }
return TRUE; return TRUE;
} }
// Here we override the default layout of the icons; normally Area layouts its children // Here we override the default layout of the icons; normally Area layouts its children
// in a stack; we need to layout them in a kind of table // in a stack; we need to layout them in a kind of table
void launcher_icon_on_change_layout(void *obj) void launcher_icon_on_change_layout(void *obj)
{ {
LauncherIcon *launcherIcon = (LauncherIcon *)obj; LauncherIcon *launcherIcon = (LauncherIcon *)obj;
launcherIcon->area.posy = ((Area *)launcherIcon->area.parent)->posy + launcherIcon->y; launcherIcon->area.posy = ((Area *)launcherIcon->area.parent)->posy + launcherIcon->y;
launcherIcon->area.posx = ((Area *)launcherIcon->area.parent)->posx + launcherIcon->x; launcherIcon->area.posx = ((Area *)launcherIcon->area.parent)->posx + launcherIcon->x;
launcherIcon->area.width = launcherIcon->icon_size; launcherIcon->area.width = launcherIcon->icon_size;
launcherIcon->area.height = launcherIcon->icon_size; launcherIcon->area.height = launcherIcon->icon_size;
} }
int launcher_icon_compute_desired_size(void *obj) int launcher_icon_compute_desired_size(void *obj)
{ {
LauncherIcon *icon = (LauncherIcon *)obj; LauncherIcon *icon = (LauncherIcon *)obj;
return icon->icon_size; return icon->icon_size;
} }
char *launcher_icon_get_tooltip_text(void *obj) char *launcher_icon_get_tooltip_text(void *obj)
{ {
LauncherIcon *launcherIcon = (LauncherIcon *)obj; LauncherIcon *launcherIcon = (LauncherIcon *)obj;
return strdup(launcherIcon->icon_tooltip); return strdup(launcherIcon->icon_tooltip);
} }
void draw_launcher_icon(void *obj, cairo_t *c) void draw_launcher_icon(void *obj, cairo_t *c)
{ {
LauncherIcon *launcherIcon = (LauncherIcon *)obj; LauncherIcon *launcherIcon = (LauncherIcon *)obj;
Imlib_Image image; Imlib_Image image;
// Render // Render
if (panel_config.mouse_effects) { if (panel_config.mouse_effects) {
if (launcherIcon->area.mouse_state == MOUSE_OVER) if (launcherIcon->area.mouse_state == MOUSE_OVER)
image = launcherIcon->image_hover ? launcherIcon->image_hover : launcherIcon->image; image = launcherIcon->image_hover ? launcherIcon->image_hover : launcherIcon->image;
else if (launcherIcon->area.mouse_state == MOUSE_DOWN) else if (launcherIcon->area.mouse_state == MOUSE_DOWN)
image = launcherIcon->image_pressed ? launcherIcon->image_pressed : launcherIcon->image; image = launcherIcon->image_pressed ? launcherIcon->image_pressed : launcherIcon->image;
else else
image = launcherIcon->image; image = launcherIcon->image;
} else { } else {
image = launcherIcon->image; image = launcherIcon->image;
} }
imlib_context_set_image(image); imlib_context_set_image(image);
render_image(launcherIcon->area.pix, 0, 0); render_image(launcherIcon->area.pix, 0, 0);
} }
void launcher_icon_dump_geometry(void *obj, int indent) void launcher_icon_dump_geometry(void *obj, int indent)
{ {
LauncherIcon *launcherIcon = (LauncherIcon *)obj; LauncherIcon *launcherIcon = (LauncherIcon *)obj;
fprintf(stderr, "%*sIcon: w = h = %d, name = %s\n", indent, "", launcherIcon->icon_size, launcherIcon->icon_name); fprintf(stderr, "%*sIcon: w = h = %d, name = %s\n", indent, "", launcherIcon->icon_size, launcherIcon->icon_name);
} }
Imlib_Image scale_icon(Imlib_Image original, int icon_size) Imlib_Image scale_icon(Imlib_Image original, int icon_size)
{ {
Imlib_Image icon_scaled; Imlib_Image icon_scaled;
if (original) { if (original) {
imlib_context_set_image(original); imlib_context_set_image(original);
icon_scaled = imlib_create_cropped_scaled_image(0, icon_scaled = imlib_create_cropped_scaled_image(0,
0, 0,
imlib_image_get_width(), imlib_image_get_width(),
imlib_image_get_height(), imlib_image_get_height(),
icon_size, icon_size,
icon_size); icon_size);
imlib_context_set_image(icon_scaled); imlib_context_set_image(icon_scaled);
imlib_image_set_has_alpha(1); imlib_image_set_has_alpha(1);
DATA32 *data = imlib_image_get_data(); DATA32 *data = imlib_image_get_data();
adjust_asb(data, adjust_asb(data,
icon_size, icon_size,
icon_size, icon_size,
launcher_alpha / 100.0, launcher_alpha / 100.0,
launcher_saturation / 100.0, launcher_saturation / 100.0,
launcher_brightness / 100.0); launcher_brightness / 100.0);
imlib_image_put_back_data(data); imlib_image_put_back_data(data);
imlib_context_set_image(icon_scaled); imlib_context_set_image(icon_scaled);
} else { } else {
icon_scaled = imlib_create_image(icon_size, icon_size); icon_scaled = imlib_create_image(icon_size, icon_size);
imlib_context_set_image(icon_scaled); imlib_context_set_image(icon_scaled);
imlib_context_set_color(255, 255, 255, 255); imlib_context_set_color(255, 255, 255, 255);
imlib_image_fill_rectangle(0, 0, icon_size, icon_size); imlib_image_fill_rectangle(0, 0, icon_size, icon_size);
} }
return icon_scaled; return icon_scaled;
} }
void free_icon(Imlib_Image icon) void free_icon(Imlib_Image icon)
{ {
if (icon) { if (icon) {
imlib_context_set_image(icon); imlib_context_set_image(icon);
imlib_free_image(); imlib_free_image();
} }
} }
void launcher_action(LauncherIcon *icon, XEvent *evt) void launcher_action(LauncherIcon *icon, XEvent *evt)
{ {
launcher_reload_icon((Launcher *)icon->area.parent, icon); launcher_reload_icon((Launcher *)icon->area.parent, icon);
launcher_reload_hidden_icons((Launcher *)icon->area.parent); launcher_reload_hidden_icons((Launcher *)icon->area.parent);
char *cmd = calloc(strlen(icon->cmd) + 10, 1); char *cmd = calloc(strlen(icon->cmd) + 10, 1);
sprintf(cmd, "(%s&)", icon->cmd); sprintf(cmd, "(%s&)", icon->cmd);
#if HAVE_SN #if HAVE_SN
SnLauncherContext *ctx = 0; SnLauncherContext *ctx = 0;
Time time; Time time;
if (startup_notifications) { if (startup_notifications) {
ctx = sn_launcher_context_new(server.sn_display, server.screen); ctx = sn_launcher_context_new(server.sn_display, server.screen);
sn_launcher_context_set_name(ctx, icon->icon_tooltip); sn_launcher_context_set_name(ctx, icon->icon_tooltip);
sn_launcher_context_set_description(ctx, "Application launched from tint2"); sn_launcher_context_set_description(ctx, "Application launched from tint2");
sn_launcher_context_set_binary_name(ctx, icon->cmd); sn_launcher_context_set_binary_name(ctx, icon->cmd);
// Get a timestamp from the X event // Get a timestamp from the X event
if (evt->type == ButtonPress || evt->type == ButtonRelease) { if (evt->type == ButtonPress || evt->type == ButtonRelease) {
time = evt->xbutton.time; time = evt->xbutton.time;
} else { } else {
fprintf(stderr, "Unknown X event: %d\n", evt->type); fprintf(stderr, "Unknown X event: %d\n", evt->type);
free(cmd); free(cmd);
return; return;
} }
sn_launcher_context_initiate(ctx, "tint2", icon->cmd, time); sn_launcher_context_initiate(ctx, "tint2", icon->cmd, time);
} }
#endif /* HAVE_SN */ #endif /* HAVE_SN */
pid_t pid; pid_t pid;
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
fprintf(stderr, "Could not fork\n"); fprintf(stderr, "Could not fork\n");
} else if (pid == 0) { } else if (pid == 0) {
// Child process // Child process
#if HAVE_SN #if HAVE_SN
if (startup_notifications) { if (startup_notifications) {
sn_launcher_context_setup_child_process(ctx); sn_launcher_context_setup_child_process(ctx);
} }
#endif // HAVE_SN #endif // HAVE_SN
// Allow children to exist after parent destruction // Allow children to exist after parent destruction
setsid(); setsid();
// Run the command // Run the command
if (icon->cwd) if (icon->cwd)
chdir(icon->cwd); chdir(icon->cwd);
execl("/bin/sh", "/bin/sh", "-c", icon->cmd, NULL); execl("/bin/sh", "/bin/sh", "-c", icon->cmd, NULL);
fprintf(stderr, "Failed to execlp %s\n", icon->cmd); fprintf(stderr, "Failed to execlp %s\n", icon->cmd);
#if HAVE_SN #if HAVE_SN
if (startup_notifications) { if (startup_notifications) {
sn_launcher_context_unref(ctx); sn_launcher_context_unref(ctx);
} }
#endif // HAVE_SN #endif // HAVE_SN
exit(1); exit(1);
} else { } else {
// Parent process // Parent process
#if HAVE_SN #if HAVE_SN
if (startup_notifications) { if (startup_notifications) {
g_tree_insert(server.pids, GINT_TO_POINTER(pid), ctx); g_tree_insert(server.pids, GINT_TO_POINTER(pid), ctx);
} }
#endif // HAVE_SN #endif // HAVE_SN
} }
free(cmd); free(cmd);
} }
// Populates the list_icons list from the list_apps list // Populates the list_icons list from the list_apps list
void launcher_load_icons(Launcher *launcher) void launcher_load_icons(Launcher *launcher)
{ {
// Load apps (.desktop style launcher items) // Load apps (.desktop style launcher items)
GSList *app = launcher->list_apps; GSList *app = launcher->list_apps;
int index = 0; int index = 0;
while (app != NULL) { while (app != NULL) {
index++; index++;
LauncherIcon *launcherIcon = (LauncherIcon *)calloc(1, sizeof(LauncherIcon)); LauncherIcon *launcherIcon = (LauncherIcon *)calloc(1, sizeof(LauncherIcon));
launcherIcon->area.panel = launcher->area.panel; launcherIcon->area.panel = launcher->area.panel;
launcherIcon->area._draw_foreground = draw_launcher_icon; launcherIcon->area._draw_foreground = draw_launcher_icon;
launcherIcon->area.size_mode = LAYOUT_FIXED; launcherIcon->area.size_mode = LAYOUT_FIXED;
launcherIcon->area._resize = NULL; launcherIcon->area._resize = NULL;
launcherIcon->area._compute_desired_size = launcher_icon_compute_desired_size; launcherIcon->area._compute_desired_size = launcher_icon_compute_desired_size;
sprintf(launcherIcon->area.name, "LauncherIcon %d", index); sprintf(launcherIcon->area.name, "LauncherIcon %d", index);
launcherIcon->area.resize_needed = 0; launcherIcon->area.resize_needed = 0;
launcherIcon->area.has_mouse_over_effect = panel_config.mouse_effects; launcherIcon->area.has_mouse_over_effect = panel_config.mouse_effects;
launcherIcon->area.has_mouse_press_effect = launcherIcon->area.has_mouse_over_effect; launcherIcon->area.has_mouse_press_effect = launcherIcon->area.has_mouse_over_effect;
launcherIcon->area.bg = launcher_icon_bg; launcherIcon->area.bg = launcher_icon_bg;
launcherIcon->area.on_screen = TRUE; launcherIcon->area.on_screen = TRUE;
launcherIcon->area.posx = -1; launcherIcon->area.posx = -1;
launcherIcon->area._on_change_layout = launcher_icon_on_change_layout; launcherIcon->area._on_change_layout = launcher_icon_on_change_layout;
launcherIcon->area._dump_geometry = launcher_icon_dump_geometry; launcherIcon->area._dump_geometry = launcher_icon_dump_geometry;
if (launcher_tooltip_enabled) { if (launcher_tooltip_enabled) {
launcherIcon->area._get_tooltip_text = launcher_icon_get_tooltip_text; launcherIcon->area._get_tooltip_text = launcher_icon_get_tooltip_text;
} else { } else {
launcherIcon->area._get_tooltip_text = NULL; launcherIcon->area._get_tooltip_text = NULL;
} }
launcherIcon->config_path = strdup(app->data); launcherIcon->config_path = strdup(app->data);
add_area(&launcherIcon->area, (Area *)launcher); add_area(&launcherIcon->area, (Area *)launcher);
launcher->list_icons = g_slist_append(launcher->list_icons, launcherIcon); launcher->list_icons = g_slist_append(launcher->list_icons, launcherIcon);
launcherIcon->icon_size = launcher->icon_size; launcherIcon->icon_size = launcher->icon_size;
launcher_reload_icon(launcher, launcherIcon); launcher_reload_icon(launcher, launcherIcon);
instantiate_area_gradients(&launcherIcon->area); instantiate_area_gradients(&launcherIcon->area);
app = g_slist_next(app); app = g_slist_next(app);
} }
} }
void launcher_reload_icon(Launcher *launcher, LauncherIcon *launcherIcon) void launcher_reload_icon(Launcher *launcher, LauncherIcon *launcherIcon)
{ {
DesktopEntry entry; DesktopEntry entry;
if (read_desktop_file(launcherIcon->config_path, &entry) && entry.exec) { if (read_desktop_file(launcherIcon->config_path, &entry) && entry.exec) {
schedule_redraw(&launcherIcon->area); schedule_redraw(&launcherIcon->area);
if (launcherIcon->cmd) if (launcherIcon->cmd)
free(launcherIcon->cmd); free(launcherIcon->cmd);
launcherIcon->cmd = strdup(entry.exec); launcherIcon->cmd = strdup(entry.exec);
if (launcherIcon->cwd) if (launcherIcon->cwd)
free(launcherIcon->cwd); free(launcherIcon->cwd);
if (entry.cwd) if (entry.cwd)
launcherIcon->cwd = strdup(entry.cwd); launcherIcon->cwd = strdup(entry.cwd);
else else
launcherIcon->cwd = NULL; launcherIcon->cwd = NULL;
if (launcherIcon->icon_name) if (launcherIcon->icon_name)
free(launcherIcon->icon_name); free(launcherIcon->icon_name);
launcherIcon->icon_name = entry.icon ? strdup(entry.icon) : strdup(DEFAULT_ICON); launcherIcon->icon_name = entry.icon ? strdup(entry.icon) : strdup(DEFAULT_ICON);
if (entry.name) { if (entry.name) {
if (entry.generic_name) { if (entry.generic_name) {
launcherIcon->icon_tooltip = g_strdup_printf("%s (%s)", entry.name, entry.generic_name); launcherIcon->icon_tooltip = g_strdup_printf("%s (%s)", entry.name, entry.generic_name);
} else { } else {
launcherIcon->icon_tooltip = g_strdup_printf("%s", entry.name); launcherIcon->icon_tooltip = g_strdup_printf("%s", entry.name);
} }
} else { } else {
if (entry.generic_name) { if (entry.generic_name) {
launcherIcon->icon_tooltip = g_strdup_printf("%s", entry.generic_name); launcherIcon->icon_tooltip = g_strdup_printf("%s", entry.generic_name);
} else if (entry.exec) { } else if (entry.exec) {
launcherIcon->icon_tooltip = g_strdup_printf("%s", entry.exec); launcherIcon->icon_tooltip = g_strdup_printf("%s", entry.exec);
} }
} }
launcher_reload_icon_image(launcher, launcherIcon); launcher_reload_icon_image(launcher, launcherIcon);
show(&launcherIcon->area); show(&launcherIcon->area);
} else { } else {
hide(&launcherIcon->area); hide(&launcherIcon->area);
} }
free_desktop_entry(&entry); free_desktop_entry(&entry);
} }
void launcher_reload_hidden_icons(Launcher *launcher) void launcher_reload_hidden_icons(Launcher *launcher)
{ {
for (GSList *l = launcher->list_icons; l; l = l->next) { for (GSList *l = launcher->list_icons; l; l = l->next) {
LauncherIcon *launcherIcon = (LauncherIcon *)l->data; LauncherIcon *launcherIcon = (LauncherIcon *)l->data;
if (!launcherIcon->area.on_screen) if (!launcherIcon->area.on_screen)
launcher_reload_icon(launcher, launcherIcon); launcher_reload_icon(launcher, launcherIcon);
} }
} }
void launcher_reload_icon_image(Launcher *launcher, LauncherIcon *launcherIcon) void launcher_reload_icon_image(Launcher *launcher, LauncherIcon *launcherIcon)
{ {
free_icon(launcherIcon->image); free_icon(launcherIcon->image);
free_icon(launcherIcon->image_hover); free_icon(launcherIcon->image_hover);
free_icon(launcherIcon->image_pressed); free_icon(launcherIcon->image_pressed);
launcherIcon->image = NULL; launcherIcon->image = NULL;
char *new_icon_path = get_icon_path(icon_theme_wrapper, launcherIcon->icon_name, launcherIcon->icon_size, TRUE); char *new_icon_path = get_icon_path(icon_theme_wrapper, launcherIcon->icon_name, launcherIcon->icon_size, TRUE);
if (new_icon_path) if (new_icon_path)
launcherIcon->image = load_image(new_icon_path, TRUE); launcherIcon->image = load_image(new_icon_path, TRUE);
// On loading error, fallback to default // On loading error, fallback to default
if (!launcherIcon->image) { if (!launcherIcon->image) {
free(new_icon_path); free(new_icon_path);
new_icon_path = get_icon_path(icon_theme_wrapper, DEFAULT_ICON, launcherIcon->icon_size, TRUE); new_icon_path = get_icon_path(icon_theme_wrapper, DEFAULT_ICON, launcherIcon->icon_size, TRUE);
if (new_icon_path) if (new_icon_path)
launcherIcon->image = load_image(new_icon_path, TRUE); launcherIcon->image = load_image(new_icon_path, TRUE);
} }
Imlib_Image original = launcherIcon->image; Imlib_Image original = launcherIcon->image;
launcherIcon->image = scale_icon(launcherIcon->image, launcherIcon->icon_size); launcherIcon->image = scale_icon(launcherIcon->image, launcherIcon->icon_size);
free_icon(original); free_icon(original);
free(launcherIcon->icon_path); free(launcherIcon->icon_path);
launcherIcon->icon_path = new_icon_path; launcherIcon->icon_path = new_icon_path;
// fprintf(stderr, "launcher.c %d: Using icon %s\n", __LINE__, launcherIcon->icon_path); // fprintf(stderr, "launcher.c %d: Using icon %s\n", __LINE__, launcherIcon->icon_path);
if (panel_config.mouse_effects) { if (panel_config.mouse_effects) {
launcherIcon->image_hover = adjust_icon(launcherIcon->image, launcherIcon->image_hover = adjust_icon(launcherIcon->image,
panel_config.mouse_over_alpha, panel_config.mouse_over_alpha,
panel_config.mouse_over_saturation, panel_config.mouse_over_saturation,
panel_config.mouse_over_brightness); panel_config.mouse_over_brightness);
launcherIcon->image_pressed = adjust_icon(launcherIcon->image, launcherIcon->image_pressed = adjust_icon(launcherIcon->image,
panel_config.mouse_pressed_alpha, panel_config.mouse_pressed_alpha,
panel_config.mouse_pressed_saturation, panel_config.mouse_pressed_saturation,
panel_config.mouse_pressed_brightness); panel_config.mouse_pressed_brightness);
} }
schedule_redraw(&launcherIcon->area); schedule_redraw(&launcherIcon->area);
} }
void load_icon_themes() void load_icon_themes()
{ {
if (icon_theme_wrapper) if (icon_theme_wrapper)
return; return;
icon_theme_wrapper = icon_theme_wrapper =
load_themes(launcher_icon_theme_override load_themes(launcher_icon_theme_override
? (icon_theme_name_config ? icon_theme_name_config ? (icon_theme_name_config ? icon_theme_name_config
: icon_theme_name_xsettings ? icon_theme_name_xsettings : "hicolor") : icon_theme_name_xsettings ? icon_theme_name_xsettings : "hicolor")
: (icon_theme_name_xsettings ? icon_theme_name_xsettings : (icon_theme_name_xsettings ? icon_theme_name_xsettings
: icon_theme_name_config ? icon_theme_name_config : "hicolor")); : icon_theme_name_config ? icon_theme_name_config : "hicolor"));
} }
void launcher_default_icon_theme_changed() void launcher_default_icon_theme_changed()
{ {
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
Launcher *launcher = &panels[i].launcher; Launcher *launcher = &panels[i].launcher;
cleanup_launcher_theme(launcher); cleanup_launcher_theme(launcher);
launcher_load_icons(launcher); launcher_load_icons(launcher);
launcher->area.resize_needed = 1; launcher->area.resize_needed = 1;
} }
schedule_panel_redraw(); schedule_panel_redraw();
} }

View File

@@ -17,27 +17,27 @@ void load_icon_themes();
void free_icon_themes(); void free_icon_themes();
typedef struct Launcher { typedef struct Launcher {
// always start with area // always start with area
Area area; Area area;
GSList *list_apps; // List of char*, each is a path to a app.desktop file GSList *list_apps; // List of char*, each is a path to a app.desktop file
GSList *list_icons; // List of LauncherIcon* GSList *list_icons; // List of LauncherIcon*
int icon_size; int icon_size;
} Launcher; } Launcher;
typedef struct LauncherIcon { typedef struct LauncherIcon {
// always start with area // always start with area
Area area; Area area;
char *config_path; char *config_path;
Imlib_Image image; Imlib_Image image;
Imlib_Image image_hover; Imlib_Image image_hover;
Imlib_Image image_pressed; Imlib_Image image_pressed;
char *cmd; char *cmd;
char *cwd; char *cwd;
char *icon_name; char *icon_name;
char *icon_path; char *icon_path;
char *icon_tooltip; char *icon_tooltip;
int icon_size; int icon_size;
int x, y; int x, y;
} LauncherIcon; } LauncherIcon;
extern gboolean launcher_enabled; extern gboolean launcher_enabled;

View File

@@ -34,78 +34,78 @@
#include "launcher.h" #include "launcher.h"
struct _XSettingsClient { struct _XSettingsClient {
Display *display; Display *display;
int screen; int screen;
XSettingsNotifyFunc notify; XSettingsNotifyFunc notify;
XSettingsWatchFunc watch; XSettingsWatchFunc watch;
void *cb_data; void *cb_data;
Window manager_window; Window manager_window;
XSettingsList *settings; XSettingsList *settings;
}; };
void xsettings_notify_cb(const char *name, XSettingsAction action, XSettingsSetting *setting, void *data) void xsettings_notify_cb(const char *name, XSettingsAction action, XSettingsSetting *setting, void *data)
{ {
if ((action == XSETTINGS_ACTION_NEW || action == XSETTINGS_ACTION_CHANGED) && name != NULL && setting != NULL) { if ((action == XSETTINGS_ACTION_NEW || action == XSETTINGS_ACTION_CHANGED) && name != NULL && setting != NULL) {
if (strcmp(name, "Net/IconThemeName") == 0 && setting->type == XSETTINGS_TYPE_STRING) { if (strcmp(name, "Net/IconThemeName") == 0 && setting->type == XSETTINGS_TYPE_STRING) {
fprintf(stderr, "xsettings: %s = %s\n", name, setting->data.v_string); fprintf(stderr, "xsettings: %s = %s\n", name, setting->data.v_string);
if (icon_theme_name_xsettings) { if (icon_theme_name_xsettings) {
if (strcmp(icon_theme_name_xsettings, setting->data.v_string) == 0) if (strcmp(icon_theme_name_xsettings, setting->data.v_string) == 0)
return; return;
free(icon_theme_name_xsettings); free(icon_theme_name_xsettings);
} }
icon_theme_name_xsettings = strdup(setting->data.v_string); icon_theme_name_xsettings = strdup(setting->data.v_string);
default_icon_theme_changed(); default_icon_theme_changed();
} else if (strcmp(name, "Gtk/FontName") == 0 && setting->type == XSETTINGS_TYPE_STRING) { } else if (strcmp(name, "Gtk/FontName") == 0 && setting->type == XSETTINGS_TYPE_STRING) {
fprintf(stderr, "xsettings: %s = %s\n", name, setting->data.v_string); fprintf(stderr, "xsettings: %s = %s\n", name, setting->data.v_string);
if (default_font) { if (default_font) {
if (strcmp(default_font, setting->data.v_string) == 0) if (strcmp(default_font, setting->data.v_string) == 0)
return; return;
free(default_font); free(default_font);
} }
default_font = strdup(setting->data.v_string); default_font = strdup(setting->data.v_string);
default_font_changed(); default_font_changed();
} }
} }
} }
static void notify_changes(XSettingsClient *client, XSettingsList *old_list) static void notify_changes(XSettingsClient *client, XSettingsList *old_list)
{ {
XSettingsList *old_iter = old_list; XSettingsList *old_iter = old_list;
XSettingsList *new_iter = client->settings; XSettingsList *new_iter = client->settings;
if (!client->notify) if (!client->notify)
return; return;
while (old_iter || new_iter) { while (old_iter || new_iter) {
int cmp; int cmp;
if (old_iter && new_iter) if (old_iter && new_iter)
cmp = strcmp(old_iter->setting->name, new_iter->setting->name); cmp = strcmp(old_iter->setting->name, new_iter->setting->name);
else if (old_iter) else if (old_iter)
cmp = -1; cmp = -1;
else else
cmp = 1; cmp = 1;
if (cmp < 0) { if (cmp < 0) {
client->notify(old_iter->setting->name, XSETTINGS_ACTION_DELETED, NULL, client->cb_data); client->notify(old_iter->setting->name, XSETTINGS_ACTION_DELETED, NULL, client->cb_data);
} else if (cmp == 0) { } else if (cmp == 0) {
if (!xsettings_setting_equal(old_iter->setting, new_iter->setting)) if (!xsettings_setting_equal(old_iter->setting, new_iter->setting))
client->notify(old_iter->setting->name, XSETTINGS_ACTION_CHANGED, new_iter->setting, client->cb_data); client->notify(old_iter->setting->name, XSETTINGS_ACTION_CHANGED, new_iter->setting, client->cb_data);
} else { } else {
client->notify(new_iter->setting->name, XSETTINGS_ACTION_NEW, new_iter->setting, client->cb_data); client->notify(new_iter->setting->name, XSETTINGS_ACTION_NEW, new_iter->setting, client->cb_data);
} }
if (old_iter) if (old_iter)
old_iter = old_iter->next; old_iter = old_iter->next;
if (new_iter) if (new_iter)
new_iter = new_iter->next; new_iter = new_iter->next;
} }
} }
static int ignore_errors(Display *display, XErrorEvent *event) static int ignore_errors(Display *display, XErrorEvent *event)
{ {
return True; return True;
} }
static char local_byte_order = '\0'; static char local_byte_order = '\0';
@@ -114,364 +114,364 @@ static char local_byte_order = '\0';
static XSettingsResult fetch_card16(XSettingsBuffer *buffer, CARD16 *result) static XSettingsResult fetch_card16(XSettingsBuffer *buffer, CARD16 *result)
{ {
CARD16 x; CARD16 x;
if (BYTES_LEFT(buffer) < 2) if (BYTES_LEFT(buffer) < 2)
return XSETTINGS_ACCESS; return XSETTINGS_ACCESS;
x = *(CARD16 *)buffer->pos; x = *(CARD16 *)buffer->pos;
buffer->pos += 2; buffer->pos += 2;
if (buffer->byte_order == local_byte_order) if (buffer->byte_order == local_byte_order)
*result = x; *result = x;
else else
*result = (x << 8) | (x >> 8); *result = (x << 8) | (x >> 8);
return XSETTINGS_SUCCESS; return XSETTINGS_SUCCESS;
} }
static XSettingsResult fetch_ushort(XSettingsBuffer *buffer, unsigned short *result) static XSettingsResult fetch_ushort(XSettingsBuffer *buffer, unsigned short *result)
{ {
CARD16 x; CARD16 x;
XSettingsResult r; XSettingsResult r;
r = fetch_card16(buffer, &x); r = fetch_card16(buffer, &x);
if (r == XSETTINGS_SUCCESS) if (r == XSETTINGS_SUCCESS)
*result = x; *result = x;
return r; return r;
} }
static XSettingsResult fetch_card32(XSettingsBuffer *buffer, CARD32 *result) static XSettingsResult fetch_card32(XSettingsBuffer *buffer, CARD32 *result)
{ {
CARD32 x; CARD32 x;
if (BYTES_LEFT(buffer) < 4) if (BYTES_LEFT(buffer) < 4)
return XSETTINGS_ACCESS; return XSETTINGS_ACCESS;
x = *(CARD32 *)buffer->pos; x = *(CARD32 *)buffer->pos;
buffer->pos += 4; buffer->pos += 4;
if (buffer->byte_order == local_byte_order) if (buffer->byte_order == local_byte_order)
*result = x; *result = x;
else else
*result = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24); *result = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
return XSETTINGS_SUCCESS; return XSETTINGS_SUCCESS;
} }
static XSettingsResult fetch_card8(XSettingsBuffer *buffer, CARD8 *result) static XSettingsResult fetch_card8(XSettingsBuffer *buffer, CARD8 *result)
{ {
if (BYTES_LEFT(buffer) < 1) if (BYTES_LEFT(buffer) < 1)
return XSETTINGS_ACCESS; return XSETTINGS_ACCESS;
*result = *(CARD8 *)buffer->pos; *result = *(CARD8 *)buffer->pos;
buffer->pos += 1; buffer->pos += 1;
return XSETTINGS_SUCCESS; return XSETTINGS_SUCCESS;
} }
#define XSETTINGS_PAD(n, m) ((n + m - 1) & (~(m - 1))) #define XSETTINGS_PAD(n, m) ((n + m - 1) & (~(m - 1)))
static XSettingsList *parse_settings(unsigned char *data, size_t len) static XSettingsList *parse_settings(unsigned char *data, size_t len)
{ {
XSettingsBuffer buffer; XSettingsBuffer buffer;
XSettingsResult result = XSETTINGS_SUCCESS; XSettingsResult result = XSETTINGS_SUCCESS;
XSettingsList *settings = NULL; XSettingsList *settings = NULL;
CARD32 serial; CARD32 serial;
CARD32 n_entries; CARD32 n_entries;
CARD32 i; CARD32 i;
XSettingsSetting *setting = NULL; XSettingsSetting *setting = NULL;
local_byte_order = xsettings_byte_order(); local_byte_order = xsettings_byte_order();
buffer.byte_order = local_byte_order; buffer.byte_order = local_byte_order;
buffer.pos = buffer.data = data; buffer.pos = buffer.data = data;
buffer.len = len; buffer.len = len;
result = fetch_card8(&buffer, (CARD8 *)&buffer.byte_order); result = fetch_card8(&buffer, (CARD8 *)&buffer.byte_order);
if (buffer.byte_order != MSBFirst && buffer.byte_order != LSBFirst) { if (buffer.byte_order != MSBFirst && buffer.byte_order != LSBFirst) {
fprintf(stderr, "Invalid byte order %x in XSETTINGS property\n", buffer.byte_order); fprintf(stderr, "Invalid byte order %x in XSETTINGS property\n", buffer.byte_order);
result = XSETTINGS_FAILED; result = XSETTINGS_FAILED;
goto out; goto out;
} }
buffer.pos += 3; buffer.pos += 3;
result = fetch_card32(&buffer, &serial); result = fetch_card32(&buffer, &serial);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
result = fetch_card32(&buffer, &n_entries); result = fetch_card32(&buffer, &n_entries);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
for (i = 0; i < n_entries; i++) { for (i = 0; i < n_entries; i++) {
CARD8 type; CARD8 type;
CARD16 name_len; CARD16 name_len;
CARD32 v_int; CARD32 v_int;
size_t pad_len; size_t pad_len;
result = fetch_card8(&buffer, &type); result = fetch_card8(&buffer, &type);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
buffer.pos += 1; buffer.pos += 1;
result = fetch_card16(&buffer, &name_len); result = fetch_card16(&buffer, &name_len);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
pad_len = XSETTINGS_PAD(name_len, 4); pad_len = XSETTINGS_PAD(name_len, 4);
if (BYTES_LEFT(&buffer) < pad_len) { if (BYTES_LEFT(&buffer) < pad_len) {
result = XSETTINGS_ACCESS; result = XSETTINGS_ACCESS;
goto out; goto out;
} }
setting = calloc(1, sizeof *setting); setting = calloc(1, sizeof *setting);
if (!setting) { if (!setting) {
result = XSETTINGS_NO_MEM; result = XSETTINGS_NO_MEM;
goto out; goto out;
} }
setting->type = XSETTINGS_TYPE_INT; /* No allocated memory */ setting->type = XSETTINGS_TYPE_INT; /* No allocated memory */
setting->name = calloc(name_len + 1, 1); setting->name = calloc(name_len + 1, 1);
if (!setting->name) { if (!setting->name) {
result = XSETTINGS_NO_MEM; result = XSETTINGS_NO_MEM;
goto out; goto out;
} }
memcpy(setting->name, buffer.pos, name_len); memcpy(setting->name, buffer.pos, name_len);
setting->name[name_len] = '\0'; setting->name[name_len] = '\0';
buffer.pos += pad_len; buffer.pos += pad_len;
result = fetch_card32(&buffer, &v_int); result = fetch_card32(&buffer, &v_int);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
setting->last_change_serial = v_int; setting->last_change_serial = v_int;
switch (type) { switch (type) {
case XSETTINGS_TYPE_INT: case XSETTINGS_TYPE_INT:
result = fetch_card32(&buffer, &v_int); result = fetch_card32(&buffer, &v_int);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
setting->data.v_int = (INT32)v_int; setting->data.v_int = (INT32)v_int;
break; break;
case XSETTINGS_TYPE_STRING: case XSETTINGS_TYPE_STRING:
result = fetch_card32(&buffer, &v_int); result = fetch_card32(&buffer, &v_int);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
pad_len = XSETTINGS_PAD(v_int, 4); pad_len = XSETTINGS_PAD(v_int, 4);
if (v_int + 1 == 0 || /* Guard against wrap-around */ if (v_int + 1 == 0 || /* Guard against wrap-around */
BYTES_LEFT(&buffer) < pad_len) { BYTES_LEFT(&buffer) < pad_len) {
result = XSETTINGS_ACCESS; result = XSETTINGS_ACCESS;
goto out; goto out;
} }
setting->data.v_string = calloc(v_int + 1, 1); setting->data.v_string = calloc(v_int + 1, 1);
if (!setting->data.v_string) { if (!setting->data.v_string) {
result = XSETTINGS_NO_MEM; result = XSETTINGS_NO_MEM;
goto out; goto out;
} }
memcpy(setting->data.v_string, buffer.pos, v_int); memcpy(setting->data.v_string, buffer.pos, v_int);
setting->data.v_string[v_int] = '\0'; setting->data.v_string[v_int] = '\0';
buffer.pos += pad_len; buffer.pos += pad_len;
break; break;
case XSETTINGS_TYPE_COLOR: case XSETTINGS_TYPE_COLOR:
result = fetch_ushort(&buffer, &setting->data.v_color.red); result = fetch_ushort(&buffer, &setting->data.v_color.red);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
result = fetch_ushort(&buffer, &setting->data.v_color.green); result = fetch_ushort(&buffer, &setting->data.v_color.green);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
result = fetch_ushort(&buffer, &setting->data.v_color.blue); result = fetch_ushort(&buffer, &setting->data.v_color.blue);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
result = fetch_ushort(&buffer, &setting->data.v_color.alpha); result = fetch_ushort(&buffer, &setting->data.v_color.alpha);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
break; break;
default: default:
/* Quietly ignore unknown types */ /* Quietly ignore unknown types */
break; break;
} }
setting->type = type; setting->type = type;
result = xsettings_list_insert(&settings, setting); result = xsettings_list_insert(&settings, setting);
if (result != XSETTINGS_SUCCESS) if (result != XSETTINGS_SUCCESS)
goto out; goto out;
setting = NULL; setting = NULL;
} }
out: out:
if (result != XSETTINGS_SUCCESS) { if (result != XSETTINGS_SUCCESS) {
switch (result) { switch (result) {
case XSETTINGS_NO_MEM: case XSETTINGS_NO_MEM:
fprintf(stderr, "Out of memory reading XSETTINGS property\n"); fprintf(stderr, "Out of memory reading XSETTINGS property\n");
break; break;
case XSETTINGS_ACCESS: case XSETTINGS_ACCESS:
fprintf(stderr, "Invalid XSETTINGS property (read off end)\n"); fprintf(stderr, "Invalid XSETTINGS property (read off end)\n");
break; break;
case XSETTINGS_DUPLICATE_ENTRY: case XSETTINGS_DUPLICATE_ENTRY:
fprintf(stderr, "Duplicate XSETTINGS entry for '%s'\n", setting->name); fprintf(stderr, "Duplicate XSETTINGS entry for '%s'\n", setting->name);
case XSETTINGS_FAILED: case XSETTINGS_FAILED:
case XSETTINGS_SUCCESS: case XSETTINGS_SUCCESS:
case XSETTINGS_NO_ENTRY: case XSETTINGS_NO_ENTRY:
break; break;
} }
if (setting) if (setting)
xsettings_setting_free(setting); xsettings_setting_free(setting);
xsettings_list_free(settings); xsettings_list_free(settings);
settings = NULL; settings = NULL;
} }
return settings; return settings;
} }
static void read_settings(XSettingsClient *client) static void read_settings(XSettingsClient *client)
{ {
Atom type; Atom type;
int format; int format;
unsigned long n_items; unsigned long n_items;
unsigned long bytes_after; unsigned long bytes_after;
unsigned char *data; unsigned char *data;
int (*old_handler)(Display *, XErrorEvent *); int (*old_handler)(Display *, XErrorEvent *);
XSettingsList *old_list = client->settings; XSettingsList *old_list = client->settings;
client->settings = NULL; client->settings = NULL;
old_handler = XSetErrorHandler(ignore_errors); old_handler = XSetErrorHandler(ignore_errors);
int result = XGetWindowProperty(client->display, int result = XGetWindowProperty(client->display,
client->manager_window, client->manager_window,
server.atom._XSETTINGS_SETTINGS, server.atom._XSETTINGS_SETTINGS,
0, 0,
LONG_MAX, LONG_MAX,
False, False,
server.atom._XSETTINGS_SETTINGS, server.atom._XSETTINGS_SETTINGS,
&type, &type,
&format, &format,
&n_items, &n_items,
&bytes_after, &bytes_after,
&data); &data);
XSetErrorHandler(old_handler); XSetErrorHandler(old_handler);
if (result == Success && type == server.atom._XSETTINGS_SETTINGS) { if (result == Success && type == server.atom._XSETTINGS_SETTINGS) {
if (format != 8) { if (format != 8) {
fprintf(stderr, "Invalid format for XSETTINGS property %d", format); fprintf(stderr, "Invalid format for XSETTINGS property %d", format);
} else } else
client->settings = parse_settings(data, n_items); client->settings = parse_settings(data, n_items);
XFree(data); XFree(data);
} }
notify_changes(client, old_list); notify_changes(client, old_list);
xsettings_list_free(old_list); xsettings_list_free(old_list);
} }
static void check_manager_window(XSettingsClient *client) static void check_manager_window(XSettingsClient *client)
{ {
if (client->manager_window && client->watch) if (client->manager_window && client->watch)
client->watch(client->manager_window, False, 0, client->cb_data); client->watch(client->manager_window, False, 0, client->cb_data);
XGrabServer(client->display); XGrabServer(client->display);
client->manager_window = XGetSelectionOwner(server.display, server.atom._XSETTINGS_SCREEN); client->manager_window = XGetSelectionOwner(server.display, server.atom._XSETTINGS_SCREEN);
if (client->manager_window) if (client->manager_window)
XSelectInput(server.display, client->manager_window, PropertyChangeMask | StructureNotifyMask); XSelectInput(server.display, client->manager_window, PropertyChangeMask | StructureNotifyMask);
XUngrabServer(client->display); XUngrabServer(client->display);
XFlush(client->display); XFlush(client->display);
if (client->manager_window && client->watch) if (client->manager_window && client->watch)
client->watch(client->manager_window, True, PropertyChangeMask | StructureNotifyMask, client->cb_data); client->watch(client->manager_window, True, PropertyChangeMask | StructureNotifyMask, client->cb_data);
read_settings(client); read_settings(client);
} }
XSettingsClient *xsettings_client_new(Display *display, XSettingsClient *xsettings_client_new(Display *display,
int screen, int screen,
XSettingsNotifyFunc notify, XSettingsNotifyFunc notify,
XSettingsWatchFunc watch, XSettingsWatchFunc watch,
void *cb_data) void *cb_data)
{ {
XSettingsClient *client = calloc(1, sizeof *client); XSettingsClient *client = calloc(1, sizeof *client);
if (!client) if (!client)
return NULL; return NULL;
client->display = display; client->display = display;
client->screen = screen; client->screen = screen;
client->notify = notify; client->notify = notify;
client->watch = watch; client->watch = watch;
client->cb_data = cb_data; client->cb_data = cb_data;
client->manager_window = None; client->manager_window = None;
client->settings = NULL; client->settings = NULL;
if (client->watch) if (client->watch)
client->watch(RootWindow(display, screen), True, StructureNotifyMask, client->cb_data); client->watch(RootWindow(display, screen), True, StructureNotifyMask, client->cb_data);
check_manager_window(client); check_manager_window(client);
if (client->manager_window == None) { if (client->manager_window == None) {
printf("No XSETTINGS manager, tint2 uses config option 'launcher_icon_theme'.\n"); printf("No XSETTINGS manager, tint2 uses config option 'launcher_icon_theme'.\n");
free(client); free(client);
return NULL; return NULL;
} else { } else {
return client; return client;
} }
} }
void xsettings_client_destroy(XSettingsClient *client) void xsettings_client_destroy(XSettingsClient *client)
{ {
if (!client) if (!client)
return; return;
if (client->watch) if (client->watch)
client->watch(RootWindow(client->display, client->screen), False, 0, client->cb_data); client->watch(RootWindow(client->display, client->screen), False, 0, client->cb_data);
if (client->manager_window && client->watch) if (client->manager_window && client->watch)
client->watch(client->manager_window, False, 0, client->cb_data); client->watch(client->manager_window, False, 0, client->cb_data);
xsettings_list_free(client->settings); xsettings_list_free(client->settings);
free(client); free(client);
} }
XSettingsResult xsettings_client_get_setting(XSettingsClient *client, const char *name, XSettingsSetting **setting) XSettingsResult xsettings_client_get_setting(XSettingsClient *client, const char *name, XSettingsSetting **setting)
{ {
XSettingsSetting *search = xsettings_list_lookup(client->settings, name); XSettingsSetting *search = xsettings_list_lookup(client->settings, name);
if (search) { if (search) {
*setting = xsettings_setting_copy(search); *setting = xsettings_setting_copy(search);
return *setting ? XSETTINGS_SUCCESS : XSETTINGS_NO_MEM; return *setting ? XSETTINGS_SUCCESS : XSETTINGS_NO_MEM;
} else } else
return XSETTINGS_NO_ENTRY; return XSETTINGS_NO_ENTRY;
} }
Bool xsettings_client_process_event(XSettingsClient *client, XEvent *xev) Bool xsettings_client_process_event(XSettingsClient *client, XEvent *xev)
{ {
/* The checks here will not unlikely cause us to reread /* The checks here will not unlikely cause us to reread
* the properties from the manager window a number of * the properties from the manager window a number of
* times when the manager changes from A->B. But manager changes * times when the manager changes from A->B. But manager changes
* are going to be pretty rare. * are going to be pretty rare.
*/ */
if (xev->xany.window == RootWindow(server.display, server.screen)) { if (xev->xany.window == RootWindow(server.display, server.screen)) {
if (xev->xany.type == ClientMessage && xev->xclient.message_type == server.atom.MANAGER) { if (xev->xany.type == ClientMessage && xev->xclient.message_type == server.atom.MANAGER) {
check_manager_window(client); check_manager_window(client);
return True; return True;
} }
} else if (xev->xany.window == client->manager_window) { } else if (xev->xany.window == client->manager_window) {
if (xev->xany.type == DestroyNotify) { if (xev->xany.type == DestroyNotify) {
check_manager_window(client); check_manager_window(client);
return True; return True;
} else if (xev->xany.type == PropertyNotify) { } else if (xev->xany.type == PropertyNotify) {
read_settings(client); read_settings(client);
return True; return True;
} }
} }
return False; return False;
} }

View File

@@ -38,10 +38,10 @@ typedef void (*XSettingsNotifyFunc)(const char *name, XSettingsAction action, XS
typedef void (*XSettingsWatchFunc)(Window window, Bool is_start, long mask, void *cb_data); typedef void (*XSettingsWatchFunc)(Window window, Bool is_start, long mask, void *cb_data);
XSettingsClient *xsettings_client_new(Display *display, XSettingsClient *xsettings_client_new(Display *display,
int screen, int screen,
XSettingsNotifyFunc notify, XSettingsNotifyFunc notify,
XSettingsWatchFunc watch, XSettingsWatchFunc watch,
void *cb_data); void *cb_data);
void xsettings_client_destroy(XSettingsClient *client); void xsettings_client_destroy(XSettingsClient *client);
Bool xsettings_client_process_event(XSettingsClient *client, XEvent *xev); Bool xsettings_client_process_event(XSettingsClient *client, XEvent *xev);

View File

@@ -30,216 +30,216 @@
XSettingsSetting *xsettings_setting_copy(XSettingsSetting *setting) XSettingsSetting *xsettings_setting_copy(XSettingsSetting *setting)
{ {
XSettingsSetting *result; XSettingsSetting *result;
size_t str_len; size_t str_len;
result = calloc(1, sizeof *result); result = calloc(1, sizeof *result);
if (!result) if (!result)
return NULL; return NULL;
str_len = strlen(setting->name); str_len = strlen(setting->name);
result->name = calloc(str_len + 1, 1); result->name = calloc(str_len + 1, 1);
if (!result->name) if (!result->name)
goto err; goto err;
memcpy(result->name, setting->name, str_len + 1); memcpy(result->name, setting->name, str_len + 1);
result->type = setting->type; result->type = setting->type;
switch (setting->type) { switch (setting->type) {
case XSETTINGS_TYPE_INT: case XSETTINGS_TYPE_INT:
result->data.v_int = setting->data.v_int; result->data.v_int = setting->data.v_int;
break; break;
case XSETTINGS_TYPE_COLOR: case XSETTINGS_TYPE_COLOR:
result->data.v_color = setting->data.v_color; result->data.v_color = setting->data.v_color;
break; break;
case XSETTINGS_TYPE_STRING: case XSETTINGS_TYPE_STRING:
str_len = strlen(setting->data.v_string); str_len = strlen(setting->data.v_string);
result->data.v_string = calloc(str_len + 1, 1); result->data.v_string = calloc(str_len + 1, 1);
if (!result->data.v_string) if (!result->data.v_string)
goto err; goto err;
memcpy(result->data.v_string, setting->data.v_string, str_len + 1); memcpy(result->data.v_string, setting->data.v_string, str_len + 1);
break; break;
default: default:
break; break;
} }
result->last_change_serial = setting->last_change_serial; result->last_change_serial = setting->last_change_serial;
return result; return result;
err: err:
if (result->name) if (result->name)
free(result->name); free(result->name);
free(result); free(result);
return NULL; return NULL;
} }
XSettingsList *xsettings_list_copy(XSettingsList *list) XSettingsList *xsettings_list_copy(XSettingsList *list)
{ {
XSettingsList *new = NULL; XSettingsList *new = NULL;
XSettingsList *old_iter = list; XSettingsList *old_iter = list;
XSettingsList *new_iter = NULL; XSettingsList *new_iter = NULL;
while (old_iter) { while (old_iter) {
XSettingsList *new_node; XSettingsList *new_node;
new_node = calloc(1, sizeof *new_node); new_node = calloc(1, sizeof *new_node);
if (!new_node) if (!new_node)
goto error; goto error;
new_node->setting = xsettings_setting_copy(old_iter->setting); new_node->setting = xsettings_setting_copy(old_iter->setting);
if (!new_node->setting) { if (!new_node->setting) {
free(new_node); free(new_node);
goto error; goto error;
} }
if (new_iter) if (new_iter)
new_iter->next = new_node; new_iter->next = new_node;
else else
new = new_node; new = new_node;
new_iter = new_node; new_iter = new_node;
old_iter = old_iter->next; old_iter = old_iter->next;
} }
return new; return new;
error: error:
xsettings_list_free(new); xsettings_list_free(new);
return NULL; return NULL;
} }
int xsettings_setting_equal(XSettingsSetting *setting_a, XSettingsSetting *setting_b) int xsettings_setting_equal(XSettingsSetting *setting_a, XSettingsSetting *setting_b)
{ {
if (setting_a->type != setting_b->type) if (setting_a->type != setting_b->type)
return 0; return 0;
if (strcmp(setting_a->name, setting_b->name) != 0) if (strcmp(setting_a->name, setting_b->name) != 0)
return 0; return 0;
switch (setting_a->type) { switch (setting_a->type) {
case XSETTINGS_TYPE_INT: case XSETTINGS_TYPE_INT:
return setting_a->data.v_int == setting_b->data.v_int; return setting_a->data.v_int == setting_b->data.v_int;
case XSETTINGS_TYPE_COLOR: case XSETTINGS_TYPE_COLOR:
return (setting_a->data.v_color.red == setting_b->data.v_color.red && return (setting_a->data.v_color.red == setting_b->data.v_color.red &&
setting_a->data.v_color.green == setting_b->data.v_color.green && setting_a->data.v_color.green == setting_b->data.v_color.green &&
setting_a->data.v_color.blue == setting_b->data.v_color.blue && setting_a->data.v_color.blue == setting_b->data.v_color.blue &&
setting_a->data.v_color.alpha == setting_b->data.v_color.alpha); setting_a->data.v_color.alpha == setting_b->data.v_color.alpha);
case XSETTINGS_TYPE_STRING: case XSETTINGS_TYPE_STRING:
return strcmp(setting_a->data.v_string, setting_b->data.v_string) == 0; return strcmp(setting_a->data.v_string, setting_b->data.v_string) == 0;
default: default:
break; break;
} }
return 0; return 0;
} }
void xsettings_setting_free(XSettingsSetting *setting) void xsettings_setting_free(XSettingsSetting *setting)
{ {
if (setting->type == XSETTINGS_TYPE_STRING) if (setting->type == XSETTINGS_TYPE_STRING)
free(setting->data.v_string); free(setting->data.v_string);
if (setting->name) if (setting->name)
free(setting->name); free(setting->name);
free(setting); free(setting);
} }
void xsettings_list_free(XSettingsList *list) void xsettings_list_free(XSettingsList *list)
{ {
while (list) { while (list) {
XSettingsList *next = list->next; XSettingsList *next = list->next;
xsettings_setting_free(list->setting); xsettings_setting_free(list->setting);
free(list); free(list);
list = next; list = next;
} }
} }
XSettingsResult xsettings_list_insert(XSettingsList **list, XSettingsSetting *setting) XSettingsResult xsettings_list_insert(XSettingsList **list, XSettingsSetting *setting)
{ {
XSettingsList *node; XSettingsList *node;
XSettingsList *iter; XSettingsList *iter;
XSettingsList *last = NULL; XSettingsList *last = NULL;
node = calloc(1, sizeof *node); node = calloc(1, sizeof *node);
if (!node) if (!node)
return XSETTINGS_NO_MEM; return XSETTINGS_NO_MEM;
node->setting = setting; node->setting = setting;
iter = *list; iter = *list;
while (iter) { while (iter) {
int cmp = strcmp(setting->name, iter->setting->name); int cmp = strcmp(setting->name, iter->setting->name);
if (cmp < 0) if (cmp < 0)
break; break;
else if (cmp == 0) { else if (cmp == 0) {
free(node); free(node);
return XSETTINGS_DUPLICATE_ENTRY; return XSETTINGS_DUPLICATE_ENTRY;
} }
last = iter; last = iter;
iter = iter->next; iter = iter->next;
} }
if (last) if (last)
last->next = node; last->next = node;
else else
*list = node; *list = node;
node->next = iter; node->next = iter;
return XSETTINGS_SUCCESS; return XSETTINGS_SUCCESS;
} }
XSettingsResult xsettings_list_delete(XSettingsList **list, const char *name) XSettingsResult xsettings_list_delete(XSettingsList **list, const char *name)
{ {
XSettingsList *iter; XSettingsList *iter;
XSettingsList *last = NULL; XSettingsList *last = NULL;
iter = *list; iter = *list;
while (iter) { while (iter) {
if (strcmp(name, iter->setting->name) == 0) { if (strcmp(name, iter->setting->name) == 0) {
if (last) if (last)
last->next = iter->next; last->next = iter->next;
else else
*list = iter->next; *list = iter->next;
xsettings_setting_free(iter->setting); xsettings_setting_free(iter->setting);
free(iter); free(iter);
return XSETTINGS_SUCCESS; return XSETTINGS_SUCCESS;
} }
last = iter; last = iter;
iter = iter->next; iter = iter->next;
} }
return XSETTINGS_FAILED; return XSETTINGS_FAILED;
} }
XSettingsSetting *xsettings_list_lookup(XSettingsList *list, const char *name) XSettingsSetting *xsettings_list_lookup(XSettingsList *list, const char *name)
{ {
XSettingsList *iter; XSettingsList *iter;
iter = list; iter = list;
while (iter) { while (iter) {
if (strcmp(name, iter->setting->name) == 0) if (strcmp(name, iter->setting->name) == 0)
return iter->setting; return iter->setting;
iter = iter->next; iter = iter->next;
} }
return NULL; return NULL;
} }
char xsettings_byte_order(void) char xsettings_byte_order(void)
{ {
CARD32 myint = 0x01020304; CARD32 myint = 0x01020304;
return (*(char *)&myint == 1) ? MSBFirst : LSBFirst; return (*(char *)&myint == 1) ? MSBFirst : LSBFirst;
} }

View File

@@ -36,48 +36,48 @@ typedef struct _XSettingsSetting XSettingsSetting;
* protocol values. * protocol values.
*/ */
typedef enum { typedef enum {
XSETTINGS_TYPE_INT = 0, XSETTINGS_TYPE_INT = 0,
XSETTINGS_TYPE_STRING = 1, XSETTINGS_TYPE_STRING = 1,
XSETTINGS_TYPE_COLOR = 2, XSETTINGS_TYPE_COLOR = 2,
XSETTINGS_TYPE_NONE = 0xff XSETTINGS_TYPE_NONE = 0xff
} XSettingsType; } XSettingsType;
typedef enum { typedef enum {
XSETTINGS_SUCCESS, XSETTINGS_SUCCESS,
XSETTINGS_NO_MEM, XSETTINGS_NO_MEM,
XSETTINGS_ACCESS, XSETTINGS_ACCESS,
XSETTINGS_FAILED, XSETTINGS_FAILED,
XSETTINGS_NO_ENTRY, XSETTINGS_NO_ENTRY,
XSETTINGS_DUPLICATE_ENTRY XSETTINGS_DUPLICATE_ENTRY
} XSettingsResult; } XSettingsResult;
struct _XSettingsBuffer { struct _XSettingsBuffer {
char byte_order; char byte_order;
size_t len; size_t len;
unsigned char *data; unsigned char *data;
unsigned char *pos; unsigned char *pos;
}; };
struct _XSettingsColor { struct _XSettingsColor {
unsigned short red, green, blue, alpha; unsigned short red, green, blue, alpha;
}; };
struct _XSettingsList { struct _XSettingsList {
XSettingsSetting *setting; XSettingsSetting *setting;
XSettingsList *next; XSettingsList *next;
}; };
struct _XSettingsSetting { struct _XSettingsSetting {
char *name; char *name;
XSettingsType type; XSettingsType type;
union { union {
int v_int; int v_int;
char *v_string; char *v_string;
XSettingsColor v_color; XSettingsColor v_color;
} data; } data;
unsigned long last_change_serial; unsigned long last_change_serial;
}; };
XSettingsSetting *xsettings_setting_copy(XSettingsSetting *setting); XSettingsSetting *xsettings_setting_copy(XSettingsSetting *setting);

File diff suppressed because it is too large Load Diff

View File

@@ -42,29 +42,29 @@ extern MouseAction mouse_tilt_right;
// panel mode // panel mode
typedef enum TaskbarMode { typedef enum TaskbarMode {
SINGLE_DESKTOP = 0, SINGLE_DESKTOP = 0,
MULTI_DESKTOP, MULTI_DESKTOP,
} TaskbarMode; } TaskbarMode;
typedef enum Layer { typedef enum Layer {
BOTTOM_LAYER, BOTTOM_LAYER,
NORMAL_LAYER, NORMAL_LAYER,
TOP_LAYER, TOP_LAYER,
} Layer; } Layer;
// panel position // panel position
typedef enum PanelPosition { typedef enum PanelPosition {
LEFT = 0x01, LEFT = 0x01,
RIGHT = 0x02, RIGHT = 0x02,
CENTER = 0X04, CENTER = 0X04,
TOP = 0X08, TOP = 0X08,
BOTTOM = 0x10, BOTTOM = 0x10,
} PanelPosition; } PanelPosition;
typedef enum Strut { typedef enum Strut {
STRUT_MINIMUM, STRUT_MINIMUM,
STRUT_FOLLOW_SIZE, STRUT_FOLLOW_SIZE,
STRUT_NONE, STRUT_NONE,
} Strut; } Strut;
extern TaskbarMode taskbar_mode; extern TaskbarMode taskbar_mode;
@@ -95,54 +95,54 @@ extern gboolean debug_fps;
extern gboolean debug_frames; extern gboolean debug_frames;
typedef struct Panel { typedef struct Panel {
Area area; Area area;
Window main_win; Window main_win;
Pixmap temp_pmap; Pixmap temp_pmap;
// position relative to root window // position relative to root window
int posx, posy; int posx, posy;
int marginx, marginy; int marginx, marginy;
gboolean fractional_width, fractional_height; gboolean fractional_width, fractional_height;
int max_size; int max_size;
int monitor; int monitor;
int font_shadow; int font_shadow;
gboolean mouse_effects; gboolean mouse_effects;
// Mouse effects for icons // Mouse effects for icons
int mouse_over_alpha; int mouse_over_alpha;
int mouse_over_saturation; int mouse_over_saturation;
int mouse_over_brightness; int mouse_over_brightness;
int mouse_pressed_alpha; int mouse_pressed_alpha;
int mouse_pressed_saturation; int mouse_pressed_saturation;
int mouse_pressed_brightness; int mouse_pressed_brightness;
// Per-panel parameters and states for Taskbar and Task // Per-panel parameters and states for Taskbar and Task
GlobalTaskbar g_taskbar; GlobalTaskbar g_taskbar;
GlobalTask g_task; GlobalTask g_task;
// Array of Taskbar, with num_desktops items // Array of Taskbar, with num_desktops items
Taskbar *taskbar; Taskbar *taskbar;
int num_desktops; int num_desktops;
gboolean taskbarname_has_font; gboolean taskbarname_has_font;
PangoFontDescription *taskbarname_font_desc; PangoFontDescription *taskbarname_font_desc;
Clock clock; Clock clock;
#ifdef ENABLE_BATTERY #ifdef ENABLE_BATTERY
Battery battery; Battery battery;
#endif #endif
Launcher launcher; Launcher launcher;
GList *freespace_list; GList *freespace_list;
GList *separator_list; GList *separator_list;
GList *execp_list; GList *execp_list;
GList *button_list; GList *button_list;
// Autohide // Autohide
gboolean is_hidden; gboolean is_hidden;
int hidden_width, hidden_height; int hidden_width, hidden_height;
Pixmap hidden_pixmap; Pixmap hidden_pixmap;
timeout *autohide_timeout; timeout *autohide_timeout;
} Panel; } Panel;
extern Panel panel_config; extern Panel panel_config;

View File

@@ -19,132 +19,132 @@ int separator_compute_desired_size(void *obj);
Separator *create_separator() Separator *create_separator()
{ {
Separator *separator = (Separator *)calloc(1, sizeof(Separator)); Separator *separator = (Separator *)calloc(1, sizeof(Separator));
separator->color.rgb[0] = 0.5; separator->color.rgb[0] = 0.5;
separator->color.rgb[1] = 0.5; separator->color.rgb[1] = 0.5;
separator->color.rgb[2] = 0.5; separator->color.rgb[2] = 0.5;
separator->color.alpha = 0.9; separator->color.alpha = 0.9;
separator->style = SEPARATOR_DOTS; separator->style = SEPARATOR_DOTS;
separator->thickness = 3; separator->thickness = 3;
separator->area.paddingxlr = 1; separator->area.paddingxlr = 1;
return separator; return separator;
} }
void destroy_separator(void *obj) void destroy_separator(void *obj)
{ {
Separator *separator = (Separator *)obj; Separator *separator = (Separator *)obj;
remove_area(&separator->area); remove_area(&separator->area);
free_area(&separator->area); free_area(&separator->area);
free_and_null(separator); free_and_null(separator);
} }
gpointer copy_separator(gconstpointer arg, gpointer data) gpointer copy_separator(gconstpointer arg, gpointer data)
{ {
Separator *old = (Separator *)arg; Separator *old = (Separator *)arg;
Separator *copy = (Separator *)calloc(1, sizeof(Separator)); Separator *copy = (Separator *)calloc(1, sizeof(Separator));
memcpy(copy, old, sizeof(Separator)); memcpy(copy, old, sizeof(Separator));
return copy; return copy;
} }
void init_separator() void init_separator()
{ {
GList *to_remove = panel_config.separator_list; GList *to_remove = panel_config.separator_list;
for (int k = 0; k < strlen(panel_items_order) && to_remove; k++) { for (int k = 0; k < strlen(panel_items_order) && to_remove; k++) {
if (panel_items_order[k] == ':') { if (panel_items_order[k] == ':') {
to_remove = to_remove->next; to_remove = to_remove->next;
} }
} }
if (to_remove) { if (to_remove) {
if (to_remove == panel_config.separator_list) { if (to_remove == panel_config.separator_list) {
g_list_free_full(to_remove, destroy_separator); g_list_free_full(to_remove, destroy_separator);
panel_config.separator_list = NULL; panel_config.separator_list = NULL;
} else { } else {
// Cut panel_config.separator_list // Cut panel_config.separator_list
if (to_remove->prev) if (to_remove->prev)
to_remove->prev->next = NULL; to_remove->prev->next = NULL;
to_remove->prev = NULL; to_remove->prev = NULL;
// Remove all elements of to_remove and to_remove itself // Remove all elements of to_remove and to_remove itself
g_list_free_full(to_remove, destroy_separator); g_list_free_full(to_remove, destroy_separator);
} }
} }
} }
void init_separator_panel(void *p) void init_separator_panel(void *p)
{ {
Panel *panel = (Panel *)p; Panel *panel = (Panel *)p;
// Make sure this is only done once if there are multiple items // Make sure this is only done once if there are multiple items
if (panel->separator_list) if (panel->separator_list)
return; return;
// panel->separator_list is now a copy of the pointer panel_config.separator_list // panel->separator_list is now a copy of the pointer panel_config.separator_list
// We make it a deep copy // We make it a deep copy
panel->separator_list = g_list_copy_deep(panel_config.separator_list, copy_separator, NULL); panel->separator_list = g_list_copy_deep(panel_config.separator_list, copy_separator, NULL);
for (GList *l = panel->separator_list; l; l = l->next) { for (GList *l = panel->separator_list; l; l = l->next) {
Separator *separator = (Separator *)l->data; Separator *separator = (Separator *)l->data;
if (!separator->area.bg) if (!separator->area.bg)
separator->area.bg = &g_array_index(backgrounds, Background, 0); separator->area.bg = &g_array_index(backgrounds, Background, 0);
separator->area.parent = p; separator->area.parent = p;
separator->area.panel = p; separator->area.panel = p;
snprintf(separator->area.name, sizeof(separator->area.name), "separator"); snprintf(separator->area.name, sizeof(separator->area.name), "separator");
separator->area.size_mode = LAYOUT_FIXED; separator->area.size_mode = LAYOUT_FIXED;
separator->area.resize_needed = 1; separator->area.resize_needed = 1;
separator->area.on_screen = TRUE; separator->area.on_screen = TRUE;
separator->area._resize = resize_separator; separator->area._resize = resize_separator;
separator->area._compute_desired_size = separator_compute_desired_size; separator->area._compute_desired_size = separator_compute_desired_size;
separator->area._draw_foreground = draw_separator; separator->area._draw_foreground = draw_separator;
instantiate_area_gradients(&separator->area); instantiate_area_gradients(&separator->area);
} }
} }
void cleanup_separator() void cleanup_separator()
{ {
// Cleanup frontends // Cleanup frontends
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
g_list_free_full(panels[i].separator_list, destroy_separator); g_list_free_full(panels[i].separator_list, destroy_separator);
panels[i].separator_list = NULL; panels[i].separator_list = NULL;
} }
// Cleanup backends // Cleanup backends
g_list_free_full(panel_config.separator_list, destroy_separator); g_list_free_full(panel_config.separator_list, destroy_separator);
panel_config.separator_list = NULL; panel_config.separator_list = NULL;
} }
int separator_compute_desired_size(void *obj) int separator_compute_desired_size(void *obj)
{ {
Separator *separator = (Separator *)obj; Separator *separator = (Separator *)obj;
if (!separator->area.on_screen) if (!separator->area.on_screen)
return 0; return 0;
if (panel_horizontal) if (panel_horizontal)
return separator->thickness + 2 * separator->area.paddingxlr + left_right_border_width(&separator->area); return separator->thickness + 2 * separator->area.paddingxlr + left_right_border_width(&separator->area);
else else
return separator->thickness + 2 * separator->area.paddingxlr + top_bottom_border_width(&separator->area); return separator->thickness + 2 * separator->area.paddingxlr + top_bottom_border_width(&separator->area);
} }
gboolean resize_separator(void *obj) gboolean resize_separator(void *obj)
{ {
Separator *separator = (Separator *)obj; Separator *separator = (Separator *)obj;
if (!separator->area.on_screen) if (!separator->area.on_screen)
return FALSE; return FALSE;
if (panel_horizontal) { if (panel_horizontal) {
separator->area.width = separator->area.width =
separator->thickness + 2 * separator->area.paddingxlr + left_right_border_width(&separator->area); separator->thickness + 2 * separator->area.paddingxlr + left_right_border_width(&separator->area);
separator->length = separator->length =
separator->area.height - 2 * separator->area.paddingy - top_bottom_border_width(&separator->area); separator->area.height - 2 * separator->area.paddingy - top_bottom_border_width(&separator->area);
} else { } else {
separator->area.height = separator->area.height =
separator->thickness + 2 * separator->area.paddingxlr + top_bottom_border_width(&separator->area); separator->thickness + 2 * separator->area.paddingxlr + top_bottom_border_width(&separator->area);
separator->length = separator->length =
separator->area.width - 2 * separator->area.paddingy - left_right_border_width(&separator->area); separator->area.width - 2 * separator->area.paddingy - left_right_border_width(&separator->area);
} }
schedule_redraw(&separator->area); schedule_redraw(&separator->area);
schedule_panel_redraw(); schedule_panel_redraw();
return TRUE; return TRUE;
} }
void draw_separator_line(void *obj, cairo_t *c); void draw_separator_line(void *obj, cairo_t *c);
@@ -152,80 +152,80 @@ void draw_separator_dots(void *obj, cairo_t *c);
void draw_separator(void *obj, cairo_t *c) void draw_separator(void *obj, cairo_t *c)
{ {
Separator *separator = (Separator *)obj; Separator *separator = (Separator *)obj;
if (separator->style == SEPARATOR_EMPTY) if (separator->style == SEPARATOR_EMPTY)
return; return;
else if (separator->style == SEPARATOR_LINE) else if (separator->style == SEPARATOR_LINE)
draw_separator_line(separator, c); draw_separator_line(separator, c);
else if (separator->style == SEPARATOR_DOTS) else if (separator->style == SEPARATOR_DOTS)
draw_separator_dots(separator, c); draw_separator_dots(separator, c);
} }
void draw_separator_line(void *obj, cairo_t *c) void draw_separator_line(void *obj, cairo_t *c)
{ {
Separator *separator = (Separator *)obj; Separator *separator = (Separator *)obj;
if (separator->thickness <= 0) if (separator->thickness <= 0)
return; return;
cairo_set_source_rgba(c, cairo_set_source_rgba(c,
separator->color.rgb[0], separator->color.rgb[0],
separator->color.rgb[1], separator->color.rgb[1],
separator->color.rgb[2], separator->color.rgb[2],
separator->color.alpha); separator->color.alpha);
cairo_set_line_width(c, separator->thickness); cairo_set_line_width(c, separator->thickness);
cairo_set_line_cap(c, CAIRO_LINE_CAP_ROUND); cairo_set_line_cap(c, CAIRO_LINE_CAP_ROUND);
if (panel_horizontal) { if (panel_horizontal) {
cairo_move_to(c, separator->area.width / 2.0, separator->area.height / 2.0 - separator->length / 2.0); cairo_move_to(c, separator->area.width / 2.0, separator->area.height / 2.0 - separator->length / 2.0);
cairo_line_to(c, separator->area.width / 2.0, separator->area.height / 2.0 + separator->length / 2.0); cairo_line_to(c, separator->area.width / 2.0, separator->area.height / 2.0 + separator->length / 2.0);
} else { } else {
cairo_move_to(c, separator->area.width / 2.0 - separator->length / 2.0, separator->area.height / 2.0); cairo_move_to(c, separator->area.width / 2.0 - separator->length / 2.0, separator->area.height / 2.0);
cairo_line_to(c, separator->area.width / 2.0 + separator->length / 2.0, separator->area.height / 2.0); cairo_line_to(c, separator->area.width / 2.0 + separator->length / 2.0, separator->area.height / 2.0);
} }
cairo_stroke(c); cairo_stroke(c);
} }
void draw_separator_dots(void *obj, cairo_t *c) void draw_separator_dots(void *obj, cairo_t *c)
{ {
const double PI = 3.14159265359; const double PI = 3.14159265359;
Separator *separator = (Separator *)obj; Separator *separator = (Separator *)obj;
if (separator->thickness <= 0) if (separator->thickness <= 0)
return; return;
cairo_set_source_rgba(c, cairo_set_source_rgba(c,
separator->color.rgb[0], separator->color.rgb[0],
separator->color.rgb[1], separator->color.rgb[1],
separator->color.rgb[2], separator->color.rgb[2],
separator->color.alpha); separator->color.alpha);
cairo_set_line_width(c, 0); cairo_set_line_width(c, 0);
int num_circles = separator->length / (1.618 * separator->thickness - 1); int num_circles = separator->length / (1.618 * separator->thickness - 1);
double spacing = (separator->length - num_circles * separator->thickness) / MAX(1.0, num_circles - 1.0); double spacing = (separator->length - num_circles * separator->thickness) / MAX(1.0, num_circles - 1.0);
if (spacing > separator->thickness) if (spacing > separator->thickness)
num_circles++; num_circles++;
spacing = (separator->length - num_circles * separator->thickness) / MAX(1.0, num_circles - 1.0); spacing = (separator->length - num_circles * separator->thickness) / MAX(1.0, num_circles - 1.0);
double offset = (panel_horizontal ? separator->area.height : separator->area.width) / 2.0 - separator->length / 2.0; double offset = (panel_horizontal ? separator->area.height : separator->area.width) / 2.0 - separator->length / 2.0;
if (num_circles == 1) if (num_circles == 1)
offset += spacing / 2.0; offset += spacing / 2.0;
for (int i = 0; i < num_circles; i++) { for (int i = 0; i < num_circles; i++) {
if (panel_horizontal) { if (panel_horizontal) {
cairo_arc(c, cairo_arc(c,
separator->area.width / 2.0, separator->area.width / 2.0,
offset + separator->thickness / 2.0, offset + separator->thickness / 2.0,
separator->thickness / 2.0, separator->thickness / 2.0,
0, 0,
2 * PI); 2 * PI);
} else { } else {
cairo_arc(c, cairo_arc(c,
offset + separator->thickness / 2.0, offset + separator->thickness / 2.0,
separator->area.height / 2.0, separator->area.height / 2.0,
separator->thickness / 2.0, separator->thickness / 2.0,
0, 0,
2 * PI); 2 * PI);
} }
cairo_stroke_preserve(c); cairo_stroke_preserve(c);
cairo_fill(c); cairo_fill(c);
offset += separator->thickness + spacing; offset += separator->thickness + spacing;
} }
} }

View File

@@ -7,18 +7,14 @@
#include "common.h" #include "common.h"
#include "area.h" #include "area.h"
typedef enum SeparatorStyle { typedef enum SeparatorStyle { SEPARATOR_EMPTY = 0, SEPARATOR_LINE, SEPARATOR_DOTS } SeparatorStyle;
SEPARATOR_EMPTY = 0,
SEPARATOR_LINE,
SEPARATOR_DOTS
} SeparatorStyle;
typedef struct Separator { typedef struct Separator {
Area area; Area area;
SeparatorStyle style; SeparatorStyle style;
Color color; Color color;
int thickness; int thickness;
int length; int length;
} Separator; } Separator;
Separator *create_separator(); Separator *create_separator();

File diff suppressed because it is too large Load Diff

View File

@@ -21,123 +21,123 @@
extern gboolean primary_monitor_first; extern gboolean primary_monitor_first;
typedef struct Global_atom { typedef struct Global_atom {
Atom _XROOTPMAP_ID; Atom _XROOTPMAP_ID;
Atom _XROOTMAP_ID; Atom _XROOTMAP_ID;
Atom _NET_CURRENT_DESKTOP; Atom _NET_CURRENT_DESKTOP;
Atom _NET_NUMBER_OF_DESKTOPS; Atom _NET_NUMBER_OF_DESKTOPS;
Atom _NET_DESKTOP_NAMES; Atom _NET_DESKTOP_NAMES;
Atom _NET_DESKTOP_GEOMETRY; Atom _NET_DESKTOP_GEOMETRY;
Atom _NET_DESKTOP_VIEWPORT; Atom _NET_DESKTOP_VIEWPORT;
Atom _NET_WORKAREA; Atom _NET_WORKAREA;
Atom _NET_ACTIVE_WINDOW; Atom _NET_ACTIVE_WINDOW;
Atom _NET_WM_WINDOW_TYPE; Atom _NET_WM_WINDOW_TYPE;
Atom _NET_WM_STATE_SKIP_PAGER; Atom _NET_WM_STATE_SKIP_PAGER;
Atom _NET_WM_STATE_SKIP_TASKBAR; Atom _NET_WM_STATE_SKIP_TASKBAR;
Atom _NET_WM_STATE_STICKY; Atom _NET_WM_STATE_STICKY;
Atom _NET_WM_STATE_DEMANDS_ATTENTION; Atom _NET_WM_STATE_DEMANDS_ATTENTION;
Atom _NET_WM_WINDOW_TYPE_DOCK; Atom _NET_WM_WINDOW_TYPE_DOCK;
Atom _NET_WM_WINDOW_TYPE_DESKTOP; Atom _NET_WM_WINDOW_TYPE_DESKTOP;
Atom _NET_WM_WINDOW_TYPE_TOOLBAR; Atom _NET_WM_WINDOW_TYPE_TOOLBAR;
Atom _NET_WM_WINDOW_TYPE_MENU; Atom _NET_WM_WINDOW_TYPE_MENU;
Atom _NET_WM_WINDOW_TYPE_SPLASH; Atom _NET_WM_WINDOW_TYPE_SPLASH;
Atom _NET_WM_WINDOW_TYPE_DIALOG; Atom _NET_WM_WINDOW_TYPE_DIALOG;
Atom _NET_WM_WINDOW_TYPE_NORMAL; Atom _NET_WM_WINDOW_TYPE_NORMAL;
Atom _NET_WM_DESKTOP; Atom _NET_WM_DESKTOP;
Atom WM_STATE; Atom WM_STATE;
Atom _NET_WM_STATE; Atom _NET_WM_STATE;
Atom _NET_WM_STATE_MAXIMIZED_VERT; Atom _NET_WM_STATE_MAXIMIZED_VERT;
Atom _NET_WM_STATE_MAXIMIZED_HORZ; Atom _NET_WM_STATE_MAXIMIZED_HORZ;
Atom _NET_WM_STATE_SHADED; Atom _NET_WM_STATE_SHADED;
Atom _NET_WM_STATE_HIDDEN; Atom _NET_WM_STATE_HIDDEN;
Atom _NET_WM_STATE_BELOW; Atom _NET_WM_STATE_BELOW;
Atom _NET_WM_STATE_ABOVE; Atom _NET_WM_STATE_ABOVE;
Atom _NET_WM_STATE_MODAL; Atom _NET_WM_STATE_MODAL;
Atom _NET_CLIENT_LIST; Atom _NET_CLIENT_LIST;
Atom _NET_WM_NAME; Atom _NET_WM_NAME;
Atom _NET_WM_VISIBLE_NAME; Atom _NET_WM_VISIBLE_NAME;
Atom _NET_WM_STRUT; Atom _NET_WM_STRUT;
Atom _NET_WM_ICON; Atom _NET_WM_ICON;
Atom _NET_WM_ICON_GEOMETRY; Atom _NET_WM_ICON_GEOMETRY;
Atom _NET_WM_ICON_NAME; Atom _NET_WM_ICON_NAME;
Atom _NET_CLOSE_WINDOW; Atom _NET_CLOSE_WINDOW;
Atom UTF8_STRING; Atom UTF8_STRING;
Atom _NET_SUPPORTING_WM_CHECK; Atom _NET_SUPPORTING_WM_CHECK;
Atom _NET_WM_CM_S0; Atom _NET_WM_CM_S0;
Atom _NET_WM_STRUT_PARTIAL; Atom _NET_WM_STRUT_PARTIAL;
Atom WM_NAME; Atom WM_NAME;
Atom __SWM_VROOT; Atom __SWM_VROOT;
Atom _MOTIF_WM_HINTS; Atom _MOTIF_WM_HINTS;
Atom WM_HINTS; Atom WM_HINTS;
Atom _NET_SYSTEM_TRAY_SCREEN; Atom _NET_SYSTEM_TRAY_SCREEN;
Atom _NET_SYSTEM_TRAY_OPCODE; Atom _NET_SYSTEM_TRAY_OPCODE;
Atom MANAGER; Atom MANAGER;
Atom _NET_SYSTEM_TRAY_MESSAGE_DATA; Atom _NET_SYSTEM_TRAY_MESSAGE_DATA;
Atom _NET_SYSTEM_TRAY_ORIENTATION; Atom _NET_SYSTEM_TRAY_ORIENTATION;
Atom _NET_SYSTEM_TRAY_ICON_SIZE; Atom _NET_SYSTEM_TRAY_ICON_SIZE;
Atom _NET_SYSTEM_TRAY_PADDING; Atom _NET_SYSTEM_TRAY_PADDING;
Atom _XEMBED; Atom _XEMBED;
Atom _XEMBED_INFO; Atom _XEMBED_INFO;
Atom _NET_WM_PID; Atom _NET_WM_PID;
Atom _XSETTINGS_SCREEN; Atom _XSETTINGS_SCREEN;
Atom _XSETTINGS_SETTINGS; Atom _XSETTINGS_SETTINGS;
Atom XdndAware; Atom XdndAware;
Atom XdndEnter; Atom XdndEnter;
Atom XdndPosition; Atom XdndPosition;
Atom XdndStatus; Atom XdndStatus;
Atom XdndDrop; Atom XdndDrop;
Atom XdndLeave; Atom XdndLeave;
Atom XdndSelection; Atom XdndSelection;
Atom XdndTypeList; Atom XdndTypeList;
Atom XdndActionCopy; Atom XdndActionCopy;
Atom XdndFinished; Atom XdndFinished;
Atom TARGETS; Atom TARGETS;
} Global_atom; } Global_atom;
typedef struct Monitor { typedef struct Monitor {
int x; int x;
int y; int y;
int width; int width;
int height; int height;
gboolean primary; gboolean primary;
gchar **names; gchar **names;
} Monitor; } Monitor;
typedef struct Viewport { typedef struct Viewport {
int x; int x;
int y; int y;
int width; int width;
int height; int height;
} Viewport; } Viewport;
typedef struct Server { typedef struct Server {
Display *display; Display *display;
Window root_win; Window root_win;
Window composite_manager; Window composite_manager;
gboolean real_transparency; gboolean real_transparency;
gboolean disable_transparency; gboolean disable_transparency;
// current desktop // current desktop
int desktop; int desktop;
int screen; int screen;
int depth; int depth;
int num_desktops; int num_desktops;
// number of monitor (without monitor included into another one) // number of monitor (without monitor included into another one)
int num_monitors; int num_monitors;
// Non-null only if WM uses viewports (compiz) and number of viewports > 1. // Non-null only if WM uses viewports (compiz) and number of viewports > 1.
// In that case there are num_desktops viewports. // In that case there are num_desktops viewports.
Viewport *viewports; Viewport *viewports;
Monitor *monitors; Monitor *monitors;
gboolean got_root_win; gboolean got_root_win;
Visual *visual; Visual *visual;
Visual *visual32; Visual *visual32;
// root background // root background
Pixmap root_pmap; Pixmap root_pmap;
GC gc; GC gc;
Colormap colormap; Colormap colormap;
Colormap colormap32; Colormap colormap32;
Global_atom atom; Global_atom atom;
#ifdef HAVE_SN #ifdef HAVE_SN
SnDisplay *sn_display; SnDisplay *sn_display;
GTree *pids; GTree *pids;
#endif // HAVE_SN #endif // HAVE_SN
} Server; } Server;

File diff suppressed because it is too large Load Diff

View File

@@ -21,50 +21,50 @@
#define XEMBED_MAPPED (1 << 0) #define XEMBED_MAPPED (1 << 0)
typedef enum SystraySortMethod { typedef enum SystraySortMethod {
SYSTRAY_SORT_ASCENDING = 0, SYSTRAY_SORT_ASCENDING = 0,
SYSTRAY_SORT_DESCENDING, SYSTRAY_SORT_DESCENDING,
SYSTRAY_SORT_LEFT2RIGHT, SYSTRAY_SORT_LEFT2RIGHT,
SYSTRAY_SORT_RIGHT2LEFT, SYSTRAY_SORT_RIGHT2LEFT,
} SystraySortMethod; } SystraySortMethod;
typedef struct { typedef struct {
// always start with area // always start with area
Area area; Area area;
GSList *list_icons; GSList *list_icons;
SystraySortMethod sort; SystraySortMethod sort;
int alpha, saturation, brightness; int alpha, saturation, brightness;
int icon_size, icons_per_column, icons_per_row, margin; int icon_size, icons_per_column, icons_per_row, margin;
} Systray; } Systray;
typedef struct { typedef struct {
// The actual tray icon window (created by the application) // The actual tray icon window (created by the application)
Window win; Window win;
// The parent window created by tint2 to embed the icon // The parent window created by tint2 to embed the icon
Window parent; Window parent;
int x, y; int x, y;
int width, height; int width, height;
int depth; int depth;
gboolean reparented; gboolean reparented;
gboolean embedded; gboolean embedded;
// Process PID or zero. // Process PID or zero.
int pid; int pid;
// A number that is incremented for each new icon, used to sort them by the order in which they were created. // A number that is incremented for each new icon, used to sort them by the order in which they were created.
int chrono; int chrono;
// Name of the tray icon window. // Name of the tray icon window.
char *name; char *name;
// Members used for rendering // Members used for rendering
struct timespec time_last_render; struct timespec time_last_render;
int num_fast_renders; int num_fast_renders;
timeout *render_timeout; timeout *render_timeout;
// Members used for resizing // Members used for resizing
int bad_size_counter; int bad_size_counter;
struct timespec time_last_resize; struct timespec time_last_resize;
timeout *resize_timeout; timeout *resize_timeout;
// Icon contents if we are compositing the icon, otherwise null // Icon contents if we are compositing the icon, otherwise null
Imlib_Image image; Imlib_Image image;
// XDamage // XDamage
Damage damage; Damage damage;
} TrayWindow; } TrayWindow;
// net_sel_win != None when protocol started // net_sel_win != None when protocol started

File diff suppressed because it is too large Load Diff

View File

@@ -14,65 +14,65 @@
#include "timer.h" #include "timer.h"
typedef enum TaskState { typedef enum TaskState {
TASK_NORMAL = 0, TASK_NORMAL = 0,
TASK_ACTIVE, TASK_ACTIVE,
TASK_ICONIFIED, TASK_ICONIFIED,
TASK_URGENT, TASK_URGENT,
TASK_UNDEFINED, TASK_UNDEFINED,
TASK_STATE_COUNT, TASK_STATE_COUNT,
} TaskState; } TaskState;
typedef struct GlobalTask { typedef struct GlobalTask {
Area area; Area area;
gboolean has_text; gboolean has_text;
gboolean has_icon; gboolean has_icon;
gboolean centered; gboolean centered;
int icon_posy; int icon_posy;
int icon_size1; int icon_size1;
int maximum_width; int maximum_width;
int maximum_height; int maximum_height;
int alpha[TASK_STATE_COUNT]; int alpha[TASK_STATE_COUNT];
int saturation[TASK_STATE_COUNT]; int saturation[TASK_STATE_COUNT];
int brightness[TASK_STATE_COUNT]; int brightness[TASK_STATE_COUNT];
int config_asb_mask; int config_asb_mask;
Background *background[TASK_STATE_COUNT]; Background *background[TASK_STATE_COUNT];
GList *gradient[TASK_STATE_COUNT]; GList *gradient[TASK_STATE_COUNT];
int config_background_mask; int config_background_mask;
// starting position for text ~ task_padding + task_border + icon_size // starting position for text ~ task_padding + task_border + icon_size
double text_posx, text_height; double text_posx, text_height;
gboolean has_font; gboolean has_font;
PangoFontDescription *font_desc; PangoFontDescription *font_desc;
Color font[TASK_STATE_COUNT]; Color font[TASK_STATE_COUNT];
int config_font_mask; int config_font_mask;
gboolean tooltip_enabled; gboolean tooltip_enabled;
} GlobalTask; } GlobalTask;
// Stores information about a task. // Stores information about a task.
// Warning: any dynamically allocated members are shared between the Task instances created for the same window // Warning: any dynamically allocated members are shared between the Task instances created for the same window
// (if the task appears on all desktops, there will be a different instance on each desktop's taskbar). // (if the task appears on all desktops, there will be a different instance on each desktop's taskbar).
typedef struct Task { typedef struct Task {
Area area; Area area;
Window win; Window win;
int desktop; int desktop;
TaskState current_state; TaskState current_state;
Imlib_Image icon[TASK_STATE_COUNT]; Imlib_Image icon[TASK_STATE_COUNT];
Imlib_Image icon_hover[TASK_STATE_COUNT]; Imlib_Image icon_hover[TASK_STATE_COUNT];
Imlib_Image icon_press[TASK_STATE_COUNT]; Imlib_Image icon_press[TASK_STATE_COUNT];
unsigned int icon_width; unsigned int icon_width;
unsigned int icon_height; unsigned int icon_height;
char *title; char *title;
int urgent_tick; int urgent_tick;
// These may not be up-to-date // These may not be up-to-date
int win_x; int win_x;
int win_y; int win_y;
int win_w; int win_w;
int win_h; int win_h;
struct timespec last_activation_time; struct timespec last_activation_time;
int _text_width; int _text_width;
int _text_height; int _text_height;
double _text_posy; double _text_posy;
int _icon_x; int _icon_x;
int _icon_y; int _icon_y;
} Task; } Task;
extern timeout *urgent_timeout; extern timeout *urgent_timeout;

File diff suppressed because it is too large Load Diff

View File

@@ -12,39 +12,39 @@
#include "taskbarname.h" #include "taskbarname.h"
typedef enum TaskbarState { typedef enum TaskbarState {
TASKBAR_NORMAL = 0, TASKBAR_NORMAL = 0,
TASKBAR_ACTIVE, TASKBAR_ACTIVE,
TASKBAR_STATE_COUNT, TASKBAR_STATE_COUNT,
} TaskbarState; } TaskbarState;
typedef enum TaskbarSortMethod { typedef enum TaskbarSortMethod {
TASKBAR_NOSORT = 0, TASKBAR_NOSORT = 0,
TASKBAR_SORT_CENTER, TASKBAR_SORT_CENTER,
TASKBAR_SORT_TITLE, TASKBAR_SORT_TITLE,
TASKBAR_SORT_LRU, TASKBAR_SORT_LRU,
TASKBAR_SORT_MRU, TASKBAR_SORT_MRU,
} TaskbarSortMethod; } TaskbarSortMethod;
typedef struct { typedef struct {
Area area; Area area;
gchar *name; gchar *name;
int posy; int posy;
} TaskbarName; } TaskbarName;
typedef struct { typedef struct {
Area area; Area area;
int desktop; int desktop;
TaskbarName bar_name; TaskbarName bar_name;
int text_width; int text_width;
} Taskbar; } Taskbar;
typedef struct GlobalTaskbar { typedef struct GlobalTaskbar {
Area area; Area area;
Area area_name; Area area_name;
Background *background[TASKBAR_STATE_COUNT]; Background *background[TASKBAR_STATE_COUNT];
Background *background_name[TASKBAR_STATE_COUNT]; Background *background_name[TASKBAR_STATE_COUNT];
GList *gradient[TASKBAR_STATE_COUNT]; GList *gradient[TASKBAR_STATE_COUNT];
GList *gradient_name[TASKBAR_STATE_COUNT]; GList *gradient_name[TASKBAR_STATE_COUNT];
} GlobalTaskbar; } GlobalTaskbar;
extern gboolean taskbar_enabled; extern gboolean taskbar_enabled;

View File

@@ -41,176 +41,176 @@ int taskbarname_compute_desired_size(void *obj);
void default_taskbarname() void default_taskbarname()
{ {
taskbarname_enabled = FALSE; taskbarname_enabled = FALSE;
} }
void init_taskbarname_panel(void *p) void init_taskbarname_panel(void *p)
{ {
if (!taskbarname_enabled) if (!taskbarname_enabled)
return; return;
Panel *panel = (Panel *)p; Panel *panel = (Panel *)p;
taskbarname_init_fonts(); taskbarname_init_fonts();
GSList *list = get_desktop_names(); GSList *list = get_desktop_names();
GSList *l = list; GSList *l = list;
for (int j = 0; j < panel->num_desktops; j++) { for (int j = 0; j < panel->num_desktops; j++) {
Taskbar *taskbar = &panel->taskbar[j]; Taskbar *taskbar = &panel->taskbar[j];
memcpy(&taskbar->bar_name.area, &panel->g_taskbar.area_name, sizeof(Area)); memcpy(&taskbar->bar_name.area, &panel->g_taskbar.area_name, sizeof(Area));
taskbar->bar_name.area.parent = taskbar; taskbar->bar_name.area.parent = taskbar;
taskbar->bar_name.area.has_mouse_over_effect = panel_config.mouse_effects; taskbar->bar_name.area.has_mouse_over_effect = panel_config.mouse_effects;
taskbar->bar_name.area.has_mouse_press_effect = panel_config.mouse_effects; taskbar->bar_name.area.has_mouse_press_effect = panel_config.mouse_effects;
taskbar->bar_name.area._compute_desired_size = taskbarname_compute_desired_size; taskbar->bar_name.area._compute_desired_size = taskbarname_compute_desired_size;
if (j == server.desktop) { if (j == server.desktop) {
taskbar->bar_name.area.bg = panel->g_taskbar.background_name[TASKBAR_ACTIVE]; taskbar->bar_name.area.bg = panel->g_taskbar.background_name[TASKBAR_ACTIVE];
} else { } else {
taskbar->bar_name.area.bg = panel->g_taskbar.background_name[TASKBAR_NORMAL]; taskbar->bar_name.area.bg = panel->g_taskbar.background_name[TASKBAR_NORMAL];
} }
// use desktop number if name is missing // use desktop number if name is missing
if (l) { if (l) {
taskbar->bar_name.name = g_strdup(l->data); taskbar->bar_name.name = g_strdup(l->data);
l = l->next; l = l->next;
} else { } else {
taskbar->bar_name.name = g_strdup_printf("%d", j + 1); taskbar->bar_name.name = g_strdup_printf("%d", j + 1);
} }
// append the name at the beginning of taskbar // append the name at the beginning of taskbar
taskbar->area.children = g_list_append(taskbar->area.children, &taskbar->bar_name); taskbar->area.children = g_list_append(taskbar->area.children, &taskbar->bar_name);
instantiate_area_gradients(&taskbar->bar_name.area); instantiate_area_gradients(&taskbar->bar_name.area);
} }
for (l = list; l; l = l->next) for (l = list; l; l = l->next)
g_free(l->data); g_free(l->data);
g_slist_free(list); g_slist_free(list);
} }
void taskbarname_init_fonts() void taskbarname_init_fonts()
{ {
if (!panel_config.taskbarname_font_desc) { if (!panel_config.taskbarname_font_desc) {
panel_config.taskbarname_font_desc = pango_font_description_from_string(get_default_font()); panel_config.taskbarname_font_desc = pango_font_description_from_string(get_default_font());
pango_font_description_set_weight(panel_config.taskbarname_font_desc, PANGO_WEIGHT_BOLD); pango_font_description_set_weight(panel_config.taskbarname_font_desc, PANGO_WEIGHT_BOLD);
} }
} }
void taskbarname_default_font_changed() void taskbarname_default_font_changed()
{ {
if (!taskbar_enabled) if (!taskbar_enabled)
return; return;
if (!taskbarname_enabled) if (!taskbarname_enabled)
return; return;
if (panel_config.taskbarname_has_font) if (panel_config.taskbarname_has_font)
return; return;
pango_font_description_free(panel_config.taskbarname_font_desc); pango_font_description_free(panel_config.taskbarname_font_desc);
panel_config.taskbarname_font_desc = NULL; panel_config.taskbarname_font_desc = NULL;
taskbarname_init_fonts(); taskbarname_init_fonts();
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
for (int j = 0; j < panels[i].num_desktops; j++) { for (int j = 0; j < panels[i].num_desktops; j++) {
Taskbar *taskbar = &panels[i].taskbar[j]; Taskbar *taskbar = &panels[i].taskbar[j];
taskbar->bar_name.area.resize_needed = TRUE; taskbar->bar_name.area.resize_needed = TRUE;
schedule_redraw(&taskbar->bar_name.area); schedule_redraw(&taskbar->bar_name.area);
} }
} }
schedule_panel_redraw(); schedule_panel_redraw();
} }
void cleanup_taskbarname() void cleanup_taskbarname()
{ {
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
Panel *panel = &panels[i]; Panel *panel = &panels[i];
for (int j = 0; j < panel->num_desktops; j++) { for (int j = 0; j < panel->num_desktops; j++) {
Taskbar *taskbar = &panel->taskbar[j]; Taskbar *taskbar = &panel->taskbar[j];
g_free(taskbar->bar_name.name); g_free(taskbar->bar_name.name);
taskbar->bar_name.name = NULL; taskbar->bar_name.name = NULL;
free_area(&taskbar->bar_name.area); free_area(&taskbar->bar_name.area);
remove_area((Area *)&taskbar->bar_name); remove_area((Area *)&taskbar->bar_name);
} }
} }
} }
int taskbarname_compute_desired_size(void *obj) int taskbarname_compute_desired_size(void *obj)
{ {
TaskbarName *taskbar_name = (TaskbarName *)obj; TaskbarName *taskbar_name = (TaskbarName *)obj;
Panel *panel = (Panel *)taskbar_name->area.panel; Panel *panel = (Panel *)taskbar_name->area.panel;
int name_height, name_width, name_height_ink; int name_height, name_width, name_height_ink;
get_text_size2(panel_config.taskbarname_font_desc, get_text_size2(panel_config.taskbarname_font_desc,
&name_height_ink, &name_height_ink,
&name_height, &name_height,
&name_width, &name_width,
panel->area.height, panel->area.height,
panel->area.width, panel->area.width,
taskbar_name->name, taskbar_name->name,
strlen(taskbar_name->name), strlen(taskbar_name->name),
PANGO_WRAP_WORD_CHAR, PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE, PANGO_ELLIPSIZE_NONE,
FALSE); FALSE);
if (panel_horizontal) { if (panel_horizontal) {
return name_width + 2 * taskbar_name->area.paddingxlr + left_right_border_width(&taskbar_name->area); return name_width + 2 * taskbar_name->area.paddingxlr + left_right_border_width(&taskbar_name->area);
} else { } else {
return name_height + 2 * taskbar_name->area.paddingxlr + top_bottom_border_width(&taskbar_name->area); return name_height + 2 * taskbar_name->area.paddingxlr + top_bottom_border_width(&taskbar_name->area);
} }
} }
gboolean resize_taskbarname(void *obj) gboolean resize_taskbarname(void *obj)
{ {
TaskbarName *taskbar_name = (TaskbarName *)obj; TaskbarName *taskbar_name = (TaskbarName *)obj;
Panel *panel = (Panel *)taskbar_name->area.panel; Panel *panel = (Panel *)taskbar_name->area.panel;
schedule_redraw(&taskbar_name->area); schedule_redraw(&taskbar_name->area);
int name_height, name_width, name_height_ink; int name_height, name_width, name_height_ink;
get_text_size2(panel_config.taskbarname_font_desc, get_text_size2(panel_config.taskbarname_font_desc,
&name_height_ink, &name_height_ink,
&name_height, &name_height,
&name_width, &name_width,
panel->area.height, panel->area.height,
panel->area.width, panel->area.width,
taskbar_name->name, taskbar_name->name,
strlen(taskbar_name->name), strlen(taskbar_name->name),
PANGO_WRAP_WORD_CHAR, PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE, PANGO_ELLIPSIZE_NONE,
FALSE); FALSE);
gboolean result = FALSE; gboolean result = FALSE;
int new_size = taskbarname_compute_desired_size(obj); int new_size = taskbarname_compute_desired_size(obj);
if (panel_horizontal) { if (panel_horizontal) {
if (new_size != taskbar_name->area.width) { if (new_size != taskbar_name->area.width) {
taskbar_name->area.width = new_size; taskbar_name->area.width = new_size;
taskbar_name->posy = (taskbar_name->area.height - name_height) / 2; taskbar_name->posy = (taskbar_name->area.height - name_height) / 2;
result = TRUE; result = TRUE;
} }
} else { } else {
if (new_size != taskbar_name->area.height) { if (new_size != taskbar_name->area.height) {
taskbar_name->area.height = new_size; taskbar_name->area.height = new_size;
taskbar_name->posy = (taskbar_name->area.height - name_height) / 2; taskbar_name->posy = (taskbar_name->area.height - name_height) / 2;
result = TRUE; result = TRUE;
} }
} }
return result; return result;
} }
void draw_taskbarname(void *obj, cairo_t *c) void draw_taskbarname(void *obj, cairo_t *c)
{ {
TaskbarName *taskbar_name = obj; TaskbarName *taskbar_name = obj;
Taskbar *taskbar = taskbar_name->area.parent; Taskbar *taskbar = taskbar_name->area.parent;
Color *config_text = (taskbar->desktop == server.desktop) ? &taskbarname_active_font : &taskbarname_font; Color *config_text = (taskbar->desktop == server.desktop) ? &taskbarname_active_font : &taskbarname_font;
// draw content // draw content
PangoLayout *layout = pango_cairo_create_layout(c); PangoLayout *layout = pango_cairo_create_layout(c);
pango_layout_set_font_description(layout, panel_config.taskbarname_font_desc); pango_layout_set_font_description(layout, panel_config.taskbarname_font_desc);
pango_layout_set_width(layout, taskbar_name->area.width * PANGO_SCALE); pango_layout_set_width(layout, taskbar_name->area.width * PANGO_SCALE);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_set_text(layout, taskbar_name->name, strlen(taskbar_name->name)); pango_layout_set_text(layout, taskbar_name->name, strlen(taskbar_name->name));
cairo_set_source_rgba(c, config_text->rgb[0], config_text->rgb[1], config_text->rgb[2], config_text->alpha); cairo_set_source_rgba(c, config_text->rgb[0], config_text->rgb[1], config_text->rgb[2], config_text->alpha);
pango_cairo_update_layout(c, layout); pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, taskbar_name->posy, config_text, ((Panel *)taskbar_name->area.panel)->font_shadow); draw_text(layout, c, 0, taskbar_name->posy, config_text, ((Panel *)taskbar_name->area.panel)->font_shadow);
g_object_unref(layout); g_object_unref(layout);
} }

3449
src/tint.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -22,23 +22,23 @@ void gradient_stop_update_image(int index);
void current_gradient_stop_changed(GtkWidget *widget, gpointer data); void current_gradient_stop_changed(GtkWidget *widget, gpointer data);
typedef enum GradientConfigType { typedef enum GradientConfigType {
GRADIENT_CONFIG_VERTICAL = 0, GRADIENT_CONFIG_VERTICAL = 0,
GRADIENT_CONFIG_HORIZONTAL, GRADIENT_CONFIG_HORIZONTAL,
GRADIENT_CONFIG_RADIAL GRADIENT_CONFIG_RADIAL
} GradientConfigType; } GradientConfigType;
typedef struct GradientConfigColorStop { typedef struct GradientConfigColorStop {
Color color; Color color;
// offset in 0-1 // offset in 0-1
double offset; double offset;
} GradientConfigColorStop; } GradientConfigColorStop;
typedef struct GradientConfig { typedef struct GradientConfig {
GradientConfigType type; GradientConfigType type;
GradientConfigColorStop start_color; GradientConfigColorStop start_color;
GradientConfigColorStop end_color; GradientConfigColorStop end_color;
// Each element is a GradientConfigColorStop // Each element is a GradientConfigColorStop
GList *extra_color_stops; GList *extra_color_stops;
} GradientConfig; } GradientConfig;
void gradient_create_new(GradientConfigType t); void gradient_create_new(GradientConfigType t);

File diff suppressed because it is too large Load Diff

View File

@@ -40,235 +40,232 @@ typedef u_int64_t u64;
#define shash_desc md4_ctx #define shash_desc md4_ctx
#define shash_desc_ctx(x) (x) #define shash_desc_ctx(x) (x)
#define MD4_DIGEST_SIZE 16 #define MD4_DIGEST_SIZE 16
#define MD4_HMAC_BLOCK_SIZE 64 #define MD4_HMAC_BLOCK_SIZE 64
#define MD4_BLOCK_WORDS 16 #define MD4_BLOCK_WORDS 16
#define MD4_HASH_WORDS 4 #define MD4_HASH_WORDS 4
struct md4_ctx { struct md4_ctx {
u32 hash[MD4_HASH_WORDS]; u32 hash[MD4_HASH_WORDS];
u32 block[MD4_BLOCK_WORDS]; u32 block[MD4_BLOCK_WORDS];
u64 byte_count; u64 byte_count;
}; };
static inline u32 lshift(u32 x, unsigned int s) static inline u32 lshift(u32 x, unsigned int s)
{ {
x &= 0xFFFFFFFF; x &= 0xFFFFFFFF;
return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
} }
static inline u32 F(u32 x, u32 y, u32 z) static inline u32 F(u32 x, u32 y, u32 z)
{ {
return (x & y) | ((~x) & z); return (x & y) | ((~x) & z);
} }
static inline u32 G(u32 x, u32 y, u32 z) static inline u32 G(u32 x, u32 y, u32 z)
{ {
return (x & y) | (x & z) | (y & z); return (x & y) | (x & z) | (y & z);
} }
static inline u32 H(u32 x, u32 y, u32 z) static inline u32 H(u32 x, u32 y, u32 z)
{ {
return x ^ y ^ z; return x ^ y ^ z;
} }
#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s)) #define ROUND1(a, b, c, d, k, s) (a = lshift(a + F(b, c, d) + k, s))
#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (u32)0x5A827999,s)) #define ROUND2(a, b, c, d, k, s) (a = lshift(a + G(b, c, d) + k + (u32)0x5A827999, s))
#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (u32)0x6ED9EBA1,s)) #define ROUND3(a, b, c, d, k, s) (a = lshift(a + H(b, c, d) + k + (u32)0x6ED9EBA1, s))
/* XXX: this stuff can be optimized */ /* XXX: this stuff can be optimized */
static inline void le32_to_cpu_array(u32 *buf, unsigned int words) static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
{ {
while (words--) { while (words--) {
*buf = ntohl(*buf); *buf = ntohl(*buf);
buf++; buf++;
} }
} }
static inline void cpu_to_le32_array(u32 *buf, unsigned int words) static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
{ {
while (words--) { while (words--) {
*buf = htonl(*buf); *buf = htonl(*buf);
buf++; buf++;
} }
} }
static void md4_transform(u32 *hash, u32 const *in) static void md4_transform(u32 *hash, u32 const *in)
{ {
u32 a, b, c, d; u32 a, b, c, d;
a = hash[0]; a = hash[0];
b = hash[1]; b = hash[1];
c = hash[2]; c = hash[2];
d = hash[3]; d = hash[3];
ROUND1(a, b, c, d, in[0], 3); ROUND1(a, b, c, d, in[0], 3);
ROUND1(d, a, b, c, in[1], 7); ROUND1(d, a, b, c, in[1], 7);
ROUND1(c, d, a, b, in[2], 11); ROUND1(c, d, a, b, in[2], 11);
ROUND1(b, c, d, a, in[3], 19); ROUND1(b, c, d, a, in[3], 19);
ROUND1(a, b, c, d, in[4], 3); ROUND1(a, b, c, d, in[4], 3);
ROUND1(d, a, b, c, in[5], 7); ROUND1(d, a, b, c, in[5], 7);
ROUND1(c, d, a, b, in[6], 11); ROUND1(c, d, a, b, in[6], 11);
ROUND1(b, c, d, a, in[7], 19); ROUND1(b, c, d, a, in[7], 19);
ROUND1(a, b, c, d, in[8], 3); ROUND1(a, b, c, d, in[8], 3);
ROUND1(d, a, b, c, in[9], 7); ROUND1(d, a, b, c, in[9], 7);
ROUND1(c, d, a, b, in[10], 11); ROUND1(c, d, a, b, in[10], 11);
ROUND1(b, c, d, a, in[11], 19); ROUND1(b, c, d, a, in[11], 19);
ROUND1(a, b, c, d, in[12], 3); ROUND1(a, b, c, d, in[12], 3);
ROUND1(d, a, b, c, in[13], 7); ROUND1(d, a, b, c, in[13], 7);
ROUND1(c, d, a, b, in[14], 11); ROUND1(c, d, a, b, in[14], 11);
ROUND1(b, c, d, a, in[15], 19); ROUND1(b, c, d, a, in[15], 19);
ROUND2(a, b, c, d,in[ 0], 3); ROUND2(a, b, c, d, in[0], 3);
ROUND2(d, a, b, c, in[4], 5); ROUND2(d, a, b, c, in[4], 5);
ROUND2(c, d, a, b, in[8], 9); ROUND2(c, d, a, b, in[8], 9);
ROUND2(b, c, d, a, in[12], 13); ROUND2(b, c, d, a, in[12], 13);
ROUND2(a, b, c, d, in[1], 3); ROUND2(a, b, c, d, in[1], 3);
ROUND2(d, a, b, c, in[5], 5); ROUND2(d, a, b, c, in[5], 5);
ROUND2(c, d, a, b, in[9], 9); ROUND2(c, d, a, b, in[9], 9);
ROUND2(b, c, d, a, in[13], 13); ROUND2(b, c, d, a, in[13], 13);
ROUND2(a, b, c, d, in[2], 3); ROUND2(a, b, c, d, in[2], 3);
ROUND2(d, a, b, c, in[6], 5); ROUND2(d, a, b, c, in[6], 5);
ROUND2(c, d, a, b, in[10], 9); ROUND2(c, d, a, b, in[10], 9);
ROUND2(b, c, d, a, in[14], 13); ROUND2(b, c, d, a, in[14], 13);
ROUND2(a, b, c, d, in[3], 3); ROUND2(a, b, c, d, in[3], 3);
ROUND2(d, a, b, c, in[7], 5); ROUND2(d, a, b, c, in[7], 5);
ROUND2(c, d, a, b, in[11], 9); ROUND2(c, d, a, b, in[11], 9);
ROUND2(b, c, d, a, in[15], 13); ROUND2(b, c, d, a, in[15], 13);
ROUND3(a, b, c, d,in[ 0], 3); ROUND3(a, b, c, d, in[0], 3);
ROUND3(d, a, b, c, in[8], 9); ROUND3(d, a, b, c, in[8], 9);
ROUND3(c, d, a, b, in[4], 11); ROUND3(c, d, a, b, in[4], 11);
ROUND3(b, c, d, a, in[12], 15); ROUND3(b, c, d, a, in[12], 15);
ROUND3(a, b, c, d, in[2], 3); ROUND3(a, b, c, d, in[2], 3);
ROUND3(d, a, b, c, in[10], 9); ROUND3(d, a, b, c, in[10], 9);
ROUND3(c, d, a, b, in[6], 11); ROUND3(c, d, a, b, in[6], 11);
ROUND3(b, c, d, a, in[14], 15); ROUND3(b, c, d, a, in[14], 15);
ROUND3(a, b, c, d, in[1], 3); ROUND3(a, b, c, d, in[1], 3);
ROUND3(d, a, b, c, in[9], 9); ROUND3(d, a, b, c, in[9], 9);
ROUND3(c, d, a, b, in[5], 11); ROUND3(c, d, a, b, in[5], 11);
ROUND3(b, c, d, a, in[13], 15); ROUND3(b, c, d, a, in[13], 15);
ROUND3(a, b, c, d, in[3], 3); ROUND3(a, b, c, d, in[3], 3);
ROUND3(d, a, b, c, in[11], 9); ROUND3(d, a, b, c, in[11], 9);
ROUND3(c, d, a, b, in[7], 11); ROUND3(c, d, a, b, in[7], 11);
ROUND3(b, c, d, a, in[15], 15); ROUND3(b, c, d, a, in[15], 15);
hash[0] += a; hash[0] += a;
hash[1] += b; hash[1] += b;
hash[2] += c; hash[2] += c;
hash[3] += d; hash[3] += d;
} }
static inline void md4_transform_helper(struct md4_ctx *ctx) static inline void md4_transform_helper(struct md4_ctx *ctx)
{ {
le32_to_cpu_array(ctx->block, ARRAY_SIZE(ctx->block)); le32_to_cpu_array(ctx->block, ARRAY_SIZE(ctx->block));
md4_transform(ctx->hash, ctx->block); md4_transform(ctx->hash, ctx->block);
} }
static int md4_init(struct shash_desc *desc) static int md4_init(struct shash_desc *desc)
{ {
struct md4_ctx *mctx = shash_desc_ctx(desc); struct md4_ctx *mctx = shash_desc_ctx(desc);
mctx->hash[0] = 0x67452301; mctx->hash[0] = 0x67452301;
mctx->hash[1] = 0xefcdab89; mctx->hash[1] = 0xefcdab89;
mctx->hash[2] = 0x98badcfe; mctx->hash[2] = 0x98badcfe;
mctx->hash[3] = 0x10325476; mctx->hash[3] = 0x10325476;
mctx->byte_count = 0; mctx->byte_count = 0;
return 0; return 0;
} }
static int md4_update(struct shash_desc *desc, const u8 *data, unsigned int len) static int md4_update(struct shash_desc *desc, const u8 *data, unsigned int len)
{ {
struct md4_ctx *mctx = shash_desc_ctx(desc); struct md4_ctx *mctx = shash_desc_ctx(desc);
const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
mctx->byte_count += len; mctx->byte_count += len;
if (avail > len) { if (avail > len) {
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, len);
data, len); return 0;
return 0; }
}
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, avail);
data, avail);
md4_transform_helper(mctx); md4_transform_helper(mctx);
data += avail; data += avail;
len -= avail; len -= avail;
while (len >= sizeof(mctx->block)) { while (len >= sizeof(mctx->block)) {
memcpy(mctx->block, data, sizeof(mctx->block)); memcpy(mctx->block, data, sizeof(mctx->block));
md4_transform_helper(mctx); md4_transform_helper(mctx);
data += sizeof(mctx->block); data += sizeof(mctx->block);
len -= sizeof(mctx->block); len -= sizeof(mctx->block);
} }
memcpy(mctx->block, data, len); memcpy(mctx->block, data, len);
return 0; return 0;
} }
static int md4_final(struct shash_desc *desc, u8 *out) static int md4_final(struct shash_desc *desc, u8 *out)
{ {
struct md4_ctx *mctx = shash_desc_ctx(desc); struct md4_ctx *mctx = shash_desc_ctx(desc);
const unsigned int offset = mctx->byte_count & 0x3f; const unsigned int offset = mctx->byte_count & 0x3f;
char *p = (char *)mctx->block + offset; char *p = (char *)mctx->block + offset;
int padding = 56 - (offset + 1); int padding = 56 - (offset + 1);
*p++ = 0x80; *p++ = 0x80;
if (padding < 0) { if (padding < 0) {
memset(p, 0x00, padding + sizeof (u64)); memset(p, 0x00, padding + sizeof(u64));
md4_transform_helper(mctx); md4_transform_helper(mctx);
p = (char *)mctx->block; p = (char *)mctx->block;
padding = 56; padding = 56;
} }
memset(p, 0, padding); memset(p, 0, padding);
mctx->block[14] = mctx->byte_count << 3; mctx->block[14] = mctx->byte_count << 3;
mctx->block[15] = mctx->byte_count >> 29; mctx->block[15] = mctx->byte_count >> 29;
le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - sizeof(u64)) / sizeof(u32));
sizeof(u64)) / sizeof(u32)); md4_transform(mctx->hash, mctx->block);
md4_transform(mctx->hash, mctx->block); cpu_to_le32_array(mctx->hash, ARRAY_SIZE(mctx->hash));
cpu_to_le32_array(mctx->hash, ARRAY_SIZE(mctx->hash)); memcpy(out, mctx->hash, sizeof(mctx->hash));
memcpy(out, mctx->hash, sizeof(mctx->hash)); memset(mctx, 0, sizeof(*mctx));
memset(mctx, 0, sizeof(*mctx));
return 0; return 0;
} }
static char to_hex(u8 v) static char to_hex(u8 v)
{ {
v = v & 0xf; v = v & 0xf;
if (v < 0xa) if (v < 0xa)
return '0' + v; return '0' + v;
return 'a' + v - 0xa; return 'a' + v - 0xa;
} }
void md4hexf(const char *path, char *hash) void md4hexf(const char *path, char *hash)
{ {
struct md4_ctx mctx; struct md4_ctx mctx;
md4_init(&mctx); md4_init(&mctx);
int fd = open(path, O_RDONLY); int fd = open(path, O_RDONLY);
if (fd >= 0) { if (fd >= 0) {
u8 buffer[MD4_HMAC_BLOCK_SIZE]; u8 buffer[MD4_HMAC_BLOCK_SIZE];
while (1) { while (1) {
ssize_t count = read(fd, buffer, sizeof(buffer)); ssize_t count = read(fd, buffer, sizeof(buffer));
if (count <= 0) if (count <= 0)
break; break;
md4_update(&mctx, buffer, (unsigned)count); md4_update(&mctx, buffer, (unsigned)count);
} }
close(fd); close(fd);
} }
u8 out[MD4_DIGEST_SIZE]; u8 out[MD4_DIGEST_SIZE];
md4_final(&mctx, out); md4_final(&mctx, out);
for (int i = 0; i < MD4_DIGEST_SIZE; i++) { for (int i = 0; i < MD4_DIGEST_SIZE; i++) {
hash[2*i+0] = to_hex(out[i] >> 4); hash[2 * i + 0] = to_hex(out[i] >> 4);
hash[2*i+1] = to_hex(out[i] & 0xf); hash[2 * i + 1] = to_hex(out[i] & 0xf);
} }
hash[2*MD4_DIGEST_SIZE] = 0; hash[2 * MD4_DIGEST_SIZE] = 0;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -8,22 +8,20 @@
#include "../launcher/icon-theme-common.h" #include "../launcher/icon-theme-common.h"
// panel // panel
extern GtkWidget *panel_width, *panel_height, *panel_margin_x, *panel_margin_y, *panel_padding_x, *panel_padding_y, *panel_spacing; extern GtkWidget *panel_width, *panel_height, *panel_margin_x, *panel_margin_y, *panel_padding_x, *panel_padding_y,
extern GtkWidget *panel_wm_menu, *panel_dock, *panel_autohide, *panel_autohide_show_time, *panel_autohide_hide_time, *panel_autohide_size; *panel_spacing;
extern GtkWidget *panel_combo_strut_policy, *panel_combo_layer, *panel_combo_width_type, *panel_combo_height_type, *panel_combo_monitor; extern GtkWidget *panel_wm_menu, *panel_dock, *panel_autohide, *panel_autohide_show_time, *panel_autohide_hide_time,
*panel_autohide_size;
extern GtkWidget *panel_combo_strut_policy, *panel_combo_layer, *panel_combo_width_type, *panel_combo_height_type,
*panel_combo_monitor;
extern GtkWidget *panel_window_name, *disable_transparency; extern GtkWidget *panel_window_name, *disable_transparency;
extern GtkWidget *panel_mouse_effects; extern GtkWidget *panel_mouse_effects;
extern GtkWidget *mouse_hover_icon_opacity, *mouse_hover_icon_saturation, *mouse_hover_icon_brightness; extern GtkWidget *mouse_hover_icon_opacity, *mouse_hover_icon_saturation, *mouse_hover_icon_brightness;
extern GtkWidget *mouse_pressed_icon_opacity, *mouse_pressed_icon_saturation, *mouse_pressed_icon_brightness; extern GtkWidget *mouse_pressed_icon_opacity, *mouse_pressed_icon_saturation, *mouse_pressed_icon_brightness;
extern GtkWidget *panel_primary_monitor_first, *panel_shrink; extern GtkWidget *panel_primary_monitor_first, *panel_shrink;
enum { enum { itemsColName = 0, itemsColValue, itemsNumCols };
itemsColName = 0,
itemsColValue,
itemsNumCols
};
extern GtkListStore *panel_items, *all_items; extern GtkListStore *panel_items, *all_items;
extern GtkWidget *panel_items_view, *all_items_view; extern GtkWidget *panel_items_view, *all_items_view;
char *get_panel_items(); char *get_panel_items();
@@ -52,44 +50,34 @@ extern GtkWidget *panel_background;
// taskbar // taskbar
extern GtkWidget *taskbar_show_desktop, *taskbar_show_name, *taskbar_padding_x, *taskbar_padding_y, *taskbar_spacing; extern GtkWidget *taskbar_show_desktop, *taskbar_show_name, *taskbar_padding_x, *taskbar_padding_y, *taskbar_spacing;
extern GtkWidget *taskbar_hide_inactive_tasks, *taskbar_hide_diff_monitor; extern GtkWidget *taskbar_hide_inactive_tasks, *taskbar_hide_diff_monitor;
extern GtkWidget *taskbar_name_padding_x, *taskbar_name_padding_y, *taskbar_name_inactive_color, *taskbar_name_active_color; extern GtkWidget *taskbar_name_padding_x, *taskbar_name_padding_y, *taskbar_name_inactive_color,
*taskbar_name_active_color;
extern GtkWidget *taskbar_name_font, *taskbar_name_font_set; extern GtkWidget *taskbar_name_font, *taskbar_name_font_set;
extern GtkWidget *taskbar_active_background, *taskbar_inactive_background; extern GtkWidget *taskbar_active_background, *taskbar_inactive_background;
extern GtkWidget *taskbar_name_active_background, *taskbar_name_inactive_background; extern GtkWidget *taskbar_name_active_background, *taskbar_name_inactive_background;
extern GtkWidget *taskbar_distribute_size, *taskbar_sort_order, *taskbar_alignment, *taskbar_always_show_all_desktop_tasks; extern GtkWidget *taskbar_distribute_size, *taskbar_sort_order, *taskbar_alignment,
*taskbar_always_show_all_desktop_tasks;
extern GtkWidget *taskbar_hide_empty; extern GtkWidget *taskbar_hide_empty;
// task // task
extern GtkWidget *task_mouse_left, *task_mouse_middle, *task_mouse_right, *task_mouse_scroll_up, *task_mouse_scroll_down; extern GtkWidget *task_mouse_left, *task_mouse_middle, *task_mouse_right, *task_mouse_scroll_up,
*task_mouse_scroll_down;
extern GtkWidget *task_show_icon, *task_show_text, *task_align_center, *font_shadow; extern GtkWidget *task_show_icon, *task_show_text, *task_align_center, *font_shadow;
extern GtkWidget *task_maximum_width, *task_maximum_height, *task_padding_x, *task_padding_y, *task_spacing; extern GtkWidget *task_maximum_width, *task_maximum_height, *task_padding_x, *task_padding_y, *task_spacing;
extern GtkWidget *task_font, *task_font_set; extern GtkWidget *task_font, *task_font_set;
extern GtkWidget *task_default_color, *task_default_color_set, extern GtkWidget *task_default_color, *task_default_color_set, *task_default_icon_opacity, *task_default_icon_osb_set,
*task_default_icon_opacity, *task_default_icon_osb_set, *task_default_icon_saturation, *task_default_icon_brightness, *task_default_background,
*task_default_icon_saturation, *task_default_background_set;
*task_default_icon_brightness, extern GtkWidget *task_normal_color, *task_normal_color_set, *task_normal_icon_opacity, *task_normal_icon_osb_set,
*task_default_background, *task_default_background_set; *task_normal_icon_saturation, *task_normal_icon_brightness, *task_normal_background, *task_normal_background_set;
extern GtkWidget *task_normal_color, *task_normal_color_set, extern GtkWidget *task_active_color, *task_active_color_set, *task_active_icon_opacity, *task_active_icon_osb_set,
*task_normal_icon_opacity, *task_normal_icon_osb_set, *task_active_icon_saturation, *task_active_icon_brightness, *task_active_background, *task_active_background_set;
*task_normal_icon_saturation, extern GtkWidget *task_urgent_color, *task_urgent_color_set, *task_urgent_icon_opacity, *task_urgent_icon_osb_set,
*task_normal_icon_brightness, *task_urgent_icon_saturation, *task_urgent_icon_brightness, *task_urgent_background, *task_urgent_background_set;
*task_normal_background, *task_normal_background_set;
extern GtkWidget *task_active_color, *task_active_color_set,
*task_active_icon_opacity, *task_active_icon_osb_set,
*task_active_icon_saturation,
*task_active_icon_brightness,
*task_active_background, *task_active_background_set;
extern GtkWidget *task_urgent_color, *task_urgent_color_set,
*task_urgent_icon_opacity, *task_urgent_icon_osb_set,
*task_urgent_icon_saturation,
*task_urgent_icon_brightness,
*task_urgent_background, *task_urgent_background_set;
extern GtkWidget *task_urgent_blinks; extern GtkWidget *task_urgent_blinks;
extern GtkWidget *task_iconified_color, *task_iconified_color_set, extern GtkWidget *task_iconified_color, *task_iconified_color_set, *task_iconified_icon_opacity,
*task_iconified_icon_opacity, *task_iconified_icon_osb_set, *task_iconified_icon_osb_set, *task_iconified_icon_saturation, *task_iconified_icon_brightness,
*task_iconified_icon_saturation, *task_iconified_background, *task_iconified_background_set;
*task_iconified_icon_brightness,
*task_iconified_background, *task_iconified_background_set;
// clock // clock
extern GtkWidget *clock_format_line1, *clock_format_line2, *clock_tmz_line1, *clock_tmz_line2; extern GtkWidget *clock_format_line1, *clock_format_line2, *clock_tmz_line1, *clock_tmz_line2;
@@ -102,10 +90,12 @@ extern GtkWidget *clock_background;
// battery // battery
extern GtkWidget *battery_hide_if_higher, *battery_alert_if_lower, *battery_alert_cmd; extern GtkWidget *battery_hide_if_higher, *battery_alert_if_lower, *battery_alert_cmd;
extern GtkWidget *battery_padding_x, *battery_padding_y; extern GtkWidget *battery_padding_x, *battery_padding_y;
extern GtkWidget *battery_font_line1, *battery_font_line1_set, *battery_font_line2, *battery_font_line2_set, *battery_font_color; extern GtkWidget *battery_font_line1, *battery_font_line1_set, *battery_font_line2, *battery_font_line2_set,
*battery_font_color;
extern GtkWidget *battery_background; extern GtkWidget *battery_background;
extern GtkWidget *battery_tooltip; extern GtkWidget *battery_tooltip;
extern GtkWidget *battery_left_command, *battery_mclick_command, *battery_right_command, *battery_uwheel_command, *battery_dwheel_command; extern GtkWidget *battery_left_command, *battery_mclick_command, *battery_right_command, *battery_uwheel_command,
*battery_dwheel_command;
extern GtkWidget *ac_connected_cmd, *ac_disconnected_cmd; extern GtkWidget *ac_connected_cmd, *ac_disconnected_cmd;
// systray // systray
@@ -121,60 +111,55 @@ extern GtkWidget *tooltip_background;
// Separator // Separator
typedef struct Separator { typedef struct Separator {
char name[256]; char name[256];
GtkWidget *container; GtkWidget *container;
GtkWidget *page_separator; GtkWidget *page_separator;
GtkWidget *page_label; GtkWidget *page_label;
GtkWidget *separator_background; GtkWidget *separator_background;
GtkWidget *separator_color; GtkWidget *separator_color;
GtkWidget *separator_style; GtkWidget *separator_style;
GtkWidget *separator_size; GtkWidget *separator_size;
GtkWidget *separator_padding_x; GtkWidget *separator_padding_x;
GtkWidget *separator_padding_y; GtkWidget *separator_padding_y;
} Separator; } Separator;
extern GArray *separators; extern GArray *separators;
// Executor // Executor
typedef struct Executor { typedef struct Executor {
char name[256]; char name[256];
GtkWidget *container; GtkWidget *container;
GtkWidget *page_execp; GtkWidget *page_execp;
GtkWidget *page_label; GtkWidget *page_label;
GtkWidget *execp_command, *execp_interval, *execp_has_icon, *execp_cache_icon, *execp_show_tooltip; GtkWidget *execp_command, *execp_interval, *execp_has_icon, *execp_cache_icon, *execp_show_tooltip;
GtkWidget *execp_continuous, *execp_markup, *execp_tooltip; GtkWidget *execp_continuous, *execp_markup, *execp_tooltip;
GtkWidget *execp_left_command, *execp_right_command; GtkWidget *execp_left_command, *execp_right_command;
GtkWidget *execp_mclick_command, *execp_rclick_command, *execp_uwheel_command, *execp_dwheel_command; GtkWidget *execp_mclick_command, *execp_rclick_command, *execp_uwheel_command, *execp_dwheel_command;
GtkWidget *execp_font, *execp_font_set, *execp_font_color, *execp_padding_x, *execp_padding_y, *execp_centered; GtkWidget *execp_font, *execp_font_set, *execp_font_color, *execp_padding_x, *execp_padding_y, *execp_centered;
GtkWidget *execp_background, *execp_icon_w, *execp_icon_h; GtkWidget *execp_background, *execp_icon_w, *execp_icon_h;
} Executor; } Executor;
extern GArray *executors; extern GArray *executors;
// Button // Button
typedef struct Button { typedef struct Button {
char name[256]; char name[256];
GtkWidget *container; GtkWidget *container;
GtkWidget *page_button; GtkWidget *page_button;
GtkWidget *page_label; GtkWidget *page_label;
GtkWidget *button_icon, *button_text, *button_tooltip; GtkWidget *button_icon, *button_text, *button_tooltip;
GtkWidget *button_left_command, *button_right_command; GtkWidget *button_left_command, *button_right_command;
GtkWidget *button_mclick_command, *button_rclick_command, *button_uwheel_command, *button_dwheel_command; GtkWidget *button_mclick_command, *button_rclick_command, *button_uwheel_command, *button_dwheel_command;
GtkWidget *button_font, *button_font_set, *button_font_color, *button_padding_x, *button_padding_y, *button_centered; GtkWidget *button_font, *button_font_set, *button_font_color, *button_padding_x, *button_padding_y,
GtkWidget *button_background, *button_max_icon_size; *button_centered;
GtkWidget *button_background, *button_max_icon_size;
} Button; } Button;
extern GArray *buttons; extern GArray *buttons;
// launcher // launcher
enum { enum { appsColIcon = 0, appsColIconName, appsColText, appsColPath, appsNumCols };
appsColIcon = 0,
appsColIconName,
appsColText,
appsColPath,
appsNumCols
};
extern GtkListStore *launcher_apps, *all_apps; extern GtkListStore *launcher_apps, *all_apps;
extern GtkWidget *launcher_apps_view, *all_apps_view; extern GtkWidget *launcher_apps_view, *all_apps_view;
@@ -195,73 +180,49 @@ gchar *get_current_icon_theme();
// background // background
enum { enum {
bgColPixbuf = 0, bgColPixbuf = 0,
bgColFillColor, bgColFillColor,
bgColFillOpacity, bgColFillOpacity,
bgColBorderColor, bgColBorderColor,
bgColBorderOpacity, bgColBorderOpacity,
bgColGradientId, bgColGradientId,
bgColBorderWidth, bgColBorderWidth,
bgColCornerRadius, bgColCornerRadius,
bgColText, bgColText,
bgColFillColorOver, bgColFillColorOver,
bgColFillOpacityOver, bgColFillOpacityOver,
bgColBorderColorOver, bgColBorderColorOver,
bgColBorderOpacityOver, bgColBorderOpacityOver,
bgColGradientIdOver, bgColGradientIdOver,
bgColFillColorPress, bgColFillColorPress,
bgColFillOpacityPress, bgColFillOpacityPress,
bgColBorderColorPress, bgColBorderColorPress,
bgColBorderOpacityPress, bgColBorderOpacityPress,
bgColGradientIdPress, bgColGradientIdPress,
bgColBorderSidesTop, bgColBorderSidesTop,
bgColBorderSidesBottom, bgColBorderSidesBottom,
bgColBorderSidesLeft, bgColBorderSidesLeft,
bgColBorderSidesRight, bgColBorderSidesRight,
bgNumCols bgNumCols
}; };
extern GtkListStore *backgrounds; extern GtkListStore *backgrounds;
extern GtkWidget *current_background, extern GtkWidget *current_background, *background_fill_color, *background_border_color, *background_gradient,
*background_fill_color, *background_fill_color_over, *background_border_color_over, *background_gradient_over, *background_fill_color_press,
*background_border_color, *background_border_color_press, *background_gradient_press, *background_border_width, *background_border_sides_top,
*background_gradient, *background_border_sides_bottom, *background_border_sides_left, *background_border_sides_right,
*background_fill_color_over, *background_corner_radius;
*background_border_color_over,
*background_gradient_over,
*background_fill_color_press,
*background_border_color_press,
*background_gradient_press,
*background_border_width,
*background_border_sides_top,
*background_border_sides_bottom,
*background_border_sides_left,
*background_border_sides_right,
*background_corner_radius;
// gradients // gradients
enum { enum { grColPixbuf = 0, grColId, grColText, grNumCols };
grColPixbuf = 0,
grColId,
grColText,
grNumCols
};
// gradient color stops // gradient color stops
enum { enum { grStopColPixbuf = 0, grStopNumCols };
grStopColPixbuf = 0,
grStopNumCols
};
extern GtkListStore *gradient_ids, *gradient_stop_ids; extern GtkListStore *gradient_ids, *gradient_stop_ids;
extern GList *gradients; extern GList *gradients;
extern GtkWidget *current_gradient, extern GtkWidget *current_gradient, *gradient_combo_type, *gradient_start_color, *gradient_end_color,
*gradient_combo_type, *current_gradient_stop, *gradient_stop_color, *gradient_stop_offset;
*gradient_start_color,
*gradient_end_color,
*current_gradient_stop,
*gradient_stop_color,
*gradient_stop_offset;
void background_create_new(); void background_create_new();
void background_force_update(); void background_force_update();

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
char *get_current_theme_path(); char *get_current_theme_path();
gboolean config_is_manual(const char *path); gboolean config_is_manual(const char *path);
void config_read_file (const char *path); void config_read_file(const char *path);
void config_save_file(const char *path); void config_save_file(const char *path);
#endif #endif

View File

@@ -34,203 +34,216 @@ gint theme_name_compare(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpo
GtkWidget *create_view() GtkWidget *create_view()
{ {
GtkTreeViewColumn *col; GtkTreeViewColumn *col;
GtkCellRenderer *renderer; GtkCellRenderer *renderer;
theme_list_store = theme_list_store = gtk_list_store_new(NB_COL,
gtk_list_store_new(NB_COL, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_INT, G_TYPE_INT, G_TYPE_BOOLEAN); G_TYPE_STRING,
G_TYPE_STRING,
GDK_TYPE_PIXBUF,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_BOOLEAN);
GtkWidget *view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(theme_list_store)); GtkWidget *view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(theme_list_store));
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
g_object_unref(theme_list_store); // destroy store automatically with view g_object_unref(theme_list_store); // destroy store automatically with view
renderer = gtk_cell_renderer_text_new(); renderer = gtk_cell_renderer_text_new();
col = gtk_tree_view_column_new(); col = gtk_tree_view_column_new();
gtk_tree_view_column_pack_start(col, renderer, TRUE); gtk_tree_view_column_pack_start(col, renderer, TRUE);
gtk_tree_view_column_add_attribute(col, renderer, "text", COL_THEME_FILE); gtk_tree_view_column_add_attribute(col, renderer, "text", COL_THEME_FILE);
gtk_tree_view_column_set_visible(col, FALSE); gtk_tree_view_column_set_visible(col, FALSE);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
renderer = gtk_cell_renderer_text_new(); renderer = gtk_cell_renderer_text_new();
col = gtk_tree_view_column_new(); col = gtk_tree_view_column_new();
gtk_tree_view_column_pack_start(col, renderer, TRUE); gtk_tree_view_column_pack_start(col, renderer, TRUE);
gtk_tree_view_column_add_attribute(col, renderer, "text", COL_THEME_NAME); gtk_tree_view_column_add_attribute(col, renderer, "text", COL_THEME_NAME);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
g_renderer = gtk_cell_renderer_pixbuf_new(); g_renderer = gtk_cell_renderer_pixbuf_new();
g_object_set(g_renderer, "xalign", 0.0, NULL); g_object_set(g_renderer, "xalign", 0.0, NULL);
gtk_cell_renderer_set_fixed_size(g_renderer, 200, 30); gtk_cell_renderer_set_fixed_size(g_renderer, 200, 30);
col = gtk_tree_view_column_new(); col = gtk_tree_view_column_new();
gtk_tree_view_column_pack_start(col, g_renderer, TRUE); gtk_tree_view_column_pack_start(col, g_renderer, TRUE);
gtk_tree_view_column_add_attribute(col, g_renderer, "pixbuf", COL_SNAPSHOT); gtk_tree_view_column_add_attribute(col, g_renderer, "pixbuf", COL_SNAPSHOT);
gtk_tree_view_column_add_attribute(col, g_renderer, "width", COL_WIDTH); gtk_tree_view_column_add_attribute(col, g_renderer, "width", COL_WIDTH);
gtk_tree_view_column_add_attribute(col, g_renderer, "height", COL_HEIGHT); gtk_tree_view_column_add_attribute(col, g_renderer, "height", COL_HEIGHT);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
GtkTreeSortable *sortable = GTK_TREE_SORTABLE(theme_list_store); GtkTreeSortable *sortable = GTK_TREE_SORTABLE(theme_list_store);
gtk_tree_sortable_set_sort_column_id(sortable, COL_THEME_FILE, GTK_SORT_ASCENDING); gtk_tree_sortable_set_sort_column_id(sortable, COL_THEME_FILE, GTK_SORT_ASCENDING);
gtk_tree_sortable_set_sort_func(sortable, COL_THEME_FILE, theme_name_compare, NULL, NULL); gtk_tree_sortable_set_sort_func(sortable, COL_THEME_FILE, theme_name_compare, NULL, NULL);
return view; return view;
} }
gint theme_name_compare(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) gint theme_name_compare(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
{ {
gchar *path_a, *path_b; gchar *path_a, *path_b;
gtk_tree_model_get(model, a, COL_THEME_FILE, &path_a, -1); gtk_tree_model_get(model, a, COL_THEME_FILE, &path_a, -1);
gtk_tree_model_get(model, b, COL_THEME_FILE, &path_b, -1); gtk_tree_model_get(model, b, COL_THEME_FILE, &path_b, -1);
gboolean home_a = strstr(path_a, g_get_user_config_dir()) == path_a; gboolean home_a = strstr(path_a, g_get_user_config_dir()) == path_a;
gboolean home_b = strstr(path_b, g_get_user_config_dir()) == path_b; gboolean home_b = strstr(path_b, g_get_user_config_dir()) == path_b;
if (home_a && !home_b) if (home_a && !home_b)
return -1; return -1;
if (!home_a && home_b) if (!home_a && home_b)
return 1; return 1;
gchar *name_a = path_a; gchar *name_a = path_a;
gchar *p; gchar *p;
for (p = name_a; *p; p++) { for (p = name_a; *p; p++) {
if (*p == '/') if (*p == '/')
name_a = p + 1; name_a = p + 1;
} }
gchar *name_b = path_b; gchar *name_b = path_b;
for (p = name_b; *p; p++) { for (p = name_b; *p; p++) {
if (*p == '/') if (*p == '/')
name_b = p + 1; name_b = p + 1;
} }
if (g_str_equal(name_a, name_b)) if (g_str_equal(name_a, name_b))
return 0; return 0;
if (g_str_equal(name_a, "tint2rc")) if (g_str_equal(name_a, "tint2rc"))
return -1; return -1;
if (g_str_equal(name_b, "tint2rc")) if (g_str_equal(name_b, "tint2rc"))
return 1; return 1;
gint result = strnatcasecmp(name_a, name_b); gint result = strnatcasecmp(name_a, name_b);
g_free(path_a); g_free(path_a);
g_free(path_b); g_free(path_b);
return result; return result;
} }
gboolean theme_list_contains(const char *given_path) gboolean theme_list_contains(const char *given_path)
{ {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(g_theme_view)); GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(g_theme_view));
GtkTreeIter iter; GtkTreeIter iter;
gboolean have_iter = gtk_tree_model_get_iter_first(model, &iter); gboolean have_iter = gtk_tree_model_get_iter_first(model, &iter);
while (have_iter) { while (have_iter) {
gchar *filepath; gchar *filepath;
gtk_tree_model_get(model, &iter, COL_THEME_FILE, &filepath, -1); gtk_tree_model_get(model, &iter, COL_THEME_FILE, &filepath, -1);
if (g_str_equal(filepath, given_path)) { if (g_str_equal(filepath, given_path)) {
gtk_list_store_set(theme_list_store, &iter, COL_SNAPSHOT, NULL, -1); gtk_list_store_set(theme_list_store, &iter, COL_SNAPSHOT, NULL, -1);
g_free(filepath); g_free(filepath);
return TRUE; return TRUE;
} }
g_free(filepath); g_free(filepath);
have_iter = gtk_tree_model_iter_next(model, &iter); have_iter = gtk_tree_model_iter_next(model, &iter);
} }
return FALSE; return FALSE;
} }
void theme_list_append(const gchar *path) void theme_list_append(const gchar *path)
{ {
if (theme_list_contains(path)) if (theme_list_contains(path))
return; return;
GtkTreeIter iter; GtkTreeIter iter;
gtk_list_store_append(theme_list_store, &iter); gtk_list_store_append(theme_list_store, &iter);
gchar *name = strrchr(path, '/') + 1; gchar *name = strrchr(path, '/') + 1;
gchar *dir = g_strdup(path); gchar *dir = g_strdup(path);
strrchr(dir, '/')[0] = 0; strrchr(dir, '/')[0] = 0;
char *suffix = contract_tilde(dir); char *suffix = contract_tilde(dir);
g_free(dir); g_free(dir);
gchar *display_name = g_strdup_printf("%s\n(%s)", name, suffix); gchar *display_name = g_strdup_printf("%s\n(%s)", name, suffix);
gtk_list_store_set(theme_list_store, &iter, COL_THEME_FILE, path, COL_THEME_NAME, display_name, COL_FORCE_REFRESH, FALSE, -1); gtk_list_store_set(theme_list_store,
g_free(display_name); &iter,
g_free(suffix); COL_THEME_FILE,
path,
COL_THEME_NAME,
display_name,
COL_FORCE_REFRESH,
FALSE,
-1);
g_free(display_name);
g_free(suffix);
} }
gboolean update_snapshot(gpointer ignored) gboolean update_snapshot(gpointer ignored)
{ {
{ {
gchar *tint2_cache_dir = g_build_filename(g_get_user_cache_dir(), "tint2", NULL); gchar *tint2_cache_dir = g_build_filename(g_get_user_cache_dir(), "tint2", NULL);
if (!g_file_test(tint2_cache_dir, G_FILE_TEST_IS_DIR)) if (!g_file_test(tint2_cache_dir, G_FILE_TEST_IS_DIR))
g_mkdir(tint2_cache_dir, 0700); g_mkdir(tint2_cache_dir, 0700);
g_free(tint2_cache_dir); g_free(tint2_cache_dir);
} }
const gint PADDING = 20; const gint PADDING = 20;
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(g_theme_view)); GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(g_theme_view));
GtkTreeIter iter; GtkTreeIter iter;
gboolean have_iter; gboolean have_iter;
int num_updates = 0; int num_updates = 0;
gboolean need_pls_wait = FALSE; gboolean need_pls_wait = FALSE;
have_iter = gtk_tree_model_get_iter_first(model, &iter); have_iter = gtk_tree_model_get_iter_first(model, &iter);
while (have_iter) { while (have_iter) {
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
gtk_tree_model_get(model, &iter, COL_SNAPSHOT, &pixbuf, -1); gtk_tree_model_get(model, &iter, COL_SNAPSHOT, &pixbuf, -1);
if (pixbuf) { if (pixbuf) {
g_object_unref(pixbuf); g_object_unref(pixbuf);
have_iter = gtk_tree_model_iter_next(model, &iter); have_iter = gtk_tree_model_iter_next(model, &iter);
continue; continue;
} }
gchar *path; gchar *path;
gboolean force_refresh; gboolean force_refresh;
gtk_tree_model_get(model, &iter, COL_THEME_FILE, &path, COL_FORCE_REFRESH, &force_refresh, -1); gtk_tree_model_get(model, &iter, COL_THEME_FILE, &path, COL_FORCE_REFRESH, &force_refresh, -1);
char hash[MD4_HEX_SIZE + 4]; char hash[MD4_HEX_SIZE + 4];
md4hexf(path, hash); md4hexf(path, hash);
strcat(hash, ".png"); strcat(hash, ".png");
gchar *snap = g_build_filename(g_get_user_cache_dir(), "tint2", hash, NULL); gchar *snap = g_build_filename(g_get_user_cache_dir(), "tint2", hash, NULL);
pixbuf = force_refresh ? NULL : gdk_pixbuf_new_from_file(snap, NULL); pixbuf = force_refresh ? NULL : gdk_pixbuf_new_from_file(snap, NULL);
if (!pixbuf) { if (!pixbuf) {
gchar *cmd = g_strdup_printf("tint2 -c \'%s\' -s \'%s\' 1>/dev/null 2>/dev/null", path, snap); gchar *cmd = g_strdup_printf("tint2 -c \'%s\' -s \'%s\' 1>/dev/null 2>/dev/null", path, snap);
num_updates++; num_updates++;
if (num_updates > 3 && !need_pls_wait) { if (num_updates > 3 && !need_pls_wait) {
need_pls_wait = TRUE; need_pls_wait = TRUE;
create_please_wait(GTK_WINDOW(g_window)); create_please_wait(GTK_WINDOW(g_window));
} }
if (system(cmd) == 0) { if (system(cmd) == 0) {
// load // load
pixbuf = gdk_pixbuf_new_from_file(snap, NULL); pixbuf = gdk_pixbuf_new_from_file(snap, NULL);
} }
g_free(cmd); g_free(cmd);
} }
g_free(snap); g_free(snap);
g_free(path); g_free(path);
gtk_list_store_set(theme_list_store, gtk_list_store_set(theme_list_store,
&iter, &iter,
COL_SNAPSHOT, COL_SNAPSHOT,
pixbuf, pixbuf,
COL_WIDTH, COL_WIDTH,
gdk_pixbuf_get_width(pixbuf) + PADDING, gdk_pixbuf_get_width(pixbuf) + PADDING,
COL_HEIGHT, COL_HEIGHT,
gdk_pixbuf_get_height(pixbuf) + PADDING, gdk_pixbuf_get_height(pixbuf) + PADDING,
COL_FORCE_REFRESH, COL_FORCE_REFRESH,
FALSE, FALSE,
-1); -1);
if (pixbuf) if (pixbuf)
g_object_unref(pixbuf); g_object_unref(pixbuf);
if (need_pls_wait) if (need_pls_wait)
process_events(); process_events();
have_iter = gtk_tree_model_iter_next(model, &iter); have_iter = gtk_tree_model_iter_next(model, &iter);
} }
if (need_pls_wait) if (need_pls_wait)
destroy_please_wait(); destroy_please_wait();
return FALSE; return FALSE;
} }

View File

@@ -5,13 +5,15 @@
extern GtkWidget *g_theme_view; extern GtkWidget *g_theme_view;
extern GtkListStore *theme_list_store; extern GtkListStore *theme_list_store;
enum { COL_THEME_FILE = 0, enum {
COL_THEME_NAME, COL_THEME_FILE = 0,
COL_SNAPSHOT, COL_THEME_NAME,
COL_WIDTH, COL_SNAPSHOT,
COL_HEIGHT, COL_WIDTH,
COL_FORCE_REFRESH, COL_HEIGHT,
NB_COL, }; COL_FORCE_REFRESH,
NB_COL,
};
GtkWidget *create_view(); GtkWidget *create_view();

View File

@@ -1,411 +1,261 @@
#include "tint2rc.h" #include "tint2rc.h"
unsigned char themes_tint2rc[] = { unsigned char themes_tint2rc[] =
0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, {0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20,
0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x69, 0x6e, 0x74, 0x32, 0x74, 0x69, 0x6e, 0x74, 0x32, 0x63, 0x6f, 0x6e, 0x66, 0x20, 0x32, 0x36, 0x34, 0x31, 0x20, 0x2d, 0x2d, 0x2d, 0x2d,
0x63, 0x6f, 0x6e, 0x66, 0x20, 0x32, 0x36, 0x34, 0x31, 0x20, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x65, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x6c,
0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x53, 0x65, 0x65, 0x20, 0x68, 0x74, 0x74, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x39, 0x30, 0x30, 0x30, 0x2f, 0x74, 0x69, 0x6e, 0x74, 0x32, 0x2f,
0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x77, 0x69, 0x6b, 0x69, 0x73, 0x2f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x20, 0x66, 0x6f, 0x72,
0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x39, 0x30, 0x30, 0x30, 0x2f, 0x74, 0x69, 0x20, 0x0a, 0x23, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74,
0x6e, 0x74, 0x32, 0x2f, 0x77, 0x69, 0x6b, 0x69, 0x73, 0x2f, 0x43, 0x6f, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a, 0x23, 0x2d, 0x2d, 0x2d,
0x0a, 0x23, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x42,
0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x0a, 0x23, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x31, 0x3a, 0x20, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64,
0x6e, 0x73, 0x2e, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x36, 0x30, 0x0a, 0x62, 0x6f, 0x72,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x42, 0x61, 0x63, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x0a, 0x23, 0x20, 0x42, 0x20, 0x33, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f,
0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x31, 0x3a, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x36,
0x20, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65,
0x65, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x33, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b,
0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x36, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64,
0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20,
0x30, 0x30, 0x20, 0x36, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x33, 0x30, 0x0a, 0x0a, 0x23, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x67,
0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x32, 0x3a, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x61,
0x30, 0x30, 0x30, 0x30, 0x20, 0x33, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x6b, 0x2c, 0x20, 0x49, 0x63, 0x6f, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x0a,
0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x34, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f,
0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e,
0x30, 0x30, 0x30, 0x30, 0x20, 0x36, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x20, 0x32,
0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x37,
0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x37, 0x37, 0x37, 0x37, 0x37, 0x20, 0x33, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64,
0x20, 0x33, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x61,
0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x61, 0x61, 0x61, 0x20, 0x32, 0x32, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x65, 0x61, 0x65, 0x61, 0x65, 0x61, 0x20, 0x34, 0x34,
0x30, 0x30, 0x20, 0x36, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70,
0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x20, 0x34, 0x0a,
0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65,
0x20, 0x33, 0x30, 0x0a, 0x0a, 0x23, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x65, 0x61, 0x65, 0x61, 0x65, 0x61, 0x20, 0x34, 0x34, 0x0a, 0x0a, 0x23, 0x20, 0x42,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x32, 0x3a, 0x20, 0x44, 0x65, 0x66, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x33, 0x3a, 0x20, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65,
0x61, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x2c, 0x20, 0x49, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x34, 0x0a, 0x62,
0x63, 0x6f, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x74, 0x61, 0x73, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x61, 0x63,
0x6b, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x37, 0x37,
0x34, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x37, 0x37, 0x37, 0x37, 0x20, 0x32, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f,
0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x20, 0x34, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20,
0x3d, 0x20, 0x23, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x20, 0x32, 0x30, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x20, 0x32, 0x32, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72,
0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x65, 0x61, 0x65,
0x72, 0x20, 0x3d, 0x20, 0x23, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x20, 0x61, 0x65, 0x61, 0x20, 0x34, 0x34, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63,
0x33, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x35, 0x35, 0x35,
0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x35, 0x35, 0x35, 0x20, 0x34, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f,
0x72, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x65, 0x61, 0x65, 0x61, 0x65, 0x61, 0x20, 0x34,
0x32, 0x32, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x34, 0x0a, 0x0a, 0x23, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x34, 0x3a, 0x20,
0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x55, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64,
0x23, 0x65, 0x61, 0x65, 0x61, 0x65, 0x61, 0x20, 0x34, 0x34, 0x0a, 0x62, 0x20, 0x3d, 0x20, 0x34, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d,
0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x20, 0x31, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x34, 0x34, 0x30, 0x30, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64,
0x3d, 0x20, 0x23, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x20, 0x34, 0x0a, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x37, 0x37, 0x33, 0x33, 0x20,
0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f,
0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x63, 0x63, 0x37, 0x37, 0x30, 0x30, 0x20, 0x31,
0x65, 0x61, 0x65, 0x61, 0x65, 0x61, 0x20, 0x34, 0x34, 0x0a, 0x0a, 0x23, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76,
0x20, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x37, 0x37, 0x33, 0x33, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61,
0x33, 0x3a, 0x20, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x74, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73,
0x73, 0x6b, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x3d, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x20, 0x34, 0x0a, 0x62, 0x6f, 0x72,
0x20, 0x34, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x77, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d,
0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x20, 0x23, 0x61, 0x61, 0x37, 0x37, 0x33, 0x33, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x0a, 0x23, 0x20, 0x42, 0x61, 0x63,
0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x35, 0x3a, 0x20, 0x54, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x0a,
0x20, 0x3d, 0x20, 0x23, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x20, 0x32, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f,
0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e,
0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x61, 0x61, 0x20, 0x31,
0x20, 0x34, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23,
0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75,
0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66,
0x20, 0x32, 0x32, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x66, 0x66, 0x66, 0x61, 0x61, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f,
0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x20, 0x23, 0x65, 0x61, 0x65, 0x61, 0x65, 0x61, 0x20, 0x34, 0x34, 0x0a, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x61,
0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x61, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f,
0x20, 0x3d, 0x20, 0x23, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x20, 0x34, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x31,
0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x30, 0x30, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x23, 0x65, 0x61, 0x65, 0x61, 0x65, 0x61, 0x20, 0x34, 0x34, 0x0a, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f,
0x23, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x4c, 0x54, 0x53, 0x43, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f,
0x20, 0x34, 0x3a, 0x20, 0x55, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x25, 0x20, 0x33, 0x30, 0x0a, 0x70, 0x61, 0x6e, 0x65,
0x61, 0x73, 0x6b, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x6c, 0x5f, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x70, 0x61, 0x6e, 0x65,
0x3d, 0x20, 0x34, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x77, 0x6c, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x32, 0x20, 0x30, 0x20, 0x32, 0x0a, 0x70,
0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x61, 0x63, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20,
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x3d, 0x20, 0x31, 0x0a, 0x77, 0x6d, 0x5f, 0x6d, 0x65, 0x6e, 0x75, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x70, 0x61, 0x6e,
0x72, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x34, 0x34, 0x30, 0x30, 0x20, 0x65, 0x6c, 0x5f, 0x64, 0x6f, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x70,
0x31, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x20, 0x63, 0x65,
0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x37, 0x37, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x0a, 0x70, 0x61, 0x6e,
0x33, 0x33, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x65, 0x6c, 0x5f, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x70, 0x0a, 0x70, 0x61, 0x6e, 0x65,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x6c, 0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x61, 0x6c, 0x6c, 0x0a, 0x70, 0x72, 0x69,
0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x63, 0x63, 0x37, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20,
0x37, 0x30, 0x30, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x3d, 0x20, 0x30, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x68, 0x69, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x61, 0x75,
0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x6f, 0x76, 0x74, 0x6f, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x37, 0x37, 0x33, 0x33, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x68, 0x69, 0x64, 0x65, 0x5f,
0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x2e, 0x35, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x68,
0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x32, 0x0a, 0x73, 0x74, 0x72, 0x75,
0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x35, 0x35, 0x35, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x73,
0x35, 0x35, 0x35, 0x20, 0x34, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x7a, 0x65, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x5f, 0x6e, 0x61,
0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x69, 0x6e, 0x74, 0x32, 0x0a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f,
0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x61, 0x61, 0x37, 0x37, 0x33, 0x33, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x6d, 0x6f,
0x20, 0x31, 0x30, 0x30, 0x0a, 0x0a, 0x23, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x73, 0x65, 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x66, 0x6f, 0x6e,
0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x35, 0x3a, 0x20, 0x54, 0x6f, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f,
0x6f, 0x6c, 0x74, 0x69, 0x70, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x62, 0x20, 0x3d, 0x20, 0x31, 0x30,
0x64, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x30, 0x20, 0x30, 0x20, 0x31, 0x30, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65,
0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x64, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x62, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x20, 0x30, 0x20,
0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x30, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x61, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x61, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x54, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62,
0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x61, 0x72, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x5f, 0x64, 0x65,
0x30, 0x30, 0x30, 0x30, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x30, 0x20, 0x30, 0x20, 0x32, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f,
0x72, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74,
0x66, 0x66, 0x66, 0x61, 0x61, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67,
0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x68, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61,
0x6f, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f,
0x30, 0x30, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x64,
0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20,
0x66, 0x66, 0x66, 0x61, 0x61, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x6f, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x5f, 0x73, 0x68,
0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x77, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x5f, 0x74, 0x61, 0x73, 0x6b,
0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x23, 0x30, 0x30, 0x73, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f,
0x30, 0x30, 0x30, 0x30, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x0a, 0x23, 0x2d, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x34, 0x20, 0x32, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f,
0x0a, 0x23, 0x20, 0x50, 0x61, 0x6e, 0x65, 0x6c, 0x0a, 0x70, 0x61, 0x6e, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x65, 0x6c, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x4c, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x65, 0x33, 0x65, 0x33,
0x54, 0x53, 0x43, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x69, 0x65, 0x33, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x7a, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x25, 0x20, 0x33, 0x30, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20,
0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62,
0x6e, 0x20, 0x3d, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x61, 0x72, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20,
0x6c, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x72,
0x32, 0x20, 0x30, 0x20, 0x32, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x61, 0x6c, 0x69,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x67, 0x6e, 0x20, 0x3d, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x64, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x77, 0x6d, 0x5f, 0x6d, 0x65, 0x6e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x75, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x54, 0x61, 0x73, 0x6b, 0x0a,
0x64, 0x6f, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x70, 0x61, 0x6e, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f,
0x65, 0x6c, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x63, 0x65, 0x6e, 0x74, 0x65,
0x3d, 0x20, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x20, 0x63, 0x65, 0x6e, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x75, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x62, 0x5f, 0x6f,
0x74, 0x65, 0x72, 0x20, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x66, 0x5f, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x74, 0x61,
0x61, 0x6c, 0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x6c, 0x61, 0x79, 0x73, 0x6b, 0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x31,
0x65, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x70, 0x0a, 0x70, 0x61, 0x6e, 0x35, 0x30, 0x20, 0x33, 0x35, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20,
0x65, 0x6c, 0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x20, 0x32, 0x20, 0x34, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69,
0x20, 0x61, 0x6c, 0x6c, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x70, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c,
0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x5f, 0x66, 0x69, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x74, 0x61,
0x73, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x68, 0x73, 0x6b, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20,
0x69, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x32, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67,
0x68, 0x69, 0x64, 0x65, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x74, 0x69, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x33, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x75,
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x61, 0x75, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64,
0x74, 0x6f, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x20, 0x3d, 0x20, 0x34, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64,
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x2e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x32, 0x0a,
0x35, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x68, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65,
0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x32, 0x0a, 0x73, 0x74, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x69, 0x66, 0x79, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x69, 0x64, 0x64,
0x72, 0x75, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x3d, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x72, 0x69, 0x67,
0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x63,
0x0a, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x75, 0x70, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x0a, 0x6d, 0x6f,
0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x69, 0x6e, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x20, 0x3d, 0x20, 0x69,
0x74, 0x32, 0x0a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x63, 0x6f, 0x6e, 0x69, 0x66, 0x79, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x3d, 0x20, 0x31, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x65, 0x66, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x74,
0x66, 0x65, 0x63, 0x74, 0x73, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x66, 0x6f, 0x72, 0x61, 0x79, 0x20, 0x28, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61,
0x6e, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x61, 0x29, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x72, 0x61, 0x79, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e,
0x30, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x68, 0x6f, 0x76, 0x65, 0x67, 0x20, 0x3d, 0x20, 0x30, 0x20, 0x34, 0x20, 0x32, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x72, 0x61, 0x79, 0x5f, 0x62,
0x72, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x62, 0x20, 0x3d, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x73, 0x79,
0x20, 0x31, 0x30, 0x30, 0x20, 0x30, 0x20, 0x31, 0x30, 0x0a, 0x6d, 0x6f, 0x73, 0x74, 0x72, 0x61, 0x79, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64,
0x75, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x67, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x73, 0x69,
0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x62, 0x20, 0x3d, 0x20, 0x31, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x32, 0x34, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x63, 0x6f,
0x30, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x6e, 0x5f, 0x61, 0x73, 0x62, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x73, 0x79, 0x73,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x74, 0x72, 0x61, 0x79, 0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x0a, 0x23,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
0x20, 0x54, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x0a, 0x74, 0x61, 0x73, 0x23, 0x20, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72,
0x6b, 0x62, 0x61, 0x72, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x32, 0x20, 0x34, 0x20, 0x32, 0x0a, 0x6c, 0x61,
0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69,
0x6f, 0x70, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x70, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x63, 0x6f, 0x6e,
0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x30, 0x20, 0x30, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a,
0x20, 0x32, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20,
0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x3d, 0x20, 0x32, 0x34, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f,
0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x61, 0x73, 0x62, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63,
0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x5f, 0x6f, 0x76, 0x65, 0x72,
0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x72, 0x69, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x6e, 0x6f,
0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x6c, 0x61, 0x75,
0x6d, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x6c,
0x61, 0x72, 0x5f, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x61, 0x63, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x70, 0x70, 0x20, 0x3d, 0x20,
0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x20, 0x3d, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x68, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x74, 0x69, 0x6e, 0x74, 0x32, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x64, 0x65, 0x73, 0x6b,
0x69, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x6f, 0x70, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61,
0x74, 0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x70, 0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x73, 0x68, 0x61,
0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x61, 0x6c, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x74, 0x69, 0x6e,
0x77, 0x61, 0x79, 0x73, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x61, 0x6c, 0x74, 0x32, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x6c, 0x61, 0x75, 0x6e,
0x6c, 0x5f, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x5f, 0x74, 0x61, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x70, 0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73,
0x73, 0x6b, 0x73, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x72, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x64, 0x73, 0x2f, 0x66, 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x2e, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x6c,
0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x34, 0x20, 0x32, 0x0a, 0x74, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x70, 0x70, 0x20, 0x3d, 0x20,
0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x69, 0x63, 0x65, 0x77, 0x65, 0x61, 0x73, 0x65, 0x6c, 0x2e, 0x64, 0x65, 0x73, 0x6b,
0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x61, 0x74, 0x6f, 0x70, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61,
0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x70, 0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70,
0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d, 0x2d,
0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x2e, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x6c, 0x61, 0x75,
0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x66, 0x6f, 0x6e, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x70, 0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75,
0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x65, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x33, 0x65, 0x33, 0x65, 0x33, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x74, 0x61, 0x6e, 0x73, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2d, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2e, 0x64, 0x65,
0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x0a, 0x74, 0x69, 0x6d,
0x66, 0x66, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x62, 0x65, 0x31, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x25, 0x48, 0x3a, 0x25, 0x4d, 0x0a, 0x74,
0x61, 0x72, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6d, 0x65, 0x32, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x25, 0x41, 0x20, 0x25, 0x64,
0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x74, 0x20, 0x25, 0x42, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x31, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x20,
0x61, 0x73, 0x6b, 0x62, 0x61, 0x72, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x3d, 0x20, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x32, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x20, 0x3d,
0x6f, 0x72, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x20, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20,
0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b,
0x3d, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x32, 0x20, 0x30, 0x0a, 0x63, 0x6c, 0x6f, 0x63,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x6b, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x20, 0x3d, 0x20, 0x0a, 0x63,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f,
0x20, 0x54, 0x61, 0x73, 0x6b, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x74, 0x6e, 0x65, 0x20, 0x3d, 0x20, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6c, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f,
0x65, 0x78, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x63,
0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x74, 0x61, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x6f, 0x72, 0x61, 0x67,
0x73, 0x6b, 0x5f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x65, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d,
0x3d, 0x20, 0x31, 0x0a, 0x75, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x75, 0x77, 0x68, 0x65, 0x65, 0x6c,
0x62, 0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x3d, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64,
0x20, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x77, 0x68, 0x65, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x0a, 0x23,
0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x73, 0x69, 0x7a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x65, 0x20, 0x3d, 0x20, 0x31, 0x35, 0x30, 0x20, 0x33, 0x35, 0x0a, 0x74, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a,
0x61, 0x73, 0x6b, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x23, 0x20, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x74,
0x3d, 0x20, 0x32, 0x20, 0x32, 0x20, 0x34, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f,
0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x20, 0x3d, 0x20, 0x31, 0x6c, 0x6f, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x0a, 0x62, 0x61, 0x74,
0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x6d, 0x64, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x74, 0x69,
0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x79, 0x2d, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x22, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x20, 0x6c, 0x6f,
0x66, 0x66, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x77, 0x22, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x62, 0x61,
0x64, 0x20, 0x3d, 0x20, 0x32, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x31, 0x20, 0x30,
0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64,
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x33, 0x0a, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x68, 0x69, 0x64,
0x74, 0x61, 0x73, 0x6b, 0x5f, 0x75, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x31, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x63, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x69, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x62, 0x61, 0x74, 0x74,
0x64, 0x20, 0x3d, 0x20, 0x34, 0x0a, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x65, 0x72, 0x79, 0x5f, 0x72, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20,
0x63, 0x6f, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x3d, 0x20, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x63,
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x75,
0x20, 0x32, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6c, 0x65, 0x66, 0x77, 0x68, 0x65, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x62, 0x61,
0x74, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x5f, 0x69, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x64, 0x77, 0x68, 0x65, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x63, 0x6f, 0x6e, 0x69, 0x66, 0x79, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x61, 0x63, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x63,
0x5f, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x6d, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x61, 0x63, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
0x6e, 0x65, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x72, 0x69, 0x67, 0x65, 0x64, 0x5f, 0x63, 0x6d, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x68, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0a, 0x6d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x6f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x54, 0x6f, 0x6f, 0x6c, 0x74,
0x75, 0x70, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x0a, 0x69, 0x70, 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x74, 0x69, 0x6d,
0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x2e, 0x35, 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f,
0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x20, 0x3d, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x2e, 0x31, 0x0a,
0x69, 0x66, 0x79, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x32,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x32, 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x35, 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x66,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x53, 0x79, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
0x73, 0x74, 0x65, 0x6d, 0x20, 0x74, 0x72, 0x61, 0x79, 0x20, 0x28, 0x6e, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x0a};
0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x61, 0x72, 0x65, 0x61, 0x29, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x72, 0x61,
0x79, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20,
0x30, 0x20, 0x34, 0x20, 0x32, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x72, 0x61,
0x79, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64,
0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x73, 0x79, 0x73, 0x74,
0x72, 0x61, 0x79, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x61,
0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x0a, 0x73, 0x79, 0x73,
0x74, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x73, 0x69,
0x7a, 0x65, 0x20, 0x3d, 0x20, 0x32, 0x34, 0x0a, 0x73, 0x79, 0x73, 0x74,
0x72, 0x61, 0x79, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x61, 0x73, 0x62,
0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x73,
0x79, 0x73, 0x74, 0x72, 0x61, 0x79, 0x5f, 0x6d, 0x6f, 0x6e, 0x69, 0x74,
0x6f, 0x72, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23,
0x20, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x0a, 0x6c, 0x61,
0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
0x6e, 0x67, 0x20, 0x3d, 0x20, 0x32, 0x20, 0x34, 0x20, 0x32, 0x0a, 0x6c,
0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x63, 0x6b,
0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20,
0x30, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69,
0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75,
0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x6c, 0x61,
0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f,
0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x32, 0x34, 0x0a, 0x6c, 0x61,
0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f,
0x61, 0x73, 0x62, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x20, 0x30, 0x20,
0x30, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69,
0x63, 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x5f, 0x6f, 0x76,
0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x73,
0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x31,
0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x74, 0x6f,
0x6f, 0x6c, 0x74, 0x69, 0x70, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x6c, 0x61,
0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f,
0x61, 0x70, 0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73,
0x68, 0x61, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x74, 0x69, 0x6e, 0x74, 0x32, 0x63,
0x6f, 0x6e, 0x66, 0x2e, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a,
0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65,
0x6d, 0x5f, 0x61, 0x70, 0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73, 0x72,
0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65,
0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x2f, 0x74, 0x69, 0x6e, 0x74, 0x32, 0x63, 0x6f, 0x6e, 0x66, 0x2e,
0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x6c, 0x61, 0x75, 0x6e,
0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x70,
0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61,
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x2f, 0x66, 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x2e,
0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x6c, 0x61, 0x75, 0x6e,
0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x70,
0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61,
0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x2f, 0x69, 0x63, 0x65, 0x77, 0x65, 0x61, 0x73, 0x65,
0x6c, 0x2e, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x6c, 0x61,
0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f,
0x61, 0x70, 0x70, 0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73,
0x68, 0x61, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69,
0x75, 0x6d, 0x2d, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x2e, 0x64,
0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x0a, 0x6c, 0x61, 0x75, 0x6e, 0x63,
0x68, 0x65, 0x72, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x70, 0x70,
0x20, 0x3d, 0x20, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x73, 0x68, 0x61, 0x72,
0x65, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2d, 0x63, 0x68,
0x72, 0x6f, 0x6d, 0x65, 0x2e, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70,
0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x43, 0x6c, 0x6f, 0x63, 0x6b,
0x0a, 0x74, 0x69, 0x6d, 0x65, 0x31, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61,
0x74, 0x20, 0x3d, 0x20, 0x25, 0x48, 0x3a, 0x25, 0x4d, 0x0a, 0x74, 0x69,
0x6d, 0x65, 0x32, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x3d,
0x20, 0x25, 0x41, 0x20, 0x25, 0x64, 0x20, 0x25, 0x42, 0x0a, 0x74, 0x69,
0x6d, 0x65, 0x31, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65,
0x20, 0x3d, 0x20, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x32, 0x5f, 0x74, 0x69,
0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x20, 0x3d, 0x20, 0x0a, 0x63, 0x6c,
0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c,
0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x20, 0x31, 0x30, 0x30, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x70,
0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x32, 0x20, 0x30,
0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x30,
0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x74,
0x69, 0x70, 0x20, 0x3d, 0x20, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x74, 0x69, 0x6d, 0x65,
0x7a, 0x6f, 0x6e, 0x65, 0x20, 0x3d, 0x20, 0x0a, 0x63, 0x6c, 0x6f, 0x63,
0x6b, 0x5f, 0x6c, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6d,
0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x63, 0x6c, 0x6f, 0x63,
0x6b, 0x5f, 0x72, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6d,
0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x6f, 0x72, 0x61, 0x67, 0x65,
0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6d, 0x63, 0x6c, 0x69, 0x63,
0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20,
0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x75, 0x77, 0x68, 0x65, 0x65,
0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20,
0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x77, 0x68, 0x65, 0x65,
0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20,
0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x42, 0x61, 0x74, 0x74, 0x65,
0x72, 0x79, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x74,
0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x62,
0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x6f, 0x77, 0x5f, 0x73,
0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x0a, 0x62,
0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x6f, 0x77, 0x5f, 0x63,
0x6d, 0x64, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2d,
0x73, 0x65, 0x6e, 0x64, 0x20, 0x22, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72,
0x79, 0x20, 0x6c, 0x6f, 0x77, 0x22, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65,
0x72, 0x79, 0x5f, 0x66, 0x6f, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f,
0x72, 0x20, 0x3d, 0x20, 0x23, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x20,
0x31, 0x30, 0x30, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f,
0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x31, 0x20,
0x30, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x62, 0x61,
0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20,
0x3d, 0x20, 0x30, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f,
0x68, 0x69, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x31, 0x0a, 0x62,
0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6c, 0x63, 0x6c, 0x69, 0x63,
0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20,
0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x72, 0x63, 0x6c,
0x69, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20,
0x3d, 0x20, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x6d,
0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
0x64, 0x20, 0x3d, 0x20, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79,
0x5f, 0x75, 0x77, 0x68, 0x65, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x62, 0x61, 0x74, 0x74, 0x65,
0x72, 0x79, 0x5f, 0x64, 0x77, 0x68, 0x65, 0x65, 0x6c, 0x5f, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x0a, 0x61, 0x63, 0x5f,
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6d,
0x64, 0x20, 0x3d, 0x20, 0x0a, 0x61, 0x63, 0x5f, 0x64, 0x69, 0x73, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6d, 0x64,
0x20, 0x3d, 0x20, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, 0x54, 0x6f,
0x6f, 0x6c, 0x74, 0x69, 0x70, 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69,
0x70, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f,
0x75, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x2e, 0x35, 0x0a, 0x74, 0x6f, 0x6f,
0x6c, 0x74, 0x69, 0x70, 0x5f, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x74, 0x69,
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x2e, 0x31, 0x0a,
0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x70, 0x61, 0x64, 0x64,
0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x32, 0x20, 0x32, 0x0a, 0x74, 0x6f,
0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72,
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x35, 0x0a,
0x74, 0x6f, 0x6f, 0x6c, 0x74, 0x69, 0x70, 0x5f, 0x66, 0x6f, 0x6e, 0x74,
0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x23, 0x32, 0x32,
0x32, 0x32, 0x32, 0x32, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x0a
};
unsigned int themes_tint2rc_len = 4870; unsigned int themes_tint2rc_len = 4870;

View File

@@ -41,290 +41,290 @@ Tooltip g_tooltip;
void default_tooltip() void default_tooltip()
{ {
// give the tooltip some reasonable default values // give the tooltip some reasonable default values
memset(&g_tooltip, 0, sizeof(Tooltip)); memset(&g_tooltip, 0, sizeof(Tooltip));
g_tooltip.font_color.rgb[0] = 1; g_tooltip.font_color.rgb[0] = 1;
g_tooltip.font_color.rgb[1] = 1; g_tooltip.font_color.rgb[1] = 1;
g_tooltip.font_color.rgb[2] = 1; g_tooltip.font_color.rgb[2] = 1;
g_tooltip.font_color.alpha = 1; g_tooltip.font_color.alpha = 1;
just_shown = FALSE; just_shown = FALSE;
} }
void cleanup_tooltip() void cleanup_tooltip()
{ {
stop_tooltip_timeout(); stop_tooltip_timeout();
tooltip_hide(NULL); tooltip_hide(NULL);
tooltip_copy_text(NULL); tooltip_copy_text(NULL);
if (g_tooltip.window) if (g_tooltip.window)
XDestroyWindow(server.display, g_tooltip.window); XDestroyWindow(server.display, g_tooltip.window);
g_tooltip.window = 0; g_tooltip.window = 0;
pango_font_description_free(g_tooltip.font_desc); pango_font_description_free(g_tooltip.font_desc);
g_tooltip.font_desc = NULL; g_tooltip.font_desc = NULL;
} }
void init_tooltip() void init_tooltip()
{ {
if (!g_tooltip.bg) if (!g_tooltip.bg)
g_tooltip.bg = &g_array_index(backgrounds, Background, 0); g_tooltip.bg = &g_array_index(backgrounds, Background, 0);
tooltip_init_fonts(); tooltip_init_fonts();
XSetWindowAttributes attr; XSetWindowAttributes attr;
attr.override_redirect = True; attr.override_redirect = True;
attr.event_mask = StructureNotifyMask; attr.event_mask = StructureNotifyMask;
attr.colormap = server.colormap; attr.colormap = server.colormap;
attr.background_pixel = 0; attr.background_pixel = 0;
attr.border_pixel = 0; attr.border_pixel = 0;
unsigned long mask = CWEventMask | CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect; unsigned long mask = CWEventMask | CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect;
if (g_tooltip.window) if (g_tooltip.window)
XDestroyWindow(server.display, g_tooltip.window); XDestroyWindow(server.display, g_tooltip.window);
g_tooltip.window = XCreateWindow(server.display, g_tooltip.window = XCreateWindow(server.display,
server.root_win, server.root_win,
0, 0,
0, 0,
100, 100,
20, 20,
0, 0,
server.depth, server.depth,
InputOutput, InputOutput,
server.visual, server.visual,
mask, mask,
&attr); &attr);
} }
void tooltip_init_fonts() void tooltip_init_fonts()
{ {
if (!g_tooltip.font_desc) if (!g_tooltip.font_desc)
g_tooltip.font_desc = pango_font_description_from_string(get_default_font()); g_tooltip.font_desc = pango_font_description_from_string(get_default_font());
} }
void tooltip_default_font_changed() void tooltip_default_font_changed()
{ {
if (g_tooltip.has_font) if (g_tooltip.has_font)
return; return;
if (!g_tooltip.has_font) { if (!g_tooltip.has_font) {
pango_font_description_free(g_tooltip.font_desc); pango_font_description_free(g_tooltip.font_desc);
g_tooltip.font_desc = NULL; g_tooltip.font_desc = NULL;
} }
tooltip_init_fonts(); tooltip_init_fonts();
tooltip_update(); tooltip_update();
} }
void tooltip_trigger_show(Area *area, Panel *p, XEvent *e) void tooltip_trigger_show(Area *area, Panel *p, XEvent *e)
{ {
// Position the tooltip in the center of the area // Position the tooltip in the center of the area
x = area->posx + MIN(area->width / 3, 22) + e->xmotion.x_root - e->xmotion.x; x = area->posx + MIN(area->width / 3, 22) + e->xmotion.x_root - e->xmotion.x;
y = area->posy + area->height / 2 + e->xmotion.y_root - e->xmotion.y; y = area->posy + area->height / 2 + e->xmotion.y_root - e->xmotion.y;
just_shown = TRUE; just_shown = TRUE;
g_tooltip.panel = p; g_tooltip.panel = p;
if (g_tooltip.mapped && g_tooltip.area != area) { if (g_tooltip.mapped && g_tooltip.area != area) {
tooltip_copy_text(area); tooltip_copy_text(area);
tooltip_update(); tooltip_update();
stop_tooltip_timeout(); stop_tooltip_timeout();
} else if (!g_tooltip.mapped) { } else if (!g_tooltip.mapped) {
start_show_timeout(); start_show_timeout();
} }
} }
void tooltip_show(void *arg) void tooltip_show(void *arg)
{ {
int mx, my; int mx, my;
Window w; Window w;
XTranslateCoordinates(server.display, server.root_win, g_tooltip.panel->main_win, x, y, &mx, &my, &w); XTranslateCoordinates(server.display, server.root_win, g_tooltip.panel->main_win, x, y, &mx, &my, &w);
Area *area = find_area_under_mouse(g_tooltip.panel, mx, my); Area *area = find_area_under_mouse(g_tooltip.panel, mx, my);
if (!g_tooltip.mapped && area->_get_tooltip_text) { if (!g_tooltip.mapped && area->_get_tooltip_text) {
tooltip_copy_text(area); tooltip_copy_text(area);
g_tooltip.mapped = True; g_tooltip.mapped = True;
XMapWindow(server.display, g_tooltip.window); XMapWindow(server.display, g_tooltip.window);
tooltip_update(); tooltip_update();
XFlush(server.display); XFlush(server.display);
} }
} }
void tooltip_update_geometry() void tooltip_update_geometry()
{ {
Panel *panel = g_tooltip.panel; Panel *panel = g_tooltip.panel;
int screen_width = server.monitors[panel->monitor].x + server.monitors[panel->monitor].width; int screen_width = server.monitors[panel->monitor].x + server.monitors[panel->monitor].width;
cairo_surface_t *cs = cairo_xlib_surface_create(server.display, g_tooltip.window, server.visual, width, height); cairo_surface_t *cs = cairo_xlib_surface_create(server.display, g_tooltip.window, server.visual, width, height);
cairo_t *c = cairo_create(cs); cairo_t *c = cairo_create(cs);
PangoLayout *layout = pango_cairo_create_layout(c); PangoLayout *layout = pango_cairo_create_layout(c);
pango_layout_set_font_description(layout, g_tooltip.font_desc); pango_layout_set_font_description(layout, g_tooltip.font_desc);
PangoRectangle r1, r2; PangoRectangle r1, r2;
pango_layout_set_text(layout, "1234567890", -1); pango_layout_set_text(layout, "1234567890", -1);
pango_layout_get_pixel_extents(layout, &r1, &r2); pango_layout_get_pixel_extents(layout, &r1, &r2);
int max_width = MIN(r2.width * 7, screen_width * 2 / 3); int max_width = MIN(r2.width * 7, screen_width * 2 / 3);
pango_layout_set_width(layout, max_width * PANGO_SCALE); pango_layout_set_width(layout, max_width * PANGO_SCALE);
pango_layout_set_text(layout, g_tooltip.tooltip_text, -1); pango_layout_set_text(layout, g_tooltip.tooltip_text, -1);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD); pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
pango_layout_get_pixel_extents(layout, &r1, &r2); pango_layout_get_pixel_extents(layout, &r1, &r2);
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx + r2.width; width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx + r2.width;
height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy + r2.height; height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy + r2.height;
if (panel_horizontal && panel_position & BOTTOM) if (panel_horizontal && panel_position & BOTTOM)
y = panel->posy - height; y = panel->posy - height;
else if (panel_horizontal && panel_position & TOP) else if (panel_horizontal && panel_position & TOP)
y = panel->posy + panel->area.height; y = panel->posy + panel->area.height;
else if (panel_position & LEFT) else if (panel_position & LEFT)
x = panel->posx + panel->area.width; x = panel->posx + panel->area.width;
else else
x = panel->posx - width; x = panel->posx - width;
g_object_unref(layout); g_object_unref(layout);
cairo_destroy(c); cairo_destroy(c);
cairo_surface_destroy(cs); cairo_surface_destroy(cs);
} }
void tooltip_adjust_geometry() void tooltip_adjust_geometry()
{ {
// adjust coordinates and size to not go offscreen // adjust coordinates and size to not go offscreen
// it seems quite impossible that the height needs to be adjusted, but we do it anyway. // it seems quite impossible that the height needs to be adjusted, but we do it anyway.
Panel *panel = g_tooltip.panel; Panel *panel = g_tooltip.panel;
int screen_width = server.monitors[panel->monitor].x + server.monitors[panel->monitor].width; int screen_width = server.monitors[panel->monitor].x + server.monitors[panel->monitor].width;
int screen_height = server.monitors[panel->monitor].y + server.monitors[panel->monitor].height; int screen_height = server.monitors[panel->monitor].y + server.monitors[panel->monitor].height;
if (x + width <= screen_width && y + height <= screen_height && x >= server.monitors[panel->monitor].x && if (x + width <= screen_width && y + height <= screen_height && x >= server.monitors[panel->monitor].x &&
y >= server.monitors[panel->monitor].y) y >= server.monitors[panel->monitor].y)
return; // no adjustment needed return; // no adjustment needed
int min_x, min_y, max_width, max_height; int min_x, min_y, max_width, max_height;
if (panel_horizontal) { if (panel_horizontal) {
min_x = 0; min_x = 0;
max_width = server.monitors[panel->monitor].width; max_width = server.monitors[panel->monitor].width;
max_height = server.monitors[panel->monitor].height - panel->area.height; max_height = server.monitors[panel->monitor].height - panel->area.height;
if (panel_position & BOTTOM) if (panel_position & BOTTOM)
min_y = 0; min_y = 0;
else else
min_y = panel->area.height; min_y = panel->area.height;
} else { } else {
max_width = server.monitors[panel->monitor].width - panel->area.width; max_width = server.monitors[panel->monitor].width - panel->area.width;
min_y = 0; min_y = 0;
max_height = server.monitors[panel->monitor].height; max_height = server.monitors[panel->monitor].height;
if (panel_position & LEFT) if (panel_position & LEFT)
min_x = panel->area.width; min_x = panel->area.width;
else else
min_x = 0; min_x = 0;
} }
if (x + width > server.monitors[panel->monitor].x + server.monitors[panel->monitor].width) if (x + width > server.monitors[panel->monitor].x + server.monitors[panel->monitor].width)
x = server.monitors[panel->monitor].x + server.monitors[panel->monitor].width - width; x = server.monitors[panel->monitor].x + server.monitors[panel->monitor].width - width;
if (y + height > server.monitors[panel->monitor].y + server.monitors[panel->monitor].height) if (y + height > server.monitors[panel->monitor].y + server.monitors[panel->monitor].height)
y = server.monitors[panel->monitor].y + server.monitors[panel->monitor].height - height; y = server.monitors[panel->monitor].y + server.monitors[panel->monitor].height - height;
if (x < min_x) if (x < min_x)
x = min_x; x = min_x;
if (width > max_width) if (width > max_width)
width = max_width; width = max_width;
if (y < min_y) if (y < min_y)
y = min_y; y = min_y;
if (height > max_height) if (height > max_height)
height = max_height; height = max_height;
} }
void tooltip_update() void tooltip_update()
{ {
if (!g_tooltip.tooltip_text) { if (!g_tooltip.tooltip_text) {
tooltip_hide(0); tooltip_hide(0);
return; return;
} }
tooltip_update_geometry(); tooltip_update_geometry();
if (just_shown) { if (just_shown) {
if (!panel_horizontal) if (!panel_horizontal)
y -= height / 2; // center vertically y -= height / 2; // center vertically
just_shown = FALSE; just_shown = FALSE;
} }
tooltip_adjust_geometry(); tooltip_adjust_geometry();
XMoveResizeWindow(server.display, g_tooltip.window, x, y, width, height); XMoveResizeWindow(server.display, g_tooltip.window, x, y, width, height);
// Stuff for drawing the tooltip // Stuff for drawing the tooltip
cairo_surface_t *cs = cairo_xlib_surface_create(server.display, g_tooltip.window, server.visual, width, height); cairo_surface_t *cs = cairo_xlib_surface_create(server.display, g_tooltip.window, server.visual, width, height);
cairo_t *c = cairo_create(cs); cairo_t *c = cairo_create(cs);
Color bc = g_tooltip.bg->fill_color; Color bc = g_tooltip.bg->fill_color;
Border b = g_tooltip.bg->border; Border b = g_tooltip.bg->border;
if (server.real_transparency) { if (server.real_transparency) {
clear_pixmap(g_tooltip.window, 0, 0, width, height); clear_pixmap(g_tooltip.window, 0, 0, width, height);
draw_rect(c, b.width, b.width, width - 2 * b.width, height - 2 * b.width, b.radius - b.width / 1.571); draw_rect(c, b.width, b.width, width - 2 * b.width, height - 2 * b.width, b.radius - b.width / 1.571);
cairo_set_source_rgba(c, bc.rgb[0], bc.rgb[1], bc.rgb[2], bc.alpha); cairo_set_source_rgba(c, bc.rgb[0], bc.rgb[1], bc.rgb[2], bc.alpha);
} else { } else {
cairo_rectangle(c, 0., 0, width, height); cairo_rectangle(c, 0., 0, width, height);
cairo_set_source_rgb(c, bc.rgb[0], bc.rgb[1], bc.rgb[2]); cairo_set_source_rgb(c, bc.rgb[0], bc.rgb[1], bc.rgb[2]);
} }
cairo_fill(c); cairo_fill(c);
cairo_set_line_width(c, b.width); cairo_set_line_width(c, b.width);
if (server.real_transparency) if (server.real_transparency)
draw_rect(c, b.width / 2.0, b.width / 2.0, width - b.width, height - b.width, b.radius); draw_rect(c, b.width / 2.0, b.width / 2.0, width - b.width, height - b.width, b.radius);
else else
cairo_rectangle(c, b.width / 2.0, b.width / 2.0, width - b.width, height - b.width); cairo_rectangle(c, b.width / 2.0, b.width / 2.0, width - b.width, height - b.width);
cairo_set_source_rgba(c, b.color.rgb[0], b.color.rgb[1], b.color.rgb[2], b.color.alpha); cairo_set_source_rgba(c, b.color.rgb[0], b.color.rgb[1], b.color.rgb[2], b.color.alpha);
cairo_stroke(c); cairo_stroke(c);
Color fc = g_tooltip.font_color; Color fc = g_tooltip.font_color;
cairo_set_source_rgba(c, fc.rgb[0], fc.rgb[1], fc.rgb[2], fc.alpha); cairo_set_source_rgba(c, fc.rgb[0], fc.rgb[1], fc.rgb[2], fc.alpha);
PangoLayout *layout = pango_cairo_create_layout(c); PangoLayout *layout = pango_cairo_create_layout(c);
pango_layout_set_font_description(layout, g_tooltip.font_desc); pango_layout_set_font_description(layout, g_tooltip.font_desc);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD); pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
pango_layout_set_text(layout, g_tooltip.tooltip_text, -1); pango_layout_set_text(layout, g_tooltip.tooltip_text, -1);
PangoRectangle r1, r2; PangoRectangle r1, r2;
pango_layout_get_pixel_extents(layout, &r1, &r2); pango_layout_get_pixel_extents(layout, &r1, &r2);
pango_layout_set_width(layout, width * PANGO_SCALE); pango_layout_set_width(layout, width * PANGO_SCALE);
pango_layout_set_height(layout, height * PANGO_SCALE); pango_layout_set_height(layout, height * PANGO_SCALE);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
// I do not know why this is the right way, but with the below cairo_move_to it seems to be centered (horiz. and // I do not know why this is the right way, but with the below cairo_move_to it seems to be centered (horiz. and
// vert.) // vert.)
cairo_move_to(c, cairo_move_to(c,
-r1.x / 2 + left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx, -r1.x / 2 + left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx,
-r1.y / 2 + 1 + top_bg_border_width(g_tooltip.bg) + g_tooltip.paddingy); -r1.y / 2 + 1 + top_bg_border_width(g_tooltip.bg) + g_tooltip.paddingy);
pango_cairo_show_layout(c, layout); pango_cairo_show_layout(c, layout);
g_object_unref(layout); g_object_unref(layout);
cairo_destroy(c); cairo_destroy(c);
cairo_surface_destroy(cs); cairo_surface_destroy(cs);
} }
void tooltip_trigger_hide() void tooltip_trigger_hide()
{ {
if (g_tooltip.mapped) { if (g_tooltip.mapped) {
tooltip_copy_text(0); tooltip_copy_text(0);
start_hide_timeout(); start_hide_timeout();
} else { } else {
// tooltip not visible yet, but maybe a timeout is still pending // tooltip not visible yet, but maybe a timeout is still pending
stop_tooltip_timeout(); stop_tooltip_timeout();
} }
} }
void tooltip_hide(void *arg) void tooltip_hide(void *arg)
{ {
if (g_tooltip.mapped) { if (g_tooltip.mapped) {
g_tooltip.mapped = False; g_tooltip.mapped = False;
XUnmapWindow(server.display, g_tooltip.window); XUnmapWindow(server.display, g_tooltip.window);
XFlush(server.display); XFlush(server.display);
} }
} }
void start_show_timeout() void start_show_timeout()
{ {
change_timeout(&g_tooltip.timeout, g_tooltip.show_timeout_msec, 0, tooltip_show, 0); change_timeout(&g_tooltip.timeout, g_tooltip.show_timeout_msec, 0, tooltip_show, 0);
} }
void start_hide_timeout() void start_hide_timeout()
{ {
change_timeout(&g_tooltip.timeout, g_tooltip.hide_timeout_msec, 0, tooltip_hide, 0); change_timeout(&g_tooltip.timeout, g_tooltip.hide_timeout_msec, 0, tooltip_hide, 0);
} }
void stop_tooltip_timeout() void stop_tooltip_timeout()
{ {
stop_timeout(g_tooltip.timeout); stop_timeout(g_tooltip.timeout);
} }
void tooltip_copy_text(Area *area) void tooltip_copy_text(Area *area)
{ {
free(g_tooltip.tooltip_text); free(g_tooltip.tooltip_text);
if (area && area->_get_tooltip_text) if (area && area->_get_tooltip_text)
g_tooltip.tooltip_text = area->_get_tooltip_text(area); g_tooltip.tooltip_text = area->_get_tooltip_text(area);
else else
g_tooltip.tooltip_text = NULL; g_tooltip.tooltip_text = NULL;
g_tooltip.area = area; g_tooltip.area = area;
} }

View File

@@ -23,20 +23,20 @@
#include "timer.h" #include "timer.h"
typedef struct { typedef struct {
Area *area; // never ever use the area attribut if you are not 100% sure that this area was not freed Area *area; // never ever use the area attribut if you are not 100% sure that this area was not freed
char *tooltip_text; char *tooltip_text;
Panel *panel; Panel *panel;
Window window; Window window;
int show_timeout_msec; int show_timeout_msec;
int hide_timeout_msec; int hide_timeout_msec;
Bool mapped; Bool mapped;
int paddingx; int paddingx;
int paddingy; int paddingy;
gboolean has_font; gboolean has_font;
PangoFontDescription *font_desc; PangoFontDescription *font_desc;
Color font_color; Color font_color;
Background *bg; Background *bg;
timeout *timeout; timeout *timeout;
} Tooltip; } Tooltip;
extern Tooltip g_tooltip; extern Tooltip g_tooltip;

File diff suppressed because it is too large Load Diff

View File

@@ -121,125 +121,125 @@
// The Area's _get_tooltip_text member must point to this function. // The Area's _get_tooltip_text member must point to this function.
typedef enum BorderMask { typedef enum BorderMask {
BORDER_TOP = 1 << 0, BORDER_TOP = 1 << 0,
BORDER_BOTTOM = 1 << 1, BORDER_BOTTOM = 1 << 1,
BORDER_LEFT = 1 << 2, BORDER_LEFT = 1 << 2,
BORDER_RIGHT = 1 << 3 BORDER_RIGHT = 1 << 3
} BorderMask; } BorderMask;
#define BORDER_ALL (BORDER_TOP | BORDER_BOTTOM | BORDER_LEFT | BORDER_RIGHT) #define BORDER_ALL (BORDER_TOP | BORDER_BOTTOM | BORDER_LEFT | BORDER_RIGHT)
typedef struct Border { typedef struct Border {
// It's essential that the first member is color // It's essential that the first member is color
Color color; Color color;
// Width in pixels // Width in pixels
int width; int width;
// Corner radius // Corner radius
int radius; int radius;
// Mask: bitwise OR of BorderMask // Mask: bitwise OR of BorderMask
int mask; int mask;
} Border; } Border;
typedef enum MouseState { MOUSE_NORMAL = 0, MOUSE_OVER = 1, MOUSE_DOWN = 2, MOUSE_STATE_COUNT } MouseState; typedef enum MouseState { MOUSE_NORMAL = 0, MOUSE_OVER = 1, MOUSE_DOWN = 2, MOUSE_STATE_COUNT } MouseState;
typedef struct Background { typedef struct Background {
// Normal state // Normal state
Color fill_color; Color fill_color;
Border border; Border border;
// On mouse hover // On mouse hover
Color fill_color_hover; Color fill_color_hover;
Color border_color_hover; Color border_color_hover;
// On mouse press // On mouse press
Color fill_color_pressed; Color fill_color_pressed;
Color border_color_pressed; Color border_color_pressed;
// Pointer to a GradientClass or NULL, no ownership // Pointer to a GradientClass or NULL, no ownership
GradientClass *gradients[MOUSE_STATE_COUNT]; GradientClass *gradients[MOUSE_STATE_COUNT];
} Background; } Background;
typedef enum Layout { typedef enum Layout {
LAYOUT_DYNAMIC, LAYOUT_DYNAMIC,
LAYOUT_FIXED, LAYOUT_FIXED,
} Layout; } Layout;
typedef enum Alignment { typedef enum Alignment {
ALIGN_LEFT = 0, ALIGN_LEFT = 0,
ALIGN_CENTER = 1, ALIGN_CENTER = 1,
ALIGN_RIGHT = 2, ALIGN_RIGHT = 2,
} Alignment; } Alignment;
struct Panel; struct Panel;
typedef struct Area { typedef struct Area {
// Position relative to the panel window // Position relative to the panel window
int posx, posy; int posx, posy;
// Size, including borders // Size, including borders
int width, height; int width, height;
int old_width, old_height; int old_width, old_height;
Background *bg; Background *bg;
// Each element is a GradientInstance attached to this Area (list can be empty) // Each element is a GradientInstance attached to this Area (list can be empty)
GList *gradient_instances_by_state[MOUSE_STATE_COUNT]; GList *gradient_instances_by_state[MOUSE_STATE_COUNT];
// Each element is a GradientInstance that depends on this Area's geometry (position or size) // Each element is a GradientInstance that depends on this Area's geometry (position or size)
GList *dependent_gradients; GList *dependent_gradients;
// List of children, each one a pointer to Area // List of children, each one a pointer to Area
GList *children; GList *children;
// Pointer to the parent Area or NULL // Pointer to the parent Area or NULL
void *parent; void *parent;
// Pointer to the Panel that contains this Area // Pointer to the Panel that contains this Area
void *panel; void *panel;
Layout size_mode; Layout size_mode;
Alignment alignment; Alignment alignment;
gboolean has_mouse_over_effect; gboolean has_mouse_over_effect;
gboolean has_mouse_press_effect; gboolean has_mouse_press_effect;
// TODO padding/spacing is a clusterfuck // TODO padding/spacing is a clusterfuck
// paddingxlr = padding // paddingxlr = padding
// paddingy = vertical padding, sometimes // paddingy = vertical padding, sometimes
// paddingx = spacing // paddingx = spacing
int paddingxlr, paddingx, paddingy; int paddingxlr, paddingx, paddingy;
MouseState mouse_state; MouseState mouse_state;
// Set to non-zero if the Area is visible. An object may exist but stay hidden. // Set to non-zero if the Area is visible. An object may exist but stay hidden.
gboolean on_screen; gboolean on_screen;
// Set to non-zero if the size of the Area has to be recalculated. // Set to non-zero if the size of the Area has to be recalculated.
gboolean resize_needed; gboolean resize_needed;
// Set to non-zero if the Area has to be redrawn. // Set to non-zero if the Area has to be redrawn.
// Do not set this directly; use schedule_redraw() instead. // Do not set this directly; use schedule_redraw() instead.
gboolean _redraw_needed; gboolean _redraw_needed;
// Set to non-zero if the position/size has changed, thus _on_change_layout needs to be called // Set to non-zero if the position/size has changed, thus _on_change_layout needs to be called
gboolean _changed; gboolean _changed;
// This is the pixmap on which the Area is rendered. Render to it directly if needed. // This is the pixmap on which the Area is rendered. Render to it directly if needed.
Pixmap pix; Pixmap pix;
Pixmap pix_by_state[MOUSE_STATE_COUNT]; Pixmap pix_by_state[MOUSE_STATE_COUNT];
char name[32]; char name[32];
// Callbacks // Callbacks
// Called on draw before any drawing takes place, obj = pointer to the Area // Called on draw before any drawing takes place, obj = pointer to the Area
void (*_clear)(void *obj); void (*_clear)(void *obj);
// Called on draw, obj = pointer to the Area // Called on draw, obj = pointer to the Area
void (*_draw_foreground)(void *obj, cairo_t *c); void (*_draw_foreground)(void *obj, cairo_t *c);
// Called on resize, obj = pointer to the Area // Called on resize, obj = pointer to the Area
// Returns 1 if the new size is different than the previous size. // Returns 1 if the new size is different than the previous size.
gboolean (*_resize)(void *obj); gboolean (*_resize)(void *obj);
// Called before resize, obj = pointer to the Area // Called before resize, obj = pointer to the Area
// Returns the desired size of the Area // Returns the desired size of the Area
int (*_compute_desired_size)(void *obj); int (*_compute_desired_size)(void *obj);
// Implemented only to override the default layout algorithm for this widget. // Implemented only to override the default layout algorithm for this widget.
// For example, if this widget is a cell in a table, its position and size should be computed here. // For example, if this widget is a cell in a table, its position and size should be computed here.
void (*_on_change_layout)(void *obj); void (*_on_change_layout)(void *obj);
// Returns a copy of the tooltip to be displayed for this widget. // Returns a copy of the tooltip to be displayed for this widget.
// The caller takes ownership of the pointer. // The caller takes ownership of the pointer.
char *(*_get_tooltip_text)(void *obj); char *(*_get_tooltip_text)(void *obj);
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window. // Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
// Leave this to NULL to use a default implementation. // Leave this to NULL to use a default implementation.
gboolean (*_is_under_mouse)(void *obj, int x, int y); gboolean (*_is_under_mouse)(void *obj, int x, int y);
// Prints the geometry of the object on stderr, with left indentation of indent spaces. // Prints the geometry of the object on stderr, with left indentation of indent spaces.
void (*_dump_geometry)(void *obj, int indent); void (*_dump_geometry)(void *obj, int indent);
} Area; } Area;
// Initializes the Background member to default values. // Initializes the Background member to default values.

View File

@@ -32,129 +32,129 @@
void init_cache(Cache *cache) void init_cache(Cache *cache)
{ {
if (cache->_table) if (cache->_table)
free_cache(cache); free_cache(cache);
cache->_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); cache->_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
cache->dirty = FALSE; cache->dirty = FALSE;
cache->loaded = FALSE; cache->loaded = FALSE;
} }
void free_cache(Cache *cache) void free_cache(Cache *cache)
{ {
if (cache->_table) if (cache->_table)
g_hash_table_destroy(cache->_table); g_hash_table_destroy(cache->_table);
cache->_table = NULL; cache->_table = NULL;
cache->dirty = FALSE; cache->dirty = FALSE;
cache->loaded = FALSE; cache->loaded = FALSE;
} }
void load_cache(Cache *cache, const gchar *cache_path) void load_cache(Cache *cache, const gchar *cache_path)
{ {
init_cache(cache); init_cache(cache);
cache->loaded = TRUE; cache->loaded = TRUE;
int fd = open(cache_path, O_RDONLY); int fd = open(cache_path, O_RDONLY);
if (fd == -1) if (fd == -1)
return; return;
flock(fd, LOCK_SH); flock(fd, LOCK_SH);
FILE *f = fopen(cache_path, "rt"); FILE *f = fopen(cache_path, "rt");
if (!f) if (!f)
goto unlock; goto unlock;
char *line = NULL; char *line = NULL;
size_t line_size; size_t line_size;
while (getline(&line, &line_size, f) >= 0) { while (getline(&line, &line_size, f) >= 0) {
char *key, *value; char *key, *value;
size_t line_len = strlen(line); size_t line_len = strlen(line);
gboolean has_newline = FALSE; gboolean has_newline = FALSE;
if (line_len >= 1) { if (line_len >= 1) {
if (line[line_len - 1] == '\n') { if (line[line_len - 1] == '\n') {
line[line_len - 1] = '\0'; line[line_len - 1] = '\0';
line_len--; line_len--;
has_newline = TRUE; has_newline = TRUE;
} }
} }
if (!has_newline) if (!has_newline)
break; break;
if (line_len == 0) if (line_len == 0)
continue; continue;
if (parse_line(line, &key, &value)) { if (parse_line(line, &key, &value)) {
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value)); g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
free(key); free(key);
free(value); free(value);
} }
} }
free(line); free(line);
fclose(f); fclose(f);
unlock: unlock:
flock(fd, LOCK_UN); flock(fd, LOCK_UN);
close(fd); close(fd);
} }
void write_cache_line(gpointer key, gpointer value, gpointer user_data) void write_cache_line(gpointer key, gpointer value, gpointer user_data)
{ {
gchar *k = key; gchar *k = key;
gchar *v = value; gchar *v = value;
FILE *f = user_data; FILE *f = user_data;
fprintf(f, "%s=%s\n", k, v); fprintf(f, "%s=%s\n", k, v);
} }
void save_cache(Cache *cache, const gchar *cache_path) void save_cache(Cache *cache, const gchar *cache_path)
{ {
int fd = open(cache_path, O_RDONLY | O_CREAT, 0600); int fd = open(cache_path, O_RDONLY | O_CREAT, 0600);
if (fd == -1) { if (fd == -1) {
gchar *dir_path = g_path_get_dirname(cache_path); gchar *dir_path = g_path_get_dirname(cache_path);
g_mkdir_with_parents(dir_path, 0700); g_mkdir_with_parents(dir_path, 0700);
g_free(dir_path); g_free(dir_path);
fd = open(cache_path, O_RDONLY | O_CREAT, 0600); fd = open(cache_path, O_RDONLY | O_CREAT, 0600);
} }
if (fd == -1) { if (fd == -1) {
fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n"); fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n");
return; return;
} }
flock(fd, LOCK_EX); flock(fd, LOCK_EX);
FILE *f = fopen(cache_path, "w"); FILE *f = fopen(cache_path, "w");
if (!f) { if (!f) {
fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n"); fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n");
goto unlock; goto unlock;
} }
g_hash_table_foreach(cache->_table, write_cache_line, f); g_hash_table_foreach(cache->_table, write_cache_line, f);
fclose(f); fclose(f);
cache->dirty = FALSE; cache->dirty = FALSE;
unlock: unlock:
flock(fd, LOCK_UN); flock(fd, LOCK_UN);
close(fd); close(fd);
} }
const gchar *get_from_cache(Cache *cache, const gchar *key) const gchar *get_from_cache(Cache *cache, const gchar *key)
{ {
if (!cache->_table) if (!cache->_table)
return NULL; return NULL;
return g_hash_table_lookup(cache->_table, key); return g_hash_table_lookup(cache->_table, key);
} }
void add_to_cache(Cache *cache, const gchar *key, const gchar *value) void add_to_cache(Cache *cache, const gchar *key, const gchar *value)
{ {
if (!cache->_table) if (!cache->_table)
init_cache(cache); init_cache(cache);
if (!key || !value) if (!key || !value)
return; return;
gchar *old_value = g_hash_table_lookup(cache->_table, key); gchar *old_value = g_hash_table_lookup(cache->_table, key);
if (old_value && g_str_equal(old_value, value)) if (old_value && g_str_equal(old_value, value))
return; return;
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value)); g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
cache->dirty = TRUE; cache->dirty = TRUE;
} }

View File

@@ -6,9 +6,9 @@
// A cache with string keys and values, backed by a file. // A cache with string keys and values, backed by a file.
// The strings must not be NULL and are stripped of any whitespace at start and end. // The strings must not be NULL and are stripped of any whitespace at start and end.
typedef struct Cache { typedef struct Cache {
gboolean dirty; gboolean dirty;
gboolean loaded; gboolean loaded;
GHashTable *_table; GHashTable *_table;
} Cache; } Cache;
// Initializes the cache. You can also call load_cache directly if you set the memory contents to zero first. // Initializes the cache. You can also call load_cache directly if you set the memory contents to zero first.

View File

@@ -1,2 +1 @@
#include "color.h" #include "color.h"

View File

@@ -2,10 +2,10 @@
#define COLOR_H #define COLOR_H
typedef struct Color { typedef struct Color {
// Values are in [0, 1], with 0 meaning no intensity. // Values are in [0, 1], with 0 meaning no intensity.
double rgb[3]; double rgb[3];
// Values are in [0, 1], with 0 meaning fully transparent, 1 meaning fully opaque. // Values are in [0, 1], with 0 meaning fully transparent, 1 meaning fully opaque.
double alpha; double alpha;
} Color; } Color;
#endif // COLOR_H #endif // COLOR_H

File diff suppressed because it is too large Load Diff

View File

@@ -24,19 +24,19 @@
// mouse actions // mouse actions
typedef enum MouseAction { typedef enum MouseAction {
NONE = 0, NONE = 0,
CLOSE, CLOSE,
TOGGLE, TOGGLE,
ICONIFY, ICONIFY,
SHADE, SHADE,
TOGGLE_ICONIFY, TOGGLE_ICONIFY,
MAXIMIZE_RESTORE, MAXIMIZE_RESTORE,
MAXIMIZE, MAXIMIZE,
RESTORE, RESTORE,
DESKTOP_LEFT, DESKTOP_LEFT,
DESKTOP_RIGHT, DESKTOP_RIGHT,
NEXT_TASK, NEXT_TASK,
PREV_TASK PREV_TASK
} MouseAction; } MouseAction;
#define ALL_DESKTOPS 0xFFFFFFFF #define ALL_DESKTOPS 0xFFFFFFFF
@@ -94,16 +94,16 @@ void create_heuristic_mask(DATA32 *data, int w, int h);
void render_image(Drawable d, int x, int y); void render_image(Drawable d, int x, int y);
void get_text_size2(PangoFontDescription *font, void get_text_size2(PangoFontDescription *font,
int *height_ink, int *height_ink,
int *height, int *height,
int *width, int *width,
int panel_height, int panel_height,
int panel_with, int panel_with,
char *text, char *text,
int len, int len,
PangoWrapMode wrap, PangoWrapMode wrap,
PangoEllipsizeMode ellipsis, PangoEllipsizeMode ellipsis,
gboolean markup); gboolean markup);
void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color, int font_shadow); void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color, int font_shadow);
@@ -125,10 +125,10 @@ GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr
gint cmp_ptr(gconstpointer a, gconstpointer b); gint cmp_ptr(gconstpointer a, gconstpointer b);
#define free_and_null(p) \ #define free_and_null(p) \
{ \ { \
free(p); \ free(p); \
p = NULL; \ p = NULL; \
} }
#if !GLIB_CHECK_VERSION(2, 33, 4) #if !GLIB_CHECK_VERSION(2, 33, 4)
GList *g_list_copy_deep(GList *list, GCopyFunc func, gpointer user_data); GList *g_list_copy_deep(GList *list, GCopyFunc func, gpointer user_data);

View File

@@ -8,116 +8,116 @@
gboolean read_double(const char *str, double *value) gboolean read_double(const char *str, double *value)
{ {
if (!str[0]) if (!str[0])
return FALSE; return FALSE;
char *end; char *end;
*value = strtod(str, &end); *value = strtod(str, &end);
if (end[0]) if (end[0])
return FALSE; return FALSE;
return TRUE; return TRUE;
} }
gboolean read_double_with_percent(const char *str, double *value) gboolean read_double_with_percent(const char *str, double *value)
{ {
if (!str[0]) if (!str[0])
return FALSE; return FALSE;
char *end; char *end;
*value = strtod(str, &end); *value = strtod(str, &end);
if (end[0] == '%' && !end[1]) { if (end[0] == '%' && !end[1]) {
*value *= 0.01; *value *= 0.01;
return TRUE; return TRUE;
} }
if (end[0]) if (end[0])
return FALSE; return FALSE;
return TRUE; return TRUE;
} }
GradientType gradient_type_from_string(const char *str) GradientType gradient_type_from_string(const char *str)
{ {
if (g_str_equal(str, "horizontal")) if (g_str_equal(str, "horizontal"))
return GRADIENT_HORIZONTAL; return GRADIENT_HORIZONTAL;
if (g_str_equal(str, "vertical")) if (g_str_equal(str, "vertical"))
return GRADIENT_VERTICAL; return GRADIENT_VERTICAL;
if (g_str_equal(str, "radial")) if (g_str_equal(str, "radial"))
return GRADIENT_CENTERED; return GRADIENT_CENTERED;
fprintf(stderr, RED "Invalid gradient type: %s" RESET "\n", str); fprintf(stderr, RED "Invalid gradient type: %s" RESET "\n", str);
return GRADIENT_VERTICAL; return GRADIENT_VERTICAL;
} }
void init_gradient(GradientClass *g, GradientType type) void init_gradient(GradientClass *g, GradientType type)
{ {
memset(g, 0, sizeof(*g)); memset(g, 0, sizeof(*g));
g->type = type; g->type = type;
if (g->type == GRADIENT_VERTICAL) { if (g->type == GRADIENT_VERTICAL) {
Offset *offset_top = (Offset *)calloc(1, sizeof(Offset)); Offset *offset_top = (Offset *)calloc(1, sizeof(Offset));
offset_top->constant = TRUE; offset_top->constant = TRUE;
offset_top->constant_value = 0; offset_top->constant_value = 0;
g->from.offsets_y = g_list_append(g->from.offsets_y, offset_top); g->from.offsets_y = g_list_append(g->from.offsets_y, offset_top);
Offset *offset_bottom = (Offset *)calloc(1, sizeof(Offset)); Offset *offset_bottom = (Offset *)calloc(1, sizeof(Offset));
offset_bottom->constant = FALSE; offset_bottom->constant = FALSE;
offset_bottom->element = ELEMENT_SELF; offset_bottom->element = ELEMENT_SELF;
offset_bottom->variable = SIZE_HEIGHT; offset_bottom->variable = SIZE_HEIGHT;
offset_bottom->multiplier = 1.0; offset_bottom->multiplier = 1.0;
g->to.offsets_y = g_list_append(g->to.offsets_y, offset_bottom); g->to.offsets_y = g_list_append(g->to.offsets_y, offset_bottom);
} else if (g->type == GRADIENT_HORIZONTAL) { } else if (g->type == GRADIENT_HORIZONTAL) {
Offset *offset_left = (Offset *)calloc(1, sizeof(Offset)); Offset *offset_left = (Offset *)calloc(1, sizeof(Offset));
offset_left->constant = TRUE; offset_left->constant = TRUE;
offset_left->constant_value = 0; offset_left->constant_value = 0;
g->from.offsets_x = g_list_append(g->from.offsets_x, offset_left); g->from.offsets_x = g_list_append(g->from.offsets_x, offset_left);
Offset *offset_right = (Offset *)calloc(1, sizeof(Offset)); Offset *offset_right = (Offset *)calloc(1, sizeof(Offset));
offset_right->constant = FALSE; offset_right->constant = FALSE;
offset_right->element = ELEMENT_SELF; offset_right->element = ELEMENT_SELF;
offset_right->variable = SIZE_WIDTH; offset_right->variable = SIZE_WIDTH;
offset_right->multiplier = 1.0; offset_right->multiplier = 1.0;
g->to.offsets_x = g_list_append(g->to.offsets_x, offset_right); g->to.offsets_x = g_list_append(g->to.offsets_x, offset_right);
} else if (g->type == GRADIENT_CENTERED) { } else if (g->type == GRADIENT_CENTERED) {
// from // from
Offset *offset_center_x = (Offset *)calloc(1, sizeof(Offset)); Offset *offset_center_x = (Offset *)calloc(1, sizeof(Offset));
offset_center_x->constant = FALSE; offset_center_x->constant = FALSE;
offset_center_x->element = ELEMENT_SELF; offset_center_x->element = ELEMENT_SELF;
offset_center_x->variable = SIZE_CENTERX; offset_center_x->variable = SIZE_CENTERX;
offset_center_x->multiplier = 1.0; offset_center_x->multiplier = 1.0;
g->from.offsets_x = g_list_append(g->from.offsets_x, offset_center_x); g->from.offsets_x = g_list_append(g->from.offsets_x, offset_center_x);
Offset *offset_center_y = (Offset *)calloc(1, sizeof(Offset)); Offset *offset_center_y = (Offset *)calloc(1, sizeof(Offset));
offset_center_y->constant = FALSE; offset_center_y->constant = FALSE;
offset_center_y->element = ELEMENT_SELF; offset_center_y->element = ELEMENT_SELF;
offset_center_y->variable = SIZE_CENTERY; offset_center_y->variable = SIZE_CENTERY;
offset_center_y->multiplier = 1.0; offset_center_y->multiplier = 1.0;
g->from.offsets_y = g_list_append(g->from.offsets_y, offset_center_y); g->from.offsets_y = g_list_append(g->from.offsets_y, offset_center_y);
Offset *offset_center_r = (Offset *)calloc(1, sizeof(Offset)); Offset *offset_center_r = (Offset *)calloc(1, sizeof(Offset));
offset_center_r->constant = TRUE; offset_center_r->constant = TRUE;
offset_center_r->constant_value = 0; offset_center_r->constant_value = 0;
g->from.offsets_r = g_list_append(g->from.offsets_r, offset_center_r); g->from.offsets_r = g_list_append(g->from.offsets_r, offset_center_r);
// to // to
offset_center_x = (Offset *)calloc(1, sizeof(Offset)); offset_center_x = (Offset *)calloc(1, sizeof(Offset));
offset_center_x->constant = FALSE; offset_center_x->constant = FALSE;
offset_center_x->element = ELEMENT_SELF; offset_center_x->element = ELEMENT_SELF;
offset_center_x->variable = SIZE_CENTERX; offset_center_x->variable = SIZE_CENTERX;
offset_center_x->multiplier = 1.0; offset_center_x->multiplier = 1.0;
g->to.offsets_x = g_list_append(g->to.offsets_x, offset_center_x); 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 = (Offset *)calloc(1, sizeof(Offset));
offset_center_y->constant = FALSE; offset_center_y->constant = FALSE;
offset_center_y->element = ELEMENT_SELF; offset_center_y->element = ELEMENT_SELF;
offset_center_y->variable = SIZE_CENTERY; offset_center_y->variable = SIZE_CENTERY;
offset_center_y->multiplier = 1.0; offset_center_y->multiplier = 1.0;
g->to.offsets_y = g_list_append(g->to.offsets_y, offset_center_y); 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 = (Offset *)calloc(1, sizeof(Offset));
offset_center_r->constant = FALSE; offset_center_r->constant = FALSE;
offset_center_r->element = ELEMENT_SELF; offset_center_r->element = ELEMENT_SELF;
offset_center_r->variable = SIZE_RADIUS; offset_center_r->variable = SIZE_RADIUS;
offset_center_r->multiplier = 1.0; offset_center_r->multiplier = 1.0;
g->to.offsets_r = g_list_append(g->to.offsets_r, offset_center_r); g->to.offsets_r = g_list_append(g->to.offsets_r, offset_center_r);
} }
} }
void cleanup_gradient(GradientClass *g) void cleanup_gradient(GradientClass *g)
{ {
g_list_free_full(g->extra_color_stops, free); 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_x, free);
g_list_free_full(g->from.offsets_y, free); g_list_free_full(g->from.offsets_y, free);
g_list_free_full(g->from.offsets_r, 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_x, free);
g_list_free_full(g->to.offsets_y, free); g_list_free_full(g->to.offsets_y, free);
g_list_free_full(g->to.offsets_r, free); g_list_free_full(g->to.offsets_r, free);
bzero(g, sizeof(*g)); bzero(g, sizeof(*g));
} }

View File

@@ -9,62 +9,54 @@
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Gradient types read from config options, not associated to any area // Gradient types read from config options, not associated to any area
typedef enum GradientType { typedef enum GradientType { GRADIENT_VERTICAL = 0, GRADIENT_HORIZONTAL, GRADIENT_CENTERED } GradientType;
GRADIENT_VERTICAL = 0,
GRADIENT_HORIZONTAL,
GRADIENT_CENTERED
} GradientType;
typedef struct ColorStop { typedef struct ColorStop {
Color color; Color color;
// offset in 0-1 // offset in 0-1
double offset; double offset;
} ColorStop; } ColorStop;
typedef enum Element { typedef enum Element { ELEMENT_SELF = 0, ELEMENT_PARENT, ELEMENT_PANEL } Element;
ELEMENT_SELF = 0,
ELEMENT_PARENT,
ELEMENT_PANEL
} Element;
typedef enum SizeVariable { typedef enum SizeVariable {
SIZE_WIDTH = 0, SIZE_WIDTH = 0,
SIZE_HEIGHT, SIZE_HEIGHT,
SIZE_RADIUS, SIZE_RADIUS,
SIZE_LEFT, SIZE_LEFT,
SIZE_RIGHT, SIZE_RIGHT,
SIZE_TOP, SIZE_TOP,
SIZE_BOTTOM, SIZE_BOTTOM,
SIZE_CENTERX, SIZE_CENTERX,
SIZE_CENTERY SIZE_CENTERY
} SizeVariable; } SizeVariable;
typedef struct Offset { typedef struct Offset {
gboolean constant; gboolean constant;
// if constant == true // if constant == true
double constant_value; double constant_value;
// else // else
Element element; Element element;
SizeVariable variable; SizeVariable variable;
double multiplier; double multiplier;
} Offset; } Offset;
typedef struct ControlPoint { typedef struct ControlPoint {
// Each element is an Offset // Each element is an Offset
GList *offsets_x; GList *offsets_x;
GList *offsets_y; GList *offsets_y;
// Defined only for radial gradients // Defined only for radial gradients
GList *offsets_r; GList *offsets_r;
} ControlPoint; } ControlPoint;
typedef struct GradientClass { typedef struct GradientClass {
GradientType type; GradientType type;
Color start_color; Color start_color;
Color end_color; Color end_color;
// Each element is a ColorStop // Each element is a ColorStop
GList *extra_color_stops; GList *extra_color_stops;
ControlPoint from; ControlPoint from;
ControlPoint to; ControlPoint to;
} GradientClass; } GradientClass;
GradientType gradient_type_from_string(const char *str); GradientType gradient_type_from_string(const char *str);
@@ -78,9 +70,9 @@ struct Area;
typedef struct Area Area; typedef struct Area Area;
typedef struct GradientInstance { typedef struct GradientInstance {
GradientClass *gradient_class; GradientClass *gradient_class;
Area *area; Area *area;
cairo_pattern_t *pattern; cairo_pattern_t *pattern;
} GradientInstance; } GradientInstance;
extern gboolean debug_gradients; extern gboolean debug_gradients;

View File

@@ -43,110 +43,110 @@
// remember it in BIAS. // remember it in BIAS.
static int compare_right(char const *a, char const *b) static int compare_right(char const *a, char const *b)
{ {
int bias = 0; int bias = 0;
for (;; a++, b++) { for (;; a++, b++) {
if (!isdigit(*a) && !isdigit(*b)) if (!isdigit(*a) && !isdigit(*b))
return bias; return bias;
else if (!isdigit(*a)) else if (!isdigit(*a))
return -1; return -1;
else if (!isdigit(*b)) else if (!isdigit(*b))
return +1; return +1;
else if (*a < *b) { else if (*a < *b) {
if (!bias) if (!bias)
bias = -1; bias = -1;
} else if (*a > *b) { } else if (*a > *b) {
if (!bias) if (!bias)
bias = +1; bias = +1;
} else if (!*a && !*b) } else if (!*a && !*b)
return bias; return bias;
} }
return 0; return 0;
} }
// Compare two left-aligned numbers: // Compare two left-aligned numbers:
// The first to have a different value wins. // The first to have a different value wins.
static int compare_left(char const *a, char const *b) static int compare_left(char const *a, char const *b)
{ {
for (;; a++, b++) { for (;; a++, b++) {
if (!isdigit(*a) && !isdigit(*b)) if (!isdigit(*a) && !isdigit(*b))
return 0; return 0;
else if (!isdigit(*a)) else if (!isdigit(*a))
return -1; return -1;
else if (!isdigit(*b)) else if (!isdigit(*b))
return +1; return +1;
else if (*a < *b) else if (*a < *b)
return -1; return -1;
else if (*a > *b) else if (*a > *b)
return +1; return +1;
} }
return 0; return 0;
} }
static int strnatcmp0(char const *a, char const *b, int ignore_case) static int strnatcmp0(char const *a, char const *b, int ignore_case)
{ {
assert(a && b); assert(a && b);
int ai, bi; int ai, bi;
ai = bi = 0; ai = bi = 0;
while (1) { while (1) {
char ca = a[ai]; char ca = a[ai];
char cb = b[bi]; char cb = b[bi];
// Skip over leading spaces // Skip over leading spaces
while (isspace(ca)) { while (isspace(ca)) {
ai++; ai++;
ca = a[ai]; ca = a[ai];
} }
while (isspace(cb)) { while (isspace(cb)) {
bi++; bi++;
cb = b[bi]; cb = b[bi];
} }
// Process run of digits // Process run of digits
if (isdigit(ca) && isdigit(cb)) { if (isdigit(ca) && isdigit(cb)) {
int fractional = (ca == '0' || cb == '0'); int fractional = (ca == '0' || cb == '0');
if (fractional) { if (fractional) {
int result = compare_left(a + ai, b + bi); int result = compare_left(a + ai, b + bi);
if (result) if (result)
return result; return result;
} else { } else {
int result = compare_right(a + ai, b + bi); int result = compare_right(a + ai, b + bi);
if (result) if (result)
return result; return result;
} }
} }
if (!ca && !cb) { if (!ca && !cb) {
// The strings compare the same. Perhaps the caller will want to call strcmp to break the tie. // The strings compare the same. Perhaps the caller will want to call strcmp to break the tie.
return 0; return 0;
} }
if (ignore_case) { if (ignore_case) {
ca = toupper(ca); ca = toupper(ca);
cb = toupper(cb); cb = toupper(cb);
} }
if (ca < cb) if (ca < cb)
return -1; return -1;
else if (ca > cb) else if (ca > cb)
return +1; return +1;
ai++; ai++;
bi++; bi++;
} }
} }
int strnatcmp(char const *a, char const *b) int strnatcmp(char const *a, char const *b)
{ {
return strnatcmp0(a, b, 0); return strnatcmp0(a, b, 0);
} }
int strnatcasecmp(char const *a, char const *b) int strnatcasecmp(char const *a, char const *b)
{ {
return strnatcmp0(a, b, 1); return strnatcmp0(a, b, 1);
} }

View File

@@ -28,22 +28,22 @@ GHashTable *multi_timeouts;
// functions and structs for multi timeouts // functions and structs for multi timeouts
typedef struct { typedef struct {
int current_count; int current_count;
int count_to_expiration; int count_to_expiration;
} multi_timeout; } multi_timeout;
typedef struct { typedef struct {
GSList *timeout_list; GSList *timeout_list;
timeout *parent_timeout; timeout *parent_timeout;
} multi_timeout_handler; } multi_timeout_handler;
struct _timeout { struct _timeout {
int interval_msec; int interval_msec;
struct timespec timeout_expires; struct timespec timeout_expires;
void (*_callback)(void *); void (*_callback)(void *);
void *arg; void *arg;
multi_timeout *multi_timeout; multi_timeout *multi_timeout;
timeout **self; timeout **self;
}; };
void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout *t); void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout *t);
@@ -61,25 +61,25 @@ void stop_multi_timeout(timeout *t);
void default_timeout() void default_timeout()
{ {
timeout_list = NULL; timeout_list = NULL;
multi_timeouts = NULL; multi_timeouts = NULL;
} }
void cleanup_timeout() void cleanup_timeout()
{ {
while (timeout_list) { while (timeout_list) {
timeout *t = timeout_list->data; timeout *t = timeout_list->data;
if (t->multi_timeout) if (t->multi_timeout)
stop_multi_timeout(t); stop_multi_timeout(t);
if (t->self) if (t->self)
*t->self = NULL; *t->self = NULL;
free(t); free(t);
timeout_list = g_slist_remove(timeout_list, t); timeout_list = g_slist_remove(timeout_list, t);
} }
if (multi_timeouts) { if (multi_timeouts) {
g_hash_table_destroy(multi_timeouts); g_hash_table_destroy(multi_timeouts);
multi_timeouts = NULL; multi_timeouts = NULL;
} }
} }
// Implementation notes for timeouts // Implementation notes for timeouts
@@ -96,358 +96,358 @@ void cleanup_timeout()
timeout *add_timeout(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout **self) timeout *add_timeout(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout **self)
{ {
if (self && *self) if (self && *self)
return *self; return *self;
timeout *t = calloc(1, sizeof(timeout)); timeout *t = calloc(1, sizeof(timeout));
t->self = self; t->self = self;
add_timeout_intern(value_msec, interval_msec, _callback, arg, t); add_timeout_intern(value_msec, interval_msec, _callback, arg, t);
return t; return t;
} }
void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_callback)(), void *arg) void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_callback)(), void *arg)
{ {
if (!((timeout_list && g_slist_find(timeout_list, *t)) || if (!((timeout_list && g_slist_find(timeout_list, *t)) ||
(multi_timeouts && g_hash_table_lookup(multi_timeouts, *t)))) (multi_timeouts && g_hash_table_lookup(multi_timeouts, *t))))
*t = add_timeout(value_msec, interval_msec, _callback, arg, t); *t = add_timeout(value_msec, interval_msec, _callback, arg, t);
else { else {
if ((*t)->multi_timeout) if ((*t)->multi_timeout)
remove_from_multi_timeout(*t); remove_from_multi_timeout(*t);
else else
timeout_list = g_slist_remove(timeout_list, *t); timeout_list = g_slist_remove(timeout_list, *t);
add_timeout_intern(value_msec, interval_msec, _callback, arg, *t); add_timeout_intern(value_msec, interval_msec, _callback, arg, *t);
} }
} }
void update_next_timeout() void update_next_timeout()
{ {
if (timeout_list) { if (timeout_list) {
timeout *t = timeout_list->data; timeout *t = timeout_list->data;
struct timespec cur_time; struct timespec cur_time;
struct timespec next_timeout2 = {.tv_sec = next_timeout.tv_sec, .tv_nsec = next_timeout.tv_usec * 1000}; struct timespec next_timeout2 = {.tv_sec = next_timeout.tv_sec, .tv_nsec = next_timeout.tv_usec * 1000};
clock_gettime(CLOCK_MONOTONIC, &cur_time); clock_gettime(CLOCK_MONOTONIC, &cur_time);
if (timespec_subtract(&next_timeout2, &t->timeout_expires, &cur_time)) { if (timespec_subtract(&next_timeout2, &t->timeout_expires, &cur_time)) {
next_timeout.tv_sec = 0; next_timeout.tv_sec = 0;
next_timeout.tv_usec = 0; next_timeout.tv_usec = 0;
} else { } else {
next_timeout.tv_sec = next_timeout2.tv_sec; next_timeout.tv_sec = next_timeout2.tv_sec;
next_timeout.tv_usec = next_timeout2.tv_nsec / 1000; next_timeout.tv_usec = next_timeout2.tv_nsec / 1000;
} }
} else } else
next_timeout.tv_sec = -1; next_timeout.tv_sec = -1;
} }
void callback_timeout_expired() void callback_timeout_expired()
{ {
struct timespec cur_time; struct timespec cur_time;
timeout *t; timeout *t;
while (timeout_list) { while (timeout_list) {
clock_gettime(CLOCK_MONOTONIC, &cur_time); clock_gettime(CLOCK_MONOTONIC, &cur_time);
t = timeout_list->data; t = timeout_list->data;
if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) { if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) {
// it's time for the callback function // it's time for the callback function
t->_callback(t->arg); t->_callback(t->arg);
// If _callback() calls stop_timeout(t) the timer 't' was freed and is not in the timeout_list // If _callback() calls stop_timeout(t) the timer 't' was freed and is not in the timeout_list
if (g_slist_find(timeout_list, t)) { if (g_slist_find(timeout_list, t)) {
// Timer still exists // Timer still exists
timeout_list = g_slist_remove(timeout_list, t); timeout_list = g_slist_remove(timeout_list, t);
if (t->interval_msec > 0) { if (t->interval_msec > 0) {
add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t->arg, t); add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t->arg, t);
} else { } else {
// Destroy single-shot timer // Destroy single-shot timer
if (t->self) if (t->self)
*t->self = NULL; *t->self = NULL;
free(t); free(t);
} }
} }
} else { } else {
return; return;
} }
} }
} }
void stop_timeout(timeout *t) void stop_timeout(timeout *t)
{ {
if (!t) if (!t)
return; return;
// if not in the list, it was deleted in callback_timeout_expired // if not in the list, it was deleted in callback_timeout_expired
if ((timeout_list && g_slist_find(timeout_list, t)) || (multi_timeouts && g_hash_table_lookup(multi_timeouts, t))) { if ((timeout_list && g_slist_find(timeout_list, t)) || (multi_timeouts && g_hash_table_lookup(multi_timeouts, t))) {
if (multi_timeouts && t->multi_timeout) if (multi_timeouts && t->multi_timeout)
remove_from_multi_timeout(t); remove_from_multi_timeout(t);
if (timeout_list) if (timeout_list)
timeout_list = g_slist_remove(timeout_list, t); timeout_list = g_slist_remove(timeout_list, t);
if (t->self) if (t->self)
*t->self = NULL; *t->self = NULL;
free(t); free(t);
} }
} }
void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(), void *arg, timeout *t) void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(), void *arg, timeout *t)
{ {
t->interval_msec = interval_msec; t->interval_msec = interval_msec;
t->_callback = _callback; t->_callback = _callback;
t->arg = arg; t->arg = arg;
struct timespec cur_time; struct timespec cur_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time); clock_gettime(CLOCK_MONOTONIC, &cur_time);
t->timeout_expires = add_msec_to_timespec(cur_time, value_msec); t->timeout_expires = add_msec_to_timespec(cur_time, value_msec);
int can_align = 0; int can_align = 0;
if (interval_msec > 0 && !t->multi_timeout) if (interval_msec > 0 && !t->multi_timeout)
can_align = align_with_existing_timeouts(t); can_align = align_with_existing_timeouts(t);
if (!can_align) if (!can_align)
timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts); timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts);
} }
gint compare_timeouts(gconstpointer t1, gconstpointer t2) gint compare_timeouts(gconstpointer t1, gconstpointer t2)
{ {
return compare_timespecs(&((const timeout *)t1)->timeout_expires, &((const timeout *)t2)->timeout_expires); return compare_timespecs(&((const timeout *)t1)->timeout_expires, &((const timeout *)t2)->timeout_expires);
} }
gint compare_timespecs(const struct timespec *t1, const struct timespec *t2) gint compare_timespecs(const struct timespec *t1, const struct timespec *t2)
{ {
if (t1->tv_sec < t2->tv_sec) if (t1->tv_sec < t2->tv_sec)
return -1; return -1;
else if (t1->tv_sec == t2->tv_sec) { else if (t1->tv_sec == t2->tv_sec) {
if (t1->tv_nsec < t2->tv_nsec) if (t1->tv_nsec < t2->tv_nsec)
return -1; return -1;
else if (t1->tv_nsec == t2->tv_nsec) else if (t1->tv_nsec == t2->tv_nsec)
return 0; return 0;
else else
return 1; return 1;
} else } else
return 1; return 1;
} }
int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y) int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y)
{ {
/* Perform the carry for the later subtraction by updating y. */ /* Perform the carry for the later subtraction by updating y. */
if (x->tv_nsec < y->tv_nsec) { if (x->tv_nsec < y->tv_nsec) {
int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1; int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
y->tv_nsec -= 1000000000 * nsec; y->tv_nsec -= 1000000000 * nsec;
y->tv_sec += nsec; y->tv_sec += nsec;
} }
if (x->tv_nsec - y->tv_nsec > 1000000000) { if (x->tv_nsec - y->tv_nsec > 1000000000) {
int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000; int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
y->tv_nsec += 1000000000 * nsec; y->tv_nsec += 1000000000 * nsec;
y->tv_sec -= nsec; y->tv_sec -= nsec;
} }
/* Compute the time remaining to wait. tv_nsec is certainly positive. */ /* Compute the time remaining to wait. tv_nsec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec; result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_nsec = x->tv_nsec - y->tv_nsec; result->tv_nsec = x->tv_nsec - y->tv_nsec;
/* Return 1 if result is negative. */ /* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec; return x->tv_sec < y->tv_sec;
} }
struct timespec add_msec_to_timespec(struct timespec ts, int msec) struct timespec add_msec_to_timespec(struct timespec ts, int msec)
{ {
ts.tv_sec += msec / 1000; ts.tv_sec += msec / 1000;
ts.tv_nsec += (msec % 1000) * 1000000; ts.tv_nsec += (msec % 1000) * 1000000;
if (ts.tv_nsec >= 1000000000) { // 10^9 if (ts.tv_nsec >= 1000000000) { // 10^9
ts.tv_sec++; ts.tv_sec++;
ts.tv_nsec -= 1000000000; ts.tv_nsec -= 1000000000;
} }
return ts; return ts;
} }
int align_with_existing_timeouts(timeout *t) int align_with_existing_timeouts(timeout *t)
{ {
GSList *it = timeout_list; GSList *it = timeout_list;
while (it) { while (it) {
timeout *t2 = it->data; timeout *t2 = it->data;
if (t2->interval_msec > 0) { if (t2->interval_msec > 0) {
if (t->interval_msec % t2->interval_msec == 0 || t2->interval_msec % t->interval_msec == 0) { if (t->interval_msec % t2->interval_msec == 0 || t2->interval_msec % t->interval_msec == 0) {
if (!multi_timeouts) if (!multi_timeouts)
multi_timeouts = g_hash_table_new(0, 0); multi_timeouts = g_hash_table_new(0, 0);
if (!t->multi_timeout && !t2->multi_timeout) { if (!t->multi_timeout && !t2->multi_timeout) {
// both timeouts can be aligned, but there is no multi timeout for them // both timeouts can be aligned, but there is no multi timeout for them
create_multi_timeout(t, t2); create_multi_timeout(t, t2);
} else { } else {
// there is already a multi timeout, so we append the new timeout to the multi timeout // there is already a multi timeout, so we append the new timeout to the multi timeout
append_multi_timeout(t, t2); append_multi_timeout(t, t2);
} }
return 1; return 1;
} }
} }
it = it->next; it = it->next;
} }
return 0; return 0;
} }
int calc_multi_timeout_interval(multi_timeout_handler *mth) int calc_multi_timeout_interval(multi_timeout_handler *mth)
{ {
GSList *it = mth->timeout_list; GSList *it = mth->timeout_list;
timeout *t = it->data; timeout *t = it->data;
int min_interval = t->interval_msec; int min_interval = t->interval_msec;
it = it->next; it = it->next;
while (it) { while (it) {
t = it->data; t = it->data;
if (t->interval_msec < min_interval) if (t->interval_msec < min_interval)
min_interval = t->interval_msec; min_interval = t->interval_msec;
it = it->next; it = it->next;
} }
return min_interval; return min_interval;
} }
void create_multi_timeout(timeout *t1, timeout *t2) void create_multi_timeout(timeout *t1, timeout *t2)
{ {
multi_timeout *mt1 = calloc(1, sizeof(multi_timeout)); multi_timeout *mt1 = calloc(1, sizeof(multi_timeout));
multi_timeout *mt2 = calloc(1, sizeof(multi_timeout)); multi_timeout *mt2 = calloc(1, sizeof(multi_timeout));
multi_timeout_handler *mth = calloc(1, sizeof(multi_timeout_handler)); multi_timeout_handler *mth = calloc(1, sizeof(multi_timeout_handler));
timeout *real_timeout = calloc(1, sizeof(timeout)); timeout *real_timeout = calloc(1, sizeof(timeout));
mth->timeout_list = 0; mth->timeout_list = 0;
mth->timeout_list = g_slist_prepend(mth->timeout_list, t1); mth->timeout_list = g_slist_prepend(mth->timeout_list, t1);
mth->timeout_list = g_slist_prepend(mth->timeout_list, t2); mth->timeout_list = g_slist_prepend(mth->timeout_list, t2);
mth->parent_timeout = real_timeout; mth->parent_timeout = real_timeout;
g_hash_table_insert(multi_timeouts, t1, mth); g_hash_table_insert(multi_timeouts, t1, mth);
g_hash_table_insert(multi_timeouts, t2, mth); g_hash_table_insert(multi_timeouts, t2, mth);
g_hash_table_insert(multi_timeouts, real_timeout, mth); g_hash_table_insert(multi_timeouts, real_timeout, mth);
t1->multi_timeout = mt1; t1->multi_timeout = mt1;
t2->multi_timeout = mt2; t2->multi_timeout = mt2;
// set real_timeout->multi_timeout to something, such that we see in add_timeout_intern that // set real_timeout->multi_timeout to something, such that we see in add_timeout_intern that
// it is already a multi_timeout (we never use it, except of checking for 0 ptr) // it is already a multi_timeout (we never use it, except of checking for 0 ptr)
real_timeout->multi_timeout = (void *)real_timeout; real_timeout->multi_timeout = (void *)real_timeout;
timeout_list = g_slist_remove(timeout_list, t1); timeout_list = g_slist_remove(timeout_list, t1);
timeout_list = g_slist_remove(timeout_list, t2); timeout_list = g_slist_remove(timeout_list, t2);
update_multi_timeout_values(mth); update_multi_timeout_values(mth);
} }
void append_multi_timeout(timeout *t1, timeout *t2) void append_multi_timeout(timeout *t1, timeout *t2)
{ {
if (t2->multi_timeout) { if (t2->multi_timeout) {
// swap t1 and t2 such that t1 is the multi timeout // swap t1 and t2 such that t1 is the multi timeout
timeout *tmp = t2; timeout *tmp = t2;
t2 = t1; t2 = t1;
t1 = tmp; t1 = tmp;
} }
multi_timeout *mt = calloc(1, sizeof(multi_timeout)); multi_timeout *mt = calloc(1, sizeof(multi_timeout));
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t1); multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t1);
mth->timeout_list = g_slist_prepend(mth->timeout_list, t2); mth->timeout_list = g_slist_prepend(mth->timeout_list, t2);
g_hash_table_insert(multi_timeouts, t2, mth); g_hash_table_insert(multi_timeouts, t2, mth);
t2->multi_timeout = mt; t2->multi_timeout = mt;
update_multi_timeout_values(mth); update_multi_timeout_values(mth);
} }
void update_multi_timeout_values(multi_timeout_handler *mth) void update_multi_timeout_values(multi_timeout_handler *mth)
{ {
int interval = calc_multi_timeout_interval(mth); int interval = calc_multi_timeout_interval(mth);
int next_timeout_msec = interval; int next_timeout_msec = interval;
struct timespec cur_time; struct timespec cur_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time); clock_gettime(CLOCK_MONOTONIC, &cur_time);
GSList *it = mth->timeout_list; GSList *it = mth->timeout_list;
struct timespec diff_time; struct timespec diff_time;
while (it) { while (it) {
timeout *t = it->data; timeout *t = it->data;
t->multi_timeout->count_to_expiration = t->interval_msec / interval; t->multi_timeout->count_to_expiration = t->interval_msec / interval;
timespec_subtract(&diff_time, &t->timeout_expires, &cur_time); timespec_subtract(&diff_time, &t->timeout_expires, &cur_time);
int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000; int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000;
int count_left = msec_to_expiration / interval + (msec_to_expiration % interval != 0); int count_left = msec_to_expiration / interval + (msec_to_expiration % interval != 0);
t->multi_timeout->current_count = t->multi_timeout->count_to_expiration - count_left; t->multi_timeout->current_count = t->multi_timeout->count_to_expiration - count_left;
if (msec_to_expiration < next_timeout_msec) if (msec_to_expiration < next_timeout_msec)
next_timeout_msec = msec_to_expiration; next_timeout_msec = msec_to_expiration;
it = it->next; it = it->next;
} }
mth->parent_timeout->interval_msec = interval; mth->parent_timeout->interval_msec = interval;
timeout_list = g_slist_remove(timeout_list, mth->parent_timeout); timeout_list = g_slist_remove(timeout_list, mth->parent_timeout);
add_timeout_intern(next_timeout_msec, interval, callback_multi_timeout, mth, mth->parent_timeout); add_timeout_intern(next_timeout_msec, interval, callback_multi_timeout, mth, mth->parent_timeout);
} }
void callback_multi_timeout(void *arg) void callback_multi_timeout(void *arg)
{ {
multi_timeout_handler *mth = arg; multi_timeout_handler *mth = arg;
struct timespec cur_time; struct timespec cur_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time); clock_gettime(CLOCK_MONOTONIC, &cur_time);
GSList *it = mth->timeout_list; GSList *it = mth->timeout_list;
while (it) { while (it) {
timeout *t = it->data; timeout *t = it->data;
if (++t->multi_timeout->current_count >= t->multi_timeout->count_to_expiration) { if (++t->multi_timeout->current_count >= t->multi_timeout->count_to_expiration) {
t->_callback(t->arg); t->_callback(t->arg);
if (multi_timeouts && g_hash_table_lookup(multi_timeouts, t)) { if (multi_timeouts && g_hash_table_lookup(multi_timeouts, t)) {
// Timer still exists // Timer still exists
t->multi_timeout->current_count = 0; t->multi_timeout->current_count = 0;
t->timeout_expires = add_msec_to_timespec(cur_time, t->interval_msec); t->timeout_expires = add_msec_to_timespec(cur_time, t->interval_msec);
} else { } else {
return; return;
} }
} }
it = it->next; it = it->next;
} }
} }
void remove_from_multi_timeout(timeout *t) void remove_from_multi_timeout(timeout *t)
{ {
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t); multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t);
g_hash_table_remove(multi_timeouts, t); g_hash_table_remove(multi_timeouts, t);
mth->timeout_list = g_slist_remove(mth->timeout_list, t); mth->timeout_list = g_slist_remove(mth->timeout_list, t);
free(t->multi_timeout); free(t->multi_timeout);
t->multi_timeout = 0; t->multi_timeout = 0;
if (g_slist_length(mth->timeout_list) == 1) { if (g_slist_length(mth->timeout_list) == 1) {
timeout *last_timeout = mth->timeout_list->data; timeout *last_timeout = mth->timeout_list->data;
mth->timeout_list = g_slist_remove(mth->timeout_list, last_timeout); mth->timeout_list = g_slist_remove(mth->timeout_list, last_timeout);
free(last_timeout->multi_timeout); free(last_timeout->multi_timeout);
last_timeout->multi_timeout = 0; last_timeout->multi_timeout = 0;
g_hash_table_remove(multi_timeouts, last_timeout); g_hash_table_remove(multi_timeouts, last_timeout);
g_hash_table_remove(multi_timeouts, mth->parent_timeout); g_hash_table_remove(multi_timeouts, mth->parent_timeout);
mth->parent_timeout->multi_timeout = 0; mth->parent_timeout->multi_timeout = 0;
stop_timeout(mth->parent_timeout); stop_timeout(mth->parent_timeout);
free(mth); free(mth);
struct timespec cur_time, diff_time; struct timespec cur_time, diff_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time); clock_gettime(CLOCK_MONOTONIC, &cur_time);
timespec_subtract(&diff_time, &t->timeout_expires, &cur_time); timespec_subtract(&diff_time, &t->timeout_expires, &cur_time);
int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000; int msec_to_expiration = diff_time.tv_sec * 1000 + diff_time.tv_nsec / 1000000;
add_timeout_intern(msec_to_expiration, add_timeout_intern(msec_to_expiration,
last_timeout->interval_msec, last_timeout->interval_msec,
last_timeout->_callback, last_timeout->_callback,
last_timeout->arg, last_timeout->arg,
last_timeout); last_timeout);
} else } else
update_multi_timeout_values(mth); update_multi_timeout_values(mth);
} }
void stop_multi_timeout(timeout *t) void stop_multi_timeout(timeout *t)
{ {
multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t); multi_timeout_handler *mth = g_hash_table_lookup(multi_timeouts, t);
g_hash_table_remove(multi_timeouts, mth->parent_timeout); g_hash_table_remove(multi_timeouts, mth->parent_timeout);
while (mth->timeout_list) { while (mth->timeout_list) {
timeout *t1 = mth->timeout_list->data; timeout *t1 = mth->timeout_list->data;
mth->timeout_list = g_slist_remove(mth->timeout_list, t1); mth->timeout_list = g_slist_remove(mth->timeout_list, t1);
g_hash_table_remove(multi_timeouts, t1); g_hash_table_remove(multi_timeouts, t1);
free(t1->multi_timeout); free(t1->multi_timeout);
free(t1); free(t1);
} }
free(mth); free(mth);
} }
double profiling_get_time_old_time = 0; double profiling_get_time_old_time = 0;
double get_time() double get_time()
{ {
struct timespec cur_time; struct timespec cur_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time); clock_gettime(CLOCK_MONOTONIC, &cur_time);
return cur_time.tv_sec + cur_time.tv_nsec * 1.0e-9; return cur_time.tv_sec + cur_time.tv_nsec * 1.0e-9;
} }
double profiling_get_time() double profiling_get_time()
{ {
double t = get_time(); double t = get_time();
if (profiling_get_time_old_time == 0) if (profiling_get_time_old_time == 0)
profiling_get_time_old_time = t; profiling_get_time_old_time = t;
double delta = t - profiling_get_time_old_time; double delta = t - profiling_get_time_old_time;
profiling_get_time_old_time = t; profiling_get_time_old_time = t;
return delta; return delta;
} }

View File

@@ -38,170 +38,170 @@ static GList *notifiers = NULL;
static const char *has_prefix(const char *str, const char *end, const char *prefix, size_t prefixlen) static const char *has_prefix(const char *str, const char *end, const char *prefix, size_t prefixlen)
{ {
if ((end - str) < prefixlen) if ((end - str) < prefixlen)
return NULL; return NULL;
if (!memcmp(str, prefix, prefixlen)) if (!memcmp(str, prefix, prefixlen))
return str + prefixlen; return str + prefixlen;
return NULL; return NULL;
} }
#define HAS_CONST_PREFIX(str, end, prefix) has_prefix((str), end, prefix, sizeof(prefix) - 1) #define HAS_CONST_PREFIX(str, end, prefix) has_prefix((str), end, prefix, sizeof(prefix) - 1)
static void uevent_param_free(gpointer data) static void uevent_param_free(gpointer data)
{ {
struct uevent_parameter *param = data; struct uevent_parameter *param = data;
free(param->key); free(param->key);
free(param->val); free(param->val);
free(param); free(param);
} }
static void uevent_free(struct uevent *ev) static void uevent_free(struct uevent *ev)
{ {
free(ev->path); free(ev->path);
free(ev->subsystem); free(ev->subsystem);
g_list_free_full(ev->params, uevent_param_free); g_list_free_full(ev->params, uevent_param_free);
free(ev); free(ev);
} }
static struct uevent *uevent_new(char *buffer, int size) static struct uevent *uevent_new(char *buffer, int size)
{ {
gboolean first = TRUE; gboolean first = TRUE;
if (size == 0) if (size == 0)
return NULL; return NULL;
struct uevent *ev = calloc(1, sizeof(*ev)); struct uevent *ev = calloc(1, sizeof(*ev));
if (!ev) if (!ev)
return NULL; return NULL;
/* ensure nul termination required by strlen() */ /* ensure nul termination required by strlen() */
buffer[size - 1] = '\0'; buffer[size - 1] = '\0';
const char *s = buffer; const char *s = buffer;
const char *end = s + size; const char *end = s + size;
for (; s < end; s += strlen(s) + 1) { for (; s < end; s += strlen(s) + 1) {
if (first) { if (first) {
const char *p = strchr(s, '@'); const char *p = strchr(s, '@');
if (!p) { if (!p) {
/* error: kernel events contain @ */ /* error: kernel events contain @ */
/* triggered by udev events, though */ /* triggered by udev events, though */
free(ev); free(ev);
return NULL; return NULL;
} }
ev->path = strdup(p + 1); ev->path = strdup(p + 1);
first = FALSE; first = FALSE;
} else { } else {
const char *val; const char *val;
if ((val = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) { if ((val = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
if (!strcmp(val, "add")) if (!strcmp(val, "add"))
ev->action = UEVENT_ADD; ev->action = UEVENT_ADD;
else if (!strcmp(val, "remove")) else if (!strcmp(val, "remove"))
ev->action = UEVENT_REMOVE; ev->action = UEVENT_REMOVE;
else if (!strcmp(val, "change")) else if (!strcmp(val, "change"))
ev->action = UEVENT_CHANGE; ev->action = UEVENT_CHANGE;
else else
ev->action = UEVENT_UNKNOWN; ev->action = UEVENT_UNKNOWN;
} else if ((val = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) { } else if ((val = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
ev->sequence = atoi(val); ev->sequence = atoi(val);
} else if ((val = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) { } else if ((val = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
ev->subsystem = strdup(val); ev->subsystem = strdup(val);
} else { } else {
val = strchr(s, '='); val = strchr(s, '=');
if (val) { if (val) {
struct uevent_parameter *param = malloc(sizeof(*param)); struct uevent_parameter *param = malloc(sizeof(*param));
if (param) { if (param) {
param->key = strndup(s, val - s); param->key = strndup(s, val - s);
param->val = strdup(val + 1); param->val = strdup(val + 1);
ev->params = g_list_append(ev->params, param); ev->params = g_list_append(ev->params, param);
} }
} }
} }
} }
} }
return ev; return ev;
} }
void uevent_register_notifier(struct uevent_notify *nb) void uevent_register_notifier(struct uevent_notify *nb)
{ {
notifiers = g_list_append(notifiers, nb); notifiers = g_list_append(notifiers, nb);
} }
void uevent_unregister_notifier(struct uevent_notify *nb) void uevent_unregister_notifier(struct uevent_notify *nb)
{ {
GList *l = notifiers; GList *l = notifiers;
while (l != NULL) { while (l != NULL) {
GList *next = l->next; GList *next = l->next;
struct uevent_notify *lnb = l->data; struct uevent_notify *lnb = l->data;
if (memcmp(nb, lnb, sizeof(struct uevent_notify)) == 0) if (memcmp(nb, lnb, sizeof(struct uevent_notify)) == 0)
notifiers = g_list_delete_link(notifiers, l); notifiers = g_list_delete_link(notifiers, l);
l = next; l = next;
} }
} }
void uevent_handler() void uevent_handler()
{ {
if (ueventfd < 0) if (ueventfd < 0)
return; return;
char buf[512]; char buf[512];
int len = recv(ueventfd, buf, sizeof(buf), MSG_DONTWAIT); int len = recv(ueventfd, buf, sizeof(buf), MSG_DONTWAIT);
if (len < 0) if (len < 0)
return; return;
struct uevent *ev = uevent_new(buf, len); struct uevent *ev = uevent_new(buf, len);
if (ev) { if (ev) {
for (GList *l = notifiers; l; l = l->next) { for (GList *l = notifiers; l; l = l->next) {
struct uevent_notify *nb = l->data; struct uevent_notify *nb = l->data;
if (!(ev->action & nb->action)) if (!(ev->action & nb->action))
continue; continue;
if (nb->subsystem && strcmp(ev->subsystem, nb->subsystem)) if (nb->subsystem && strcmp(ev->subsystem, nb->subsystem))
continue; continue;
nb->cb(ev, nb->userdata); nb->cb(ev, nb->userdata);
} }
uevent_free(ev); uevent_free(ev);
} }
} }
int uevent_init() int uevent_init()
{ {
/* Open hotplug event netlink socket */ /* Open hotplug event netlink socket */
memset(&nls, 0, sizeof(struct sockaddr_nl)); memset(&nls, 0, sizeof(struct sockaddr_nl));
nls.nl_family = AF_NETLINK; nls.nl_family = AF_NETLINK;
nls.nl_pid = getpid(); nls.nl_pid = getpid();
nls.nl_groups = -1; nls.nl_groups = -1;
/* open socket */ /* open socket */
ueventfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); ueventfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (ueventfd < 0) { if (ueventfd < 0) {
fprintf(stderr, "Error: socket open failed\n"); fprintf(stderr, "Error: socket open failed\n");
return -1; return -1;
} }
/* Listen to netlink socket */ /* Listen to netlink socket */
if (bind(ueventfd, (void *)&nls, sizeof(struct sockaddr_nl))) { if (bind(ueventfd, (void *)&nls, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Bind failed\n"); fprintf(stderr, "Bind failed\n");
return -1; return -1;
} }
printf("Kernel uevent interface initialized...\n"); printf("Kernel uevent interface initialized...\n");
return ueventfd; return ueventfd;
} }
void uevent_cleanup() void uevent_cleanup()
{ {
if (ueventfd >= 0) if (ueventfd >= 0)
close(ueventfd); close(ueventfd);
} }
#endif #endif

View File

@@ -21,31 +21,31 @@
#define UEVENT_H #define UEVENT_H
enum uevent_action { enum uevent_action {
UEVENT_UNKNOWN = 0x01, UEVENT_UNKNOWN = 0x01,
UEVENT_ADD = 0x02, UEVENT_ADD = 0x02,
UEVENT_REMOVE = 0x04, UEVENT_REMOVE = 0x04,
UEVENT_CHANGE = 0x08, UEVENT_CHANGE = 0x08,
}; };
struct uevent_parameter { struct uevent_parameter {
char *key; char *key;
char *val; char *val;
}; };
struct uevent { struct uevent {
char *path; char *path;
enum uevent_action action; enum uevent_action action;
int sequence; int sequence;
char *subsystem; char *subsystem;
GList *params; GList *params;
}; };
struct uevent_notify { struct uevent_notify {
int action; /* bitfield */ int action; /* bitfield */
char *subsystem; /* NULL => any */ char *subsystem; /* NULL => any */
void *userdata; void *userdata;
void (*cb)(struct uevent *e, void *userdata); void (*cb)(struct uevent *e, void *userdata);
}; };
#if ENABLE_UEVENT #if ENABLE_UEVENT
@@ -58,7 +58,7 @@ void uevent_unregister_notifier(struct uevent_notify *nb);
#else #else
static inline int uevent_init() static inline int uevent_init()
{ {
return -1; return -1;
} }
static inline void uevent_cleanup() static inline void uevent_cleanup()

View File

@@ -37,288 +37,288 @@
void activate_window(Window win) void activate_window(Window win)
{ {
send_event32(win, server.atom._NET_ACTIVE_WINDOW, 2, CurrentTime, 0); send_event32(win, server.atom._NET_ACTIVE_WINDOW, 2, CurrentTime, 0);
} }
void change_window_desktop(Window win, int desktop) void change_window_desktop(Window win, int desktop)
{ {
send_event32(win, server.atom._NET_WM_DESKTOP, desktop, 2, 0); send_event32(win, server.atom._NET_WM_DESKTOP, desktop, 2, 0);
} }
void close_window(Window win) void close_window(Window win)
{ {
send_event32(win, server.atom._NET_CLOSE_WINDOW, 0, 2, 0); send_event32(win, server.atom._NET_CLOSE_WINDOW, 0, 2, 0);
} }
void toggle_window_shade(Window win) void toggle_window_shade(Window win)
{ {
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_SHADED, 0); send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_SHADED, 0);
} }
void toggle_window_maximized(Window win) void toggle_window_maximized(Window win)
{ {
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_MAXIMIZED_VERT, 0); send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_MAXIMIZED_VERT, 0);
send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_MAXIMIZED_HORZ, 0); send_event32(win, server.atom._NET_WM_STATE, 2, server.atom._NET_WM_STATE_MAXIMIZED_HORZ, 0);
} }
gboolean window_is_hidden(Window win) gboolean window_is_hidden(Window win)
{ {
Window window; Window window;
int count; int count;
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count); Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) { if (at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) {
XFree(at); XFree(at);
return TRUE; return TRUE;
} }
// do not add transient_for windows if the transient window is already in the taskbar // do not add transient_for windows if the transient window is already in the taskbar
window = win; window = win;
while (XGetTransientForHint(server.display, window, &window)) { while (XGetTransientForHint(server.display, window, &window)) {
if (get_task_buttons(window)) { if (get_task_buttons(window)) {
XFree(at); XFree(at);
return TRUE; return TRUE;
} }
} }
} }
XFree(at); XFree(at);
at = server_get_property(win, server.atom._NET_WM_WINDOW_TYPE, XA_ATOM, &count); at = server_get_property(win, server.atom._NET_WM_WINDOW_TYPE, XA_ATOM, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (at[i] == server.atom._NET_WM_WINDOW_TYPE_DOCK || at[i] == server.atom._NET_WM_WINDOW_TYPE_DESKTOP || if (at[i] == server.atom._NET_WM_WINDOW_TYPE_DOCK || at[i] == server.atom._NET_WM_WINDOW_TYPE_DESKTOP ||
at[i] == server.atom._NET_WM_WINDOW_TYPE_TOOLBAR || at[i] == server.atom._NET_WM_WINDOW_TYPE_MENU || at[i] == server.atom._NET_WM_WINDOW_TYPE_TOOLBAR || at[i] == server.atom._NET_WM_WINDOW_TYPE_MENU ||
at[i] == server.atom._NET_WM_WINDOW_TYPE_SPLASH) { at[i] == server.atom._NET_WM_WINDOW_TYPE_SPLASH) {
XFree(at); XFree(at);
return TRUE; return TRUE;
} }
} }
XFree(at); XFree(at);
for (int i = 0; i < num_panels; i++) { for (int i = 0; i < num_panels; i++) {
if (panels[i].main_win == win) { if (panels[i].main_win == win) {
return TRUE; return TRUE;
} }
} }
// specification // specification
// Windows with neither _NET_WM_WINDOW_TYPE nor WM_TRANSIENT_FOR set // Windows with neither _NET_WM_WINDOW_TYPE nor WM_TRANSIENT_FOR set
// MUST be taken as top-level window. // MUST be taken as top-level window.
return FALSE; return FALSE;
} }
int get_window_desktop(Window win) int get_window_desktop(Window win)
{ {
int desktop = get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL); int desktop = get_property32(win, server.atom._NET_WM_DESKTOP, XA_CARDINAL);
if (desktop == ALL_DESKTOPS) if (desktop == ALL_DESKTOPS)
return desktop; return desktop;
if (!server.viewports) if (!server.viewports)
return CLAMP(desktop, 0, server.num_desktops - 1); return CLAMP(desktop, 0, server.num_desktops - 1);
int x, y, w, h; int x, y, w, h;
get_window_coordinates(win, &x, &y, &w, &h); get_window_coordinates(win, &x, &y, &w, &h);
desktop = get_current_desktop(); desktop = get_current_desktop();
// Window coordinates are relative to the current viewport, make them absolute // Window coordinates are relative to the current viewport, make them absolute
x += server.viewports[desktop].x; x += server.viewports[desktop].x;
y += server.viewports[desktop].y; y += server.viewports[desktop].y;
if (x < 0 || y < 0) { if (x < 0 || y < 0) {
int num_results; int num_results;
long *x_screen_size = long *x_screen_size =
server_get_property(server.root_win, server.atom._NET_DESKTOP_GEOMETRY, XA_CARDINAL, &num_results); server_get_property(server.root_win, server.atom._NET_DESKTOP_GEOMETRY, XA_CARDINAL, &num_results);
if (!x_screen_size) if (!x_screen_size)
return 0; return 0;
int x_screen_width = x_screen_size[0]; int x_screen_width = x_screen_size[0];
int x_screen_height = x_screen_size[1]; int x_screen_height = x_screen_size[1];
XFree(x_screen_size); XFree(x_screen_size);
// Wrap // Wrap
if (x < 0) if (x < 0)
x += x_screen_width; x += x_screen_width;
if (y < 0) if (y < 0)
y += x_screen_height; y += x_screen_height;
} }
int best_match = -1; int best_match = -1;
int match_right = 0; int match_right = 0;
int match_bottom = 0; int match_bottom = 0;
// There is an ambiguity when a window is right on the edge between viewports. // There is an ambiguity when a window is right on the edge between viewports.
// In that case, prefer the viewports which is on the right and bottom of the window's top-left corner. // In that case, prefer the viewports which is on the right and bottom of the window's top-left corner.
for (int i = 0; i < server.num_desktops; i++) { for (int i = 0; i < server.num_desktops; i++) {
if (x >= server.viewports[i].x && x <= (server.viewports[i].x + server.viewports[i].width) && if (x >= server.viewports[i].x && x <= (server.viewports[i].x + server.viewports[i].width) &&
y >= server.viewports[i].y && y <= (server.viewports[i].y + server.viewports[i].height)) { y >= server.viewports[i].y && y <= (server.viewports[i].y + server.viewports[i].height)) {
int current_right = x < (server.viewports[i].x + server.viewports[i].width); int current_right = x < (server.viewports[i].x + server.viewports[i].width);
int current_bottom = y < (server.viewports[i].y + server.viewports[i].height); int current_bottom = y < (server.viewports[i].y + server.viewports[i].height);
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) { if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
best_match = i; best_match = i;
} }
} }
} }
if (best_match < 0) if (best_match < 0)
best_match = 0; best_match = 0;
// fprintf(stderr, "window %lx %s : viewport %d, (%d, %d)\n", win, get_task(win) ? get_task(win)->title : "??", // fprintf(stderr, "window %lx %s : viewport %d, (%d, %d)\n", win, get_task(win) ? get_task(win)->title : "??",
// best_match+1, x, y); // best_match+1, x, y);
return best_match; return best_match;
} }
int get_window_monitor(Window win) int get_window_monitor(Window win)
{ {
int x, y, w, h; int x, y, w, h;
get_window_coordinates(win, &x, &y, &w, &h); get_window_coordinates(win, &x, &y, &w, &h);
int best_match = -1; int best_match = -1;
int match_right = 0; int match_right = 0;
int match_bottom = 0; int match_bottom = 0;
// There is an ambiguity when a window is right on the edge between screens. // There is an ambiguity when a window is right on the edge between screens.
// In that case, prefer the monitor which is on the right and bottom of the window's top-left corner. // In that case, prefer the monitor which is on the right and bottom of the window's top-left corner.
for (int i = 0; i < server.num_monitors; i++) { for (int i = 0; i < server.num_monitors; i++) {
if (x >= server.monitors[i].x && x <= (server.monitors[i].x + server.monitors[i].width) && if (x >= server.monitors[i].x && x <= (server.monitors[i].x + server.monitors[i].width) &&
y >= server.monitors[i].y && y <= (server.monitors[i].y + server.monitors[i].height)) { y >= server.monitors[i].y && y <= (server.monitors[i].y + server.monitors[i].height)) {
int current_right = x < (server.monitors[i].x + server.monitors[i].width); int current_right = x < (server.monitors[i].x + server.monitors[i].width);
int current_bottom = y < (server.monitors[i].y + server.monitors[i].height); int current_bottom = y < (server.monitors[i].y + server.monitors[i].height);
if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) { if (best_match < 0 || (!match_right && current_right) || (!match_bottom && current_bottom)) {
best_match = i; best_match = i;
} }
} }
} }
if (best_match < 0) if (best_match < 0)
best_match = 0; best_match = 0;
// fprintf(stderr, "desktop %d, window %lx %s : monitor %d, (%d, %d)\n", 1 + get_current_desktop(), win, // fprintf(stderr, "desktop %d, window %lx %s : monitor %d, (%d, %d)\n", 1 + get_current_desktop(), win,
// get_task(win) ? get_task(win)->title : "??", best_match+1, x, y); // get_task(win) ? get_task(win)->title : "??", best_match+1, x, y);
return best_match; return best_match;
} }
void get_window_coordinates(Window win, int *x, int *y, int *w, int *h) void get_window_coordinates(Window win, int *x, int *y, int *w, int *h)
{ {
int dummy_int; int dummy_int;
unsigned ww, wh, bw, bh; unsigned ww, wh, bw, bh;
Window src; Window src;
XTranslateCoordinates(server.display, win, server.root_win, 0, 0, x, y, &src); XTranslateCoordinates(server.display, win, server.root_win, 0, 0, x, y, &src);
XGetGeometry(server.display, win, &src, &dummy_int, &dummy_int, &ww, &wh, &bw, &bh); XGetGeometry(server.display, win, &src, &dummy_int, &dummy_int, &ww, &wh, &bw, &bh);
*w = ww + bw; *w = ww + bw;
*h = wh + bh; *h = wh + bh;
} }
gboolean window_is_iconified(Window win) gboolean window_is_iconified(Window win)
{ {
// EWMH specification : minimization of windows use _NET_WM_STATE_HIDDEN. // EWMH specification : minimization of windows use _NET_WM_STATE_HIDDEN.
// WM_STATE is not accurate for shaded window and in multi_desktop mode. // WM_STATE is not accurate for shaded window and in multi_desktop mode.
int count; int count;
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count); Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (at[i] == server.atom._NET_WM_STATE_HIDDEN) { if (at[i] == server.atom._NET_WM_STATE_HIDDEN) {
XFree(at); XFree(at);
return TRUE; return TRUE;
} }
} }
XFree(at); XFree(at);
return FALSE; return FALSE;
} }
gboolean window_is_urgent(Window win) gboolean window_is_urgent(Window win)
{ {
int count; int count;
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count); Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (at[i] == server.atom._NET_WM_STATE_DEMANDS_ATTENTION) { if (at[i] == server.atom._NET_WM_STATE_DEMANDS_ATTENTION) {
XFree(at); XFree(at);
return TRUE; return TRUE;
} }
} }
XFree(at); XFree(at);
return FALSE; return FALSE;
} }
gboolean window_is_skip_taskbar(Window win) gboolean window_is_skip_taskbar(Window win)
{ {
int count; int count;
Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count); Atom *at = server_get_property(win, server.atom._NET_WM_STATE, XA_ATOM, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) { if (at[i] == server.atom._NET_WM_STATE_SKIP_TASKBAR) {
XFree(at); XFree(at);
return 1; return 1;
} }
} }
XFree(at); XFree(at);
return FALSE; return FALSE;
} }
Window get_active_window() Window get_active_window()
{ {
return get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW); return get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW);
} }
gboolean window_is_active(Window win) gboolean window_is_active(Window win)
{ {
return (win == get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW)); return (win == get_property32(server.root_win, server.atom._NET_ACTIVE_WINDOW, XA_WINDOW));
} }
int get_icon_count(gulong *data, int num) int get_icon_count(gulong *data, int num)
{ {
int count, pos, w, h; int count, pos, w, h;
count = 0; count = 0;
pos = 0; pos = 0;
while (pos + 2 < num) { while (pos + 2 < num) {
w = data[pos++]; w = data[pos++];
h = data[pos++]; h = data[pos++];
pos += w * h; pos += w * h;
if (pos > num || w <= 0 || h <= 0) if (pos > num || w <= 0 || h <= 0)
break; break;
count++; count++;
} }
return count; return count;
} }
gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, int best_icon_size) gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, int best_icon_size)
{ {
int width[icon_count], height[icon_count], pos, i, w, h; int width[icon_count], height[icon_count], pos, i, w, h;
gulong *icon_data[icon_count]; gulong *icon_data[icon_count];
/* List up icons */ /* List up icons */
pos = 0; pos = 0;
i = icon_count; i = icon_count;
while (i--) { while (i--) {
w = data[pos++]; w = data[pos++];
h = data[pos++]; h = data[pos++];
if (pos + w * h > num) if (pos + w * h > num)
break; break;
width[i] = w; width[i] = w;
height[i] = h; height[i] = h;
icon_data[i] = &data[pos]; icon_data[i] = &data[pos];
pos += w * h; pos += w * h;
} }
/* Try to find exact size */ /* Try to find exact size */
int icon_num = -1; int icon_num = -1;
for (i = 0; i < icon_count; i++) { for (i = 0; i < icon_count; i++) {
if (width[i] == best_icon_size) { if (width[i] == best_icon_size) {
icon_num = i; icon_num = i;
break; break;
} }
} }
/* Take the biggest or whatever */ /* Take the biggest or whatever */
if (icon_num < 0) { if (icon_num < 0) {
int highest = 0; int highest = 0;
for (i = 0; i < icon_count; i++) { for (i = 0; i < icon_count; i++) {
if (width[i] > highest) { if (width[i] > highest) {
icon_num = i; icon_num = i;
highest = width[i]; highest = width[i];
} }
} }
} }
*iw = width[icon_num]; *iw = width[icon_num];
*ih = height[icon_num]; *ih = height[icon_num];
return icon_data[icon_num]; return icon_data[icon_num];
} }
// Thanks zcodes! // Thanks zcodes!