1 /********************************************************************************
2 * *
3 * D o c k H a n d l e r W i d g e t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 2005,2006 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (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 GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
21 *********************************************************************************
22 * $Id: FXDockHandler.cpp,v 1.8 2006/01/22 17:58:23 fox Exp $ *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxkeys.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXRegistry.h"
36 #include "FXApp.h"
37 #include "FXDockHandler.h"
38
39
40 /*
41 Notes:
42 - On MS-Windows, this works just fine, without fanfare.
43 - On X11, some quaintness in the X-Server causes havoc if reparent()
44 is called on a window while it was grabbed.
45 - Not to be deterred, we implement here the following workaround:
46
47 1) We create a temporary dummy window, just 1x1 pixels in size, in the
48 upper left corner of the screen [yes, that was not a dead pixel
49 after all!].
50
51 2) We add this to the hash table, so now events from the "true" window
52 as well those from the dummy window are dispatched to the toolbar grip.
53
54 3) We temporarily replace the xid of the true window with the dummy one,
55 then invoke grab() to grab the mouse, then restore the original xid.
56
57 4) Now you can wave your mouse around and dock or undock toolbars.
58
59 5) When we're done, we replace the xid again with the dummy window,
60 call ungrab(), then restore the original xid again.
61
62 6) Then, delete the dummy window.
63
64 - The only downside of this method is that the win_x and win_y member
65 data in FXEvent is unreliable; fortunately, the standard toolbar docking
66 algorithms do not use these members.
67 - Of course, we'd rather not have to do all this; so don't hesitate
68 to inform us if you have a better way!
69
70 */
71
72
73
74
75 using namespace FX;
76
77 /*******************************************************************************/
78
79 namespace FX {
80
81 // Map
82 FXDEFMAP(FXDockHandler) FXDockHandlerMap[]={
83 FXMAPFUNC(SEL_MOTION,0,FXDockHandler::onMotion),
84 FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXDockHandler::onLeftBtnPress),
85 FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXDockHandler::onLeftBtnRelease),
86 FXMAPFUNC(SEL_KEYPRESS,0,FXDockHandler::onKeyPress),
87 FXMAPFUNC(SEL_KEYRELEASE,0,FXDockHandler::onKeyRelease),
88 FXMAPFUNC(SEL_QUERY_TIP,0,FXDockHandler::onQueryTip),
89 FXMAPFUNC(SEL_QUERY_HELP,0,FXDockHandler::onQueryHelp),
90 FXMAPFUNC(SEL_COMMAND,FXDockHandler::ID_SETHELPSTRING,FXDockHandler::onCmdSetHelp),
91 FXMAPFUNC(SEL_COMMAND,FXDockHandler::ID_GETHELPSTRING,FXDockHandler::onCmdGetHelp),
92 FXMAPFUNC(SEL_COMMAND,FXDockHandler::ID_SETTIPSTRING,FXDockHandler::onCmdSetTip),
93 FXMAPFUNC(SEL_COMMAND,FXDockHandler::ID_GETTIPSTRING,FXDockHandler::onCmdGetTip),
94 };
95
96
97 // Object implementation
FXIMPLEMENT_ABSTRACT(FXDockHandler,FXFrame,FXDockHandlerMap,ARRAYNUMBER (FXDockHandlerMap))98 FXIMPLEMENT_ABSTRACT(FXDockHandler,FXFrame,FXDockHandlerMap,ARRAYNUMBER(FXDockHandlerMap))
99
100
101 // Deserialization
102 FXDockHandler::FXDockHandler(){
103 flags|=FLAG_ENABLED|FLAG_SHOWN;
104 xxx=0;
105 }
106
107
108 // Construct and init
FXDockHandler(FXComposite * p,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb)109 FXDockHandler::FXDockHandler(FXComposite* p,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb):
110 FXFrame(p,opts,x,y,w,h,pl,pr,pt,pb){
111 flags|=FLAG_SHOWN|FLAG_ENABLED;
112 dragCursor=getApp()->getDefaultCursor(DEF_MOVE_CURSOR);
113 target=tgt;
114 message=sel;
115 xxx=0;
116 }
117
118
119 // Can have focus
canFocus() const120 bool FXDockHandler::canFocus() const { return true; }
121
122
123 // Moved
onMotion(FXObject *,FXSelector,void * ptr)124 long FXDockHandler::onMotion(FXObject*,FXSelector,void* ptr){
125 if(flags&FLAG_DODRAG){
126 handle(this,FXSEL(SEL_DRAGGED,0),ptr);
127 return 1;
128 }
129 if((flags&FLAG_TRYDRAG) && ((FXEvent*)ptr)->moved){
130 if(handle(this,FXSEL(SEL_BEGINDRAG,0),ptr)) flags|=FLAG_DODRAG;
131 flags&=~FLAG_TRYDRAG;
132 return 1;
133 }
134 return 0;
135 }
136
137
138 // Pressed LEFT button
onLeftBtnPress(FXObject *,FXSelector,void * ptr)139 long FXDockHandler::onLeftBtnPress(FXObject*,FXSelector,void* ptr){
140 flags&=~FLAG_TIP;
141 handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
142 if(isEnabled()){
143 flags=(flags&~(FLAG_UPDATE|FLAG_DODRAG))|FLAG_TRYDRAG;
144 #ifndef WIN32
145 Display *display=(Display*)getApp()->getDisplay();
146 const unsigned long mask=CWBackPixmap|CWWinGravity|CWBitGravity|CWBorderPixel|CWOverrideRedirect|CWSaveUnder|CWEventMask|CWDontPropagate|CWColormap|CWCursor;
147 XSetWindowAttributes wattr;
148 FXID tempxid=xid;
149 wattr.background_pixmap=None;
150 wattr.background_pixel=0;
151 wattr.border_pixmap=None;
152 wattr.border_pixel=0;
153 wattr.bit_gravity=ForgetGravity;
154 wattr.win_gravity=NorthWestGravity;
155 wattr.backing_store=NotUseful;
156 wattr.backing_planes=0;
157 wattr.backing_pixel=0;
158 wattr.save_under=FALSE;
159 wattr.event_mask=ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask | FocusChangeMask|StructureNotifyMask | StructureNotifyMask|ExposureMask|PropertyChangeMask|EnterWindowMask|LeaveWindowMask;
160 wattr.do_not_propagate_mask=KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|ButtonMotionMask;
161 wattr.override_redirect=TRUE;
162 wattr.colormap=DefaultColormap(display,DefaultScreen(display));
163 wattr.cursor=None;
164 xxx=XCreateWindow(display,RootWindow(display,DefaultScreen(display)),0,0,1,1,0,DefaultDepth(display,DefaultScreen(display)),InputOutput,DefaultVisual(display,DefaultScreen(display)),mask,&wattr);
165 getApp()->hash.insert((void*)xxx,this);
166 XMapWindow(display,xxx);
167 xid=xxx;
168 grab();
169 xid=tempxid;
170 #else
171 grab();
172 #endif
173 update();
174 }
175 return 1;
176 }
177
178
179 // Released LEFT button
onLeftBtnRelease(FXObject *,FXSelector,void * ptr)180 long FXDockHandler::onLeftBtnRelease(FXObject*,FXSelector,void* ptr){
181 if(isEnabled()){
182 if(flags&FLAG_DODRAG){handle(this,FXSEL(SEL_ENDDRAG,0),ptr);}
183 flags=(flags&~(FLAG_TRYDRAG|FLAG_DODRAG))|FLAG_UPDATE;
184 #ifndef WIN32
185 Display *display=(Display*)getApp()->getDisplay();
186 FXID tempxid=xid;
187 xid=xxx;
188 ungrab();
189 xid=tempxid;
190 getApp()->hash.remove((void*)xxx);
191 XDestroyWindow(display,xxx);
192 xxx=0;
193 #else
194 ungrab();
195 #endif
196 update();
197 }
198 return 1;
199 }
200
201
202 // Key Press
onKeyPress(FXObject *,FXSelector,void * ptr)203 long FXDockHandler::onKeyPress(FXObject*,FXSelector,void* ptr){
204 FXEvent* event=static_cast<FXEvent*>(ptr);
205 if(isEnabled()){
206 if(target && target->tryHandle(this,FXSEL(SEL_KEYPRESS,message),ptr)) return 1;
207 if(event->code==KEY_Control_L || event->code==KEY_Control_R){
208 if(flags&FLAG_DODRAG){handle(this,FXSEL(SEL_DRAGGED,0),ptr);}
209 return 1;
210 }
211 }
212 return 0;
213 }
214
215
216 // Key Release
onKeyRelease(FXObject *,FXSelector,void * ptr)217 long FXDockHandler::onKeyRelease(FXObject*,FXSelector,void* ptr){
218 FXEvent* event=static_cast<FXEvent*>(ptr);
219 if(isEnabled()){
220 if(target && target->tryHandle(this,FXSEL(SEL_KEYRELEASE,message),ptr)) return 1;
221 if(event->code==KEY_Control_L || event->code==KEY_Control_R){
222 if(flags&FLAG_DODRAG){handle(this,FXSEL(SEL_DRAGGED,0),ptr);}
223 return 1;
224 }
225 }
226 return 0;
227 }
228
229
230 // We were asked about tip text
onQueryTip(FXObject * sender,FXSelector sel,void * ptr)231 long FXDockHandler::onQueryTip(FXObject* sender,FXSelector sel,void* ptr){
232 if(FXFrame::onQueryTip(sender,sel,ptr)) return 1;
233 if((flags&FLAG_TIP) && !tip.empty()){
234 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&tip);
235 return 1;
236 }
237 return 0;
238 }
239
240
241 // We were asked about status text
onQueryHelp(FXObject * sender,FXSelector sel,void * ptr)242 long FXDockHandler::onQueryHelp(FXObject* sender,FXSelector sel,void* ptr){
243 if(FXFrame::onQueryHelp(sender,sel,ptr)) return 1;
244 if((flags&FLAG_HELP) && !help.empty()){
245 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&help);
246 return 1;
247 }
248 return 0;
249 }
250
251
252 // Set tip using a message
onCmdSetTip(FXObject *,FXSelector,void * ptr)253 long FXDockHandler::onCmdSetTip(FXObject*,FXSelector,void* ptr){
254 setTipText(*((FXString*)ptr));
255 return 1;
256 }
257
258
259 // Get tip using a message
onCmdGetTip(FXObject *,FXSelector,void * ptr)260 long FXDockHandler::onCmdGetTip(FXObject*,FXSelector,void* ptr){
261 *((FXString*)ptr)=getTipText();
262 return 1;
263 }
264
265
266 // Set help using a message
onCmdSetHelp(FXObject *,FXSelector,void * ptr)267 long FXDockHandler::onCmdSetHelp(FXObject*,FXSelector,void* ptr){
268 setHelpText(*((FXString*)ptr));
269 return 1;
270 }
271
272
273 // Get help using a message
onCmdGetHelp(FXObject *,FXSelector,void * ptr)274 long FXDockHandler::onCmdGetHelp(FXObject*,FXSelector,void* ptr){
275 *((FXString*)ptr)=getHelpText();
276 return 1;
277 }
278
279
280 // Save data
save(FXStream & store) const281 void FXDockHandler::save(FXStream& store) const {
282 FXFrame::save(store);
283 store << tip;
284 store << help;
285 }
286
287
288 // Load data
load(FXStream & store)289 void FXDockHandler::load(FXStream& store){
290 FXFrame::load(store);
291 store >> tip;
292 store >> help;
293 }
294
295
296 }
297