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