Bladeren bron

Added a --nodecoration window selection feature, and a way to offset selections that had decorations removed.

Dalton Nell 10 jaren geleden
bovenliggende
commit
eae2f3fa73
6 gewijzigde bestanden met toevoegingen van 199 en 61 verwijderingen
  1. 37
    2
      README.md
  2. 36
    15
      main.cpp
  3. 67
    11
      options.cpp
  4. 6
    0
      options.hpp
  5. 47
    28
      x.cpp
  6. 6
    5
      x.hpp

+ 37
- 2
README.md Bestand weergeven

@@ -12,9 +12,10 @@ features
12 12
 * Supports simple arguments:
13 13
     * Change selection rectangle border size.
14 14
     * Select X display.
15
-    * Set padding size, even to negative padding sizes!
15
+    * Set padding size, even negative padding sizes!
16 16
     * Set click tolerance for if you have a shaky mouse.
17 17
     * Set the color of the selection rectangles to match your theme!
18
+    * Remove window decorations from selections.
18 19
 
19 20
 practical applications
20 21
 ----------------------
@@ -44,4 +45,38 @@ Ok. Here's a comparison between 'scrot -s's selection and slop's:
44 45
 ![slopgood](http://farmpolice.com/content/images/slrn_good.png)
45 46
 
46 47
 You can see scrot leaves garbage lines over the things you're trying to screenshot!
47
-While slop not only looks nicer, it's impossible for it to end up in screenshots or recordings because it shuts down before ffmpeg or imagemagick can take a picture.
48
+While slop not only looks nicer, it's impossible for it to end up in screenshots or recordings because it waits for DestroyNotify events before completely shutting down. Only after the window is completely destroyed can ffmpeg or imagemagick take a picture.
49
+
50
+help
51
+----
52
+```text
53
+Usage: slop [options]
54
+Print user selected region to stdout. Pressing keys or right-clicking cancels selection.
55
+
56
+Options
57
+    -h, --help                     Show this message.
58
+    -nkb, --nokeyboard             Disables the ability to cancel selections with the keyboard.
59
+    -b=INT, --bordersize=INT       Set selection rectangle border size.
60
+    -p=INT, --padding=INT          Set padding size for selection.
61
+    -t=INT, --tolerance=INT        How far in pixels the mouse can move after clicking and still be detected
62
+                                   as a normal click. Setting to zero will disable window selections.
63
+    -x=STRING, --xdisplay=STRING   Set x display (STRING must be hostname:number.screen_number format)
64
+    -c=COLOR, --color=COLOR        Set selection rectangle color, COLOR is in format FLOAT,FLOAT,FLOAT
65
+    -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations
66
+                                   in seconds.
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
72
+
73
+Examples
74
+    $ # gray, thick border for maximum visiblity.
75
+    $ slop -b=20 -c=0.5,0.5,0.5
76
+
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
79
+
80
+    $ # Disable window selections. Useful for selecting individual pixels.
81
+    $ slop -t=0
82
+```

+ 36
- 15
main.cpp Bestand weergeven

@@ -21,6 +21,7 @@ int main( int argc, char** argv ) {
21 21
     float g = options->m_green;
22 22
     float b = options->m_blue;
23 23
     bool keyboard = options->m_keyboard;
24
+    bool decorations = options->m_decorations;
24 25
     timespec start, time;
25 26
     int cx = 0;
26 27
     int cy = 0;
@@ -86,20 +87,31 @@ int main( int argc, char** argv ) {
86 87
                 // If xengine has found a window we're hovering over (or if it changed)
87 88
                 // create a rectangle around it so the user knows he/she can click on it.
88 89
                 // --but only if the user wants us to
89
-                if ( window != xengine->m_hoverXWindow && tolerance > 0 ) {
90
+                if ( window != xengine->m_hoverWindow && tolerance > 0 ) {
90 91
                     // Make sure to delete the old selection rectangle.
91 92
                     if ( windowselection ) {
92 93
                         xengine->removeRect( windowselection ); // removeRect also dealloc's the rectangle for us.
93 94
                     }
94
-                    slop::WindowRectangle t = xengine->m_hoverWindow;
95
-                    windowselection = new slop::Rectangle( t.m_x,
96
-                                                         t.m_y,
97
-                                                         t.m_width + t.m_border * 2,
98
-                                                         t.m_height + t.m_border * 2,
99
-                                                         borderSize, padding,
100
-                                                         r, g, b );
95
+                    slop::WindowRectangle t;
96
+                    t.setGeometry( xengine->m_hoverWindow, decorations );
97
+                    // 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 );
105
+                    } 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 );
112
+                    }
101 113
                     xengine->addRect( windowselection );
102
-                    window = xengine->m_hoverXWindow;
114
+                    window = xengine->m_hoverWindow;
103 115
                 }
104 116
                 // If the user clicked, remove the old selection rectangle and then
105 117
                 // move on to the next state.
@@ -186,7 +198,7 @@ int main( int argc, char** argv ) {
186 198
                     xengine->removeRect( selection );
187 199
                     // if we're not hovering over a window, or our selection is larger than our tolerance
188 200
                     // just print the selection.
189
-                    if ( w >= tolerance || h >= tolerance || xengine->m_hoverXWindow == None ) {
201
+                    if ( w >= tolerance || h >= tolerance || xengine->m_hoverWindow == None ) {
190 202
                         printf( "X=%i\n", x );
191 203
                         printf( "Y=%i\n", y );
192 204
                         printf( "W=%i\n", w );
@@ -197,11 +209,20 @@ int main( int argc, char** argv ) {
197 209
                 // Otherwise lets grab the window's dimensions and use those (with padding).
198 210
                 // --but only if the user lets us, if the user doesn't just select a single pixel there.
199 211
                 if ( tolerance > 0 ) {
200
-                    slop::WindowRectangle t = xengine->m_hoverWindow;
201
-                    x = t.m_x - padding;
202
-                    y = t.m_y - padding;
203
-                    w = t.m_width + t.m_border * 2 + padding * 2;
204
-                    h = t.m_height + t.m_border * 2 + padding * 2;
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
+                    }
205 226
                 } else {
206 227
                     x = cx;
207 228
                     y = cy;

+ 67
- 11
options.cpp Bestand weergeven

@@ -12,23 +12,43 @@ slop::Options::Options() {
12 12
     m_blue = 0;
13 13
     m_gracetime = 0.3;
14 14
     m_keyboard = true;
15
+    m_decorations = true;
16
+    m_offsetx = 0;
17
+    m_offsety = 0;
18
+    m_offsetw = 0;
19
+    m_offseth = 0;
15 20
 }
16 21
 
17 22
 void slop::Options::printHelp() {
18 23
     printf( "Usage: slop [options]\n" );
19 24
     printf( "Print user selected region to stdout. Pressing keys or right-clicking cancels selection.\n" );
20 25
     printf( "\n" );
21
-    printf( "options\n" );
22
-    printf( "    -h, --help                     show this message.\n" );
23
-    printf( "    -nkb, --nokeyboard             disables the ability to cancel selections with the keyboard.\n" );
24
-    printf( "    -b=INT, --bordersize=INT       set selection rectangle border size.\n" );
25
-    printf( "    -p=INT, --padding=INT          set padding size for selection.\n" );
26
-    printf( "    -t=INT, --tolerance=INT        if you have a shaky mouse, increasing this value will make slop detect single clicks better. Rather than interpreting your shaky clicks as region selections. Setting to zero will disable window selections.\n" );
27
-    printf( "    -x=STRING, --xdisplay=STRING   set x display (STRING must be hostname:number.screen_number format)\n" );
28
-    printf( "    -c=COLOR, --color=COLOR        set selection rectangle color, COLOR is in format FLOAT,FLOAT,FLOAT\n" );
29
-    printf( "    -g=FLOAT, --gracetime=FLOAT    set the amount of time before slop will check for keyboard cancellations in seconds.\n" );
30
-    printf( "examples\n" );
31
-    printf( "    slop -b=10 -x=:0 -p=-30 -t=4 -c=0.5,0.5,0.5 -g=.3\n" );
26
+    printf( "Options\n" );
27
+    printf( "    -h, --help                     Show this message.\n" );
28
+    printf( "    -nkb, --nokeyboard             Disables the ability to cancel selections with the keyboard.\n" );
29
+    printf( "    -b=INT, --bordersize=INT       Set selection rectangle border size.\n" );
30
+    printf( "    -p=INT, --padding=INT          Set padding size for selection.\n" );
31
+    printf( "    -t=INT, --tolerance=INT        How far in pixels the mouse can move after clicking and still be detected\n" );
32
+    printf( "                                   as a normal click. Setting to zero will disable window selections.\n" );
33
+    printf( "    -x=STRING, --xdisplay=STRING   Set x display (STRING must be hostname:number.screen_number format)\n" );
34
+    printf( "    -c=COLOR, --color=COLOR        Set selection rectangle color, COLOR is in format FLOAT,FLOAT,FLOAT\n" );
35
+    printf( "    -g=FLOAT, --gracetime=FLOAT    Set the amount of time before slop will check for keyboard cancellations\n" );
36
+    printf( "                                   in seconds.\n" );
37
+    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" );
42
+    printf( "\n" );
43
+    printf( "Examples\n" );
44
+    printf( "    $ # gray, thick border for maximum visiblity.\n" );
45
+    printf( "    $ slop -b=20 -c=0.5,0.5,0.5\n" );
46
+    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" );
49
+    printf( "\n" );
50
+    printf( "    $ # Disable window selections. Useful for selecting individual pixels.\n" );
51
+    printf( "    $ slop -t=0\n" );
32 52
 }
33 53
 
34 54
 int slop::Options::parseOptions( int argc, char** argv ) {
@@ -44,6 +64,11 @@ int slop::Options::parseOptions( int argc, char** argv ) {
44 64
             if ( m_borderSize < 0 ) {
45 65
                 m_borderSize = 0;
46 66
             }
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
+            }
47 72
         } else if ( matches( arg, "-p=", "--padding=" ) ) {
48 73
             int err = parseInt( arg, &m_padding );
49 74
             if ( err ) {
@@ -77,6 +102,8 @@ int slop::Options::parseOptions( int argc, char** argv ) {
77 102
             }
78 103
         } else if ( matches( arg, "-nkb", "--nokeyboard" ) ) {
79 104
             m_keyboard = false;
105
+        } else if ( matches( arg, "-nd", "--nodecorations" ) ) {
106
+            m_decorations = false;
80 107
         } else if ( matches( arg, "-h", "--help" ) ) {
81 108
             printHelp();
82 109
             return 2;
@@ -195,3 +222,32 @@ int slop::Options::parseColor( std::string arg, float* r, float* g, float* b ) {
195 222
     delete[] x;
196 223
     return 0;
197 224
 }
225
+
226
+int slop::Options::parseGeometry( std::string arg, int* x, int* y, int* w, int* h ) {
227
+    std::string copy = arg;
228
+    // Replace the first =, all x's and +'s with spaces.
229
+    int find = copy.find( "=" );
230
+    while( find != copy.npos ) {
231
+        copy.at( find ) = ' ';
232
+        find = copy.find( "x" );
233
+    }
234
+    find = copy.find( "+" );
235
+    while( find != copy.npos ) {
236
+        copy.at( find ) = ' ';
237
+        find = copy.find( "+" );
238
+    }
239
+
240
+    // Just in case we error out, grab the actual argument name into x.
241
+    char* foo = new char[ arg.size() ];
242
+    int num = sscanf( copy.c_str(), "%s %d %d %d %d", foo, w, h, x, y );
243
+    if ( num != 5 ) {
244
+        fprintf( stderr, "Error parsing command arguments near %s\n", arg.c_str() );
245
+        fprintf( stderr, "Usage: %s=GEOMETRY\n", foo );
246
+        fprintf( stderr, "Example: %s=1920x1080+0+0 or %s=256x256+100+-200\n", foo, foo );
247
+        fprintf( stderr, "Try -h or --help for help.\n" );
248
+        delete[] foo;
249
+        return 1;
250
+    }
251
+    delete[] foo;
252
+    return 0;
253
+}

+ 6
- 0
options.hpp Bestand weergeven

@@ -20,10 +20,16 @@ public:
20 20
     std::string m_xdisplay;
21 21
     float       m_gracetime;
22 22
     bool        m_keyboard;
23
+    bool        m_decorations;
24
+    int         m_offsetx;
25
+    int         m_offsety;
26
+    int         m_offsetw;
27
+    int         m_offseth;
23 28
 private:
24 29
     int         parseInt( std::string arg, int* returnInt );
25 30
     int         parseFloat( std::string arg, float* returnFloat );
26 31
     int         parseString( std::string arg, std::string* returnString );
32
+    int         parseGeometry( std::string arg, int* x, int* y, int* w, int* h );
27 33
     int         parseColor( std::string arg, float* r, float* g, float* b );
28 34
     bool        matches( std::string arg, std::string shorthand, std::string longhand );
29 35
 };

+ 47
- 28
x.cpp Bestand weergeven

@@ -30,7 +30,7 @@ slop::XEngine::XEngine() {
30 30
     m_good = false;
31 31
     m_mousex = -1;
32 32
     m_mousey = -1;
33
-    m_hoverXWindow = None;
33
+    m_hoverWindow = None;
34 34
 }
35 35
 
36 36
 slop::XEngine::~XEngine() {
@@ -245,6 +245,43 @@ void slop::XEngine::setCursor( slop::CursorType type ) {
245 245
                               xfontcursor, CurrentTime );
246 246
 }
247 247
 
248
+void slop::WindowRectangle::setGeometry( Window win, bool decorations ) {
249
+    Window junk;
250
+    if ( decorations ) {
251
+        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;
260
+        return;
261
+    }
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
+    }
274
+    XWindowAttributes attr;
275
+    // We use XGetWindowAttributes to know our root window.
276
+    XGetWindowAttributes( xengine->m_display, win, &attr );
277
+    //m_x = attr.x;
278
+    //m_y = attr.y;
279
+    m_width = attr.width;
280
+    m_height = attr.height;
281
+    m_border = attr.border_width;
282
+    XTranslateCoordinates( xengine->m_display, win, attr.root, -attr.border_width, -attr.border_width, &(m_x), &(m_y), &junk );
283
+}
284
+
248 285
 slop::Rectangle::~Rectangle() {
249 286
     //XFreeGC( xengine->m_display, m_gc );
250 287
     if ( m_window == None ) {
@@ -359,56 +396,38 @@ void slop::Rectangle::setDim( int w, int h ) {
359 396
 }
360 397
 
361 398
 void slop::XEngine::updateHoverWindow() {
362
-    Window root, child;
399
+    Window root, hoverwin;
363 400
     int mx, my;
364 401
     int wx, wy;
365 402
     unsigned int mask;
366 403
     // Query the pointer for the child window, the child window is basically the window we're hovering over.
367
-    XQueryPointer( m_display, m_root, &root, &child, &mx, &my, &wx, &wy, &mask );
404
+    XQueryPointer( m_display, m_root, &root, &hoverwin, &mx, &my, &wx, &wy, &mask );
368 405
     // If we already know that we're hovering over it, do nothing.
369
-    if ( m_hoverXWindow == child ) {
406
+    if ( m_hoverWindow == hoverwin ) {
370 407
         return;
371 408
     }
372 409
     // Make sure we can't select one of our selection rectangles, that's just weird.
373 410
     for ( unsigned int i=0; i<m_rects.size(); i++ ) {
374
-        if ( m_rects.at( i )->m_window == child ) {
411
+        if ( m_rects.at( i )->m_window == hoverwin ) {
375 412
             return;
376 413
         }
377 414
     }
378
-    m_hoverXWindow = child;
379
-    if ( child == None ) {
380
-        return;
381
-    }
382
-    // Generate the geometry values so we can use them if needed.
383
-    unsigned int depth;
384
-    XGetGeometry( m_display, child, &root,
385
-                  &(m_hoverWindow.m_x), &(m_hoverWindow.m_y),
386
-                  &(m_hoverWindow.m_width), &(m_hoverWindow.m_height),
387
-                  &(m_hoverWindow.m_border), &depth );
415
+    m_hoverWindow = hoverwin;
388 416
 }
389 417
 
390
-void slop::XEngine::updateHoverWindow( Window child ) {
418
+void slop::XEngine::updateHoverWindow( Window hoverwin ) {
391 419
     // Same thing as updateHoverWindow but it uses the specified child.
392 420
     // It's used when we first grab the cursor so it's slightly more effecient
393 421
     // than calling XQueryPointer twice.
394
-    if ( m_hoverXWindow == child ) {
422
+    if ( m_hoverWindow == hoverwin ) {
395 423
         return;
396 424
     }
397 425
     for ( unsigned int i=0; i<m_rects.size(); i++ ) {
398
-        if ( m_rects.at( i )->m_window == child ) {
426
+        if ( m_rects.at( i )->m_window == hoverwin ) {
399 427
             return;
400 428
         }
401 429
     }
402
-    m_hoverXWindow = child;
403
-    if ( child == None ) {
404
-        return;
405
-    }
406
-    unsigned int depth;
407
-    Window root;
408
-    XGetGeometry( m_display, child, &root,
409
-                  &(m_hoverWindow.m_x), &(m_hoverWindow.m_y),
410
-                  &(m_hoverWindow.m_width), &(m_hoverWindow.m_height),
411
-                  &(m_hoverWindow.m_border), &depth );
430
+    m_hoverWindow = hoverwin;
412 431
 }
413 432
 
414 433
 // Keeps our rectangle's sizes all positive, so Xlib doesn't throw an exception.

+ 6
- 5
x.hpp Bestand weergeven

@@ -29,11 +29,13 @@ enum CursorType {
29 29
 
30 30
 class WindowRectangle {
31 31
 public:
32
-    int m_x;
33
-    int m_y;
32
+    int          m_x;
33
+    int          m_y;
34 34
     unsigned int m_width;
35 35
     unsigned int m_height;
36 36
     unsigned int m_border;
37
+    bool         m_decorations;
38
+    void         setGeometry( Window win, bool decorations );
37 39
 };
38 40
 
39 41
 class Rectangle {
@@ -66,7 +68,7 @@ public:
66 68
     int                 init( std::string display );
67 69
     void                tick();
68 70
     int                 grabCursor( slop::CursorType type );
69
-    int                grabKeyboard();
71
+    int                 grabKeyboard();
70 72
     bool                anyKeyPressed();
71 73
     int                 releaseCursor();
72 74
     int                 releaseKeyboard();
@@ -83,8 +85,7 @@ public:
83 85
     int                 m_mousey;
84 86
     std::vector<bool>   m_mouse;
85 87
     bool                mouseDown( unsigned int button );
86
-    WindowRectangle     m_hoverWindow;
87
-    Window              m_hoverXWindow;
88
+    Window              m_hoverWindow;
88 89
     bool                m_keypressed;
89 90
 private:
90 91
     void                updateHoverWindow();