Bläddra i källkod

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 9 år sedan
förälder
incheckning
c0f4ef1327
4 ändrade filer med 55 tillägg och 39 borttagningar
  1. 2
    15
      main.cpp
  2. 3
    3
      options.cpp
  3. 44
    20
      x.cpp
  4. 6
    1
      x.hpp

+ 2
- 15
main.cpp Visa fil

@@ -67,7 +67,7 @@ int main( int argc, char** argv ) {
67 67
         double timei = double( time.tv_sec*1000000000L + time.tv_nsec )/1000000000.f;
68 68
         double starti = double( start.tv_sec*1000000000L + start.tv_nsec )/1000000000.f;
69 69
         if ( timei - starti > options->m_gracetime ) {
70
-            if ( xengine->m_keypressed ) {
70
+            if ( xengine->anyKeyPressed() && keyboard || xengine->mouseDown( 3 ) ) {
71 71
                 printf( "X=0\n" );
72 72
                 printf( "Y=0\n" );
73 73
                 printf( "W=0\n" );
@@ -76,17 +76,6 @@ int main( int argc, char** argv ) {
76 76
                 state = -1;
77 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 80
         // Our adorable little state manager will handle what state we're in.
92 81
         switch ( state ) {
@@ -235,12 +224,10 @@ int main( int argc, char** argv ) {
235 224
     xengine->releaseCursor();
236 225
     xengine->releaseKeyboard();
237 226
     // Try to process any last-second requests.
238
-    xengine->tick();
227
+    //xengine->tick();
239 228
     // Clean up global classes.
240 229
     delete xengine;
241 230
     delete options;
242
-    // Wait to make sure X11 cleans up our window before we end.
243
-    usleep( 100000 );
244 231
     // If we canceled the selection, return error.
245 232
     if ( state == -1 ) {
246 233
         return 1;

+ 3
- 3
options.cpp Visa fil

@@ -10,7 +10,7 @@ slop::Options::Options() {
10 10
     m_red = 0;
11 11
     m_green = 0;
12 12
     m_blue = 0;
13
-    m_gracetime = 0.1;
13
+    m_gracetime = 0.3;
14 14
     m_keyboard = true;
15 15
 }
16 16
 
@@ -20,7 +20,7 @@ void slop::Options::printHelp() {
20 20
     printf( "\n" );
21 21
     printf( "options\n" );
22 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 24
     printf( "    -b=INT, --bordersize=INT       set selection rectangle border size.\n" );
25 25
     printf( "    -p=INT, --padding=INT          set padding size for selection.\n" );
26 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,7 +28,7 @@ void slop::Options::printHelp() {
28 28
     printf( "    -c=COLOR, --color=COLOR        set selection rectangle color, COLOR is in format FLOAT,FLOAT,FLOAT\n" );
29 29
     printf( "    -g=FLOAT, --gracetime=FLOAT    set the amount of time before slop will check for keyboard cancellations in seconds.\n" );
30 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 34
 int slop::Options::parseOptions( int argc, char** argv ) {

+ 44
- 20
x.cpp Visa fil

@@ -2,8 +2,21 @@
2 2
 
3 3
 slop::XEngine* xengine = new slop::XEngine();
4 4
 
5
+static Bool isDestroyNotify( Display* dpy, XEvent* ev, XPointer win ) {
6
+    return ev->type == DestroyNotify && ev->xdestroywindow.window == *((Window*)win);
7
+}
8
+
9
+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 19
 slop::XEngine::XEngine() {
6
-    m_keypressed = false;
7 20
     m_display = NULL;
8 21
     m_visual = NULL;
9 22
     m_screen = NULL;
@@ -65,23 +78,33 @@ int slop::XEngine::init( std::string display ) {
65 78
     m_root      = DefaultRootWindow( m_display );
66 79
 
67 80
     m_good = true;
81
+    slop::OldXErrorHandler = XSetErrorHandler( slop::XEngineErrorHandler );
68 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 103
 int slop::XEngine::grabKeyboard() {
72 104
     if ( !m_good ) {
73 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 108
     return 0;
86 109
 }
87 110
 
@@ -164,15 +187,11 @@ void slop::XEngine::tick() {
164 187
                 }
165 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 191
             case KeyPress: {
170
-                m_keypressed = true;
171 192
                 break;
172 193
             }
173
-            // Since we also don't care if it's released, do nothing! yay
174 194
             case KeyRelease: {
175
-                //m_keypressed = false;
176 195
                 break;
177 196
             }
178 197
             default: break;
@@ -226,10 +245,13 @@ slop::Rectangle::~Rectangle() {
226 245
     }
227 246
     //XFreeColors( xengine->m_display, xengine->m_colormap, m_color.pixel, 1,
228 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 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 257
 slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int padding, float r, float g, float b ) {
@@ -264,7 +286,9 @@ slop::Rectangle::Rectangle( int x, int y, int width, int height, int border, int
264 286
     attributes.override_redirect = True;
265 287
     // We must use our color map, because that's where our color is allocated.
266 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 293
     // Create the window offset by our generated offsets (see constrain( float, float ))
270 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 Visa fil

@@ -9,6 +9,7 @@
9 9
 #include <X11/cursorfont.h>
10 10
 #include <X11/extensions/shape.h>
11 11
 
12
+#include <cstdlib>
12 13
 #include <cmath>
13 14
 #include <cstdio>
14 15
 #include <string>
@@ -65,7 +66,8 @@ public:
65 66
     int                 init( std::string display );
66 67
     void                tick();
67 68
     int                 grabCursor( slop::CursorType type );
68
-    int                 grabKeyboard();
69
+    int                grabKeyboard();
70
+    bool                anyKeyPressed();
69 71
     int                 releaseCursor();
70 72
     int                 releaseKeyboard();
71 73
     void                setCursor( slop::CursorType type );
@@ -93,6 +95,9 @@ private:
93 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 103
 extern slop::XEngine* xengine;