naelstrof 11 vuotta sitten
commit
7f72447efe
5 muutettua tiedostoa jossa 434 lisäystä ja 0 poistoa
  1. 7
    0
      README.md
  2. 67
    0
      main.cpp
  3. 14
    0
      makefile
  4. 266
    0
      x.cpp
  5. 80
    0
      x.hpp

+ 7
- 0
README.md Näytä tiedosto

@@ -0,0 +1,7 @@
1
+slrn
2
+----
3
+
4
+slrn is an application that literally just allows a user to select a region of his screen. It grabs the cursor, draws a fancy box, and prints the selection's dimensions and position to stdout.
5
+
6
+It does a better job than scrot's selection since it doesn't draw directly to the root window, it creates its own to draw the selection rectangle.
7
+However due to the X11's Shape extension and window resizing not being synchronized it doesn't render a perfect box during movement. I'm hoping to fix this later by never resizing the window.

+ 67
- 0
main.cpp Näytä tiedosto

@@ -0,0 +1,67 @@
1
+#include <unistd.h>
2
+#include "x.hpp"
3
+
4
+int main( int argc, char** argv ) {
5
+    int state = 0;
6
+    bool running = true;
7
+    is::Rectangle* selection;
8
+
9
+    xengine->init( ":0" );
10
+    xengine->grabCursor( is::Cross );
11
+    while ( running ) {
12
+        xengine->tick();
13
+        switch ( state ) {
14
+            case 0: {
15
+                if ( xengine->mouseDown( 1 ) ) {
16
+                    state++;
17
+                }
18
+                break;
19
+            }
20
+            case 1: {
21
+                // Check to make sure we actually have a cursor position before creating the selection rectangle.
22
+                if ( xengine->m_mousex == -1 ) {
23
+                    break;
24
+                }
25
+                selection = new is::Rectangle( xengine->m_mousex, xengine->m_mousey, 1, 1, 10, 0 );
26
+                selection->setPos( xengine->m_mousex, xengine->m_mousey );
27
+                xengine->addRect( selection );
28
+                state++;
29
+                break;
30
+            }
31
+            case 2: {
32
+                if ( !xengine->mouseDown( 1 ) ) {
33
+                    state++;
34
+                    break;
35
+                }
36
+                selection->setDim( xengine->m_mousex - selection->m_x, xengine->m_mousey - selection->m_y );
37
+                // x and y offsets can indicate if the selection is inside-out, which lets us know which kind of cursor we need.
38
+                int x = selection->m_xoffset;
39
+                int y = selection->m_yoffset;
40
+                if ( x == 0 && y == 0) {
41
+                    xengine->setCursor( is::LowerRightCorner );
42
+                } else if ( x && y == 0 ) {
43
+                    xengine->setCursor( is::LowerLeftCorner );
44
+                } else if ( x == 0 && y ) {
45
+                    xengine->setCursor( is::UpperRightCorner );
46
+                } else {
47
+                    xengine->setCursor( is::UpperLeftCorner );
48
+                }
49
+
50
+                break;
51
+            }
52
+            case 3: {
53
+                printf( "X: %i\n", selection->m_x+selection->m_xoffset );
54
+                printf( "Y: %i\n", selection->m_y+selection->m_yoffset );
55
+                printf( "W: %i\n", selection->m_width + 1 );
56
+                printf( "H: %i\n", selection->m_height + 1 );
57
+                xengine->removeRect( selection );
58
+                running = false;
59
+                break;
60
+            }
61
+        }
62
+        // No need to max out CPU--
63
+        usleep( 1000 );
64
+    }
65
+    delete xengine;
66
+    return 0;
67
+}

+ 14
- 0
makefile Näytä tiedosto

@@ -0,0 +1,14 @@
1
+CC=g++
2
+CFLAGS=-O2 -g
3
+LDFLAGS=-lX11 -lXext
4
+SOURCES=main.cpp x.cpp
5
+OBJECTS=$(SOURCES:.cpp=.o)
6
+EXECUTABLE=slrn
7
+
8
+all: $(SOURCES) $(EXECUTABLE)
9
+
10
+$(EXECUTABLE): $(OBJECTS)
11
+	$(CC) $(LDFLAGS) $(OBJECTS) -o $@
12
+
13
+clean:
14
+	rm -rf $(OBJECTS) $(EXECUTABLE)

+ 266
- 0
x.cpp Näytä tiedosto

