1 #include "xshaperectangle.hpp"
2 
XShapeRectangle(glm::vec2 p1,glm::vec2 p2,float border,float padding,glm::vec4 color,bool highlight)3 slop::XShapeRectangle::XShapeRectangle( glm::vec2 p1, glm::vec2 p2, float border, float padding, glm::vec4 color, bool highlight ) {
4     this->color = convertColor( color );
5     this->border = border;
6     this->padding = padding;
7     this->highlight = highlight;
8     this->alpha = color.a;
9     // Find each corner of the rectangle
10     ul = glm::vec2( glm::min( p1.x, p2.x ), glm::max( p1.y, p2.y ) ) ;
11     bl = glm::vec2( glm::min( p1.x, p2.x ), glm::min( p1.y, p2.y ) ) ;
12     ur = glm::vec2( glm::max( p1.x, p2.x ), glm::max( p1.y, p2.y ) ) ;
13     br = glm::vec2( glm::max( p1.x, p2.x ), glm::min( p1.y, p2.y ) ) ;
14     // Offset the inner corners by the padding.
15     ul = ul + glm::vec2(-padding,padding);
16     bl = bl + glm::vec2(-padding,-padding);
17     ur = ur + glm::vec2(padding,padding);
18     br = br + glm::vec2(padding,-padding);
19     // Create the outer corners by offsetting the inner by the bordersize
20     oul = ul + glm::vec2(-border,border);
21     obl = bl + glm::vec2(-border,-border);
22     our = ur + glm::vec2(border,border);
23     obr = br + glm::vec2(border,-border);
24 
25     XSetWindowAttributes attributes;
26     // Set up the window so it's our color
27     attributes.background_pixel = this->color.pixel;
28     // Disable window decorations.
29     attributes.override_redirect = True;
30     // Make sure we know when we've been successfully destroyed later!
31     attributes.event_mask = StructureNotifyMask;
32     unsigned long valueMask = CWBackPixel | CWOverrideRedirect | CWEventMask;
33     // Create the window
34     window = XCreateWindow( x11->display, x11->root, 0, 0, WidthOfScreen( x11->screen ), HeightOfScreen( x11->screen ),
35                               0, CopyFromParent, InputOutput,
36                               CopyFromParent, valueMask, &attributes );
37     if ( alpha < 1 ) {
38         // Change the window opacity
39         unsigned int cardinal_alpha = (unsigned int) (alpha * (unsigned int)-1) ;
40         XChangeProperty( x11->display, window, XInternAtom( x11->display, "_NET_WM_WINDOW_OPACITY", 0),
41                          XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&cardinal_alpha, 1 );
42     }
43     // Set the class hint, and title to "slop"
44     XClassHint classhints;
45     char name[] = "slop";
46     classhints.res_name = name;
47     classhints.res_class = name;
48     XSetClassHint( x11->display, window, &classhints );
49     // Now punch a hole into it so it looks like a selection rectangle, but only if we're not highlighting.
50     generateHoles();
51     createdWindow = false;
52 }
53 
createWindow()54 void slop::XShapeRectangle::createWindow() {
55     if ( createdWindow ) {
56         return;
57     }
58     XMapWindow( x11->display, window );
59     createdWindow = true;
60 }
61 
generateHoles()62 void slop::XShapeRectangle::generateHoles() {
63     if ( !highlight ) {
64         XRectangle rects[4];
65         // Left
66         rects[0].x = oul.x;
67         rects[0].y = obl.y;
68         rects[0].width = border;
69         rects[0].height = oul.y-obl.y;
70         // Top
71         rects[1].x = ul.x;
72         rects[1].y = obl.y;
73         rects[1].width = ur.x-ul.x;
74         rects[1].height = border;
75         // Right
76         rects[2].x = ur.x;
77         rects[2].y = obr.y;
78         rects[2].width = border;
79         rects[2].height = our.y - obr.y;
80         // Bottom
81         rects[3].x = bl.x;
82         rects[3].y = ul.y;
83         rects[3].width = br.x-bl.x;
84         rects[3].height = border;
85         XShapeCombineRectangles( x11->display, window, ShapeBounding, 0, 0, rects, 4, ShapeSet, 0);
86         return;
87     }
88     XRectangle rect;
89     rect.x = oul.x;
90     rect.y = obl.y;
91     rect.width = our.x-oul.x;
92     rect.height = oul.y-obl.y;
93     XShapeCombineRectangles( x11->display, window, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0);
94 }
95 
setPoints(glm::vec2 p1,glm::vec2 p2)96 void slop::XShapeRectangle::setPoints( glm::vec2 p1, glm::vec2 p2 ) {
97     // Find each corner of the rectangle
98     ul = glm::vec2( glm::min( p1.x, p2.x ), glm::max( p1.y, p2.y ) ) ;
99     bl = glm::vec2( glm::min( p1.x, p2.x ), glm::min( p1.y, p2.y ) ) ;
100     ur = glm::vec2( glm::max( p1.x, p2.x ), glm::max( p1.y, p2.y ) ) ;
101     br = glm::vec2( glm::max( p1.x, p2.x ), glm::min( p1.y, p2.y ) ) ;
102     // Offset the inner corners by the padding.
103     ul = ul + glm::vec2(-padding,padding);
104     bl = bl + glm::vec2(-padding,-padding);
105     ur = ur + glm::vec2(padding,padding);
106     br = br + glm::vec2(padding,-padding);
107     // Create the outer corners by offsetting the inner by the bordersize
108     oul = ul + glm::vec2(-border,border);
109     obl = bl + glm::vec2(-border,-border);
110     our = ur + glm::vec2(border,border);
111     obr = br + glm::vec2(border,-border);
112     generateHoles();
113 }
114 
~XShapeRectangle()115 slop::XShapeRectangle::~XShapeRectangle() {
116     XUnmapWindow( x11->display, window );
117     XDestroyWindow( x11->display, window );
118 }
119 
draw(glm::mat4 & matrix)120 void slop::XShapeRectangle::draw( glm::mat4& matrix ) {
121     // We don't want to be visible until we're asked to draw.
122     createWindow();
123 }
124 
getRect()125 glm::vec4 slop::XShapeRectangle::getRect() {
126     return glm::vec4( bl.x, bl.y, ur.x-ul.x, ul.y-bl.y );
127 }
128 
convertColor(glm::vec4 color)129 XColor slop::XShapeRectangle::convertColor( glm::vec4 color ) {
130     // Convert float colors to shorts.
131     short red   = short( floor( color.r * 65535.f ) );
132     short green = short( floor( color.g * 65535.f ) );
133     short blue  = short( floor( color.b * 65535.f ) );
134     XColor xc;
135     xc.red = red;
136     xc.green = green;
137     xc.blue = blue;
138     int err = XAllocColor( x11->display, DefaultColormap( x11->display, XScreenNumberOfScreen( x11->screen ) ), &xc );
139     if ( err == BadColor ) {
140         throw std::runtime_error(std::string("Couldn't allocate a color"));
141     }
142     return xc;
143 }
144