Browse Source

Added error handler that catches the non-fatal BadAccess error, added a DestroyNotify blocker that waits for the window to be destroyed before actually shutting down, and now we're using SFML's way of detecting keyboard presses.

Dalton Nell 10 years ago
parent
commit
c0f4ef1327
4 changed files with 55 additions and 39 deletions
  1. 2
    15
      main.cpp
  2. 3
    3
      options.cpp
  3. 44
    20
      x.cpp
  4. 6
    1
      x.hpp

+ 2
- 15
main.cpp View File

67
         double timei = double( time.tv_sec*1000000000L + time.tv_nsec )/1000000000.f;
67
         double timei = double( time.tv_sec*1000000000L + time.tv_nsec )/1000000000.f;
68
         double starti = double( start.tv_sec*1000000000L + start.tv_nsec )/1000000000.f;
68
         double starti = double( start.tv_sec*1000000000L + start.tv_nsec )/1000000000.f;
69
         if ( timei - starti > options->m_gracetime ) {
69
         if ( timei - starti > options->m_gracetime ) {
70
-            if ( xengine->m_keypressed ) {
70
+            if ( xengine->anyKeyPressed() && keyboard || xengine->mouseDown( 3 ) ) {
71
                 printf( "X=0\n" );
71
                 printf( "X=0\n" );
72
                 printf( "Y=0\n" );
72
                 printf( "Y=0\n" );
73
                 printf( "W=0\n" );
73
                 printf( "W=0\n" );
76
                 state = -1;
76
                 state = -1;
77
                 running = false;
77
                 running = false;
78
             }
78
             }
79
-        } else {
80
-            xengine->m_keypressed = false;
81
-        }
82
-        if ( xengine->mouseDown( 3 ) ) {
83
-            printf( "X=0\n" );
84
-            printf( "Y=0\n" );
85
-            printf( "W=0\n" );
86
-            printf( "H=0\n" );
87
-            fprintf( stderr, "User right-clicked. Canceled selection.\n" );
88
-            state = -1;
89
-            running = false;
90
         }
79
         }
91
         // Our adorable little state manager will handle what state we're in.
80
         // Our adorable little state manager will handle what state we're in.
92
         switch ( state ) {
81
         switch ( state ) {
235
     xengine->releaseCursor();
224
     xengine->releaseCursor();
236
     xengine->releaseKeyboard();
225
     xengine->releaseKeyboard();
237
     // Try to process any last-second requests.
226
     // Try to process any last-second requests.
238
-    xengine->tick();
227
+    //xengine->tick();
239
     // Clean up global classes.
228
     // Clean up global classes.
240
     delete xengine;
229
     delete xengine;
241
     delete options;
230
     delete options;
242
-    // Wait to make sure X11 cleans up our window before we end.
243
-    usleep( 100000 );
244
     // If we canceled the selection, return error.
231
     // If we canceled the selection, return error.
245
     if ( state == -1 ) {
232
     if ( state == -1 ) {
246
         return 1;
233
         return 1;

+ 3
- 3
options.cpp View File

10
     m_red = 0;
10
     m_red = 0;
11
     m_green = 0;
11
     m_green = 0;
12
     m_blue = 0;
12
     m_blue = 0;
13
-    m_gracetime = 0.1;
13
+    m_gracetime = 0.3;
14
     m_keyboard = true;
14
     m_keyboard = true;
15
 }
15
 }
16
 
16
 
20
     printf( "\n" );
20
     printf( "\n" );
21
     printf( "options\n" );
21
     printf( "options\n" );
22
     printf( "    -h, --help                     show this message.\n" );
22
     printf( "    -h, --help                     show this message.\n" );
23
-    printf( "    -nkb, --nokeyboard             don't try to grab the keyboard. This may fix problems with certain window managers.\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" );
24
     printf( "    -b=INT, --bordersize=INT       set selection rectangle border size.\n" );
25
     printf( "    -p=INT, --padding=INT          set padding size for selection.\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" );
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" );
28
     printf( "    -c=COLOR, --color=COLOR        set selection rectangle color, COLOR is in format FLOAT,FLOAT,FLOAT\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" );
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" );
30
     printf( "examples\n" );
31
-    printf( "    slop -b=10 -x=:0 -p=-30 -t=4 -c=0.5,0.5,0.5 -g=.2\n" );
31
+    printf( "    slop -b=10 -x=:0 -p=-30 -t=4 -c=0.5,0.5,0.5 -g=.3\n" );
32
 }
32
 }
