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
 ```bash
32
 ```bash
33
 #!/bin/bash
33
 #!/bin/bash
34
 eval `slop`
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
 You can see my implementation of slop in a screenshooter here:
38
 You can see my implementation of slop in a screenshooter here:
65
     -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations
65
     -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations
66
                                    in seconds.
66
                                    in seconds.
67
     -nd, --nodecorations           attempts to remove decorations from window selections.
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
 Examples
70
 Examples
74
-    $ # gray, thick border for maximum visiblity.
71
+    $ # Gray, thick border for maximum visiblity.
75
     $ slop -b=20 -c=0.5,0.5,0.5
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
     $ # Disable window selections. Useful for selecting individual pixels.
77
     $ # Disable window selections. Useful for selecting individual pixels.
81
     $ slop -t=0
78
     $ slop -t=0

+ 87
- 122
main.cpp View File

1
 #include <unistd.h>
1
 #include <unistd.h>
2
 #include <cstdio>
2
 #include <cstdio>
3
 #include "x.hpp"
3
 #include "x.hpp"
4
+#include "rectangle.hpp"
4
 #include "options.hpp"
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
 int main( int argc, char** argv ) {
33
 int main( int argc, char** argv ) {
7
     int err = options->parseOptions( argc, argv );
34
     int err = options->parseOptions( argc, argv );
8
     if ( err ) {
35
     if ( err ) {
11
     int state = 0;
38
     int state = 0;
12
     bool running = true;
39
     bool running = true;
13
     slop::Rectangle* selection = NULL;
40
     slop::Rectangle* selection = NULL;
14
-    slop::Rectangle* windowselection = NULL;
15
     Window window = None;
41
     Window window = None;
16
     std::string xdisplay = options->m_xdisplay;
42
     std::string xdisplay = options->m_xdisplay;
17
     int padding = options->m_padding;
43
     int padding = options->m_padding;
25
     timespec start, time;
51
     timespec start, time;
26
     int cx = 0;
52
     int cx = 0;
27
     int cy = 0;
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
     // First we set up the x interface and grab the mouse,
59
     // First we set up the x interface and grab the mouse,
34
     // if we fail for either we exit immediately.
60
     // if we fail for either we exit immediately.
35
     err = xengine->init( xdisplay.c_str() );
61
     err = xengine->init( xdisplay.c_str() );
36
     if ( err ) {
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
         return err;
64
         return err;
42
     }
65
     }
43
     err = xengine->grabCursor( slop::Cross );
66
     err = xengine->grabCursor( slop::Cross );
44
     if ( err ) {
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
         return err;
69
         return err;
50
     }
70
     }
51
     if ( keyboard ) {
71
     if ( keyboard ) {
52
         err = xengine->grabKeyboard();
72
         err = xengine->grabKeyboard();
53
         if ( err ) {
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
             return err;
75
             return err;
59
         }
76
         }
60
     }
77
     }
69
         double starti = double( start.tv_sec*1000000000L + start.tv_nsec )/1000000000.f;
86
         double starti = double( start.tv_sec*1000000000L + start.tv_nsec )/1000000000.f;
70
         if ( timei - starti > options->m_gracetime ) {
87
         if ( timei - starti > options->m_gracetime ) {
71
             if ( xengine->anyKeyPressed() && keyboard || xengine->mouseDown( 3 ) ) {
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
                 fprintf( stderr, "User pressed key. Canceled selection.\n" );
90
                 fprintf( stderr, "User pressed key. Canceled selection.\n" );
77
                 state = -1;
91
                 state = -1;
78
                 running = false;
92
                 running = false;
88
                 // create a rectangle around it so the user knows he/she can click on it.
102
                 // create a rectangle around it so the user knows he/she can click on it.
89
                 // --but only if the user wants us to
103
                 // --but only if the user wants us to
90
                 if ( window != xengine->m_hoverWindow && tolerance > 0 ) {
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
                     slop::WindowRectangle t;
105
                     slop::WindowRectangle t;
96
                     t.setGeometry( xengine->m_hoverWindow, decorations );
106
                     t.setGeometry( xengine->m_hoverWindow, decorations );
97
                     // Make sure we only apply offsets to windows that we've forcibly removed decorations on.
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
                     } else {
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
                     window = xengine->m_hoverWindow;
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
                 if ( xengine->mouseDown( 1 ) ) {
121
                 if ( xengine->mouseDown( 1 ) ) {
119
-                    if ( windowselection ) {
120
-                        xengine->removeRect( windowselection );
121
-                    }
122
                     state++;
122
                     state++;
123
                 }
123
                 }
124
                 break;
124
                 break;
127
                 // Set the mouse position of where we clicked, used so that click tolerance doesn't affect the rectangle's position.
127
                 // Set the mouse position of where we clicked, used so that click tolerance doesn't affect the rectangle's position.
128
                 cx = xengine->m_mousex;
128
                 cx = xengine->m_mousex;
129
                 cy = xengine->m_mousey;
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
                 state++;
140
                 state++;
131
                 break;
141
                 break;
132
             }
142
             }
133
             case 2: {
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
                 // If the user has let go of the mouse button, we'll just
153
                 // If the user has let go of the mouse button, we'll just
135
                 // continue to the next state.
154
                 // continue to the next state.
136
                 if ( !xengine->mouseDown( 1 ) ) {
155
                 if ( !xengine->mouseDown( 1 ) ) {
137
                     state++;
156
                     state++;
138
                     break;
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
                 int w = xengine->m_mousex - cx;
160
                 int w = xengine->m_mousex - cx;
142
                 int h = xengine->m_mousey - cy;
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
                     continue;
166
                     continue;
148
                 }
167
                 }
149
                 // We also detect which way the user is pulling and set the mouse icon accordingly.
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
                 bool x = selection->m_flippedx;
169
                 bool x = selection->m_flippedx;
152
                 bool y = selection->m_flippedy;
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
                     xengine->setCursor( slop::LowerRightCorner );
174
                     xengine->setCursor( slop::LowerRightCorner );
159
                 } else if ( x && !y ) {
175
                 } else if ( x && !y ) {
160
-                    cxoffset = 1;
161
-                    cyoffset = 0;
162
-                    woffset = -1;
163
-                    hoffset = 1;
164
                     xengine->setCursor( slop::LowerLeftCorner );
176
                     xengine->setCursor( slop::LowerLeftCorner );
165
                 } else if ( !x && y ) {
177
                 } else if ( !x && y ) {
166
-                    cxoffset = 0;
167
-                    cyoffset = 1;
168
-                    woffset = 1;
169
-                    hoffset = -1;
170
                     xengine->setCursor( slop::UpperRightCorner );
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
                     xengine->setCursor( slop::UpperLeftCorner );
180
                     xengine->setCursor( slop::UpperLeftCorner );
177
                 }
181
                 }
178
                 // Set the selection rectangle's dimensions to mouse movement.
182
                 // Set the selection rectangle's dimensions to mouse movement.
179
                 // We use the function setDim since rectangles can't have negative widths,
183
                 // We use the function setDim since rectangles can't have negative widths,
180
                 // and because the rectangles have borders and padding to worry about.
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
                 break;
186
                 break;
184
             }
187
             }
185
             case 3: {
188
             case 3: {
186
                 int x, y, w, h;
189
                 int x, y, w, h;
187
                 // Exit the utility after this state runs once.
190
                 // Exit the utility after this state runs once.
188
                 running = false;
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
                 break;
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
     xengine->releaseCursor();
210
     xengine->releaseCursor();
246
     xengine->releaseKeyboard();
211
     xengine->releaseKeyboard();

+ 9
- 17
options.cpp View File

3
 slop::Options* options = new slop::Options();
3
 slop::Options* options = new slop::Options();
4
 
4
 
5
 slop::Options::Options() {
5
 slop::Options::Options() {
6
+    m_version = "2.0.0";
6
     m_borderSize = 10;
7
     m_borderSize = 10;
7
     m_padding = 0;
8
     m_padding = 0;
8
     m_xdisplay = ":0";
9
     m_xdisplay = ":0";
10
     m_red = 0;
11
     m_red = 0;
11
     m_green = 0;
12
     m_green = 0;
12
     m_blue = 0;
13
     m_blue = 0;
13
-    m_gracetime = 0.3;
14
+    m_gracetime = 0.4;
14
     m_keyboard = true;
15
     m_keyboard = true;
15
     m_decorations = true;
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
 void slop::Options::printHelp() {
19
 void slop::Options::printHelp() {
35
     printf( "    -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations\n" );
32
     printf( "    -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations\n" );
36
     printf( "                                   in seconds.\n" );
33
     printf( "                                   in seconds.\n" );
37
     printf( "    -nd, --nodecorations           attempts to remove decorations from window selections.\n" );
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
     printf( "\n" );
36
     printf( "\n" );
43
     printf( "Examples\n" );
37
     printf( "Examples\n" );
44
-    printf( "    $ # gray, thick border for maximum visiblity.\n" );
38
+    printf( "    $ # Gray, thick border for maximum visiblity.\n" );
45
     printf( "    $ slop -b=20 -c=0.5,0.5,0.5\n" );
39
     printf( "    $ slop -b=20 -c=0.5,0.5,0.5\n" );
46
     printf( "\n" );
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
     printf( "\n" );
43
     printf( "\n" );
50
     printf( "    $ # Disable window selections. Useful for selecting individual pixels.\n" );
44
     printf( "    $ # Disable window selections. Useful for selecting individual pixels.\n" );
51
     printf( "    $ slop -t=0\n" );
45
     printf( "    $ slop -t=0\n" );
64
             if ( m_borderSize < 0 ) {
58
             if ( m_borderSize < 0 ) {
65
                 m_borderSize = 0;
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
         } else if ( matches( arg, "-p=", "--padding=" ) ) {
61
         } else if ( matches( arg, "-p=", "--padding=" ) ) {
73
             int err = parseInt( arg, &m_padding );
62
             int err = parseInt( arg, &m_padding );
74
             if ( err ) {
63
             if ( err ) {
107
         } else if ( matches( arg, "-h", "--help" ) ) {
96
         } else if ( matches( arg, "-h", "--help" ) ) {
108
             printHelp();
97
             printHelp();
109
             return 2;
98
             return 2;
99
+        } else if ( matches( arg, "-v", "--version" ) ) {
100
+            printf( "slop %s\n", m_version.c_str() );
101
+            return 2;
110
         } else {
102
         } else {
111
             if ( i == 0 ) {
103
             if ( i == 0 ) {
112
                 continue;
104
                 continue;

+ 1
- 4
options.hpp View File

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

+ 192
- 0
rectangle.cpp View File

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

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
 
2
 
3
 slop::XEngine* xengine = new slop::XEngine();
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
 int slop::XEngineErrorHandler( Display* dpy, XErrorEvent* event ) {
5
 int slop::XEngineErrorHandler( Display* dpy, XErrorEvent* event ) {
10
     // Ignore XGrabKeyboard BadAccess errors, we can work without it.
6
     // Ignore XGrabKeyboard BadAccess errors, we can work without it.
11
     // 31 = XGrabKeyboard's request code
7
     // 31 = XGrabKeyboard's request code
12
     if ( event->request_code == 31 && event->error_code == BadAccess ) {
8
     if ( event->request_code == 31 && event->error_code == BadAccess ) {
9
+        fprintf( stderr, "_X Error \"BadAccess\" for XGrabKeyboard ignored...\n" );
13
         return 0;
10
         return 0;
14
     }
11
     }
15
     // Everything else should be fatal as I don't like undefined behavior.
12
     // Everything else should be fatal as I don't like undefined behavior.
42
             XFreeCursor( m_display, m_cursors[i] );
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
     XCloseDisplay( m_display );
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
 bool slop::XEngine::mouseDown( unsigned int button ) {
45
 bool slop::XEngine::mouseDown( unsigned int button ) {
68
     if ( button >= m_mouse.size() ) {
46
     if ( button >= m_mouse.size() ) {
69
         return false;
47
         return false;
86
 
64
 
87
     m_good = true;
65
     m_good = true;
88
     XSetErrorHandler( slop::XEngineErrorHandler );
66
     XSetErrorHandler( slop::XEngineErrorHandler );
67
+    selectAllInputs( m_root, EnterWindowMask );
89
     return 0;
68
     return 0;
90
 }
69
 }
91
 
70
 
111
     if ( !m_good ) {
90
     if ( !m_good ) {
112
         return 1;
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
     return 0;
100
     return 0;
116
 }
101
 }
117
 
102
 
123
     return 0;
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
 // Grabs the cursor, be wary that setCursor changes the mouse masks.
122
 // Grabs the cursor, be wary that setCursor changes the mouse masks.
127
 int slop::XEngine::grabCursor( slop::CursorType type ) {
123
 int slop::XEngine::grabCursor( slop::CursorType type ) {
128
     if ( !m_good ) {
124
     if ( !m_good ) {
129
         return 1;
125
         return 1;
130
     }
126
     }
131
     int xfontcursor = getCursor( type );
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
     if ( err != GrabSuccess ) {
131
     if ( err != GrabSuccess ) {
136
         fprintf( stderr, "Error: Failed to grab X cursor.\n" );
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
         return 1;
134
         return 1;
140
     }
135
     }
141
-
142
     // Quickly set the mouse position so we don't have to worry about x11 generating an event.
136
     // Quickly set the mouse position so we don't have to worry about x11 generating an event.
143
     Window root, child;
137
     Window root, child;
144
     int mx, my;
138
     int mx, my;
148
     m_mousex = mx;
142
     m_mousex = mx;
149
     m_mousey = my;
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
     return 0;
152
     return 0;
154
 }
153
 }
155
 
154
 
185
                 }
184
                 }
186
                 break;
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
             case ButtonRelease: {
198
             case ButtonRelease: {
189
                 if ( m_mouse.size() > event.xbutton.button ) {
199
                 if ( m_mouse.size() > event.xbutton.button ) {
190
                     m_mouse.at( event.xbutton.button ) = false;
200
                     m_mouse.at( event.xbutton.button ) = false;
204
             default: break;
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
 // This converts an enum into a preallocated cursor, the cursor will automatically deallocate itself on ~XEngine
219
 // This converts an enum into a preallocated cursor, the cursor will automatically deallocate itself on ~XEngine
246
 }
253
 }
247
 
254
 
248
 void slop::WindowRectangle::setGeometry( Window win, bool decorations ) {
255
 void slop::WindowRectangle::setGeometry( Window win, bool decorations ) {
249
-    Window junk;
250
     if ( decorations ) {
256
     if ( decorations ) {
257
+        Window root, parent, test, junk;
258
+        Window* childlist;
259
+        unsigned int ujunk;
251
         unsigned int depth;
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
         return;
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
     XWindowAttributes attr;
287
     XWindowAttributes attr;
275
     // We use XGetWindowAttributes to know our root window.
288
     // We use XGetWindowAttributes to know our root window.
276
     XGetWindowAttributes( xengine->m_display, win, &attr );
289
     XGetWindowAttributes( xengine->m_display, win, &attr );
281
     m_border = attr.border_width;
294
     m_border = attr.border_width;
282
     XTranslateCoordinates( xengine->m_display, win, attr.root, -attr.border_width, -attr.border_width, &(m_x), &(m_y), &junk );
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
     void         setGeometry( Window win, bool decorations );
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
 class XEngine {
41
 class XEngine {
65
 public:
42
 public:
66
                         XEngine();
43
                         XEngine();
74
     int                 releaseKeyboard();
51
     int                 releaseKeyboard();
75
     void                setCursor( slop::CursorType type );
52
     void                setCursor( slop::CursorType type );
76
     void                drawRect( int x, int y, unsigned int w, unsigned int h );
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
     Display*            m_display;
56
     Display*            m_display;
80
     Visual*             m_visual;
57
     Visual*             m_visual;
81
     Screen*             m_screen;
58
     Screen*             m_screen;
82
     Colormap            m_colormap;
59
     Colormap            m_colormap;
83
     Window              m_root;
60
     Window              m_root;
84
-    int                 m_mousex;
85
-    int                 m_mousey;
61
+    Window              m_hoverWindow;
86
     std::vector<bool>   m_mouse;
62
     std::vector<bool>   m_mouse;
87
     bool                mouseDown( unsigned int button );
63
     bool                mouseDown( unsigned int button );
88
-    Window              m_hoverWindow;
89
     bool                m_keypressed;
64
     bool                m_keypressed;
90
 private:
65
 private:
91
-    void                updateHoverWindow();
92
-    void                updateHoverWindow( Window child );
93
     bool                m_good;
66
     bool                m_good;
94
     std::vector<Cursor> m_cursors;
67
     std::vector<Cursor> m_cursors;
95
-    std::vector<Rectangle*> m_rects;
96
     Cursor              getCursor( slop::CursorType type );
68
     Cursor              getCursor( slop::CursorType type );
69
+    void                selectAllInputs( Window win, long event_mask);
97
 };
70
 };
98
 
71
 
99
 int XEngineErrorHandler( Display* dpy, XErrorEvent* event );
72
 int XEngineErrorHandler( Display* dpy, XErrorEvent* event );