mouse.cpp 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #include <chrono>
  2. #include <thread>
  3. #include "mouse.hpp"
  4. void slop::Mouse::setButton( int button, int state ) {
  5. for (unsigned int i=0;i<buttons.size();i++ ) {
  6. if ( buttons[i].x == button ) {
  7. buttons[i].y = state;
  8. return;
  9. }
  10. }
  11. buttons.push_back(glm::ivec2(button,state));
  12. }
  13. int slop::Mouse::getButton( int button ) {
  14. for (unsigned int i=0;i<buttons.size();i++ ) {
  15. if ( buttons[i].x == button ) {
  16. return buttons[i].y;
  17. }
  18. }
  19. return 0;
  20. }
  21. glm::vec2 slop::Mouse::getMousePos() {
  22. Window root, child;
  23. int mx, my;
  24. int wx, wy;
  25. unsigned int mask;
  26. XQueryPointer( x11->display, x11->root, &root, &child, &mx, &my, &wx, &wy, &mask );
  27. return glm::vec2( mx, my );
  28. }
  29. void slop::Mouse::setCursor( int cursor ) {
  30. if ( currentCursor == cursor ) {
  31. return;
  32. }
  33. XFreeCursor( x11->display, xcursor );
  34. xcursor = XCreateFontCursor( x11->display, cursor );
  35. XChangeActivePointerGrab( x11->display,
  36. PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask,
  37. xcursor, CurrentTime );
  38. }
  39. slop::Mouse::Mouse(X11* x11, int nodecorations, Window ignoreWindow ) {
  40. this->x11 = x11;
  41. currentCursor = XC_cross;
  42. xcursor = XCreateFontCursor( x11->display, XC_cross );
  43. hoverWindow = None;
  44. int err = XGrabPointer( x11->display, x11->root, True,
  45. PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask,
  46. GrabModeAsync, GrabModeAsync, None, xcursor, CurrentTime );
  47. int tries = 0;
  48. while( err != GrabSuccess && tries < 5 ) {
  49. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  50. err = XGrabPointer( x11->display, x11->root, True,
  51. PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask,
  52. GrabModeAsync, GrabModeAsync, None, xcursor, CurrentTime );
  53. tries++;
  54. }
  55. if ( err != GrabSuccess ) {
  56. throw new std::runtime_error( "Couldn't grab the mouse after 10 tries." );
  57. }
  58. this->nodecorations = nodecorations;
  59. this->ignoreWindow = ignoreWindow;
  60. hoverWindow = findWindow(x11->root);
  61. }
  62. slop::Mouse::~Mouse() {
  63. XUngrabPointer( x11->display, CurrentTime );
  64. }
  65. void slop::Mouse::update() {
  66. XEvent event;
  67. while ( XCheckTypedEvent( x11->display, ButtonPress, &event ) ) {
  68. setButton( event.xbutton.button, 1 );
  69. }
  70. bool findNewWindow = false;
  71. while ( XCheckTypedEvent( x11->display, MotionNotify, &event ) ) {
  72. findNewWindow = true;
  73. }
  74. if ( findNewWindow ) {
  75. hoverWindow = findWindow(x11->root);
  76. }
  77. while ( XCheckTypedEvent( x11->display, ButtonRelease, &event ) ) {
  78. setButton( event.xbutton.button, 0 );
  79. }
  80. while ( XCheckTypedEvent( x11->display, EnterNotify, &event ) ) {
  81. hoverWindow = event.xcrossing.window;
  82. }
  83. }
  84. Window slop::Mouse::findWindow( Window foo ) {
  85. glm::vec2 pos = getMousePos();
  86. Window root, parent;
  87. Window* children;
  88. unsigned int nchildren;
  89. Window selectedWindow;
  90. XQueryTree( x11->display, foo, &root, &parent, &children, &nchildren );
  91. if ( !children || nchildren <= 0 ) {
  92. return foo;
  93. }
  94. // The children are ordered, so we traverse backwards.
  95. for( int i=nchildren-1;i>=0;i-- ) {
  96. if ( children[i] == ignoreWindow ) {
  97. continue;
  98. }
  99. // We need to make sure the window is mapped.
  100. XWindowAttributes attr;
  101. XGetWindowAttributes( x11->display, children[i], &attr );
  102. if ( attr.map_state != IsViewable ) {
  103. continue;
  104. }
  105. // We need to make sure we can get pixel data from it as well
  106. if ( attr.c_class == InputOnly ) {
  107. continue;
  108. }
  109. glm::vec4 rect = getWindowGeometry(children[i], false);
  110. float a = pos.x - rect.x;
  111. float b = pos.y - rect.y;
  112. if ( a <= rect.z && a >= 0 ) {
  113. if ( b <= rect.w && b >= 0 ) {
  114. selectedWindow = children[i];
  115. switch( nodecorations ) {
  116. case 0:
  117. XFree(children);
  118. return selectedWindow;
  119. case 1:
  120. XFree(children);
  121. //return findWindow( selectedWindow );
  122. XQueryTree( x11->display, selectedWindow, &root, &parent, &children, &nchildren );
  123. if ( !children || nchildren <= 0 ) {
  124. return selectedWindow;
  125. }
  126. return children[nchildren-1];
  127. case 2:
  128. return findWindow( selectedWindow );
  129. }
  130. }
  131. }
  132. }
  133. return foo;
  134. }