Created
December 10, 2021 07:05
-
-
Save matyklug18/83a7fe6fb2805c47cf929cf82ce54110 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
//xlib, for interacting with the X server | |
#include <X11/Xatom.h> | |
//cairo, for drawing | |
#include <cairo.h> | |
#include <cairo-xlib.h> | |
#include "app.h" | |
#include "../config.h" | |
//initialize the app, taking the initial size of the window as a parameter | |
main_window init(const app_params params) { | |
//the display, representing the connection to X | |
Display *dsp; | |
//the window, representing the X window for this app | |
Drawable da; | |
//the screen, representing the monitor (?) | |
int screen; | |
//the cairo surface, used when drawing | |
cairo_surface_t *sfc; | |
XInitThreads(); | |
//open the display | |
dsp = XOpenDisplay(NULL); | |
//set the screen to the default screen (?) | |
screen = DefaultScreen(dsp); | |
//create the window, telling X it exists without showing it | |
da = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp), 0, 0, DisplayWidth(dsp, screen), params.height, 0, 0, 0); | |
sleep(0.1); | |
//tell xorg, that we want mouse button events, resize events and repaint needed events (?). | |
XSelectInput(dsp, da, ButtonPressMask | StructureNotifyMask | ExposureMask); | |
//make it into a bar/dock, by setting the "_NET_WM_WINDOW_TYPE" to "_NET_WM_WINDOW_TYPE_DOCK" | |
Atom type = XInternAtom(dsp, "_NET_WM_WINDOW_TYPE", False); | |
long value = XInternAtom(dsp, "_NET_WM_WINDOW_TYPE_DOCK", False); | |
XChangeProperty(dsp, da, type, | |
XA_ATOM, 32, PropModeReplace, (unsigned char *) &value, 1); | |
//move the bar to the bottom of the screen | |
#if POSITION==BOTTOM | |
XMoveWindow(dsp, da, 0, DisplayHeight(dsp, screen)); | |
#elif POSITION=TOP | |
XMoveWindow(dsp, da, 0, 0); | |
#endif | |
//actually show the window | |
XMapWindow(dsp, da); | |
//create the cairo surface, so we can draw to the window | |
sfc = cairo_xlib_surface_create(dsp, da, DefaultVisual(dsp, screen), DisplayWidth(dsp, screen), params.height); | |
sleep(0.1); | |
//resize the surface (?) | |
cairo_xlib_surface_set_size(sfc, DisplayWidth(dsp, screen), params.height); | |
//create the cairo type, which is usually used when drawing | |
cairo_t* ctx = cairo_create(sfc); | |
//make the struct | |
main_window win_return = (main_window) {ctx, sfc, da, dsp}; | |
win_return.font_pos = params.font_pos; | |
win_return.font_size = params.font_size; | |
return win_return; | |
} | |
//the paint function, paints on the window using the cairo variables | |
void paint(main_window* app, const char* text_in) { | |
// (?) | |
cairo_push_group(app->cairo); | |
//set the background color to a dark color (#282a36) | |
cairo_set_source_rgb(app->cairo, COLOR); | |
//paint the background with the color | |
cairo_paint(app->cairo); | |
//set the drawing location to (50, 32) | |
cairo_move_to(app->cairo, app->font_size / 2, app->font_pos); | |
//select the font | |
cairo_select_font_face(app->cairo, "Hack Nerd Font Mono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); | |
//set the size of the font | |
cairo_set_font_size(app->cairo, app->font_size); | |
//change the color from black to a light color (#f8f8f2) | |
cairo_set_source_rgb(app->cairo, 0.973, 0.973, 0.949); | |
//render the text in the *text* variable | |
cairo_show_text(app->cairo, text_in); | |
// (?) | |
cairo_pop_group_to_source(app->cairo); | |
cairo_paint(app->cairo); | |
//update the cairo surface of the window, then the window itself | |
cairo_surface_flush(app->cairo_surface); | |
XFlush(app->display); | |
} | |
//when the window is closed or the app crashed, destroy cairo and close the connection to X. | |
//if this isnt done, we get an error. | |
void exit_app(main_window* app) { | |
cairo_destroy(app->cairo); | |
XCloseDisplay(app->display); | |
} | |
char out[256]; | |
//update the text && repaint | |
void update_text(main_window* app) { | |
//memset(out, 0, 256); | |
app->text_update(out); | |
paint(app, out); | |
} | |
//a function that runs asynchronously from the main thread, managing the functionality of the app | |
//modifies the text painted in paint() to the output of the update_text function. | |
void* update(void* inp_app) { | |
main_window* app = (main_window*) inp_app; | |
while(True) { | |
update_text(app); | |
sleep(app->interval); | |
} | |
return NULL; | |
} | |
//simple function to resize the cairo surface && repaint it | |
void resize(main_window* app, const unsigned int width, const unsigned int height) { | |
//resize the cairo surface | |
cairo_xlib_surface_set_size(app->cairo_surface, width, height); | |
//repaint the app | |
paint(app, out); | |
} | |
//event loop | |
void* event_loop(void* inp_app) { | |
main_window* app = (main_window*) inp_app; | |
//the event loop. when an event is recieved, its managed in one of the IFs inside | |
for(;;) { | |
//declare the event variable | |
XEvent e; | |
//fill the event variable with the next event | |
//wait if there is no next event | |
XNextEvent(app->display, &e); | |
if(e.type == MapNotify) { | |
} | |
//if the event recieved was ButtonPress, which is recieved when a mouse button is pressed... | |
if(e.type == ButtonPress) { | |
//get the events data from xbutton, | |
//which is the data for the event, since the type is ButtonPress. | |
XButtonEvent ev = e.xbutton; | |
printf("%d %d\n", ev.x, ev.y); | |
fflush(stdout); | |
} | |
//if the event was ConfigureNotify, which is usually reported when the window, for example, changes size... | |
if(e.type == ConfigureNotify) { | |
//call the resize() function | |
resize(app, e.xconfigure.width, e.xconfigure.height); | |
} | |
//if the event was ConfigureNotify, which is usually reported, when the window needs redrawing, because, for example, new area was exposed. | |
if(e.type == Expose) { | |
paint(app, out); | |
} | |
} | |
//because the infinite loop exited, close the app | |
exit_app(app); | |
return NULL; | |
} | |
void start(main_window* app, void (*text_update)(char*), float interval) { | |
//set few basic vars | |
app->text_update = text_update; | |
app->interval = interval; | |
//paint the app before any events occur, so its not just empty (not sure if required) | |
paint(app, ""); | |
//start the update loop | |
pthread_t update_thread_id; | |
pthread_create(&update_thread_id, NULL, update, app); | |
//start the event loop | |
pthread_t event_thread_id; | |
pthread_create(&event_thread_id, NULL, event_loop, app); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -------------- | |
// TextBar v0.1.0 | |
// -------------- | |
// Usage: <text generator> | textbar | <input handler> | |
// | |
// Shows the last two lines from stdin on a bar | |
// Every odd line is on the left | |
// Every even line is on the right | |
// Updating one side at a time is not possible | |
// Line buffered | |
// Prints all mouse clicks to stdout | |
// In the format of `X Y` (without the '`') | |
#include <pthread.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <stdbool.h> | |
#include <X11/Xlib.h> | |
#include <X11/Xatom.h> | |
#include <X11/Xutil.h> | |
#include <cairo.h> | |
#include <cairo-xlib.h> | |
Display* dpy; | |
Window win; | |
cairo_surface_t* sfc; | |
cairo_t* ctx; | |
char text[256] = {0}; | |
char text_other[256] = {0}; | |
int width; | |
// CONFIG | |
#define POSITION 0 // 1 means top, 0 means bottom. Blame C. | |
#define FONT "Fira Code" | |
#define FONT_SIZE 16 | |
#define BG_COLOR 0.157, 0.165, 0.212, 0.950 | |
#define FG_COLOR 0.973, 0.973, 0.949, 1.000 | |
// COMPUTATION | |
#define HEIGHT FONT_SIZE*2 | |
#define FONT_POS FONT_SIZE*1.4 | |
void init() { | |
dpy = XOpenDisplay(NULL); | |
int screen = DefaultScreen(dpy); | |
width = DisplayWidth(dpy, screen); | |
XVisualInfo visualinfo; | |
XMatchVisualInfo(dpy, screen, 32, TrueColor, &visualinfo); | |
GC gc; | |
XSetWindowAttributes attr; | |
attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), visualinfo.visual, AllocNone); | |
attr.background_pixel = 0; | |
attr.border_pixel = 0; | |
win = XCreateWindow(dpy, DefaultRootWindow(dpy), | |
0, 0, width, HEIGHT, | |
0, visualinfo.depth, InputOutput, visualinfo.visual, CWBackPixel | CWColormap | CWBorderPixel, &attr); | |
gc = XCreateGC(dpy, win, 0, 0); | |
XSync(dpy, False); | |
Atom wm_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); | |
long wm_type_dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); | |
XChangeProperty(dpy, win, wm_type, | |
XA_ATOM, 32, PropModeReplace, (unsigned char *) &wm_type_dock, 1); | |
Atom wm_strut = XInternAtom(dpy, "_NET_WM_STRUT", False); | |
#if POSITION == 0 | |
XMoveWindow(dpy, win, 0, DisplayHeight(dpy, screen)); | |
uint32_t strut[4] = {0, 0, 0, HEIGHT}; | |
XChangeProperty(dpy, win, wm_strut, | |
XA_CARDINAL, 32, PropModeReplace, (unsigned char *) strut, 4); | |
#elif POSITION == 1 | |
uint32_t strut[4] = {0, 0, HEIGHT, 0}; | |
XChangeProperty(dpy, win, wm_strut, | |
XA_CARDINAL, 32, PropModeReplace, (unsigned char *) strut, 4); | |
XMoveWindow(dpy, win, 0, 0); | |
#endif | |
XMapWindow(dpy, win); | |
sfc = cairo_xlib_surface_create(dpy, win, visualinfo.visual, DisplayWidth(dpy, screen), HEIGHT); | |
ctx = cairo_create(sfc); | |
} | |
pthread_mutex_t do_paint; | |
void paint(Display* dpy) { | |
if(!pthread_mutex_trylock(&do_paint)) { | |
XClearWindow(dpy, win); | |
cairo_push_group(ctx); | |
cairo_set_source_rgba(ctx, BG_COLOR); | |
cairo_paint(ctx); | |
cairo_move_to(ctx, FONT_SIZE / 2, FONT_POS); | |
cairo_select_font_face(ctx, FONT, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); | |
cairo_set_font_size(ctx, FONT_SIZE); | |
cairo_set_source_rgba(ctx, FG_COLOR); | |
cairo_show_text(ctx, text); | |
cairo_text_extents_t extents; | |
cairo_text_extents(ctx, text_other, &extents); | |
cairo_move_to(ctx, (width-extents.width) - FONT_SIZE / 2, FONT_POS); | |
cairo_show_text(ctx, text_other); | |
cairo_pop_group_to_source(ctx); | |
cairo_paint(ctx); | |
cairo_surface_flush(sfc); | |
XFlush(dpy); | |
pthread_mutex_unlock(&do_paint); | |
} | |
} | |
void update() { | |
while(1) { | |
fgets(text, 256, stdin); | |
fgets(text_other, 256, stdin); | |
text[strcspn(text, "\n")] = 0; | |
text_other[strcspn(text_other, "\n")] = 0; | |
paint(dpy); | |
} | |
} | |
void x_loop() { | |
Display* x_dpy = XOpenDisplay(NULL); | |
XSelectInput(x_dpy, win, ButtonPressMask | StructureNotifyMask | ExposureMask); | |
while(1) { | |
XEvent e; | |
XNextEvent(x_dpy, &e); | |
if(e.type == ButtonPress) { | |
printf("%d %d\n", e.xbutton.x, e.xbutton.y); | |
fflush(stdout); | |
} else | |
if(e.type == ConfigureNotify) { | |
cairo_xlib_surface_set_size(sfc, e.xconfigure.width, e.xconfigure.height); | |
} else | |
if(e.type == Expose) { | |
paint(x_dpy); | |
} | |
} | |
} | |
int main() { | |
init(); | |
pthread_mutex_init(&do_paint, NULL); | |
pthread_t x_thread_id; | |
pthread_create(&x_thread_id, NULL, &x_loop, NULL); | |
update(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment