initial commit
[vkray] / src / main_x11.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <X11/Xlib.h>
4 #include <X11/Xutil.h>
5 #include "app.h"
6
7 static Window create_window(const char *title, int xsz, int ysz);
8 static void handle_event(XEvent *ev);
9 static int translate_keysym(KeySym sym);
10
11 static Display *dpy;
12 static Window win, root_win;
13 static int xscr;
14 static Atom xa_wm_proto, xa_wm_del_win;
15 static int reshape_pending, quit;
16 static int win_width, win_height, win_mapped;
17
18 int main(int argc, char **argv)
19 {
20         XEvent ev;
21
22         if(!(dpy = XOpenDisplay(0))) {
23                 fprintf(stderr, "failed to connect to the X server\n");
24                 return 1;
25         }
26         xscr = DefaultScreen(dpy);
27         root_win = RootWindow(dpy, xscr);
28         xa_wm_proto = XInternAtom(dpy, "WM_PROTOCOLS", False);
29         xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
30
31         if(!(win = create_window("vkray", 1280, 800))) {
32                 return 1;
33         }
34
35         for(;;) {
36                 while(XPending(dpy)) {
37                         XNextEvent(dpy, &ev);
38                         handle_event(&ev);
39                         if(quit) goto end;
40                 }
41
42                 if(reshape_pending) {
43                         app_reshape(win_width, win_height);
44                 }
45                 app_display();
46         }
47
48 end:
49         XDestroyWindow(dpy, win);
50         XCloseDisplay(dpy);
51         return 0;
52 }
53
54 void app_quit(void)
55 {
56         quit = 1;
57 }
58
59 void app_swap_buffers(void)
60 {
61 }
62
63 static Window create_window(const char *title, int xsz, int ysz)
64 {
65         Window win;
66         XVisualInfo vinf;
67         XTextProperty txprop;
68         XSetWindowAttributes xattr;
69
70         if(!XMatchVisualInfo(dpy, xscr, 24, TrueColor, &vinf)) {
71                 fprintf(stderr, "no suitable visual found\n");
72                 return 0;
73         }
74
75         xattr.background_pixel = BlackPixel(dpy, xscr);
76         xattr.colormap = XCreateColormap(dpy, root_win, vinf.visual, AllocNone);
77
78         if(!(win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, 24, InputOutput,
79                                         vinf.visual, CWBackPixel | CWColormap, &xattr))) {
80                 fprintf(stderr, "failed to create window\n");
81                 return 0;
82         }
83
84         XSelectInput(dpy, win, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
85                         ButtonMotionMask | ExposureMask | StructureNotifyMask);
86
87         XSetWMProtocols(dpy, win, &xa_wm_del_win, 1);
88
89         if(XStringListToTextProperty((char**)&title, 1, &txprop)) {
90                 XSetWMName(dpy, win, &txprop);
91                 XSetWMIconName(dpy, win, &txprop);
92                 XFree(txprop.value);
93         }
94
95         XMapWindow(dpy, win);
96
97         reshape_pending = 1;
98         return win;
99 }
100
101 static void handle_event(XEvent *ev)
102 {
103         KeySym sym;
104         int key;
105
106         switch(ev->type) {
107         case MapNotify:
108                 win_mapped = 1;
109                 break;
110         case UnmapNotify:
111                 win_mapped = 0;
112                 break;
113
114         case ConfigureNotify:
115                 if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) {
116                         win_width = ev->xconfigure.width;
117                         win_height = ev->xconfigure.height;
118                         reshape_pending = 1;
119                 }
120                 break;
121
122         case KeyPress:
123         case KeyRelease:
124                 if((sym = XLookupKeysym(&ev->xkey, 0)) && (key = translate_keysym(sym))) {
125                         app_keyboard(key, ev->type == KeyPress);
126                 }
127                 break;
128
129         case ButtonPress:
130         case ButtonRelease:
131                 app_mouse(ev->xbutton.button - Button1, ev->type == ButtonPress, ev->xbutton.x, ev->xbutton.y);
132                 break;
133
134         case ClientMessage:
135                 if(ev->xclient.message_type == xa_wm_proto) {
136                         if(ev->xclient.data.l[0] == xa_wm_del_win) {
137                                 quit = 1;
138                         }
139                 }
140                 break;
141
142         default:
143                 break;
144         }
145 }
146
147 static int translate_keysym(KeySym sym)
148 {
149         if(sym < 128) return sym;
150
151         switch(sym) {
152         case XK_Escape: return 27;
153         case XK_Tab: return '\t';
154         case XK_Return: return '\n';
155         case XK_BackSpace: return '\b';
156         case XK_Delete: return KEY_DEL;
157         case XK_Home: return KEY_HOME;
158         case XK_End: return KEY_END;
159         case XK_Page_Up: return KEY_PGUP;
160         case XK_Page_Down: return KEY_PGDOWN;
161         default:
162                 break;
163         }
164
165         return 0;
166 }