Blob Blame Raw

#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);
}