1 /*
2 * The Rubik's cube.
3 *
4 * Sed - april 1999 / december 2003.
5 *
6 * This program is in the public domain.
7 *--------------------
8 * The screen stuff, ie X.
9 *
10 * Heavily hacked by J.-P. Demailly during week-end in October 2003,
11 * to make following additions work :
12 * wm_delete ClientMessage intercepted + menu popup + automatic resize
13 *
14 */
15
16 #include "screen.h"
17
18 #include <X11/Xlib.h>
19 #include <X11/Xutil.h>
20 #include <X11/keysym.h>
21 #include <X11/cursorfont.h>
22 #include <string.h>
23 #include <math.h>
24 #include <sys/time.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include "cube.h"
30 #include "device.h"
31
32 extern char help1[];
33 extern char help2[];
34 extern char help3[];
35 extern char control_str[];
36 extern char close_str[];
37 extern char *controlwin_str[];
38 extern char save_output_str[];
39 extern char perspective_str[];
40 extern char cube_saved_str[];
41
42
43 static Atom wm_protocols, wm_delete_window;
44
45 static int mark = 1;
46 static short color_marks[54];
47
48 static int gl_u[6] = { 150, 30, 150, 270, 390, 150};
49 static int gl_v[6] = { 120, 240, 240, 240, 240, 360};
50
51 /* color pixels */
52 unsigned long pixel[11];
53
set_colors(SCREEN * s)54 int set_colors(SCREEN *s)
55 {
56 XColor color, exact;
57 int i, failed;
58
59 failed = 0;
60 for (i=10; i>=0; i--) {
61 if (!XAllocNamedColor(s->d, s->cm, palette[i], &color, &exact))
62 failed = 1;
63 pixel[i] = color.pixel;
64 /*
65 printf("%lu %d %d %d\n", pixel[i],
66 color.red, color.green, color.blue);
67 */
68 }
69 /* printf("Failure : %d\n", failed); */
70 return failed;
71 }
72
error_statement(SCREEN * s)73 void error_statement(SCREEN *s)
74 {
75 perror("");
76 fprintf(stderr, "Meaning no rubix\n");
77 XCloseDisplay(s->d);
78 s->d=(Display *)0;
79 }
80
reset_data_buffers(SCREEN * s)81 int reset_data_buffers(SCREEN *s)
82 {
83
84 if (s->im)
85 XDestroyImage(s->im);
86
87 s->buffer=(char *)malloc(((SCREEN_X+7)/8)*SCREEN_Y*s->depth);
88
89 if (!s->buffer) {
90 error_statement(s);
91 return -1;
92 }
93
94 if (the_lines)
95 free(the_lines);
96 the_lines = (device_line *)malloc(SCREEN_Y*sizeof(device_line));
97
98 if (!the_lines) {
99 error_statement(s);
100 return -1;
101 }
102
103 /* create our XImage */
104 /* bitmap_pad, what the heck is it ?? mail sed@free.fr if you know, please...
105 * Well, seems it has to be 32...
106 */
107 /* Sed - december 2003 - no it has to be 8 */
108 s->im=XCreateImage(s->d, DefaultVisual(s->d, DefaultScreen(s->d)),
109 s->depth==32?24:s->depth, ZPixmap,
110 0, s->buffer, SCREEN_X, SCREEN_Y, 8, 0);
111
112 if (!s->im) {
113 error_statement(s);
114 return -1;
115 } else
116 return 0;
117 }
118
set_cube_size()119 void set_cube_size()
120 {
121 int s;
122 s = SCREEN_X;
123 if (SCREEN_Y < s) s = SCREEN_Y;
124 CUBE_SIZE = s * (0.95 - 0.2 * fabs(PERSPECTIVE));
125 }
126
127 /* return -1 if error, 0 if ok */
init_screen(SCREEN * s)128 int init_screen(SCREEN *s)
129 {
130 extern device d;
131 XGCValues gcv;
132 XEvent ev;
133 XClassHint xch;
134
135 memset(s, 0, sizeof(SCREEN));
136
137 if (!(s->d=XOpenDisplay((char *)0)))
138 return -1;
139
140 s->depth=DefaultDepth(s->d, DefaultScreen(s->d));
141
142 if (s->depth!=8 && s->depth!=16 && s->depth!=24) {
143 fprintf(stderr, "screen depth not supported (only 8, 16 and 24bpp (which means 32bpp too) handled\n");
144 XCloseDisplay(s->d);
145 s->d=(Display *)0;
146 return -1;
147 }
148
149 wm_protocols = XInternAtom(s->d, "WM_PROTOCOLS", False);
150 wm_delete_window = XInternAtom(s->d, "WM_DELETE_WINDOW", False);
151
152 s->font = XLoadQueryFont(s->d, FONT);
153 if (!s->font) {
154 fprintf(stderr, "cannot load font %s !!\n", FONT);
155 return -1;
156 }
157 HELP_X = (help_maxlen + 1) * XTextWidth(s->font, "w", 1);
158 HELP_Y = (help_numlines + 2) *
159 (s->font->max_bounds.ascent + s->font->max_bounds.descent + 2) + 3;
160
161 /* we don't know if s->depth==24 if it's 24 or 32bpp, let's check it */
162 if (s->depth==24) {
163 int n;
164 XPixmapFormatValues *v;
165
166 v=XListPixmapFormats(s->d, &n);
167 if (!v || !n) {
168 if (v)
169 XFree(v);
170 fprintf(stderr, "Error while trying to distinguish between 24 or 32bpp, damned...\n");
171 XCloseDisplay(s->d);
172 s->d=(Display *)0;
173 return -1;
174 }
175 for (n--; n>=0; n--)
176 if (v[n].bits_per_pixel==32)
177 s->depth=32;
178 XFree(v);
179 }
180
181 s->cm = DefaultColormap(s->d, DefaultScreen(s->d));
182
183 /* let's create and map our window */
184 s->w=XCreateWindow(s->d, DefaultRootWindow(s->d), 0, 0,
185 SCREEN_X, SCREEN_Y, 3, s->depth==32?24:s->depth,
186 CopyFromParent, CopyFromParent, 0, NULL);
187 s->h=XCreateWindow(s->d, DefaultRootWindow(s->d), 0, 0,
188 HELP_X, HELP_Y, 3, s->depth==32?24:s->depth,
189 CopyFromParent, CopyFromParent, 0, NULL);
190
191 xch.res_name = "rubix";
192 xch.res_class = "Rubix";
193 XSetClassHint(s->d, s->w, &xch);
194 XStoreName(s->d, s->w, xch.res_name);
195
196 XSelectInput(s->d, s->w,
197 KeyPressMask|ExposureMask|StructureNotifyMask|
198 PointerMotionMask|ButtonPressMask|ButtonReleaseMask);
199 XSetWMProtocols(s->d, s->w, &wm_delete_window, 1);
200
201 XSelectInput(s->d, s->h, ExposureMask|ButtonReleaseMask);
202 XSetWMProtocols(s->d, s->h, &wm_delete_window, 1);
203
204 XMapWindow(s->d, s->w);
205 do
206 XNextEvent(s->d, &ev);
207 while (ev.type!=Expose || ev.xexpose.window!=s->w);
208 /* XFlush(s->d); no xflush */
209 XSetWMProtocols(s->d, s->w, &wm_delete_window, 1);
210
211 gcv.function=GXcopy;
212 s->gc=XCreateGC(s->d, s->w, GCFunction, &gcv);
213 XSetFont(s->d, s->gc, s->font->fid);
214
215 if (reset_data_buffers(s) == -1)
216 return -1;
217
218 d.buffer=(unsigned char*)s->buffer;
219 d.depth=s->depth;
220 return 0;
221 }
222
realize_colors(SCREEN * s)223 void realize_colors(SCREEN *s)
224 {
225 if (set_colors(s) && s->depth<=8) {
226 s->cm=XCreateColormap(s->d, DefaultRootWindow(s->d),
227 DefaultVisual(s->d, DefaultScreen(s->d)), AllocNone);
228 set_colors(s);
229 }
230
231 if (s->depth<=8) {
232 XSetWindowColormap(s->d, s->w, s->cm);
233 XSetWindowColormap(s->d, s->h, s->cm);
234 }
235
236 XSetWindowBackground(s->d, s->w, pixel[10]);
237 XSetWindowBackground(s->d, s->h, pixel[10]);
238 }
239
grab_pointer(SCREEN * s,int mode)240 void grab_pointer(SCREEN *s, int mode)
241 {
242 static Cursor void_cursor = None;
243 static Cursor arrow_cursor = None;
244 Pixmap p;
245 XColor a;
246 GC pixgc;
247 XSetWindowAttributes attributs;
248
249 if (mode == 0) {
250 XUngrabPointer(s->d, 0);
251 if (arrow_cursor == None)
252 arrow_cursor = XCreateFontCursor(s->d, XC_hand2);
253 attributs.cursor = arrow_cursor;
254 XChangeWindowAttributes(s->d, s->w, CWCursor, &attributs);
255 return;
256 }
257
258
259 /* let's create a void cursor for our window */
260 if (void_cursor == None) {
261 p=XCreatePixmap(s->d, DefaultRootWindow(s->d), 1, 1, 1);
262 pixgc=XCreateGC(s->d, p, 0, 0);
263 a.red=a.green=a.blue=0;
264 XFillRectangle(s->d, p, pixgc, 0, 0, 2, 2);
265 XFreeGC(s->d, pixgc);
266 void_cursor = XCreatePixmapCursor(s->d, p, p, &a, &a, 0, 0);
267 /* XFreePixmap(s->d, p); */
268 }
269 attributs.cursor = void_cursor;
270 XChangeWindowAttributes(s->d, s->w, CWCursor, &attributs);
271
272 if (XGrabPointer(s->d, s->w, False,
273 PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
274 GrabModeAsync, GrabModeAsync, s->w, None, 0))
275 fprintf(stderr, "Could not grab the pointer, the program won't run very nice.\n");
276 place_mouse(s);
277 }
278
display_help(SCREEN * s)279 void display_help(SCREEN *s)
280 {
281 int i, dx, dy;
282 XStoreName(s->d, s->h, "rubix/help");
283 /* XFlush(s->d); no xflush */
284 /* usleep(50000); no usleep */
285 XSetForeground(s->d, s->gc, pixel[9]);
286 dy = s->font->max_bounds.ascent + s->font->max_bounds.descent + 2;
287 for (i=0; i<help_numlines; i++)
288 XDrawString(s->d, s->h, s->gc, 6,
289 s->font->max_bounds.ascent + 6 + i * dy,
290 help_index[i], strlen(help_index[i]));
291
292 dx = XTextWidth(s->font, control_str, strlen(control_str));
293 XDrawString(s->d, s->h, s->gc, 13,
294 HELP_Y - s->font->max_bounds.descent - 12, control_str, strlen(control_str));
295 XDrawRectangle(s->d, s->h, s->gc, 6, HELP_Y - dy - 14, dx+14, dy+6);
296 XDrawRectangle(s->d, s->h, s->gc, 5, HELP_Y - dy - 15, dx+16, dy+8);
297
298 dx = XTextWidth(s->font, close_str, strlen(close_str));
299 XDrawString(s->d, s->h, s->gc, HELP_X - dx - 15,
300 HELP_Y - s->font->max_bounds.descent - 12, close_str, strlen(close_str));
301 XDrawRectangle(s->d, s->h, s->gc, HELP_X - dx - 22, HELP_Y - dy - 14, dx+14, dy+6);
302 XDrawRectangle(s->d, s->h, s->gc, HELP_X - dx - 23, HELP_Y - dy - 15, dx+16, dy+8);
303 /* XFlush(s->d); no xflush */
304 }
305
306 void
show_text(SCREEN * s,int mode)307 show_text(SCREEN *s, int mode)
308 {
309 char dum[50];
310 int h;
311 h = s->font->max_bounds.ascent + s->font->max_bounds.descent + 17;
312 XClearArea(s->d, s->w, 0, SCREEN_Y - h, SCREEN_X, h, 0);
313 switch(mode) {
314 case 0: sprintf(dum, "%s = %s",
315 save_output_str, formats[FORMAT]); break;
316 case 1: sprintf(dum, "%s = %.1f",
317 perspective_str, PERSPECTIVE); break;
318 case 2: sprintf(dum, "%s ./rubix.%s",
319 cube_saved_str, formats[FORMAT]);
320 dum[25] = '\0'; break;
321 default: strcpy(dum, "???"); break;
322 }
323 XSetForeground(s->d, s->gc, pixel[9]);
324 XDrawString(s->d, s->w, s->gc,
325 SCREEN_X - XTextWidth(s->font, dum, strlen(dum)) - 8,
326 SCREEN_Y - s->font->max_bounds.descent - 6,
327 dum, strlen(dum));
328 }
329
get_marks(CUBE * c)330 void get_marks(CUBE *c)
331 {
332 c->cubes[25].colors[1] = color_marks[0];
333 c->cubes[22].colors[1] = color_marks[1];
334 c->cubes[20].colors[1] = color_marks[2];
335 c->cubes[24].colors[1] = color_marks[3];
336 c->cubes[1].colors[1] = color_marks[4];
337 c->cubes[19].colors[1] = color_marks[5];
338 c->cubes[23].colors[1] = color_marks[6];
339 c->cubes[21].colors[1] = color_marks[7];
340 c->cubes[18].colors[1] = color_marks[8];
341
342 c->cubes[25].colors[2] = color_marks[9];
343 c->cubes[24].colors[2] = color_marks[10];
344 c->cubes[23].colors[2] = color_marks[11];
345 c->cubes[23].colors[4] = color_marks[18];
346 c->cubes[21].colors[4] = color_marks[19];
347 c->cubes[18].colors[4] = color_marks[20];
348 c->cubes[18].colors[3] = color_marks[27];
349 c->cubes[19].colors[3] = color_marks[28];
350 c->cubes[20].colors[3] = color_marks[29];
351 c->cubes[20].colors[5] = color_marks[36];
352 c->cubes[22].colors[5] = color_marks[37];
353 c->cubes[25].colors[5] = color_marks[38];
354
355 c->cubes[17].colors[2] = color_marks[12];
356 c->cubes[2].colors[2] = color_marks[13];
357 c->cubes[16].colors[2] = color_marks[14];
358 c->cubes[16].colors[4] = color_marks[21];
359 c->cubes[4].colors[4] = color_marks[22];
360 c->cubes[14].colors[4] = color_marks[23];
361 c->cubes[14].colors[3] = color_marks[30];
362 c->cubes[3].colors[3] = color_marks[31];
363 c->cubes[15].colors[3] = color_marks[32];
364 c->cubes[15].colors[5] = color_marks[39];
365 c->cubes[5].colors[5] = color_marks[40];
366 c->cubes[17].colors[5] = color_marks[41];
367
368 c->cubes[13].colors[2] = color_marks[15];
369 c->cubes[12].colors[2] = color_marks[16];
370 c->cubes[11].colors[2] = color_marks[17];
371 c->cubes[11].colors[4] = color_marks[24];
372 c->cubes[9].colors[4] = color_marks[25];
373 c->cubes[6].colors[4] = color_marks[26];
374 c->cubes[6].colors[3] = color_marks[33];
375 c->cubes[7].colors[3] = color_marks[34];
376 c->cubes[8].colors[3] = color_marks[35];
377 c->cubes[8].colors[5] = color_marks[42];
378 c->cubes[10].colors[5] = color_marks[43];
379 c->cubes[13].colors[5] = color_marks[44];
380
381 c->cubes[11].colors[0] = color_marks[45];
382 c->cubes[9].colors[0] = color_marks[46];
383 c->cubes[6].colors[0] = color_marks[47];
384 c->cubes[12].colors[0] = color_marks[48];
385 c->cubes[0].colors[0] = color_marks[49];
386 c->cubes[7].colors[0] = color_marks[50];
387 c->cubes[13].colors[0] = color_marks[51];
388 c->cubes[10].colors[0] = color_marks[52];
389 c->cubes[8].colors[0] = color_marks[53];
390 }
391
set_marks(CUBE * c)392 void set_marks(CUBE *c)
393 {
394 color_marks[0] = c->cubes[25].colors[1];
395 color_marks[1] = c->cubes[22].colors[1];
396 color_marks[2] = c->cubes[20].colors[1];
397 color_marks[3] = c->cubes[24].colors[1];
398 color_marks[4] = c->cubes[1].colors[1];
399 color_marks[5] = c->cubes[19].colors[1];
400 color_marks[6] = c->cubes[23].colors[1];
401 color_marks[7] = c->cubes[21].colors[1];
402 color_marks[8] = c->cubes[18].colors[1];
403
404 color_marks[9] = c->cubes[25].colors[2];
405 color_marks[10] = c->cubes[24].colors[2];
406 color_marks[11] = c->cubes[23].colors[2];
407 color_marks[18] = c->cubes[23].colors[4];
408 color_marks[19] = c->cubes[21].colors[4];
409 color_marks[20] = c->cubes[18].colors[4];
410 color_marks[27] = c->cubes[18].colors[3];
411 color_marks[28] = c->cubes[19].colors[3];
412 color_marks[29]= c->cubes[20].colors[3];
413 color_marks[36]= c->cubes[20].colors[5];
414 color_marks[37]= c->cubes[22].colors[5];
415 color_marks[38]= c->cubes[25].colors[5];
416
417 color_marks[12] = c->cubes[17].colors[2];
418 color_marks[13] = c->cubes[2].colors[2];
419 color_marks[14] = c->cubes[16].colors[2];
420 color_marks[21] = c->cubes[16].colors[4];
421 color_marks[22] = c->cubes[4].colors[4];
422 color_marks[23] = c->cubes[14].colors[4];
423 color_marks[30] = c->cubes[14].colors[3];
424 color_marks[31] = c->cubes[3].colors[3];
425 color_marks[32]= c->cubes[15].colors[3];
426 color_marks[39]= c->cubes[15].colors[5];
427 color_marks[40]= c->cubes[5].colors[5];
428 color_marks[41]= c->cubes[17].colors[5];
429
430 color_marks[15] = c->cubes[13].colors[2];
431 color_marks[16] = c->cubes[12].colors[2];
432 color_marks[17] = c->cubes[11].colors[2];
433 color_marks[24] = c->cubes[11].colors[4];
434 color_marks[25] = c->cubes[9].colors[4];
435 color_marks[26] = c->cubes[6].colors[4];
436 color_marks[33] = c->cubes[6].colors[3];
437 color_marks[34] = c->cubes[7].colors[3];
438 color_marks[35]= c->cubes[8].colors[3];
439 color_marks[42]= c->cubes[8].colors[5];
440 color_marks[43]= c->cubes[10].colors[5];
441 color_marks[44]= c->cubes[13].colors[5];
442
443 color_marks[45] = c->cubes[11].colors[0];
444 color_marks[46] = c->cubes[9].colors[0];
445 color_marks[47] = c->cubes[6].colors[0];
446 color_marks[48] = c->cubes[12].colors[0];
447 color_marks[49] = c->cubes[0].colors[0];
448 color_marks[50] = c->cubes[7].colors[0];
449 color_marks[51] = c->cubes[13].colors[0];
450 color_marks[52] = c->cubes[10].colors[0];
451 color_marks[53] = c->cubes[8].colors[0];
452 }
453
display_controls(SCREEN * s)454 void display_controls(SCREEN *s)
455 {
456 int i, j, k, p, dx, dy;
457 static char faces[] = "BCEDFA";
458
459 dy = s->font->max_bounds.ascent + s->font->max_bounds.descent + 2;
460
461 XStoreName(s->d, s->h, "rubix/control");
462 /* XFlush(s->d); no xflush */
463 /* usleep(50000); no usleep */
464
465 color_marks[4] = 2;
466 color_marks[13] = 3;
467 color_marks[22] = 5;
468 color_marks[31] = 4;
469 color_marks[40] = 6;
470 color_marks[49] = 1;
471
472 for (i=0; i<6; i++) {
473 XSetForeground(s->d, s->gc, (i+1==mark)?pixel[9]:pixel[10]);
474 XDrawRectangle(s->d, s->h, s->gc, 29+60*i, 19, 42, 42);
475 XSetForeground(s->d, s->gc, pixel[7]);
476 XDrawRectangle(s->d, s->h, s->gc, 30+60*i, 20, 40, 40);
477 XDrawRectangle(s->d, s->h, s->gc, 31+60*i, 21, 38, 38);
478 XSetForeground(s->d, s->gc, pixel[i+1]);
479 XFillRectangle(s->d, s->h, s->gc, 32+60*i, 22, 37, 37);
480 }
481
482 for (i=0; i<6; i++) {
483 for (j=0; j<3; j++)
484 for (k=0; k<3; k++) {
485 XSetForeground(s->d, s->gc, pixel[7]);
486 XDrawRectangle(s->d, s->h, s->gc, gl_u[i]+40*j, gl_v[i]+40*k, 40, 40);
487 p = color_marks[9*i+j+3*k];
488 XSetForeground(s->d, s->gc, pixel[p]);
489 XFillRectangle(s->d, s->h, s->gc, gl_u[i]+40*j+1, gl_v[i]+40*k+1, 39, 39);
490 }
491 XSetForeground(s->d, s->gc, pixel[8]);
492 XDrawString(s->d, s->h, s->gc, gl_u[i]+58, gl_v[i]+64, faces+i, 1);
493 XSetForeground(s->d, s->gc, pixel[7]);
494 XDrawRectangle(s->d, s->h, s->gc, gl_u[i], gl_v[i], 120, 120);
495 XDrawRectangle(s->d, s->h, s->gc, gl_u[i]+1, gl_v[i]+1, 118, 118);
496
497 }
498
499 XSetForeground(s->d, s->gc, pixel[9]);
500 dx = XTextWidth(s->font, controlwin_str[3], strlen(controlwin_str[3]));
501 for (i=0; i<5; i++) {
502 XDrawString(s->d, s->h, s->gc, 30 + (dx+40)*i,
503 HELP_Y - s->font->max_bounds.descent - 12, controlwin_str[i], strlen(controlwin_str[i]));
504 XDrawRectangle(s->d, s->h, s->gc, 20+(dx+40)*i, HELP_Y - dy - 14, dx+14, dy+6);
505 XDrawRectangle(s->d, s->h, s->gc, 19+(dx+40)*i, HELP_Y - dy - 15, dx+16, dy+8);
506 }
507 /* XFlush(s->d); no xflush */
508 }
509
510 /* return -1 if end, 0 otherwise */
screen_key(SCREEN * s,CUBE * c,XKeyEvent * ev)511 int screen_key(SCREEN *s, CUBE *c, XKeyEvent *ev)
512 {
513 char dum[50];
514 KeySym ks;
515 int n;
516
517 XLookupString(ev, dum, 50, &ks, (XComposeStatus *)0);
518
519 switch(ks) {
520 case XK_Escape :
521 case XK_q :
522 case XK_Q :
523 return -1;
524 case XK_a:
525 case XK_A:
526 case XK_b:
527 case XK_B:
528 case XK_c:
529 case XK_C:
530 case XK_d:
531 case XK_D:
532 case XK_e:
533 case XK_E:
534 case XK_f:
535 case XK_F:
536 n = -1;
537 if (!c->letters) {
538 c->letters = 1;
539 display_cube(c, s);
540 break;
541 }
542 if ((ks>=XK_a) && (ks<=XK_f)) {
543 c->rotated = n = ks-XK_a;
544 c->orient = 0;
545 }
546 if ((ks>=XK_A) && (ks<=XK_F)) {
547 c->rotated = n = ks-XK_A;
548 c->orient = 1;
549 }
550 if (n == -1) break;
551 c->letters = 1;
552 c->anim = -1;
553 c->time = get_time();
554 break;
555 case XK_l:
556 case XK_L:
557 c->letters = 1 - c->letters;
558 display_cube(c, s);
559 break;
560 case XK_exclam :
561 XMapRaised(s->d, s->h);
562 XClearWindow(s->d, s->h);
563 s->control = 2;
564 set_marks(c);
565 display_controls(s);
566 s->pause = 0;
567 goto do_pause;
568 case XK_asterisk :
569 case XK_KP_Multiply :
570 FORMAT = (FORMAT+1)%3;
571 show_text(s, 0);
572 break;
573 case XK_plus :
574 case XK_KP_Add :
575 n = (int) (10*PERSPECTIVE + 10.5);
576 ++n;
577 if (n>20) n = 20;
578 PERSPECTIVE = 0.1 * n - 1.0;
579 set_cube_size();
580 display_cube(c, s);
581 show_text(s, 1);
582 break;
583 case XK_minus :
584 case XK_KP_Subtract :
585 n = (int) (10*PERSPECTIVE + 10.5);
586 --n;
587 if (n<0) n = 0;
588 PERSPECTIVE = 0.1 * n - 1.0;
589 set_cube_size();
590 display_cube(c, s);
591 show_text(s, 1);
592 break;
593 case XK_h :
594 case XK_H :
595 XMapRaised(s->d, s->h);
596 XClearWindow(s->d, s->h);
597 s->pause = 0;
598 s->control = 0;
599 display_help(s);
600 case XK_space :
601 do_pause:
602 s->pause=1-s->pause;
603 if (s->pause) {
604 grab_pointer(s, 0);
605 } else {
606 grab_pointer(s, 1);
607 }
608 display_cube(c, s);
609 break;
610 case XK_i :
611 case XK_I :
612 init_cube(c, NULL, -1);
613 display_cube(c, s);
614 break;
615 case XK_p :
616 case XK_P :
617 init_cube(c, NULL, 1);
618 display_cube(c, s);
619 break;
620 case XK_r :
621 case XK_R :
622 reset_cube(c);
623 display_cube(c, s);
624 break;
625 case XK_s :
626 case XK_S :
627 save_cube(c);
628 show_text(s, 2);
629 break;
630 case XK_Left :
631 if (!s->pause)
632 cube_generate_rotate(c, s, 0);
633 break;
634 case XK_Right :
635 if (!s->pause)
636 cube_generate_rotate(c, s, 1);
637 break;
638 }
639
640 return 0;
641 }
642
place_mouse(SCREEN * s)643 void place_mouse(SCREEN *s)
644 {
645 if (!s->pause) {
646 XWarpPointer(s->d, None, s->w, 0, 0, 0, 0, SCREEN_X/2, SCREEN_Y/2);
647 /* XFlush(s->d); no xflush */
648 }
649 }
650
mouse_pre_event(XMotionEvent * ev,int * a,int * b)651 void mouse_pre_event(XMotionEvent *ev, int *a, int *b)
652 {
653 if (ev->x==SCREEN_X/2 && ev->y==SCREEN_Y/2)
654 return;
655
656 *a=ev->y-SCREEN_Y/2;
657 *b=ev->x-SCREEN_X/2;
658 }
659
mouse_event(SCREEN * s,CUBE * c,int a,int b)660 void mouse_event(SCREEN *s, CUBE *c, int a, int b)
661 {
662 #define SPEED (1024.)
663 if (s->pause)
664 return;
665
666 if (a==0 && b==0)
667 return;
668
669 place_mouse(s);
670
671 /* the x is y and vice-versa */
672 cube_rotate(s, c, a*M_PI/SPEED, b*M_PI/SPEED);
673 display_cube(c, s);
674 }
675
676 /* danger: this returns the incorrect height with some window managers */
get_window_size(SCREEN * s,int * x,int * y)677 void get_window_size(SCREEN *s, int *x, int*y)
678 {
679 Window root, parent, *children;
680 int u, v;
681 unsigned int b, d;
682 unsigned int n;
683 XQueryTree(s->d, s->w, &root, &parent, &children, &n);
684
685 if (!parent) {
686 fprintf(stderr, "Cannot query window tree!\n");
687 return;
688 }
689
690 XGetGeometry(s->d, parent, &root, &u, &v,
691 (unsigned int *)x, (unsigned int *)y, &b, &d);
692 }
693
evpred(Display * d,XEvent * ev,XPointer a)694 Bool evpred(Display *d, XEvent *ev, XPointer a)
695 {
696 return (True);
697 }
698
confpred(Display * d,XEvent * ev,XPointer a)699 Bool confpred(Display *d, XEvent *ev, XPointer a)
700 {
701 if (ev->type==ConfigureNotify)
702 return (True);
703 else
704 return (False);
705 }
706
707 /* Discard all events but last expose event */
purge_events(Display * dpy)708 void purge_events(Display *dpy)
709 {
710 XEvent ev, evp;
711 evp.type = 0;
712 while (XPending(dpy)) {
713 XNextEvent(dpy, &ev);
714 if (ev.type==Expose) evp = ev;
715 }
716 if (evp.type==Expose) XPutBackEvent(dpy, &evp);
717 }
718
719 /* return -1 if end, 0 if ok */
screen_event(SCREEN * s,CUBE * c)720 int screen_event(SCREEN *s, CUBE *c)
721 {
722 #define EXPOSE 1
723 #define MOTION 2
724 int win_expose = 0; /* 1: w win, 2: h win: 3: both */
725 extern device d;
726 int type=0;
727 int i, j, k, a=0, b=0, dx, dy;
728 static int new_x, new_y, notify = 0;
729
730 XEvent ev;
731
732 dy = s->font->max_bounds.ascent + s->font->max_bounds.descent + 2;
733
734 while(XCheckIfEvent(s->d, &ev, evpred, (XPointer)0)) {
735 switch(ev.type) {
736 case ClientMessage :
737 if (ev.xclient.message_type == wm_protocols &&
738 ev.xclient.format == 32 &&
739 ev.xclient.data.l[0] == wm_delete_window) {
740 if (ev.xclient.window == s->w) {
741 close_screen(s);
742 exit(0);
743 }
744 if (ev.xclient.window == s->h) {
745 XUnmapWindow(s->d, s->h);
746 s->control = 0;
747 }
748 }
749 break;
750 case Expose :
751 type|=EXPOSE;
752 if (ev.xexpose.window == s->w) win_expose |= 1;
753 if (ev.xexpose.window == s->h) win_expose |= 2;
754 break;
755 case KeyPress :
756 if (screen_key(s, c, &ev.xkey)==-1)
757 return -1;
758 break;
759 case ButtonRelease :
760 if (ev.xbutton.window==s->w) {
761 if (!s->pause) break;
762 dx = XTextWidth(s->font, help1, strlen(help1));
763 if (ev.xbutton.x>=6 && ev.xbutton.x<=dx+20 &&
764 ev.xbutton.y>=6 && ev.xbutton.y<=dy+12) {
765 s->pause=0;
766 grab_pointer(s, 1);
767 display_cube(c, s);
768 break;
769 }
770 dx = XTextWidth(s->font, help2, strlen(help2));
771 if (ev.xbutton.x>=6 && ev.xbutton.x<=dx+20 &&
772 ev.xbutton.y>=SCREEN_Y - dy - 14 &&
773 ev.xbutton.y<=SCREEN_Y - 8) {
774 XMapRaised(s->d, s->h);
775 XClearWindow(s->d, s->h);
776 s->control = 0;
777 display_help(s);
778 break;;
779 }
780 dx = XTextWidth(s->font, help3, strlen(help3));
781 if (ev.xbutton.x>=SCREEN_X - dx - 22 && ev.xbutton.x<=SCREEN_X - 8 &&
782 ev.xbutton.y>=SCREEN_Y - dy - 14 && ev.xbutton.y<=SCREEN_Y - 8) {
783 XMapRaised(s->d, s->h);
784 XClearWindow(s->d, s->h);
785 set_marks(c);
786 s->control = 2;
787 display_controls(s);
788 break;
789 }
790 break;
791 }
792 if (ev.xbutton.window==s->h) {
793 dx = XTextWidth(s->font, control_str, strlen(control_str));
794 if (s->control == 0 &&
795 ev.xbutton.x>=6 && ev.xbutton.x<=dx+20 &&
796 ev.xbutton.y>=HELP_Y - dy - 14 && ev.xbutton.y<=HELP_Y - 8) {
797 s->control = 2;
798 XClearWindow(s->d, s->h);
799 set_marks(c);
800 display_controls(s);
801 break;
802 }
803 dx = XTextWidth(s->font, close_str, strlen(close_str));
804 if (s->control == 0 &&
805 ev.xbutton.x>=HELP_X - dx - 22 && ev.xbutton.x<=HELP_X - 8 &&
806 ev.xbutton.y>=HELP_Y - dy - 14 && ev.xbutton.y<=HELP_Y - 8) {
807 XUnmapWindow(s->d, s->h);
808 }
809 if (s->control == 0) break;
810 j = -1;
811 dx = XTextWidth(s->font, controlwin_str[3], strlen(controlwin_str[3]));
812 for (i=0; i<5; i++)
813 if (ev.xbutton.x>=20+(dx+40)*i && ev.xbutton.x<=-6+(dx+40)*(i+1) &&
814 ev.xbutton.y>=HELP_Y - dy - 14 && ev.xbutton.y<=HELP_Y - 8) {
815 j = i;
816 break;
817 }
818 if (j>=0)
819 switch(j) {
820 case 0: s->control = 1;
821 memset(color_marks, 0, 54*sizeof(short));
822 goto skip;
823 case 1: s->control = 2;
824 get_marks(c);
825 display_cube(c, s);
826 goto endcontrol;
827 case 2: s->control = 2;
828 init_cube(c, NULL, -1);
829 display_cube(c, s);
830 goto skip;
831 case 3: s->control = 2;
832 init_cube(c, NULL, 1);
833 display_cube(c, s);
834 goto skip;
835 case 4: s->control = 0;
836 XUnmapWindow(s->d, s->h);
837 goto endcontrol;
838 }
839 for (i=0; i<6; i++) {
840 if (ev.xbutton.x>=30+60*i && ev.xbutton.x<=70+60*i &&
841 ev.xbutton.y>=20 && ev.xbutton.y<=60) {
842 mark = i+1;
843 goto skip;
844 }
845 }
846 for (i=0; i<6; i++) {
847 for (j=0; j<3; j++)
848 for (k=0; k<3; k++) {
849 if (ev.xbutton.x>=gl_u[i]+40*j && ev.xbutton.x<=gl_u[i]+40+40*j &&
850 ev.xbutton.y>=gl_v[i]+40*k && ev.xbutton.y<=gl_v[i]+40+40*k) {
851 color_marks[9*i+j+3*k] = mark;
852 if (s->control==2) s->control = 1;
853 goto skip;
854 }
855 }
856 }
857 skip:
858 display_controls(s);
859 if (!s->control) break;
860 }
861 endcontrol:
862 break;
863 case ButtonPress :
864 if (ev.xbutton.window != s->w)
865 break;
866 if (c->letters) {
867 c->letters = 0;
868 display_cube(c, s);
869 break;
870 }
871 if (ev.xbutton.button==Button1) {
872 cube_generate_rotate(c, s, 0);
873 } else if (ev.xbutton.button==Button2) {
874 s->pause=1;
875 grab_pointer(s, 0);
876 display_cube(c, s);
877 } else if (ev.xbutton.button==Button3) {
878 cube_generate_rotate(c, s, 1);
879 }
880 break;
881 case MotionNotify :
882 if (ev.xmotion.window != s->w)
883 break;
884 mouse_pre_event(&ev.xmotion, &a, &b);
885 type |= MOTION;
886 break;
887 case PropertyNotify:
888 case ConfigureNotify:
889 new_x = ev.xconfigure.width;
890 new_y = ev.xconfigure.height;
891 if (new_x!=SCREEN_X || new_y!=SCREEN_Y)
892 notify = 1;
893 break;
894 #if 0
895 case FocusOut :
896 if (!s->pause)
897 place_mouse(s);
898 break;
899 #endif
900 }
901 }
902
903 if (notify) {
904 /* XFlush(s->d); no xflush */
905 /* usleep(200000); no usleep */
906 if (new_x!=SCREEN_X || new_y!=SCREEN_Y ||
907 XCheckIfEvent(s->d, &ev, confpred, (XPointer)0)) {
908 if (new_x<80) new_x = 80;
909 if (new_y<60) new_y = 60;
910 XResizeWindow(s->d, s->w, new_x, new_y);
911 XClearArea(s->d, s->w, 0, 0, 1, 1, True);
912 SCREEN_X = new_x;
913 SCREEN_Y = new_y;
914 reset_data_buffers(s);
915 d.buffer=(unsigned char *)s->buffer;
916 set_cube_size();
917 } else {
918 display_cube(c, s);
919 /* XFlush(s->d); no xflush */
920 put_screen(c, s);
921 notify = 0;
922 }
923 purge_events(s->d);
924 /* just in case purge_events removed some xexpose for the other window */
925 if (s->control) display_controls(s);
926 if (!s->control) display_help(s);
927 return 0;
928 }
929
930 if (type & EXPOSE) {
931 /*if (ev.xexpose.window == s->w) */
932 if (win_expose & 1)
933 put_screen(c, s);
934 /* if (ev.xexpose.window == s->h) { */
935 if (win_expose & 2) {
936 if (s->control) display_controls(s);
937 if (!s->control) display_help(s);
938 }
939 }
940
941 if (type & MOTION) {
942 i = s->control;
943 s->control = 0;
944 mouse_event(s, c, a, b);
945 s->control = i;
946 }
947
948 return 0;
949 }
950
close_screen(SCREEN * s)951 void close_screen(SCREEN *s)
952 {
953 XDestroyWindow(s->d, s->w);
954 XFreeGC(s->d, s->gc);
955 if (s->depth==8)
956 XFreeColormap(s->d, s->cm);
957 XCloseDisplay(s->d);
958 }
959
clear_screen(SCREEN * s)960 void clear_screen(SCREEN *s)
961 {
962 /* fill s->im with pixel[10], avoid XPutPixel which is rather slow... */
963 int i, w, dw;
964 w = (SCREEN_X+7)/8;
965 dw = s->depth/8;
966 XPutPixel(s->im, 0, 0, pixel[10]);
967 for (i=1; i<8*w; i++)
968 memcpy(s->buffer + i*dw, s->buffer, dw);
969 w = w * s->depth;
970 for (i=1; i<SCREEN_Y; i++)
971 memcpy(s->buffer + i*w, s->buffer, w);
972 }
973
put_screen(CUBE * c,SCREEN * s)974 void put_screen(CUBE *c, SCREEN *s)
975 {
976 int dx, dy;
977 XPutImage(s->d, s->w, s->gc, s->im, 0, 0, 0, 0, SCREEN_X, SCREEN_Y);
978 if (s->pause) {
979 XSetForeground(s->d, s->gc, pixel[9]);
980 dy = s->font->max_bounds.ascent + s->font->max_bounds.descent + 2;
981
982 dx = XTextWidth(s->font, help1, strlen(help1));
983 XDrawString(s->d, s->w, s->gc, 13,
984 s->font->max_bounds.ascent + 10, help1, strlen(help1));
985 XDrawRectangle(s->d, s->w, s->gc, 6, 6, dx+14, dy+6);
986 XDrawRectangle(s->d, s->w, s->gc, 5, 5, dx+16, dy+8);
987
988 dx = XTextWidth(s->font, help2, strlen(help2));
989 XDrawString(s->d, s->w, s->gc, 13,
990 SCREEN_Y - s->font->max_bounds.descent - 12,
991 help2, strlen(help2));
992 XDrawRectangle(s->d, s->w, s->gc, 6,
993 SCREEN_Y - dy - 14, dx+14, dy+6);
994 XDrawRectangle(s->d, s->w, s->gc, 5,
995 SCREEN_Y - dy - 15, dx+16, dy+8);
996
997 dx = XTextWidth(s->font, help3, strlen(help3));
998 XDrawString(s->d, s->w, s->gc, SCREEN_X - dx - 15,
999 SCREEN_Y - s->font->max_bounds.descent - 12,
1000 help3, strlen(help3));
1001 XDrawRectangle(s->d, s->w, s->gc, SCREEN_X - dx - 22,
1002 SCREEN_Y - dy - 14, dx+14, dy+6);
1003 XDrawRectangle(s->d, s->w, s->gc, SCREEN_X - dx - 23,
1004 SCREEN_Y - dy - 15, dx+16, dy+8);
1005 XFlush(s->d);
1006 }
1007 if (s->control == 2 && c->anim==0) {
1008 set_marks(c);
1009 display_controls(s);
1010 /* XFlush(s->d); no xflush */
1011 }
1012 /* XFlush(s->d); */
1013 }
1014
1015 /* return ms */
get_time(void)1016 struct timeval get_time(void)
1017 {
1018 struct timeval t;
1019 struct timezone d;
1020 if (gettimeofday(&t, &d)==-1) {
1021 perror("gettimeofday");
1022 return t;
1023 }
1024 return t;
1025 }
1026