From 5d170a634ead0119f6e5a9f63c23b2b064126f75 Mon Sep 17 00:00:00 2001 From: Federico Angelilli Date: Mon, 8 Jul 2024 15:22:41 +0200 Subject: Remove old files --- src/animate.c | 222 ---------------------------- src/animate.h | 51 ------- src/button.c | 122 --------------- src/button.h | 77 ---------- src/comet.c | 464 ---------------------------------------------------------- src/connect.c | 408 --------------------------------------------------- src/connect.h | 42 ------ src/draw.c | 391 ------------------------------------------------- src/draw.h | 69 --------- src/dwm.c | 445 ------------------------------------------------------- src/dwm.h | 30 ---- src/log.h | 25 ---- src/state.c | 137 ----------------- src/state.h | 38 ----- src/window.c | 306 -------------------------------------- src/window.h | 41 ------ 16 files changed, 2868 deletions(-) delete mode 100644 src/animate.c delete mode 100644 src/animate.h delete mode 100644 src/button.c delete mode 100644 src/button.h delete mode 100644 src/comet.c delete mode 100644 src/connect.c delete mode 100644 src/connect.h delete mode 100644 src/draw.c delete mode 100644 src/draw.h delete mode 100644 src/dwm.c delete mode 100644 src/dwm.h delete mode 100644 src/log.h delete mode 100644 src/state.c delete mode 100644 src/state.h delete mode 100644 src/window.c delete mode 100644 src/window.h diff --git a/src/animate.c b/src/animate.c deleted file mode 100644 index 839e748..0000000 --- a/src/animate.c +++ /dev/null @@ -1,222 +0,0 @@ -#include -#include -#include - -#include "animate.h" -#include "state.h" -#include "log.h" - -double clamp(double x, double min, double max) -{ - const double t = x < min ? min : x; - return t > max ? max : t; -} - -double smoothstep(double x, double edge0, double edge1) -{ - x = clamp((x - edge0) / (edge1 - edge0), 0, 1); - return x * x * (3.0 - 2.0 * x); -} - -double quadratic_bezier(double x, double a, double b, double c) -{ - g_assert(x >= 0 && x <= 1); - const double t = 1 - x; - return a * t * t + 2 * b * t * x + c * x * x; -} - -double cubic_bezier(double x, double a, double b, double c, double d) -{ - g_assert(x >= 0 && x <= 1); - const double t = 1 - x; - return a * (t * t * t) + 3 * b * (t * t * x) + 3 * c * (t * x * x) + d * (x * x * x); -} - -typedef struct { - Animation anim; - int width; - cairo_pattern_t *gradient; -} AnimationShine; - -static bool shine_func(AnimationShine *shine, Layout *layout, cairo_t *cr) -{ - gint64 end = shine->anim.start + shine->anim.duration; - gint64 now = g_get_monotonic_time(); - if (now > end) return false; - - double t = (double)(now - shine->anim.start) / (end - shine->anim.start); - double pos = cubic_bezier(t, 0.19, 1.0, 0.22, 1.0); - - double angle = atan((double)layout->height / layout->width); - - // Make it double just to be sure - int h = 2 * (double)layout->height / cos(angle); - int x = layout->x + pos * layout->width - shine->width; - int y = layout->y; - - cairo_matrix_t matrix; - cairo_matrix_init_translate(&matrix, -x, -y); - cairo_pattern_set_matrix(shine->gradient, &matrix); - - int dx = layout->x + layout->width / 2; - int dy = layout->y + layout->height / 2; - - cairo_translate(cr, dx, dy); - cairo_rotate(cr, -angle); - cairo_translate(cr, -dx, -dy); - - cairo_set_operator(cr, CAIRO_OPERATOR_ATOP); - cairo_set_source(cr, shine->gradient); - cairo_rectangle(cr, x, y - (h - layout->height) / 2, shine->width, h); - cairo_fill(cr); - - return true; -} - -Animation *animation_shine_create(gint64 duration) -{ - // Note the 0 initialization - AnimationShine *shine = g_malloc0(sizeof(AnimationShine)); - shine->anim.type = ANIM_SHINE; - shine->anim.after_func = (DrawFunc)shine_func; - shine->anim.duration = duration; - - // TODO: Change it depending on container size - shine->width = 25; - - shine->gradient = cairo_pattern_create_linear(0, 0, shine->width, 0); - cairo_pattern_add_color_stop_rgba(shine->gradient, 0, 1, 1, 1, 0); - cairo_pattern_add_color_stop_rgba(shine->gradient, 0.5, 1, 1, 1, 0.2); - cairo_pattern_add_color_stop_rgba(shine->gradient, 1, 1, 1, 1, 0); - - return (gpointer)shine; -} - -static bool pulse_func(Animation *pulse, Layout *layout, cairo_t *cr) -{ - gint64 end = pulse->start + pulse->duration; - gint64 now = g_get_monotonic_time(); - if (now > end) return false; - - // After half the duration we invert direction - gint64 mid = pulse->start + pulse->duration / 2; - double t = now <= mid - ? (double)(now - pulse->start) / (mid - pulse->start) - : 1.0 - (double)(now - mid) / (end - mid); - - double pos = cubic_bezier(t, 0.19, 1.0, 0.22, 1.0); - int max = 0.15 * layout->height; - - layout->x_pad = layout->btn->x_pad + max * pos; - layout->y_pad = layout->btn->y_pad + max * pos; - - return true; -} - -Animation *animation_pulse_create(gint64 duration) -{ - // Note the 0 initialization - Animation *pulse = g_malloc0(sizeof(Animation)); - pulse->type = ANIM_PULSE; - pulse->before_func = (DrawFunc)pulse_func; - pulse->duration = duration; - return pulse; -} - -static bool shrink_func(Animation *shrink, Layout *layout) -{ - g_assert_false(layout->btn->simple); - ButtonGroup *group = (gpointer)layout->btn; - - gint64 end = shrink->start + shrink->duration; - gint64 now = g_get_monotonic_time(); - - if (now > end) { - // NOTE: Actually remove the buttons from the group after the animation's end - // This part is quite rough around the edges... - if (group->children->next) { - g_list_free(g_list_remove_link(group->children, group->children)); - g_list_free_full(g_list_remove_link(layout->children, layout->children), (GDestroyNotify)layout_destroy); - layout->width = CAST(layout->children->data, Layout)->width; - return true; - } - - return false; - } - - double t = (double)(now - shrink->start) / (end - shrink->start); - double pos = smoothstep(t, 0, 1); - - int target_w = CAST(layout->children->data, Layout)->width; - int width = layout->width - pos * (layout->width - target_w); - layout->width = width; - - for (GList *it = layout->children, *next = it->next; it; it = next, next = it ? it->next : NULL) { - Layout *child = it->data; - if (child->x + child->width <= layout->x + width) continue; - - layout_destroy(it->data); - layout->children = g_list_delete_link(layout->children, it); - } - - return true; -} - -Animation *animation_group_shrink_create(gint64 duration) -{ - // Note the 0 initialization - Animation *shrink = g_malloc0(sizeof(Animation)); - shrink->type = ANIM_GROUP_SHRINK; - shrink->layout_func = (LayoutFunc)shrink_func; - shrink->duration = duration; - return shrink; -} - -static bool grow_func(Animation *grow, Layout *layout) -{ - g_assert_false(layout->btn->simple); - ButtonGroup *group = (gpointer)layout->btn; - - gint64 end = grow->start + grow->duration; - gint64 now = g_get_monotonic_time(); - if (now > end) return false; - - double t = (double)(now - grow->start) / (end - grow->start); - double pos = smoothstep(t, 0, 1); - - int start_w = CAST(layout->children->data, Layout)->width; - int width = start_w + pos * (layout->width - start_w); - layout->width = width; - - for (GList *it = layout->children->next, *next = it->next; it; it = next, next = it ? it->next : NULL) { - Layout *child = it->data; - if (child->x + child->width <= layout->x + width) continue; - - layout_destroy(it->data); - layout->children = g_list_delete_link(layout->children, it); - } - - return true; -} - -Animation *animation_group_grow_create(gint64 duration) -{ - // Note the 0 initialization - Animation *grow = g_malloc0(sizeof(Animation)); - grow->type = ANIM_GROUP_GROW; - grow->layout_func = (LayoutFunc)grow_func; - grow->duration = duration; - return grow; -} - -void animation_destroy(Animation *anim) -{ - if (anim == NULL) return; - - if (anim->type == ANIM_SHINE) - cairo_pattern_destroy(CAST(anim, AnimationShine)->gradient); - - g_free(anim); -} - -// vim: ts=4 sw=4 et diff --git a/src/animate.h b/src/animate.h deleted file mode 100644 index 79b6174..0000000 --- a/src/animate.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef COMET_ANIMATE_H -#define COMET_ANIMATE_H - -#include - -#include "draw.h" - -#define MILLIS(n) ((n) * G_TIME_SPAN_MILLISECOND) - -typedef struct Animation Animation; -typedef struct State State; - -typedef bool (* LayoutFunc)(Animation *anim, Layout *layout); -typedef bool (* DrawFunc)(Animation *anim, Layout *layout, cairo_t *cr); - -struct Animation { - enum { - ANIM_SHINE, - ANIM_PULSE, - ANIM_GROUP_SHRINK, - ANIM_GROUP_GROW, - } type; - gint64 start; - gint64 duration; - LayoutFunc layout_func; - // NOTE: These should not change the layout width - DrawFunc before_func; - DrawFunc after_func; -}; - -double clamp(double x, double min, double max); - -double smoothstep(double x, double edge0, double edge1); - -double quadratic_bezier(double x, double a, double b, double c); - -double cubic_bezier(double x, double a, double b, double c, double d); - -Animation *animation_shine_create(gint64 duration); - -Animation *animation_pulse_create(gint64 duration); - -Animation *animation_group_shrink_create(gint64 duration); - -Animation *animation_group_grow_create(gint64 duration); - -void animation_destroy(Animation *anim); - -#endif - -// vim: ts=4 sw=4 et diff --git a/src/button.c b/src/button.c deleted file mode 100644 index b11f5b1..0000000 --- a/src/button.c +++ /dev/null @@ -1,122 +0,0 @@ -#include - -#include "button.h" -#include "log.h" - -Button *button_simple_create(PangoAlignment align, Color color) -{ - Button *btn = g_malloc0(sizeof(ButtonSimple)); - btn->simple = true; - btn->align = align; - btn->color = color; - CAST(btn, ButtonSimple)->action = NULL; - return btn; -} - -void button_simple_set_text(Button *btn, char *text, Color text_color) -{ - g_assert(btn->simple); - ButtonSimple *sbtn = CAST(btn, ButtonSimple); - g_free(sbtn->text); - sbtn->text = text; - sbtn->text_color = text_color; -} - -const char *button_simple_get_text(Button *btn) -{ - g_assert(btn->simple); - return CAST(btn, ButtonSimple)->text; -} - -void button_simple_set_action(Button *btn, ButtonAction action, gpointer data) -{ - g_assert(btn->simple); - CAST(btn, ButtonSimple)->action = action; - CAST(btn, ButtonSimple)->data = data; -} - -ButtonAction button_simple_get_action(Button *btn) -{ - g_assert(btn->simple); - return CAST(btn, ButtonSimple)->action; -} - -Button *button_group_create(PangoAlignment align, Color color) -{ - Button *btn = g_malloc0(sizeof(ButtonGroup)); - btn->simple = false; - btn->align = align; - btn->color = color; - return btn; -} - -void button_group_append(Button *btn, Button *child) -{ - g_assert(!btn->simple); - CAST(btn, ButtonGroup)->children = g_list_append(CAST(btn, ButtonGroup)->children, child); -} - -void button_set_padding(Button *btn, int x_pad, int y_pad) -{ - g_assert(x_pad >= 0 && y_pad >= 0); - btn->x_pad = x_pad; - btn->y_pad = y_pad; -} - -bool button_set_animation(Button *btn, Animation *anim) -{ - if (btn->anim != NULL) - return false; - - btn->anim = anim; - return true; -} - -void button_set_line(Button *btn, Color line_color, int line_width) -{ - btn->line_color = line_color; - btn->line_width = line_width; -} - -void button_set_width(Button *btn, int max, int min) -{ - g_assert(max == 0 || max >= min); - g_assert(max >= 0 && min >= 0); - btn->max_width = max; - btn->min_width = min; -} - -Button *button_copy(Button *btn) -{ - if (btn->simple) { - ButtonSimple *copy = g_malloc0(sizeof(ButtonSimple)); - memcpy(copy, CAST(btn, ButtonSimple), sizeof(ButtonSimple)); - copy->text = g_strdup(CAST(btn, ButtonSimple)->text); - copy->btn.anim = NULL; - // NOTE: What to do with data? - return CAST(copy, Button); - } else { - ButtonGroup *copy = g_malloc0(sizeof(ButtonGroup)); - memcpy(copy, CAST(btn, ButtonGroup), sizeof(ButtonGroup)); - copy->btn.anim = NULL; - copy->children = NULL; - - for (GList *it = CAST(btn, ButtonGroup)->children; it != NULL; it = it->next) { - copy->children = g_list_prepend(copy->children, button_copy(it->data)); - } - copy->children = g_list_reverse(copy->children); - return CAST(copy, Button); - } -} - -void button_destroy(Button *btn) -{ - animation_destroy(btn->anim); - - if (btn->simple) - g_free(CAST(btn, ButtonSimple)->text); - else - g_list_free_full(CAST(btn, ButtonGroup)->children, (GDestroyNotify)button_destroy); - - g_free(btn); -} diff --git a/src/button.h b/src/button.h deleted file mode 100644 index 4b6c834..0000000 --- a/src/button.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef COMET_BUTTON_H -#define COMET_BUTTON_H - -#include -#include -#include - -#include "draw.h" -#include "animate.h" - -// For pointers only -#define CAST(ptr, type) ((type *)ptr) - -typedef struct Button Button; - -typedef void (* ButtonAction)(Button *btn); - -struct Button { - bool simple; - int x_pad; - int y_pad; - PangoAlignment align; - Color color; - Color line_color; - int line_width; - int max_width; - int min_width; - // TODO: Make animations not depend on the button - Animation *anim; -}; - -typedef struct { - Button btn; - Color text_color; - char *text; - ButtonAction action; - gpointer data; -} ButtonSimple; - -typedef struct { - Button btn; - GList *children; -} ButtonGroup; - -// NOTE: For the moment all button specific functions take a generic button -// pointer and assert the right type, so the check should be done by the caller - -Button *button_simple_create(PangoAlignment align, Color color); - -// Takes ownership of text -void button_simple_set_text(Button *btn, char *text, Color text_color); - -const char *button_simple_get_text(Button *btn); - -void button_simple_set_action(Button *btn, ButtonAction action, gpointer data); - -ButtonAction button_simple_get_action(Button *btn); - -Button *button_group_create(PangoAlignment align, Color color); - -void button_group_append(Button *btn, Button *child); - -void button_set_padding(Button *btn, int x_pad, int y_pad); - -bool button_set_animation(Button *btn, Animation *anim); - -void button_set_line(Button *btn, Color line_color, int line_width); - -void button_set_width(Button *btn, int max, int min); - -Button *button_copy(Button *btn); - -void button_destroy(Button *btn); - -#endif - -// vim: ts=4 sw=4 et diff --git a/src/comet.c b/src/comet.c deleted file mode 100644 index b97f8bd..0000000 --- a/src/comet.c +++ /dev/null @@ -1,464 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "window.h" -#include "log.h" -#include "draw.h" -#include "connect.h" -#include "state.h" -#include "dwm.h" - -#define EVEN(n) ((int)(n) - ((int)(n) % 2 != 0)) - -static void log_handler(const char *log_domain, - GLogLevelFlags level, - const char *message, - gpointer log_level) -{ - GLogLevelFlags message_level = level & G_LOG_LEVEL_MASK; - - if ((GLogLevelFlags)log_level < message_level) - return; - - if (message_level <= G_LOG_LEVEL_WARNING) - g_printerr("%s\n", message); - else - g_print("%s\n", message); -} - - -static gboolean mainloop_quit(gpointer data) -{ - g_main_loop_quit(data); - return G_SOURCE_CONTINUE; -} - -// Taken from slstatus -// XXX: Change with something more robust -char *cpu_percentage(void) -{ - static long double a[7]; - long double b[7], sum; - memcpy(b, a, sizeof(b)); - - FILE *stat = fopen("/proc/stat", "rb"); - g_assert_nonnull(stat); - - /* cpu user nice system idle iowait irq softirq */ - g_assert(7 == fscanf(stat, "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf", - &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6])); - - fclose(stat); - if (b[0] == 0) return NULL; - - sum = (b[0] + b[1] + b[2] + b[3] + b[4] + b[5] + b[6]) - - (a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6]); - - if (sum == 0) return NULL; - - return g_strdup_printf(" %d%%", (int)(100 * - ((b[0] + b[1] + b[2] + b[5] + b[6]) - - (a[0] + a[1] + a[2] + a[5] + a[6])) / sum)); -} - -static gboolean cpu_update(Button *btn) -{ - char *perc = cpu_percentage(); - - // Don't update on error - if (perc == NULL) - return G_SOURCE_CONTINUE; - - ButtonSimple *sbtn = CAST(btn, ButtonSimple); - bool update = g_strcmp0(perc, sbtn->text) != 0; - button_simple_set_text(btn, perc, sbtn->text_color); - - if (update) - state_request_redraw(sbtn->data, false); - - return G_SOURCE_CONTINUE; -} - -static gboolean ram_update(Button *btn) -{ - FILE *meminfo = fopen("/proc/meminfo", "rb"); - g_assert_nonnull(meminfo); - - uintmax_t total, unused, buffers, cached; - g_assert(5 == fscanf(meminfo, - "MemTotal: %ju kB\n" - "MemFree: %ju kB\n" - "MemAvailable: %ju kB\n" - "Buffers: %ju kB\n" - "Cached: %ju kB\n", - &total, &unused, &buffers, &buffers, &cached)); - - int usage = 100 * (total - unused - buffers - cached) / total; - fclose(meminfo); - - - ButtonSimple *sbtn = CAST(btn, ButtonSimple); - char *ram = g_strdup_printf(" %d%%", usage); - bool update = g_strcmp0(ram, sbtn->text) != 0; - button_simple_set_text(btn, ram, sbtn->text_color); - - if (update) - state_request_redraw(sbtn->data, false); - - return G_SOURCE_CONTINUE; -} - -static gboolean temp_update(Button *btn) -{ - FILE *thermal = fopen("/sys/class/thermal/thermal_zone2/temp", "rb"); - g_assert_nonnull(thermal); - - uintmax_t value; - g_assert(1 == fscanf(thermal, "%ju\n", &value)); - fclose(thermal); - - ButtonSimple *sbtn = CAST(btn, ButtonSimple); - char *temp = g_strdup_printf(" %d °C", (int)(value / 1000)); - bool update = g_strcmp0(temp, sbtn->text) != 0; - button_simple_set_text(btn, temp, sbtn->text_color); - - if (update) - state_request_redraw(sbtn->data, false); - - return G_SOURCE_CONTINUE; -} - -static gboolean disk_update(Button *btn) -{ - struct statvfs buffer; - g_assert(statvfs("/", &buffer) == 0); - const double used = 1.0 - ((double)buffer.f_bavail / (double)buffer.f_blocks); - - ButtonSimple *sbtn = CAST(btn, ButtonSimple); - char *disk = g_strdup_printf(" %d%%", (int)round(used * 100.0)); - bool update = g_strcmp0(disk, sbtn->text) != 0; - button_simple_set_text(btn, disk, sbtn->text_color); - - if (update) - state_request_redraw(sbtn->data, false); - - return G_SOURCE_CONTINUE; -} - -static gboolean date_update(Button *btn) -{ - GDateTime *dt = g_date_time_new_now_local(); - char *text = g_date_time_format(dt, "%A %d %H:%M"); - g_date_time_unref(dt); - - g_assert_nonnull(text); - button_simple_set_text(btn, text, CAST(btn, ButtonSimple)->text_color); - - struct { - State *state; - timer_t timer; - } *date_ctx = CAST(btn, ButtonSimple)->data; - - log_debug("Updated date and time"); - state_request_redraw(date_ctx->state, false); - - struct timespec current; - clock_gettime(CLOCK_REALTIME, ¤t); - - struct itimerspec its = { 0 }; - its.it_value.tv_sec = 60 - (current.tv_sec % 60); - timer_settime(date_ctx->timer, 0, &its, NULL); - - return G_SOURCE_CONTINUE; -} - -static void show_action(Button *btn) -{ - log_info("Called action: %s", button_simple_get_text(btn)); -} - -static void quit_action(Button *btn) -{ - log_info("Quit button pressed"); - g_main_loop_quit(CAST(btn, ButtonSimple)->data); -} - -static void menu_action(Button *btn) -{ - struct { - State *state; - ButtonGroup *group; - char *strings[2]; - GList *toggled; - bool closed; - } *menu_ctx = CAST(btn, ButtonSimple)->data; - - // NOTE: Clear the previous animation, if any - g_list_free(menu_ctx->group->children); - g_clear_pointer(&menu_ctx->group->btn.anim, animation_destroy); - menu_ctx->group->children = g_list_copy(menu_ctx->toggled); - - char *text = g_strdup(menu_ctx->strings[menu_ctx->closed]); - button_simple_set_text(btn, text, CAST(btn, ButtonSimple)->text_color); - - Animation *anim = menu_ctx->closed - ? animation_group_grow_create(MILLIS(600)) - : animation_group_shrink_create(MILLIS(600)); - - g_assert(button_set_animation((gpointer)menu_ctx->group, anim)); - state_request_animation(menu_ctx->state); - - log_debug("%s menu", menu_ctx->closed ? "Opened" : "Closed"); - menu_ctx->closed = !menu_ctx->closed; -} - -static void register_buttons(State *state, Color color, Color text_color, Color line_color, int line_w) -{ - // Precompute max button size - int text_w; - draw_compute_text_size(state->draw, " 100%", &text_w, NULL); - int min_w = text_w + line_w + state->draw->height; - - // Cpu usage button - Button *cpu_btn = button_simple_create(PANGO_ALIGN_RIGHT, color); - button_simple_set_text(cpu_btn, g_strdup(" 0%"), text_color); - button_simple_set_action(cpu_btn, show_action, state); - button_set_line(cpu_btn, line_color, line_w); - button_set_width(cpu_btn, 0, min_w); - state_add_button(state, cpu_btn); - - cpu_update(cpu_btn); - g_timeout_add(MILLIS(1), G_SOURCE_FUNC(cpu_update), cpu_btn); - - // Temperature button - Button *temp_btn = button_simple_create(PANGO_ALIGN_RIGHT, color); - button_simple_set_text(temp_btn, NULL, text_color); - button_simple_set_action(temp_btn, show_action, state); - button_set_line(temp_btn, line_color, line_w); - button_set_width(temp_btn, 0, min_w); - state_add_button(state, temp_btn); - - temp_update(temp_btn); - g_timeout_add(MILLIS(20), G_SOURCE_FUNC(temp_update), temp_btn); - - // Ram usage button - Button *ram_btn = button_simple_create(PANGO_ALIGN_RIGHT, color); - button_simple_set_text(ram_btn, NULL, text_color); - button_simple_set_action(ram_btn, show_action, state); - button_set_line(ram_btn, line_color, line_w); - button_set_width(ram_btn, 0, min_w); - state_add_button(state, ram_btn); - - ram_update(ram_btn); - g_timeout_add(MILLIS(10), G_SOURCE_FUNC(ram_update), ram_btn); - - // Disk usage button - Button *disk_btn = button_simple_create(PANGO_ALIGN_RIGHT, color); - button_simple_set_text(disk_btn, NULL, text_color); - button_simple_set_action(disk_btn, show_action, state); - button_set_line(disk_btn, line_color, line_w); - button_set_width(disk_btn, 0, min_w); - state_add_button(state, disk_btn); - - disk_update(disk_btn); - g_timeout_add(MILLIS(60), G_SOURCE_FUNC(disk_update), disk_btn); -} - -int main(int argc, char **argv) -{ - setlocale(LC_CTYPE, ""); - g_log_set_default_handler(log_handler, (gpointer)G_LOG_LEVEL_DEBUG); - - GMainLoop *mainloop = g_main_loop_new(NULL, FALSE); - - Connection *con = connect_create(); - - Window *win = window_create(con); - - int screen_width = con->screen_size->width; - int screen_height = con->screen_size->height; - double scale = window_get_scale(win); - - int height = EVEN(round(screen_height * 0.021)); - int x_padding = EVEN(round(screen_width * 0.005)); - int y_padding = EVEN(round(screen_height * 0.004)); - - log_debug("Calculated dimensions [height=%d, x_pad=%d, y_pad=%d]", height, x_padding, y_padding); - - Color background_all = { 0.3, 0.3, 0.3, 1 }; - PangoContext *context = pango_cairo_create_context(window_get_context(win)); - - Drawer *draw = draw_create(); - draw_set_background(draw, background_all); - draw_set_separator(draw, 10); - draw_set_font(draw, "Hack 13 Bold"); - draw_set_context(draw, context); - draw_set_size(draw, height, x_padding, x_padding, y_padding); - - State *state = state_create("$1", win, draw); - - Window *win2 = window_create(con); - int x_padding2 = EVEN(round(screen_width * 0.025)); - int y_padding2 = screen_height - height - EVEN(round(screen_height * 0.005)); - - PangoContext *context2 = pango_cairo_create_context(window_get_context(win2)); - - Drawer *draw2 = draw_create(); - draw_set_background(draw2, background_all); - draw_set_separator(draw2, 10); - draw_set_font(draw2, "Hack 13 Bold"); - draw_set_context(draw2, context); - draw_set_size(draw2, height, x_padding2, x_padding2 * 3, y_padding2); - - State *state2 = state_create("$2", win2, draw2); - - Color color = { 0.4, 0.4, 0.4, 1 }; - Color purple = { 0.502, 0.168, 0.886, 1 }; - Color line_color = { 0.8, 0.8, 0.8, 1 }; - Color text_color = { 0.9, 0.9, 0.9, 1 }; - - // Dwm tags - DwmIpc *dwm = dwm_create(state, "/tmp/dwm.sock"); - dwm_register_tags(dwm, color, purple, text_color); - - int line_w = 0; - register_buttons(state, color, text_color, line_color, line_w); - - // Buttons with special handling - - struct { - State *state; - timer_t timer; - } date_ctx = { state, 0 }; - - int text_w; - draw_compute_text_size(state->draw, "Wednesday 31 12:34", &text_w, NULL); - int min_w = text_w + line_w + state->draw->height; - - // Date & time button - Button *date_btn = button_simple_create(PANGO_ALIGN_CENTER, color); - button_simple_set_text(date_btn, NULL, text_color); - button_simple_set_action(date_btn, NULL, &date_ctx); - button_set_width(date_btn, 0, min_w); - state_add_button(state, date_btn); - - struct sigevent sev = { 0 }; - sev.sigev_notify = SIGEV_SIGNAL; - sev.sigev_signo = SIGUSR1; - - g_assert(timer_create(CLOCK_REALTIME, &sev, &date_ctx.timer) == 0); - date_update(date_btn); - - // Quit button - Button *q_btn = button_simple_create(PANGO_ALIGN_RIGHT, purple); - button_simple_set_text(q_btn, g_strdup(""), text_color); - button_simple_set_action(q_btn, quit_action, mainloop); - state_add_button(state, q_btn); - - // Menu button(s) - Color grey = { 0.5, 0.5, 0.5, 1 }; - Button *group = button_group_create(PANGO_ALIGN_LEFT, grey); - - Button *child1 = button_simple_create(PANGO_ALIGN_CENTER, color); - button_set_padding(child1, 1, 1); - button_simple_set_text(child1, g_strdup("C1"), text_color); - button_simple_set_action(child1, show_action, NULL); - - Button *child2 = button_simple_create(PANGO_ALIGN_CENTER, color); - button_set_padding(child2, 1, 1); - button_simple_set_text(child2, g_strdup("C2"), text_color); - button_simple_set_action(child2, show_action, NULL); - - Button *child3 = button_simple_create(PANGO_ALIGN_CENTER, color); - button_set_padding(child3, 1, 1); - button_simple_set_text(child3, g_strdup("C3"), text_color); - button_simple_set_action(child3, show_action, NULL); - - struct { - State *state; - ButtonGroup *group; - char *strings[2]; - GList *toggled; - bool closed; - } menu_ctx = { state, (gpointer)group, {"", ""}, NULL, true }; - - Button *menu = button_simple_create(PANGO_ALIGN_LEFT, color); - button_simple_set_text(menu, g_strdup(menu_ctx.strings[0]), text_color); - button_simple_set_action(menu, menu_action, &menu_ctx); - - menu_ctx.toggled = g_list_append(menu_ctx.toggled, menu); - menu_ctx.toggled = g_list_append(menu_ctx.toggled, child1); - menu_ctx.toggled = g_list_append(menu_ctx.toggled, child2); - menu_ctx.toggled = g_list_append(menu_ctx.toggled, child3); - - button_group_append(group, menu); - state_add_button(state, group); - - state_order_button(state); - - Button *btn2 = button_simple_create(PANGO_ALIGN_LEFT, color); - button_set_padding(btn2, 1, 1); - button_simple_set_text(btn2, g_strdup("YAY"), text_color); - button_simple_set_action(btn2, show_action, NULL); - - state_add_button(state2, btn2); - state_order_button(state2); - - // TODO: Mirroring - //for (GList *it = state->btns; it != NULL; it = it->next) { - // state_add_button(state2, button_copy(it->data)); - //} - - connect_add_state(con, state); - connect_add_state(con, state2); - connect_attach_source(con); - - guint source_alrm = g_unix_signal_add(SIGUSR1, G_SOURCE_FUNC(date_update), date_btn); - guint source_term = g_unix_signal_add(SIGTERM, mainloop_quit, mainloop); - guint source_int = g_unix_signal_add(SIGINT, mainloop_quit, mainloop); - - state_request_redraw(state, true); - - log_debug("Starting main loop"); - g_main_loop_run(mainloop); - - log_debug("Cleaning main loop"); - g_clear_pointer(&mainloop, g_main_loop_unref); - - g_source_remove(source_alrm); - g_source_remove(source_term); - g_source_remove(source_int); - - // NOTE: Skip the first element (the open/close button) - if (menu_ctx.closed) - g_list_free_full(g_list_delete_link(menu_ctx.toggled, menu_ctx.toggled), (GDestroyNotify)button_destroy); - else - g_list_free(menu_ctx.toggled); - - timer_delete(date_ctx.timer); - g_object_unref(context); - - // NOTE: Buttons are freed by state_destroy - dwm_destroy(dwm); - - g_list_free_full(state->btns, (GDestroyNotify)button_destroy); - - state_destroy(state); - draw_destroy(draw); - window_destroy(win); - - state_destroy(state2); - draw_destroy(draw2); - window_destroy(win2); - - connect_destroy(con); - - return 0; -} - -// vim: ts=4 sw=4 et diff --git a/src/connect.c b/src/connect.c deleted file mode 100644 index aaced77..0000000 --- a/src/connect.c +++ /dev/null @@ -1,408 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "connect.h" -#include "state.h" - -static bool query_xrm(Connection *con, const char *res, char **value) -{ - if (xcb_xrm_resource_get_string(con->database, res, res, value) >= 0) { - log_debug("Xrm query '%s' found '%s'", res, *value); - return true; - } - - log_debug("Xrm query '%s' not found", res); - return false; -} - -static void update_xrm(Connection *con) -{ - xcb_flush(con->connection); - xcb_xrm_database_t *database = xcb_xrm_database_from_default(con->connection); - - if (database == NULL) { - log_warning("Xrm database couldn't be updated"); - return; - } - - xcb_xrm_database_free(con->database); - con->database = database; - log_debug("Xrm database updated"); -} - -static void update_scale(Connection *con) -{ - char *dpi_value; - if (query_xrm(con, "Xft.dpi", &dpi_value)) { - con->screen_dpi = strtod(dpi_value, NULL); - g_free(dpi_value); - } else { - con->screen_dpi = (double)con->screen_size->height * 25.4 / (double)con->screen_size->mheight; - log_debug("Fallback dpi value '%.2lf'", con->screen_dpi); - } -} - -// Check if point (px, py) is inside a rectangle in (x, y), (x+w, y), (x, y+h) and (w+h, y+h) -static inline bool in_rect(int px, int py, int x, int y, int w, int h) -{ - return px >= x && px <= x + w && py >= y && py <= y + h; -} - -// Check if point (px, py) is inside a circle of radius r and center (x, y) -static inline bool in_circle(int px, int py, int x, int y, int r) -{ - int dx = x - px; - int dy = y - py; - return (dx * dx + dy * dy) <= r * r; -} - -// Check if point (px, py) is inside a capsule in (x, y), (x+w, y), (x, y+h) and (w+h, y+h) -static inline bool in_capsule(int px, int py, int x, int y, int w, int h) -{ - g_assert(w >= h); - int radius = h / 2; - - // Circle case - if (w == h) return in_circle(px, py, x + radius, y + radius, radius); - - // Capsule case - return in_circle(px, py, x + radius, y + radius, radius) - || in_circle(px, py, x + w - radius, y + radius, radius) - || in_rect(px, py, x + radius, y, w - 2 * radius, h); -} - -static bool button_action_find(State *state, GList *layouts, int x, int y) -{ - for (GList *it = layouts; it; it = it->next) { - const Layout *layout = it->data; - - // Skip - if (layout->x + layout->width < x) continue; - if (layout->x > x) break; - - // Bound check click coordinates - int w = layout->width - 2 * layout->x_pad; - int h = layout->height - 2 * layout->y_pad; - - if (!in_capsule(x, y, layout->x + layout->x_pad, layout->y + layout->y_pad, w, h)) - continue; - - Button *btn = layout->btn; - if (!layout->btn->simple) { - log_debug("Button group layout [x=%d, y=%d, w=%d, h=%d, button=%p]", - layout->x, layout->y, layout->width, layout->height, btn); - - // Check the group children - return button_action_find(state, layout->children, x, y); - } - - log_debug("Button layout [x=%d, y=%d, w=%d, h=%d, button=%p]", - layout->x, layout->y, layout->width, layout->height, btn); - - ButtonAction action = button_simple_get_action(btn); - if (action == NULL) { - // TODO: Button labels - log_debug("Ignoring button without action [button=%p]", btn); - return true; - } - - // NOTE: Animations may change the layouts! - Animation *anim = animation_shine_create(MILLIS(250)); - //Animation *anim = animation_pulse_create(MILLIS(200)); - - if (button_set_animation(btn, anim)) - state_request_animation(state); - else - animation_destroy(anim); - - log_info("Triggering action for button [text=\"%s\", button=%p]", button_simple_get_text(btn), btn); - action(btn); - return true; - } - - return false; -} - -static void button_action(State *state, const char *event, int x, int y) -{ - double scale = window_get_scale(state->win); - int digital_x = x / scale; - int digital_y = y / scale; - - log_debug("Checking %s event [device_x=%d, device_y=%d, x=%d, y=%d]", event, x, y, digital_x, digital_y); - if (!button_action_find(state, state->draw->layouts, digital_x, digital_y)) - log_debug("Ignoring %s", event); -} - -typedef struct { - GSource source; - Connection *con; - gpointer fd_tag; - xcb_generic_event_t *event; -} EventSource; - -static gboolean source_check(GSource *source) -{ - EventSource *xsource = (EventSource *)source; - xcb_flush(xsource->con->connection); - g_assert_null(xsource->event); - - GIOCondition flags = g_source_query_unix_fd(source, xsource->fd_tag); - if (flags & G_IO_IN) { - g_assert_false(xcb_connection_has_error(xsource->con->connection)); - xsource->event = xcb_poll_for_event(xsource->con->connection); - } - - return xsource->event != NULL; -} - -static gboolean source_dispatch(GSource *source, GSourceFunc callback, gpointer data) -{ - EventSource *xsource = (EventSource *)source; - g_assert_nonnull(xsource->event); - - do { - switch (xsource->event->response_type & ~0x80) { - case 0: { - xcb_generic_error_t *error = (xcb_generic_error_t *)xsource->event; - - const char *extension; - const char *name = xcb_errors_get_name_for_error(xsource->con->errors, error->error_code, &extension); - const char *major = xcb_errors_get_name_for_major_code(xsource->con->errors, error->major_code); - const char *minor = xcb_errors_get_name_for_minor_code(xsource->con->errors, error->major_code, error->minor_code); - - // TODO: Handle errors instead of aborting - log_error("Xcb error '%s' [extension=%s, major=%s, minor=%s, resource=%u, sequence=%u]", - name, - extension ? extension : "none", - major, - minor ? minor : "none", - (unsigned int)error->resource_id, - (unsigned int)error->sequence); - break; - } - - case XCB_EXPOSE: { - xcb_expose_event_t *expose = (xcb_expose_event_t *)xsource->event; - log_debug("Processing event 'Expose' [type=%d]", XCB_EXPOSE); - - for (GList *it = xsource->con->states; it != NULL; it = it->next) { - State *state = it->data; - if (state->win->window == expose->window) { - state_request_redraw(state, true); - break; - } - } - break; - } - - case XCB_CREATE_NOTIFY: { - xcb_create_notify_event_t *create = (xcb_create_notify_event_t *)xsource->event; - log_debug("Processing event 'CreateNotify' [type=%d]", XCB_CREATE_NOTIFY); - - // TODO: Circulate top the window if override_redirect == 0 - - break; - } - - case XCB_BUTTON_RELEASE: { - xcb_button_release_event_t *button = (xcb_button_release_event_t *)xsource->event; - log_debug("Processing event 'ButtonRelease' [type=%d]", XCB_BUTTON_RELEASE); - - // TODO: Handle different actions properly - switch (button->detail) { - case XCB_BUTTON_INDEX_2: // left click - case XCB_BUTTON_INDEX_1: // right click - case XCB_BUTTON_INDEX_3: // middle click - for (GList *it = xsource->con->states; it != NULL; it = it->next) { - State *state = it->data; - if (state->win->window == button->event) { - button_action(state, "button release", button->event_x, button->event_y); - break; - } - } - break; - - default: - log_debug("Ignoring button release [button=%d]", button->detail); - break; - } - break; - } - - // TODO: Implement correctly hovering - //case XCB_MOTION_NOTIFY: { - // xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xsource->event; - // log_debug("Processing event 'MotionNotify' [type=%d]", XCB_MOTION_NOTIFY); - // button_action(xsource->con->state, "motion notify", motion->event_x, motion->event_y); - // break; - //} - - case XCB_PROPERTY_NOTIFY: { - xcb_property_notify_event_t *property = (xcb_property_notify_event_t *)xsource->event; - log_debug("Processing event 'PropertyNotify' [type=%d]", XCB_PROPERTY_NOTIFY); - - if (property->atom == XCB_ATOM_RESOURCE_MANAGER) { - update_xrm(xsource->con); - update_scale(xsource->con); - for (GList *it = xsource->con->states; it != NULL; it = it->next) - state_request_redraw(it->data, true); - } - break; - } - - default: { - const char *extension; - const char *name = xcb_errors_get_name_for_xcb_event(xsource->con->errors, xsource->event, &extension); - - // TODO: Handle XCB_RANDR_SCREEN_CHANGE_NOTIFY - - log_debug("Ignoring event '%s' [type=%d, extension=%s]", - name, - xsource->event->response_type & 0x7f, - extension ? extension : "none"); - } - } - g_free(xsource->event); - } while ((xsource->event = xcb_poll_for_event(xsource->con->connection)) != NULL); - - return G_SOURCE_CONTINUE; -} - -static GSourceFuncs source_fns = { - NULL, - source_check, - source_dispatch, - NULL, -}; - -static void attach_source(Connection *con) -{ - EventSource *source = (EventSource *)g_source_new(&source_fns, sizeof(EventSource)); - con->source = (GSource *)source; - g_source_set_static_name(con->source, "EventSource"); - - source->con = con; - source->event = NULL; - source->fd_tag = g_source_add_unix_fd(con->source, xcb_get_file_descriptor(con->connection), G_IO_IN | G_IO_HUP | G_IO_ERR); - - g_source_attach(con->source, NULL); -} - -Connection *connect_create() -{ - Connection *con = g_malloc0(sizeof(Connection)); - g_assert_nonnull(con); - - int preferred_screen = 0; - con->connection = xcb_connect(NULL, &preferred_screen); - g_assert_true(con->connection != NULL && !xcb_connection_has_error(con->connection)); - log_debug("Xcb connection established"); - - log_debug("Default screen '%d'", preferred_screen); - xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(con->connection)); - - while (preferred_screen != 0 && iter.rem) { - xcb_screen_next(&iter); - preferred_screen--; - } - - con->screen = iter.data; - xcb_generic_error_t *error; - - xcb_randr_query_version_cookie_t version_cookie = xcb_randr_query_version(con->connection, - XCB_RANDR_MAJOR_VERSION, - XCB_RANDR_MINOR_VERSION); - - xcb_randr_query_version_reply_t *randr_version = xcb_randr_query_version_reply(con->connection, - version_cookie, - &error); - - g_assert_null(error); - log_debug("RandR loaded [version=%d.%d]", randr_version->major_version, randr_version->minor_version); - g_assert_cmpint(randr_version->major_version, >=, 1); - g_free(randr_version); - - xcb_randr_get_screen_info_cookie_t cookie = xcb_randr_get_screen_info(con->connection, con->screen->root); - con->info_reply = xcb_randr_get_screen_info_reply(con->connection, cookie, &error); - g_assert_null(error); - - con->screen_size = xcb_randr_get_screen_info_sizes(con->info_reply); - g_assert_nonnull(con->screen_size); - log_debug("Screen size [width=%d, height=%d]", con->screen_size->width, con->screen_size->height); - - xcb_randr_select_input(con->connection, - con->screen->root, - XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | - XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | - XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY); - - log_debug("Xcb searching 32 bit visual"); - con->visual_type = xcb_aux_find_visual_by_attrs(con->screen, XCB_VISUAL_CLASS_TRUE_COLOR, 32); - con->screen_depth = 32; - - if (con->visual_type == NULL) { - // NOTE: 24 bit visuals don't have the alpha channel for transparency - log_debug("Fallback to 24 bit visual"); - con->visual_type = xcb_aux_find_visual_by_attrs(con->screen, XCB_VISUAL_CLASS_TRUE_COLOR, 24); - con->screen_depth = 24; - } - - g_assert_nonnull(con->visual_type); - log_debug("Xcb visual type found [id=%u]", con->visual_type->visual_id); - - xcb_intern_atom_cookie_t *ewmh_cookie = xcb_ewmh_init_atoms(con->connection, &con->ewmh); - g_assert_true(xcb_ewmh_init_atoms_replies(&con->ewmh, ewmh_cookie, &error)); - g_assert_null(error); - log_debug("Xcb ewmh initialized"); - - con->database = xcb_xrm_database_from_default(con->connection); - g_assert_nonnull(con->database); - - // TODO: Dpi aware scaling - update_scale(con); - - g_assert(xcb_errors_context_new(con->connection, &con->errors) == 0); - log_debug("Xcb errors loaded"); - - xcb_flush(con->connection); - log_debug("Xcb set up"); - - return con; -} - -void connect_attach_source(Connection *con) -{ - g_assert_null(con->source); - attach_source(con); - log_debug("Xcb event loop attached"); -} - -void connect_add_state(Connection *con, State *state) -{ - g_assert_nonnull(state); - con->states = g_list_append(con->states, state); - log_debug("Add state to event loop [state=%p, state=\"%s\"]", state, state->label); -} - -void connect_destroy(Connection *con) -{ - g_source_destroy(con->source); - g_source_unref(con->source); - - xcb_ewmh_connection_wipe(&con->ewmh); - xcb_errors_context_free(con->errors); - xcb_xrm_database_free(con->database); - xcb_disconnect(con->connection); - - g_free(con->info_reply); - g_free(con); -} - -// vim: ts=4 sw=4 et diff --git a/src/connect.h b/src/connect.h deleted file mode 100644 index dbb650c..0000000 --- a/src/connect.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef COMET_CONNEC_H -#define COMET_CONNEC_H - -#include -#include -#include -#include -#include -#include - -// Forward declaration -typedef struct State State; - -typedef struct Connection Connection; - -// TODO: Make this opaque -struct Connection { - xcb_connection_t *connection; - xcb_screen_t *screen; - xcb_randr_get_screen_info_reply_t *info_reply; - xcb_randr_screen_size_t *screen_size; - double screen_dpi; - int screen_depth; - xcb_visualtype_t *visual_type; - xcb_xrm_database_t *database; - xcb_errors_context_t *errors; - xcb_ewmh_connection_t ewmh; - GSource *source; - GList *states; -}; - -Connection *connect_create(); - -void connect_attach_source(Connection *con); - -void connect_add_state(Connection *con, State *state); - -void connect_destroy(Connection *con); - -#endif - -// vim: ts=4 sw=4 et diff --git a/src/draw.c b/src/draw.c deleted file mode 100644 index 44baba6..0000000 --- a/src/draw.c +++ /dev/null @@ -1,391 +0,0 @@ -#include -#include -#include -#include -#include - -#include "draw.h" -#include "button.h" -#include "log.h" - -#define ANIMATION(btn, which, ...) \ - do { \ - if ((btn)->anim != NULL && (btn)->anim->which##_func != NULL) { \ - if ((btn)->anim->start == 0) { \ - (btn)->anim->start = g_get_monotonic_time(); \ - log_debug("Starting animation [type=%d, func=%s, start=%ld, duration=%ld, button=%p]", \ - (btn)->anim->type, #which, (btn)->anim->start, (btn)->anim->duration, (btn)); \ - } \ - if (!(btn)->anim->which##_func((btn)->anim, __VA_ARGS__)) \ - (btn)->anim->which##_func = NULL; \ - } \ - } while (false) - -Drawer *draw_create() -{ - Drawer *draw = g_malloc0(sizeof(Drawer)); - g_assert_nonnull(draw); - return draw; -} - -static void paint_button(cairo_t *cr, const Layout *layout) -{ - double degree = M_PI / 180.0; - int radius = (layout->height - 2 * layout->y_pad) / 2; - int line_radius = radius - layout->line_w / 2; - -#if 0 - // Debug lines - - // Layout size - cairo_set_source_rgb(cr, 0, 0, 0); - cairo_move_to(cr, layout->x, layout->y); - cairo_line_to(cr, layout->x, layout->y + layout->height); - cairo_stroke(cr); - - cairo_move_to(cr, layout->x + layout->width, layout->y); - cairo_line_to(cr, layout->x + layout->width, layout->y + layout->height); - cairo_stroke(cr); - - // Layout padding - cairo_set_source_rgb(cr, 0.5, 0.1, 0.1); - cairo_rectangle(cr, layout->x + layout->x_pad, layout->y + layout->y_pad, layout->width - 2 * layout->x_pad, layout->height - 2 * layout->y_pad); - cairo_stroke(cr); -#endif - - cairo_set_line_width(cr, layout->line_w); - - // Button background - Color color = layout->btn->color; - cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); - cairo_new_sub_path(cr); - cairo_arc(cr, layout->x + layout->x_pad + radius, layout->y + layout->y_pad + radius, radius, 90 * degree, 270 * degree); - cairo_arc(cr, layout->x + layout->width - layout->x_pad - radius, layout->y + layout->y_pad + radius, radius, 270 * degree, 450 * degree); - cairo_close_path(cr); - cairo_fill(cr); - - // Button border - color = layout->btn->line_color; - cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); - cairo_new_sub_path(cr); - cairo_arc(cr, layout->x + layout->x_pad + radius, layout->y + layout->y_pad + radius, line_radius, 90 * degree, 270 * degree); - cairo_arc(cr, layout->x + layout->width - layout->x_pad - radius, layout->y + layout->y_pad + radius, line_radius, 270 * degree, 450 * degree); - cairo_close_path(cr); - cairo_stroke(cr); -} - -static void paint_text(cairo_t *cr, const Layout *layout) -{ - int text_x = layout->x + layout->width / 2 - layout->text_w / 2; - int text_y = layout->y + layout->height / 2 - layout->text_h / 2; - - Color color = CAST(layout->btn, ButtonSimple)->text_color; - cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a); - cairo_move_to(cr, text_x, text_y); - - // NOTE: This works only if the text didn't change in size after the layouting - pango_layout_set_text(layout->pl, CAST(layout->btn, ButtonSimple)->text, -1); - pango_cairo_update_layout(cr, layout->pl); - pango_cairo_show_layout(cr, layout->pl); -} - -static void paint_button_list(cairo_t *cr, GList *layouts) -{ - for (GList *it = layouts; it; it = it->next) { - Layout *layout = it->data; - Button *btn = layout->btn; - - cairo_push_group(cr); - - // Apply before_func on the layout and cairo context - ANIMATION(btn, before, layout, cr); - - paint_button(cr, layout); - - if (btn->simple) { - g_assert_null(layout->children); - paint_text(cr, layout); - } else { - g_assert_nonnull(layout->children); - paint_button_list(cr, layout->children); - } - - // Apply after_func on the layout and cairo context - ANIMATION(btn, after, layout, cr); - - cairo_pop_group_to_source(cr); - cairo_paint(cr); - } -} - -void draw_paint(Drawer *draw, Window *win) -{ - // Back buffering - cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, draw->width, draw->height); - - cairo_t *cr = cairo_create(surface); - cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - // Fill the background - cairo_set_source_rgba(cr, draw->background.r, draw->background.g, draw->background.b, draw->background.a); - cairo_paint(cr); - - // Treat the top-level buttons similarly to a button group - paint_button_list(cr, draw->layouts); - cairo_destroy(cr); - - // Use device pixels - double scale = window_get_scale(win); - window_move(win, draw->left_pad * scale, draw->top_pad * scale); - window_resize(win, draw->width * scale, draw->height * scale); - - window_paint_surface(win, surface, draw->width * scale, draw->height * scale); - cairo_surface_destroy(surface); -} - -void layout_destroy(Layout *layout) -{ - if (layout->pl != NULL) - g_object_unref(layout->pl); - - g_list_free_full(layout->children, (GDestroyNotify)layout_destroy); - g_free(layout); -} - -static void layout_invalidate(GList *layouts) -{ - g_list_free_full(layouts, (GDestroyNotify)layout_destroy); -} - -static void layout_adjust(GList *start, GList *end, int off) -{ - // NOTE: end must be present in the list or segfault - for (GList *it = start; it != end; it = it->next) { - Layout *layout = it->data; - layout->x += off; - layout_adjust(layout->children, NULL, off); - } -} - -static void layout_set_text(Layout *layout, PangoFontDescription *desc, int height) -{ - g_assert(layout->btn->simple); - const char *text = CAST(layout->btn, ButtonSimple)->text; - - pango_layout_set_font_description(layout->pl, desc); - pango_layout_set_alignment(layout->pl, PANGO_ALIGN_CENTER); - pango_layout_set_height(layout->pl, 0); - pango_layout_set_text(layout->pl, text, -1); - pango_layout_get_pixel_size(layout->pl, &layout->text_w, &layout->text_h); - - // If there is only one glyph the button should be round - size_t text_l = g_utf8_strlen(text, -1); - layout->width = text_l == 1 ? height : layout->text_w + height; -} - -static void compute_width(Drawer *draw, Window *win) -{ - int screen_width = win->con->screen_size->width; - double scale = window_get_scale(win); - draw->width = (screen_width - draw->right_pad - draw->left_pad) / scale; - log_debug("Draw context width calculated [scale=%lf, width=%d]", scale, draw->width); -} - -static void layout_check_width(Layout *layout) -{ - // FIXME: Max width is not implemented correctly - if (layout->btn->max_width > 0) - layout->width = MIN(layout->btn->max_width, layout->width); - - if (layout->btn->min_width > 0) - layout->width = MAX(layout->btn->min_width, layout->width); -} - -static GList *compute_group_layout(Drawer *draw, GList *btns, int bx, bool root) -{ - GList *layouts = NULL; - for (GList *it = btns; it; it = it->next) { - Button *btn = it->data; - PangoAlignment align = btn->align; - - Layout *layout = g_malloc0(sizeof(Layout)); - layouts = g_list_prepend(layouts, layout); - - layout->btn = btn; - layout->height = draw->height; - layout->line_w = btn->line_width; - layout->x_pad = btn->x_pad; - layout->y_pad = btn->y_pad; - layout->x = bx; - layout->y = 0; - -retry: - if (!btn->simple) { - ButtonGroup *group = CAST(btn, ButtonGroup); - g_assert_nonnull(group->children); - - // NOTE: If a group has only one children treat it as a single button - // As a consequence btn->align can't be trusted - if (group->children->next == NULL) { - // XXX: We should also keep track of the group animation - // Is this the right way to do it? Can it loop? - ANIMATION(btn, layout, layout); - - layout->btn = btn = group->children->data; - goto retry; - } else { - layout->children = compute_group_layout(draw, group->children, bx, false); - g_assert_nonnull(layout->children); - - Layout *last = g_list_last(layout->children)->data; - layout->width = last->x + last->width - bx; - - // FIXME: Temporary solution to make the antialiasing (or the circles not - // overlapping correctly) problem less noticeable - bool fix_left = CAST(layout->children->data, Layout)->x_pad == 0; - if (fix_left) { - layout->x += 1; - layout->width -= 1; - } - - bool fix_right = last->x_pad == 0; - if (fix_right) - layout->width -= 1; - } - } else { - layout->pl = pango_layout_new(draw->context); - layout_set_text(layout, draw->desc, draw->height); - } - - // NOTE: We add half a line width on both sides - layout->width += layout->line_w; - layout_check_width(layout); - - // Apply layout_func on the layout - ANIMATION(btn, layout, layout); - - bx += layout->width; - if (root) { - draw->layout_bx[align] = bx; - draw->layout_end[align] = layouts; - } - - if (it->next != NULL && (!root || CAST(it->next->data, Button)->align == align)) - bx += draw->sep; - } - - // Otherwise button_action_find will not work! - layouts = g_list_reverse(layouts); - return layouts; -} - -void draw_compute_layout(Drawer *draw, Window *win, GList *btns) -{ - // Move this somewhere else - compute_width(draw, win); - - double scale = window_get_scale(win); - cairo_surface_set_device_scale(win->surface, scale, scale); - pango_cairo_context_set_resolution(draw->context, scale * 96); - pango_cairo_update_context(win->cr, draw->context); - - memset(draw->layout_end, 0, sizeof(draw->layout_end)); - memset(draw->layout_bx, 0, sizeof(draw->layout_bx)); - - g_clear_pointer(&draw->layouts, layout_invalidate); - draw->layouts = compute_group_layout(draw, btns, 0, true); - - draw->layout_width[PANGO_ALIGN_LEFT] = draw->layout_bx[PANGO_ALIGN_LEFT]; - draw->layout_width[PANGO_ALIGN_CENTER] = draw->layout_bx[PANGO_ALIGN_CENTER] - draw->layout_bx[PANGO_ALIGN_LEFT]; - draw->layout_width[PANGO_ALIGN_RIGHT] = draw->layout_bx[PANGO_ALIGN_RIGHT] - MAX(draw->layout_bx[PANGO_ALIGN_CENTER], draw->layout_bx[PANGO_ALIGN_LEFT]); - - if (draw->layout_bx[PANGO_ALIGN_RIGHT] > draw->width) { - log_error("Layout is bigger than the window (%d vs %d)", draw->layout_bx[PANGO_ALIGN_RIGHT], draw->width); - } - - bool has_left = draw->layout_end[PANGO_ALIGN_LEFT] != NULL; - bool has_center = draw->layout_end[PANGO_ALIGN_CENTER] != NULL; - - GList *center_start = has_left ? draw->layout_end[PANGO_ALIGN_LEFT]->next : draw->layouts; - GList *right_start = has_center ? draw->layout_end[PANGO_ALIGN_CENTER]->next : - has_left ? draw->layout_end[PANGO_ALIGN_LEFT]->next : draw->layouts; - - if (center_start != NULL) { - int center = round(draw->width / 2); - int center_off = center - draw->layout_width[PANGO_ALIGN_CENTER] / 2 - draw->layout_bx[PANGO_ALIGN_LEFT]; - - log_debug("Aligning center layout [center=%d, off=%d]", center, center_off); - layout_adjust(center_start, right_start, center_off); - } - - if (right_start != NULL) { - int right = draw->width - draw->layout_width[PANGO_ALIGN_RIGHT]; - int right_off = right - MAX(draw->layout_bx[PANGO_ALIGN_LEFT], draw->layout_bx[PANGO_ALIGN_CENTER]); - - log_debug("Aligning right layout [x=%d, off=%d]", right, right_off); - layout_adjust(right_start, NULL, right_off); - } - - log_debug("Updated layouts"); -} - -void draw_compute_text_size(Drawer *draw, const char *text, int *text_w, int *text_h) -{ - PangoLayout *pl = pango_layout_new(draw->context); - pango_layout_set_font_description(pl, draw->desc); - pango_layout_set_height(pl, 0); - pango_layout_set_alignment(pl, PANGO_ALIGN_CENTER); - pango_layout_set_text(pl, text, -1); - pango_layout_get_pixel_size(pl, text_w, text_h); - g_object_unref(pl); -} - -void draw_set_background(Drawer *draw, Color background) -{ - draw->background = background; -} - -void draw_set_separator(Drawer *draw, int sep) -{ - g_assert(sep >= 0); - draw->sep = sep; -} - -void draw_set_font(Drawer *draw, const char *font) -{ - log_debug("Pango loading font description '%s'", font); - draw->desc = pango_font_description_from_string(font); - g_assert_nonnull(draw->desc); - log_debug("Pango found matching font '%s'", pango_font_description_get_family(draw->desc)); -} - -// NOTE: Don't call this between layout and paint! -void draw_set_context(Drawer *draw, PangoContext *context) -{ - g_assert_nonnull(context); - draw->context = context; - log_debug("Pango context updated [context=%p]", context); -} - -void draw_set_size(Drawer *draw, int height, int left_pad, int right_pad, int top_pad) -{ - g_assert(height > 0); - - draw->height = height; - draw->left_pad = left_pad; - draw->right_pad = right_pad; - draw->top_pad = top_pad; - - log_debug("Draw context size updated [height=%d, left_pad=%d, right_pad=%d, top_pad=%d]", - height, left_pad, right_pad, top_pad); -} - -void draw_destroy(Drawer *draw) -{ - g_clear_pointer(&draw->layouts, layout_invalidate); - pango_font_description_free(draw->desc); - g_free(draw); -} - -// vim: ts=4 sw=4 et diff --git a/src/draw.h b/src/draw.h deleted file mode 100644 index 6d0119f..0000000 --- a/src/draw.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef COMET_DRAW_H -#define COMET_DRAW_H - -#include -#include -#include - -#include "window.h" - -typedef struct { - double r, g, b, a; -} Color; - -// The one who draws ('o')7 - -typedef struct { - PangoFontDescription *desc; - PangoContext *context; - int height; - int width; - int left_pad; - int right_pad; - int top_pad; - int sep; - Color background; - GList *layouts; - // Calculated by draw_compute_layout - GList *layout_end[3]; - int layout_bx[3]; - int layout_width[3]; -} Drawer; - -typedef struct { - struct Button *btn; - int x, y; - int width, height; - int text_w, text_h; - int x_pad, y_pad; - int line_w; - PangoLayout *pl; - GList *children; -} Layout; - -Drawer *draw_create(); - -void draw_paint(Drawer *draw, Window *win); - -void layout_destroy(Layout *layout); - -// TODO: Rework the api so that we don't need to pass the window -void draw_compute_layout(Drawer *draw, Window *win, GList *btns); - -void draw_compute_text_size(Drawer *draw, const char *text, int *text_w, int *text_h); - -void draw_set_background(Drawer *draw, Color background); - -void draw_set_separator(Drawer *draw, int sep); - -void draw_set_font(Drawer *draw, const char *font); - -void draw_set_context(Drawer *draw, PangoContext *context); - -void draw_set_size(Drawer *draw, int height, int left_pad, int right_pad, int top_pad); - -void draw_destroy(Drawer *draw); - -#endif - -// vim: ts=4 sw=4 et diff --git a/src/dwm.c b/src/dwm.c deleted file mode 100644 index eda553e..0000000 --- a/src/dwm.c +++ /dev/null @@ -1,445 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "dwm.h" -#include "log.h" - -#define IPC_MAGIC "DWM-IPC" -#define IPC_MAGIC_LEN 7 - -typedef struct { - uint8_t magic[IPC_MAGIC_LEN]; - uint32_t size; - uint8_t type; -} __attribute__((packed)) DwmIpcHeader; - -typedef enum { - IPC_TYPE_RUN_COMMAND = 0, - IPC_TYPE_GET_MONITORS = 1, - IPC_TYPE_GET_TAGS = 2, - IPC_TYPE_GET_LAYOUTS = 3, - IPC_TYPE_GET_DWM_CLIENT = 4, - IPC_TYPE_SUBSCRIBE = 5, - IPC_TYPE_EVENT = 6 -} DwmIpcMessage; - -#define IPC_EVENT_TAG_CHANGE "tag_change_event" -#define IPC_EVENT_CLIENT_FOCUS_CHANGE "client_focus_change_event" -#define IPC_EVENT_LAYOUT_CHANGE "layout_change_event" -#define IPC_EVENT_MONITOR_FOCUS_CHANGE "monitor_focus_change_event" -#define IPC_EVENT_FOCUSED_TITLE_CHANGE "focused_title_change_event" -#define IPC_EVENT_FOCUSED_STATE_CHANGE "focused_state_change_event" - -static void ipc_send(DwmIpc *dwm, DwmIpcMessage msg_type, uint8_t *msg, uint32_t msg_size) -{ - DwmIpcHeader header; - memcpy(header.magic, IPC_MAGIC, IPC_MAGIC_LEN); - header.size = msg_size; - header.type = msg_type; - - GError *error = NULL; - - gssize size = 0; - while (size < sizeof(DwmIpcHeader)) { - gssize sent = g_socket_send(dwm->socket, (void *)&header + size, sizeof(DwmIpcHeader) - size, NULL, &error); - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - g_error_free(error); - continue; - } - g_assert(sent != -1); - size += sent; - } - - size = 0; - while (size < msg_size) { - gssize sent = g_socket_send(dwm->socket, msg + size, msg_size - size, NULL, &error); - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - g_error_free(error); - continue; - } - g_assert(sent != -1); - size += sent; - } - - log_debug("Sent ipc message [type=%d, size=%d]", msg_type, msg_size); -} - -static void ipc_subscribe(DwmIpc *dwm, const char *event) -{ - // { - // "event": "", - // "action": "subscribe" - // } - - JsonBuilder *builder = json_builder_new(); - - json_builder_begin_object(builder); - - json_builder_set_member_name(builder, "event"); - json_builder_add_string_value(builder, event); - - json_builder_set_member_name(builder, "action"); - json_builder_add_string_value(builder, "subscribe"); - - json_builder_end_object(builder); - - JsonNode *root = json_builder_get_root(builder); - - JsonGenerator *gen = json_generator_new(); - json_generator_set_root(gen, root); - - gsize msg_len = 0; - gchar *msg = json_generator_to_data(gen, &msg_len); - - log_debug("Subscribing to dwm ipc: %s", msg); - ipc_send(dwm, IPC_TYPE_SUBSCRIBE, msg, msg_len); - - json_node_free(root); - g_object_unref(gen); - g_object_unref(builder); - g_free(msg); -} - -static void ipc_run_command(DwmIpc *dwm, const char *cmd, JsonNode **args) -{ - // { - // "command": "", - // "args": [ ... ] - // } - - JsonBuilder *builder = json_builder_new(); - - json_builder_begin_object(builder); - - json_builder_set_member_name(builder, "command"); - json_builder_add_string_value(builder, cmd); - - json_builder_set_member_name(builder, "args"); - json_builder_begin_array(builder); - - while (*args != NULL) { - json_builder_add_value(builder, *args++); - } - - json_builder_end_array(builder); - json_builder_end_object(builder); - - JsonNode *root = json_builder_get_root(builder); - - JsonGenerator *gen = json_generator_new(); - json_generator_set_root(gen, root); - - gsize msg_len = 0; - gchar *msg = json_generator_to_data(gen, &msg_len); - - log_debug("Sending run_command to dwm ipc: %s", msg); - ipc_send(dwm, IPC_TYPE_RUN_COMMAND, msg, msg_len); - - json_node_free(root); - g_object_unref(gen); - g_object_unref(builder); - g_free(msg); -} - -static void ipc_get_tags(DwmIpc *dwm) -{ - log_debug("Sending get_tags to dwm ipc"); - ipc_send(dwm, IPC_TYPE_GET_TAGS, "", 1); -} - -#define JSON_FIELD(reader, member) (json_reader_end_member(reader), json_reader_read_member(reader, member)) - -static void ipc_handle(DwmIpc *dwm, DwmIpcMessage type, char *reply, uint32_t reply_size) -{ - GError *error = NULL; - JsonParser *parser = json_parser_new(); - if (!json_parser_load_from_data(parser, reply, reply_size - 1, &error)) { - log_warning("Failed to parse dwm ipc reply: %s", error->message); - g_error_free(error); - return; - } - - JsonReader *reader = json_reader_new(json_parser_get_root(parser)); - - switch (type) { - case IPC_TYPE_EVENT: - { - if (json_reader_read_member(reader, IPC_EVENT_TAG_CHANGE)) { - log_debug("Handling dwm ipc event [event=%s]", IPC_EVENT_TAG_CHANGE); - - json_reader_read_member(reader, "new_state"); - json_reader_read_member(reader, "selected"); - long selected = json_reader_get_int_value(reader); - json_reader_end_member(reader); - json_reader_end_member(reader); - json_reader_end_member(reader); - - log_debug("Selected tag mask: %ld", selected); - - if (dwm->tags[0] != NULL) { - for (int i = 0; i < 9; i++) - dwm->tags[i]->color = selected & (1 << i) ? dwm->selected : dwm->color; - - state_request_redraw(dwm->state, false); - } - } else if (JSON_FIELD(reader, IPC_EVENT_CLIENT_FOCUS_CHANGE)) { - log_debug("Handling dwm ipc event [event=%s]", IPC_EVENT_CLIENT_FOCUS_CHANGE); - - json_reader_read_member(reader, "new_win_id"); - long win_id = json_reader_get_int_value(reader); - json_reader_end_member(reader); - json_reader_end_member(reader); - - char *msg = g_strdup_printf("{ \"client_window_id\": %ld }\n", win_id); - dwm->change_title = true; - ipc_send(dwm, IPC_TYPE_GET_DWM_CLIENT, msg, strlen(msg)); - g_free(msg); - } else if (JSON_FIELD(reader, IPC_EVENT_LAYOUT_CHANGE)) { - log_debug("Ignoring dwm ipc event [event=%s]", IPC_EVENT_LAYOUT_CHANGE); - // TODO - - } else if (JSON_FIELD(reader, IPC_EVENT_MONITOR_FOCUS_CHANGE)) { - log_debug("Ignoring dwm ipc event [event=%s]", IPC_EVENT_MONITOR_FOCUS_CHANGE); - // TODO - - } else if (JSON_FIELD(reader, IPC_EVENT_FOCUSED_TITLE_CHANGE)) { - log_debug("Ignoring dwm ipc event [event=%s]", IPC_EVENT_FOCUSED_TITLE_CHANGE); - // TODO - - } else if (JSON_FIELD(reader, IPC_EVENT_FOCUSED_STATE_CHANGE)) { - log_debug("Ignoring dwm ipc event [event=%s]", IPC_EVENT_FOCUSED_STATE_CHANGE); - // TODO - - } else { - const char *event = "?"; - if (json_reader_read_element(reader, 0)) - event = json_reader_get_string_value(reader); - - log_warning("Unrecognized dwm ipc event: %s", event); - } - break; - } - - case IPC_TYPE_GET_DWM_CLIENT: - { - log_debug("Received dwm client information message [type=%d]", type); - - if (dwm->change_title) { - json_reader_read_member(reader, "name"); - const char *title = json_reader_get_string_value(reader); - - log_debug("Changing current program title: %s", title ? title : "?"); - if (title == NULL || *title == '\0') { - state_remove_button(dwm->state, dwm->title); - dwm->hidden_title = true; - } else { - button_simple_set_text(dwm->title, g_strdup(title), dwm->text_color); - if (dwm->hidden_title) { - state_add_button(dwm->state, dwm->title); - state_order_button(dwm->state); - dwm->hidden_title = false; - } - } - - dwm->change_title = false; - state_request_redraw(dwm->state, true); - json_reader_end_member(reader); - } - break; - } - - case IPC_TYPE_GET_TAGS: - { - log_debug("Received dwm tag information message [type=%d]", type); - - guint index = 0; - while (json_reader_read_element(reader, index)) { - - json_reader_read_member(reader, "bit_mask"); - int mask = json_reader_get_int_value(reader); - json_reader_end_element(reader); - - // XXX: Handle nicely - g_assert_cmpint(mask, ==, 1 << index); - - // Set the tag names accordingly - json_reader_read_member(reader, "name"); - const char *name = json_reader_get_string_value(reader); - json_reader_end_element(reader); - - g_assert(index < 9); - button_simple_set_text(dwm->tags[index], g_strdup(name), dwm->text_color); - - json_reader_end_element(reader); - index++; - } - - break; - } - - default: - { - log_debug("Ignoring dwm ipc message [type=%d]", type); - //log_debug("%s", reply); - break; - } - } - - g_object_unref(reader); - g_object_unref(parser); -} - -static gboolean socket_callback(GSocket *socket, GIOCondition condition, gpointer data) -{ - if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) return G_SOURCE_REMOVE; - GError *error = NULL; - - DwmIpcHeader header; - gssize size = 0; - while (size < sizeof(DwmIpcHeader)) { - gssize read = g_socket_receive(socket, (void *)&header + size, sizeof(DwmIpcHeader) - size, NULL, &error); - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - g_error_free(error); - continue; - } - g_assert(read != -1); - size += read; - } - - if (memcmp(&header, IPC_MAGIC, IPC_MAGIC_LEN) != 0) { - log_warning("Malformed dwm ipc message"); - return G_SOURCE_CONTINUE;; - } - - uint32_t reply_size; - memcpy(&reply_size, (void *)&header + IPC_MAGIC_LEN, sizeof(uint32_t)); - - uint8_t msg_type; - memcpy(&msg_type, (void *)&header + IPC_MAGIC_LEN + sizeof(uint32_t), sizeof(uint8_t)); - - char *reply = g_malloc(reply_size); - size = 0; - while (size < reply_size) { - gssize read = g_socket_receive(socket, reply + size, reply_size - size, NULL, NULL); - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - g_error_free(error); - continue; - } - g_assert(read != -1); - size += read; - } - - //log_debug("Received dwm ipc response: %s", reply); - ipc_handle(data, msg_type, reply, reply_size); - g_free(reply); - - return G_SOURCE_CONTINUE; -} - -DwmIpc *dwm_create(State *state, const char *socket) -{ - DwmIpc *dwm = g_malloc0(sizeof(DwmIpc)); - dwm->state = state; - - GError *error = NULL; - dwm->socket = g_socket_new(G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, 0, &error); - g_assert_nonnull(dwm->socket); - - GSocketAddress *addr = g_unix_socket_address_new(socket); - if (!g_socket_connect(dwm->socket, addr, NULL, &error)) { - g_assert_nonnull(error); - log_debug("Failed to connect socket %s: %s", socket, error->message); - log_info("Skipped dwm ipc [socket=%s]", socket); - - g_error_free(error); - g_object_unref(dwm->socket); - g_free(dwm); - return NULL; - } - - dwm->source = g_socket_create_source(dwm->socket, G_IO_IN, NULL); - g_source_set_static_name(dwm->source, "DwmIpcSource"); - g_source_set_callback(dwm->source, (GSourceFunc)socket_callback, dwm, NULL); - - const char *events[] = { - IPC_EVENT_TAG_CHANGE, - IPC_EVENT_CLIENT_FOCUS_CHANGE, - IPC_EVENT_LAYOUT_CHANGE, - IPC_EVENT_MONITOR_FOCUS_CHANGE, - IPC_EVENT_FOCUSED_TITLE_CHANGE, - IPC_EVENT_FOCUSED_STATE_CHANGE, - }; - for (int i = 0; i < G_N_ELEMENTS(events); ++i) - ipc_subscribe(dwm, events[i]); - - g_source_attach(dwm->source, NULL); - log_info("Attached dwm ipc source [socket=%s]", socket); - - g_object_unref(addr); - return dwm; -} - -static void change_tag_action(Button *btn) -{ - ButtonSimple *sbtn = CAST(btn, ButtonSimple); - DwmIpc *dwm = sbtn->data; - - int n = sbtn->text[0] - '0'; - g_assert(n >= 1 && n <= 9); - - log_info("Toggled tag %d", n); - - JsonNode *args[] = { - json_node_init_int(json_node_alloc(), 1 << (n - 1)), - NULL - }; - ipc_run_command(dwm, "view", args); -} - -void dwm_register_tags(DwmIpc *dwm, Color color, Color selected, Color text_color) -{ - if (dwm == NULL) return; - - dwm->color = color; - dwm->text_color = text_color; - dwm->selected = selected; - - // Tags button - for (int i = 0; i < 9; ++i) { - char text[] = { '1' + i, '\0' }; - dwm->tags[i] = button_simple_create(PANGO_ALIGN_LEFT, color); - button_simple_set_text(dwm->tags[i], g_strdup(text), text_color); - button_simple_set_action(dwm->tags[i], change_tag_action, dwm); - state_add_button(dwm->state, dwm->tags[i]); - } - - // This will set the tag names - ipc_get_tags(dwm); - - dwm->title = button_simple_create(PANGO_ALIGN_CENTER, color); - dwm->hidden_title = true; - - // FIXME: Set the first tag - CAST(dwm->tags[0], ButtonSimple)->action(dwm->tags[0]); - dwm->tags[0]->color = dwm->selected; -} - -void dwm_destroy(DwmIpc *dwm) -{ - if (dwm == NULL) return; - - g_source_destroy(dwm->source); - g_source_unref(dwm->source); - g_object_unref(dwm->socket); - - if (dwm->hidden_title) - button_destroy(dwm->title); - - g_free(dwm); -} - -// vim: ts=4 sw=4 et diff --git a/src/dwm.h b/src/dwm.h deleted file mode 100644 index 2ce055c..0000000 --- a/src/dwm.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef COMET_DWM_H -#define COMET_DWM_H - -#include -#include - -#include "state.h" - -typedef struct { - GSocket *socket; - GSource *source; - State *state; - Color color; - Color text_color; - Color selected; - Button *tags[9]; - Button *title; - bool change_title; - bool hidden_title; -} DwmIpc; - -DwmIpc *dwm_create(State *state, const char *socket); - -void dwm_register_tags(DwmIpc *dwm, Color color, Color selected, Color text_color); - -void dwm_destroy(DwmIpc *dwm); - -#endif - -// vim: ts=4 sw=4 et diff --git a/src/log.h b/src/log.h deleted file mode 100644 index 8ee600f..0000000 --- a/src/log.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef COMET_LOG_H -#define COMET_LOG_H - -#include - -#define DEBUG_FORMAT(format, ...) \ - "[%s] \x1b[1mdebug\x1b[0m: " format, __func__, ## __VA_ARGS__ - -#define INFO_FORMAT(format, ...) \ - "[%s] \x1b[1;96minfo\x1b[0m: " format, __func__, ## __VA_ARGS__ - -#define WARNING_FORMAT(format, ...) \ - "[%s] \x1b[1;33mwarning\x1b[0m: " format, __func__, ## __VA_ARGS__ - -#define ERROR_FORMAT(format, ...) \ - "[%s] \x1b[1;31merror\x1b[0m: " format, __func__, ## __VA_ARGS__ - -#define log_debug(...) g_debug(DEBUG_FORMAT(__VA_ARGS__)) -#define log_info(...) g_info(INFO_FORMAT(__VA_ARGS__)) -#define log_warning(...) g_warning(WARNING_FORMAT(__VA_ARGS__)) -#define log_error(...) g_error(ERROR_FORMAT(__VA_ARGS__)) - -#endif - -// vim: ts=4 sw=4 et diff --git a/src/state.c b/src/state.c deleted file mode 100644 index c8fe0df..0000000 --- a/src/state.c +++ /dev/null @@ -1,137 +0,0 @@ -#include - -#include "state.h" -#include "log.h" - -State *state_create(const char *label, Window *win, Drawer *draw) -{ - State *state = g_malloc0(sizeof(State)); - g_assert_nonnull(state); - state->label = label ? label : "comet"; - state->win = win; - state->draw = draw; - return state; -} - -void state_add_button(State *state, Button *btn) -{ - state->btns = g_list_append(state->btns, btn); -} - -void state_remove_button(State *state, Button *btn) -{ - state->btns = g_list_remove(state->btns, btn); -} - -static gint align_compare(gconstpointer a, gconstpointer b) -{ - PangoAlignment a_align = CAST(a, Button)->align; - PangoAlignment b_align = CAST(b, Button)->align; - - if (a_align < b_align) return -1; - if (a_align > b_align) return 1; - return 0; -} - -void state_order_button(State *state) -{ - state->btns = g_list_sort(state->btns, align_compare); -} - -static gboolean redraw_handler(State *state) -{ - log_debug("Redrawing once [relayout=%d, state=\"%s\"]", state->relayout, state->label); - - if (state->relayout) { - draw_compute_layout(state->draw, state->win, state->btns); - state->relayout = false; - } - - draw_paint(state->draw, state->win); - - state->idle_id = 0; - return G_SOURCE_REMOVE; -} - -void state_request_redraw(State *state, bool relayout) -{ - // Override old redraw - if (state->idle_id != 0) - g_source_remove(state->idle_id); - - state->relayout = relayout; - - if (state->anim_id != 0) return; - - state->idle_id = g_idle_add(G_SOURCE_FUNC(redraw_handler), state); -} - -static bool anim_check_more(State *state, GList *btns) -{ - bool more = false; - for (GList *it = btns; it; it = it->next) { - Button *btn = it->data; - - if (btn->anim != NULL) { - bool layout = btn->anim->layout_func != NULL; - bool before = btn->anim->before_func != NULL; - bool after = btn->anim->after_func != NULL; - - // Remove animation if all functions finished - if (!layout && !before && !after) { - log_debug("Removing animation [type=%d, end=%ld, button=%p, state=\"%s\"]", - btn->anim->type, btn->anim->start + btn->anim->duration, btn, state->label); - - g_clear_pointer(&btn->anim, animation_destroy); - } else { - more = true; - state->relayout |= layout; - } - } - - if (!btn->simple && anim_check_more(state, CAST(btn, ButtonGroup)->children)) - more = true; - } - return more; -} - -static gboolean anim_handler(State *state) -{ - bool more = anim_check_more(state, state->btns); - log_debug("Redrawing animation [relayout=%d, more=%d, state=\"%s\"]", - state->relayout, more, state->label); - - if (state->relayout) { - draw_compute_layout(state->draw, state->win, state->btns); - state->relayout = false; - } - - draw_paint(state->draw, state->win); - - if (!more) state->anim_id = 0; - return more; -} - -// FIXME: When spamming animations there seem to be occasional -// race condition that block animations from playing -// (the animation timeout eagerly quits) -void state_request_animation(State *state) -{ - if (state->idle_id != 0) { - g_source_remove(state->idle_id); - state->idle_id = 0; - } - - if (state->anim_id != 0) return; - if (!anim_handler(state)) return; - - const int fps = 60; - state->anim_id = g_timeout_add(1000 / fps, G_SOURCE_FUNC(anim_handler), state); -} - -void state_destroy(State *state) -{ - g_free(state); -} - -// vim: ts=4 sw=4 et diff --git a/src/state.h b/src/state.h deleted file mode 100644 index 6ea331f..0000000 --- a/src/state.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef COMET_STATE_H -#define COMET_STATE_H - -#include - -#include "window.h" -#include "draw.h" -#include "button.h" - -typedef struct State State; - -struct State { - const char *label; - Window *win; - Drawer *draw; - GList *btns; - gint idle_id; - gint anim_id; - bool relayout; -}; - -State *state_create(const char *label, Window *win, Drawer *draw); - -void state_add_button(State *state, Button *btn); - -void state_remove_button(State *state, Button *btn); - -void state_order_button(State *state); - -void state_request_redraw(State *state, bool relayout); - -void state_request_animation(State *state); - -void state_destroy(State *state); - -#endif - -// vim: ts=4 sw=4 et diff --git a/src/window.c b/src/window.c deleted file mode 100644 index b3577c3..0000000 --- a/src/window.c +++ /dev/null @@ -1,306 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "window.h" -#include "log.h" - -static xcb_atom_t intern_atom(Window *win, const char *atom) -{ - xcb_generic_error_t *error; - xcb_intern_atom_cookie_t cookie = xcb_intern_atom(win->con->connection, false, strlen(atom), atom); - xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(win->con->connection, cookie, &error); - - g_assert_null(error); - xcb_atom_t id = reply->atom; - g_free(reply); - return id; -} - -static void wm_set_size(Window *win) -{ - xcb_size_hints_t hints = { 0 }; - xcb_icccm_size_hints_set_size(&hints, false, win->width, win->height); - xcb_icccm_size_hints_set_min_size(&hints, win->width, win->height); - xcb_icccm_size_hints_set_max_size(&hints, win->width, win->height); - xcb_icccm_size_hints_set_base_size(&hints, win->width, win->height); - xcb_icccm_size_hints_set_position(&hints, false, win->x, win->y); - - xcb_icccm_set_wm_size_hints(win->con->connection, win->window, XCB_ATOM_WM_NORMAL_HINTS, &hints); - log_debug("Xcb icccm size hints updated"); -} - -static void wm_set_struts(Window *win) -{ - const uint32_t end = MAX(0, win->x + win->width - 1); - - const uint32_t values[12] = { - 0, 0, win->height, 0, // left, right, top, bottom - 0, 0, 0, 0, // left y0, left y1, right y0, right y1 - win->x, end, 0, 0, // top y0, top y1, bottom y0, bottom y1 - }; - - xcb_change_property(win->con->connection, - XCB_PROP_MODE_REPLACE, - win->window, - win->con->ewmh._NET_WM_STRUT, - XCB_ATOM_CARDINAL, - 32, - 4, - values); - - xcb_change_property(win->con->connection, - XCB_PROP_MODE_REPLACE, - win->window, - win->con->ewmh._NET_WM_STRUT_PARTIAL, - XCB_ATOM_CARDINAL, - 32, - 12, - values); - - log_debug("Xcb ewmh struts updated"); -} - -static void wm_setup(Window *win) -{ - const char *title = "comet"; - xcb_icccm_set_wm_name(win->con->connection, win->window, XCB_ATOM_STRING, 8, strlen(title), title); - log_debug("Window updated title [%s]", title); - - const char class[] = "comet\0Comet"; - xcb_icccm_set_wm_class(win->con->connection, win->window, strlen(class), class); - log_debug("Window updated class [%s]", "comet\\0Comet"); - - xcb_generic_error_t *error; - xcb_intern_atom_cookie_t *ewmh_cookie = xcb_ewmh_init_atoms(win->con->connection, &win->con->ewmh); - - g_assert_true(xcb_ewmh_init_atoms_replies(&win->con->ewmh, ewmh_cookie, &error)); - g_assert_null(error); - log_debug("Xcb ewmh connected"); - - xcb_ewmh_set_wm_window_type(&win->con->ewmh, win->window, 1, &win->con->ewmh._NET_WM_WINDOW_TYPE_DOCK); - xcb_ewmh_set_wm_desktop(&win->con->ewmh, win->window, 0xFFFFFFFF); - xcb_ewmh_set_wm_pid(&win->con->ewmh, win->window, getpid()); - - xcb_atom_t state[] = { - win->con->ewmh._NET_WM_STATE_STICKY, - win->con->ewmh._NET_WM_STATE_ABOVE - }; - xcb_ewmh_set_wm_state(&win->con->ewmh, win->window, G_N_ELEMENTS(state), state); - - // TODO: These should be updated depdending on the situation! - wm_set_size(win); - wm_set_struts(win); -} - -Window *window_create(Connection *con) -{ - Window *win = g_malloc0(sizeof(Window)); - g_assert_nonnull(win); - win->con = con; - - // Set mask and params for CreateWindow - win->cw_mask = XCB_CW_BACK_PIXMAP | XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL - | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; - - uint32_t event_mask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY - | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_FOCUS_CHANGE - | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS; - // TODO: Implement hovering - //| XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_POINTER_MOTION_HINT; - - xcb_colormap_t colormap = xcb_generate_id(con->connection); - xcb_create_colormap(con->connection, XCB_COLORMAP_ALLOC_NONE, colormap, con->screen->root, con->visual_type->visual_id); - log_debug("Xcb colormap created [id=%u]", colormap); - - XCB_AUX_ADD_PARAM(&win->cw_mask, &win->cw_params, back_pixmap, XCB_NONE); - XCB_AUX_ADD_PARAM(&win->cw_mask, &win->cw_params, back_pixel, 0x00000000); - XCB_AUX_ADD_PARAM(&win->cw_mask, &win->cw_params, border_pixel, 0x00000000); - XCB_AUX_ADD_PARAM(&win->cw_mask, &win->cw_params, override_redirect, true); - XCB_AUX_ADD_PARAM(&win->cw_mask, &win->cw_params, event_mask, event_mask); - XCB_AUX_ADD_PARAM(&win->cw_mask, &win->cw_params, colormap, colormap); - - win->width = win->height = 1; - log_debug("Window temporary size [width=%d, height=%d]", win->width, win->height); - - win->x = win->y = 0; - log_debug("Window temporary position [x=%d, y=%d]", win->x, win->y); - - win->window = xcb_generate_id(con->connection); - xcb_aux_create_window(con->connection, - con->screen_depth, - win->window, - con->screen->root, - win->x, win->y, - win->width, win->height, - 0, // border - XCB_WINDOW_CLASS_COPY_FROM_PARENT, - con->visual_type->visual_id, - win->cw_mask, - &win->cw_params); - - log_debug("Xcb window created [id=%u]", win->window); - - wm_setup(win); - log_debug("Window wm options completed"); - - xcb_map_window(con->connection, win->window); - xcb_flush(con->connection); - log_debug("Xcb initialized"); - - win->surface = cairo_xcb_surface_create(con->connection, - win->window, - con->visual_type, - con->screen_size->width, - con->screen_size->height); - - g_assert_cmpint(cairo_surface_status(win->surface), ==, CAIRO_STATUS_SUCCESS); - log_debug("Cairo surface created"); - - win->cr = cairo_create(win->surface); - g_assert_cmpint(cairo_status(win->cr), ==, CAIRO_STATUS_SUCCESS); - log_debug("Cairo context created"); - - return win; -} - -cairo_t *window_get_context(Window *win) -{ - return win->cr; -} - -double window_get_scale(Window *win) -{ - const int n = 4; - return MAX(1, floor((win->con->screen_dpi / 96.0) * n) * (1.0 / n)); -} - -void window_get_screen_size(Window *win, int *width, int *height) -{ - *width = win->con->screen_size->width; - *height = win->con->screen_size->height; -} - -void window_move(Window *win, int x, int y) -{ - if (win->x == x && win->y == y) return; - - win->x = x; - win->y = y; - - const uint32_t values[] = { x, y }; - xcb_configure_window(win->con->connection, - win->window, - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, - values); - - log_debug("Window updated position [x=%d, y=%d]", win->x, win->y); -} - -static void window_paint_corners(Window *win) -{ - // TODO: Actually make this a parameter - int radius = win->height / 2; - double degree = M_PI / 180.0; - - // TODO: Check this value - int depth = 1; - - xcb_pixmap_t bitmap = xcb_generate_id(win->con->connection); - xcb_create_pixmap(win->con->connection, depth, bitmap, win->window, win->width, win->height); - log_debug("Xcb pixmap created [id=%u]", bitmap); - - cairo_surface_t *surface = cairo_xcb_surface_create_for_bitmap(win->con->connection, - win->con->screen, - bitmap, - win->width, - win->height); - - cairo_t *cr = cairo_create(surface); - - // TODO: Fix antialiasing situation - //cairo_set_antialias(cr, CAIRO_ANTIALIAS_GOOD); - - cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - - cairo_set_source_rgba(cr, 0, 0, 0, 0); - cairo_paint(cr); - - cairo_set_source_rgba(cr, 1, 1, 1, 1); - cairo_arc(cr, radius, radius, radius, 90.0 * degree, 270 * degree); - cairo_arc(cr, win->width - radius, radius, radius, 270 * degree, 450 * degree); - cairo_fill(cr); - - log_debug("Xcb shape painted"); - - cairo_show_page(cr); - cairo_destroy(cr); - cairo_surface_flush(surface); - cairo_surface_destroy(surface); - - xcb_shape_mask(win->con->connection, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, win->window, 0, 0, bitmap); - xcb_shape_select_input(win->con->connection, win->window, XCB_SHAPE_NOTIFY); - log_debug("Xcb shape mask configured"); - - xcb_free_pixmap(win->con->connection, bitmap); -} - -void window_resize(Window *win, int width, int height) -{ - if (win->width == width && win->height == height) return; - - win->width = width; - win->height = height; - - const uint32_t values[] = { width, height }; - xcb_configure_window(win->con->connection, - win->window, - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - values); - - log_debug("Window updated size [width=%d, height=%d]", win->width, win->height); - - wm_set_size(win); - - // Update shape mask - window_paint_corners(win); -} - -void window_paint_surface(Window *win, cairo_surface_t *surface, int width, int height) -{ - cairo_xcb_surface_set_size(win->surface, width, height); - xcb_clear_area(win->con->connection, false, win->window, 0, 0, 0, 0); - - cairo_save(win->cr); - cairo_set_source_surface(win->cr, surface, 0, 0); - - cairo_paint(win->cr); - cairo_show_page(win->cr); - - cairo_surface_flush(win->surface); - cairo_restore(win->cr); - - xcb_circulate_window(win->con->connection, XCB_CIRCULATE_RAISE_LOWEST, win->window); - xcb_flush(win->con->connection); -} - -void window_destroy(Window *win) -{ - cairo_destroy(win->cr); - cairo_surface_destroy(win->surface); - g_free(win); -} - -// vim: ts=4 sw=4 et diff --git a/src/window.h b/src/window.h deleted file mode 100644 index ea1209a..0000000 --- a/src/window.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef COMET_WINDOW_H -#define COMET_WINDOW_H - -#include -#include -#include - -#include "connect.h" - -typedef struct Window Window; - -struct Window { - Connection *con; - xcb_drawable_t window; - uint32_t cw_mask; - xcb_params_cw_t cw_params; - cairo_surface_t *surface; - cairo_t *cr; - int x, y; - int width, height; -}; - -Window *window_create(Connection *con); - -cairo_t *window_get_context(Window *win); - -double window_get_scale(Window *win); - -void window_get_screen_size(Window *win, int *width, int *height); - -void window_move(Window *win, int x, int y); - -void window_resize(Window *win, int width, int height); - -void window_paint_surface(Window *win, cairo_surface_t *surface, int width, int height); - -void window_destroy(Window *win); - -#endif - -// vim: ts=4 sw=4 et -- cgit v1.2.3