00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <iostream>
00021 #include <X11/Xutil.h>
00022 #include <X11/keysym.h>
00023
00024 #include "construo_error.hxx"
00025 #include "config.h"
00026 #include "x11_display.hxx"
00027 #include "settings.hxx"
00028 #include "construo_main.hxx"
00029
00030 #include "controller.hxx"
00031 #include "screen_manager.hxx"
00032
00033 extern ConstruoMain* construo_main;
00034 Atom wm_delete_window;
00035
00036 static char zoom_tool_cursor[] = {
00037 0x00,
00038 0x00,
00039 0x18,
00040 0x3c,
00041 0x3c,
00042 0x18,
00043 0x00,
00044 0x00
00045 };
00046
00047 X11Display::X11Display(int w, int h, bool fullscreen_)
00048 : doublebuffer (settings.doublebuffer),
00049 width(w), height(h), shift_pressed (false), fullscreen (fullscreen_)
00050 {
00051 std::cout << "Opening X11 display" << std::endl;
00052 display = XOpenDisplay(NULL);
00053
00054 if (!display)
00055 throw ConstruoError("X11Display: Couldn't conncet to X server");
00056
00057 int screen = DefaultScreen(display);
00058 XSetWindowAttributes attributes;
00059
00060 attributes.background_pixel = BlackPixel(display, screen);
00061 attributes.border_pixel = WhitePixel(display, screen);
00062 if (fullscreen)
00063 attributes.override_redirect = True;
00064 else
00065 attributes.override_redirect = False;
00066
00067 attributes.event_mask =
00068 KeyPressMask |
00069 KeyReleaseMask |
00070 ExposureMask |
00071 PointerMotionMask |
00072 ButtonPressMask |
00073 ButtonReleaseMask |
00074 StructureNotifyMask |
00075 ExposureMask;
00076
00077 colormap = DefaultColormap (display, screen);
00078 attributes.colormap = colormap;
00079 window = XCreateWindow(display, RootWindow(display, screen),
00080 0,0,
00081 width, height, 0,
00082 CopyFromParent, InputOutput, CopyFromParent,
00083 CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWEventMask | CWColormap,
00084 &attributes);
00085
00086 {
00087 char *title = "Construo " VERSION;
00088
00089 XTextProperty text_property;
00090 XStringListToTextProperty(&title, 1, &text_property);
00091 XSizeHints size_hints;
00092 size_hints.x = 0;
00093 size_hints.y = 0;
00094 size_hints.flags = PSize | PMinSize | PMaxSize;
00095
00096 size_hints.width = width;
00097 size_hints.height = height;
00098
00099 size_hints.min_width = width;
00100 size_hints.min_height = height;
00101 size_hints.max_width = width;
00102 size_hints.max_height = height;
00103
00104 XSetWMProperties(
00105 display,
00106 window,
00107 &text_property,
00108 &text_property,
00109 0,
00110 0,
00111 &size_hints,
00112 0,
00113 0);
00114
00115
00116 wm_delete_window = XInternAtom (display, "WM_DELETE_WINDOW", False);
00117 XSetWMProtocols (display, window, &wm_delete_window, 1);
00118 }
00119
00120 if (doublebuffer)
00121 drawable = XCreatePixmap (display, window, width, height,
00122 DefaultDepth(display, screen));
00123 else
00124 drawable = window;
00125
00126 XMapRaised(display, window);
00127
00128 XGCValues gcv;
00129 gcv.foreground = 0xFFFFFF;
00130 gcv.background = 0x000000;
00131 gcv.line_width = 2;
00132 gc = XCreateGC(display, window,
00133 GCLineWidth | GCForeground | GCBackground,
00134 &gcv);
00135
00136 if (fullscreen)
00137 set_fullscreen (true);
00138
00139 if (0)
00140 {
00141 XColor cursor_fg;
00142 XColor cursor_bg;
00143
00144
00145
00146 Pixmap cursor_pm = XCreateBitmapFromData (display, window, zoom_tool_cursor, 8, 8);
00147 Cursor cursor = XCreatePixmapCursor(display, cursor_pm, None, &cursor_bg, &cursor_fg, 4, 4);
00148 XDefineCursor (display, window, cursor);
00149 }
00150 }
00151
00152 X11Display::~X11Display ()
00153 {
00154 std::cout << "Closing X11 display" << std::endl;
00155 if (fullscreen)
00156 restore_mode ();
00157
00158 if (doublebuffer)
00159 XFreePixmap (display, drawable);
00160
00161 XDestroyWindow (display, window);
00162 XCloseDisplay(display);
00163 }
00164
00165 void
00166 X11Display::draw_lines (std::vector<Line>& lines, Color color, int wide)
00167 {
00168 std::vector<XSegment> segments (lines.size());
00169
00170 for (std::vector<Line>::size_type i = 0; i < lines.size(); ++i)
00171 {
00172 segments[i].x1 = static_cast<short>(lines[i].x1);
00173 segments[i].y1 = static_cast<short>(lines[i].y1);
00174 segments[i].x2 = static_cast<short>(lines[i].x2);
00175 segments[i].y2 = static_cast<short>(lines[i].y2);
00176 }
00177
00178 XDrawSegments(display, drawable, gc, &*segments.begin(), segments.size());
00179 }
00180
00181 void
00182 X11Display::draw_circles(std::vector<Circle>& circles, Color color)
00183 {
00184 std::vector<XArc> arcs (circles.size());
00185 for (std::vector<Circle>::size_type i = 0; i < circles.size(); ++i)
00186 {
00187 arcs[i].x = static_cast<short>(circles[i].x - circles[i].r);
00188 arcs[i].y = static_cast<short>(circles[i].y - circles[i].r);
00189 arcs[i].width = static_cast<short>(2 * circles[i].r);
00190 arcs[i].height = static_cast<short>(2 * circles[i].r);
00191 arcs[i].angle1 = 0;
00192 arcs[i].angle2 = 360 * 64;
00193 }
00194
00195 XSetForeground(display, gc, get_color_value(color));
00196 XFillArcs(display, drawable, gc,
00197 &*arcs.begin(), arcs.size());
00198 }
00199
00200 void
00201 X11Display::draw_line(float x1, float y1, float x2, float y2, Color color, int wide)
00202 {
00203 XSetForeground(display, gc, get_color_value(color));
00204 XDrawLine (display, drawable, gc, (int) x1, (int) y1, (int) x2, (int) y2);
00205 }
00206
00207 void
00208 X11Display::draw_fill_rect(float x1, float y1, float x2, float y2, Color color)
00209 {
00210 XSetForeground(display, gc, get_color_value(color));
00211 XFillRectangle (display, drawable, gc,
00212 int(x1), int(y1),
00213 int(x2 - x1), int(y2 - y1));
00214 }
00215
00216 void
00217 X11Display::draw_fill_circle(float x, float y, float r, Color color)
00218 {
00219
00220 XSetForeground(display, gc, get_color_value(color));
00221 XFillArc(display, drawable, gc,
00222 int(x-r), int(y-r),
00223 int(r*2), int(r*2), 0,
00224 360*64);
00225 }
00226
00227 void
00228 X11Display::draw_circle(float x, float y, float r, Color color)
00229 {
00230
00231 XSetForeground(display, gc, get_color_value(color));
00232 XDrawArc(display, drawable, gc, int(x-r), int(y-r), int(r*2.0f), int(r*2.0f), 0, 360*64);
00233 }
00234
00235 void
00236 X11Display::draw_rect(float x1, float y1, float x2, float y2, Color color)
00237 {
00238 XSetForeground(display, gc, get_color_value(color));
00239 XDrawRectangle (display, drawable, gc,
00240 int(x1), int(y1),
00241 int(x2 - x1), int(y2 - y1));
00242 }
00243
00244 void
00245 X11Display::draw_string(float x, float y, const std::string& str, Color color)
00246 {
00247 XSetForeground(display, gc, get_color_value(color));
00248 XDrawString (display, drawable, gc, int(x), int(y), str.c_str (), str.length ());
00249 }
00250
00251 void
00252 X11Display::draw_string_centered(float x, float y, const std::string& str, Color color)
00253 {
00254 XSetForeground(display, gc, get_color_value(color));
00255 XDrawString (display, drawable, gc,
00256 int(x) - ((str.length() * 6) / 2), int(y),
00257 str.c_str (), str.length ());
00258 }
00259
00260 int
00261 X11Display::get_mouse_x ()
00262 {
00263 return mouse_x;
00264 }
00265
00266 int
00267 X11Display::get_mouse_y ()
00268 {
00269 return mouse_y;
00270 }
00271
00272 bool
00273 X11Display::get_key (int key)
00274 {
00275 return false;
00276 }
00277
00278 void
00279 X11Display::wait_for_events_blocking ()
00280 {
00281 do {
00282 while (read_event () == false);
00283 } while (XPending (display) > 0);
00284 }
00285
00286 void
00287 X11Display::wait_for_events ()
00288 {
00289 while (XPending (display) > 0)
00290 {
00291 read_event ();
00292 }
00293 }
00294
00295 bool
00296 X11Display::read_event ()
00297 {
00298 XEvent event;
00299
00300 XNextEvent (display, &event);
00301
00302 switch (event.type)
00303 {
00304 case MotionNotify:
00305 mouse_x = event.xmotion.x;
00306 mouse_y = event.xmotion.y;
00307 break;
00308
00309 case Expose:
00310 if (event.xexpose.count == 0)
00311 flip ();
00312 break;
00313
00314 case NoExpose:
00315
00316 return false;
00317 break;
00318
00319 case ButtonPress:
00320 {
00321
00322
00323 if (event.xbutton.button == 1)
00324 send_button_press(BUTTON_PRIMARY);
00325 else if (event.xbutton.button == 2)
00326 send_button_press(BUTTON_TERTIARY);
00327 else if (event.xbutton.button == 3)
00328 send_button_press(BUTTON_SECONDARY);
00329 else if (event.xbutton.button == 4)
00330 send_button_press(BUTTON_ZOOM_IN);
00331 else if (event.xbutton.button == 5)
00332 send_button_press(BUTTON_ZOOM_OUT);
00333 }
00334 break;
00335
00336 case ButtonRelease:
00337 {
00338
00339 if (event.xbutton.button == 1)
00340 send_button_release(BUTTON_PRIMARY);
00341 else if (event.xbutton.button == 2)
00342 send_button_release(BUTTON_TERTIARY);
00343 else if (event.xbutton.button == 3)
00344 send_button_release(BUTTON_SECONDARY);
00345 else if (event.xbutton.button == 4)
00346 send_button_release(BUTTON_ZOOM_IN);
00347 else if (event.xbutton.button == 5)
00348 send_button_release(BUTTON_ZOOM_OUT);
00349 }
00350 break;
00351
00352 case KeyPress:
00353 {
00354 KeySym sym = XLookupKeysym(&event.xkey,0);
00355
00356 switch (sym)
00357 {
00358 case XK_Left:
00359 send_button_press(BUTTON_SCROLL_LEFT);
00360 break;
00361
00362 case XK_Right:
00363 send_button_press(BUTTON_SCROLL_RIGHT);
00364 break;
00365
00366 case XK_Up:
00367 send_button_press(BUTTON_SCROLL_UP);
00368 break;
00369
00370 case XK_Down:
00371 send_button_press(BUTTON_SCROLL_DOWN);
00372 break;
00373
00374 case XK_a:
00375 send_button_press(BUTTON_ACTIONCAM);
00376 break;
00377
00378 case XK_o:
00379 send_button_press(BUTTON_HIDEDOTS);
00380 break;
00381
00382 case XK_v:
00383 send_button_press(BUTTON_SETVELOCITY);
00384 break;
00385
00386 case XK_Shift_L:
00387 case XK_Shift_R:
00388 shift_pressed = true;
00389 break;
00390 case XK_m:
00391 send_button_press(BUTTON_MODE_CHANGE);
00392 break;
00393 case XK_f:
00394 send_button_press(BUTTON_FIX);
00395 break;
00396 case XK_h:
00397 send_button_press(BUTTON_FLIP);
00398 break;
00399 case XK_c:
00400 send_button_press(BUTTON_CLEAR);
00401 break;
00402 case XK_Delete:
00403 send_button_press(BUTTON_DELETE);
00404 break;
00405 case XK_Escape:
00406 send_button_press(BUTTON_ESCAPE);
00407 break;
00408 case XK_u:
00409 send_button_press(BUTTON_UNDO);
00410 break;
00411 case XK_r:
00412 send_button_press(BUTTON_REDO);
00413 break;
00414 case XK_d:
00415 send_button_press(BUTTON_DUPLICATE);
00416 break;
00417 case XK_space:
00418 send_button_press(BUTTON_RUN);
00419 break;
00420 case XK_Tab:
00421 send_button_press(BUTTON_TOGGLESLOWMO);
00422 break;
00423 case 65451:
00424 case XK_equal:
00425 case XK_plus:
00426 send_button_press(BUTTON_ZOOM_IN);
00427 break;
00428 case 65453:
00429 case XK_minus:
00430 send_button_press(BUTTON_ZOOM_OUT);
00431 break;
00432 case XK_0:
00433 send_load_or_save(0);
00434 break;
00435 case XK_1:
00436 send_load_or_save(1);
00437 break;
00438 case XK_2:
00439 send_load_or_save(2);
00440 break;
00441 case XK_3:
00442 send_load_or_save(3);
00443 break;
00444 case XK_4:
00445 send_load_or_save(4);
00446 break;
00447 case XK_5:
00448 send_load_or_save(5);
00449 break;
00450 case XK_6:
00451 send_load_or_save(6);
00452 break;
00453 case XK_7:
00454 send_load_or_save(7);
00455 break;
00456 case XK_8:
00457 send_load_or_save(8);
00458 break;
00459 case XK_9:
00460 send_load_or_save(9);
00461 break;
00462
00463 default:
00464 std::cout << "X11Display: unhandled keypress: " << sym << " " << XK_grave << std::endl;
00465 break;
00466 }
00467 }
00468 break;
00469
00470 case KeyRelease:
00471 {
00472 KeySym sym = XLookupKeysym(&event.xkey,0);
00473
00474 switch (sym)
00475 {
00476 case XK_Shift_L:
00477 case XK_Shift_R:
00478 shift_pressed = false;
00479 break;
00480 default:
00481
00482 break;
00483 }
00484 }
00485 break;
00486
00487 case ConfigureNotify:
00488
00489
00490 break;
00491
00492 case DestroyNotify:
00493 std::cout << "Window got destroyed" << std::endl;
00494 break;
00495
00496 case ClientMessage:
00497 std::cout << "X11Display: got client message" << std::endl;
00498
00499 if ((int) event.xclient.data.l[0] == (int) wm_delete_window) {
00500 std::cout << "Window is destroyed" << std::endl;
00501 send_button_press(BUTTON_ESCAPE);
00502 }
00503 break;
00504
00505 default:
00506 std::cout << "X11Display: Unhandled event: " << event.type << std::endl;
00507 break;
00508 }
00509 return true;
00510 }
00511
00512 void
00513 X11Display::send_load_or_save(int n)
00514 {
00515 if (shift_pressed)
00516 send_button_press(BUTTON_QUICKLOAD0 + n);
00517 else
00518 send_button_press(BUTTON_QUICKSAVE0 + n);
00519 }
00520
00521 void
00522 X11Display::send_button_press (int i)
00523 {
00524 Event ev;
00525 ev.button.type = BUTTON_EVENT;
00526 ev.button.id = i;
00527 ev.button.pressed = true;
00528 events.push(ev);
00529 }
00530
00531 void
00532 X11Display::send_button_release (int i)
00533 {
00534 Event ev;
00535 ev.button.type = BUTTON_EVENT;
00536 ev.button.id = i;
00537 ev.button.pressed = false;
00538 events.push(ev);
00539 }
00540
00541 void
00542 X11Display::clear ()
00543 {
00544 XSetForeground (display, gc, 0x000000);
00545 XFillRectangle (display, drawable, gc, 0, 0, width, height);
00546 }
00547
00548 void
00549 X11Display::flip (int x1, int y1, int x2, int y2)
00550 {
00551 if (doublebuffer)
00552 {
00553 FlipRect flip_rect;
00554
00555 flip_rect.x1 = x1;
00556 flip_rect.y1 = y1;
00557 flip_rect.x2 = x2;
00558 flip_rect.y2 = y2;
00559
00560
00561 }
00562 }
00563
00564 void
00565 X11Display::real_flip ()
00566 {
00567 if (doublebuffer)
00568 {
00569 for (std::vector<FlipRect>::iterator i = flip_rects.begin ();
00570 i != flip_rects.end ();
00571 ++i)
00572 {
00573 XCopyArea (display, drawable, window, gc,
00574 i->x1, i->y1,
00575 i->x2 - i->x1, i->y2 - i->y1,
00576 i->x1, i->y1
00577 );
00578 }
00579 flip_rects.clear ();
00580 }
00581 }
00582
00583 void
00584 X11Display::flip ()
00585 {
00586 if (doublebuffer)
00587 {
00588
00589 XCopyArea (display, drawable, window, gc,
00590 0, 0,
00591 width, height,
00592 0, 0
00593 );
00594
00595 }
00596 }
00597
00598 void
00599 X11Display::set_fullscreen (bool fullscreen)
00600 {
00601 #ifdef HAVE_LIBXXF86VM
00602 int event_base;
00603 int error_base;
00604 if (XF86VidModeQueryExtension(display, &event_base, &error_base) != True)
00605 {
00606
00607 std::cout << "X11Display: VidMode extension not available, bailout." << std::endl;
00608 return;
00609 }
00610
00611 int screen = DefaultScreen(display);
00612
00613 memset(&orig_modeline, 0, sizeof(orig_modeline));
00614
00615 XF86VidModeGetModeLine(display,
00616 screen,
00617 &orig_dotclock,
00618 &orig_modeline);
00619
00620 XF86VidModeGetViewPort(display,
00621 screen,
00622 &orig_viewport_x,
00623 &orig_viewport_y);
00624
00625 XF86VidModeModeInfo **modes;
00626 int nmodes;
00627 int mode_index = -1;
00628 if (XF86VidModeGetAllModeLines(display,
00629 screen,
00630 &nmodes,&modes))
00631 {
00632 std::cout << "VideoModes: (searching for " << width << "x" << height << ")" << std::endl;
00633 for (int i = 0; i < nmodes; i++)
00634 {
00635
00636 std::cout << " " << modes[i]->hdisplay
00637 << "x" << modes[i]->vdisplay;
00638
00639 if (modes[i]->hdisplay == width && modes[i]->vdisplay == height)
00640 {
00641 std::cout << " <-";
00642 mode_index = i;
00643 }
00644 std::cout << std::endl;
00645 }
00646
00647 if (mode_index != -1)
00648 {
00649 if (0)
00650 {
00651 std::cout << "Changing override_redirect" << std::endl;
00652
00653 XSetWindowAttributes attributes;
00654 attributes.override_redirect = True;
00655 XChangeWindowAttributes(display, window, CWOverrideRedirect, &attributes);
00656 }
00657
00658 std::cout << "Switching to: "
00659 << modes[mode_index]->hdisplay << "x" << modes[mode_index]->vdisplay
00660 << std::endl;
00661
00662 if(XF86VidModeSwitchToMode(display,
00663 screen,
00664 modes[mode_index]))
00665 {
00666 XF86VidModeSetViewPort(display, screen, 0, 0);
00667
00668 XSetInputFocus(display, window, RevertToParent, CurrentTime);
00669
00670
00671 if (XGrabPointer(display, window, true, 0, GrabModeAsync, GrabModeAsync, window, None, CurrentTime)
00672 != GrabSuccess)
00673 {
00674 std::cout << "X11Display: Couldn't grab the pointer" << std::endl;
00675 }
00676 }
00677 }
00678 else
00679 {
00680 std::cout << "Disabling override redirect" << std::endl;
00681
00682 XSetWindowAttributes attributes;
00683 attributes.override_redirect = False;
00684 XChangeWindowAttributes(display, window, CWOverrideRedirect, &attributes);
00685
00686
00687 XUnmapWindow (display, window);
00688 XMapRaised(display, window);
00689 }
00690 }
00691 else
00692 {
00693 std::cout << "X11Display: Couldn't get available video modes" << std::endl;
00694 }
00695 #endif
00696 }
00697
00698 void
00699 X11Display::run()
00700 {
00701 while (!ScreenManager::instance ()->is_finished ())
00702 {
00703 if (Controller::instance()->is_running())
00704 {
00705 system_context->sleep (0);
00706 wait_for_events();
00707 }
00708 else
00709 {
00710 wait_for_events_blocking();
00711 }
00712 ScreenManager::instance ()->run_once();
00713 }
00714 }
00715
00716 void
00717 X11Display::restore_mode ()
00718 {
00719 #ifdef HAVE_LIBXXF86VM
00720 XF86VidModeModeInfo modeinfo;
00721
00722 modeinfo.dotclock = orig_dotclock;
00723
00724
00725 modeinfo.hdisplay = orig_modeline.hdisplay;
00726 modeinfo.hsyncstart = orig_modeline.hsyncstart;
00727 modeinfo.hsyncend = orig_modeline.hsyncend;
00728 modeinfo.htotal = orig_modeline.htotal;
00729 modeinfo.hskew = orig_modeline.hskew;
00730 modeinfo.vdisplay = orig_modeline.vdisplay;
00731 modeinfo.vsyncstart = orig_modeline.vsyncstart;
00732 modeinfo.vsyncend = orig_modeline.vsyncend;
00733 modeinfo.vtotal = orig_modeline.vtotal;
00734 modeinfo.flags = orig_modeline.flags;
00735 modeinfo.privsize = orig_modeline.privsize;
00736 modeinfo.c_private = orig_modeline.c_private;
00737
00738 XF86VidModeSwitchToMode(display, DefaultScreen(display),
00739 &modeinfo);
00740 XF86VidModeSetViewPort(display, DefaultScreen(display),
00741 orig_viewport_x, orig_viewport_y);
00742
00743 fullscreen = false;
00744 #endif
00745 }
00746
00747 void
00748 X11Display::set_clip_rect (int x1, int y1, int x2, int y2)
00749 {
00750 XRectangle rect[1];
00751
00752 rect[0].x = x1;
00753 rect[0].y = y1;
00754 rect[0].width = x2 - x1 + 1;
00755 rect[0].height = y2 - y1 + 1;
00756
00757 XSetClipRectangles (display, gc,
00758 0, 0,
00759 rect, 1,
00760 Unsorted);
00761 }
00762
00763 unsigned int
00764 X11Display::get_color_value(Color& color)
00765 {
00766 XColor x_color;
00767
00768 x_color.red = int(color.r * 65535);
00769 x_color.green = int(color.g * 65535);
00770 x_color.blue = int(color.b * 65535);
00771
00772 XAllocColor(display, colormap, &x_color);
00773
00774 return x_color.pixel;
00775 }
00776
00777