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