#include "xmain.h"
Display *dpy;
int screen;
Window win;
Drawable drw;
Visual *visual;
GC gc;
int winW, winH;
static int dblbuf;
int run;
int exitCode;
void stop(int code) {
if (!exitCode)
exitCode = code;
LOGDBG("stop: code %d (%d)", code, exitCode);
run = 0;
}
int main() {
LOGDBG("main: open dysplay");
dpy = XOpenDisplay(NULL);
if (!dpy)
return LOGERR("init: cannot connect to xcb"), 1;
LOGDBG("main: get screen");
screen = DefaultScreen(dpy);
LOGDBG("main: search 24 bit visual");
XVisualInfo vi = {};
if (!XMatchVisualInfo(dpy, screen, 24, TrueColor, &vi))
return LOGERR("main: cannot get 24 bit visual"), XCloseDisplay(dpy), 1;
LOGDBG("main: query double buffering extension");
int major, minor;
if (XdbeQueryExtension(dpy, &major, &minor)) {
LOGDBG("main: XdbeGetVisualInfo");
int numScreens = 1;
Drawable roots[] = { DefaultRootWindow(dpy) };
XdbeScreenVisualInfo *info = XdbeGetVisualInfo(dpy, roots, &numScreens);
if (info && numScreens > 0 && info->count > 0) {
XVisualInfo visinfo = {
.visualid = info->visinfo[0].visual,
.screen = screen,
.depth = 24 };
LOGDBG("main: XGetVisualInfo for double buffering");
int matches;
XVisualInfo *match = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask | VisualDepthMask, &visinfo, &matches);
if (match && matches > 0) {
LOGDBG("main: double buffering is supported");
dblbuf = 1;
vi = *match;
}
}
}
LOGDBG("main: get root window");
Window root = RootWindow(dpy, screen);
LOGDBG("main: create window");
XSetWindowAttributes attr = {};
attr.colormap = XCreateColormap(dpy, XDefaultRootWindow(dpy), vi.visual, AllocNone);
drw = win = XCreateWindow(
dpy, root, // display and parent window
10, 10, 512, 512, 0, // position, size and border width
24, // depth
CopyFromParent,//InputOutput, // class
vi.visual, // visual
0,//CWBackPixel | CWColormap | CWBorderPixel, // attributes mask
&attr ); // attributes
if (dblbuf) {
LOGDBG("main: allocate back buffer");
drw = XdbeAllocateBackBufferName(dpy, win, XdbeUndefined);
if (!drw) {
LOGWRN("main: cannot allocate backbuffer");
drw = win;
}
}
LOGDBG("main: select input");
XSelectInput(
dpy, win,
StructureNotifyMask
| ExposureMask
| ButtonPressMask
| ButtonReleaseMask );
LOGDBG("main: subscribe to windows delete message from window manager");
Atom aWmDel = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(dpy, win, &aWmDel, 1);
LOGDBG("main: map window");
XMapWindow(dpy, win);
LOGDBG("main: get window attributes");
XWindowAttributes wa = {};
if (!XGetWindowAttributes(dpy, win, &wa))
return LOGERR("main: cannot get window attributes"), XCloseDisplay(dpy), 1;
visual = wa.visual;
winW = wa.width;
winH = wa.height;
LOGDBG("main: greate gc");
gc = XCreateGC(dpy, drw, 0, NULL);
XFlush(dpy);
LOGDBG("main: init");
run = 1;
if (!init())
stop(1);
LOGDBG("main: start event loop");
XEvent event = {};
int redrawRequested = 0;
while(run) {
XNextEvent(dpy, &event);
int forceDraw = 0;
switch(event.type) {
case Expose:
if (!event.xexpose.count) {
LOGDBG( "main: event: expose: x=%d, y=%d, w=%d, h=%d",
event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height );
redrawRequested = 1;
}
break;
case ConfigureNotify:
if ( event.xconfigure.width
&& event.xconfigure.height
&& ( winW != event.xconfigure.width
|| winH != event.xconfigure.height ))
{
LOGDBG( "main: event: moved: x=%d y=%d w=%d, h=%d",
event.xconfigure.x, event.xconfigure.y, event.xconfigure.width, event.xconfigure.height );
winW = event.xconfigure.width;
winH = event.xconfigure.height;
resize();
redrawRequested = 1;
}
break;
case ButtonPress:
if (event.xbutton.button == 1) {
LOGDBG("main: event: mouse down: x=%d, y=%d", event.xbutton.x, event.xbutton.y);
mouseDown(event.xbutton.x, event.xbutton.y);
forceDraw = 1;
}
break;
case ButtonRelease:
if (event.xbutton.button == 1) {
LOGDBG("main: event: mouse up: x=%d, y=%d", event.xbutton.x, event.xbutton.y);
mouseUp();
forceDraw = 1;
}
break;
case ClientMessage:
if (event.xclient.data.l[0] == aWmDel) {
LOGDBG("main: event: delete window event");
stop(0);
}
break;
}
if (forceDraw || (redrawRequested && !XEventsQueued(dpy, QueuedAfterFlush))) {
if (winW > 0 && winH > 0) {
LOGDBG("main: draw");
draw();
if (dblbuf) {
XdbeSwapInfo swapInfo = {
.swap_window = win,
.swap_action = XdbeUndefined };
if (!XdbeSwapBuffers(dpy, &swapInfo, 1))
LOGWRN("main: cannot swap buffers");
}
XFlush(dpy);
}
redrawRequested = 0;
}
}
XFlush(dpy);
LOGDBG("main: deinit");
deinit();
LOGDBG("main: close display");
XCloseDisplay(dpy);
return exitCode;
}