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