1 /********************************************************************************
2 * *
3 * D r a g C o r n e r W i d g e t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1997,2020 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as published by *
10 * the Free Software Foundation; either version 3 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/> *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "FXArray.h"
26 #include "FXHash.h"
27 #include "FXMutex.h"
28 #include "FXStream.h"
29 #include "FXString.h"
30 #include "FXSize.h"
31 #include "FXPoint.h"
32 #include "FXRectangle.h"
33 #include "FXStringDictionary.h"
34 #include "FXSettings.h"
35 #include "FXRegistry.h"
36 #include "FXEvent.h"
37 #include "FXWindow.h"
38 #include "FXDCWindow.h"
39 #include "FXApp.h"
40 #include "FXDragCorner.h"
41
42
43 #define CORNERSIZE 17
44
45 #define DISPLAY(app) ((Display*)((app)->getDisplay()))
46
47
48 /*
49 Notes:
50 - Need to grab server while dragging?
51 - Need to use extended window manager hints so that minimum/maximum size
52 and so on are properly observed.
53 */
54
55 using namespace FX;
56
57
58 /*******************************************************************************/
59
60 namespace FX {
61
62
63 // Map
64 FXDEFMAP(FXDragCorner) FXDragCornerMap[]={
65 FXMAPFUNC(SEL_PAINT,0,FXDragCorner::onPaint),
66 FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXDragCorner::onLeftBtnPress),
67 FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXDragCorner::onLeftBtnRelease),
68 FXMAPFUNC(SEL_MOTION,0,FXDragCorner::onMotion),
69 };
70
71
72 // Object implementation
FXIMPLEMENT(FXDragCorner,FXWindow,FXDragCornerMap,ARRAYNUMBER (FXDragCornerMap))73 FXIMPLEMENT(FXDragCorner,FXWindow,FXDragCornerMap,ARRAYNUMBER(FXDragCornerMap))
74
75
76 // Deserialization
77 FXDragCorner::FXDragCorner(){
78 flags|=FLAG_ENABLED|FLAG_SHOWN;
79 hiliteColor=0;
80 shadowColor=0;
81 oldw=0;
82 oldh=0;
83 xoff=0;
84 yoff=0;
85 ewmh=false;
86 }
87
88
89 // Construct and init
FXDragCorner(FXComposite * p)90 FXDragCorner::FXDragCorner(FXComposite* p):FXWindow(p,LAYOUT_RIGHT|LAYOUT_BOTTOM){
91 flags|=FLAG_ENABLED|FLAG_SHOWN;
92 defaultCursor=getApp()->getDefaultCursor(DEF_DRAGBR_CURSOR);
93 dragCursor=getApp()->getDefaultCursor(DEF_DRAGBR_CURSOR);
94 backColor=getApp()->getBaseColor();
95 hiliteColor=getApp()->getHiliteColor();
96 shadowColor=getApp()->getShadowColor();
97 oldw=0;
98 oldh=0;
99 xoff=0;
100 yoff=0;
101 ewmh=false;
102 }
103
104
105 // Get default width
getDefaultWidth()106 FXint FXDragCorner::getDefaultWidth(){
107 return CORNERSIZE;
108 }
109
110
111 // Get default height
getDefaultHeight()112 FXint FXDragCorner::getDefaultHeight(){
113 return CORNERSIZE;
114 }
115
116
117 // Create drag corner
create()118 void FXDragCorner::create(){
119 FXWindow::create();
120 #ifndef WIN32
121 unsigned long n,i; Atom type; unsigned char *prop; int format;
122 if(Success==XGetWindowProperty(DISPLAY(getApp()),XDefaultRootWindow(DISPLAY(getApp())),getApp()->wmNetSupported,0,2048,False,XA_ATOM,&type,&format,&n,&i,&prop)){
123 for(i=0; i<n; i++){
124 if(((Atom*)prop)[i]==getApp()->wmNetMoveResize){ ewmh=true; break; }
125 }
126 XFree(prop);
127 }
128 #endif
129 }
130
131
132 // Slightly different from Frame border
onPaint(FXObject *,FXSelector,void * ptr)133 long FXDragCorner::onPaint(FXObject*,FXSelector,void* ptr){
134 FXEvent *ev=(FXEvent*)ptr;
135 FXDCWindow dc(this,ev);
136 dc.setForeground(backColor);
137 dc.fillRectangle(ev->rect.x,ev->rect.y,ev->rect.w,ev->rect.h);
138 dc.setForeground(shadowColor);
139 dc.drawLine(width-2,height-1,width,height-3);
140 dc.drawLine(width-8,height-1,width,height-9);
141 dc.drawLine(width-14,height-1,width,height-15);
142 dc.setForeground(hiliteColor);
143 dc.drawLine(width-5,height-1,width,height-6);
144 dc.drawLine(width-11,height-1,width,height-12);
145 dc.drawLine(width-17,height-1,width,height-18);
146 return 1;
147 }
148
149
150 // Pressed LEFT button
onLeftBtnPress(FXObject *,FXSelector,void * ptr)151 long FXDragCorner::onLeftBtnPress(FXObject*,FXSelector,void* ptr){
152 FXEvent *event=(FXEvent*)ptr;
153 #ifndef WIN32
154 if(ewmh){
155 XClientMessageEvent ev;
156 ev.type=ClientMessage;
157 ev.display=DISPLAY(getApp());
158 ev.window=getShell()->id();
159 ev.message_type=getApp()->wmNetMoveResize;
160 ev.format=32;
161 ev.data.l[0]=event->root_x;
162 ev.data.l[1]=event->root_y;
163 ev.data.l[2]=4; // Bottom right
164 ev.data.l[3]=LEFTBUTTON;
165 ev.data.l[4]=0;
166 XSendEvent(DISPLAY(getApp()),XDefaultRootWindow(DISPLAY(getApp())),False,(SubstructureRedirectMask|SubstructureNotifyMask),(XEvent*)&ev);
167 ungrab();
168 return 1;
169 }
170 #endif
171 FXDCWindow dc(getRoot());
172 FXint xx,yy,wx,wy;
173 grab();
174 xoff=width-event->win_x;
175 yoff=height-event->win_y;
176 translateCoordinatesTo(wx,wy,getShell(),event->win_x,event->win_y);
177 oldw=wx+xoff;
178 oldh=wy+yoff;
179 dc.clipChildren(false);
180 dc.setFunction(BLT_SRC_XOR_DST);
181 dc.setForeground(FXRGB(255,255,255));
182 getShell()->translateCoordinatesTo(xx,yy,getRoot(),0,0);
183 dc.drawRectangle(xx,yy,oldw,oldh);
184 flags|=FLAG_PRESSED;
185 return 1;
186 }
187
188
189
190 // Released LEFT button
onLeftBtnRelease(FXObject *,FXSelector,void * ptr)191 long FXDragCorner::onLeftBtnRelease(FXObject*,FXSelector,void* ptr){
192 FXEvent *event=(FXEvent*)ptr;
193 if(flags&FLAG_PRESSED){
194 FXDCWindow dc(getRoot());
195 FXint xx,yy,wx,wy;
196 ungrab();
197 getShell()->translateCoordinatesTo(xx,yy,getRoot(),0,0);
198 translateCoordinatesTo(wx,wy,getShell(),event->win_x,event->win_y);
199 dc.clipChildren(false);
200 dc.setFunction(BLT_SRC_XOR_DST);
201 dc.setForeground(FXRGB(255,255,255));
202 dc.drawRectangle(xx,yy,oldw,oldh);
203 getShell()->resize(wx+xoff,wy+yoff);
204 flags&=~FLAG_PRESSED;
205 }
206 return 1;
207 }
208
209
210 // Moved
onMotion(FXObject *,FXSelector,void * ptr)211 long FXDragCorner::onMotion(FXObject*,FXSelector,void* ptr){
212 FXEvent *event=(FXEvent*)ptr;
213 if(flags&FLAG_PRESSED){
214 FXDCWindow dc(getRoot());
215 FXint xx,yy,wx,wy;
216 getShell()->translateCoordinatesTo(xx,yy,getRoot(),0,0);
217 translateCoordinatesTo(wx,wy,getShell(),event->win_x,event->win_y);
218 dc.clipChildren(false);
219 dc.setFunction(BLT_SRC_XOR_DST);
220 dc.setForeground(FXRGB(255,255,255));
221 dc.drawRectangle(xx,yy,oldw,oldh);
222 oldw=wx+xoff;
223 oldh=wy+yoff;
224 dc.drawRectangle(xx,yy,oldw,oldh);
225 return 1;
226 }
227 return 0;
228 }
229
230
231 // Set highlight color
setHiliteColor(FXColor clr)232 void FXDragCorner::setHiliteColor(FXColor clr){
233 if(hiliteColor!=clr){
234 hiliteColor=clr;
235 update();
236 }
237 }
238
239
240 // Set shadow color
setShadowColor(FXColor clr)241 void FXDragCorner::setShadowColor(FXColor clr){
242 if(shadowColor!=clr){
243 shadowColor=clr;
244 update();
245 }
246 }
247
248
249
250 // Save data
save(FXStream & store) const251 void FXDragCorner::save(FXStream& store) const {
252 FXWindow::save(store);
253 store << hiliteColor;
254 store << shadowColor;
255 }
256
257
258 // Load data
load(FXStream & store)259 void FXDragCorner::load(FXStream& store){
260 FXWindow::load(store);
261 store >> hiliteColor;
262 store >> shadowColor;
263 }
264
265 }
266
267