eh, make ’em volatile, this is not time-critical code anyway
[alioth/magicpoint.git] / x11.c
1 /*
2  * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the project nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include "mgp.h"
30
31 /* covered by gcconf */
32 GC gcfore;
33 GC gcpen;
34 GC gcred;
35 GC gcgreen;
36 GC gcyellow;
37
38 /* not covered by gcconf */
39 GC gc_pl;
40 GC gc_plrev;
41 GC gc_pta;
42 GC gc_ptk;
43
44 /* for caching */
45 GC gc_cache;
46
47 long xeventmask = EVENT_DEFAULT | EVENT_RAKUGAKI;
48
49 static u_long zero = 0;
50
51 static struct gcconf {
52         GC *gc;
53         u_long *fore;
54         u_long *back;
55         const char *color;
56         int func;
57 } gcconf[]  = {
58         { &gcfore,      &fore_color[0], &zero,  NULL,           GXcopy },
59         { &gcpen,       NULL,           NULL,   "red",          GXcopy },
60         { &gcred,       NULL,           NULL,   "red",          GXcopy },
61         { &gcgreen,     NULL,           NULL,   "green",        GXcopy },
62         { &gcyellow,    NULL,           NULL,   "yellow",       GXcopy },
63         { NULL,         NULL,           NULL,   NULL,           0 }
64 };
65
66 static XWindowAttributes xa;
67
68 int window_x;
69 int window_y;
70
71 static Visual *
72 get_visual(Display *dpy, int scrn, u_int *depthp)
73 {
74         XVisualInfo *best, *vinfo, vinfo_template;
75         Visual *ret;
76         int vinfo_mask, i, ninfo;
77
78         vinfo_template.screen = scrn;
79         vinfo_mask = VisualScreenMask;
80
81         vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &ninfo);
82         best = NULL;
83         for (i = 0; i < ninfo; i++) {
84                 switch (vinfo[i].class) {
85                 case TrueColor:
86                         if (vinfo[i].depth < 15 || 24 < vinfo[i].depth)
87                                 break;
88                         if (best == NULL ||
89                             best->class != TrueColor ||
90                             best->depth < vinfo[i].depth)
91                                 best = &vinfo[i];
92                         break;
93                 case PseudoColor:
94                         if (best == NULL)
95                                 best = &vinfo[i];
96                         break;
97                 }
98         }
99         if (best) {
100                 ret = best->visual;
101                 *depthp = best->depth;
102         } else {
103                 ret = DefaultVisual(dpy, scrn);
104                 *depthp = DefaultDepth(dpy, scrn);
105         }
106         XFree(vinfo);
107         return ret;
108 }
109
110 void
111 init_win1(char *geometry)
112 {
113         int xloc, yloc;
114         unsigned int xsiz, ysiz;
115         int mode;
116         u_int i;
117
118         if ((display = XOpenDisplay(NULL)) == NULL) {
119                 fprintf(stderr, "Can't open display\n");
120                 exit(-1);
121         }
122         screen = DefaultScreen(display);
123         visual = get_visual(display, screen, &depth);
124         depth_mask = 1;
125         for (i = depth; i; i--)
126                 depth_mask *= 2;
127         depth_mask--;
128         /* depth_mask is the max value of pixel */
129
130         XGetWindowAttributes(display, DefaultRootWindow(display), &xa);
131
132         /* determine geometry to use. */
133         window_width = window_height = -1;
134         window_x = window_y = -1;
135         if (geometry) {
136                 mode = XParseGeometry(geometry, &xloc, &yloc,
137                         &xsiz, &ysiz);
138                 if (mode == 0) {
139                         fprintf(stderr, "bad geometry string %s\n",
140                                 geometry);
141                         exit(-1);
142                 }
143                 if (!(mode & WidthValue))
144                         xsiz = 0;
145                 if (!(mode & HeightValue))
146                         ysiz = 0;
147                 if (!(mode & XValue))
148                         xloc = -1;
149                 if (!(mode & YValue))
150                         yloc = -1;
151         } else {
152                 xsiz = ysiz = 0;
153                 xloc = yloc = -1;
154                 mode = 0;
155         }
156
157         if (xsiz == 0) {
158                 window_width = ((mgp_flag & FL_OVER) && !(mgp_flag & FL_NODECORATION))
159                         ? (int)(xa.width * 96 / 100)
160                         : xa.width;
161         } else
162                 window_width = xsiz;
163         if (ysiz == 0) {
164                 window_height = ((mgp_flag & FL_OVER) && !(mgp_flag & FL_NODECORATION))
165                         ? (int)(xa.height * 96 / 100)
166                         : xa.height;
167         } else
168                 window_height = ysiz;
169
170         if (0 <= xloc) {
171                 window_x = (mode & XNegative)
172                         ? xa.width - window_width - xloc
173                         : xloc;
174         }
175         if (0 <= yloc) {
176                 window_y = (mode & YNegative)
177                         ? xa.height - window_height - yloc
178                         : yloc;
179         }
180 #if 0
181         if (window_x < 0)
182                 window_x = 0;   /*XXX*/
183         if (window_y < 0)
184                 window_y = 0;   /*XXX*/
185 #endif
186         if (visual != DefaultVisual(display, screen))
187                 colormap = XCreateColormap(display, RootWindow(display, screen), visual, AllocNone);
188         else {
189                 colormap = DefaultColormap(display, screen);
190                 if (mgp_flag & FL_PRIVATE)
191                         colormap = XCopyColormapAndFree(display, colormap);
192         }
193
194         char_size[0] = window_height * DEFAULT_CHARSIZE / 100;
195         nonscaled_size[0] = char_size[0];
196         sup_off = DEFAULT_SUPOFF;
197         sub_off = DEFAULT_SUBOFF;
198         sup_scale = DEFAULT_SUPSCALE;
199         (void)get_color(DEFAULT_FORE, &fore_color[0]);
200         ctrl_color[0] = fore_color[0];
201
202         (void)get_color(back_clname, &back_color[0]);
203 }
204
205 static const char res_mgp[] = "MagicPoint";
206 static char res_name[sizeof(res_mgp)];
207 static char res_class[sizeof(res_mgp)];
208 void
209 init_win2(void)
210 {
211         XSetWindowAttributes xsa;
212         XSizeHints hints;
213         u_long mask;
214         struct gcconf *pc;
215         u_long color;
216         XClassHint res = { res_name, res_class };
217
218         memcpy(res_name, res_mgp, sizeof(res_mgp));
219         memcpy(res_class, res_mgp, sizeof(res_mgp));
220         xsa.border_pixel = fore_color[0];
221         xsa.background_pixel = back_color[0];
222         xsa.backing_store = Always;
223         xsa.colormap = colormap;
224         mask = CWBorderPixel | CWBackPixel | CWBackingStore | CWColormap;
225
226 #if 1   // this method is old. we should use WM_STATE_FULLSCREEN.
227         if (!(mgp_flag & FL_OVER)) {
228                 xsa.override_redirect = True;
229                 mask |= CWOverrideRedirect;
230         }
231 #endif
232
233         window = XCreateWindow(display, RootWindow(display, screen),
234                 (window_x < 0) ? 0 : window_x,
235                 (window_y < 0) ? 0 : window_y,
236                 (window_width < 0) ? 0 : window_width,
237                 (window_height < 0) ? 0 : window_height,
238                 0, depth, InputOutput, visual, mask, &xsa);
239         XStoreName(display, window, mgp_wname);
240         XSetIconName(display, window, mgp_wname);
241         XSetClassHint(display, window, &res);
242         pixmap = XCreatePixmap(display, window, xa.width, xa.height, depth);
243         maskpix = XCreatePixmap(display, window, xa.width, xa.height, depth);
244         cachewin = XCreatePixmap(display, window, xa.width, xa.height, depth);
245         cachetmp = XCreatePixmap(display, window, xa.width, xa.height, depth);
246         gc_cache = XCreateGC(display, window, 0, 0);
247         XSetGraphicsExposures(display, gc_cache, False);
248
249         for (pc = &gcconf[0]; pc->gc; pc++) {
250                 *pc->gc = XCreateGC(display, window, 0, 0);
251                 XSetFunction(display, *pc->gc, pc->func);
252                 if (pc->fore)
253                         XSetForeground(display, *pc->gc, *pc->fore);
254                 if (pc->back)
255                         XSetBackground(display, *pc->gc, *pc->back);
256                 if (pc->color) {
257                         (void)get_color(pc->color, &color);
258                         XSetForeground(display, *pc->gc, color);
259                 }
260         }
261
262         if (mgp_flag & FL_OVER){
263                 if (0 <= window_x && 0 <= window_y) {
264                         hints.x = window_x;
265                         hints.y = window_y;
266                         hints.flags = USPosition;
267                         XSetNormalHints(display, window, &hints);
268                 }
269         }
270         if (mgp_flag & FL_NODECORATION)
271                 XSetTransientForHint(display, window, window);
272
273         XMapRaised(display, window);
274
275         gc_pl = XCreateGC(display, window, 0, 0);
276         gc_plrev = XCreateGC(display, window, 0, 0);
277         gc_pta = XCreateGC(display, window, 0, 0);
278         gc_ptk = XCreateGC(display, window, 0, 0);
279         plfs = XLoadQueryFont(display, PAGELIST_FONT);
280         plkfs = XLoadQueryFont(display, PAGELIST_KFONT);
281         if (plfs) {
282                 XSetFont(display, gc_pl, plfs->fid);
283                 XSetFont(display, gc_plrev, plfs->fid);
284                 XSetFont(display, gc_pta, plfs->fid);
285         } else
286                 fprintf(stderr,
287                 "cannot find %s font. please modify PAGELIST_FONT to display page guide.\n",
288                                 PAGELIST_FONT);
289
290         if (plkfs)
291                 XSetFont(display, gc_ptk, plkfs->fid);
292         else
293                 fprintf(stderr, "cannot find %s font.\n", PAGELIST_KFONT);
294
295         XSetFunction(display, gc_pl, GXcopy);
296         XSetFunction(display, gc_plrev, GXcopy);
297         XSetFunction(display, gc_pta, GXcopy);
298         XSetFunction(display, gc_ptk, GXcopy);
299         XSetForeground(display, gc_pl, BlackPixel(display, screen));
300         XSetBackground(display, gc_pl, WhitePixel(display, screen));
301         XSetForeground(display, gc_plrev, WhitePixel(display, screen));
302         XSetBackground(display, gc_plrev, BlackPixel(display, screen));
303         if (plfs) {
304                 pl_fh = (plfs->max_bounds.ascent + plfs->max_bounds.descent) * 1.2;
305                 pl_fw = plfs->max_bounds.rbearing + plfs->max_bounds.lbearing;
306                 if (!plkfs) plkfs = plfs;
307         }
308 }
309
310 void
311 init_win3(void)
312 {
313         Window dummy;
314         int revert;
315
316         XSelectInput(display, window, xeventmask);
317
318         if (!(mgp_flag & FL_OVER)) {
319                 XGetInputFocus(display, &dummy, &revert);
320                 XSetInputFocus(display, window, RevertToParent, CurrentTime);
321                 if (XGrabKeyboard(display, window, True,
322                         GrabModeAsync, GrabModeAsync, CurrentTime)
323                                 != GrabSuccess) {
324                         fprintf(stderr, "XGrabKeyboard failed. sorry \n");
325                         exit(-1);
326                 }
327                 if (XGrabPointer(display, window, True, ButtonPressMask,
328                         GrabModeAsync, GrabModeAsync, window, None, CurrentTime)
329                                 != GrabSuccess) {
330                         fprintf(stderr, "XGrabPointer failed. sorry \n");
331                         exit(-1);
332                 }
333         }
334
335         // do fullscreen
336         if (!(mgp_flag & FL_OVER)) {
337                 toggle_fullscreen();
338         }
339 }
340
341 void
342 toggle_fullscreen(void)
343 {
344         static int fullscreen = 0;
345         XClientMessageEvent  xev;
346
347         fullscreen = (!fullscreen) & 1;
348         memset(&xev, 0, sizeof(xev));
349         xev.type=ClientMessage;
350         xev.message_type=XInternAtom(display, "_NET_WM_STATE", False);
351         xev.display=display;
352         xev.window=window;
353         xev.format=32;
354         xev.data.l[0]=fullscreen;
355         xev.data.l[1]= XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
356         xev.data.l[2]=0;
357         XSendEvent(display, DefaultRootWindow(display), False,
358         SubstructureRedirectMask, (XEvent*)&xev);
359 }
360
361 void
362 finish_win(void)
363 {
364         XUngrabKeyboard(display, CurrentTime);
365         XUngrabPointer(display, CurrentTime);
366         XCloseDisplay(display);
367 }
368
369 int
370 get_color(const char *colorname, u_long *value)
371 {
372         XColor c0, c1;
373
374         screen = DefaultScreen(display);
375 /*XXX*/
376         if (strcasecmp(colorname, "darkblue") == 0)
377                 colorname = "#00008B";
378         if (XAllocNamedColor(display, colormap, colorname, &c1, &c0) == 0)
379                 return -1;
380         if (value)
381                 *value = c1.pixel;
382         return 0;
383 }
384
385 struct g_color *
386 name2gcolor(const char *colorname)
387 {
388         XColor c0, c1;
389         struct g_color *color;
390
391         color = (struct g_color *)malloc(sizeof(struct g_color));
392
393         if (XLookupColor(display, colormap, colorname, &c1, &c0)) {
394                 color->r = (c1.red >> 8) & 0xff;
395                 color->g = (c1.green >> 8) & 0xff;
396                 color->b = (c1.blue >> 8) & 0xff;
397         } else {
398                 fprintf(stderr,"color '%s' unknown. ignored.\n", colorname);
399         }
400
401         return color;
402 }
403
404 void
405 free_alloc_colors(struct alloc_color *clr)
406 {
407         if (clr->num){
408                 XFreeColors(display, colormap, clr->colors, clr->num, 0);
409                 free(clr->colors);
410                 clr->colors = NULL;
411                 clr->num = 0;
412         }
413 }
414
415 void
416 regist_alloc_colors(struct alloc_color *clr, u_long *colors, u_int num)
417 {
418         u_int   i;
419
420         if (!clr->num)
421                 clr->colors = (u_long *)malloc(sizeof(u_long) * num);
422         else
423                 clr->colors = (u_long *)realloc(clr->colors,
424                                                 sizeof(u_long) * (clr->num + num));
425         for (i = 0; i < num; i++)
426                 clr->colors[clr->num +i] = (u_long)*(colors +i);
427         clr->num += num;
428 }