33
 
33
 
34
 int slop::Options::parseOptions( int argc, char** argv ) {
34
 int slop::Options::parseOptions( int argc, char** argv ) {

+ 44
- 20
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 ) {
10
+    // Ignore XGrabKeyboard BadAccess errors
11
+    // 31 = XGrabKeyboard's request code
12
+    if ( event->request_code == 31 && event->error_code == BadAccess ) {
13
+        return 0;
14
+    }
15
+    // Otherwise call the default error handler
16
+    return slop::OldXErrorHandler( dpy, event );
17
+}
18
+
5
 slop::XEngine::XEngine() {
19
 slop::XEngine::XEngine() {
6
-    m_keypressed = false;
7
     m_display = NULL;
20
     m_display = NULL;
8
     m_visual = NULL;
21
     m_visual = NULL;
9
     m_screen = NULL;
22
     m_screen = NULL;
65
     m_root      = DefaultRootWindow( m_display );
78
     m_root      = DefaultRootWindow( m_display );
66
 
79
 
67
     m_good = true;
80
     m_good = true;
81
+    slop::OldXErrorHandler = XSetErrorHandler( slop::XEngineErrorHandler );
68
     return 0;
82
     return 0;
69
 }
83
 }
70
 
84
 
85
+bool slop::XEngine::anyKeyPressed() {
86
+    if ( !m_good ) {
87
+        return false;
88
+    }
89
+    // Thanks to SFML for some reliable key state grabbing.
90
+    // Get the whole keyboard state
91
+    char keys[ 32 ];
92
+    XQueryKeymap( m_display, keys );
93
+    // Each bit indicates a different key, 1 for pressed, 0 otherwise.
94
+    // Every bit should be 0 if nothing is pressed.
95
+    for ( unsigned int i = 0; i < 32; i++ ) {
96
+        if ( keys[ i ] != 0 ) {
97
+            return true;
98
+        }
99
+    }
100
+    return false;
101
+}
102
+
71
 int slop::XEngine::grabKeyboard() {
103
 int slop::XEngine::grabKeyboard() {
72
     if ( !m_good ) {
104
     if ( !m_good ) {
73
         return 1;
105
         return 1;
74
     }
106
     }
75
-    XGrabKey( m_display, AnyKey, AnyModifier, m_root, False, GrabModeAsync, GrabModeAsync );
76
-    // For whatever we fail to grab the keyboard 100% of the time if slop is launched in the background.
77
-    /*int err = XGrabKeyboard( m_display, m_root, False,
78
-                             GrabModeAsync, GrabModeAsync, CurrentTime );
79
-    if ( err != GrabSuccess ) {
80
-        fprintf( stderr, "Error: Failed to grab X keyboard.\n" );
81
-        fprintf( stderr, "This can be caused by launching slop incorrectly.\n" );
82
-        fprintf( stderr, "gnome-session launches it fine from keyboard binds.\n" );
83
-        return 1;
84
-    }*/
107
+    XGrabKeyboard( m_display, m_root, False, GrabModeAsync, GrabModeAsync, CurrentTime );
85
     return 0;
108
     return 0;
86
 }
109
 }
87
 
110
 
164
                 }
187
                 }
165
                 break;
188
                 break;
166
             }
189
             }
167
-            // For this particular utility, we only care if a key is pressed.
168
-            // I'm too lazy to implement an actual keyhandler for that.
190
+            // Due to X11 really hating applications grabbing the keyboard, we use XQueryKeymap to check for downed keys elsewhere.
169
             case KeyPress: {
191
             case KeyPress: {
170
-                m_keypressed = true;
171
                 break;
192
                 break;
172
             }
193
             }
173
-            // Since we also don't care if it's released, do nothing! yay
174
             case KeyRelease: {
194
             case KeyRelease: {
175
-                //m_keypressed = false;
176
                 break;
195
                 break;
177
             }
196
             }
178
             default: break;
197
             default: break;
226
     }
245
     }
227
     //XFreeColors( xengine->m_display, xengine->m_colormap, m_color.pixel, 1,
246
     //XFreeColors( xengine->m_display, xengine->m_colormap, m_color.pixel, 1,
228
     // Attempt to move window offscreen before trying to remove it.
247
     // Attempt to move window offscreen before trying to remove it.
229
-    XResizeWindow( xengine->m_display, m_window, 1, 1 );
230
-    XMoveWindow( xengine->m_display, m_window, 0, 0 );
231
-    XUnmapWindow( xengine->m_display, m_window );
248
+    //XResizeWindow( xengine->m_display, m_window, 1, 1 );
249
+    //XMoveWindow( xengine->m_display, m_window, 0, 0 );
250
+    //XUnmapWindow( xengine->m_display, m_window );
232
     XDestroyWindow( xengine->m_display, m_window );
251
     XDestroyWindow( xengine->m_display, m_window );
252
+    XEvent event;
253
+    // Block until the window is actually completely removed.
254
+    XIfEvent( xengine->m_display, &event, &isDestroyNotify, (XPointer)&m_window );
233
 }
255
 }
234
 
256
 
235
 slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int padding, float r, float g, float b ) {
257
 slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int padding, float r, float g, float b ) {
264
     attributes.override_redirect = True;
286
     attributes.override_redirect = True;
265
     // We must use our color map, because that's where our color is allocated.
287
     // We must use our color map, because that's where our color is allocated.
266
     attributes.colormap = xengine->m_colormap;
288
     attributes.colormap = xengine->m_colormap;
267
-    unsigned long valueMask = CWBackPixmap | CWBackPixel | CWOverrideRedirect | CWColormap;
289
+    // Make sure we know when we've been successfully destroyed later!
290
+    attributes.event_mask = StructureNotifyMask;
291
+    unsigned long valueMask = CWBackPixmap | CWBackPixel | CWOverrideRedirect | CWColormap | CWEventMask;
268
 
292
 
269
     // Create the window offset by our generated offsets (see constrain( float, float ))
293
     // Create the window offset by our generated offsets (see constrain( float, float ))
270
     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,
294
     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,

+ 6
- 1
x.hpp View File

9
 #include <X11/cursorfont.h>
9
 #include <X11/cursorfont.h>
10
 #include <X11/extensions/shape.h>
10
 #include <X11/extensions/shape.h>
11
 
11
 
12
+#include <cstdlib>
12
 #include <cmath>
13
 #include <cmath>
13
 #include <cstdio>
14
 #include <cstdio>
14
 #include <string>
15
 #include <string>
65
     int                 init( std::string display );
66
     int                 init( std::string display );
66
     void                tick();
67
     void                tick();
67
     int                 grabCursor( slop::CursorType type );
68
     int                 grabCursor( slop::CursorType type );
68
-    int                 grabKeyboard();
69
+    int                grabKeyboard();
70
+    bool                anyKeyPressed();
69
     int                 releaseCursor();
71
     int                 releaseCursor();
70
     int                 releaseKeyboard();
72
     int                 releaseKeyboard();
71
     void                setCursor( slop::CursorType type );
73
     void                setCursor( slop::CursorType type );
93
     Cursor              getCursor( slop::CursorType type );
95
     Cursor              getCursor( slop::CursorType type );
94
 };
96
 };
95
 
97
 
98
+int XEngineErrorHandler( Display* dpy, XErrorEvent* event );
99
+XErrorHandler OldXErrorHandler;
100
+
96
 }
101
 }
97
 
102
 
98
 extern slop::XEngine* xengine;
103
 extern slop::XEngine* xengine;