00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "x11GraphicsWindow.h"
00016 #include "config_x11display.h"
00017 #include "x11GraphicsPipe.h"
00018
00019 #include "graphicsPipe.h"
00020 #include "keyboardButton.h"
00021 #include "mouseButton.h"
00022 #include "clockObject.h"
00023 #include "pStatTimer.h"
00024 #include "textEncoder.h"
00025 #include "throw_event.h"
00026 #include "lightReMutexHolder.h"
00027 #include "nativeWindowHandle.h"
00028 #include "virtualFileSystem.h"
00029 #include "get_x11.h"
00030
00031 #include <errno.h>
00032 #include <fcntl.h>
00033 #include <sys/time.h>
00034
00035 #ifdef HAVE_LINUX_INPUT_H
00036 #include <linux/input.h>
00037 #endif
00038
00039 #ifdef HAVE_XCURSOR
00040 static int xcursor_read(XcursorFile *file, unsigned char *buf, int len) {
00041 istream* str = (istream*) file->closure;
00042 str->read((char*) buf, len);
00043 return str->gcount();
00044 }
00045
00046 static int xcursor_write(XcursorFile *file, unsigned char *buf, int len) {
00047
00048 nassertr_always(false, 0);
00049 }
00050
00051 static int xcursor_seek(XcursorFile *file, long offset, int whence) {
00052 istream* str = (istream*) file->closure;
00053 switch (whence) {
00054 case SEEK_SET:
00055 str->seekg(offset, istream::beg);
00056 break;
00057 case SEEK_CUR:
00058 str->seekg(offset, istream::cur);
00059 break;
00060 case SEEK_END:
00061 str->seekg(offset, istream::end);
00062 }
00063
00064 return str->tellg();
00065 }
00066 #endif
00067
00068 TypeHandle x11GraphicsWindow::_type_handle;
00069
00070 #define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)&7)))
00071
00072
00073
00074
00075
00076
00077 x11GraphicsWindow::
00078 x11GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
00079 const string &name,
00080 const FrameBufferProperties &fb_prop,
00081 const WindowProperties &win_prop,
00082 int flags,
00083 GraphicsStateGuardian *gsg,
00084 GraphicsOutput *host) :
00085 GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00086 {
00087 x11GraphicsPipe *x11_pipe;
00088 DCAST_INTO_V(x11_pipe, _pipe);
00089 _display = x11_pipe->get_display();
00090 _screen = x11_pipe->get_screen();
00091 _xwindow = (X11_Window)NULL;
00092 _ic = (XIC)NULL;
00093 _visual_info = NULL;
00094
00095 #ifdef HAVE_XRANDR
00096 _orig_size_id = -1;
00097 int event, error;
00098 _have_xrandr = XRRQueryExtension(_display, &event, &error);
00099 #else
00100 _have_xrandr = false;
00101 #endif
00102
00103 _awaiting_configure = false;
00104 _dga_mouse_enabled = false;
00105 _wm_delete_window = x11_pipe->_wm_delete_window;
00106 _net_wm_window_type = x11_pipe->_net_wm_window_type;
00107 _net_wm_window_type_splash = x11_pipe->_net_wm_window_type_splash;
00108 _net_wm_window_type_fullscreen = x11_pipe->_net_wm_window_type_fullscreen;
00109 _net_wm_state = x11_pipe->_net_wm_state;
00110 _net_wm_state_fullscreen = x11_pipe->_net_wm_state_fullscreen;
00111 _net_wm_state_above = x11_pipe->_net_wm_state_above;
00112 _net_wm_state_below = x11_pipe->_net_wm_state_below;
00113 _net_wm_state_add = x11_pipe->_net_wm_state_add;
00114 _net_wm_state_remove = x11_pipe->_net_wm_state_remove;
00115
00116 GraphicsWindowInputDevice device =
00117 GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
00118 add_input_device(device);
00119 }
00120
00121
00122
00123
00124
00125
00126 x11GraphicsWindow::
00127 ~x11GraphicsWindow() {
00128 pmap<Filename, X11_Cursor>::iterator it;
00129
00130 for (it = _cursor_filenames.begin(); it != _cursor_filenames.end(); it++) {
00131 XFreeCursor(_display, it->second);
00132 }
00133 }
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 bool x11GraphicsWindow::
00146 move_pointer(int device, int x, int y) {
00147
00148
00149 if (device == 0) {
00150
00151 if (!_properties.get_foreground() ||
00152 !_input_devices[0].get_pointer().get_in_window()) {
00153
00154
00155 return false;
00156 }
00157
00158 const MouseData &md = _input_devices[0].get_pointer();
00159 if (!md.get_in_window() || md.get_x() != x || md.get_y() != y) {
00160 if (!_dga_mouse_enabled) {
00161 XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y);
00162 }
00163 _input_devices[0].set_pointer_in_window(x, y);
00164 }
00165 return true;
00166 } else {
00167
00168 if ((device < 1)||(device >= _input_devices.size())) {
00169 return false;
00170 }
00171 _input_devices[device].set_pointer_in_window(x, y);
00172 return true;
00173 }
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 bool x11GraphicsWindow::
00187 begin_frame(FrameMode mode, Thread *current_thread) {
00188 PStatTimer timer(_make_current_pcollector, current_thread);
00189
00190 begin_frame_spam(mode);
00191 if (_gsg == (GraphicsStateGuardian *)NULL) {
00192 return false;
00193 }
00194 if (_awaiting_configure) {
00195
00196
00197 return false;
00198 }
00199
00200
00201
00202
00203 _gsg->reset_if_new();
00204
00205 if (mode == FM_render) {
00206
00207 clear_cube_map_selection();
00208 }
00209
00210 _gsg->set_current_properties(&get_fb_properties());
00211 return _gsg->begin_frame(current_thread);
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221 void x11GraphicsWindow::
00222 end_frame(FrameMode mode, Thread *current_thread) {
00223 end_frame_spam(mode);
00224 nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00225
00226 if (mode == FM_render) {
00227
00228 copy_to_textures();
00229 }
00230
00231 _gsg->end_frame(current_thread);
00232
00233 if (mode == FM_render) {
00234 trigger_flip();
00235 clear_cube_map_selection();
00236 }
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 void x11GraphicsWindow::
00250 process_events() {
00251 LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
00252
00253 GraphicsWindow::process_events();
00254
00255 if (_xwindow == (X11_Window)0) {
00256 return;
00257 }
00258
00259 poll_raw_mice();
00260
00261 XEvent event;
00262 XKeyEvent keyrelease_event;
00263 bool got_keyrelease_event = false;
00264
00265 while (XCheckIfEvent(_display, &event, check_event, (char *)this)) {
00266 if (XFilterEvent(&event, None)) {
00267 continue;
00268 }
00269
00270 if (got_keyrelease_event) {
00271
00272
00273
00274
00275
00276 got_keyrelease_event = false;
00277
00278 if (event.type == KeyPress &&
00279 event.xkey.keycode == keyrelease_event.keycode &&
00280 (event.xkey.time - keyrelease_event.time <= 1)) {
00281
00282
00283 handle_keystroke(event.xkey);
00284
00285
00286
00287 handle_keypress(event.xkey);
00288 continue;
00289
00290 } else {
00291
00292
00293 handle_keyrelease(keyrelease_event);
00294 }
00295 }
00296
00297 WindowProperties properties;
00298 ButtonHandle button;
00299
00300 switch (event.type) {
00301 case ReparentNotify:
00302 break;
00303
00304 case ConfigureNotify:
00305 _awaiting_configure = false;
00306
00307
00308
00309
00310
00311
00312
00313 properties.set_origin(event.xconfigure.x, event.xconfigure.y);
00314
00315 if (_properties.get_fixed_size()) {
00316
00317
00318
00319
00320
00321
00322 WindowProperties current_props = get_properties();
00323 if (event.xconfigure.width != current_props.get_x_size() ||
00324 event.xconfigure.height != current_props.get_y_size()) {
00325 XWindowChanges changes;
00326 changes.width = current_props.get_x_size();
00327 changes.height = current_props.get_y_size();
00328 int value_mask = (CWWidth | CWHeight);
00329 XConfigureWindow(_display, _xwindow, value_mask, &changes);
00330 }
00331
00332 } else {
00333
00334 properties.set_size(event.xconfigure.width, event.xconfigure.height);
00335 }
00336 system_changed_properties(properties);
00337 break;
00338
00339 case ButtonPress:
00340
00341 button = get_mouse_button(event.xbutton);
00342 if (!_dga_mouse_enabled) {
00343 _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
00344 }
00345 _input_devices[0].button_down(button);
00346 break;
00347
00348 case ButtonRelease:
00349 button = get_mouse_button(event.xbutton);
00350 if (!_dga_mouse_enabled) {
00351 _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
00352 }
00353 _input_devices[0].button_up(button);
00354 break;
00355
00356 case MotionNotify:
00357 if (_dga_mouse_enabled) {
00358 const MouseData &md = _input_devices[0].get_raw_pointer();
00359 _input_devices[0].set_pointer_in_window(md.get_x() + event.xmotion.x_root, md.get_y() + event.xmotion.y_root);
00360 } else {
00361 _input_devices[0].set_pointer_in_window(event.xmotion.x, event.xmotion.y);
00362 }
00363 break;
00364
00365 case KeyPress:
00366 handle_keystroke(event.xkey);
00367 handle_keypress(event.xkey);
00368 break;
00369
00370 case KeyRelease:
00371
00372
00373
00374 keyrelease_event = event.xkey;
00375 got_keyrelease_event = true;
00376 break;
00377
00378 case EnterNotify:
00379 if (_dga_mouse_enabled) {
00380 const MouseData &md = _input_devices[0].get_raw_pointer();
00381 _input_devices[0].set_pointer_in_window(md.get_x(), md.get_y());
00382 } else {
00383 _input_devices[0].set_pointer_in_window(event.xcrossing.x, event.xcrossing.y);
00384 }
00385 break;
00386
00387 case LeaveNotify:
00388 _input_devices[0].set_pointer_out_of_window();
00389 break;
00390
00391 case FocusIn:
00392 properties.set_foreground(true);
00393 system_changed_properties(properties);
00394 break;
00395
00396 case FocusOut:
00397 _input_devices[0].focus_lost();
00398 properties.set_foreground(false);
00399 system_changed_properties(properties);
00400 break;
00401
00402 case UnmapNotify:
00403 properties.set_minimized(true);
00404 system_changed_properties(properties);
00405 break;
00406
00407 case MapNotify:
00408 properties.set_minimized(false);
00409 system_changed_properties(properties);
00410
00411
00412 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
00413 break;
00414
00415 case ClientMessage:
00416 if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) {
00417
00418
00419 string close_request_event = get_close_request_event();
00420 if (!close_request_event.empty()) {
00421
00422
00423 throw_event(close_request_event);
00424
00425 } else {
00426
00427
00428
00429
00430 close_window();
00431 properties.set_open(false);
00432 system_changed_properties(properties);
00433 }
00434 }
00435 break;
00436
00437 case DestroyNotify:
00438
00439
00440
00441 x11display_cat.info()
00442 << "DestroyNotify\n";
00443 break;
00444
00445 default:
00446 x11display_cat.warning()
00447 << "unhandled X event type " << event.type << "\n";
00448 }
00449 }
00450
00451 if (got_keyrelease_event) {
00452
00453
00454 handle_keyrelease(keyrelease_event);
00455 }
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 void x11GraphicsWindow::
00476 set_properties_now(WindowProperties &properties) {
00477 if (_pipe == (GraphicsPipe *)NULL) {
00478
00479 GraphicsWindow::set_properties_now(properties);
00480 return;
00481 }
00482
00483 x11GraphicsPipe *x11_pipe;
00484 DCAST_INTO_V(x11_pipe, _pipe);
00485
00486
00487 if (properties.has_fullscreen()) {
00488 if (properties.get_fullscreen()) {
00489 if (_have_xrandr) {
00490 #ifdef HAVE_XRANDR
00491 XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, x11_pipe->get_root());
00492 if (_orig_size_id == (SizeID) -1) {
00493 _orig_size_id = XRRConfigCurrentConfiguration(conf, &_orig_rotation);
00494 }
00495 int num_sizes, reqsizex, reqsizey, new_size_id = -1;
00496 if (properties.has_size()) {
00497 reqsizex = properties.get_x_size();
00498 reqsizey = properties.get_y_size();
00499 } else {
00500 reqsizex = _properties.get_x_size();
00501 reqsizey = _properties.get_y_size();
00502 }
00503 XRRScreenSize *xrrs;
00504 xrrs = XRRSizes(_display, 0, &num_sizes);
00505 for (int i = 0; i < num_sizes; ++i) {
00506 if (xrrs[i].width == properties.get_x_size() &&
00507 xrrs[i].height == properties.get_y_size()) {
00508 new_size_id = i;
00509 }
00510 }
00511 if (new_size_id == -1) {
00512 x11display_cat.error()
00513 << "Videocard has no supported display resolutions at specified res ("
00514 << reqsizex << " x " << reqsizey <<")\n";
00515 _orig_size_id = -1;
00516 } else {
00517 if (new_size_id != _orig_size_id) {
00518 XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime);
00519 } else {
00520 _orig_size_id = -1;
00521 }
00522 }
00523 #endif
00524 } else {
00525
00526
00527 properties.set_size(x11_pipe->get_display_width(),
00528 x11_pipe->get_display_height());
00529 }
00530 } else {
00531 #ifdef HAVE_XRANDR
00532
00533
00534 if (_have_xrandr && _orig_size_id != (SizeID) -1) {
00535 XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, x11_pipe->get_root());
00536 XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), _orig_size_id, _orig_rotation, CurrentTime);
00537 _orig_size_id = -1;
00538 }
00539 #endif
00540
00541 if (!properties.has_origin() && _properties.has_origin()) {
00542 properties.set_origin(_properties.get_x_origin(), _properties.get_y_origin());
00543 }
00544 }
00545 }
00546
00547 if (properties.has_origin()) {
00548
00549 if (properties.get_x_origin() == -2 || properties.get_y_origin() == -2) {
00550 int x_origin = properties.get_x_origin();
00551 int y_origin = properties.get_y_origin();
00552 if (properties.has_size()) {
00553 if (x_origin == -2) {
00554 x_origin = 0.5 * (x11_pipe->get_display_width() - properties.get_x_size());
00555 }
00556 if (y_origin == -2) {
00557 y_origin = 0.5 * (x11_pipe->get_display_height() - properties.get_y_size());
00558 }
00559 } else {
00560 if (x_origin == -2) {
00561 x_origin = 0.5 * (x11_pipe->get_display_width() - _properties.get_x_size());
00562 }
00563 if (y_origin == -2) {
00564 y_origin = 0.5 * (x11_pipe->get_display_height() - _properties.get_y_size());
00565 }
00566 }
00567 properties.set_origin(x_origin, y_origin);
00568 }
00569 }
00570
00571 GraphicsWindow::set_properties_now(properties);
00572 if (!properties.is_any_specified()) {
00573
00574 return;
00575 }
00576
00577
00578
00579
00580
00581 WindowProperties wm_properties = _properties;
00582 wm_properties.add_properties(properties);
00583
00584
00585
00586 if (properties.has_title()) {
00587 _properties.set_title(properties.get_title());
00588 properties.clear_title();
00589 }
00590
00591
00592 if (properties.has_fullscreen()) {
00593 _properties.set_fullscreen(properties.get_fullscreen());
00594 properties.clear_fullscreen();
00595 }
00596
00597
00598
00599
00600
00601 XWindowChanges changes;
00602 int value_mask = 0;
00603
00604 if (_properties.get_fullscreen()) {
00605 changes.x = 0;
00606 changes.y = 0;
00607 value_mask |= CWX | CWY;
00608 properties.clear_origin();
00609 } else if (properties.has_origin()) {
00610 changes.x = properties.get_x_origin();
00611 changes.y = properties.get_y_origin();
00612 if (changes.x != -1) value_mask |= CWX;
00613 if (changes.y != -1) value_mask |= CWY;
00614 properties.clear_origin();
00615 }
00616
00617 if (properties.has_size()) {
00618 changes.width = properties.get_x_size();
00619 changes.height = properties.get_y_size();
00620 value_mask |= (CWWidth | CWHeight);
00621 properties.clear_size();
00622 }
00623
00624 if (properties.has_z_order()) {
00625
00626
00627
00628
00629 _properties.set_z_order(properties.get_z_order());
00630 switch (properties.get_z_order()) {
00631 case WindowProperties::Z_bottom:
00632 changes.stack_mode = Below;
00633 break;
00634
00635 case WindowProperties::Z_normal:
00636 changes.stack_mode = TopIf;
00637 break;
00638
00639 case WindowProperties::Z_top:
00640 changes.stack_mode = Above;
00641 break;
00642 }
00643
00644 value_mask |= (CWStackMode);
00645 properties.clear_z_order();
00646 }
00647
00648 if (value_mask != 0) {
00649 XReconfigureWMWindow(_display, _xwindow, _screen, value_mask, &changes);
00650
00651
00652 _awaiting_configure = true;
00653 }
00654
00655
00656
00657 if (properties.has_cursor_hidden() || properties.has_cursor_filename()) {
00658 if (properties.has_cursor_hidden()) {
00659 _properties.set_cursor_hidden(properties.get_cursor_hidden());
00660 properties.clear_cursor_hidden();
00661 }
00662 Filename cursor_filename;
00663 if (properties.has_cursor_filename()) {
00664 cursor_filename = properties.get_cursor_filename();
00665 _properties.set_cursor_filename(cursor_filename);
00666 properties.clear_cursor_filename();
00667 }
00668 Filename filename = properties.get_cursor_filename();
00669 _properties.set_cursor_filename(filename);
00670
00671 if (_properties.get_cursor_hidden()) {
00672 XDefineCursor(_display, _xwindow, x11_pipe->get_hidden_cursor());
00673
00674 } else if (!cursor_filename.empty()) {
00675
00676 X11_Cursor cursor = get_cursor(cursor_filename);
00677 XDefineCursor(_display, _xwindow, cursor);
00678
00679 } else {
00680 XDefineCursor(_display, _xwindow, None);
00681 }
00682 }
00683
00684 if (properties.has_foreground()) {
00685 if (properties.get_foreground()) {
00686 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
00687 } else {
00688 XSetInputFocus(_display, PointerRoot, RevertToPointerRoot, CurrentTime);
00689 }
00690 properties.clear_foreground();
00691 }
00692
00693 set_wm_properties(wm_properties, true);
00694 }
00695
00696
00697
00698
00699
00700
00701 void x11GraphicsWindow::
00702 mouse_mode_absolute() {
00703 #ifdef HAVE_XF86DGA
00704 if (!_dga_mouse_enabled) return;
00705
00706 XUngrabPointer(_display, CurrentTime);
00707 x11display_cat.info() << "Disabling relative mouse using XF86DGA extension\n";
00708 XF86DGADirectVideo(_display, _screen, 0);
00709 _dga_mouse_enabled = false;
00710 #endif
00711 }
00712
00713
00714
00715
00716
00717
00718 void x11GraphicsWindow::
00719 mouse_mode_relative() {
00720 #ifdef HAVE_XF86DGA
00721 if (_dga_mouse_enabled) return;
00722
00723 int major_ver, minor_ver;
00724 if (XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) {
00725
00726 X11_Cursor cursor = None;
00727 if (_properties.get_cursor_hidden()) {
00728 x11GraphicsPipe *x11_pipe;
00729 DCAST_INTO_V(x11_pipe, _pipe);
00730 cursor = x11_pipe->get_hidden_cursor();
00731 }
00732
00733 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
00734 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
00735 x11display_cat.error() << "Failed to grab pointer!\n";
00736 return;
00737 }
00738
00739 x11display_cat.info() << "Enabling relative mouse using XF86DGA extension\n";
00740 XF86DGADirectVideo(_display, _screen, XF86DGADirectMouse);
00741
00742 _dga_mouse_enabled = true;
00743 } else {
00744 x11display_cat.info() << "XF86DGA extension not available\n";
00745 _dga_mouse_enabled = false;
00746 }
00747
00748
00749
00750 XEvent event;
00751 XQueryPointer(_display, _xwindow, &event.xbutton.root,
00752 &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
00753 &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
00754 _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
00755 #endif
00756 }
00757
00758
00759
00760
00761
00762
00763
00764 void x11GraphicsWindow::
00765 close_window() {
00766 if (_gsg != (GraphicsStateGuardian *)NULL) {
00767 _gsg.clear();
00768 }
00769
00770 if (_ic != (XIC)NULL) {
00771 XDestroyIC(_ic);
00772 _ic = (XIC)NULL;
00773 }
00774
00775 if (_xwindow != (X11_Window)NULL) {
00776 XDestroyWindow(_display, _xwindow);
00777 _xwindow = (X11_Window)NULL;
00778
00779
00780
00781 XFlush(_display);
00782 }
00783
00784 #ifdef HAVE_XRANDR
00785
00786
00787 if (_have_xrandr && _orig_size_id != (SizeID) -1) {
00788 X11_Window root;
00789 if (_pipe != NULL) {
00790 x11GraphicsPipe *x11_pipe;
00791 DCAST_INTO_V(x11_pipe, _pipe);
00792 root = x11_pipe->get_root();
00793 } else {
00794
00795
00796
00797 root = RootWindow(_display, _screen);
00798 }
00799 XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, root);
00800 XRRSetScreenConfig(_display, conf, root, _orig_size_id, _orig_rotation, CurrentTime);
00801 _orig_size_id = -1;
00802 }
00803 #endif
00804
00805 GraphicsWindow::close_window();
00806 }
00807
00808
00809
00810
00811
00812
00813
00814
00815 bool x11GraphicsWindow::
00816 open_window() {
00817 if (_visual_info == NULL) {
00818
00819 x11display_cat.error()
00820 << "No X visual: cannot open window.\n";
00821 return false;
00822 }
00823
00824 x11GraphicsPipe *x11_pipe;
00825 DCAST_INTO_R(x11_pipe, _pipe, false);
00826
00827 if (!_properties.has_origin()) {
00828 _properties.set_origin(0, 0);
00829 }
00830 if (!_properties.has_size()) {
00831 _properties.set_size(100, 100);
00832 }
00833
00834 #ifdef HAVE_XRANDR
00835 if (_properties.get_fullscreen() && _have_xrandr) {
00836 XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, x11_pipe->get_root());
00837 if (_orig_size_id == (SizeID) -1) {
00838 _orig_size_id = XRRConfigCurrentConfiguration(conf, &_orig_rotation);
00839 }
00840 int num_sizes, new_size_id = -1;
00841 XRRScreenSize *xrrs;
00842 xrrs = XRRSizes(_display, 0, &num_sizes);
00843 for (int i = 0; i < num_sizes; ++i) {
00844 if (xrrs[i].width == _properties.get_x_size() &&
00845 xrrs[i].height == _properties.get_y_size()) {
00846 new_size_id = i;
00847 }
00848 }
00849 if (new_size_id == -1) {
00850 x11display_cat.error()
00851 << "Videocard has no supported display resolutions at specified res ("
00852 << _properties.get_x_size() << " x " << _properties.get_y_size() <<")\n";
00853 _orig_size_id = -1;
00854 return false;
00855 }
00856 if (new_size_id != _orig_size_id) {
00857 XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime);
00858 } else {
00859 _orig_size_id = -1;
00860 }
00861 }
00862 #endif
00863
00864 X11_Window parent_window = x11_pipe->get_root();
00865 WindowHandle *window_handle = _properties.get_parent_window();
00866 if (window_handle != NULL) {
00867 x11display_cat.info()
00868 << "Got parent_window " << *window_handle << "\n";
00869 WindowHandle::OSHandle *os_handle = window_handle->get_os_handle();
00870 if (os_handle != NULL) {
00871 x11display_cat.info()
00872 << "os_handle type " << os_handle->get_type() << "\n";
00873
00874 if (os_handle->is_of_type(NativeWindowHandle::X11Handle::get_class_type())) {
00875 NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle);
00876 parent_window = x11_handle->get_handle();
00877 } else if (os_handle->is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
00878 NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle);
00879 parent_window = (X11_Window)int_handle->get_handle();
00880 }
00881 }
00882 }
00883 _parent_window_handle = window_handle;
00884
00885 _event_mask =
00886 ButtonPressMask | ButtonReleaseMask |
00887 KeyPressMask | KeyReleaseMask |
00888 EnterWindowMask | LeaveWindowMask |
00889 PointerMotionMask |
00890 FocusChangeMask | StructureNotifyMask;
00891
00892
00893 XSetWindowAttributes wa;
00894 wa.background_pixel = XBlackPixel(_display, _screen);
00895 wa.border_pixel = 0;
00896 wa.colormap = _colormap;
00897 wa.event_mask = _event_mask;
00898
00899 unsigned long attrib_mask =
00900 CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
00901
00902 _xwindow = XCreateWindow
00903 (_display, parent_window,
00904 _properties.get_x_origin(), _properties.get_y_origin(),
00905 _properties.get_x_size(), _properties.get_y_size(),
00906 0, _visual_info->depth, InputOutput,
00907 _visual_info->visual, attrib_mask, &wa);
00908
00909 if (_xwindow == (X11_Window)0) {
00910 x11display_cat.error()
00911 << "failed to create X window.\n";
00912 return false;
00913 }
00914 set_wm_properties(_properties, false);
00915
00916
00917
00918
00919
00920 XIM im = x11_pipe->get_im();
00921 _ic = NULL;
00922 if (im) {
00923 _ic = XCreateIC
00924 (im,
00925 XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
00926 (void*)NULL);
00927 if (_ic == (XIC)NULL) {
00928 x11display_cat.warning()
00929 << "Couldn't create input context.\n";
00930 }
00931 }
00932
00933 if (_properties.get_cursor_hidden()) {
00934 XDefineCursor(_display, _xwindow, x11_pipe->get_hidden_cursor());
00935
00936 } else if (_properties.has_cursor_filename() && !_properties.get_cursor_filename().empty()) {
00937
00938 X11_Cursor cursor = get_cursor(_properties.get_cursor_filename());
00939 XDefineCursor(_display, _xwindow, cursor);
00940 }
00941
00942 XMapWindow(_display, _xwindow);
00943
00944 if (_properties.get_raw_mice()) {
00945 open_raw_mice();
00946 } else {
00947 if (x11display_cat.is_debug()) {
00948 x11display_cat.debug()
00949 << "Raw mice not requested.\n";
00950 }
00951 }
00952
00953
00954 _window_handle = NativeWindowHandle::make_x11(_xwindow);
00955
00956
00957 if (_parent_window_handle != (WindowHandle *)NULL) {
00958 _parent_window_handle->attach_child(_window_handle);
00959 }
00960
00961 return true;
00962 }
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977 void x11GraphicsWindow::
00978 set_wm_properties(const WindowProperties &properties, bool already_mapped) {
00979
00980 XTextProperty window_name;
00981 XTextProperty *window_name_p = (XTextProperty *)NULL;
00982 if (properties.has_title()) {
00983 char *name = (char *)properties.get_title().c_str();
00984 if (XStringListToTextProperty(&name, 1, &window_name) != 0) {
00985 window_name_p = &window_name;
00986 }
00987 }
00988
00989
00990
00991 XSizeHints *size_hints_p = NULL;
00992 if (properties.has_origin() || properties.has_size()) {
00993 size_hints_p = XAllocSizeHints();
00994 if (size_hints_p != (XSizeHints *)NULL) {
00995 if (properties.has_origin()) {
00996 if (_properties.get_fullscreen()) {
00997 size_hints_p->x = 0;
00998 size_hints_p->y = 0;
00999 } else {
01000 size_hints_p->x = properties.get_x_origin();
01001 size_hints_p->y = properties.get_y_origin();
01002 }
01003 size_hints_p->flags |= USPosition;
01004 }
01005 if (properties.has_size()) {
01006 size_hints_p->width = properties.get_x_size();
01007 size_hints_p->height = properties.get_y_size();
01008 size_hints_p->flags |= USSize;
01009
01010 if (properties.get_fixed_size()) {
01011 size_hints_p->min_width = properties.get_x_size();
01012 size_hints_p->min_height = properties.get_y_size();
01013 size_hints_p->max_width = properties.get_x_size();
01014 size_hints_p->max_height = properties.get_y_size();
01015 size_hints_p->flags |= (PMinSize | PMaxSize);
01016 }
01017 }
01018 }
01019 }
01020
01021
01022
01023 XWMHints *wm_hints_p = NULL;
01024 wm_hints_p = XAllocWMHints();
01025 if (wm_hints_p != (XWMHints *)NULL) {
01026 if (properties.has_minimized() && properties.get_minimized()) {
01027 wm_hints_p->initial_state = IconicState;
01028 } else {
01029 wm_hints_p->initial_state = NormalState;
01030 }
01031 wm_hints_p->flags = StateHint;
01032 }
01033
01034
01035
01036
01037 static const int max_type_data = 32;
01038 PN_int32 type_data[max_type_data];
01039 int next_type_data = 0;
01040
01041 static const int max_state_data = 32;
01042 PN_int32 state_data[max_state_data];
01043 int next_state_data = 0;
01044
01045 static const int max_set_data = 32;
01046 class SetAction {
01047 public:
01048 inline SetAction() { }
01049 inline SetAction(Atom state, Atom action) : _state(state), _action(action) { }
01050 Atom _state;
01051 Atom _action;
01052 };
01053 SetAction set_data[max_set_data];
01054 int next_set_data = 0;
01055
01056 if (properties.get_fullscreen()) {
01057
01058
01059 type_data[next_type_data++] = _net_wm_window_type_fullscreen;
01060
01061
01062 state_data[next_state_data++] = _net_wm_state_fullscreen;
01063
01064
01065 set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, 1);
01066 } else {
01067 set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, 0);
01068 }
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079 XClassHint *class_hints_p = NULL;
01080 if (!x_wm_class.empty()) {
01081
01082 class_hints_p = XAllocClassHint();
01083 class_hints_p->res_class = (char*) x_wm_class.c_str();
01084 if (!x_wm_class_name.empty()) {
01085 class_hints_p->res_name = (char*) x_wm_class_name.c_str();
01086 }
01087
01088 } else if (properties.get_undecorated() || properties.get_fullscreen()) {
01089 class_hints_p = XAllocClassHint();
01090 class_hints_p->res_class = (char*) "Undecorated";
01091 }
01092
01093 if (properties.get_undecorated() && !properties.get_fullscreen()) {
01094 type_data[next_type_data++] = _net_wm_window_type_splash;
01095 }
01096
01097 if (properties.has_z_order()) {
01098 switch (properties.get_z_order()) {
01099 case WindowProperties::Z_bottom:
01100 state_data[next_state_data++] = _net_wm_state_below;
01101 set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_add);
01102 set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove);
01103 break;
01104
01105 case WindowProperties::Z_normal:
01106 set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove);
01107 set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove);
01108 break;
01109
01110 case WindowProperties::Z_top:
01111 state_data[next_state_data++] = _net_wm_state_above;
01112 set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove);
01113 set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_add);
01114 break;
01115 }
01116 }
01117
01118 nassertv(next_type_data < max_type_data);
01119 nassertv(next_state_data < max_state_data);
01120 nassertv(next_set_data < max_set_data);
01121
01122 XChangeProperty(_display, _xwindow, _net_wm_window_type,
01123 XA_ATOM, 32, PropModeReplace,
01124 (unsigned char *)type_data, next_type_data);
01125
01126
01127 XChangeProperty(_display, _xwindow, _net_wm_state,
01128 XA_ATOM, 32, PropModeReplace,
01129 (unsigned char *)state_data, next_state_data);
01130
01131 if (already_mapped) {
01132
01133
01134
01135
01136 x11GraphicsPipe *x11_pipe;
01137 DCAST_INTO_V(x11_pipe, _pipe);
01138
01139 for (int i = 0; i < next_set_data; ++i) {
01140 XClientMessageEvent event;
01141 memset(&event, 0, sizeof(event));
01142 event.type = ClientMessage;
01143 event.send_event = True;
01144 event.display = _display;
01145 event.window = _xwindow;
01146 event.message_type = _net_wm_state;
01147 event.format = 32;
01148 event.data.l[0] = set_data[i]._action;
01149 event.data.l[1] = set_data[i]._state;
01150 event.data.l[2] = 0;
01151 event.data.l[3] = 1;
01152
01153 XSendEvent(_display, x11_pipe->get_root(), True, SubstructureNotifyMask | SubstructureRedirectMask, (XEvent *)&event);
01154 }
01155 }
01156
01157 XSetWMProperties(_display, _xwindow, window_name_p, window_name_p,
01158 NULL, 0, size_hints_p, wm_hints_p, class_hints_p);
01159
01160 if (size_hints_p != (XSizeHints *)NULL) {
01161 XFree(size_hints_p);
01162 }
01163 if (wm_hints_p != (XWMHints *)NULL) {
01164 XFree(wm_hints_p);
01165 }
01166 if (class_hints_p != (XClassHint *)NULL) {
01167 XFree(class_hints_p);
01168 }
01169
01170
01171
01172
01173
01174 Atom protocols[] = {
01175 _wm_delete_window,
01176 };
01177
01178 XSetWMProtocols(_display, _xwindow, protocols,
01179 sizeof(protocols) / sizeof(Atom));
01180 }
01181
01182
01183
01184
01185
01186
01187
01188 void x11GraphicsWindow::
01189 setup_colormap(XVisualInfo *visual) {
01190 x11GraphicsPipe *x11_pipe;
01191 DCAST_INTO_V(x11_pipe, _pipe);
01192 X11_Window root_window = x11_pipe->get_root();
01193
01194 _colormap = XCreateColormap(_display, root_window,
01195 visual->visual, AllocNone);
01196 }
01197
01198
01199
01200
01201
01202
01203 void x11GraphicsWindow::
01204 open_raw_mice() {
01205 #ifdef HAVE_LINUX_INPUT_H
01206 bool any_present = false;
01207 bool any_mice = false;
01208
01209 for (int i=0; i<64; i++) {
01210 uint8_t evtypes[EV_MAX/8 + 1];
01211 ostringstream fnb;
01212 fnb << "/dev/input/event" << i;
01213 string fn = fnb.str();
01214 int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0);
01215 if (fd >= 0) {
01216 any_present = true;
01217 char name[256];
01218 char phys[256];
01219 char uniq[256];
01220 if ((ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)||
01221 (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0)||
01222 (ioctl(fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0)||
01223 (ioctl(fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0)) {
01224 close(fd);
01225 x11display_cat.error() <<
01226 "Opening raw mice: ioctl failed on " << fn << "\n";
01227 } else {
01228 if (test_bit(EV_REL, evtypes) || test_bit(EV_ABS, evtypes)) {
01229 for (char *p=name; *p; p++) {
01230 if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
01231 *p = '_';
01232 }
01233 }
01234 for (char *p=uniq; *p; p++) {
01235 if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
01236 *p = '_';
01237 }
01238 }
01239 string full_id = ((string)name) + "." + uniq;
01240 MouseDeviceInfo inf;
01241 inf._fd = fd;
01242 inf._input_device_index = _input_devices.size();
01243 inf._io_buffer = "";
01244 _mouse_device_info.push_back(inf);
01245 GraphicsWindowInputDevice device =
01246 GraphicsWindowInputDevice::pointer_only(this, full_id);
01247 add_input_device(device);
01248 x11display_cat.info() << "Raw mouse " <<
01249 inf._input_device_index << " detected: " << full_id << "\n";
01250 any_mice = true;
01251 } else {
01252 close(fd);
01253 }
01254 }
01255 } else {
01256 if ((errno == ENOENT)||(errno == ENOTDIR)) {
01257 break;
01258 } else {
01259 any_present = true;
01260 x11display_cat.error() <<
01261 "Opening raw mice: " << strerror(errno) << " " << fn << "\n";
01262 }
01263 }
01264 }
01265
01266 if (!any_present) {
01267 x11display_cat.error() <<
01268 "Opening raw mice: files not found: /dev/input/event*\n";
01269 } else if (!any_mice) {
01270 x11display_cat.error() <<
01271 "Opening raw mice: no mouse devices detected in /dev/input/event*\n";
01272 }
01273 #else
01274 x11display_cat.error() <<
01275 "Opening raw mice: panda not compiled with raw mouse support.\n";
01276 #endif
01277 }
01278
01279
01280
01281
01282
01283
01284 void x11GraphicsWindow::
01285 poll_raw_mice()
01286 {
01287 #ifdef HAVE_LINUX_INPUT_H
01288 for (int dev=0; dev<_mouse_device_info.size(); dev++) {
01289 MouseDeviceInfo &inf = _mouse_device_info[dev];
01290
01291
01292 if (inf._fd >= 0) {
01293 while (1) {
01294 char tbuf[1024];
01295 int nread = read(inf._fd, tbuf, sizeof(tbuf));
01296 if (nread > 0) {
01297 inf._io_buffer += string(tbuf, nread);
01298 } else {
01299 if ((nread < 0)&&((errno == EWOULDBLOCK) || (errno==EAGAIN))) {
01300 break;
01301 }
01302 close(inf._fd);
01303 inf._fd = -1;
01304 break;
01305 }
01306 }
01307 }
01308
01309
01310 int nevents = inf._io_buffer.size() / sizeof(struct input_event);
01311 if (nevents == 0) {
01312 continue;
01313 }
01314 const input_event *events = (const input_event *)(inf._io_buffer.c_str());
01315 GraphicsWindowInputDevice &dev = _input_devices[inf._input_device_index];
01316 int x = dev.get_raw_pointer().get_x();
01317 int y = dev.get_raw_pointer().get_y();
01318 for (int i=0; i<nevents; i++) {
01319 if (events[i].type == EV_REL) {
01320 if (events[i].code == REL_X) x += events[i].value;
01321 if (events[i].code == REL_Y) y += events[i].value;
01322 } else if (events[i].type == EV_ABS) {
01323 if (events[i].code == ABS_X) x = events[i].value;
01324 if (events[i].code == ABS_Y) y = events[i].value;
01325 } else if (events[i].type == EV_KEY) {
01326 if ((events[i].code >= BTN_MOUSE)&&(events[i].code < BTN_MOUSE+8)) {
01327 int btn = events[i].code - BTN_MOUSE;
01328 dev.set_pointer_in_window(x,y);
01329 if (events[i].value) {
01330 dev.button_down(MouseButton::button(btn));
01331 } else {
01332 dev.button_up(MouseButton::button(btn));
01333 }
01334 }
01335 }
01336 }
01337 inf._io_buffer.erase(0,nevents*sizeof(struct input_event));
01338 dev.set_pointer_in_window(x,y);
01339 }
01340 #endif
01341 }
01342
01343
01344
01345
01346
01347
01348
01349 void x11GraphicsWindow::
01350 handle_keystroke(XKeyEvent &event) {
01351 if (!_dga_mouse_enabled) {
01352 _input_devices[0].set_pointer_in_window(event.x, event.y);
01353 }
01354
01355 if (_ic) {
01356
01357 static const int buffer_size = 256;
01358 wchar_t buffer[buffer_size];
01359 Status status;
01360 int len = XwcLookupString(_ic, &event, buffer, buffer_size, NULL,
01361 &status);
01362 if (status == XBufferOverflow) {
01363 x11display_cat.error()
01364 << "Overflowed input buffer.\n";
01365 }
01366
01367
01368
01369 for (int i = 0; i < len; i++) {
01370 _input_devices[0].keystroke(buffer[i]);
01371 }
01372
01373 } else {
01374
01375 ButtonHandle button = get_button(event, true);
01376 if (button.has_ascii_equivalent()) {
01377 _input_devices[0].keystroke(button.get_ascii_equivalent());
01378 }
01379 }
01380 }
01381
01382
01383
01384
01385
01386
01387
01388 void x11GraphicsWindow::
01389 handle_keypress(XKeyEvent &event) {
01390 if (!_dga_mouse_enabled) {
01391 _input_devices[0].set_pointer_in_window(event.x, event.y);
01392 }
01393
01394
01395 ButtonHandle button = get_button(event, false);
01396 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
01397 _input_devices[0].button_down(KeyboardButton::control());
01398 }
01399 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
01400 _input_devices[0].button_down(KeyboardButton::shift());
01401 }
01402 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
01403 _input_devices[0].button_down(KeyboardButton::alt());
01404 }
01405 if (button != ButtonHandle::none()) {
01406 _input_devices[0].button_down(button);
01407 }
01408 }
01409
01410
01411
01412
01413
01414
01415
01416 void x11GraphicsWindow::
01417 handle_keyrelease(XKeyEvent &event) {
01418 if (!_dga_mouse_enabled) {
01419 _input_devices[0].set_pointer_in_window(event.x, event.y);
01420 }
01421
01422
01423 ButtonHandle button = get_button(event, false);
01424 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
01425 _input_devices[0].button_up(KeyboardButton::control());
01426 }
01427 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
01428 _input_devices[0].button_up(KeyboardButton::shift());
01429 }
01430 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
01431 _input_devices[0].button_up(KeyboardButton::alt());
01432 }
01433 if (button != ButtonHandle::none()) {
01434 _input_devices[0].button_up(button);
01435 }
01436 }
01437
01438
01439
01440
01441
01442
01443
01444 ButtonHandle x11GraphicsWindow::
01445 get_button(XKeyEvent &key_event, bool allow_shift) {
01446 KeySym key = XLookupKeysym(&key_event, 0);
01447
01448 if ((key_event.state & Mod2Mask) != 0) {
01449
01450
01451
01452 KeySym k2;
01453 ButtonHandle button;
01454 switch (key) {
01455 case XK_KP_Space:
01456 case XK_KP_Tab:
01457 case XK_KP_Enter:
01458 case XK_KP_F1:
01459 case XK_KP_F2:
01460 case XK_KP_F3:
01461 case XK_KP_F4:
01462 case XK_KP_Equal:
01463 case XK_KP_Multiply:
01464 case XK_KP_Add:
01465 case XK_KP_Separator:
01466 case XK_KP_Subtract:
01467 case XK_KP_Divide:
01468 case XK_KP_Left:
01469 case XK_KP_Up:
01470 case XK_KP_Right:
01471 case XK_KP_Down:
01472 case XK_KP_Begin:
01473 case XK_KP_Prior:
01474 case XK_KP_Next:
01475 case XK_KP_Home:
01476 case XK_KP_End:
01477 case XK_KP_Insert:
01478 case XK_KP_Delete:
01479 case XK_KP_0:
01480 case XK_KP_1:
01481 case XK_KP_2:
01482 case XK_KP_3:
01483 case XK_KP_4:
01484 case XK_KP_5:
01485 case XK_KP_6:
01486 case XK_KP_7:
01487 case XK_KP_8:
01488 case XK_KP_9:
01489 k2 = XLookupKeysym(&key_event, 1);
01490 button = map_button(k2);
01491 if (button != ButtonHandle::none()) {
01492 return button;
01493 }
01494
01495
01496 break;
01497
01498 default:
01499 break;
01500 }
01501 }
01502
01503 if (allow_shift) {
01504
01505 if ((key_event.state & ShiftMask) != 0) {
01506 KeySym k2 = XLookupKeysym(&key_event, 1);
01507 ButtonHandle button = map_button(k2);
01508 if (button != ButtonHandle::none()) {
01509 return button;
01510 }
01511 }
01512
01513
01514
01515
01516 if ((key_event.state & (ShiftMask | LockMask)) != 0) {
01517 if (key >= XK_a and key <= XK_z) {
01518 key += (XK_A - XK_a);
01519 }
01520 }
01521 }
01522
01523 return map_button(key);
01524 }
01525
01526
01527
01528
01529
01530
01531
01532 ButtonHandle x11GraphicsWindow::
01533 map_button(KeySym key) {
01534 switch (key) {
01535 case XK_BackSpace:
01536 return KeyboardButton::backspace();
01537 case XK_Tab:
01538 case XK_KP_Tab:
01539 return KeyboardButton::tab();
01540 case XK_Return:
01541 case XK_KP_Enter:
01542 return KeyboardButton::enter();
01543 case XK_Escape:
01544 return KeyboardButton::escape();
01545 case XK_KP_Space:
01546 case XK_space:
01547 return KeyboardButton::space();
01548 case XK_exclam:
01549 return KeyboardButton::ascii_key('!');
01550 case XK_quotedbl:
01551 return KeyboardButton::ascii_key('"');
01552 case XK_numbersign:
01553 return KeyboardButton::ascii_key('#');
01554 case XK_dollar:
01555 return KeyboardButton::ascii_key('$');
01556 case XK_percent:
01557 return KeyboardButton::ascii_key('%');
01558 case XK_ampersand:
01559 return KeyboardButton::ascii_key('&');
01560 case XK_apostrophe:
01561 return KeyboardButton::ascii_key('\'');
01562 case XK_parenleft:
01563 return KeyboardButton::ascii_key('(');
01564 case XK_parenright:
01565 return KeyboardButton::ascii_key(')');
01566 case XK_asterisk:
01567 case XK_KP_Multiply:
01568 return KeyboardButton::ascii_key('*');
01569 case XK_plus:
01570 case XK_KP_Add:
01571 return KeyboardButton::ascii_key('+');
01572 case XK_comma:
01573 case XK_KP_Separator:
01574 return KeyboardButton::ascii_key(',');
01575 case XK_minus:
01576 case XK_KP_Subtract:
01577 return KeyboardButton::ascii_key('-');
01578 case XK_period:
01579 case XK_KP_Decimal:
01580 return KeyboardButton::ascii_key('.');
01581 case XK_slash:
01582 case XK_KP_Divide:
01583 return KeyboardButton::ascii_key('/');
01584 case XK_0:
01585 case XK_KP_0:
01586 return KeyboardButton::ascii_key('0');
01587 case XK_1:
01588 case XK_KP_1:
01589 return KeyboardButton::ascii_key('1');
01590 case XK_2:
01591 case XK_KP_2:
01592 return KeyboardButton::ascii_key('2');
01593 case XK_3:
01594 case XK_KP_3:
01595 return KeyboardButton::ascii_key('3');
01596 case XK_4:
01597 case XK_KP_4:
01598 return KeyboardButton::ascii_key('4');
01599 case XK_5:
01600 case XK_KP_5:
01601 return KeyboardButton::ascii_key('5');
01602 case XK_6:
01603 case XK_KP_6:
01604 return KeyboardButton::ascii_key('6');
01605 case XK_7:
01606 case XK_KP_7:
01607 return KeyboardButton::ascii_key('7');
01608 case XK_8:
01609 case XK_KP_8:
01610 return KeyboardButton::ascii_key('8');
01611 case XK_9:
01612 case XK_KP_9:
01613 return KeyboardButton::ascii_key('9');
01614 case XK_colon:
01615 return KeyboardButton::ascii_key(':');
01616 case XK_semicolon:
01617 return KeyboardButton::ascii_key(';');
01618 case XK_less:
01619 return KeyboardButton::ascii_key('<');
01620 case XK_equal:
01621 case XK_KP_Equal:
01622 return KeyboardButton::ascii_key('=');
01623 case XK_greater:
01624 return KeyboardButton::ascii_key('>');
01625 case XK_question:
01626 return KeyboardButton::ascii_key('?');
01627 case XK_at:
01628 return KeyboardButton::ascii_key('@');
01629 case XK_A:
01630 return KeyboardButton::ascii_key('A');
01631 case XK_B:
01632 return KeyboardButton::ascii_key('B');
01633 case XK_C:
01634 return KeyboardButton::ascii_key('C');
01635 case XK_D:
01636 return KeyboardButton::ascii_key('D');
01637 case XK_E:
01638 return KeyboardButton::ascii_key('E');
01639 case XK_F:
01640 return KeyboardButton::ascii_key('F');
01641 case XK_G:
01642 return KeyboardButton::ascii_key('G');
01643 case XK_H:
01644 return KeyboardButton::ascii_key('H');
01645 case XK_I:
01646 return KeyboardButton::ascii_key('I');
01647 case XK_J:
01648 return KeyboardButton::ascii_key('J');
01649 case XK_K:
01650 return KeyboardButton::ascii_key('K');
01651 case XK_L:
01652 return KeyboardButton::ascii_key('L');
01653 case XK_M:
01654 return KeyboardButton::ascii_key('M');
01655 case XK_N:
01656 return KeyboardButton::ascii_key('N');
01657 case XK_O:
01658 return KeyboardButton::ascii_key('O');
01659 case XK_P:
01660 return KeyboardButton::ascii_key('P');
01661 case XK_Q:
01662 return KeyboardButton::ascii_key('Q');
01663 case XK_R:
01664 return KeyboardButton::ascii_key('R');
01665 case XK_S:
01666 return KeyboardButton::ascii_key('S');
01667 case XK_T:
01668 return KeyboardButton::ascii_key('T');
01669 case XK_U:
01670 return KeyboardButton::ascii_key('U');
01671 case XK_V:
01672 return KeyboardButton::ascii_key('V');
01673 case XK_W:
01674 return KeyboardButton::ascii_key('W');
01675 case XK_X:
01676 return KeyboardButton::ascii_key('X');
01677 case XK_Y:
01678 return KeyboardButton::ascii_key('Y');
01679 case XK_Z:
01680 return KeyboardButton::ascii_key('Z');
01681 case XK_bracketleft:
01682 return KeyboardButton::ascii_key('[');
01683 case XK_backslash:
01684 return KeyboardButton::ascii_key('\\');
01685 case XK_bracketright:
01686 return KeyboardButton::ascii_key(']');
01687 case XK_asciicircum:
01688 return KeyboardButton::ascii_key('^');
01689 case XK_underscore:
01690 return KeyboardButton::ascii_key('_');
01691 case XK_grave:
01692 return KeyboardButton::ascii_key('`');
01693 case XK_a:
01694 return KeyboardButton::ascii_key('a');
01695 case XK_b:
01696 return KeyboardButton::ascii_key('b');
01697 case XK_c:
01698 return KeyboardButton::ascii_key('c');
01699 case XK_d:
01700 return KeyboardButton::ascii_key('d');
01701 case XK_e:
01702 return KeyboardButton::ascii_key('e');
01703 case XK_f:
01704 return KeyboardButton::ascii_key('f');
01705 case XK_g:
01706 return KeyboardButton::ascii_key('g');
01707 case XK_h:
01708 return KeyboardButton::ascii_key('h');
01709 case XK_i:
01710 return KeyboardButton::ascii_key('i');
01711 case XK_j:
01712 return KeyboardButton::ascii_key('j');
01713 case XK_k:
01714 return KeyboardButton::ascii_key('k');
01715 case XK_l:
01716 return KeyboardButton::ascii_key('l');
01717 case XK_m:
01718 return KeyboardButton::ascii_key('m');
01719 case XK_n:
01720 return KeyboardButton::ascii_key('n');
01721 case XK_o:
01722 return KeyboardButton::ascii_key('o');
01723 case XK_p:
01724 return KeyboardButton::ascii_key('p');
01725 case XK_q:
01726 return KeyboardButton::ascii_key('q');
01727 case XK_r:
01728 return KeyboardButton::ascii_key('r');
01729 case XK_s:
01730 return KeyboardButton::ascii_key('s');
01731 case XK_t:
01732 return KeyboardButton::ascii_key('t');
01733 case XK_u:
01734 return KeyboardButton::ascii_key('u');
01735 case XK_v:
01736 return KeyboardButton::ascii_key('v');
01737 case XK_w:
01738 return KeyboardButton::ascii_key('w');
01739 case XK_x:
01740 return KeyboardButton::ascii_key('x');
01741 case XK_y:
01742 return KeyboardButton::ascii_key('y');
01743 case XK_z:
01744 return KeyboardButton::ascii_key('z');
01745 case XK_braceleft:
01746 return KeyboardButton::ascii_key('{');
01747 case XK_bar:
01748 return KeyboardButton::ascii_key('|');
01749 case XK_braceright:
01750 return KeyboardButton::ascii_key('}');
01751 case XK_asciitilde:
01752 return KeyboardButton::ascii_key('~');
01753 case XK_F1:
01754 case XK_KP_F1:
01755 return KeyboardButton::f1();
01756 case XK_F2:
01757 case XK_KP_F2:
01758 return KeyboardButton::f2();
01759 case XK_F3:
01760 case XK_KP_F3:
01761 return KeyboardButton::f3();
01762 case XK_F4:
01763 case XK_KP_F4:
01764 return KeyboardButton::f4();
01765 case XK_F5:
01766 return KeyboardButton::f5();
01767 case XK_F6:
01768 return KeyboardButton::f6();
01769 case XK_F7:
01770 return KeyboardButton::f7();
01771 case XK_F8:
01772 return KeyboardButton::f8();
01773 case XK_F9:
01774 return KeyboardButton::f9();
01775 case XK_F10:
01776 return KeyboardButton::f10();
01777 case XK_F11:
01778 return KeyboardButton::f11();
01779 case XK_F12:
01780 return KeyboardButton::f12();
01781 case XK_KP_Left:
01782 case XK_Left:
01783 return KeyboardButton::left();
01784 case XK_KP_Up:
01785 case XK_Up:
01786 return KeyboardButton::up();
01787 case XK_KP_Right:
01788 case XK_Right:
01789 return KeyboardButton::right();
01790 case XK_KP_Down:
01791 case XK_Down:
01792 return KeyboardButton::down();
01793 case XK_KP_Prior:
01794 case XK_Prior:
01795 return KeyboardButton::page_up();
01796 case XK_KP_Next:
01797 case XK_Next:
01798 return KeyboardButton::page_down();
01799 case XK_KP_Home:
01800 case XK_Home:
01801 return KeyboardButton::home();
01802 case XK_KP_End:
01803 case XK_End:
01804 return KeyboardButton::end();
01805 case XK_KP_Insert:
01806 case XK_Insert:
01807 return KeyboardButton::insert();
01808 case XK_KP_Delete:
01809 case XK_Delete:
01810 return KeyboardButton::del();
01811 case XK_Num_Lock:
01812 return KeyboardButton::num_lock();
01813 case XK_Scroll_Lock:
01814 return KeyboardButton::scroll_lock();
01815 case XK_Print:
01816 return KeyboardButton::print_screen();
01817 case XK_Pause:
01818 return KeyboardButton::pause();
01819 case XK_Shift_L:
01820 return KeyboardButton::lshift();
01821 case XK_Shift_R:
01822 return KeyboardButton::rshift();
01823 case XK_Control_L:
01824 return KeyboardButton::lcontrol();
01825 case XK_Control_R:
01826 return KeyboardButton::rcontrol();
01827 case XK_Alt_L:
01828 return KeyboardButton::lalt();
01829 case XK_Alt_R:
01830 return KeyboardButton::ralt();
01831 case XK_Meta_L:
01832 case XK_Meta_R:
01833 return KeyboardButton::meta();
01834 case XK_Caps_Lock:
01835 return KeyboardButton::caps_lock();
01836 case XK_Shift_Lock:
01837 return KeyboardButton::shift_lock();
01838 }
01839
01840 return ButtonHandle::none();
01841 }
01842
01843
01844
01845
01846
01847
01848
01849 ButtonHandle x11GraphicsWindow::
01850 get_mouse_button(XButtonEvent &button_event) {
01851 int index = button_event.button;
01852 if (index == x_wheel_up_button) {
01853 return MouseButton::wheel_up();
01854 } else if (index == x_wheel_down_button) {
01855 return MouseButton::wheel_down();
01856 } else if (index == x_wheel_left_button) {
01857 return MouseButton::wheel_left();
01858 } else if (index == x_wheel_right_button) {
01859 return MouseButton::wheel_right();
01860 } else {
01861 return MouseButton::button(index - 1);
01862 }
01863 }
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873 Bool x11GraphicsWindow::
01874 check_event(X11_Display *display, XEvent *event, char *arg) {
01875 const x11GraphicsWindow *self = (x11GraphicsWindow *)arg;
01876
01877
01878 return (event->xany.window == self->_xwindow);
01879 }
01880
01881
01882
01883
01884
01885
01886
01887
01888 X11_Cursor x11GraphicsWindow::
01889 get_cursor(const Filename &filename) {
01890 #ifndef HAVE_XCURSOR
01891 x11display_cat.info()
01892 << "XCursor support not enabled in build; cannot change mouse cursor.\n";
01893 return None;
01894 #else // HAVE_XCURSOR
01895
01896 pmap<Filename, X11_Cursor>::iterator fi = _cursor_filenames.find(filename);
01897 if (fi != _cursor_filenames.end()) {
01898 return fi->second;
01899 }
01900
01901
01902 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
01903 Filename resolved (filename);
01904 if (!vfs->resolve_filename(resolved, get_model_path())) {
01905
01906 x11display_cat.warning()
01907 << "Could not find cursor filename " << filename << "\n";
01908 return None;
01909 }
01910 fi = _cursor_filenames.find(resolved);
01911 if (fi != _cursor_filenames.end()) {
01912 _cursor_filenames[filename] = (*fi).second;
01913 return fi->second;
01914 }
01915
01916
01917 istream *str = vfs->open_read_file(resolved, true);
01918 if (str == NULL) {
01919 x11display_cat.warning()
01920 << "Could not open cursor file " << filename << "\n";
01921 return None;
01922 }
01923
01924
01925 char magic[4];
01926 str->read(magic, 4);
01927 if (!str->good()) {
01928 x11display_cat.warning()
01929 << "Could not read from cursor file " << filename << "\n";
01930 return None;
01931 }
01932 str->seekg(0, istream::beg);
01933
01934 X11_Cursor h = None;
01935 if (memcmp(magic, "Xcur", 4) == 0) {
01936
01937 x11display_cat.debug()
01938 << "Loading X11 cursor " << filename << "\n";
01939 XcursorFile xcfile;
01940 xcfile.closure = str;
01941 xcfile.read = &xcursor_read;
01942 xcfile.write = &xcursor_write;
01943 xcfile.seek = &xcursor_seek;
01944
01945 XcursorImages *images = XcursorXcFileLoadImages(&xcfile, XcursorGetDefaultSize(_display));
01946 if (images != NULL) {
01947 h = XcursorImagesLoadCursor(_display, images);
01948 XcursorImagesDestroy(images);
01949 }
01950
01951 } else if (memcmp(magic, "\0\0\1\0", 4) == 0
01952 || memcmp(magic, "\0\0\2\0", 4) == 0) {
01953
01954 x11display_cat.debug()
01955 << "Loading Windows cursor " << filename << "\n";
01956 h = read_ico(*str);
01957 }
01958
01959
01960 vfs->close_read_file(str);
01961
01962 if (h == None) {
01963 x11display_cat.warning()
01964 << "X11 cursor filename '" << resolved << "' could not be loaded!\n";
01965 }
01966
01967 _cursor_filenames[resolved] = h;
01968 return h;
01969 #endif // HAVE_XCURSOR
01970 }
01971
01972 #ifdef HAVE_XCURSOR
01973
01974
01975
01976
01977
01978
01979
01980 X11_Cursor x11GraphicsWindow::
01981 read_ico(istream &ico) {
01982
01983 typedef struct {
01984 uint16_t reserved, type, count;
01985 } IcoHeader;
01986
01987 typedef struct {
01988 uint8_t width, height, colorCount, reserved;
01989 uint16_t xhot, yhot;
01990 uint32_t bitmapSize, offset;
01991 } IcoEntry;
01992
01993 typedef struct {
01994 uint32_t headerSize, width, height;
01995 uint16_t planes, bitsPerPixel;
01996 uint32_t compression, imageSize, xPixelsPerM, yPixelsPerM, colorsUsed, colorsImportant;
01997 } IcoInfoHeader;
01998
01999 typedef struct {
02000 uint8_t blue, green, red, reserved;
02001 } IcoColor;
02002
02003 int i, entry = 0;
02004 unsigned int j, k, mask, shift;
02005 size_t colorCount, bitsPerPixel;
02006 IcoHeader header;
02007 IcoInfoHeader infoHeader;
02008 IcoEntry *entries = NULL;
02009 IcoColor color, *palette = NULL;
02010
02011 size_t xorBmpSize, andBmpSize;
02012 char *curXor, *curAnd;
02013 char *xorBmp = NULL, *andBmp = NULL;
02014 XcursorImage *image = NULL;
02015 X11_Cursor ret = None;
02016
02017 int def_size = XcursorGetDefaultSize(_display);
02018
02019
02020 ico.read(reinterpret_cast<char *>(&header), sizeof(IcoHeader));
02021 if (!ico.good()) goto cleanup;
02022 if (header.type != 1 && header.type != 2) goto cleanup;
02023 if (header.count < 1) goto cleanup;
02024
02025
02026 entries = new IcoEntry[header.count];
02027 ico.read(reinterpret_cast<char *>(entries), header.count * sizeof(IcoEntry));
02028 if (!ico.good()) goto cleanup;
02029 for (i = 1; i < header.count; i++) {
02030 if (entries[i].width == def_size && entries[i].height == def_size) {
02031
02032 entry = i;
02033 break;
02034 }
02035 if (entries[i].width > entries[entry].width ||
02036 entries[i].height > entries[entry].height)
02037 entry = i;
02038 }
02039
02040
02041 ico.seekg(entries[entry].offset);
02042 if (!ico.good()) goto cleanup;
02043 ico.read(reinterpret_cast<char *>(&infoHeader), sizeof(IcoInfoHeader));
02044 if (!ico.good()) goto cleanup;
02045 bitsPerPixel = infoHeader.bitsPerPixel;
02046
02047
02048 if (infoHeader.compression != 0) goto cleanup;
02049
02050
02051 if (bitsPerPixel != 24 && bitsPerPixel != 32) {
02052 colorCount = 1 << bitsPerPixel;
02053 palette = new IcoColor[colorCount];
02054 ico.read(reinterpret_cast<char *>(palette), colorCount * sizeof(IcoColor));
02055 if (!ico.good()) goto cleanup;
02056 }
02057
02058
02059 xorBmpSize = (infoHeader.width * (infoHeader.height / 2) * bitsPerPixel) / 8;
02060 andBmpSize = (infoHeader.width * (infoHeader.height / 2)) / 8;
02061 curXor = xorBmp = new char[xorBmpSize];
02062 curAnd = andBmp = new char[andBmpSize];
02063 ico.read(xorBmp, xorBmpSize);
02064 if (!ico.good()) goto cleanup;
02065 ico.read(andBmp, andBmpSize);
02066 if (!ico.good()) goto cleanup;
02067
02068
02069 image = XcursorImageCreate(infoHeader.width, infoHeader.height / 2);
02070 if (header.type == 2) { image->xhot = entries[entry].xhot; image->yhot = entries[entry].yhot; }
02071
02072
02073
02074 switch (bitsPerPixel) {
02075 case 1:
02076 case 4:
02077 case 8:
02078
02079
02080 mask = ((1 << bitsPerPixel) - 1);
02081 for (i = image->height - 1; i >= 0; i--) {
02082 for (j = 0; j < image->width; j += 8 / bitsPerPixel) {
02083 for (k = 0; k < 8 / bitsPerPixel; k++) {
02084 shift = 8 - ((k + 1) * bitsPerPixel);
02085 color = palette[(*curXor & (mask << shift)) >> shift];
02086 image->pixels[(i * image->width) + j + k] = (color.red << 16) +
02087 (color.green << 8) +
02088 (color.blue);
02089 }
02090
02091 curXor++;
02092 }
02093
02094
02095 for (j = 0; j < image->width; j += 8) {
02096 for (k = 0; k < 8; k++) {
02097 shift = 7 - k;
02098 image->pixels[(i * image->width) + j + k] |=
02099 ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24);
02100 }
02101
02102 curAnd++;
02103 }
02104 }
02105
02106 break;
02107 case 24:
02108
02109 for (i = image->height - 1; i >= 0; i--) {
02110 for (j = 0; j < image->width; j++) {
02111 image->pixels[(i * image->width) + j] = (*(curXor + 2) << 16) +
02112 (*(curXor + 1) << 8) + (*curXor);
02113 curXor += 3;
02114 }
02115
02116
02117 for (j = 0; j < image->width; j += 8) {
02118 for (k = 0; k < 8; k++) {
02119 shift = 7 - k;
02120 image->pixels[(i * image->width) + j + k] |=
02121 ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24);
02122 }
02123
02124 curAnd++;
02125 }
02126
02127 }
02128
02129 break;
02130 case 32:
02131
02132 for (i = image->height - 1; i >= 0; i--) {
02133 for (j = 0; j < image->width; j++) {
02134 image->pixels[(i * image->width) + j] = (*(curXor + 3) << 24) +
02135 (*(curXor + 2) << 16) +
02136 (*(curXor + 1) << 8) +
02137 (*curXor);
02138 curXor += 4;
02139 }
02140 }
02141
02142 break;
02143 default:
02144 goto cleanup;
02145 break;
02146 }
02147
02148 ret = XcursorImageLoadCursor(_display, image);
02149
02150 cleanup:
02151 XcursorImageDestroy(image);
02152 delete[] entries;
02153 delete[] palette;
02154 delete[] xorBmp;
02155 delete[] andBmp;
02156
02157 return ret;
02158 }
02159 #endif // HAVE_XCURSOR
02160