Selaa lähdekoodia

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 vuotta sitten
vanhempi
commit
c0f4ef1327
4 muutettua tiedostoa jossa 55 lisäystä ja 39 poistoa
  1. 2
    15
      main.cpp
  2. 3
    3
      options.cpp
  3. 44
    20
      x.cpp
  4. 6
    1
      x.hpp

+ 2
- 15
main.cpp Näytä tiedosto

@@ -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 Näytä tiedosto

@@ -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 Näytä tiedosto

@@ -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 Näytä tiedosto

@@ -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;