@@ -0,0 +1,266 @@
1
+#include "x.hpp"
2
+
3
+is::XEngine* xengine = new is::XEngine();
4
+
5
+is::XEngine::XEngine() {
6
+    m_display = NULL;
7
+    m_visual = NULL;
8
+    m_screen = NULL;
9
+    m_good = false;
10
+    m_mousex = -1;
11
+    m_mousey = -1;
12
+}
13
+
14
+is::XEngine::~XEngine() {
15
+    if ( !m_good ) {
16
+        return;
17
+    }
18
+    for ( unsigned int i=0; i<m_cursors.size(); i++ ) {
19
+        if ( m_cursors.at( i ) ) {
20
+            XFreeCursor( m_display, m_cursors[i] );
21
+        }
22
+    }
23
+    for ( unsigned int i=0; i<m_rects.size(); i++ ) {
24
+        delete m_rects.at( i );
25
+    }
26
+    XCloseDisplay( m_display );
27
+}
28
+
29
+void is::XEngine::addRect( Rectangle* rect ) {
30
+    m_rects.push_back( rect );
31
+}
32
+
33
+void is::XEngine::removeRect( Rectangle* rect ) {
34
+    for ( unsigned int i=0; i<m_rects.size(); i++ ) {
35
+        if ( m_rects.at( i ) == rect ) {
36
+            m_rects.erase( m_rects.begin() + i );
37
+            i--;
38
+            delete rect;
39
+            return;
40
+        }
41
+    }
42
+}
43
+
44
+bool is::XEngine::mouseDown( unsigned int button ) {
45
+    if ( button >= m_mouse.size() ) {
46
+        return false;
47
+    }
48
+    return m_mouse.at( button );
49
+}
50
+
51
+int is::XEngine::init( std::string display ) {
52
+    // Initialize display
53
+    m_display = XOpenDisplay( display.c_str() );
54
+    if ( !m_display ) {
55
+        printf( "Failed to open X display %s\n", display.c_str() );
56
+        return 1;
57
+    }
58
+    m_screen    = ScreenOfDisplay( m_display, DefaultScreen( m_display ) );
59
+    m_visual    = DefaultVisual  ( m_display, XScreenNumberOfScreen( m_screen ) );
60
+    m_colormap  = DefaultColormap( m_display, XScreenNumberOfScreen( m_screen ) );
61
+    m_root      = RootWindow     ( m_display, XScreenNumberOfScreen( m_screen ) );
62
+
63
+    m_good = true;
64
+    return 0;
65
+}
66
+
67
+int is::XEngine::grabCursor( is::CursorType type ) {
68
+    if ( !m_good ) {
69
+        return 1;
70
+    }
71
+    int xfontcursor = getCursor( type );
72
+    int err = XGrabPointer( m_display, m_root, False,
73
+                            PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
74
+                            GrabModeAsync, GrabModeAsync, m_root, xfontcursor, CurrentTime );
75
+    if ( err != GrabSuccess ) {
76
+        printf( "Failed to grab X cursor\n" );
77
+        return 1;
78
+    }
79
+    return 0;
80
+}
81
+
82
+int is::XEngine::releaseCursor() {
83
+    if ( !m_good ) {
84
+        return 1;
85
+    }
86
+    XUngrabPointer( m_display, CurrentTime );
87
+    return 0;
88
+}
89
+
90
+void is::XEngine::tick() {
91
+    if ( !m_good ) {
92
+        return;
93
+    }
94
+    XFlush( m_display );
95
+    XEvent event;
96
+    while ( XPending( m_display ) ) {
97
+        XNextEvent( m_display, &event );
98
+        switch ( event.type ) {
99
+            case MotionNotify: {
100
+                m_mousex = event.xmotion.x;
101
+                m_mousey = event.xmotion.y;
102
+                break;
103
+            }
104
+            case ButtonPress: {
105
+                if ( m_mouse.size() > event.xbutton.button ) {
106
+                    m_mouse.at( event.xbutton.button ) = true;
107
+                } else {
108
+                    m_mouse.resize( event.xbutton.button+2, false );
109
+                    m_mouse.at( event.xbutton.button ) = true;
110
+                }
111
+                break;
112
+            }
113
+            case ButtonRelease: {
114
+                if ( m_mouse.size() > event.xbutton.button ) {
115
+                    m_mouse.at( event.xbutton.button ) = false;
116
+                } else {
117
+                    m_mouse.resize( event.xbutton.button+2, false );
118
+                    m_mouse.at( event.xbutton.button ) = false;
119
+                }
120
+                break;
121
+            }
122
+        }
123
+    }
124
+}
125
+
126
+Cursor is::XEngine::getCursor( is::CursorType type ) {
127
+    int xfontcursor;
128
+    switch ( type ) {
129
+        default:
130
+        case Left:                  xfontcursor = XC_left_ptr; break;
131
+        case Crosshair:             xfontcursor = XC_crosshair; break;
132
+        case Cross:                 xfontcursor = XC_cross; break;
133
+        case UpperLeftCorner:       xfontcursor = XC_ul_angle; break;
134
+        case UpperRightCorner:      xfontcursor = XC_ur_angle; break;
135
+        case LowerLeftCorner:       xfontcursor = XC_ll_angle; break;
136
+        case LowerRightCorner:      xfontcursor = XC_lr_angle; break;
137
+    }
138
+    Cursor newcursor = 0;
139
+    if ( m_cursors.size() > xfontcursor ) {
140
+        newcursor = m_cursors.at( xfontcursor );
141
+    }
142
+    if ( !newcursor ) {
143
+        newcursor = XCreateFontCursor( m_display, xfontcursor );
144
+        m_cursors.resize( xfontcursor+2, 0 );
145
+        m_cursors.at( xfontcursor ) = newcursor;
146
+    }
147
+    return newcursor;
148
+}
149
+
150
+void is::XEngine::setCursor( is::CursorType type ) {
151
+    if ( !m_good ) {
152
+        return;
153
+    }
154
+    Cursor xfontcursor = getCursor( type );
155
+    XChangeActivePointerGrab( m_display,
156
+                              ButtonMotionMask | ButtonPressMask | ButtonReleaseMask,
157
+                              xfontcursor, CurrentTime );
158
+}
159
+
160
+is::Rectangle::~Rectangle() {
161
+    //XFreeGC( xengine->m_display, m_gc );
162
+    XUnmapWindow( xengine->m_display, m_window );
163
+    XDestroyWindow( xengine->m_display, m_window );
164
+}
165
+
166
+is::Rectangle::Rectangle( int x, int y, int width, int height, int border, int padding ) {
167
+    m_xoffset = 0;
168
+    m_yoffset = 0;
169
+    m_x = x;
170
+    m_y = y;
171
+    m_width = width;
172
+    m_height = height;
173
+    m_border = border;
174
+    m_padding = padding;
175
+
176
+    if ( m_width < 0 ) {
177
+        m_xoffset += m_width;
178
+        m_width = -m_width;
179
+    }
180
+    if ( m_height < 0 ) {
181
+        m_yoffset += m_height;
182
+        m_height = -m_height;
183
+    }
184
+    if ( m_width == 0 ) {
185
+        m_width = 1;
186
+    }
187
+    if ( m_height == 0 ) {
188
+        m_height = 1;
189
+    }
190
+
191
+    XAllocNamedColor( xengine->m_display, xengine->m_colormap, "black", &m_forground, &m_forgroundExact );
192
+    XAllocNamedColor( xengine->m_display, xengine->m_colormap, "white", &m_background, &m_backgroundExact );
193
+    XSetWindowAttributes attributes;
194
+    attributes.background_pixmap = None;
195
+    attributes.background_pixel = m_forground.pixel;
196
+    attributes.save_under = True;
197
+    attributes.override_redirect = True;
198
+    attributes.colormap = xengine->m_colormap;
199
+    unsigned long valueMask = CWBackPixmap | CWBackPixel |
200
+                              CWSaveUnder | CWOverrideRedirect |
201
+                              CWColormap;
202
+
203
+    m_window = XCreateWindow( xengine->m_display, xengine->m_root, m_x+m_xoffset, m_y+m_yoffset, m_width+m_border*2, m_height+m_border*2,
204
+                              0, CopyFromParent, InputOutput,
205
+                              CopyFromParent, valueMask, &attributes );
206
+    XRectangle rect;
207
+    rect.x = rect.y = m_border;
208
+    rect.width = m_width;
209
+    rect.height = m_height;
210
+
211
+    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
212
+    XMapWindow( xengine->m_display, m_window );
213
+
214
+    draw();
215
+}
216
+
217
+void is::Rectangle::setPos( int x, int y ) {
218
+    if ( m_x == x && m_y == y ) {
219
+        return;
220
+    }
221
+    m_x = x;
222
+    m_y = y;
223
+    XMoveWindow( xengine->m_display, m_window, m_x-m_border+m_xoffset, m_y-m_border+m_yoffset );
224
+}
225
+
226
+void is::Rectangle::setDim( int w, int h ) {
227
+    if ( m_width == w && m_height == h ) {
228
+        return;
229
+    }
230
+
231
+    m_xoffset = 0;
232
+    m_yoffset = 0;
233
+    m_width = w;
234
+    m_height = h;
235
+    if ( w < 0 ) {
236
+        m_xoffset += w;
237
+        m_width = -w;
238
+    }
239
+    if ( h < 0 ) {
240
+        m_yoffset += h;
241
+        m_height = -h;
242
+    }
243
+    if ( m_width == 0 ) {
244
+        m_width = 1;
245
+    }
246
+    if ( m_height == 0 ) {
247
+        m_height = 1;
248
+    }
249
+    XResizeWindow( xengine->m_display, m_window, m_width+m_border*2, m_height+m_border*2 );
250
+    XMoveWindow( xengine->m_display, m_window, m_x-m_border+m_xoffset, m_y-m_border+m_yoffset );
251
+    // Now punch another hole in it.
252
+    XRectangle rect;
253
+    rect.x = rect.y = 0;
254
+    rect.width = m_width+m_border*2;
255
+    rect.height = m_height+m_border*2;
256
+    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
257
+    rect;
258
+    rect.x = rect.y = m_border;
259
+    rect.width = m_width;
260
+    rect.height = m_height;
261
+    XShapeCombineRectangles( xengine->m_display, m_window, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
262
+    draw();
263
+}
264
+
265
+void is::Rectangle::draw() {
266
+}

+ 80
- 0
x.hpp Näytä tiedosto

@@ -0,0 +1,80 @@
1
+// x.hpp: handles starting and managing X
2
+
3
+#ifndef IS_X_H_
4
+#define IS_X_H_
5
+
6
+#include <unistd.h>
7
+
8
+#include <X11/Xlib.h>
9
+#include <X11/cursorfont.h>
10
+#include <X11/extensions/shape.h>
11
+
12
+#include <cstdio>
13
+#include <string>
14
+#include <vector>
15
+
16
+namespace is {
17
+
18
+enum CursorType {
19
+    Left,
20
+    Crosshair,
21
+    Cross,
22
+    UpperLeftCorner,
23
+    UpperRightCorner,
24
+    LowerRightCorner,
25
+    LowerLeftCorner
26
+};
27
+
28
+class Rectangle {
29
+public:
30
+            Rectangle( int x, int y, int width, int height, int border, int padding );
31
+            ~Rectangle();
32
+    void    setPos( int x, int y );
33
+    void    setDim( int w, int h );
34
+    void    draw();
35
+    Window  m_window;
36
+    int     m_x;
37
+    int     m_y;
38
+    int     m_xoffset;
39
+    int     m_yoffset;
40
+    int     m_width;
41
+    int     m_height;
42
+    int     m_border;
43
+    int     m_padding;
44
+    XColor  m_forground, m_forgroundExact;
45
+    XColor  m_background, m_backgroundExact;
46
+};
47
+
48
+class XEngine {
49
+public:
50
+                        XEngine();
51
+                        ~XEngine();
52
+    int                 init( std::string display );
53
+    void                tick();
54
+    int                 grabCursor( is::CursorType type );
55
+    int                 releaseCursor();
56
+    void                setCursor( is::CursorType type );
57
+    void                drawRect( int x, int y, unsigned int w, unsigned int h );
58
+    void                addRect( Rectangle* rect );
59
+    void                removeRect( Rectangle* rect );
60
+    Display*            m_display;
61
+    Visual*             m_visual;
62
+    Screen*             m_screen;
63
+    Colormap            m_colormap;
64
+    Window              m_root;
65
+    int                 m_mousex;
66
+    int                 m_mousey;
67
+    std::vector<bool>   m_mouse;
68
+    bool                mouseDown( unsigned int button );
69
+private:
70
+    bool                m_good;
71
+    std::vector<Cursor> m_cursors;
72
+    std::vector<Rectangle*> m_rects;
73
+    Cursor              getCursor( is::CursorType type );
74
+};
75
+
76
+}
77
+
78
+extern is::XEngine* xengine;
79
+
80
+#endif // IS_X_H_