Browse Source

Lots of changes here

Cleaned up code
Windows are now selected via EnterNotify events
Improved response time on rectangle drawing (no longer creates new rectangles when window selection changes, waits 0.01 seconds between re-drawing for xorg to catch up and display)
Removed offset settings as they seem useless
Added --version option
--nodecorations now doesn't attempt to actively search for the correct subwindow. Now it just allows for selection of subwindows. This should keep slop from crashing/not work properly on weird WMs like openbox, but may make it act a little unexpectedly since you can still click on decorations to include them.
Dalton Nell 10 years ago
parent
commit
b2a09cc55a
8 changed files with 414 additions and 436 deletions
  1. 5
    8
      README.md
  2. 87
    122
      main.cpp
  3. 9
    17
      options.cpp
  4. 1
    4
      options.hpp
  5. 192
    0
      rectangle.cpp
  6. 47
    0
      rectangle.hpp
  7. 69
    254
      x.cpp
  8. 4
    31
      x.hpp

+ 5
- 8
README.md View File

@@ -32,7 +32,7 @@ You can also take images using imagemagick like so:
32 32
 ```bash
33 33
 #!/bin/bash
34 34
 eval `slop`
35
-import -window root -crop "$W"x"$H"+$X+$Y ~/myimage.png
35
+import -window root -crop $G ~/myimage.png
36 36
 ```
37 37
 
38 38
 You can see my implementation of slop in a screenshooter here:
@@ -65,17 +65,14 @@ Options
65 65
     -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations
66 66
                                    in seconds.
67 67
     -nd, --nodecorations           attempts to remove decorations from window selections.
68
-    -o=GEOMETRY, --offset=GEOMETRY Offsets window selections, but only if --nodecorations is active and if the
69
-                                   window's decorations were successfully detected. Has a very specific use of
70
-                                   removing shadows from Gnome's window selections right now. GEOMETRY is in
71
-                                   format WxH+X+Y
68
+    -v, --version                  prints version.
72 69
 
73 70
 Examples
74
-    $ # gray, thick border for maximum visiblity.
71
+    $ # Gray, thick border for maximum visiblity.
75 72
     $ slop -b=20 -c=0.5,0.5,0.5
76 73
 
77
-    $ # Remove window decorations, but include the 28px titlebar. Useful to remove the arbitrarily sized shadows in Gnome where they are included in window geometry for whatever reason.
78
-    $ slop -nd -o=0x28+0-28
74
+    $ # Remove window decorations.
75
+    $ slop -nd
79 76
 
80 77
     $ # Disable window selections. Useful for selecting individual pixels.
81 78
     $ slop -t=0

+ 87
- 122
main.cpp View File

@@ -1,8 +1,35 @@
1 1
 #include <unistd.h>
2 2
 #include <cstdio>
3 3
 #include "x.hpp"
4
+#include "rectangle.hpp"
4 5
 #include "options.hpp"
5 6
 
