Parcourir la source

Added option --maximumsize, using pixel-based selection rather than boundary-based so slop can no longer output a size of 0x0 (unless a window is that size and you somehow hover over it), improved render speed for slower laptops.

naelstrof il y a 9 ans
Parent
révision
780b6a030d
7 fichiers modifiés avec 154 ajouts et 135 suppressions
  1. 74
    26
      main.cpp
  2. 14
    3
      options.cpp
  3. 2
    0
      options.hpp
  4. 19
    98
      rectangle.cpp
  5. 1
    8
      rectangle.hpp
  6. 42
    0
      x.cpp
  7. 2
    0
      x.hpp

+ 74
- 26
main.cpp Voir le fichier

@@ -30,6 +30,59 @@ void printSelection( bool cancelled, int x, int y, int w, int h ) {
30 30
     }
31 31
 }
32 32
 
33
+void constrain( int sx, int sy, int ex, int ey, int padding, int minimumsize, int maximumsize, int* rsx, int* rsy, int* rex, int* rey ) {
34
+    if ( minimumsize > maximumsize && maximumsize > 0 ) {
35
+        fprintf( stderr, "Error: minimumsize is greater than maximumsize.\n" );
36
+        exit( 1 );
37
+    }
38
+    int x = std::min( sx, ex );
39
+    int y = std::min( sy, ey );
40
+    // We add one to make sure we select the pixel under the mouse.
41
+    int w = std::max( sx, ex ) - x + 1;
42
+    int h = std::max( sy, ey ) - y + 1;
43
+    // Make sure we don't turn inside out...
44
+    if ( w + padding*2 >= 0 ) {
45
+        x -= padding;
46
+        w += padding*2;
47
+    }
48
+    if ( h + padding*2 >= 0 ) {
49
+        y -= padding;
50
+        h += padding*2;
51
+    }
52
+    if ( w < minimumsize ) {
53
+        int diff = minimumsize - w;
54
+        w = minimumsize;
55
+        x -= diff/2;
56
+    }
57
+    if ( h < minimumsize ) {
58
+        int diff = minimumsize - h;
59
+        h = minimumsize;
60
+        y -= diff/2;
61
+    }
62
+    if ( maximumsize > 0 ) {
63
+        if ( w > maximumsize ) {
64
+            int diff = w;
65
+            w = maximumsize;
66
+            x += diff/2 - maximumsize/2;
67
+        }
68
+        if ( h > maximumsize ) {
69
+            int diff = h;
70
+            h = maximumsize;
71
+            y += diff/2 - maximumsize/2;
72
+        }
73
+    }
74
+    // Center around mouse if we have a fixed size.
75
+    if ( maximumsize == minimumsize && w == maximumsize && h == maximumsize ) {
76
+        x = ex - maximumsize/2;
77
+        y = ey - maximumsize/2;
78
+        xengine->setCursor( slop::Cross );
79
+    }
80
+    *rsx = x;
81
+    *rsy = y;
82
+    *rex = x + w;
83
+    *rey = y + h;
84
+}
85
+
33 86
 int main( int argc, char** argv ) {
34 87
     int err = options->parseOptions( argc, argv );
35 88
     if ( err ) {
@@ -56,6 +109,7 @@ int main( int argc, char** argv ) {
56 109
     int wmem = 0;
57 110
     int hmem = 0;
58 111
     int minimumsize = options->m_minimumsize;
112
+    int maximumsize = options->m_maximumsize;
59 113
 
60 114
     // First we set up the x interface and grab the mouse,
61 115
     // if we fail for either we exit immediately.
@@ -106,17 +160,18 @@ int main( int argc, char** argv ) {
106 160
                 if ( window != xengine->m_hoverWindow && tolerance > 0 ) {
107 161
                     slop::WindowRectangle t;
108 162
                     t.setGeometry( xengine->m_hoverWindow, decorations );
163
+                    t.applyPadding( padding );
164
+                    t.applyMinMaxSize( minimumsize, maximumsize );
109 165
                     // Make sure we only apply offsets to windows that we've forcibly removed decorations on.
110 166
                     if ( !selection ) {
111 167
                         selection = new slop::Rectangle( t.m_x,
112 168
                                                          t.m_y,
113
-                                                         t.m_width,
114
-                                                         t.m_height,
115
-                                                         borderSize, padding,
116
-                                                         minimumsize, minimumsize,
169
+                                                         t.m_x + t.m_width,
170
+                                                         t.m_y + t.m_height,
171
+                                                         borderSize,
117 172
                                                          r, g, b );
118 173
                     } else {
119
-                        selection->setGeo( t.m_x, t.m_y, t.m_width, t.m_height );
174
+                        selection->setGeo( t.m_x, t.m_y, t.m_x + t.m_width, t.m_y + t.m_height );
120 175
                     }
121 176
                     window = xengine->m_hoverWindow;
122 177
                 }
@@ -148,10 +203,10 @@ int main( int argc, char** argv ) {
148 203
                 if ( !selection ) {
149 204
                     selection = new slop::Rectangle( cx,
150 205
                                                      cy,
151
-                                                     xengine->m_mousex - cx,
152
-                                                     xengine->m_mousey - cy,
153
-                                                     borderSize, padding,
154
-                                                     minimumsize, minimumsize,
206
+                                                     // We add one because pixels start at 0
207
+                                                     xengine->m_mousex + 1,
208
+                                                     xengine->m_mousey + 1,
209
+                                                     borderSize,
155 210
                                                      r, g, b );
156 211
                 }
157 212
                 // If the user has let go of the mouse button, we'll just
@@ -165,14 +220,14 @@ int main( int argc, char** argv ) {
165 220
                 int h = xengine->m_mousey - cy;
166 221
                 if ( ( std::abs( w ) < tolerance && std::abs( h ) < tolerance ) ) {
167 222
                     // We make sure the selection rectangle stays on the window we had selected
168
-                    selection->setGeo( xmem, ymem, wmem, hmem );
223
+                    selection->setGeo( xmem, ymem, xmem + wmem, ymem + hmem );
169 224
                     xengine->setCursor( slop::Left );
170 225
                     continue;
171 226
                 }
172 227
                 // We also detect which way the user is pulling and set the mouse icon accordingly.
173
-                bool x = selection->m_flippedx;
174
-                bool y = selection->m_flippedy;
175
-                if ( selection->m_width == 0 && selection->m_height == 0 ) {
228
+                bool x = cx > xengine->m_mousex;
229
+                bool y = cy > xengine->m_mousey;
230
+                if ( selection->m_width <= 1 && selection->m_height <= 1 ) {
176 231
                     xengine->setCursor( slop::Cross );
177 232
                 } else if ( !x && !y ) {
178 233
                     xengine->setCursor( slop::LowerRightCorner );
@@ -183,18 +238,11 @@ int main( int argc, char** argv ) {
183 238
                 } else if ( x && y ) {
184 239
                     xengine->setCursor( slop::UpperLeftCorner );
185 240
                 }
186
-                // We're 100% accurate, but the mouse can't select the very bottom row or very right column of pixels.
187
-                // We detect if either are 1 pixel off and attempt to correct it.
188
-                if ( cx + w == xengine->getWidth() - 1 ) {
189
-                    w = xengine->getWidth() - cx;
190
-                }
191
-                if ( cy + h == xengine->getHeight() - 1 ) {
192
-                    h = xengine->getHeight() - cy;
193
-                }
241
+                // Apply padding and minimum size adjustments.
242
+                int sx, sy, ex, ey;
243
+                constrain( cx, cy, xengine->m_mousex, xengine->m_mousey, padding, minimumsize, maximumsize, &sx, &sy, &ex, &ey );
194 244
                 // Set the selection rectangle's dimensions to mouse movement.
195
-                // We use the function setDim since rectangles can't have negative widths,
196
-                // and because the rectangles have borders and padding to worry about.
197
-                selection->setGeo( cx, cy, w, h );
245
+                selection->setGeo( sx, sy, ex, ey );
198 246
                 break;
199 247
             }
200 248
             case 3: {
@@ -204,8 +252,8 @@ int main( int argc, char** argv ) {
204 252
                 // We pull the dimensions and positions from the selection rectangle.
205 253
                 // The selection rectangle automatically converts the positions and
206 254
                 // dimensions to absolute coordinates when we set them earilier.
207
-                x = selection->m_x+selection->m_xoffset;
208
-                y = selection->m_y+selection->m_yoffset;
255
+                x = selection->m_x;
256
+                y = selection->m_y;
209 257
                 w = selection->m_width;
210 258
                 h = selection->m_height;
211 259
                 // Delete the rectangle, which will remove it from the screen.

+ 14
- 3
options.cpp Voir le fichier

@@ -3,7 +3,7 @@
3 3
 slop::Options* options = new slop::Options();
4 4
 
5 5
 slop::Options::Options() {
6
-    m_version = "v2.0.5";
6
+    m_version = "v2.0.6";
7 7
     m_borderSize = 10;
8 8
     m_padding = 0;
9 9
     m_xdisplay = ":0";
@@ -15,6 +15,7 @@ slop::Options::Options() {
15 15
     m_keyboard = true;
16 16
     m_decorations = true;
17 17
     m_minimumsize = 0;
18
+    m_maxsize = 0;
18 19
 }
19 20
 
20 21
 void slop::Options::printHelp() {
@@ -33,7 +34,8 @@ void slop::Options::printHelp() {
33 34
     printf( "    -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations\n" );
34 35
     printf( "                                   in seconds.\n" );
35 36
     printf( "    -nd, --nodecorations           attempts to remove decorations from window selections.\n" );
36
-    printf( "    -m=INT, --minimumsize=INT      sets the minimum output of width or height values, useful to avoid outputting 0\n" );
37
+    printf( "    -min=INT, --minimumsize=INT    sets the minimum output of width or height values, useful to avoid outputting 0\n" );
38
+    printf( "    -max=INT, --maxsize=INT        sets the maximum output of width or height values.\n" );
37 39
     printf( "                                   widths or heights.\n" );
38 40
     printf( "    -v, --version                  prints version.\n" );
39 41
     printf( "\n" );
@@ -61,11 +63,16 @@ int slop::Options::parseOptions( int argc, char** argv ) {
61 63
             if ( m_borderSize < 0 ) {
62 64
                 m_borderSize = 0;
63 65
             }
64
-        } else if ( matches( arg, "-m=", "--minimumsize=" ) ) {
66
+        } else if ( matches( arg, "-min=", "--minimumsize=" ) ) {
65 67
             int err = parseInt( arg, &m_minimumsize );
66 68
             if ( err ) {
67 69
                 return 1;
68 70
             }
71
+        } else if ( matches( arg, "-max=", "--minimumsize=" ) ) {
72
+            int err = parseInt( arg, &m_maximumsize );
73
+            if ( err ) {
74
+                return 1;
75
+            }
69 76
         } else if ( matches( arg, "-p=", "--padding=" ) ) {
70 77
             int err = parseInt( arg, &m_padding );
71 78
             if ( err ) {
@@ -116,6 +123,10 @@ int slop::Options::parseOptions( int argc, char** argv ) {
116 123
             return 1;
117 124
         }
118 125
     }
126
+    if ( m_minimumsize > m_maximumsize && m_maximumsize > 0 ) {
127
+        fprintf( stderr, "Error: minimumsize is greater than maximumsize.\n" );
128
+        return 1;
129
+    }
119 130
     return 0;
120 131
 }
121 132
 

+ 2
- 0
options.hpp Voir le fichier

@@ -16,6 +16,8 @@ public:
16 16
     int         m_padding;
17 17
     int         m_tolerance;
18 18
     int         m_minimumsize;
19
+    int         m_maximumsize;
20
+    int         m_maxsize;
19 21
     float       m_red;
20 22
     float       m_green;
21 23
     float       m_blue;

+ 19
- 98
rectangle.cpp Voir le fichier

@@ -14,24 +14,18 @@ slop::Rectangle::~Rectangle() {
14 14
     XEvent event;
15 15
     // Block until the window is actually completely removed.
16 16
     XIfEvent( xengine->m_display, &event, &isDestroyNotify, (XPointer)&m_window );
17
+    // Sleep for 0.1 seconds in hope that the screen actually cleared the window.
18
+    usleep( 10000 );
17 19
 }
18 20
 
19
-slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int padding, int minimumwidth, int minimumheight, 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_minimumwidth = minimumwidth;
27
-    m_minimumheight = minimumheight;
21
+slop::Rectangle::Rectangle( int sx, int sy, int ex, int ey, int border, float r, float g, float b ) {
22
+    m_x = std::min( sx, ex );
23
+    m_y = std::min( sy, ey );
24
+    m_width = std::max( sx, ex ) - m_x;
25
+    m_height = std::max( sy, ey ) - m_y;
28 26
     m_border = border;
29
-    m_padding = padding;
30 27
     m_window = None;
31 28
 
32
-    // Convert the width, height, x, and y to coordinates that don't have negative values.
33
-    // (also adjust for padding and border size.)
34
-    constrain( width, height );
35 29
     // If we don't have a border, we don't exist, so just die.
36 30
     if ( m_border == 0 ) {
37 31
         return;
@@ -54,8 +48,8 @@ slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int
54 48
     attributes.event_mask = StructureNotifyMask;
55 49
     unsigned long valueMask = CWBackPixmap | CWBackPixel | CWOverrideRedirect | CWColormap | CWEventMask;
56 50
 
57
-    // Create the window offset by our generated offsets (see constrain( float, float ))
58
-    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,
51
+    // Create the window
52
+    m_window = XCreateWindow( xengine->m_display, xengine->m_root, m_x-m_border, m_y-m_border, m_width+m_border*2, m_height+m_border*2,
59 53
                               0, CopyFromParent, InputOutput,
60 54
                               CopyFromParent, valueMask, &attributes );
61 55
 
@@ -75,63 +69,27 @@ slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int
75 69
     XMapWindow( xengine->m_display, m_window );
76 70
 }
77 71
 
78
-void slop::Rectangle::setPos( int x, int y ) {
79
-    if ( m_x == x && m_y == y ) {
80
-        return;
81
-    }
82
-    m_x = x;
83
-    m_y = y;
84
-    // If we don't have a border, we don't exist, so just die.
85
-    if ( m_border == 0 ) {
86
-        return;
87
-    }
88
-    XMoveWindow( xengine->m_display, m_window, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border );
89
-}
90
-
91
-void slop::Rectangle::setDim( int w, int h ) {
92
-    if ( m_width == w && m_height == h ) {
93
-        return;
94
-    }
95
-
96
-    constrain( w, h );
97
-    // If we don't have a border, we don't exist, so just die.
98
-    if ( m_border == 0 ) {
99
-        return;
100
-    }
101
-
102
-    // Change the window size and location to our generated offsets (see constrain( float, float ))
103
-    XResizeWindow( xengine->m_display, m_window, m_width+m_border*2, m_height+m_border*2 );
104
-    XMoveWindow( xengine->m_display, m_window, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border );
105
-    // Regenerate our hole
106
-    XRectangle rect;
107
-    rect.x = rect.y = 0;
108
-    rect.width = m_width+m_border*2;
109
-    rect.height = m_height+m_border*2;
110
-    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
111
-    // Then punch out another.
112
-    rect.x = rect.y = m_border;
113
-    rect.width = m_width;
114
-    rect.height = m_height;
115
-    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
116
-}
117
-
118
-void slop::Rectangle::setGeo( int x, int y, int w, int h ) {
72
+void slop::Rectangle::setGeo( int sx, int sy, int ex, int ey ) {
73
+    int x = std::min( sx, ex );
74
+    int y = std::min( sy, ey );
75
+    int w = std::max( sx, ex ) - x;
76
+    int h = std::max( sy, ey ) - y;
119 77
     if ( m_x == x && m_y == y && m_width == w && m_height == h ) {
120 78
         return;
121 79
     }
122 80
 
123 81
     m_x = x;
124 82
     m_y = y;
125
-    constrain( w, h );
83
+    m_width = w;
84
+    m_height = h;
126 85
     // If we don't have a border, we don't exist, so just die.
127 86
     if ( m_border == 0 ) {
128 87
         return;
129 88
     }
130 89
 
131
-    // Change the window size and location to our generated offsets (see constrain( float, float ))
90
+    // Change the window size
132 91
     XResizeWindow( xengine->m_display, m_window, m_width+m_border*2, m_height+m_border*2 );
133
-    XMoveWindow( xengine->m_display, m_window, m_x+m_xoffset-m_border, m_y+m_yoffset-m_border );
134
-    // Regenerate our hole
92
+    // Fill up our old hole
135 93
     XRectangle rect;
136 94
     rect.x = rect.y = 0;
137 95
     rect.width = m_width+m_border*2;
@@ -142,44 +100,7 @@ void slop::Rectangle::setGeo( int x, int y, int w, int h ) {
142 100
     rect.width = m_width;
143 101
     rect.height = m_height;
144 102
     XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
145
-}
146
-
147
-// Keeps our rectangle's sizes all positive, so Xlib doesn't throw an exception.
148
-// It also keeps our values in absolute coordinates which is nice.
149
-void slop::Rectangle::constrain( int w, int h ) {
150
-    int pad = m_padding;
151
-    if ( pad < 0 && std::abs( w ) < std::abs( pad ) * 2 ) {
152
-        pad = 0;
153
-    }
154
-    if ( w < 0 ) {
155
-        m_flippedx = true;
156
-        m_xoffset = w - pad;
157
-        m_width = -w + pad * 2;
158
-    } else {
159
-        m_flippedx = false;
160
-        m_xoffset = -pad;
161
-        m_width = w + pad * 2;
162
-    }
163
-
164
-    pad = m_padding;
165
-    if ( pad < 0 && std::abs( h ) < std::abs( pad ) * 2 ) {
166
-        pad = 0;
167
-    }
168
-    if ( h < 0 ) {
169
-        m_flippedy = true;
170
-        m_yoffset = h - pad;
171
-        m_height = -h + pad * 2;
172
-    } else {
173
-        m_flippedy = false;
174
-        m_yoffset = -pad;
175
-        m_height = h + pad * 2;
176
-    }
177
-    if ( m_width < m_minimumwidth ) {
178
-        m_width = m_minimumwidth;
179
-    }
180
-    if ( m_height < m_minimumheight ) {
181
-        m_height = m_minimumheight;
182
-    }
103
+    XMoveWindow( xengine->m_display, m_window, m_x-m_border, m_y-m_border );
183 104
 }
184 105
 
185 106
 int slop::Rectangle::convertColor( float r, float g, float b ) {

+ 1
- 8
rectangle.hpp Voir le fichier

@@ -20,7 +20,7 @@ namespace slop {
20 20
 
21 21
 class Rectangle {
22 22
 public:
23
-            Rectangle( int x, int y, int width, int height, int border, int padding, int minimumwidth, int minimumheight, float r, float g, float b );
23
+            Rectangle( int sx, int sy, int ex, int ey, int border, float r, float g, float b );
24 24
             ~Rectangle();
25 25
     void    setPos( int x, int y );
26 26
     void    setDim( int w, int h );
@@ -29,16 +29,9 @@ public:
29 29
     XColor  m_color;
30 30
     int     m_x;
31 31
     int     m_y;
32
-    int     m_xoffset;
33
-    int     m_yoffset;
34
-    int     m_minimumwidth;
35
-    int     m_minimumheight;
36 32
     int     m_width;
37 33
     int     m_height;
38 34
     int     m_border;
39
-    int     m_padding;
40
-    bool    m_flippedx;
41
-    bool    m_flippedy;
42 35
 private:
43 36
     int     convertColor( float r, float g, float b );
44 37
     void    constrain( int w, int h );

+ 42
- 0
x.cpp Voir le fichier

@@ -268,6 +268,48 @@ void slop::XEngine::setCursor( slop::CursorType type ) {
268 268
                               xfontcursor, CurrentTime );
269 269
 }
270 270
 
271
+void slop::WindowRectangle::applyPadding( int padding ) {
272
+    if ( m_width + padding*2 >= 0 ) {
273
+        m_x -= padding;
274
+        m_width += padding*2;
275
+    }
276
+    if ( m_height + padding*2 >= 0 ) {
277
+        m_y -= padding;
278
+        m_height += padding*2;
279
+    }
280
+}
281
+
282
+void slop::WindowRectangle::applyMinMaxSize( int minimumsize, int maximumsize ) {
283
+    if ( minimumsize > maximumsize && maximumsize > 0 ) {
284
+        fprintf( stderr, "Error: minimumsize is greater than maximumsize.\n" );
285
+        exit( 1 );
286
+    }
287
+    if ( m_width < minimumsize ) {
288
+        int diff = minimumsize - m_width;
289
+        m_width = minimumsize;
290
+        m_x -= diff/2;
291
+    }
292
+    if ( m_height < minimumsize ) {
293
+        int diff = minimumsize - m_height;
294
+        m_height = minimumsize;
295
+        m_y -= diff/2;
296
+    }
297
+    if ( maximumsize > 0 ) {
298
+        if ( m_width > maximumsize ) {
299
+            int diff = m_width;
300
+            m_width = maximumsize;
301
+            // Center in the center of the window
302
+            m_x += diff/2 - maximumsize/2;
303
+        }
304
+        if ( m_height > maximumsize ) {
305
+            int diff = m_height;
306
+            m_height = maximumsize;
307
+            // Center in the center of the window
308
+            m_y += diff/2 - maximumsize/2;
309
+        }
310
+    }
311
+}
312
+
271 313
 void slop::WindowRectangle::setGeometry( Window win, bool decorations ) {
272 314
     if ( decorations ) {
273 315
         Window root, parent, test, junk;

+ 2
- 0
x.hpp Voir le fichier

@@ -38,6 +38,8 @@ public:
38 38
     unsigned int m_border;
39 39
     bool         m_decorations;
40 40
     void         setGeometry( Window win, bool decorations );
41
+    void         applyPadding( int padding );
42
+    void         applyMinMaxSize( int minimumsize, int maximumsize );
41 43
 };
42 44
 
43 45
 class XEngine {