1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5
6 #include "x11.h"
7 #include "util.h"
8
9 #include "Game.h"
10 #include "UI.h"
11
12 static int in_popup;
13
14 static const char *pictdir;
15
16 static Display *display;
17 static XtAppContext app;
18 static Drawable window, rootwindow;
19 static Colormap colormap;
20 static int depth;
21 static XColor white, black;
22 static Pixmap offscreen;
23 static XtIntervalId timer;
24 static GC stdgc, whitegc;
25 static int screensize;
26
27 static Widget toplevel, field;
28
29 /*
30 * Callback functions
31 */
32
33 static void
popdown(Widget w,XtPointer client_data,XtPointer call_data)34 popdown(Widget w, XtPointer client_data, XtPointer call_data) {
35 UNUSED(w);
36 UNUSED(client_data);
37 UNUSED(call_data);
38 in_popup = 0;
39 }
40
41 void
x11_popup(Widget dialog)42 x11_popup(Widget dialog) {
43 Window temp;
44 int tx, ty;
45 XWindowAttributes tattr, pattr;
46 int px, py;
47
48 XtRealizeWidget(XtParent(dialog));
49 XtSetMappedWhenManaged(XtParent(dialog), FALSE);
50 XtManageChild(dialog);
51 in_popup = 1;
52
53 XTranslateCoordinates(display, XtWindow(toplevel), rootwindow,
54 0, 0, &tx, &ty, &temp);
55 XGetWindowAttributes(display, XtWindow(toplevel), &tattr);
56 XGetWindowAttributes(display, XtWindow(dialog), &pattr);
57 px = tx + (tattr.width - pattr.width) / 2;
58 py = ty + (tattr.height - pattr.height) / 2;
59 XtVaSetValues(XtParent(dialog), XtNx, px, XtNy, py, NULL);
60
61 XtAddCallback(XtParent(dialog), XtNpopdownCallback,
62 (XtCallbackProc) popdown, NULL);
63 XtPopup(XtParent(dialog), XtGrabExclusive);
64 while (in_popup || XtAppPending(app))
65 XtAppProcessEvent(app, XtIMXEvent);
66 }
67
68 /*
69 * Event handlers
70 */
71
72 static void
leave_window(Widget w,XtPointer client_data,XEvent * event,Boolean * b)73 leave_window(Widget w, XtPointer client_data, XEvent *event, Boolean *b) {
74 UNUSED(w);
75 UNUSED(client_data);
76 UNUSED(event);
77 UNUSED(b);
78
79 UI_pause_game();
80 }
81
82 static void
enter_window(Widget w,XtPointer client_data,XEvent * event,Boolean * b)83 enter_window(Widget w, XtPointer client_data, XEvent *event, Boolean *b) {
84 UNUSED(w);
85 UNUSED(client_data);
86 UNUSED(event);
87 UNUSED(b);
88
89 UI_resume_game();
90 }
91
92 static void
redraw_window(Widget w,XtPointer client_data,XEvent * event,Boolean * b)93 redraw_window(Widget w, XtPointer client_data, XEvent *event, Boolean *b) {
94 UNUSED(w);
95 UNUSED(client_data);
96 UNUSED(event);
97 UNUSED(b);
98
99 UI_refresh();
100 }
101
102 static void
button_press(Widget w,XtPointer data,XEvent * event,Boolean * b)103 button_press(Widget w, XtPointer data, XEvent *event, Boolean *b) {
104 XButtonEvent *buttonevent = (XButtonEvent *) event;
105
106 UNUSED(w);
107 UNUSED(data);
108 UNUSED(b);
109
110 Game_button_press(buttonevent->x, buttonevent->y);
111 }
112
113 static void
button_release(Widget w,XtPointer data,XEvent * event,Boolean * b)114 button_release(Widget w, XtPointer data, XEvent *event, Boolean *b) {
115 XButtonEvent *buttonevent = (XButtonEvent *) event;
116
117 UNUSED(w);
118 UNUSED(data);
119 UNUSED(b);
120
121 Game_button_release(buttonevent->x, buttonevent->y);
122 }
123
124 static void
timer_tick(XtPointer client_data,XtIntervalId * timer_id)125 timer_tick(XtPointer client_data, XtIntervalId *timer_id) {
126 UNUSED(client_data);
127 UNUSED(timer_id);
128
129 UI_restart_timer();
130 Game_update();
131 }
132
133 /*
134 * Cursor handling
135 */
136
137 void
x11_set_cursor(MCursor * cursor)138 x11_set_cursor(MCursor *cursor) {
139 XDefineCursor(display, window, cursor->cursor);
140 }
141
142 void
x11_load_cursor(const char * name,int masked,MCursor ** cursorp)143 x11_load_cursor(const char *name, int masked, MCursor **cursorp) {
144 MCursor *cursor;
145 Pixmap bitmap, mask;
146 int i, xh, yh;
147 unsigned width, height;
148 char file[255];
149
150 cursor = xalloc(sizeof *cursor);
151
152 sprintf(file, "%s/bitmaps/%s.xbm", pictdir, name);
153 i = XReadBitmapFile(display, rootwindow, file,
154 &width, &height, &bitmap, &xh, &yh);
155 if (i == BitmapOpenFailed)
156 fatal("cannot open %s", file);
157 if (masked == CURSOR_SEP_MASK) {
158 sprintf(file, "%s/bitmaps/%s_mask.xbm", pictdir, name);
159 i = XReadBitmapFile(display, rootwindow,
160 file, &width, &height, &mask, &xh, &yh);
161 if (i == BitmapOpenFailed)
162 fatal("cannot open %s", file);
163 }
164 else
165 mask = bitmap;
166 cursor->cursor = XCreatePixmapCursor(display, bitmap, mask,
167 &black, &white,
168 width/2, height/2);
169 *cursorp = cursor;
170 }
171
172 /*
173 * Pixmap handling
174 */
175
176 void
x11_load_picture(const char * name,int trans,Picture ** pictp)177 x11_load_picture(const char *name, int trans, Picture **pictp) {
178 Picture *pict;
179 int i;
180 char file[255];
181 XpmColorSymbol symbol;
182 Pixmap mask;
183 XpmAttributes attr;
184 unsigned long gcmask;
185 XGCValues gcval;
186
187 pict = xalloc(sizeof *pict);
188
189 gcmask = GCForeground | GCBackground | GCGraphicsExposures;
190 gcval.graphics_exposures = False;
191 attr.valuemask = XpmCloseness | XpmReturnPixels | XpmColormap |
192 XpmDepth;
193 attr.closeness = 65535;
194 attr.colormap = colormap;
195 attr.depth = depth;
196 if (!trans) {
197 symbol.name = NULL;
198 symbol.value = "none";
199 XtVaGetValues(field, XtNbackground, &symbol.pixel, NULL);
200 attr.colorsymbols = &symbol;
201 attr.numsymbols = 1;
202 attr.valuemask |= XpmColorSymbols;
203 }
204 sprintf(file, "%s/pixmaps/%s.xpm", pictdir, name);
205 i = XpmReadFileToPixmap(display, rootwindow, file, &pict->pix,
206 &mask, &attr);
207 if (i < 0)
208 fatal("cannot open %s", file);
209 pict->mask = mask;
210 pict->gc = XCreateGC(display, offscreen, gcmask, &gcval);
211 if (trans)
212 XSetClipMask(display, pict->gc, mask);
213 pict->width = attr.width;
214 pict->height = attr.height;
215
216 *pictp = pict;
217 }
218
219 void
x11_set_icon(Picture * icon)220 x11_set_icon(Picture *icon) {
221 XtVaSetValues(toplevel, XtNiconPixmap, icon->pix,
222 XtNiconMask, icon->mask, NULL);
223 }
224
225 int
x11_picture_width(Picture * pict)226 x11_picture_width(Picture *pict) {
227 return (pict->width);
228 }
229
230 int
x11_picture_height(Picture * pict)231 x11_picture_height(Picture *pict) {
232 return (pict->height);
233 }
234
235 /*
236 * Graphics operations
237 */
238
239 void
x11_graphics_init()240 x11_graphics_init() {
241 XGCValues gcval;
242 unsigned long gcmask;
243 gcmask = GCGraphicsExposures;
244 gcval.graphics_exposures = False;
245 stdgc = XCreateGC(display, window, gcmask, &gcval);
246 XSetLineAttributes(display, stdgc, 2, LineSolid, CapRound, JoinMiter);
247 XSetBackground(display, stdgc, white.pixel);
248 XSetForeground(display, stdgc, black.pixel);
249 whitegc = XCreateGC(display, window, gcmask, &gcval);
250 XSetBackground(display, whitegc, white.pixel);
251 XSetForeground(display, whitegc, white.pixel);
252 offscreen = XCreatePixmap(display, rootwindow, screensize,
253 screensize, depth);
254 }
255
256 void
x11_clear_window()257 x11_clear_window() {
258 XFillRectangle(display, offscreen, whitegc, 0, 0,
259 screensize, screensize);
260 }
261
262 void
x11_refresh_window()263 x11_refresh_window() {
264 XCopyArea(display, offscreen, window, stdgc, 0, 0,
265 screensize, screensize, 0, 0);
266 }
267
268 void
x11_draw_image(Picture * pict,int x,int y)269 x11_draw_image(Picture *pict, int x, int y) {
270 XSetClipOrigin(display, pict->gc, x, y);
271 XCopyArea(display, pict->pix, offscreen, pict->gc, 0, 0,
272 pict->width, pict->height, x, y);
273 }
274
275 void
x11_draw_line(int x1,int y1,int x2,int y2)276 x11_draw_line(int x1, int y1, int x2, int y2) {
277 XDrawLine(display, offscreen, stdgc, x1, y1, x2, y2);
278 }
279
280 void
x11_draw_string(const char * str,int x,int y)281 x11_draw_string(const char *str, int x, int y) {
282 XDrawString(display, offscreen, stdgc, x, y, str, strlen(str));
283 }
284
285 /*
286 * Timer operations
287 */
288
289 void
x11_start_timer(int ms)290 x11_start_timer(int ms) {
291 timer = XtAppAddTimeOut(app, ms, timer_tick, NULL);
292 }
293
294 void
x11_stop_timer()295 x11_stop_timer() {
296 if (!timer)
297 return;
298 XtRemoveTimeOut(timer);
299 timer = (XtIntervalId) 0;
300 }
301
302 int
x11_timer_active()303 x11_timer_active() {
304 return (!!timer);
305 }
306
307 /*
308 * Main Loop
309 */
310 void
x11_main_loop()311 x11_main_loop() {
312 XtAppMainLoop(app);
313 }
314
315 /*
316 * Initialization
317 */
318 void
x11_initialize(int * argc,char ** argv)319 x11_initialize(int *argc, char **argv) {
320 struct stat stats;
321
322 timer = (XtIntervalId) 0;
323 toplevel = XtAppInitialize(&app, "XBill", NULL, 0, argc, argv,
324 NULL, NULL, 0);
325 display = XtDisplay(toplevel);
326
327 if (stat(IMAGES, &stats) == 0)
328 pictdir = IMAGES;
329 else
330 pictdir = ".";
331 }
332
333 void
x11_setup_resources()334 x11_setup_resources() {
335 XrmDatabase database;
336
337 database = XrmGetDatabase(display);
338 XrmPutStringResource(&database, "*background", "#c4c4c4");
339 XrmPutStringResource(&database, "*foreground", "#000000");
340 XrmSetDatabase(display, database);
341 }
342
343 void
x11_setup()344 x11_setup() {
345 Screen *screen;
346 XSizeHints h;
347 Dimension winwidth, winheight;
348
349 XtRealizeWidget(toplevel);
350 screen = XtScreen(toplevel);
351 depth = DefaultDepthOfScreen(screen);
352 rootwindow = RootWindowOfScreen(screen);
353
354 colormap = DefaultColormapOfScreen(screen);
355 white.pixel = WhitePixelOfScreen(screen);
356 XQueryColor(display, colormap, &white);
357 black.pixel = BlackPixelOfScreen(screen);
358 XQueryColor(display, colormap, &black);
359
360 XtVaGetValues(toplevel, XtNwidth, &winwidth, XtNheight, &winheight,
361 NULL);
362 h.width = h.base_width = h.min_width = h.max_width = winwidth;
363 h.height = h.base_height = h.min_height = h.max_height = winheight;
364 h.width_inc = h.height_inc = 0;
365 h.flags = PSize|PMaxSize|PMinSize|PBaseSize|PResizeInc;
366 XSetWMNormalHints(display, XtWindow(toplevel), &h);
367 }
368
369 void
x11_add_event_handlers(Widget w)370 x11_add_event_handlers(Widget w) {
371 XtAddEventHandler(w, ButtonPressMask, FALSE, button_press, NULL);
372 XtAddEventHandler(w, ButtonReleaseMask, FALSE, button_release, NULL);
373 XtAddEventHandler(w, LeaveWindowMask, FALSE, leave_window, NULL);
374 XtAddEventHandler(w, EnterWindowMask, FALSE, enter_window, NULL);
375 XtAddEventHandler(w, ExposureMask, FALSE, redraw_window, NULL);
376 }
377
378 Widget
x11_toplevel()379 x11_toplevel() {
380 return toplevel;
381 }
382
383 void
x11_set_drawingarea(Widget w,int size)384 x11_set_drawingarea(Widget w, int size) {
385 field = w;
386 window = XtWindow(w);
387 screensize = size;
388 }
389