#include "app.h"
int appInit(App *app) {
LOGDBG("app: init");
LOGDBG("app: init: connect to xcb");
app->xcb = xcb_connect(NULL, NULL);
if (!app->xcb)
return LOGERR("app: init: cannot connect to xcb");
LOGDBG("app: init: get screen");
app->screen = xcb_setup_roots_iterator(xcb_get_setup(app->xcb)).data;
if (app->screen) {
LOGDBG("app: init: create window");
app->w = 300;
app->h = 150;
app->win = xcb_generate_id(app->xcb);
uint32_t mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
uint32_t values[] = {
1, // override redirect
XCB_EVENT_MASK_EXPOSURE // event mask
| XCB_EVENT_MASK_STRUCTURE_NOTIFY
| XCB_EVENT_MASK_BUTTON_PRESS
| XCB_EVENT_MASK_BUTTON_RELEASE };
xcb_create_window(
app->xcb, // connection
XCB_COPY_FROM_PARENT, // depth (same as root)
app->win, // window id
app->screen->root, // parent window
0, 0, // x, y
app->w, app->h, // width, height
10, // border_width
XCB_WINDOW_CLASS_INPUT_OUTPUT, // class
app->screen->root_visual, // visual
mask, // additional options mask
values ); // additional options
uint32_t hints[9] = {
1, // mask for input hints
0, // value of input hint
};
xcb_change_property_checked(
app->xcb,
XCB_PROP_MODE_REPLACE,
app->win,
XCB_ATOM_WM_HINTS,
XCB_ATOM_WM_HINTS,
32,
sizeof(hints)/sizeof(hints[0]), hints );
// init submodules
if (graphInit(&app->graph, app)) {
if (inputInit(&app->input, app)) {
if (keyboardInit(&app->keyboard, app)) {
return 1;
}
inputDeinit(&app->input);
}
graphDeinit(&app->graph);
}
} else {
LOGERR("app: init: no screen found");
}
xcb_disconnect(app->xcb);
return 0;
}
void appDeinit(App *app) {
LOGDBG("app: deinit");
keyboardDeinit(&app->keyboard);
inputDeinit(&app->input);
graphDeinit(&app->graph);
xcb_disconnect(app->xcb);
}
int appRun(App *app) {
LOGDBG("app: run");
LOGDBG("app: run: resize window");
app->w = app->keyboard.w;
app->h = app->keyboard.h;
uint32_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
uint32_t values[] = { app->w, app->h };
xcb_configure_window(app->xcb, app->win, mask, values);
LOGDBG("app: run: show window");
xcb_map_window(app->xcb, app->win);
xcb_flush(app->xcb);
LOGDBG("app: run: event loop");
xcb_generic_event_t *event;
while ((event = xcb_wait_for_event(app->xcb))) {
switch (event->response_type & ~0x80) {
case XCB_EXPOSE: {
xcb_expose_event_t *e = (xcb_expose_event_t*)event;
LOGDBG("app: expose: x=%d, y=%d, w=%d, h=%d", e->x, e->y, e->width, e->height);
appInvalidateRect(app, e->x, e->y, e->width, e->height);
break;
}
case XCB_CONFIGURE_NOTIFY: {
xcb_configure_notify_event_t *e = (xcb_configure_notify_event_t*)event;
if (e->width && e->height && app->w != e->width && app->h != e->height) {
LOGDBG("app: resize: w=%d, h=%d", e->width, e->height);
app->w = e->width;
app->h = e->height;
graphResize(&app->graph);
}
break;
}
case XCB_BUTTON_PRESS: {
xcb_button_press_event_t *e = (xcb_button_press_event_t*)event;
if (e->detail == 1) {
LOGDBG("app: mouse down: x=%d, y=%d", e->event_x, e->event_y);
keyboardMouseDown(&app->keyboard, e->event_x, e->event_y);
}
break;
}
case XCB_BUTTON_RELEASE: {
xcb_button_press_event_t *e = (xcb_button_press_event_t*)event;
if (e->detail == 1) {
LOGDBG("app: mouse up");
keyboardMouseUp(&app->keyboard);
}
break;
}
default:
break;
}
free(event);
if (app->irw > 0 && app->irh > 0) {
LOGDBG("app: draw: x=%d, y=%d, w=%d, h=%d", app->irx, app->iry, app->irw, app->irh);
graphDrawBackgound(&app->graph, app->irx, app->iry, app->irw, app->irh);
keyboardDraw(&app->keyboard, app->irx, app->iry, app->irw, app->irh);
xcb_flush(app->xcb);
app->irw = 0;
}
}
LOGDBG("app: run: done");
return 1;
}
void appInvalidateRect(App *app, int x, int y, int w, int h) {
LOGDBG("app: invalidate rect: x=%d, y=%d, w=%d, h=%d", x, y, w, h);
rectIntersect(&x, &y, &w, &h, 0, 0, app->w, app->h);
rectMerge(&app->irx, &app->iry, &app->irw, &app->irh, x, y, w, h);
}