Skip to content

Instantly share code, notes, and snippets.

@bynect
Created July 16, 2025 19:14
Show Gist options
  • Save bynect/58448cb94ca6c3c596525b916d7c4993 to your computer and use it in GitHub Desktop.
Save bynect/58448cb94ca6c3c596525b916d7c4993 to your computer and use it in GitHub Desktop.
Simple bar for Xorg
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_ewmh.h>
#include <cairo.h>
#include <cairo-xcb.h>
#include <math.h>
typedef struct {
int width, height;
int x, y;
int screen_n;
xcb_screen_t *scr;
xcb_connection_t *connection;
xcb_ewmh_connection_t ewmh;
xcb_drawable_t win;
unsigned int white;
xcb_visualtype_t *visual_type;
cairo_t *cr;
cairo_surface_t *surface;
} Bar;
#define MARGIN_LEFT 0.5
#define MARGIN_RIGHT 0.5
#define MARGIN_TOP 0.2
#define HEIGHT_PERC 2
#define CALC_PERC(tot, perc) (((tot)*(perc))/100)
void bar_create(Bar *bar) {
xcb_screen_iterator_t iter;
xcb_depth_iterator_t depth_iter;
bar->connection = xcb_connect(NULL, &bar->screen_n);
iter = xcb_setup_roots_iterator(xcb_get_setup(bar->connection));
for (; iter.rem; --bar->screen_n, xcb_screen_next(&iter)) {
if (bar->screen_n == 0) {
bar->scr = iter.data;
break;
}
}
printf("screen.width: %d, screen.height: %d\n", bar->scr->width_in_pixels, bar->scr->height_in_pixels);
bar->width = bar->scr->width_in_pixels \
- CALC_PERC(bar->scr->width_in_pixels, MARGIN_LEFT) \
- CALC_PERC(bar->scr->width_in_pixels, MARGIN_RIGHT);
bar->height = CALC_PERC(bar->scr->height_in_pixels, HEIGHT_PERC);
printf("bar.width: %d, bar.height: %d\n", bar->width, bar->height);
bar->x = CALC_PERC(bar->scr->width_in_pixels, MARGIN_LEFT);
bar->y = CALC_PERC(bar->scr->height_in_pixels, MARGIN_TOP);
printf("bar.x: %d, bar.y: %d\n", bar->x, bar->y);
bar->win = xcb_generate_id(bar->connection);
bar->white = bar->scr->black_pixel;
xcb_create_window(bar->connection, XCB_COPY_FROM_PARENT,
bar->win, bar->scr->root,
bar->x, bar->y,
bar->width, bar->height,
5,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
bar->scr->root_visual,
XCB_CW_BACK_PIXEL,
&bar->white);
xcb_map_window(bar->connection, bar->win);
xcb_flush(bar->connection);
xcb_size_hints_t hints;
xcb_icccm_size_hints_set_min_size(&hints, bar->width, bar->height);
xcb_icccm_size_hints_set_max_size(&hints, bar->width, bar->height);
xcb_icccm_size_hints_set_max_size(&hints, bar->width, bar->height);
xcb_icccm_size_hints_set_position(&hints, 1, bar->x, bar->y);
xcb_icccm_set_wm_size_hints(bar->connection, bar->win, XCB_ATOM_WM_NORMAL_HINTS, &hints);
xcb_icccm_set_wm_name(bar->connection, bar->win, XCB_ATOM_STRING, 8, strlen("bar"), "bar");
xcb_ewmh_init_atoms(bar->connection, &bar->ewmh);
xcb_ewmh_set_wm_window_type(&bar->ewmh, bar->win, 1, &bar->ewmh._NET_WM_WINDOW_TYPE_DOCK);
xcb_flush(bar->connection);
depth_iter = xcb_screen_allowed_depths_iterator(bar->scr);
for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
xcb_visualtype_iterator_t visual_iter;
visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
if (bar->scr->root_visual == visual_iter.data->visual_id) {
bar->visual_type = visual_iter.data;
goto visual_found;
}
}
}
visual_found: ;
bar->surface = cairo_xcb_surface_create(bar->connection, bar->win, bar->visual_type, bar->width, bar->height);
bar->cr = cairo_create(bar->surface);
//cairo_select_font_face(bar->cr, "Hack", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
//cairo_set_font_size(bar->cr, 12.0);
//cairo_set_source_rgb(bar->cr, 1.0, 1.0, 1.0);
//cairo_move_to(bar->cr, 10.0, 50.0);
//cairo_show_text(bar->cr, "Hello, world");
double x = 0;
double y = 0;
double width = bar->width;
double height = bar->height;
double aspect = 1.0;
double corner_radius = height / 10;
double radius = corner_radius / aspect;
double degrees = M_PI / 180.0;
cairo_new_sub_path(bar->cr);
cairo_arc(bar->cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
cairo_arc(bar->cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
cairo_arc(bar->cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
cairo_arc(bar->cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
cairo_close_path(bar->cr);
cairo_set_source_rgb(bar->cr, 0.5, 0.5, 0.5);
cairo_fill_preserve(bar->cr);
cairo_set_source_rgba(bar->cr, 0.5, 0, 0, 0.5);
cairo_set_line_width(bar->cr, 10.0);
cairo_stroke(bar->cr);
cairo_surface_flush(bar->surface);
xcb_flush(bar->connection);
}
void bar_destroy(Bar *bar) {
cairo_destroy(bar->cr);
cairo_surface_destroy(bar->surface);
xcb_disconnect(bar->connection);
}
static volatile int keep_going = 1;
void handle_sig(int no)
{
keep_going = 0;
}
int main() {
Bar bar;
bar_create(&bar);
signal(SIGINT, handle_sig);
while (keep_going) {
sleep(1);
printf("heartbeat elapsed\n");
}
bar_destroy(&bar);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment