1 //  Construo - A wire-frame construction game
2 //  Copyright (C) 2002 Ingo Ruhnke <grumbel@gmx.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 #include <config.h>
18 #include <iostream>
19 #include <X11/Xutil.h>
20 #include <X11/cursorfont.h>
21 #include <X11/keysym.h>
22 #include <string.h>
23 
24 #include "cursors/cursors.hpp"
25 
26 #include "construo_error.hpp"
27 #include "x11_display.hpp"
28 #include "settings.hpp"
29 #include "construo_main.hpp"
30 
31 #include "controller.hpp"
32 #include "screen_manager.hpp"
33 
34 extern ConstruoMain* construo_main;
35 Atom wm_delete_window;
36 
X11Display(int w,int h,bool fullscreen_)37 X11Display::X11Display(int w, int h, bool fullscreen_)
38   : doublebuffer (settings.doublebuffer),
39     width(w), height(h), shift_pressed (false), fullscreen (fullscreen_)
40 {
41 #ifndef HAVE_LIBXXF86VM
42   fullscreen_ = false;
43   std::cout << "X11Display: libXxf86vm missing, fullscreen support not\n"
44             << "            available, please recompile." << std::endl;
45 #endif
46 
47   std::cout << "Using X11 display" << std::endl;
48   display = XOpenDisplay(NULL);
49 
50   if (!display)
51     throw ConstruoError("X11Display: Couldn't conncet to X server");
52 
53   int screen = DefaultScreen(display);
54   XSetWindowAttributes attributes;
55 
56   attributes.background_pixel  = BlackPixel(display, screen);
57   attributes.border_pixel      = WhitePixel(display, screen);
58 
59   if (fullscreen)
60     attributes.override_redirect = True;
61   else
62     attributes.override_redirect = False;
63 
64   attributes.event_mask =
65     KeyPressMask         |
66     KeyReleaseMask       |
67     ExposureMask         |
68     PointerMotionMask    |
69     ButtonPressMask      |
70     ButtonReleaseMask    |
71     StructureNotifyMask  |
72     ExposureMask;
73 
74   colormap = DefaultColormap (display, screen);
75   attributes.colormap = colormap;
76   window = XCreateWindow(display, RootWindow(display, screen),
77                          0,0, // position
78                          width, height, 0,
79                          CopyFromParent, InputOutput, CopyFromParent,
80                          CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWEventMask | CWColormap,
81                          &attributes);
82 
83   { // Communicate a bit with the window manager
84     char *title = const_cast<char*>(construo_main->get_title());
85 
86     XTextProperty text_property;
87     XStringListToTextProperty(&title, 1, &text_property);
88 
89     XSizeHints size_hints;
90     size_hints.x = 0;
91     size_hints.y = 0;
92     size_hints.flags  = PSize | PMinSize | PMaxSize;
93 
94     size_hints.width  = width;
95     size_hints.height = height;
96 
97     size_hints.min_width  = width;
98     size_hints.min_height = height;
99     size_hints.max_width  = width;
100     size_hints.max_height = height;
101 
102     XSetWMProperties(
103                      display,
104                      window,
105                      &text_property,
106                      &text_property,
107                      0,
108                      0,
109                      &size_hints,
110                      0,
111                      0);
112 
113     // Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property (to get window_delete requests).
114     wm_delete_window = XInternAtom (display, "WM_DELETE_WINDOW", False);
115     XSetWMProtocols (display, window, &wm_delete_window, 1);
116   }
117 
118   if (doublebuffer)
119     drawable = XCreatePixmap (display, window, width, height,
120                               DefaultDepth(display, screen));
121   else
122     drawable = window;
123 
124   XMapRaised(display, window);
125 
126   XGCValues gcv;
127   gcv.foreground = 0xFFFFFF;
128   gcv.background = 0x000000;
129 
130   if (settings.thick_lines)
131     gcv.line_width = 2;
132   else
133     gcv.line_width = 0;
134 
135   gc = XCreateGC(display, window,
136                  GCLineWidth | GCForeground | GCBackground,
137                  &gcv);
138 
139   if (fullscreen)
140     enter_fullscreen();
141 
142   {
143     // Visual* visual = XDefaultVisual(display, DefaultScreen(display));
144     depth = DefaultDepth(display, DefaultScreen(display));
145     if (depth != 16 && depth != 32)
146       {
147         std::cout << "X11Display: Warring color depth '" << depth
148                   << "' not supported, Construo will be slow!" << std::endl;
149       }
150   }
151 
152   {
153     // Black&White
154     XColor cursor_fg = get_xcolor(Color(1.0f, 1.0f, 1.0f));
155     XColor cursor_bg = get_xcolor(Color(0, 0, 0));
156 
157     cursor_scroll_pix = XCreateBitmapFromData (display, window, (char*)cursor_scroll_bits,
158                                                cursor_scroll_width, cursor_scroll_height);
159     cursor_scroll_mask = XCreateBitmapFromData (display, window, (char*)cursor_scroll_mask_bits,
160                                                 cursor_scroll_width, cursor_scroll_height);
161     cursor_scroll = XCreatePixmapCursor(display, cursor_scroll_pix, cursor_scroll_mask, &cursor_bg, &cursor_fg,
162                                         cursor_scroll_x_hot, cursor_scroll_y_hot);
163 
164     cursor_zoom_pix =  XCreateBitmapFromData (display, window, (char*)cursor_zoom_bits,
165                                               cursor_zoom_width, cursor_zoom_height);
166     cursor_zoom_mask = XCreateBitmapFromData (display, window, (char*)cursor_zoom_mask_bits,
167                                               cursor_zoom_width, cursor_zoom_height);
168     cursor_zoom = XCreatePixmapCursor(display, cursor_zoom_pix, cursor_zoom_mask, &cursor_bg, &cursor_fg,
169                                       cursor_zoom_x_hot, cursor_zoom_y_hot);
170 
171     cursor_insert_pix =  XCreateBitmapFromData (display, window, (char*)cursor_insert_bits,
172                                                 cursor_insert_width, cursor_insert_height);
173     cursor_insert_mask = XCreateBitmapFromData (display, window, (char*)cursor_insert_mask_bits,
174                                                 cursor_insert_width, cursor_insert_height);
175     cursor_insert = XCreatePixmapCursor(display, cursor_insert_pix, cursor_insert_mask, &cursor_bg, &cursor_fg,
176                                         cursor_insert_x_hot, cursor_insert_y_hot);
177 
178     cursor_select_pix =  XCreateBitmapFromData (display, window, (char*)cursor_select_bits,
179                                                 cursor_select_width, cursor_select_height);
180     cursor_select_mask = XCreateBitmapFromData (display, window, (char*)cursor_select_mask_bits,
181                                                 cursor_select_width, cursor_select_height);
182     cursor_select = XCreatePixmapCursor(display, cursor_select_pix, cursor_select_mask, &cursor_bg, &cursor_fg,
183                                         cursor_select_x_hot, cursor_select_y_hot);
184 
185     cursor_collider_pix =  XCreateBitmapFromData (display, window, (char*)cursor_collider_bits,
186                                                   cursor_collider_width, cursor_collider_height);
187     cursor_collider_mask = XCreateBitmapFromData (display, window, (char*)cursor_collider_mask_bits,
188                                                   cursor_collider_width, cursor_collider_height);
189     cursor_collider = XCreatePixmapCursor(display, cursor_collider_pix, cursor_collider_mask, &cursor_bg, &cursor_fg,
190                                           cursor_collider_x_hot, cursor_collider_y_hot);
191   }
192 
193   set_cursor(CURSOR_INSERT);
194 }
195 
~X11Display()196 X11Display::~X11Display ()
197 {
198   //std::cout << "Closing X11 display" << std::endl;
199 
200   if (fullscreen)
201     {
202       //std::cout << "X11Display: Restoring video mode" << std::endl;
203       leave_fullscreen ();
204     }
205 
206   if (doublebuffer)
207     XFreePixmap (display, drawable);
208 
209   XDestroyWindow (display, window);
210   XCloseDisplay(display);
211 }
212 
213 void
set_cursor_real(CursorType cursor)214 X11Display::set_cursor_real(CursorType cursor)
215 {
216   switch(cursor)
217     {
218     case CURSOR_INSERT:
219       XDefineCursor (display, window, cursor_insert);
220       break;
221     case CURSOR_SCROLL:
222       XDefineCursor (display, window, cursor_scroll);
223       break;
224     case CURSOR_ZOOM:
225       XDefineCursor (display, window, cursor_zoom);
226       break;
227     case CURSOR_COLLIDER:
228       XDefineCursor (display, window, cursor_collider);
229       break;
230     case CURSOR_SELECT:
231       XDefineCursor (display, window, cursor_select);
232       break;
233     default:
234       std::cout << "X11Display: Unhandled cursor type: " << cursor << std::endl;
235       break;
236     }
237 }
238 
239 void
draw_lines(std::vector<Line> & lines,Color color,int wide)240 X11Display::draw_lines (std::vector<Line>& lines, Color color, int wide)
241 {
242   std::vector<XSegment> segments (lines.size());
243 
244   for (std::vector<Line>::size_type i = 0; i < lines.size(); ++i)
245     {
246       segments[i].x1 = static_cast<short>(lines[i].x1);
247       segments[i].y1 = static_cast<short>(lines[i].y1);
248       segments[i].x2 = static_cast<short>(lines[i].x2);
249       segments[i].y2 = static_cast<short>(lines[i].y2);
250     }
251 
252   XDrawSegments(display, drawable, gc, &*segments.begin(), segments.size());
253 }
254 
255 void
draw_circles(std::vector<Circle> & circles,Color color)256 X11Display::draw_circles(std::vector<Circle>& circles, Color color)
257 {
258   std::vector<XArc> arcs (circles.size());
259   for (std::vector<Circle>::size_type i = 0; i < circles.size(); ++i)
260     {
261       arcs[i].x      = static_cast<short>(circles[i].x - circles[i].r);
262       arcs[i].y      = static_cast<short>(circles[i].y - circles[i].r);
263       arcs[i].width  = static_cast<short>(2 * circles[i].r);
264       arcs[i].height = static_cast<short>(2 * circles[i].r);
265       arcs[i].angle1 = 0;
266       arcs[i].angle2 = 360 * 64;
267     }
268 
269   XSetForeground(display, gc, get_color_value(color));
270   XFillArcs(display, drawable, gc,
271             &*arcs.begin(), arcs.size());
272 }
273 
274 void
draw_line(float x1,float y1,float x2,float y2,Color color,int wide)275 X11Display::draw_line(float x1, float y1, float x2, float y2, Color color, int wide)
276 {
277   XSetForeground(display, gc, get_color_value(color));
278   XDrawLine (display, drawable, gc, (int) x1, (int) y1, (int) x2, (int) y2);
279 }
280 
281 void
draw_fill_rect(float x1,float y1,float x2,float y2,Color color)282 X11Display::draw_fill_rect(float x1, float y1, float x2, float y2, Color color)
283 {
284   XSetForeground(display, gc, get_color_value(color));
285   XFillRectangle (display, drawable, gc,
286                   int(x1), int(y1),
287                   int(x2 - x1), int(y2 - y1));
288 }
289 
290 void
draw_fill_circle(float x,float y,float r,Color color)291 X11Display::draw_fill_circle(float x, float y, float r, Color color)
292 {
293   // FIXME: doesn't work
294   XSetForeground(display, gc, get_color_value(color));
295   XFillArc(display, drawable, gc,
296            int(x-r), int(y-r),
297            int(r*2), int(r*2), 0,
298            360*64);
299 }
300 
301 void
draw_circle(float x,float y,float r,Color color)302 X11Display::draw_circle(float x, float y, float r, Color color)
303 {
304   // FIXME: doesn't work
305   XSetForeground(display, gc, get_color_value(color));
306   XDrawArc(display, drawable, gc, int(x-r), int(y-r), int(r*2.0f), int(r*2.0f), 0, 360*64);
307 }
308 
309 void
draw_rect(float x1,float y1,float x2,float y2,Color color)310 X11Display::draw_rect(float x1, float y1, float x2, float y2, Color color)
311 {
312   XSetForeground(display, gc, get_color_value(color));
313   XDrawRectangle (display, drawable, gc,
314                   int(x1), int(y1),
315                   int(x2 - x1), int(y2 - y1));
316 }
317 
318 void
draw_string(float x,float y,const std::string & str,Color color)319 X11Display::draw_string(float x, float y, const std::string& str, Color color)
320 {
321   XSetForeground(display, gc, get_color_value(color));
322   XDrawString (display, drawable, gc, int(x), int(y), str.c_str (), str.length ());
323 }
324 
325 void
draw_string_centered(float x,float y,const std::string & str,Color color)326 X11Display::draw_string_centered(float x, float y, const std::string& str, Color color)
327 {
328   XSetForeground(display, gc, get_color_value(color));
329   XDrawString (display, drawable, gc,
330                int(x) - ((str.length() * 6) / 2), int(y),
331                str.c_str (), str.length ());
332 }
333 
334 int
get_mouse_x()335 X11Display::get_mouse_x ()
336 {
337   return mouse_x;
338 }
339 
340 int
get_mouse_y()341 X11Display::get_mouse_y ()
342 {
343   return mouse_y;
344 }
345 
346 bool
get_key(int key)347 X11Display::get_key (int key)
348 {
349   return false;
350 }
351 
352 void
wait_for_events_blocking()353 X11Display::wait_for_events_blocking ()
354 {
355   do {
356     while (read_event () == false);
357   } while (XPending (display) > 0);
358 }
359 
360 void
wait_for_events()361 X11Display::wait_for_events ()
362 {
363   while (XPending (display) > 0)
364     {
365       read_event ();
366     }
367 }
368 
369 bool
read_event()370 X11Display::read_event ()
371 {
372   XEvent event;
373 
374   XNextEvent (display, &event);
375 
376   switch (event.type)
377     {
378     case MotionNotify:
379       mouse_x = event.xmotion.x;
380       mouse_y = event.xmotion.y;
381       break;
382 
383     case Expose:
384       if (event.xexpose.count == 0)
385         flip ();
386       break;
387 
388     case NoExpose:
389       //std::cout << "NoExpose" << std::endl;
390       return false; // FIXME: Hack, no idea how to handle NoExpose
391       break;
392 
393     case ButtonPress:
394       {
395         //std::cout << "ButtonID: " << event.xbutton.button << " " << event.xbutton.state << std::endl;
396 
397         if (event.xbutton.button == 1)
398           send_button_press(BUTTON_PRIMARY);
399         else if (event.xbutton.button == 2)
400           send_button_press(BUTTON_TERTIARY);
401         else if (event.xbutton.button == 3)
402           send_button_press(BUTTON_SECONDARY);
403         else if (event.xbutton.button == 4)
404           send_button_press(BUTTON_ZOOM_IN);
405         else if (event.xbutton.button == 5)
406           send_button_press(BUTTON_ZOOM_OUT);
407       }
408       break;
409 
410     case ButtonRelease:
411       {
412         //std::cout << "ButtonID: " << event.xbutton.button << " " << event.xbutton.state << std::endl;
413         if (event.xbutton.button == 1)
414           send_button_release(BUTTON_PRIMARY);
415         else if (event.xbutton.button == 2)
416           send_button_release(BUTTON_TERTIARY);
417         else if (event.xbutton.button == 3)
418           send_button_release(BUTTON_SECONDARY);
419         else if (event.xbutton.button == 4)
420           send_button_release(BUTTON_ZOOM_IN);
421         else if (event.xbutton.button == 5)
422           send_button_release(BUTTON_ZOOM_OUT);
423       }
424       break;
425 
426     case KeyPress:
427       {
428         KeySym sym = XLookupKeysym(&event.xkey,0);
429 
430         switch (sym)
431           {
432           case XK_F11:
433             // FIXME: Shortcut
434             //send_button_press(BUTTON_FULLSCREEN);
435             toggle_fullscreen();
436             break;
437 
438           case XK_Left:
439             send_button_press(BUTTON_SCROLL_LEFT);
440             break;
441 
442           case XK_Right:
443             send_button_press(BUTTON_SCROLL_RIGHT);
444             break;
445 
446           case XK_Up:
447             send_button_press(BUTTON_SCROLL_UP);
448             break;
449 
450           case XK_Down:
451             send_button_press(BUTTON_SCROLL_DOWN);
452             break;
453 
454           case XK_a:
455             send_button_press(BUTTON_ACTIONCAM);
456             break;
457 
458           case XK_s:
459             send_button_press(BUTTON_SCALE);
460             break;
461 
462           case XK_j:
463             send_button_press(BUTTON_JOIN);
464             break;
465 
466           case XK_o:
467             send_button_press(BUTTON_HIDEDOTS);
468             break;
469 
470           case XK_v:
471             send_button_press(BUTTON_SETVELOCITY);
472             break;
473 
474           case XK_Shift_L:
475           case XK_Shift_R:
476             shift_pressed = true;
477             break;
478           case XK_m:
479             send_button_press(BUTTON_MODE_CHANGE);
480             break;
481           case XK_f:
482             send_button_press(BUTTON_FIX);
483             break;
484           case XK_h:
485             send_button_press(BUTTON_FLIP);
486             break;
487           case XK_c:
488             send_button_press(BUTTON_CLEAR);
489             break;
490           case XK_Delete:
491             send_button_press(BUTTON_DELETE);
492             break;
493           case XK_Escape:
494             send_button_press(BUTTON_ESCAPE);
495             break;
496           case XK_u:
497             send_button_press(BUTTON_UNDO);
498             break;
499           case XK_r:
500             send_button_press(BUTTON_REDO);
501             break;
502           case XK_d:
503             send_button_press(BUTTON_DUPLICATE);
504             break;
505           case XK_space:
506             send_button_press(BUTTON_RUN);
507             break;
508           case XK_g:
509             send_button_press(BUTTON_GRID);
510             break;
511           case XK_Tab:
512             send_button_press(BUTTON_TOGGLESLOWMO);
513             break;
514           case 65451: // FIXME: insert symbol here
515           case XK_equal:
516           case XK_plus:
517             send_button_press(BUTTON_ZOOM_IN);
518             break;
519           case 65453: // FIXME: insert symbol here
520           case XK_minus:
521             send_button_press(BUTTON_ZOOM_OUT);
522             break;
523           case XK_0:
524             send_load_or_save(0);
525             break;
526           case XK_1:
527             send_load_or_save(1);
528             break;
529           case XK_2:
530             send_load_or_save(2);
531             break;
532           case XK_3:
533             send_load_or_save(3);
534             break;
535           case XK_4:
536             send_load_or_save(4);
537             break;
538           case XK_5:
539             send_load_or_save(5);
540             break;
541           case XK_6:
542             send_load_or_save(6);
543             break;
544           case XK_7:
545             send_load_or_save(7);
546             break;
547           case XK_8:
548             send_load_or_save(8);
549             break;
550           case XK_9:
551             send_load_or_save(9);
552             break;
553 
554           default:
555             std::cout << "X11Display: unhandled keypress: " << sym << " " << XK_grave << std::endl;
556             break;
557           }
558       }
559       break;
560 
561     case KeyRelease:
562       {
563         KeySym sym = XLookupKeysym(&event.xkey,0);
564 
565         switch (sym)
566           {
567           case XK_Shift_L:
568           case XK_Shift_R:
569             shift_pressed = false;
570             break;
571           default:
572             //std::cout << "X11Display: unhandled keyrelease: " << sym << " " << XK_f << std::endl;
573             break;
574           }
575       }
576       break;
577 
578     case ConfigureNotify:
579       //std::cout << "X11Display: " << event.xconfigure.width << "x" << event.xconfigure.height
580       //<< "+" << event.xconfigure.x << "+" << event.xconfigure.y << std::endl;
581       break;
582 
583     case DestroyNotify:
584       std::cout << "Window got destroyed" << std::endl;
585       break;
586 
587     case ClientMessage:
588       std::cout << "X11Display: got client message" << std::endl;
589       // Window close request
590       if ((int) event.xclient.data.l[0] == (int) wm_delete_window) {
591         std::cout << "Window is destroyed" << std::endl;
592         send_button_press(BUTTON_ESCAPE);
593       }
594       break;
595 
596     default:
597       //std::cout << "X11Display: Unhandled event: " << event.type << std::endl;
598       break;
599     }
600   return true;
601 }
602 
603 void
send_load_or_save(int n)604 X11Display::send_load_or_save(int n)
605 {
606   if (shift_pressed)
607     send_button_press(BUTTON_QUICKLOAD0 + n);
608   else
609     send_button_press(BUTTON_QUICKSAVE0 + n);
610 }
611 
612 void
send_button_press(int i)613 X11Display::send_button_press (int i)
614 {
615   Event ev;
616   ev.button.type = BUTTON_EVENT;
617   ev.button.id = i;
618   ev.button.pressed = true;
619   events.push(ev);
620 }
621 
622 void
send_button_release(int i)623 X11Display::send_button_release (int i)
624 {
625   Event ev;
626   ev.button.type = BUTTON_EVENT;
627   ev.button.id = i;
628   ev.button.pressed = false;
629   events.push(ev);
630 }
631 
632 void
clear()633 X11Display::clear ()
634 {
635   XSetForeground (display, gc, 0x000000);
636   XFillRectangle (display, drawable, gc, 0, 0, width, height);
637 }
638 
639 void
flip(int x1,int y1,int x2,int y2)640 X11Display::flip (int x1, int y1, int x2, int y2)
641 {
642   if (doublebuffer)
643     {
644       FlipRect flip_rect;
645 
646       flip_rect.x1 = x1;
647       flip_rect.y1 = y1;
648       flip_rect.x2 = x2;
649       flip_rect.y2 = y2;
650 
651       //flip_rects.push_back(flip_rect);
652     }
653 }
654 
655 void
real_flip()656 X11Display::real_flip ()
657 {
658   if (doublebuffer)
659     {
660       for (std::vector<FlipRect>::iterator i = flip_rects.begin ();
661            i != flip_rects.end ();
662            ++i)
663         {
664           XCopyArea (display, drawable, window, gc,
665                      i->x1, i->y1, // source
666                      i->x2 - i->x1, i->y2 - i->y1, // width/height
667                      i->x1, i->y1 // destination
668                      );
669         }
670       flip_rects.clear ();
671     }
672 }
673 
674 void
flip()675 X11Display::flip ()
676 {
677   if (doublebuffer)
678     {
679       // FIXME: Use another gc here
680       XCopyArea (display, drawable, window, gc,
681                  0, 0, // source
682                  width, height,
683                  0, 0 // destination
684                  );
685       //XFlush(display);
686     }
687 }
688 
689 void
save_mode()690 X11Display::save_mode()
691 {
692 #ifdef HAVE_LIBXXF86VM
693   memset(&orig_modeline, 0, sizeof(orig_modeline));
694 
695   // Get the current display settings for later restore
696   XF86VidModeGetModeLine(display,
697                          DefaultScreen(display),
698                          &orig_dotclock,
699                          &orig_modeline);
700 
701   XF86VidModeGetViewPort(display,
702                          DefaultScreen(display),
703                          &orig_viewport_x,
704                          &orig_viewport_y);
705   std::cout << "save_mode: "
706             << orig_dotclock << " "
707             << orig_viewport_x << ", " << orig_viewport_y << std::endl;
708 
709 #endif /* HAVE_LIBXXF86VM */
710 }
711 
712 void
enter_fullscreen()713 X11Display::enter_fullscreen ()
714 {
715 #ifndef HAVE_LIBXXF86VM
716   std::cout << "X11Display: libXxf86vm missing, fullscreen support not\n"
717             << "            available, please recompile." << std::endl;
718 #else
719   int event_base;
720   int error_base;
721 
722   if (XF86VidModeQueryExtension(display, &event_base, &error_base) != True)
723     {
724       // No VidMode extension available, bailout
725       std::cout << "X11Display: VidMode extension not available, bailout." << std::endl;
726       return;
727     }
728 
729   save_mode();
730 
731   XF86VidModeModeInfo **modes;
732   int nmodes;
733   int mode_index = -1;
734   if (XF86VidModeGetAllModeLines(display,
735                                  DefaultScreen(display),
736                                  &nmodes,&modes)) // FIXME: memleak
737     {
738       std::cout << "VideoModes: (searching for " << width << "x" << height << ")" << std::endl;
739       for (int i = 0; i < nmodes; i++)
740         {
741           //std::cout << i << "  " << mode.Width,mode.Height);
742           std::cout << "  " << modes[i]->hdisplay
743                     << "x" << modes[i]->vdisplay;
744 
745           if (modes[i]->hdisplay == width && modes[i]->vdisplay == height)
746             {
747               std::cout << " <-";
748               mode_index = i;
749             }
750           std::cout << std::endl;
751         }
752 
753       if (mode_index != -1) // Found a good mode
754         {
755           if (0)
756             { // FIXME: doesn't work to change override_redirect after window creation
757               std::cout << "Changing override_redirect" << std::endl;
758               // Switch border away and go to 0,0
759               XSetWindowAttributes attributes;
760               attributes.override_redirect = True;
761               XChangeWindowAttributes(display, window, CWOverrideRedirect, &attributes);
762             }
763 
764           std::cout << "Switching to: "
765                     << modes[mode_index]->hdisplay << "x" << modes[mode_index]->vdisplay
766                     << std::endl;
767 
768           if(XF86VidModeSwitchToMode(display,
769                                      DefaultScreen(display),
770                                      modes[mode_index]))
771             {
772               fullscreen = true;
773 
774               { // Now that we have switched to the correct mode, we
775                 // need to position the Viewport correct to the window
776 
777                 // FIXME: This won't work if the window is partly outside of the screen
778                 Window child_window;
779                 int x, y;
780                 // Get the windows absolute position (aka relative to
781                 // the root window)
782                 XTranslateCoordinates(display, window, DefaultRootWindow(display),
783                                       0, 0,
784                                       &x, &y, &child_window);
785                 XF86VidModeSetViewPort(display, DefaultScreen(display), x, y);
786               }
787 
788               // Hijack the focus (works only till the next focus change)
789               XSetInputFocus(display, window, RevertToParent, CurrentTime);
790 
791               // Capture the pointer
792               if (XGrabPointer(display, window, True, 0, GrabModeAsync, GrabModeAsync,
793                                window, None, CurrentTime) != GrabSuccess)
794                 {
795                   std::cout << "X11Display: Couldn't grab the pointer" << std::endl;
796                 }
797             }
798           else
799             {
800               std::cout << "X11Display: Throuble switiching to fullscreen?!" << std::endl;
801             }
802         }
803       else // No mode found
804         {
805           std::cout << "Disabling override redirect" << std::endl;
806           // Fullscreen not possible, switch Window attributes back to windowed mode
807           XSetWindowAttributes attributes;
808           attributes.override_redirect = False;
809           XChangeWindowAttributes(display, window, CWOverrideRedirect, &attributes);
810 
811           // Remap the Window to let the allow override to take effect
812           XUnmapWindow (display, window);
813           XMapRaised(display, window);
814         }
815     }
816   else
817     {
818       std::cout << "X11Display: Couldn't get available video modes" << std::endl;
819     }
820 #endif
821 }
822 
823 void
run()824 X11Display::run()
825 {
826   while (!ScreenManager::instance ()->is_finished ())
827     {
828       ScreenManager::instance ()->run_once();
829 
830       if (Controller::instance()->is_running())
831         {
832           system_context->sleep (0); // FIXME: limit CPU usage via brute force
833           wait_for_events();
834         }
835       else
836         {
837           wait_for_events_blocking();
838         }
839     }
840 }
841 
842 void
toggle_fullscreen()843 X11Display::toggle_fullscreen()
844 {
845   //std::cout << "Fullscreen state: " << fullscreen << std::endl;
846 
847   if (fullscreen)
848     leave_fullscreen();
849   else
850     enter_fullscreen();
851 }
852 
853 void
leave_fullscreen()854 X11Display::leave_fullscreen()
855 {
856 #ifdef HAVE_LIBXXF86VM
857   std::cout << "X11Display::restore_mode()" << std::endl;
858 
859   XF86VidModeModeInfo modeinfo;
860 
861   modeinfo.dotclock   = orig_dotclock;
862 
863   // Copy XF86VidModeModeLine struct into XF86VidModeModeInfo
864   modeinfo.hdisplay   = orig_modeline.hdisplay;
865   modeinfo.hsyncstart = orig_modeline.hsyncstart;
866   modeinfo.hsyncend   = orig_modeline.hsyncend;
867   modeinfo.htotal     = orig_modeline.htotal;
868   modeinfo.hskew      = orig_modeline.hskew;
869   modeinfo.vdisplay   = orig_modeline.vdisplay;
870   modeinfo.vsyncstart = orig_modeline.vsyncstart;
871   modeinfo.vsyncend   = orig_modeline.vsyncend;
872   modeinfo.vtotal     = orig_modeline.vtotal;
873   modeinfo.flags      = orig_modeline.flags;
874   modeinfo.privsize   = orig_modeline.privsize;
875   modeinfo.c_private  = orig_modeline.c_private;
876 
877   XF86VidModeSwitchToMode(display, DefaultScreen(display),
878                           &modeinfo);
879   XF86VidModeSetViewPort(display, DefaultScreen(display),
880                          orig_viewport_x, orig_viewport_y);
881 
882   XUngrabPointer(display, CurrentTime);
883 
884   fullscreen = false;
885 #endif
886 }
887 
888 void
set_clip_rect(int x1,int y1,int x2,int y2)889 X11Display::set_clip_rect (int x1, int y1, int x2, int y2)
890 {
891   XRectangle rect[1];
892 
893   rect[0].x = x1;
894   rect[0].y = y1;
895   rect[0].width  = x2 - x1 + 1;
896   rect[0].height = y2 - y1 + 1;
897 
898   XSetClipRectangles (display, gc,
899                       0, 0, // clip origin
900                       rect, 1,
901                       Unsorted);
902 }
903 
904 unsigned int
get_color_value(const Color & color)905 X11Display::get_color_value(const Color& color)
906 {
907   switch (depth)
908     {
909     case 32:
910       // FIXME Cast evil?!
911       return static_cast<unsigned int>(color.get_as_rrggbb());
912     case 16:
913       return int(31 * color.b) | (int((63 * color.g)) << 5) | (int((31 * color.r)) << 11);
914     default:
915       { // This is extremly slow!
916         XColor x_color;
917 
918         x_color.red   = int(color.r * 65535);
919         x_color.green = int(color.g * 65535);
920         x_color.blue  = int(color.b * 65535);
921 
922         XAllocColor(display, colormap, &x_color);
923 
924         return x_color.pixel;
925       }
926       break;
927     }
928 }
929 
930 XColor
get_xcolor(const Color & color)931 X11Display::get_xcolor(const Color& color)
932 {
933   XColor x_color;
934 
935   x_color.red   = int(color.r * 65535);
936   x_color.green = int(color.g * 65535);
937   x_color.blue  = int(color.b * 65535);
938 
939   XAllocColor(display, colormap, &x_color);
940 
941   return x_color;
942 
943 }
944 
945 /* EOF */
946