rectangle.cpp 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* rectangle.cpp: Handles creating rectangles on the screen.
  2. *
  3. * Copyright (C) 2014: Dalton Nell, Slop Contributors (https://github.com/naelstrof/slop/graphs/contributors).
  4. *
  5. * This file is part of Slop.
  6. *
  7. * Slop is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Slop is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Slop. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "rectangle.hpp"
  21. static Bool isDestroyNotify( Display* dpy, XEvent* ev, XPointer win ) {
  22. return ev->type == DestroyNotify && ev->xdestroywindow.window == *((Window*)win);
  23. }
  24. slop::Rectangle::~Rectangle() {
  25. if ( m_window == None ) {
  26. return;
  27. }
  28. // Try to erase the window before destroying it.
  29. XSetWindowBackground( xengine->m_display, m_window, 0 );
  30. XClearWindow( xengine->m_display, m_window );
  31. // Sleep for 0.1 seconds in hope that the rectangle was erased.
  32. usleep( 10000 );
  33. // Free up our color.
  34. XFreeColors( xengine->m_display, xengine->m_colormap, &m_color.pixel, 1, 0 );
  35. XDestroyWindow( xengine->m_display, m_window );
  36. XEvent event;
  37. // Block until the window is actually completely removed.
  38. XIfEvent( xengine->m_display, &event, &isDestroyNotify, (XPointer)&m_window );
  39. // Sleep for 0.1 seconds in hope that the screen actually cleared the window.
  40. usleep( 10000 );
  41. }
  42. slop::Rectangle::Rectangle( int sx, int sy, int ex, int ey, int border, bool highlight, float r, float g, float b, float a ) {
  43. m_x = std::min( sx, ex );
  44. m_y = std::min( sy, ey );
  45. m_width = std::max( sx, ex ) - m_x;
  46. m_height = std::max( sy, ey ) - m_y;
  47. m_border = border;
  48. m_window = None;
  49. m_highlight = highlight;
  50. // If we don't have a border, we don't exist, so just die.
  51. if ( m_border == 0 ) {
  52. return;
  53. }
  54. if ( m_highlight ) {
  55. m_border = 0;
  56. }
  57. m_color = convertColor( r, g, b );
  58. XSetWindowAttributes attributes;
  59. // Set up the window so it's our color
  60. attributes.background_pixel = m_color.pixel;
  61. // Disable window decorations.
  62. attributes.override_redirect = True;
  63. // Make sure we know when we've been successfully destroyed later!
  64. attributes.event_mask = StructureNotifyMask;
  65. unsigned long valueMask = CWBackPixel | CWOverrideRedirect | CWEventMask;
  66. // Create the window
  67. m_window = XCreateWindow( xengine->m_display, xengine->m_root, 0, 0, WidthOfScreen( xengine->m_screen ), HeightOfScreen( xengine->m_screen ),
  68. 0, CopyFromParent, InputOutput,
  69. CopyFromParent, valueMask, &attributes );
  70. if ( a < 1 ) {
  71. // Change the window opacity
  72. unsigned int cardinal_alpha = (unsigned int) (a * (unsigned int)-1) ;
  73. XChangeProperty( xengine->m_display, m_window, XInternAtom( xengine->m_display, "_NET_WM_WINDOW_OPACITY", 0),
  74. XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&cardinal_alpha, 1 );
  75. }
  76. XClassHint classhints;
  77. char name[] = "slop";
  78. classhints.res_name = name;
  79. classhints.res_class = name;
  80. XSetClassHint( xengine->m_display, m_window, &classhints );
  81. // Now punch a hole into it so it looks like a selection rectangle, but only if we're not highlighting.
  82. if ( !m_highlight ) {
  83. XRectangle rects[4];
  84. // Left
  85. rects[0].x = m_x-m_border;
  86. rects[0].y = m_y-m_border;
  87. rects[0].width = m_border;
  88. rects[0].height = m_height+m_border*2;
  89. // Top
  90. rects[1].x = m_x;
  91. rects[1].y = m_y-m_border;
  92. rects[1].width = m_width+m_border;
  93. rects[1].height = m_border;
  94. // Right
  95. rects[2].x = m_x+m_width;
  96. rects[2].y = m_y-m_border;
  97. rects[2].width = m_border;
  98. rects[2].height = m_height+m_border*2;
  99. // Bottom
  100. rects[3].x = m_x;
  101. rects[3].y = m_y+m_height;
  102. rects[3].width = m_width+m_border;
  103. rects[3].height = m_border;
  104. XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, rects, 4, ShapeSet, 0);
  105. } else {
  106. XRectangle rect;
  107. rect.x = m_x;
  108. rect.y = m_y;
  109. rect.width = m_width;
  110. rect.height = m_height;
  111. XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
  112. }
  113. // Make it so all input falls through
  114. XRectangle rect;
  115. rect.x = rect.y = rect.width = rect.height = 0;
  116. XShapeCombineRectangles( xengine->m_display, m_window, ShapeInput, 0, 0, &rect, 1, ShapeSet, 0);
  117. XMapWindow( xengine->m_display, m_window );
  118. }
  119. void slop::Rectangle::setGeo( int sx, int sy, int ex, int ey ) {
  120. int x = std::min( sx, ex );
  121. int y = std::min( sy, ey );
  122. int w = std::max( sx, ex ) - x;
  123. int h = std::max( sy, ey ) - y;
  124. // Only resize or move if we have to, because they're oddly expensive.
  125. m_x = x;
  126. m_y = y;
  127. m_width = w;
  128. m_height = h;
  129. if ( m_border > 0 ) {
  130. XRectangle rects[4];
  131. // Left
  132. rects[0].x = m_x-m_border;
  133. rects[0].y = m_y-m_border;
  134. rects[0].width = m_border;
  135. rects[0].height = m_height+m_border*2;
  136. // Top
  137. rects[1].x = m_x;
  138. rects[1].y = m_y-m_border;
  139. rects[1].width = m_width+m_border;
  140. rects[1].height = m_border;
  141. // Right
  142. rects[2].x = m_x+m_width;
  143. rects[2].y = m_y-m_border;
  144. rects[2].width = m_border;
  145. rects[2].height = m_height+m_border*2;
  146. // Bottom
  147. rects[3].x = m_x;
  148. rects[3].y = m_y+m_height;
  149. rects[3].width = m_width+m_border;
  150. rects[3].height = m_border;
  151. XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, rects, 4, ShapeSet, 0);
  152. } else {
  153. XRectangle rect;
  154. rect.x = m_x;
  155. rect.y = m_y;
  156. rect.width = m_width;
  157. rect.height = m_height;
  158. XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
  159. }
  160. }
  161. XColor slop::Rectangle::convertColor( float r, float g, float b ) {
  162. // Convert float colors to shorts.
  163. short red = short( floor( r * 65535.f ) );
  164. short green = short( floor( g * 65535.f ) );
  165. short blue = short( floor( b * 65535.f ) );
  166. XColor color;
  167. color.red = red;
  168. color.green = green;
  169. color.blue = blue;
  170. int err = XAllocColor( xengine->m_display, xengine->m_colormap, &color );
  171. if ( err == BadColor ) {
  172. fprintf( stderr, "Couldn't allocate color of value %f,%f,%f!\n", r, g, b );
  173. }
  174. return color;
  175. }