00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "CXWindowsScreen.h"
00020 #include "CXWindowsClipboard.h"
00021 #include "CXWindowsEventQueueBuffer.h"
00022 #include "CXWindowsKeyState.h"
00023 #include "CXWindowsScreenSaver.h"
00024 #include "CXWindowsUtil.h"
00025 #include "CClipboard.h"
00026 #include "CKeyMap.h"
00027 #include "XScreen.h"
00028 #include "XArch.h"
00029 #include "CLog.h"
00030 #include "CStopwatch.h"
00031 #include "CStringUtil.h"
00032 #include "IEventQueue.h"
00033 #include "TMethodEventJob.h"
00034 #include <cstring>
00035 #include <cstdlib>
00036 #if X_DISPLAY_MISSING
00037 # error X11 is required to build synergy
00038 #else
00039 # include <X11/X.h>
00040 # include <X11/Xutil.h>
00041 # define XK_MISCELLANY
00042 # define XK_XKB_KEYS
00043 # include <X11/keysymdef.h>
00044 # if HAVE_X11_EXTENSIONS_DPMS_H
00045 extern "C" {
00046 # include <X11/extensions/dpms.h>
00047 }
00048 # endif
00049 # if HAVE_X11_EXTENSIONS_XTEST_H
00050 # include <X11/extensions/XTest.h>
00051 # else
00052 # error The XTest extension is required to build synergy
00053 # endif
00054 # if HAVE_X11_EXTENSIONS_XINERAMA_H
00055
00056 extern "C" {
00057 # include <X11/extensions/Xinerama.h>
00058 }
00059 # endif
00060 # if HAVE_X11_EXTENSIONS_XRANDR_H
00061 # include <X11/extensions/Xrandr.h>
00062 # endif
00063 # if HAVE_XKB_EXTENSION
00064 # include <X11/XKBlib.h>
00065 # endif
00066 # ifdef HAVE_XI2
00067 # include <X11/extensions/XInput2.h>
00068 # endif
00069 #endif
00070 #include "CArch.h"
00071
00072 static int xi_opcode;
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 CXWindowsScreen* CXWindowsScreen::s_screen = NULL;
00090
00091 CXWindowsScreen::CXWindowsScreen(const char* displayName, bool isPrimary, bool disableXInitThreads, int mouseScrollDelta, IEventQueue& eventQueue) :
00092 m_isPrimary(isPrimary),
00093 m_mouseScrollDelta(mouseScrollDelta),
00094 m_display(NULL),
00095 m_root(None),
00096 m_window(None),
00097 m_isOnScreen(m_isPrimary),
00098 m_x(0), m_y(0),
00099 m_w(0), m_h(0),
00100 m_xCenter(0), m_yCenter(0),
00101 m_xCursor(0), m_yCursor(0),
00102 m_keyState(NULL),
00103 m_lastFocus(None),
00104 m_lastFocusRevert(RevertToNone),
00105 m_im(NULL),
00106 m_ic(NULL),
00107 m_lastKeycode(0),
00108 m_sequenceNumber(0),
00109 m_screensaver(NULL),
00110 m_screensaverNotify(false),
00111 m_xtestIsXineramaUnaware(true),
00112 m_preserveFocus(false),
00113 m_xkb(false),
00114 m_xi2detected(false),
00115 m_xrandr(false),
00116 m_eventQueue(eventQueue),
00117 CPlatformScreen(eventQueue)
00118 {
00119 assert(s_screen == NULL);
00120
00121 if (mouseScrollDelta==0) m_mouseScrollDelta=120;
00122 s_screen = this;
00123
00124 if (!disableXInitThreads) {
00125
00126 if (XInitThreads() == 0)
00127 throw XArch("XInitThreads() returned zero");
00128 } else {
00129 LOG((CLOG_DEBUG "skipping XInitThreads()"));
00130 }
00131
00132
00133 XSetIOErrorHandler(&CXWindowsScreen::ioErrorHandler);
00134
00135 try {
00136 m_display = openDisplay(displayName);
00137 m_root = DefaultRootWindow(m_display);
00138 saveShape();
00139 m_window = openWindow();
00140 m_screensaver = new CXWindowsScreenSaver(m_display,
00141 m_window, getEventTarget(), eventQueue);
00142 m_keyState = new CXWindowsKeyState(m_display, m_xkb, eventQueue, m_keyMap);
00143 LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_xinerama ? "(xinerama)" : ""));
00144 LOG((CLOG_DEBUG "window is 0x%08x", m_window));
00145 }
00146 catch (...) {
00147 if (m_display != NULL) {
00148 XCloseDisplay(m_display);
00149 }
00150 throw;
00151 }
00152
00153
00154 if (m_isPrimary) {
00155
00156 selectEvents(m_root);
00157 m_xi2detected = detectXI2();
00158
00159 if (m_xi2detected) {
00160 #ifdef HAVE_XI2
00161 selectXIRawMotion();
00162 #endif
00163 } else
00164 {
00165
00166 selectEvents(m_root);
00167 }
00168
00169
00170 openIM();
00171 }
00172 else {
00173
00174 XTestGrabControl(m_display, True);
00175 }
00176
00177
00178 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
00179 m_clipboard[id] = new CXWindowsClipboard(m_display, m_window, id);
00180 }
00181
00182
00183 m_eventQueue.adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(),
00184 new TMethodEventJob<CXWindowsScreen>(this,
00185 &CXWindowsScreen::handleSystemEvent));
00186
00187
00188 m_eventQueue.adoptBuffer(new CXWindowsEventQueueBuffer(m_display, m_window));
00189 }
00190
00191 CXWindowsScreen::~CXWindowsScreen()
00192 {
00193 assert(s_screen != NULL);
00194 assert(m_display != NULL);
00195
00196 m_eventQueue.adoptBuffer(NULL);
00197 m_eventQueue.removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget());
00198 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
00199 delete m_clipboard[id];
00200 }
00201 delete m_keyState;
00202 delete m_screensaver;
00203 m_keyState = NULL;
00204 m_screensaver = NULL;
00205 if (m_display != NULL) {
00206
00207 if (m_ic != NULL) {
00208 XDestroyIC(m_ic);
00209 }
00210 if (m_im != NULL) {
00211 XCloseIM(m_im);
00212 }
00213 XDestroyWindow(m_display, m_window);
00214 XCloseDisplay(m_display);
00215 }
00216 XSetIOErrorHandler(NULL);
00217
00218 s_screen = NULL;
00219 }
00220
00221 void
00222 CXWindowsScreen::enable()
00223 {
00224 if (!m_isPrimary) {
00225
00226 XKeyboardState keyControl;
00227 XGetKeyboardControl(m_display, &keyControl);
00228 m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn);
00229 m_keyState->setAutoRepeat(keyControl);
00230
00231
00232 XMoveWindow(m_display, m_window, m_xCenter, m_yCenter);
00233
00234
00235
00236 XMapRaised(m_display, m_window);
00237
00238
00239 fakeMouseMove(m_xCenter, m_yCenter);
00240 }
00241 }
00242
00243 void
00244 CXWindowsScreen::disable()
00245 {
00246
00247 if (m_ic != NULL) {
00248 XUnsetICFocus(m_ic);
00249 }
00250
00251
00252
00253 XUnmapWindow(m_display, m_window);
00254
00255
00256 if (!m_isPrimary && m_autoRepeat) {
00257
00258 }
00259 }
00260
00261 void
00262 CXWindowsScreen::enter()
00263 {
00264 screensaver(false);
00265
00266
00267 if (m_ic != NULL) {
00268 XUnsetICFocus(m_ic);
00269 }
00270
00271
00272 if (m_lastFocus != None) {
00273
00274 CXWindowsUtil::CErrorLock lock(m_display);
00275 XSetInputFocus(m_display, m_lastFocus, m_lastFocusRevert, CurrentTime);
00276 }
00277
00278 #if HAVE_X11_EXTENSIONS_DPMS_H
00279
00280
00281 int dummy;
00282 CARD16 powerlevel;
00283 BOOL enabled;
00284 if (DPMSQueryExtension(m_display, &dummy, &dummy) &&
00285 DPMSCapable(m_display) &&
00286 DPMSInfo(m_display, &powerlevel, &enabled))
00287 {
00288 if (enabled && powerlevel != DPMSModeOn)
00289 DPMSForceLevel(m_display, DPMSModeOn);
00290 }
00291 #endif
00292
00293
00294
00295 XUnmapWindow(m_display, m_window);
00296
00297
00298
00299
00300
00301
00302
00303 if (!m_isPrimary) {
00304
00305 XKeyboardState keyControl;
00306 XGetKeyboardControl(m_display, &keyControl);
00307 m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn);
00308 m_keyState->setAutoRepeat(keyControl);
00309
00310
00311
00312
00313
00314 }
00315
00316
00317 m_isOnScreen = true;
00318 }
00319
00320 bool
00321 CXWindowsScreen::leave()
00322 {
00323 if (!m_isPrimary) {
00324
00325
00326
00327
00328
00329 if (m_autoRepeat) {
00330
00331 }
00332
00333
00334 XMoveWindow(m_display, m_window, m_xCenter, m_yCenter);
00335 }
00336
00337
00338 XMapRaised(m_display, m_window);
00339
00340
00341 if (m_isPrimary && !grabMouseAndKeyboard()) {
00342 XUnmapWindow(m_display, m_window);
00343 return false;
00344 }
00345
00346
00347 XGetInputFocus(m_display, &m_lastFocus, &m_lastFocusRevert);
00348
00349
00350 if (m_isPrimary || !m_preserveFocus) {
00351 XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime);
00352 }
00353
00354
00355
00356
00357 if (m_isPrimary) {
00358 warpCursor(m_xCenter, m_yCenter);
00359 }
00360 else {
00361 fakeMouseMove(m_xCenter, m_yCenter);
00362 }
00363
00364
00365 if (m_ic != NULL) {
00366 XmbResetIC(m_ic);
00367 XSetICFocus(m_ic);
00368 m_filtered.clear();
00369 }
00370
00371
00372 m_isOnScreen = false;
00373
00374 return true;
00375 }
00376
00377 bool
00378 CXWindowsScreen::setClipboard(ClipboardID id, const IClipboard* clipboard)
00379 {
00380
00381 if (m_clipboard[id] == NULL) {
00382 return false;
00383 }
00384
00385
00386 Time timestamp = CXWindowsUtil::getCurrentTime(
00387 m_display, m_clipboard[id]->getWindow());
00388
00389 if (clipboard != NULL) {
00390
00391 return CClipboard::copy(m_clipboard[id], clipboard, timestamp);
00392 }
00393 else {
00394
00395 if (!m_clipboard[id]->open(timestamp)) {
00396 return false;
00397 }
00398 m_clipboard[id]->empty();
00399 m_clipboard[id]->close();
00400 return true;
00401 }
00402 }
00403
00404 void
00405 CXWindowsScreen::checkClipboards()
00406 {
00407
00408 }
00409
00410 void
00411 CXWindowsScreen::openScreensaver(bool notify)
00412 {
00413 m_screensaverNotify = notify;
00414 if (!m_screensaverNotify) {
00415 m_screensaver->disable();
00416 }
00417 }
00418
00419 void
00420 CXWindowsScreen::closeScreensaver()
00421 {
00422 if (!m_screensaverNotify) {
00423 m_screensaver->enable();
00424 }
00425 }
00426
00427 void
00428 CXWindowsScreen::screensaver(bool activate)
00429 {
00430 if (activate) {
00431 m_screensaver->activate();
00432 }
00433 else {
00434 m_screensaver->deactivate();
00435 }
00436 }
00437
00438 void
00439 CXWindowsScreen::resetOptions()
00440 {
00441 m_xtestIsXineramaUnaware = true;
00442 m_preserveFocus = false;
00443 }
00444
00445 void
00446 CXWindowsScreen::setOptions(const COptionsList& options)
00447 {
00448 for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
00449 if (options[i] == kOptionXTestXineramaUnaware) {
00450 m_xtestIsXineramaUnaware = (options[i + 1] != 0);
00451 LOG((CLOG_DEBUG1 "XTest is Xinerama unaware %s", m_xtestIsXineramaUnaware ? "true" : "false"));
00452 }
00453 else if (options[i] == kOptionScreenPreserveFocus) {
00454 m_preserveFocus = (options[i + 1] != 0);
00455 LOG((CLOG_DEBUG1 "Preserve Focus = %s", m_preserveFocus ? "true" : "false"));
00456 }
00457 }
00458 }
00459
00460 void
00461 CXWindowsScreen::setSequenceNumber(UInt32 seqNum)
00462 {
00463 m_sequenceNumber = seqNum;
00464 }
00465
00466 bool
00467 CXWindowsScreen::isPrimary() const
00468 {
00469 return m_isPrimary;
00470 }
00471
00472 void*
00473 CXWindowsScreen::getEventTarget() const
00474 {
00475 return const_cast<CXWindowsScreen*>(this);
00476 }
00477
00478 bool
00479 CXWindowsScreen::getClipboard(ClipboardID id, IClipboard* clipboard) const
00480 {
00481 assert(clipboard != NULL);
00482
00483
00484 if (m_clipboard[id] == NULL) {
00485 return false;
00486 }
00487
00488
00489 Time timestamp = CXWindowsUtil::getCurrentTime(
00490 m_display, m_clipboard[id]->getWindow());
00491
00492
00493 return CClipboard::copy(clipboard, m_clipboard[id], timestamp);
00494 }
00495
00496 void
00497 CXWindowsScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
00498 {
00499 x = m_x;
00500 y = m_y;
00501 w = m_w;
00502 h = m_h;
00503 }
00504
00505 void
00506 CXWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const
00507 {
00508 Window root, window;
00509 int mx, my, xWindow, yWindow;
00510 unsigned int mask;
00511 if (XQueryPointer(m_display, m_root, &root, &window,
00512 &mx, &my, &xWindow, &yWindow, &mask)) {
00513 x = mx;
00514 y = my;
00515 }
00516 else {
00517 x = m_xCenter;
00518 y = m_yCenter;
00519 }
00520 }
00521
00522 void
00523 CXWindowsScreen::reconfigure(UInt32)
00524 {
00525
00526 }
00527
00528 void
00529 CXWindowsScreen::warpCursor(SInt32 x, SInt32 y)
00530 {
00531
00532 warpCursorNoFlush(x, y);
00533
00534
00535 XEvent event;
00536 while (XCheckMaskEvent(m_display, PointerMotionMask |
00537 ButtonPressMask | ButtonReleaseMask |
00538 KeyPressMask | KeyReleaseMask |
00539 KeymapStateMask,
00540 &event)) {
00541
00542 }
00543
00544
00545 m_xCursor = x;
00546 m_yCursor = y;
00547 }
00548
00549 UInt32
00550 CXWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
00551 {
00552
00553 if ((mask & ~(KeyModifierShift | KeyModifierControl |
00554 KeyModifierAlt | KeyModifierSuper)) != 0) {
00555 LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask));
00556 return 0;
00557 }
00558
00559
00560 if (key == kKeyNone && mask == 0) {
00561 return 0;
00562 }
00563
00564
00565 unsigned int modifiers;
00566 if (!m_keyState->mapModifiersToX(mask, modifiers)) {
00567
00568 LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask));
00569 return 0;
00570 }
00571 CXWindowsKeyState::CKeycodeList keycodes;
00572 m_keyState->mapKeyToKeycodes(key, keycodes);
00573 if (key != kKeyNone && keycodes.empty()) {
00574
00575 LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask));
00576 return 0;
00577 }
00578
00579
00580 UInt32 id;
00581 if (!m_oldHotKeyIDs.empty()) {
00582 id = m_oldHotKeyIDs.back();
00583 m_oldHotKeyIDs.pop_back();
00584 }
00585 else {
00586 id = m_hotKeys.size() + 1;
00587 }
00588 HotKeyList& hotKeys = m_hotKeys[id];
00589
00590
00591
00592
00593 bool err = false;
00594 {
00595 CXWindowsUtil::CErrorLock lock(m_display, &err);
00596 if (key == kKeyNone) {
00597 static const KeyModifierMask s_hotKeyModifiers[] = {
00598 KeyModifierShift,
00599 KeyModifierControl,
00600 KeyModifierAlt,
00601 KeyModifierMeta,
00602 KeyModifierSuper
00603 };
00604
00605 XModifierKeymap* modKeymap = XGetModifierMapping(m_display);
00606 for (size_t j = 0; j < sizeof(s_hotKeyModifiers) /
00607 sizeof(s_hotKeyModifiers[0]) && !err; ++j) {
00608
00609 if ((mask & s_hotKeyModifiers[j]) == 0) {
00610 continue;
00611 }
00612
00613
00614 unsigned int modifiers2;
00615 KeyModifierMask mask2 = (mask & ~s_hotKeyModifiers[j]);
00616 if (!m_keyState->mapModifiersToX(mask2, modifiers2)) {
00617 err = true;
00618 continue;
00619 }
00620
00621
00622
00623 int index;
00624 switch (modifiers ^ modifiers2) {
00625 case ShiftMask:
00626 index = ShiftMapIndex;
00627 break;
00628
00629 case LockMask:
00630 index = LockMapIndex;
00631 break;
00632
00633 case ControlMask:
00634 index = ControlMapIndex;
00635 break;
00636
00637 case Mod1Mask:
00638 index = Mod1MapIndex;
00639 break;
00640
00641 case Mod2Mask:
00642 index = Mod2MapIndex;
00643 break;
00644
00645 case Mod3Mask:
00646 index = Mod3MapIndex;
00647 break;
00648
00649 case Mod4Mask:
00650 index = Mod4MapIndex;
00651 break;
00652
00653 case Mod5Mask:
00654 index = Mod5MapIndex;
00655 break;
00656
00657 default:
00658 err = true;
00659 continue;
00660 }
00661
00662
00663 const KeyCode* modifiermap =
00664 modKeymap->modifiermap + index * modKeymap->max_keypermod;
00665 for (int k = 0; k < modKeymap->max_keypermod && !err; ++k) {
00666 KeyCode code = modifiermap[k];
00667 if (modifiermap[k] != 0) {
00668 XGrabKey(m_display, code, modifiers2, m_root,
00669 False, GrabModeAsync, GrabModeAsync);
00670 if (!err) {
00671 hotKeys.push_back(std::make_pair(code, modifiers2));
00672 m_hotKeyToIDMap[CHotKeyItem(code, modifiers2)] = id;
00673 }
00674 }
00675 }
00676 }
00677 XFreeModifiermap(modKeymap);
00678 }
00679
00680
00681
00682
00683 else {
00684
00685 unsigned int modifier;
00686 unsigned int toggleModifiers[3];
00687 size_t numToggleModifiers = 0;
00688 if (m_keyState->mapModifiersToX(KeyModifierCapsLock, modifier)) {
00689 toggleModifiers[numToggleModifiers++] = modifier;
00690 }
00691 if (m_keyState->mapModifiersToX(KeyModifierNumLock, modifier)) {
00692 toggleModifiers[numToggleModifiers++] = modifier;
00693 }
00694 if (m_keyState->mapModifiersToX(KeyModifierScrollLock, modifier)) {
00695 toggleModifiers[numToggleModifiers++] = modifier;
00696 }
00697
00698
00699 for (CXWindowsKeyState::CKeycodeList::iterator j = keycodes.begin();
00700 j != keycodes.end() && !err; ++j) {
00701 for (size_t i = 0; i < (1u << numToggleModifiers); ++i) {
00702
00703 unsigned int tmpModifiers = modifiers;
00704 if ((i & 1) != 0) {
00705 tmpModifiers |= toggleModifiers[0];
00706 }
00707 if ((i & 2) != 0) {
00708 tmpModifiers |= toggleModifiers[1];
00709 }
00710 if ((i & 4) != 0) {
00711 tmpModifiers |= toggleModifiers[2];
00712 }
00713
00714
00715 XGrabKey(m_display, *j, tmpModifiers, m_root,
00716 False, GrabModeAsync, GrabModeAsync);
00717 if (!err) {
00718 hotKeys.push_back(std::make_pair(*j, tmpModifiers));
00719 m_hotKeyToIDMap[CHotKeyItem(*j, tmpModifiers)] = id;
00720 }
00721 }
00722 }
00723 }
00724 }
00725
00726 if (err) {
00727
00728 for (HotKeyList::iterator j = hotKeys.begin();
00729 j != hotKeys.end(); ++j) {
00730 XUngrabKey(m_display, j->first, j->second, m_root);
00731 m_hotKeyToIDMap.erase(CHotKeyItem(j->first, j->second));
00732 }
00733
00734 m_oldHotKeyIDs.push_back(id);
00735 m_hotKeys.erase(id);
00736 LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", CKeyMap::formatKey(key, mask).c_str(), key, mask));
00737 return 0;
00738 }
00739
00740 LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", CKeyMap::formatKey(key, mask).c_str(), key, mask, id));
00741 return id;
00742 }
00743
00744 void
00745 CXWindowsScreen::unregisterHotKey(UInt32 id)
00746 {
00747
00748 HotKeyMap::iterator i = m_hotKeys.find(id);
00749 if (i == m_hotKeys.end()) {
00750 return;
00751 }
00752
00753
00754 bool err = false;
00755 {
00756 CXWindowsUtil::CErrorLock lock(m_display, &err);
00757 HotKeyList& hotKeys = i->second;
00758 for (HotKeyList::iterator j = hotKeys.begin();
00759 j != hotKeys.end(); ++j) {
00760 XUngrabKey(m_display, j->first, j->second, m_root);
00761 m_hotKeyToIDMap.erase(CHotKeyItem(j->first, j->second));
00762 }
00763 }
00764 if (err) {
00765 LOG((CLOG_WARN "failed to unregister hotkey id=%d", id));
00766 }
00767 else {
00768 LOG((CLOG_DEBUG "unregistered hotkey id=%d", id));
00769 }
00770
00771
00772 m_hotKeys.erase(i);
00773 m_oldHotKeyIDs.push_back(id);
00774 }
00775
00776 void
00777 CXWindowsScreen::fakeInputBegin()
00778 {
00779
00780 }
00781
00782 void
00783 CXWindowsScreen::fakeInputEnd()
00784 {
00785
00786 }
00787
00788 SInt32
00789 CXWindowsScreen::getJumpZoneSize() const
00790 {
00791 return 1;
00792 }
00793
00794 bool
00795 CXWindowsScreen::isAnyMouseButtonDown() const
00796 {
00797
00798 Window root, window;
00799 int xRoot, yRoot, xWindow, yWindow;
00800 unsigned int state;
00801 if (XQueryPointer(m_display, m_root, &root, &window,
00802 &xRoot, &yRoot, &xWindow, &yWindow, &state)) {
00803 return ((state & (Button1Mask | Button2Mask | Button3Mask |
00804 Button4Mask | Button5Mask)) != 0);
00805 }
00806
00807 return false;
00808 }
00809
00810 void
00811 CXWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
00812 {
00813 x = m_xCenter;
00814 y = m_yCenter;
00815 }
00816
00817 void
00818 CXWindowsScreen::fakeMouseButton(ButtonID button, bool press)
00819 {
00820 const unsigned int xButton = mapButtonToX(button);
00821 if (xButton != 0) {
00822 XTestFakeButtonEvent(m_display, xButton,
00823 press ? True : False, CurrentTime);
00824 XFlush(m_display);
00825 }
00826 }
00827
00828 void
00829 CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const
00830 {
00831 if (m_xinerama && m_xtestIsXineramaUnaware) {
00832 XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y);
00833 }
00834 else {
00835 XTestFakeMotionEvent(m_display, DefaultScreen(m_display),
00836 x, y, CurrentTime);
00837 }
00838 XFlush(m_display);
00839 }
00840
00841 void
00842 CXWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
00843 {
00844
00845 if (false && m_xinerama && m_xtestIsXineramaUnaware) {
00846
00847 }
00848 else {
00849 XTestFakeRelativeMotionEvent(m_display, dx, dy, CurrentTime);
00850 }
00851 XFlush(m_display);
00852 }
00853
00854 void
00855 CXWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const
00856 {
00857
00858 if (yDelta == 0) {
00859 return;
00860 }
00861
00862
00863 const unsigned int xButton = mapButtonToX(static_cast<ButtonID>(
00864 (yDelta >= 0) ? -1 : -2));
00865 if (xButton == 0) {
00866
00867
00868
00869 KeyCode keycode = 0;
00870 if (yDelta >= 0) {
00871 keycode = XKeysymToKeycode(m_display, XK_Page_Up);
00872 }
00873 else {
00874 keycode = XKeysymToKeycode(m_display, XK_Page_Down);
00875 }
00876 if (keycode != 0) {
00877 XTestFakeKeyEvent(m_display, keycode, True, CurrentTime);
00878 XTestFakeKeyEvent(m_display, keycode, False, CurrentTime);
00879 }
00880 return;
00881 }
00882
00883
00884 if (yDelta < 0) {
00885 yDelta = -yDelta;
00886 }
00887
00888 if (yDelta < m_mouseScrollDelta) {
00889 LOG((CLOG_WARN "Wheel scroll delta (%d) smaller than threshold (%d)", yDelta, m_mouseScrollDelta));
00890 }
00891
00892
00893 for (; yDelta >= m_mouseScrollDelta; yDelta -= m_mouseScrollDelta) {
00894 XTestFakeButtonEvent(m_display, xButton, True, CurrentTime);
00895 XTestFakeButtonEvent(m_display, xButton, False, CurrentTime);
00896 }
00897 XFlush(m_display);
00898 }
00899
00900 Display*
00901 CXWindowsScreen::openDisplay(const char* displayName)
00902 {
00903
00904 if (displayName == NULL) {
00905 displayName = getenv("DISPLAY");
00906 if (displayName == NULL) {
00907 displayName = ":0.0";
00908 }
00909 }
00910
00911
00912 LOG((CLOG_DEBUG "XOpenDisplay(\"%s\")", displayName));
00913 Display* display = XOpenDisplay(displayName);
00914 if (display == NULL) {
00915 throw XScreenUnavailable(60.0);
00916 }
00917
00918
00919 if (!m_isPrimary) {
00920 int majorOpcode, firstEvent, firstError;
00921 if (!XQueryExtension(display, XTestExtensionName,
00922 &majorOpcode, &firstEvent, &firstError)) {
00923 LOG((CLOG_ERR "XTEST extension not available"));
00924 XCloseDisplay(display);
00925 throw XScreenOpenFailure();
00926 }
00927 }
00928
00929 #if HAVE_XKB_EXTENSION
00930 {
00931 m_xkb = false;
00932 int major = XkbMajorVersion, minor = XkbMinorVersion;
00933 if (XkbLibraryVersion(&major, &minor)) {
00934 int opcode, firstError;
00935 if (XkbQueryExtension(display, &opcode, &m_xkbEventBase,
00936 &firstError, &major, &minor)) {
00937 m_xkb = true;
00938 XkbSelectEvents(display, XkbUseCoreKbd,
00939 XkbMapNotifyMask, XkbMapNotifyMask);
00940 XkbSelectEventDetails(display, XkbUseCoreKbd,
00941 XkbStateNotifyMask,
00942 XkbGroupStateMask, XkbGroupStateMask);
00943 }
00944 }
00945 }
00946 #endif
00947
00948 #if HAVE_X11_EXTENSIONS_XRANDR_H
00949
00950 int dummyError;
00951 m_xrandr = XRRQueryExtension(display, &m_xrandrEventBase, &dummyError);
00952 if (m_xrandr) {
00953
00954 XRRSelectInput(display, DefaultRootWindow(display), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask);
00955 }
00956 #endif
00957
00958 return display;
00959 }
00960
00961 void
00962 CXWindowsScreen::saveShape()
00963 {
00964
00965 m_x = 0;
00966 m_y = 0;
00967
00968 m_w = WidthOfScreen(DefaultScreenOfDisplay(m_display));
00969 m_h = HeightOfScreen(DefaultScreenOfDisplay(m_display));
00970
00971 #if HAVE_X11_EXTENSIONS_XRANDR_H
00972 if (m_xrandr){
00973 int numSizes;
00974 XRRScreenSize* xrrs;
00975 Rotation rotation;
00976 xrrs = XRRSizes(m_display, DefaultScreen(m_display), &numSizes);
00977 XRRRotations(m_display, DefaultScreen(m_display), &rotation);
00978 if (xrrs != NULL) {
00979 if (rotation & (RR_Rotate_90|RR_Rotate_270) ){
00980 m_w = xrrs->height;
00981 m_h = xrrs->width;
00982 }
00983 }
00984 }
00985 #endif
00986
00987
00988 m_xCenter = m_x + (m_w >> 1);
00989 m_yCenter = m_y + (m_h >> 1);
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004 m_xinerama = false;
01005 #if HAVE_X11_EXTENSIONS_XINERAMA_H
01006 int eventBase, errorBase;
01007 if (XineramaQueryExtension(m_display, &eventBase, &errorBase) &&
01008 XineramaIsActive(m_display)) {
01009 int numScreens;
01010 XineramaScreenInfo* screens;
01011 screens = XineramaQueryScreens(m_display, &numScreens);
01012 if (screens != NULL) {
01013 if (numScreens > 1) {
01014 m_xinerama = true;
01015 m_xCenter = screens[0].x_org + (screens[0].width >> 1);
01016 m_yCenter = screens[0].y_org + (screens[0].height >> 1);
01017 }
01018 XFree(screens);
01019 }
01020 }
01021 #endif
01022 }
01023
01024 Window
01025 CXWindowsScreen::openWindow() const
01026 {
01027
01028
01029
01030 XSetWindowAttributes attr;
01031 attr.do_not_propagate_mask = 0;
01032 attr.override_redirect = True;
01033 attr.cursor = createBlankCursor();
01034
01035
01036 SInt32 x, y, w, h;
01037 if (m_isPrimary) {
01038
01039
01040
01041 attr.event_mask = PointerMotionMask |
01042 ButtonPressMask | ButtonReleaseMask |
01043 KeyPressMask | KeyReleaseMask |
01044 KeymapStateMask | PropertyChangeMask;
01045 x = m_x;
01046 y = m_y;
01047 w = m_w;
01048 h = m_h;
01049 }
01050 else {
01051
01052
01053
01054
01055
01056
01057 attr.event_mask = LeaveWindowMask;
01058 x = 0;
01059 y = 0;
01060 w = 1;
01061 h = 1;
01062 }
01063
01064
01065 Window window = XCreateWindow(m_display, m_root, x, y, w, h, 0, 0,
01066 InputOnly, CopyFromParent,
01067 CWDontPropagate | CWEventMask |
01068 CWOverrideRedirect | CWCursor,
01069 &attr);
01070 if (window == None) {
01071 throw XScreenOpenFailure();
01072 }
01073 return window;
01074 }
01075
01076 void
01077 CXWindowsScreen::openIM()
01078 {
01079
01080 XIM im = XOpenIM(m_display, NULL, NULL, NULL);
01081 if (im == NULL) {
01082 LOG((CLOG_INFO "no support for IM"));
01083 return;
01084 }
01085
01086
01087
01088 XIMStyles* styles;
01089 if (XGetIMValues(im, XNQueryInputStyle, &styles, NULL) != NULL ||
01090 styles == NULL) {
01091 LOG((CLOG_WARN "cannot get IM styles"));
01092 XCloseIM(im);
01093 return;
01094 }
01095 XIMStyle style = 0;
01096 for (unsigned short i = 0; i < styles->count_styles; ++i) {
01097 style = styles->supported_styles[i];
01098 if ((style & XIMPreeditNothing) != 0) {
01099 if ((style & (XIMStatusNothing | XIMStatusNone)) != 0) {
01100 break;
01101 }
01102 }
01103 }
01104 XFree(styles);
01105 if (style == 0) {
01106 LOG((CLOG_INFO "no supported IM styles"));
01107 XCloseIM(im);
01108 return;
01109 }
01110
01111
01112 XIC ic = XCreateIC(im, XNInputStyle, style, XNClientWindow, m_window, NULL);
01113 if (ic == NULL) {
01114 LOG((CLOG_WARN "cannot create IC"));
01115 XCloseIM(im);
01116 return;
01117 }
01118
01119
01120 unsigned long mask;
01121 if (XGetICValues(ic, XNFilterEvents, &mask, NULL) != NULL) {
01122 LOG((CLOG_WARN "cannot get IC filter events"));
01123 XDestroyIC(ic);
01124 XCloseIM(im);
01125 return;
01126 }
01127
01128
01129 m_im = im;
01130 m_ic = ic;
01131 m_lastKeycode = 0;
01132
01133
01134 XWindowAttributes attr;
01135 XGetWindowAttributes(m_display, m_window, &attr);
01136 XSelectInput(m_display, m_window, attr.your_event_mask | mask);
01137 }
01138
01139 void
01140 CXWindowsScreen::sendEvent(CEvent::Type type, void* data)
01141 {
01142 m_eventQueue.addEvent(CEvent(type, getEventTarget(), data));
01143 }
01144
01145 void
01146 CXWindowsScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id)
01147 {
01148 CClipboardInfo* info = (CClipboardInfo*)malloc(sizeof(CClipboardInfo));
01149 info->m_id = id;
01150 info->m_sequenceNumber = m_sequenceNumber;
01151 sendEvent(type, info);
01152 }
01153
01154 IKeyState*
01155 CXWindowsScreen::getKeyState() const
01156 {
01157 return m_keyState;
01158 }
01159
01160 Bool
01161 CXWindowsScreen::findKeyEvent(Display*, XEvent* xevent, XPointer arg)
01162 {
01163 CKeyEventFilter* filter = reinterpret_cast<CKeyEventFilter*>(arg);
01164 return (xevent->type == filter->m_event &&
01165 xevent->xkey.window == filter->m_window &&
01166 xevent->xkey.time == filter->m_time &&
01167 xevent->xkey.keycode == filter->m_keycode) ? True : False;
01168 }
01169
01170 void
01171 CXWindowsScreen::handleSystemEvent(const CEvent& event, void*)
01172 {
01173 XEvent* xevent = reinterpret_cast<XEvent*>(event.getData());
01174 assert(xevent != NULL);
01175
01176
01177 bool isRepeat = false;
01178 if (m_isPrimary) {
01179 if (xevent->type == KeyRelease) {
01180
01181
01182
01183
01184 CKeyEventFilter filter;
01185 filter.m_event = KeyPress;
01186 filter.m_window = xevent->xkey.window;
01187 filter.m_time = xevent->xkey.time;
01188 filter.m_keycode = xevent->xkey.keycode;
01189 XEvent xevent2;
01190 isRepeat = (XCheckIfEvent(m_display, &xevent2,
01191 &CXWindowsScreen::findKeyEvent,
01192 (XPointer)&filter) == True);
01193 }
01194
01195 if (xevent->type == KeyPress || xevent->type == KeyRelease) {
01196 if (xevent->xkey.window == m_root) {
01197
01198 onHotKey(xevent->xkey, isRepeat);
01199 return;
01200 }
01201 else if (!m_isOnScreen) {
01202
01203 if (onHotKey(xevent->xkey, isRepeat)) {
01204 return;
01205 }
01206 }
01207
01208 bool down = (isRepeat || xevent->type == KeyPress);
01209 KeyModifierMask state =
01210 m_keyState->mapModifiersFromX(xevent->xkey.state);
01211 m_keyState->onKey(xevent->xkey.keycode, down, state);
01212 }
01213 }
01214
01215
01216 if (m_ic != NULL) {
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226 if (xevent->type == KeyPress && xevent->xkey.keycode != 0) {
01227 m_lastKeycode = xevent->xkey.keycode;
01228 }
01229 else if (xevent->type == KeyRelease &&
01230 xevent->xkey.keycode == m_lastKeycode) {
01231 m_lastKeycode = 0;
01232 }
01233
01234
01235 if (XFilterEvent(xevent, DefaultRootWindow(m_display))) {
01236 if (xevent->type == KeyPress) {
01237
01238 m_filtered.insert(m_lastKeycode);
01239 }
01240 return;
01241 }
01242
01243
01244
01245 else if (xevent->type == KeyRelease &&
01246 m_filtered.count(xevent->xkey.keycode) > 0) {
01247 m_filtered.erase(xevent->xkey.keycode);
01248 return;
01249 }
01250 }
01251
01252
01253 if (m_screensaver->handleXEvent(xevent)) {
01254
01255 return;
01256 }
01257
01258 #ifdef HAVE_XI2
01259 if (m_xi2detected) {
01260
01261 XGenericEventCookie *cookie = (XGenericEventCookie*)&xevent->xcookie;
01262 if (XGetEventData(m_display, cookie) &&
01263 cookie->type == GenericEvent &&
01264 cookie->extension == xi_opcode) {
01265 if (cookie->evtype == XI_RawMotion) {
01266
01267 Window root, child;
01268 XMotionEvent xmotion;
01269 xmotion.type = MotionNotify;
01270 xmotion.send_event = False;
01271 xmotion.display = m_display;
01272 xmotion.window = m_window;
01273
01274 unsigned int msk;
01275 xmotion.same_screen = XQueryPointer(
01276 m_display, m_root, &xmotion.root, &xmotion.subwindow,
01277 &xmotion.x_root,
01278 &xmotion.y_root,
01279 &xmotion.x,
01280 &xmotion.y,
01281 &msk);
01282 onMouseMove(xmotion);
01283 XFreeEventData(m_display, cookie);
01284 return;
01285 }
01286 XFreeEventData(m_display, cookie);
01287 }
01288 }
01289 #endif
01290
01291
01292 switch (xevent->type) {
01293 case CreateNotify:
01294 if (m_isPrimary) {
01295
01296 selectEvents(xevent->xcreatewindow.window);
01297 }
01298 break;
01299
01300 case MappingNotify:
01301 refreshKeyboard(xevent);
01302 break;
01303
01304 case LeaveNotify:
01305 if (!m_isPrimary) {
01306
01307 XUnmapWindow(m_display, m_window);
01308 }
01309 break;
01310
01311 case SelectionClear:
01312 {
01313
01314
01315
01316 ClipboardID id = getClipboardID(xevent->xselectionclear.selection);
01317 if (id != kClipboardEnd) {
01318 LOG((CLOG_DEBUG "lost clipboard %d ownership at time %d", id, xevent->xselectionclear.time));
01319 m_clipboard[id]->lost(xevent->xselectionclear.time);
01320 sendClipboardEvent(getClipboardGrabbedEvent(), id);
01321 return;
01322 }
01323 }
01324 break;
01325
01326 case SelectionNotify:
01327
01328
01329
01330
01331 if (xevent->xselection.property != None) {
01332 XDeleteProperty(m_display,
01333 xevent->xselection.requestor,
01334 xevent->xselection.property);
01335 }
01336 break;
01337
01338 case SelectionRequest:
01339 {
01340
01341 ClipboardID id = getClipboardID(
01342 xevent->xselectionrequest.selection);
01343 if (id != kClipboardEnd) {
01344 m_clipboard[id]->addRequest(
01345 xevent->xselectionrequest.owner,
01346 xevent->xselectionrequest.requestor,
01347 xevent->xselectionrequest.target,
01348 xevent->xselectionrequest.time,
01349 xevent->xselectionrequest.property);
01350 return;
01351 }
01352 }
01353 break;
01354
01355 case PropertyNotify:
01356
01357 if (xevent->xproperty.state == PropertyDelete) {
01358 processClipboardRequest(xevent->xproperty.window,
01359 xevent->xproperty.time,
01360 xevent->xproperty.atom);
01361 }
01362 break;
01363
01364 case DestroyNotify:
01365
01366
01367 destroyClipboardRequest(xevent->xdestroywindow.window);
01368 break;
01369
01370 case KeyPress:
01371 if (m_isPrimary) {
01372 onKeyPress(xevent->xkey);
01373 }
01374 return;
01375
01376 case KeyRelease:
01377 if (m_isPrimary) {
01378 onKeyRelease(xevent->xkey, isRepeat);
01379 }
01380 return;
01381
01382 case ButtonPress:
01383 if (m_isPrimary) {
01384 onMousePress(xevent->xbutton);
01385 }
01386 return;
01387
01388 case ButtonRelease:
01389 if (m_isPrimary) {
01390 onMouseRelease(xevent->xbutton);
01391 }
01392 return;
01393
01394 case MotionNotify:
01395 if (m_isPrimary) {
01396 onMouseMove(xevent->xmotion);
01397 }
01398 return;
01399
01400 default:
01401 #if HAVE_XKB_EXTENSION
01402 if (m_xkb && xevent->type == m_xkbEventBase) {
01403 XkbEvent* xkbEvent = reinterpret_cast<XkbEvent*>(xevent);
01404 switch (xkbEvent->any.xkb_type) {
01405 case XkbMapNotify:
01406 refreshKeyboard(xevent);
01407 return;
01408
01409 case XkbStateNotify:
01410 LOG((CLOG_INFO "group change: %d", xkbEvent->state.group));
01411 m_keyState->setActiveGroup((SInt32)xkbEvent->state.group);
01412 return;
01413 }
01414 }
01415 #endif
01416
01417 #if HAVE_X11_EXTENSIONS_XRANDR_H
01418 if (m_xrandr) {
01419 if (xevent->type == m_xrandrEventBase + RRScreenChangeNotify
01420 || xevent->type == m_xrandrEventBase + RRNotify
01421 && reinterpret_cast<XRRNotifyEvent *>(xevent)->subtype == RRNotify_CrtcChange) {
01422 LOG((CLOG_INFO "XRRScreenChangeNotifyEvent or RRNotify_CrtcChange received"));
01423
01424
01425 XRRUpdateConfiguration(xevent);
01426
01427
01428 saveShape();
01429
01430
01431
01432
01433 if (m_isPrimary) {
01434 XMoveWindow(m_display, m_window, m_x, m_y);
01435 XResizeWindow(m_display, m_window, m_w, m_h);
01436 }
01437 }
01438 }
01439 #endif
01440
01441 break;
01442 }
01443 }
01444
01445 void
01446 CXWindowsScreen::onKeyPress(XKeyEvent& xkey)
01447 {
01448 LOG((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xkey.keycode, xkey.state));
01449 const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state);
01450 KeyID key = mapKeyFromX(&xkey);
01451 if (key != kKeyNone) {
01452
01453 if ((key == kKeyPause || key == kKeyBreak) &&
01454 (mask & (KeyModifierControl | KeyModifierAlt)) ==
01455 (KeyModifierControl | KeyModifierAlt)) {
01456
01457 LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
01458 key = kKeyDelete;
01459 }
01460
01461
01462
01463 bool isFake = false;
01464 KeyButton keycode = static_cast<KeyButton>(xkey.keycode);
01465 if (keycode == 0) {
01466 isFake = true;
01467 keycode = static_cast<KeyButton>(m_lastKeycode);
01468 if (keycode == 0) {
01469
01470 return;
01471 }
01472 }
01473
01474
01475 m_keyState->sendKeyEvent(getEventTarget(),
01476 true, false, key, mask, 1, keycode);
01477
01478
01479 if (isFake) {
01480 m_keyState->sendKeyEvent(getEventTarget(),
01481 false, false, key, mask, 1, keycode);
01482 }
01483 }
01484 }
01485
01486 void
01487 CXWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat)
01488 {
01489 const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state);
01490 KeyID key = mapKeyFromX(&xkey);
01491 if (key != kKeyNone) {
01492
01493 if ((key == kKeyPause || key == kKeyBreak) &&
01494 (mask & (KeyModifierControl | KeyModifierAlt)) ==
01495 (KeyModifierControl | KeyModifierAlt)) {
01496
01497 LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
01498 key = kKeyDelete;
01499 isRepeat = false;
01500 }
01501
01502 KeyButton keycode = static_cast<KeyButton>(xkey.keycode);
01503 if (!isRepeat) {
01504
01505 LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", keycode, xkey.state));
01506 m_keyState->sendKeyEvent(getEventTarget(),
01507 false, false, key, mask, 1, keycode);
01508 }
01509 else {
01510
01511
01512
01513
01514 LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, xkey.state));
01515 m_keyState->sendKeyEvent(getEventTarget(),
01516 false, true, key, mask, 1, keycode);
01517 }
01518 }
01519 }
01520
01521 bool
01522 CXWindowsScreen::onHotKey(XKeyEvent& xkey, bool isRepeat)
01523 {
01524
01525 HotKeyToIDMap::const_iterator i =
01526 m_hotKeyToIDMap.find(CHotKeyItem(xkey.keycode, xkey.state));
01527 if (i == m_hotKeyToIDMap.end()) {
01528 return false;
01529 }
01530
01531
01532 CEvent::Type type;
01533 if (xkey.type == KeyPress) {
01534 type = getHotKeyDownEvent();
01535 }
01536 else if (xkey.type == KeyRelease) {
01537 type = getHotKeyUpEvent();
01538 }
01539 else {
01540 return false;
01541 }
01542
01543
01544 if (!isRepeat) {
01545 m_eventQueue.addEvent(CEvent(type, getEventTarget(),
01546 CHotKeyInfo::alloc(i->second)));
01547 }
01548 return true;
01549 }
01550
01551 void
01552 CXWindowsScreen::onMousePress(const XButtonEvent& xbutton)
01553 {
01554 LOG((CLOG_DEBUG1 "event: ButtonPress button=%d", xbutton.button));
01555 ButtonID button = mapButtonFromX(&xbutton);
01556 KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state);
01557 if (button != kButtonNone) {
01558 sendEvent(getButtonDownEvent(), CButtonInfo::alloc(button, mask));
01559 }
01560 }
01561
01562 void
01563 CXWindowsScreen::onMouseRelease(const XButtonEvent& xbutton)
01564 {
01565 LOG((CLOG_DEBUG1 "event: ButtonRelease button=%d", xbutton.button));
01566 ButtonID button = mapButtonFromX(&xbutton);
01567 KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state);
01568 if (button != kButtonNone) {
01569 sendEvent(getButtonUpEvent(), CButtonInfo::alloc(button, mask));
01570 }
01571 else if (xbutton.button == 4) {
01572
01573 sendEvent(getWheelEvent(), CWheelInfo::alloc(0, 120));
01574 }
01575 else if (xbutton.button == 5) {
01576
01577 sendEvent(getWheelEvent(), CWheelInfo::alloc(0, -120));
01578 }
01579
01580 }
01581
01582 void
01583 CXWindowsScreen::onMouseMove(const XMotionEvent& xmotion)
01584 {
01585 LOG((CLOG_DEBUG2 "event: MotionNotify %d,%d", xmotion.x_root, xmotion.y_root));
01586
01587
01588
01589 SInt32 x = xmotion.x_root - m_xCursor;
01590 SInt32 y = xmotion.y_root - m_yCursor;
01591
01592
01593 m_xCursor = xmotion.x_root;
01594 m_yCursor = xmotion.y_root;
01595
01596 if (xmotion.send_event) {
01597
01598
01599
01600
01601
01602 XEvent xevent;
01603 char cntr = 0;
01604 do {
01605 XMaskEvent(m_display, PointerMotionMask, &xevent);
01606 if (cntr++ > 10) {
01607 LOG((CLOG_WARN "too many discarded events! %d", cntr));
01608 break;
01609 }
01610 } while (!xevent.xany.send_event);
01611 cntr = 0;
01612 }
01613 else if (m_isOnScreen) {
01614
01615 sendEvent(getMotionOnPrimaryEvent(),
01616 CMotionInfo::alloc(m_xCursor, m_yCursor));
01617 }
01618 else {
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631 static const SInt32 s_size = 32;
01632 if (xmotion.x_root - m_xCenter < -s_size ||
01633 xmotion.x_root - m_xCenter > s_size ||
01634 xmotion.y_root - m_yCenter < -s_size ||
01635 xmotion.y_root - m_yCenter > s_size) {
01636 warpCursorNoFlush(m_xCenter, m_yCenter);
01637 }
01638
01639
01640
01641
01642
01643
01644
01645 if (x != 0 || y != 0) {
01646 sendEvent(getMotionOnSecondaryEvent(), CMotionInfo::alloc(x, y));
01647 }
01648 }
01649 }
01650
01651 Cursor
01652 CXWindowsScreen::createBlankCursor() const
01653 {
01654
01655
01656
01657 unsigned int w, h;
01658 XQueryBestCursor(m_display, m_root, 1, 1, &w, &h);
01659
01660
01661
01662
01663 const int size = ((w + 7) >> 3) * h;
01664 char* data = new char[size];
01665 memset(data, 0, size);
01666
01667
01668 Pixmap bitmap = XCreateBitmapFromData(m_display, m_root, data, w, h);
01669
01670
01671 XColor color;
01672 color.pixel = 0;
01673 color.red = color.green = color.blue = 0;
01674 color.flags = DoRed | DoGreen | DoBlue;
01675
01676
01677 Cursor cursor = XCreatePixmapCursor(m_display, bitmap, bitmap,
01678 &color, &color, 0, 0);
01679
01680
01681 delete[] data;
01682 XFreePixmap(m_display, bitmap);
01683
01684 return cursor;
01685 }
01686
01687 ClipboardID
01688 CXWindowsScreen::getClipboardID(Atom selection) const
01689 {
01690 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
01691 if (m_clipboard[id] != NULL &&
01692 m_clipboard[id]->getSelection() == selection) {
01693 return id;
01694 }
01695 }
01696 return kClipboardEnd;
01697 }
01698
01699 void
01700 CXWindowsScreen::processClipboardRequest(Window requestor,
01701 Time time, Atom property)
01702 {
01703
01704 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
01705 if (m_clipboard[id] != NULL &&
01706 m_clipboard[id]->processRequest(requestor, time, property)) {
01707 break;
01708 }
01709 }
01710 }
01711
01712 void
01713 CXWindowsScreen::destroyClipboardRequest(Window requestor)
01714 {
01715
01716 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
01717 if (m_clipboard[id] != NULL &&
01718 m_clipboard[id]->destroyRequest(requestor)) {
01719 break;
01720 }
01721 }
01722 }
01723
01724 void
01725 CXWindowsScreen::onError()
01726 {
01727
01728 m_eventQueue.adoptBuffer(NULL);
01729 m_screensaver->destroy();
01730 m_screensaver = NULL;
01731 m_display = NULL;
01732
01733
01734 sendEvent(getErrorEvent(), NULL);
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744 }
01745
01746 int
01747 CXWindowsScreen::ioErrorHandler(Display*)
01748 {
01749
01750
01751
01752
01753 LOG((CLOG_CRIT "X display has unexpectedly disconnected"));
01754 s_screen->onError();
01755 return 0;
01756 }
01757
01758 void
01759 CXWindowsScreen::selectEvents(Window w) const
01760 {
01761
01762
01763
01764 CXWindowsUtil::CErrorLock lock(m_display);
01765
01766
01767 doSelectEvents(w);
01768 }
01769
01770 void
01771 CXWindowsScreen::doSelectEvents(Window w) const
01772 {
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792 if (w == m_window) {
01793 return;
01794 }
01795
01796
01797
01798
01799 XSelectInput(m_display, w, PointerMotionMask | SubstructureNotifyMask);
01800
01801
01802 Window rw, pw, *cw;
01803 unsigned int nc;
01804 if (XQueryTree(m_display, w, &rw, &pw, &cw, &nc)) {
01805 for (unsigned int i = 0; i < nc; ++i) {
01806 doSelectEvents(cw[i]);
01807 }
01808 XFree(cw);
01809 }
01810 }
01811
01812 KeyID
01813 CXWindowsScreen::mapKeyFromX(XKeyEvent* event) const
01814 {
01815
01816 KeySym keysym;
01817 if (event->type == KeyPress && m_ic != NULL) {
01818
01819
01820 char scratch[32];
01821 int n = sizeof(scratch) / sizeof(scratch[0]);
01822 char* buffer = scratch;
01823 int status;
01824 n = XmbLookupString(m_ic, event, buffer, n, &keysym, &status);
01825 if (status == XBufferOverflow) {
01826
01827 buffer = new char[n];
01828 n = XmbLookupString(m_ic, event, buffer, n, &keysym, &status);
01829 delete[] buffer;
01830 }
01831
01832
01833
01834 switch (status) {
01835 default:
01836 case XLookupNone:
01837 case XLookupChars:
01838 keysym = 0;
01839 break;
01840
01841 case XLookupKeySym:
01842 case XLookupBoth:
01843 break;
01844 }
01845 }
01846 else {
01847
01848 char dummy[1];
01849 XLookupString(event, dummy, 0, &keysym, NULL);
01850 }
01851
01852
01853 return CXWindowsUtil::mapKeySymToKeyID(keysym);
01854 }
01855
01856 ButtonID
01857 CXWindowsScreen::mapButtonFromX(const XButtonEvent* event) const
01858 {
01859 unsigned int button = event->button;
01860
01861
01862 if (button >= 1 && button <= 3) {
01863 return static_cast<ButtonID>(button);
01864 }
01865
01866
01867
01868 else if (button >= 6) {
01869 return static_cast<ButtonID>(button - 2);
01870 }
01871
01872
01873 else {
01874 return kButtonNone;
01875 }
01876 }
01877
01878 unsigned int
01879 CXWindowsScreen::mapButtonToX(ButtonID id) const
01880 {
01881
01882 if (id == static_cast<ButtonID>(-1)) {
01883 id = 4;
01884 }
01885
01886
01887 else if (id == static_cast<ButtonID>(-2)) {
01888 id = 5;
01889 }
01890
01891
01892
01893 else if (id >= 4) {
01894 id += 2;
01895 }
01896
01897
01898 if (id < 1 || id > m_buttons.size()) {
01899
01900 return 0;
01901 }
01902
01903
01904 return static_cast<unsigned int>(id);
01905 }
01906
01907 void
01908 CXWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
01909 {
01910 assert(m_window != None);
01911
01912
01913 XEvent eventBefore;
01914 eventBefore.type = MotionNotify;
01915 eventBefore.xmotion.display = m_display;
01916 eventBefore.xmotion.window = m_window;
01917 eventBefore.xmotion.root = m_root;
01918 eventBefore.xmotion.subwindow = m_window;
01919 eventBefore.xmotion.time = CurrentTime;
01920 eventBefore.xmotion.x = x;
01921 eventBefore.xmotion.y = y;
01922 eventBefore.xmotion.x_root = x;
01923 eventBefore.xmotion.y_root = y;
01924 eventBefore.xmotion.state = 0;
01925 eventBefore.xmotion.is_hint = NotifyNormal;
01926 eventBefore.xmotion.same_screen = True;
01927 XEvent eventAfter = eventBefore;
01928 XSendEvent(m_display, m_window, False, 0, &eventBefore);
01929
01930
01931 XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y);
01932
01933
01934 XSendEvent(m_display, m_window, False, 0, &eventAfter);
01935 XSync(m_display, False);
01936
01937 LOG((CLOG_DEBUG2 "warped to %d,%d", x, y));
01938 }
01939
01940 void
01941 CXWindowsScreen::updateButtons()
01942 {
01943
01944 UInt32 numButtons = XGetPointerMapping(m_display, NULL, 0);
01945 unsigned char* tmpButtons = new unsigned char[numButtons];
01946 XGetPointerMapping(m_display, tmpButtons, numButtons);
01947
01948
01949 unsigned char maxButton = 0;
01950 for (UInt32 i = 0; i < numButtons; ++i) {
01951 if (tmpButtons[i] > maxButton) {
01952 maxButton = tmpButtons[i];
01953 }
01954 }
01955
01956
01957 m_buttons.resize(maxButton);
01958
01959
01960
01961 for (UInt32 i = 0; i < numButtons; ++i) {
01962 m_buttons[i] = 0;
01963 }
01964 for (UInt32 i = 0; i < numButtons; ++i) {
01965 m_buttons[tmpButtons[i] - 1] = i + 1;
01966 }
01967
01968
01969 delete[] tmpButtons;
01970 }
01971
01972 bool
01973 CXWindowsScreen::grabMouseAndKeyboard()
01974 {
01975 unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask;
01976
01977
01978
01979
01980 static const double s_timeout = 1.0;
01981 int result;
01982 CStopwatch timer;
01983 do {
01984
01985 do {
01986 result = XGrabKeyboard(m_display, m_window, True,
01987 GrabModeAsync, GrabModeAsync, CurrentTime);
01988 assert(result != GrabNotViewable);
01989 if (result != GrabSuccess) {
01990 LOG((CLOG_DEBUG2 "waiting to grab keyboard"));
01991 ARCH->sleep(0.05);
01992 if (timer.getTime() >= s_timeout) {
01993 LOG((CLOG_DEBUG2 "grab keyboard timed out"));
01994 return false;
01995 }
01996 }
01997 } while (result != GrabSuccess);
01998 LOG((CLOG_DEBUG2 "grabbed keyboard"));
01999
02000
02001 result = XGrabPointer(m_display, m_window, False, event_mask,
02002 GrabModeAsync, GrabModeAsync,
02003 m_window, None, CurrentTime);
02004 assert(result != GrabNotViewable);
02005 if (result != GrabSuccess) {
02006
02007 XUngrabKeyboard(m_display, CurrentTime);
02008 LOG((CLOG_DEBUG2 "ungrabbed keyboard, waiting to grab pointer"));
02009 ARCH->sleep(0.05);
02010 if (timer.getTime() >= s_timeout) {
02011 LOG((CLOG_DEBUG2 "grab pointer timed out"));
02012 return false;
02013 }
02014 }
02015 } while (result != GrabSuccess);
02016
02017 LOG((CLOG_DEBUG1 "grabbed pointer and keyboard"));
02018 return true;
02019 }
02020
02021 void
02022 CXWindowsScreen::refreshKeyboard(XEvent* event)
02023 {
02024 if (XPending(m_display) > 0) {
02025 XEvent tmpEvent;
02026 XPeekEvent(m_display, &tmpEvent);
02027 if (tmpEvent.type == MappingNotify) {
02028
02029
02030 return;
02031 }
02032 }
02033
02034
02035 #if HAVE_XKB_EXTENSION
02036 if (m_xkb && event->type == m_xkbEventBase) {
02037 XkbRefreshKeyboardMapping((XkbMapNotifyEvent*)event);
02038 }
02039 else
02040 #else
02041 {
02042 XRefreshKeyboardMapping(&event->xmapping);
02043 }
02044 #endif
02045 m_keyState->updateKeyMap();
02046 m_keyState->updateKeyState();
02047 }
02048
02049
02050
02051
02052
02053
02054 CXWindowsScreen::CHotKeyItem::CHotKeyItem(int keycode, unsigned int mask) :
02055 m_keycode(keycode),
02056 m_mask(mask)
02057 {
02058
02059 }
02060
02061 bool
02062 CXWindowsScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const
02063 {
02064 return (m_keycode < x.m_keycode ||
02065 (m_keycode == x.m_keycode && m_mask < x.m_mask));
02066 }
02067
02068 bool
02069 CXWindowsScreen::detectXI2()
02070 {
02071 int event, error;
02072 return XQueryExtension(m_display,
02073 "XInputExtension", &xi_opcode, &event, &error);
02074 }
02075
02076 #ifdef HAVE_XI2
02077 void
02078 CXWindowsScreen::selectXIRawMotion()
02079 {
02080 XIEventMask mask;
02081
02082 mask.deviceid = XIAllDevices;
02083 mask.mask_len = XIMaskLen(XI_RawMotion);
02084 mask.mask = (unsigned char*)calloc(mask.mask_len, sizeof(char));
02085 mask.deviceid = XIAllMasterDevices;
02086 memset(mask.mask, 0, 2);
02087 XISetMask(mask.mask, XI_RawKeyRelease);
02088 XISetMask(mask.mask, XI_RawMotion);
02089 XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1);
02090 free(mask.mask);
02091 }
02092 #endif