7
+void printSelection( bool cancelled, int x, int y, int w, int h ) {
8
+    printf( "X=%i\n", x );
9
+    printf( "Y=%i\n", y );
10
+    printf( "W=%i\n", w );
11
+    printf( "H=%i\n", h );
12
+    printf( "G=%ix%i", w, h );
13
+    if ( x >= 0 ) {
14
+        printf( "+%i", x );
15
+    } else {
16
+        // Negative is already included
17
+        printf( "%i", x );
18
+    }
19
+    if ( y >= 0 ) {
20
+        printf( "+%i", y );
21
+    } else {
22
+        // Negative is already included
23
+        printf( "%i", y );
24
+    }
25
+    printf( "\n" );
26
+    if ( cancelled ) {
27
+        printf( "Cancel=true\n" );
28
+    } else {
29
+        printf( "Cancel=false\n" );
30
+    }
31
+}
32
+
6 33
 int main( int argc, char** argv ) {
7 34
     int err = options->parseOptions( argc, argv );
8 35
     if ( err ) {
@@ -11,7 +38,6 @@ int main( int argc, char** argv ) {
11 38
     int state = 0;
12 39
     bool running = true;
13 40
     slop::Rectangle* selection = NULL;
14
-    slop::Rectangle* windowselection = NULL;
15 41
     Window window = None;
16 42
     std::string xdisplay = options->m_xdisplay;
17 43
     int padding = options->m_padding;
@@ -25,36 +51,27 @@ int main( int argc, char** argv ) {
25 51
     timespec start, time;
26 52
     int cx = 0;
27 53
     int cy = 0;
28
-    int cxoffset = 0;
29
-    int cyoffset = 0;
30
-    int woffset = 0;
31
-    int hoffset = 0;
54
+    int xmem = 0;
55
+    int ymem = 0;
56
+    int wmem = 0;
57
+    int hmem = 0;
32 58
 
33 59
     // First we set up the x interface and grab the mouse,
34 60
     // if we fail for either we exit immediately.
35 61
     err = xengine->init( xdisplay.c_str() );
36 62
     if ( err ) {
37
-        printf( "X=0\n" );
38
-        printf( "Y=0\n" );
39
-        printf( "W=0\n" );
40
-        printf( "H=0\n" );
63
+        printSelection( true, 0, 0, 0, 0 );
41 64
         return err;
42 65
     }
43 66
     err = xengine->grabCursor( slop::Cross );
44 67
     if ( err ) {
45
-        printf( "X=0\n" );
46
-        printf( "Y=0\n" );
47
-        printf( "W=0\n" );
48
-        printf( "H=0\n" );
68
+        printSelection( true, 0, 0, 0, 0 );
49 69
         return err;
50 70
     }
51 71
     if ( keyboard ) {
52 72
         err = xengine->grabKeyboard();
53 73
         if ( err ) {
54
-            printf( "X=0\n" );
55
-            printf( "Y=0\n" );
56
-            printf( "W=0\n" );
57
-            printf( "H=0\n" );
74
+            printSelection( true, 0, 0, 0, 0 );
58 75
             return err;
59 76
         }
60 77
     }
@@ -69,10 +86,7 @@ int main( int argc, char** argv ) {
69 86
         double starti = double( start.tv_sec*1000000000L + start.tv_nsec )/1000000000.f;
70 87
         if ( timei - starti > options->m_gracetime ) {
71 88
             if ( xengine->anyKeyPressed() && keyboard || xengine->mouseDown( 3 ) ) {
72
-                printf( "X=0\n" );
73
-                printf( "Y=0\n" );
74
-                printf( "W=0\n" );
75
-                printf( "H=0\n" );
89
+                printSelection( true, 0, 0, 0, 0 );
76 90
                 fprintf( stderr, "User pressed key. Canceled selection.\n" );
77 91
                 state = -1;
78 92
                 running = false;
@@ -88,37 +102,23 @@ int main( int argc, char** argv ) {
88 102
                 // create a rectangle around it so the user knows he/she can click on it.
89 103
                 // --but only if the user wants us to
90 104
                 if ( window != xengine->m_hoverWindow && tolerance > 0 ) {
91
-                    // Make sure to delete the old selection rectangle.
92
-                    if ( windowselection ) {
93
-                        xengine->removeRect( windowselection ); // removeRect also dealloc's the rectangle for us.
94
-                    }
95 105
                     slop::WindowRectangle t;
96 106
                     t.setGeometry( xengine->m_hoverWindow, decorations );
97 107
                     // Make sure we only apply offsets to windows that we've forcibly removed decorations on.
98
-                    if ( !t.m_decorations ) {
99
-                        windowselection = new slop::Rectangle( t.m_x + options->m_offsetx,
100
-                                                               t.m_y + options->m_offsety,
101
-                                                               t.m_width + options->m_offsetw,
102
-                                                               t.m_height + options->m_offseth,
103
-                                                               borderSize, padding,
104
-                                                               r, g, b );
108
+                    if ( !selection ) {
109
+                        selection = new slop::Rectangle( t.m_x,
110
+                                                         t.m_y,
111
+                                                         t.m_width,
112
+                                                         t.m_height,
113
+                                                         borderSize, padding,
114
+                                                         r, g, b );
105 115
                     } else {
106
-                        windowselection = new slop::Rectangle( t.m_x,
107
-                                                               t.m_y,
108
-                                                               t.m_width,
109
-                                                               t.m_height,
110
-                                                               borderSize, padding,
111
-                                                               r, g, b );
116
+                        selection->setGeo( t.m_x, t.m_y, t.m_width, t.m_height );
112 117
                     }
113
-                    xengine->addRect( windowselection );
114 118
                     window = xengine->m_hoverWindow;
115 119
                 }
116
-                // If the user clicked, remove the old selection rectangle and then
117
-                // move on to the next state.
120
+                // If the user clicked we move on to the next state.
118 121
                 if ( xengine->mouseDown( 1 ) ) {
119
-                    if ( windowselection ) {
120
-                        xengine->removeRect( windowselection );
121
-                    }
122 122
                     state++;
123 123
                 }
124 124
                 break;
@@ -127,120 +127,85 @@ int main( int argc, char** argv ) {
127 127
                 // Set the mouse position of where we clicked, used so that click tolerance doesn't affect the rectangle's position.
128 128
                 cx = xengine->m_mousex;
129 129
                 cy = xengine->m_mousey;
130
+                // Also remember where the original selection was
131
+                if ( selection ) {
132
+                    xmem = selection->m_x;
133
+                    ymem = selection->m_y;
134
+                    wmem = selection->m_width;
135
+                    hmem = selection->m_height;
136
+                } else {
137
+                    xmem = cx;
138
+                    ymem = cy;
139
+                }
130 140
                 state++;
131 141
                 break;
132 142
             }
133 143
             case 2: {
144
+                // It's possible that our selection doesn't exist still, lets make sure it actually gets created here.
145
+                if ( !selection ) {
146
+                    selection = new slop::Rectangle( cx,
147
+                                                     cy,
148
+                                                     xengine->m_mousex - cx,
149
+                                                     xengine->m_mousey - cy,
150
+                                                     borderSize, padding,
151
+                                                     r, g, b );
152
+                }
134 153
                 // If the user has let go of the mouse button, we'll just
135 154
                 // continue to the next state.
136 155
                 if ( !xengine->mouseDown( 1 ) ) {
137 156
                     state++;
138 157
                     break;
139 158
                 }
140
-                // Check to make sure the user actually wants to drag for a selection before creating a rectangle.
159
+                // Check to make sure the user actually wants to drag for a selection before moving things around.
141 160
                 int w = xengine->m_mousex - cx;
142 161
                 int h = xengine->m_mousey - cy;
143
-                if ( ( std::abs( w ) >= tolerance || std::abs( h ) >= tolerance ) && !selection ) {
144
-                    selection = new slop::Rectangle( cx, cy, 0, 0, borderSize, padding, r, g, b );
145
-                    xengine->addRect( selection );
146
-                } else if ( !selection ) {
162
+                if ( ( std::abs( w ) < tolerance && std::abs( h ) < tolerance ) ) {
163
+                    // We make sure the selection rectangle stays on the window we had selected
164
+                    selection->setGeo( xmem, ymem, wmem, hmem );
165
+                    xengine->setCursor( slop::Left );
147 166
                     continue;
148 167
                 }
149 168
                 // We also detect which way the user is pulling and set the mouse icon accordingly.
150
-                // and offset the rectangle to be accurate, this is because the mouse actually selects a pixel up and to the left.
151 169
                 bool x = selection->m_flippedx;
152 170
                 bool y = selection->m_flippedy;
153
-                if ( !x && !y ) {
154
-                    cxoffset = 0;
155
-                    cyoffset = 0;
156
-                    woffset = 1;
157
-                    hoffset = 1;
171
+                if ( selection->m_width == 0 && selection->m_height == 0 ) {
172
+                    xengine->setCursor( slop::Cross );
173
+                } else if ( !x && !y ) {
158 174
                     xengine->setCursor( slop::LowerRightCorner );
159 175
                 } else if ( x && !y ) {
160
-                    cxoffset = 1;
161
-                    cyoffset = 0;
162
-                    woffset = -1;
163
-                    hoffset = 1;
164 176
                     xengine->setCursor( slop::LowerLeftCorner );
165 177
                 } else if ( !x && y ) {
166
-                    cxoffset = 0;
167
-                    cyoffset = 1;
168
-                    woffset = 1;
169
-                    hoffset = -1;
170 178
                     xengine->setCursor( slop::UpperRightCorner );
171
-                } else {
172
-                    cxoffset = 1;
173
-                    cyoffset = 1;
174
-                    woffset = -1;
175
-                    hoffset = -1;
179
+                } else if ( x && y ) {
176 180
                     xengine->setCursor( slop::UpperLeftCorner );
177 181
                 }
178 182
                 // Set the selection rectangle's dimensions to mouse movement.
179 183
                 // We use the function setDim since rectangles can't have negative widths,
180 184
                 // and because the rectangles have borders and padding to worry about.
181
-                selection->setPos( cx + cxoffset, cy + cyoffset );
182
-                selection->setDim( w + woffset, h + hoffset );
185
+                selection->setGeo( cx, cy, w, h );
183 186
                 break;
184 187
             }
185 188
             case 3: {
186 189
                 int x, y, w, h;
187 190
                 // Exit the utility after this state runs once.
188 191
                 running = false;
189
-                if ( selection ) {
190
-                    // We pull the dimensions and positions from the selection rectangle.
191
-                    // The selection rectangle automatically converts the positions and
192
-                    // dimensions to absolute coordinates when we set them earilier.
193
-                    x = selection->m_x+selection->m_xoffset;
194
-                    y = selection->m_y+selection->m_yoffset;
195
-                    w = selection->m_width;
196
-                    h = selection->m_height;
197
-                    // Delete the rectangle.
198
-                    xengine->removeRect( selection );
199
-                    // if we're not hovering over a window, or our selection is larger than our tolerance
200
-                    // just print the selection.
201
-                    if ( w >= tolerance || h >= tolerance || xengine->m_hoverWindow == None ) {
202
-                        printf( "X=%i\n", x );
203
-                        printf( "Y=%i\n", y );
204
-                        printf( "W=%i\n", w );
205
-                        printf( "H=%i\n", h );
206
-                        break;
207
-                    }
208
-                }
209
-                // Otherwise lets grab the window's dimensions and use those (with padding).
210
-                // --but only if the user lets us, if the user doesn't just select a single pixel there.
211
-                if ( tolerance > 0 ) {
212
-                    slop::WindowRectangle t;
213
-                    t.setGeometry( xengine->m_hoverWindow, decorations );
214
-                    // Make sure we only apply offsets to windows that we've forcibly removed decorations on.
215
-                    if ( !t.m_decorations ) {
216
-                        x = t.m_x - padding + options->m_offsetx;
217
-                        y = t.m_y - padding + options->m_offsety;
218
-                        w = t.m_width + padding * 2 + options->m_offsetw;
219
-                        h = t.m_height + padding * 2 + options->m_offseth;
220
-                    } else {
221
-                        x = t.m_x - padding;
222
-                        y = t.m_y - padding;
223
-                        w = t.m_width + padding * 2;
224
-                        h = t.m_height + padding * 2;
225
-                    }
226
-                } else {
227
-                    x = cx;
228
-                    y = cy;
229
-                    w = 1;
230
-                    h = 1;
231
-                }
232
-                printf( "X=%i\n", x );
233
-                printf( "Y=%i\n", y );
234
-                printf( "W=%i\n", w );
235
-                printf( "H=%i\n", h );
192
+                // We pull the dimensions and positions from the selection rectangle.
193
+                // The selection rectangle automatically converts the positions and
194
+                // dimensions to absolute coordinates when we set them earilier.
195
+                x = selection->m_x+selection->m_xoffset;
196
+                y = selection->m_y+selection->m_yoffset;
197
+                w = selection->m_width;
198
+                h = selection->m_height;
199
+                // Delete the rectangle, which will remove it from the screen.
200
+                delete selection;
201
+                // Print the selection :)
202
+                printSelection( false, x, y, w, h );
236 203
                 break;
237 204
             }
238 205
         }
239
-        // No need to max out CPU
240
-        // FIXME: This could be adjusted to measure how much time has passed,
241
-        // we may very well need to max out the CPU if someone has a really- really
242
-        // bad computer.
243
-        usleep( 1000 );
206
+        // This sleep is required because drawing the rectangles is a very expensive task that acts really weird with Xorg when called as fast as possible.
207
+        // 0.01 seconds
208
+        usleep( 10000 );
244 209
     }
245 210
     xengine->releaseCursor();
246 211
     xengine->releaseKeyboard();

+ 9
- 17
options.cpp View File

@@ -3,6 +3,7 @@
3 3
 slop::Options* options = new slop::Options();
4 4
 
5 5
 slop::Options::Options() {
6
+    m_version = "2.0.0";
6 7
     m_borderSize = 10;
7 8
     m_padding = 0;
8 9
     m_xdisplay = ":0";
@@ -10,13 +11,9 @@ slop::Options::Options() {
10 11
     m_red = 0;
11 12
     m_green = 0;
12 13
     m_blue = 0;
13
-    m_gracetime = 0.3;
14
+    m_gracetime = 0.4;
14 15
     m_keyboard = true;
15 16
     m_decorations = true;
16
-    m_offsetx = 0;
17
-    m_offsety = 0;
18
-    m_offsetw = 0;
19
-    m_offseth = 0;
20 17
 }
21 18
 
22 19
 void slop::Options::printHelp() {
@@ -35,17 +32,14 @@ void slop::Options::printHelp() {
35 32
     printf( "    -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations\n" );
36 33
     printf( "                                   in seconds.\n" );
37 34
     printf( "    -nd, --nodecorations           attempts to remove decorations from window selections.\n" );
38
-    printf( "    -o=GEOMETRY, --offset=GEOMETRY Offsets window selections, but only if --nodecorations is active and if the\n" );
39
-    printf( "                                   window's decorations were successfully detected. Has a very specific use of\n" );
40
-    printf( "                                   removing shadows from Gnome's window selections right now. GEOMETRY is in\n" );
41
-    printf( "                                   format WxH+X+Y\n" );
35
+    printf( "    -v, --version                  prints version.\n" );
42 36
     printf( "\n" );
43 37
     printf( "Examples\n" );
44
-    printf( "    $ # gray, thick border for maximum visiblity.\n" );
38
+    printf( "    $ # Gray, thick border for maximum visiblity.\n" );
45 39
     printf( "    $ slop -b=20 -c=0.5,0.5,0.5\n" );
46 40
     printf( "\n" );
47
-    printf( "    $ # Remove window decorations, but include the 28px titlebar. Useful to remove the arbitrarily sized shadows in Gnome where they are included in window geometry for whatever reason.\n" );
48
-    printf( "    $ slop -nd -o=0x28+0-28\n" );
41
+    printf( "    $ # Remove window decorations.\n" );
42
+    printf( "    $ slop -nd\n" );
49 43
     printf( "\n" );
50 44
     printf( "    $ # Disable window selections. Useful for selecting individual pixels.\n" );
51 45
     printf( "    $ slop -t=0\n" );
@@ -64,11 +58,6 @@ int slop::Options::parseOptions( int argc, char** argv ) {
64 58
             if ( m_borderSize < 0 ) {
65 59
                 m_borderSize = 0;
66 60
             }
67
-        } else if ( matches( arg, "-o=", "--offset=" ) ) {
68
-            int err = parseGeometry( arg, &m_offsetx, &m_offsety, &m_offsetw, &m_offseth );
69
-            if ( err ) {
70
-                return 1;
71
-            }
72 61
         } else if ( matches( arg, "-p=", "--padding=" ) ) {
73 62
             int err = parseInt( arg, &m_padding );
74 63
             if ( err ) {
@@ -107,6 +96,9 @@ int slop::Options::parseOptions( int argc, char** argv ) {
107 96
         } else if ( matches( arg, "-h", "--help" ) ) {
108 97
             printHelp();
109 98
             return 2;
99
+        } else if ( matches( arg, "-v", "--version" ) ) {
100
+            printf( "slop %s\n", m_version.c_str() );
101
+            return 2;
110 102
         } else {
111 103
             if ( i == 0 ) {
112 104
                 continue;

+ 1
- 4
options.hpp View File

@@ -11,6 +11,7 @@ public:
11 11
     int         parseOptions( int argc, char** argv );
12 12
     void        printHelp();
13 13
 
14
+    std::string m_version;
14 15
     int         m_borderSize;
15 16
     int         m_padding;
16 17
     int         m_tolerance;
@@ -21,10 +22,6 @@ public:
21 22
     float       m_gracetime;
22 23
     bool        m_keyboard;
23 24
     bool        m_decorations;
24
-    int         m_offsetx;
25
-    int         m_offsety;
26
-    int         m_offsetw;
27
-    int         m_offseth;
28 25
 private:
29 26
     int         parseInt( std::string arg, int* returnInt );
30 27
     int         parseFloat( std::string arg, float* returnFloat );

+ 192
- 0
rectangle.cpp View File

@@ -0,0 +1,192 @@
1
+#include "rectangle.hpp"
2
+
3
+static Bool isDestroyNotify( Display* dpy, XEvent* ev, XPointer win ) {
4
+    return ev->type == DestroyNotify && ev->xdestroywindow.window == *((Window*)win);
5
+}
6
+
7
+slop::Rectangle::~Rectangle() {
8
+    if ( m_window == None ) {
9
+        return;
10
+    }
11
+    // Free up our color.
12
+    XFreeColors( xengine->m_display, xengine->m_colormap, &m_color.pixel, 1, 0 );
13
+    XDestroyWindow( xengine->m_display, m_window );
14
+    XEvent event;
15
+    // Block until the window is actually completely removed.
16
+    XIfEvent( xengine->m_display, &event, &isDestroyNotify, (XPointer)&m_window );
17
+}
18
+
19
+slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int padding, float r, float g, float b ) {
20
+    m_xoffset = 0;
21
+    m_yoffset = 0;
22
+    m_x = x;
23
+    m_y = y;
24
+    m_width = width;
25
+    m_height = height;
26
+    m_border = border;
27
+    m_padding = padding;
28
+    m_window = None;
29
+
30
+    // Convert the width, height, x, and y to coordinates that don't have negative values.
31
+    // (also adjust for padding and border size.)
32
+    constrain( width, height );
33
+    // If we don't have a border, we don't exist, so just die.
34
+    if ( m_border == 0 ) {
35
+        return;
36
+    }
37
+
38
+    // This sets up m_color
39
+    int err = convertColor( r, g, b );
40
+    if ( err ) {
41
+        fprintf( stderr, "Couldn't allocate color of value %f,%f,%f!\n", r, g, b );
42
+    }
43
+    XSetWindowAttributes attributes;
44
+    // Set up the window so it's our color 
45
+    attributes.background_pixmap = None;
46
+    attributes.background_pixel = m_color.pixel;
47
+    // Not actually sure what this does, but it keeps the window from bugging out :u.
48
+    attributes.override_redirect = True;
49
+    // We must use our color map, because that's where our color is allocated.
50
+    attributes.colormap = xengine->m_colormap;
51
+    // Make sure we know when we've been successfully destroyed later!
52
+    attributes.event_mask = StructureNotifyMask;
53
+    unsigned long valueMask = CWBackPixmap | CWBackPixel | CWOverrideRedirect | CWColormap | CWEventMask;
54
+
55
+    // Create the window offset by our generated offsets (see constrain( float, float ))
56
+    m_window = XCreateWindow( xengine->m_display, xengine->m_root, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border, m_width+m_border*2, m_height+m_border*2,
57
+                              0, CopyFromParent, InputOutput,
58
+                              CopyFromParent, valueMask, &attributes );
59
+
60
+    // Now punch a hole into it so it looks like a selection rectangle!
61
+    XRectangle rect;
62
+    rect.x = rect.y = m_border;
63
+    rect.width = m_width;
64
+    rect.height = m_height;
65
+
66
+    XClassHint classhints;
67
+    char name[] = "slop";
68
+    classhints.res_name = name;
69
+    classhints.res_class = name;
70
+    XSetClassHint( xengine->m_display, m_window, &classhints );
71
+
72
+    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
73
+    XMapWindow( xengine->m_display, m_window );
74
+}
75
+
76
+void slop::Rectangle::setPos( int x, int y ) {
77
+    if ( m_x == x && m_y == y ) {
78
+        return;
79
+    }
80
+    m_x = x;
81
+    m_y = y;
82
+    // If we don't have a border, we don't exist, so just die.
83
+    if ( m_border == 0 ) {
84
+        return;
85
+    }
86
+    XMoveWindow( xengine->m_display, m_window, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border );
87
+}
88
+
89
+void slop::Rectangle::setDim( int w, int h ) {
90
+    if ( m_width == w && m_height == h ) {
91
+        return;
92
+    }
93
+
94
+    constrain( w, h );
95
+    // If we don't have a border, we don't exist, so just die.
96
+    if ( m_border == 0 ) {
97
+        return;
98
+    }
99
+
100
+    // Change the window size and location to our generated offsets (see constrain( float, float ))
101
+    XResizeWindow( xengine->m_display, m_window, m_width+m_border*2, m_height+m_border*2 );
102
+    XMoveWindow( xengine->m_display, m_window, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border );
103
+    // Regenerate our hole
104
+    XRectangle rect;
105
+    rect.x = rect.y = 0;
106
+    rect.width = m_width+m_border*2;
107
+    rect.height = m_height+m_border*2;
108
+    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
109
+    // Then punch out another.
110
+    rect.x = rect.y = m_border;
111
+    rect.width = m_width;
112
+    rect.height = m_height;
113
+    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
114
+}
115
+
116
+void slop::Rectangle::setGeo( int x, int y, int w, int h ) {
117
+    if ( m_x == x && m_y == y && m_width == w && m_height == h ) {
118
+        return;
119
+    }
120
+
121
+    m_x = x;
122
+    m_y = y;
123
+    constrain( w, h );
124
+    // If we don't have a border, we don't exist, so just die.
125
+    if ( m_border == 0 ) {
126
+        return;
127
+    }
128
+
129
+    // Change the window size and location to our generated offsets (see constrain( float, float ))
130
+    XResizeWindow( xengine->m_display, m_window, m_width+m_border*2, m_height+m_border*2 );
131
+    XMoveWindow( xengine->m_display, m_window, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border );
132
+    // Regenerate our hole
133
+    XRectangle rect;
134
+    rect.x = rect.y = 0;
135
+    rect.width = m_width+m_border*2;
136
+    rect.height = m_height+m_border*2;
137
+    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
138
+    // Then punch out another.
139
+    rect.x = rect.y = m_border;
140
+    rect.width = m_width;
141
+    rect.height = m_height;
142
+    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
143
+}
144
+
145
+// Keeps our rectangle's sizes all positive, so Xlib doesn't throw an exception.
146
+// It also keeps our values in absolute coordinates which is nice.
147
+void slop::Rectangle::constrain( int w, int h ) {
148
+    int pad = m_padding;
149
+    if ( pad < 0 && std::abs( w ) < std::abs( pad ) * 2 ) {
150
+        pad = 0;
151
+    }
152
+    if ( w < 0 ) {
153
+        m_flippedx = true;
154
+        m_xoffset = w - pad;
155
+        m_width = -w + pad * 2;
156
+    } else {
157
+        m_flippedx = false;
158
+        m_xoffset = -pad;
159
+        m_width = w + pad * 2;
160
+    }
161
+
162
+    pad = m_padding;
163
+    if ( pad < 0 && std::abs( h ) < std::abs( pad ) * 2 ) {
164
+        pad = 0;
165
+    }
166
+    if ( h < 0 ) {
167
+        m_flippedy = true;
168
+        m_yoffset = h - pad;
169
+        m_height = -h + pad * 2;
170
+    } else {
171
+        m_flippedy = false;
172
+        m_yoffset = -pad;
173
+        m_height = h + pad * 2;
174
+    }
175
+}
176
+
177
+int slop::Rectangle::convertColor( float r, float g, float b ) {
178
+    // Convert float colors to shorts.
179
+    short red   = short( floor( r * 65535.f ) );
180
+    short green = short( floor( g * 65535.f ) );
181
+    short blue  = short( floor( b * 65535.f ) );
182
+    XColor color;
183
+    color.red = red;
184
+    color.green = green;
185
+    color.blue = blue;
186
+    int err = XAllocColor( xengine->m_display, xengine->m_colormap, &color );
187
+    if ( err == BadColor ) {
188
+        return err;
189
+    }
190
+    m_color = color;
191
+    return 0;
192
+}

+ 47
- 0
rectangle.hpp View File

@@ -0,0 +1,47 @@
1
+// rectangle.hpp: handles creating rectangles on screen.
2
+
3
+#ifndef IS_RECTANGLE_H_
4
+#define IS_RECTANGLE_H_
5
+
6
+#include "x.hpp"
7
+
8
+#include <unistd.h>
9
+
10
+#include <X11/Xlib.h>
11
+#include <X11/extensions/shape.h>
12
+
13
+#include <cstdlib>
14
+#include <cmath>
15
+#include <cstdio>
16
+#include <string>
17
+#include <vector>
18
+
19
+namespace slop {
20
+
21
+class Rectangle {
22
+public:
23
+            Rectangle( int x, int y, int width, int height, int border, int padding, float r, float g, float b );
24
+            ~Rectangle();
25
+    void    setPos( int x, int y );
26
+    void    setDim( int w, int h );
27
+    void    setGeo( int x, int y, int w, int h );
28
+    Window  m_window;
29
+    XColor  m_color;
30
+    int     m_x;
31
+    int     m_y;
32
+    int     m_xoffset;
33
+    int     m_yoffset;
34
+    int     m_width;
35
+    int     m_height;
36
+    int     m_border;
37
+    int     m_padding;
38
+    bool    m_flippedx;
39
+    bool    m_flippedy;
40
+private:
41
+    int     convertColor( float r, float g, float b );
42
+    void    constrain( int w, int h );
43
+};
44
+
45
+}
46
+
47
+#endif // IS_RECTANGLE_H_

+ 69
- 254
x.cpp View File

@@ -2,14 +2,11 @@
2 2
 
3 3
 slop::XEngine* xengine = new slop::XEngine();
4 4
 
5
-static Bool isDestroyNotify( Display* dpy, XEvent* ev, XPointer win ) {
6
-    return ev->type == DestroyNotify && ev->xdestroywindow.window == *((Window*)win);
7
-}
8
-
9 5
 int slop::XEngineErrorHandler( Display* dpy, XErrorEvent* event ) {
10 6
     // Ignore XGrabKeyboard BadAccess errors, we can work without it.
11 7
     // 31 = XGrabKeyboard's request code
12 8
     if ( event->request_code == 31 && event->error_code == BadAccess ) {
9
+        fprintf( stderr, "_X Error \"BadAccess\" for XGrabKeyboard ignored...\n" );
13 10
         return 0;
14 11
     }
15 12
     // Everything else should be fatal as I don't like undefined behavior.
@@ -42,28 +39,9 @@ slop::XEngine::~XEngine() {
42 39
             XFreeCursor( m_display, m_cursors[i] );
43 40
         }
44 41
     }
45
-    for ( unsigned int i=0; i<m_rects.size(); i++ ) {
46
-        delete m_rects.at( i );
47
-    }
48 42
     XCloseDisplay( m_display );
49 43
 }
50 44
 
51
-// We need to keep track of the rectangle windows, so that they don't override our "focus"d windows.
52
-void slop::XEngine::addRect( Rectangle* rect ) {
53
-    m_rects.push_back( rect );
54
-}
55
-
56
-void slop::XEngine::removeRect( Rectangle* rect ) {
57
-    for ( unsigned int i=0; i<m_rects.size(); i++ ) {
58
-        if ( m_rects.at( i ) == rect ) {
59
-            m_rects.erase( m_rects.begin() + i );
60
-            i--;
61
-            delete rect;
62
-            return;
63
-        }
64
-    }
65
-}
66
-
67 45
 bool slop::XEngine::mouseDown( unsigned int button ) {
68 46
     if ( button >= m_mouse.size() ) {
69 47
         return false;
@@ -86,6 +64,7 @@ int slop::XEngine::init( std::string display ) {
86 64
 
87 65
     m_good = true;
88 66
     XSetErrorHandler( slop::XEngineErrorHandler );
67
+    selectAllInputs( m_root, EnterWindowMask );
89 68
     return 0;
90 69
 }
91 70
 
@@ -111,7 +90,13 @@ int slop::XEngine::grabKeyboard() {
111 90
     if ( !m_good ) {
112 91
         return 1;
113 92
     }
114
-    XGrabKeyboard( m_display, m_root, False, GrabModeAsync, GrabModeAsync, CurrentTime );
93
+    int err = XGrabKeyboard( m_display, m_root, False, GrabModeAsync, GrabModeAsync, CurrentTime );
94
+    if ( err != GrabSuccess ) {
95
+        fprintf( stderr, "Warning: Failed to grab X keyboard.\n" );
96
+        fprintf( stderr, "         This happens when something's already grabbed your keybaord.\n" );
97
+        fprintf( stderr, "         slop should still run properly though.\n" );
98
+        return 1;
99
+    }
115 100
     return 0;
116 101
 }
117 102
 
@@ -123,22 +108,31 @@ int slop::XEngine::releaseKeyboard() {
123 108
     return 0;
124 109
 }
125 110
 
111
+void slop::XEngine::selectAllInputs( Window win, long event_mask) {
112
+    Window root, parent;
113
+    Window* children;
114
+    unsigned int nchildren;
115
+    XQueryTree( m_display, win, &root, &parent, &children, &nchildren );
116
+    for ( unsigned int i=0;i<nchildren;i++ ) {
117
+        XSelectInput( m_display, children[ i ], event_mask );
118
+        selectAllInputs( children[ i ], event_mask );
119
+    }
120
+}
121
+
126 122
 // Grabs the cursor, be wary that setCursor changes the mouse masks.
127 123
 int slop::XEngine::grabCursor( slop::CursorType type ) {
128 124
     if ( !m_good ) {
129 125
         return 1;
130 126
     }
131 127
     int xfontcursor = getCursor( type );
132
-    int err = XGrabPointer( m_display, m_root, False,
133
-                            PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
134
-                            GrabModeAsync, GrabModeAsync, m_root, xfontcursor, CurrentTime );
128
+    int err = XGrabPointer( m_display, m_root, True,
129
+                            PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask,
130
+                            GrabModeAsync, GrabModeAsync, None, xfontcursor, CurrentTime );
135 131
     if ( err != GrabSuccess ) {
136 132
         fprintf( stderr, "Error: Failed to grab X cursor.\n" );
137
-        fprintf( stderr, "This can be caused by launching slop incorrectly.\n" );
138
-        fprintf( stderr, "gnome-session launches it fine from keyboard binds.\n" );
133
+        fprintf( stderr, "       This can be caused by launching slop weirdly.\n" );
139 134
         return 1;
140 135
     }
141
-
142 136
     // Quickly set the mouse position so we don't have to worry about x11 generating an event.
143 137
     Window root, child;
144 138
     int mx, my;
@@ -148,8 +142,13 @@ int slop::XEngine::grabCursor( slop::CursorType type ) {
148 142
     m_mousex = mx;
149 143
     m_mousey = my;
150 144
 
151
-    // Oh and while we're at it, make sure we set the window we're hoving over as well.
152
-    updateHoverWindow( child );
145
+    // Get the deepest available window.
146
+    Window test = child;
147
+    while( test ) {
148
+        child = test;
149
+        XQueryPointer( m_display, child, &root, &test, &mx, &my, &wx, &wy, &mask );
150
+    }
151
+    m_hoverWindow = child;
153 152
     return 0;
154 153
 }
155 154
 
@@ -185,6 +184,17 @@ void slop::XEngine::tick() {
185 184
                 }
186 185
                 break;
187 186
             }
187
+            case EnterNotify: {
188
+                if ( event.xcrossing.subwindow != None ) {
189
+                    m_hoverWindow = event.xcrossing.subwindow;
190
+                } else {
191
+                    m_hoverWindow = event.xcrossing.window;
192
+                }
193
+                break;
194
+            }
195
+            case LeaveNotify: {
196
+                break;
197
+            }
188 198
             case ButtonRelease: {
189 199
                 if ( m_mouse.size() > event.xbutton.button ) {
190 200
                     m_mouse.at( event.xbutton.button ) = false;
@@ -204,9 +214,6 @@ void slop::XEngine::tick() {
204 214
             default: break;
205 215
         }
206 216
     }
207
-
208
-    // Since I couldn't get Xlib to send EnterNotify or LeaveNotify events, we need to query the underlying window every frame.
209
-    updateHoverWindow();
210 217
 }
211 218
 
212 219
 // This converts an enum into a preallocated cursor, the cursor will automatically deallocate itself on ~XEngine
@@ -246,31 +253,37 @@ void slop::XEngine::setCursor( slop::CursorType type ) {
246 253
 }
247 254
 
248 255
 void slop::WindowRectangle::setGeometry( Window win, bool decorations ) {
249
-    Window junk;
250 256
     if ( decorations ) {
257
+        Window root, parent, test, junk;
258
+        Window* childlist;
259
+        unsigned int ujunk;
251 260
         unsigned int depth;
252
-        XGetGeometry( xengine->m_display, win, &junk,
253
-                      &(m_x), &(m_y),
254
-                      &(m_width), &(m_height),
255
-                      &(m_border), &depth );
256
-        // We make sure we include borders, since we want decorations.
257
-        m_width += m_border * 2;
258
-        m_height += m_border * 2;
259
-        m_decorations = true;
261
+        // Try to find the actual decorations.
262
+        test = win;
263
+        int status = XQueryTree( xengine->m_display, test, &root, &parent, &childlist, &ujunk);
264
+        while( parent != root ) {
265
+            if ( !parent || !status ) {
266
+                break;
267
+            }
268
+            test = parent;
269
+            status = XQueryTree( xengine->m_display, test, &root, &parent, &childlist, &ujunk);
270
+        }
271
+        // Once found, proceed normally.
272
+        if ( test && parent == root && status ) {
273
+            XWindowAttributes attr;
274
+            XGetWindowAttributes( xengine->m_display, test, &attr );
275
+            m_width = attr.width;
276
+            m_height = attr.height;
277
+            m_border = attr.border_width;
278
+            XTranslateCoordinates( xengine->m_display, test, attr.root, -attr.border_width, -attr.border_width, &(m_x), &(m_y), &junk );
279
+            // We make sure we include borders, since we want decorations.
280
+            m_width += m_border * 2;
281
+            m_height += m_border * 2;
282
+        }
260 283
         return;
261 284
     }
262
-    Window root;
263
-    Window* children = NULL;
264
-    unsigned int childcount;
265
-    // Try to get the first child of the specified window, to avoid decorations.
266
-    XQueryTree( xengine->m_display, win, &root, &junk, &children, &childcount );
267
-    if ( childcount == 1 && children ) {
268
-        win = children[ 0 ];
269
-        m_decorations = false;
270
-    } else {
271
-        //fprintf( stderr, "Warning: slop couldn't determine how to remove decorations, continuing without removing decorations...\n" );
272
-        m_decorations = true;
273
-    }
285
+    Window junk;
286
+    // Now here we should be able to just use whatever we get.
274 287
     XWindowAttributes attr;
275 288
     // We use XGetWindowAttributes to know our root window.
276 289
     XGetWindowAttributes( xengine->m_display, win, &attr );
@@ -281,201 +294,3 @@ void slop::WindowRectangle::setGeometry( Window win, bool decorations ) {
281 294
     m_border = attr.border_width;
282 295
     XTranslateCoordinates( xengine->m_display, win, attr.root, -attr.border_width, -attr.border_width, &(m_x), &(m_y), &junk );
283 296
 }
284
-
285
-slop::Rectangle::~Rectangle() {
286
-    //XFreeGC( xengine->m_display, m_gc );
287
-    if ( m_window == None ) {
288
-        return;
289
-    }
290
-    //XFreeColors( xengine->m_display, xengine->m_colormap, m_color.pixel, 1,
291
-    // Attempt to move window offscreen before trying to remove it.
292
-    //XResizeWindow( xengine->m_display, m_window, 1, 1 );
293
-    //XMoveWindow( xengine->m_display, m_window, 0, 0 );
294
-    //XUnmapWindow( xengine->m_display, m_window );
295
-    XDestroyWindow( xengine->m_display, m_window );
296
-    XEvent event;
297
-    // Block until the window is actually completely removed.
298
-    XIfEvent( xengine->m_display, &event, &isDestroyNotify, (XPointer)&m_window );
299
-}
300
-
301
-slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int padding, float r, float g, float b ) {
302
-    m_xoffset = 0;
303
-    m_yoffset = 0;
304
-    m_x = x;
305
-    m_y = y;
306
-    m_width = width;
307
-    m_height = height;
308
-    m_border = border;
309
-    m_padding = padding;
310
-    m_window = None;
311
-
312
-    // Convert the width, height, x, and y to coordinates that don't have negative values.
313
-    // (also adjust for padding and border size.)
314
-    constrain( width, height );
315
-    // If we don't have a border, we don't exist, so just die.
316
-    if ( m_border == 0 ) {
317
-        return;
318
-    }
319
-
320
-    // This sets up m_color
321
-    int err = convertColor( r, g, b );
322
-    if ( err ) {
323
-        fprintf( stderr, "Couldn't allocate color of value %f,%f,%f!\n", r, g, b );
324
-    }
325
-    XSetWindowAttributes attributes;
326
-    // Set up the window so it's our color 
327
-    attributes.background_pixmap = None;
328
-    attributes.background_pixel = m_color.pixel;
329
-    // Not actually sure what this does, but it keeps the window from bugging out :u.
330
-    attributes.override_redirect = True;
331
-    // We must use our color map, because that's where our color is allocated.
332
-    attributes.colormap = xengine->m_colormap;
333
-    // Make sure we know when we've been successfully destroyed later!
334
-    attributes.event_mask = StructureNotifyMask;
335
-    unsigned long valueMask = CWBackPixmap | CWBackPixel | CWOverrideRedirect | CWColormap | CWEventMask;
336
-
337
-    // Create the window offset by our generated offsets (see constrain( float, float ))
338
-    m_window = XCreateWindow( xengine->m_display, xengine->m_root, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border, m_width+m_border*2, m_height+m_border*2,
339
-                              0, CopyFromParent, InputOutput,
340
-                              CopyFromParent, valueMask, &attributes );
341
-
342
-    // Now punch a hole into it so it looks like a selection rectangle!
343
-    XRectangle rect;
344
-    rect.x = rect.y = m_border;
345
-    rect.width = m_width;
346
-    rect.height = m_height;
347
-
348
-    XClassHint classhints;
349
-    char name[] = "slop";
350
-    classhints.res_name = name;
351
-    classhints.res_class = name;
352
-    XSetClassHint( xengine->m_display, m_window, &classhints );
353
-
354
-    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
355
-    XMapWindow( xengine->m_display, m_window );
356
-}
357
-
358
-void slop::Rectangle::setPos( int x, int y ) {
359
-    if ( m_x == x && m_y == y ) {
360
-        return;
361
-    }
362
-    m_x = x;
363
-    m_y = y;
364
-    // If we don't have a border, we don't exist, so just die.
365
-    if ( m_border == 0 ) {
366
-        return;
367
-    }
368
-    XMoveWindow( xengine->m_display, m_window, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border );
369
-}
370
-
371
-void slop::Rectangle::setDim( int w, int h ) {
372
-    if ( m_width == w && m_height == h ) {
373
-        return;
374
-    }
375
-
376
-    constrain( w, h );
377
-    // If we don't have a border, we don't exist, so just die.
378
-    if ( m_border == 0 ) {
379
-        return;
380
-    }
381
-
382
-    // Change the window size and location to our generated offsets (see constrain( float, float ))
383
-    XResizeWindow( xengine->m_display, m_window, m_width+m_border*2, m_height+m_border*2 );
384
-    XMoveWindow( xengine->m_display, m_window, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border );
385
-    // Regenerate our hole
386
-    XRectangle rect;
387
-    rect.x = rect.y = 0;
388
-    rect.width = m_width+m_border*2;
389
-    rect.height = m_height+m_border*2;
390
-    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
391
-    // Then punch out another.
392
-    rect.x = rect.y = m_border;
393
-    rect.width = m_width;
394
-    rect.height = m_height;
395
-    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
396
-}
397
-
398
-void slop::XEngine::updateHoverWindow() {
399
-    Window root, hoverwin;
400
-    int mx, my;
401
-    int wx, wy;
402
-    unsigned int mask;
403
-    // Query the pointer for the child window, the child window is basically the window we're hovering over.
404
-    XQueryPointer( m_display, m_root, &root, &hoverwin, &mx, &my, &wx, &wy, &mask );
405
-    // If we already know that we're hovering over it, do nothing.
406
-    if ( m_hoverWindow == hoverwin ) {
407
-        return;
408
-    }
409
-    // Make sure we can't select one of our selection rectangles, that's just weird.
410
-    for ( unsigned int i=0; i<m_rects.size(); i++ ) {
411
-        if ( m_rects.at( i )->m_window == hoverwin ) {
412
-            return;
413
-        }
414
-    }
415
-    m_hoverWindow = hoverwin;
416
-}
417
-
418
-void slop::XEngine::updateHoverWindow( Window hoverwin ) {
419
-    // Same thing as updateHoverWindow but it uses the specified child.
420
-    // It's used when we first grab the cursor so it's slightly more effecient
421
-    // than calling XQueryPointer twice.
422
-    if ( m_hoverWindow == hoverwin ) {
423
-        return;
424
-    }
425
-    for ( unsigned int i=0; i<m_rects.size(); i++ ) {
426
-        if ( m_rects.at( i )->m_window == hoverwin ) {
427
-            return;
428
-        }
429
-    }
430
-    m_hoverWindow = hoverwin;
431
-}
432
-
433
-// Keeps our rectangle's sizes all positive, so Xlib doesn't throw an exception.
434
-// It also keeps our values in absolute coordinates which is nice.
435
-void slop::Rectangle::constrain( int w, int h ) {
436
-    int pad = m_padding;
437
-    if ( pad < 0 && std::abs( w ) < std::abs( pad )*2 ) {
438
-        pad = 0;
439
-    }
440
-    if ( w < 0 ) {
441
-        m_flippedx = true;
442
-        m_xoffset = w - pad;
443
-        m_width = -w + pad*2;
444
-    } else {
445
-        m_flippedx = false;
446
-        m_xoffset = -pad;
447
-        m_width = w + pad*2;
448
-    }
449
-
450
-    pad = m_padding;
451
-    if ( pad < 0 && std::abs( h ) < std::abs( pad )*2 ) {
452
-        pad = 0;
453
-    }
454
-    if ( h < 0 ) {
455
-        m_flippedy = true;
456
-        m_yoffset = h - pad;
457
-        m_height = -h + pad*2;
458
-    } else {
459
-        m_flippedy = false;
460
-        m_yoffset = -pad;
461
-        m_height = h + pad*2;
462
-    }
463
-}
464
-
465
-int slop::Rectangle::convertColor( float r, float g, float b ) {
466
-    // Convert float colors to shorts.
467
-    short red   = short( floor( r * 65535.f ) );
468
-    short green = short( floor( g * 65535.f ) );
469
-    short blue  = short( floor( b * 65535.f ) );
470
-    XColor color;
471
-    color.red = red;
472
-    color.green = green;
473
-    color.blue = blue;
474
-    // I don't deallocate this anywhere, I think X handles it ???
475
-    int err = XAllocColor( xengine->m_display, xengine->m_colormap, &color );
476
-    if ( err == BadColor ) {
477
-        return err;
478
-    }
479
-    m_color = color;
480
-    return 0;
481
-}

+ 4
- 31
x.hpp View File

@@ -38,29 +38,6 @@ public:
38 38
     void         setGeometry( Window win, bool decorations );
39 39
 };
40 40
 
41
-class Rectangle {
42
-public:
43
-            Rectangle( int x, int y, int width, int height, int border, int padding, float r, float g, float b );
44
-            ~Rectangle();
45
-    void    setPos( int x, int y );
46
-    void    setDim( int w, int h );
47
-    Window  m_window;
48
-    int     m_x;
49
-    int     m_y;
50
-    int     m_xoffset;
51
-    int     m_yoffset;
52
-    int     m_width;
53
-    int     m_height;
54
-    int     m_border;
55
-    int     m_padding;
56
-    XColor  m_color;
57
-    bool    m_flippedx;
58
-    bool    m_flippedy;
59
-private:
60
-    int     convertColor( float r, float g, float b );
61
-    void    constrain( int w, int h );
62
-};
63
-
64 41
 class XEngine {
65 42
 public:
66 43
                         XEngine();
@@ -74,26 +51,22 @@ public:
74 51
     int                 releaseKeyboard();
75 52
     void                setCursor( slop::CursorType type );
76 53
     void                drawRect( int x, int y, unsigned int w, unsigned int h );
77
-    void                addRect( Rectangle* rect );
78
-    void                removeRect( Rectangle* rect );
54
+    int                 m_mousex;
55
+    int                 m_mousey;
79 56
     Display*            m_display;
80 57
     Visual*             m_visual;
81 58
     Screen*             m_screen;
82 59
     Colormap            m_colormap;
83 60
     Window              m_root;
84
-    int                 m_mousex;
85
-    int                 m_mousey;
61
+    Window              m_hoverWindow;
86 62
     std::vector<bool>   m_mouse;
87 63
     bool                mouseDown( unsigned int button );
88
-    Window              m_hoverWindow;
89 64
     bool                m_keypressed;
90 65
 private:
91
-    void                updateHoverWindow();
92
-    void                updateHoverWindow( Window child );
93 66
     bool                m_good;
94 67
     std::vector<Cursor> m_cursors;
95
-    std::vector<Rectangle*> m_rects;
96 68
     Cursor              getCursor( slop::CursorType type );
69
+    void                selectAllInputs( Window win, long event_mask);
97 70
 };
98 71
 
99 72
 int XEngineErrorHandler( Display* dpy, XErrorEvent* event );