1 /********************************************************************************
2 *                                                                               *
3 *                            W i n d o w   O b j e c 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 "FXElement.h"
28 #include "FXMutex.h"
29 #include "FXAutoThreadStorageKey.h"
30 #include "FXRunnable.h"
31 #include "FXThread.h"
32 #include "FXStream.h"
33 #include "FXString.h"
34 #include "FXSize.h"
35 #include "FXPoint.h"
36 #include "FXRectangle.h"
37 #include "FXRegion.h"
38 #include "FXStringDictionary.h"
39 #include "FXSettings.h"
40 #include "FXRegistry.h"
41 #include "FXAccelTable.h"
42 #include "FXVisual.h"
43 #include "FXEvent.h"
44 #include "FXWindow.h"
45 #include "FXDCWindow.h"
46 #include "FXApp.h"
47 #include "FXImage.h"
48 #include "FXBitmap.h"
49 #include "FXIcon.h"
50 #include "FXCursor.h"
51 #include "FXWindow.h"
52 #include "FXFrame.h"
53 #include "FXComposite.h"
54 #include "FXRootWindow.h"
55 #include "FXShell.h"
56 #include "FXTopWindow.h"
57 #include "FXException.h"
58 #include "FXStatusLine.h"
59 #include "FXTranslator.h"
60 #include "FXComposeContext.h"
61 #include "FXTextField.h"
62 #include "FX88591Codec.h"
63 #include "FXUTF16Codec.h"
64 #include "fxpriv.h"
65 
66 
67 /*
68  Notes:
69   - Major Contributions for Windows NT by Lyle Johnson.
70   - When window is disabled, it should lose focus
71   - When no subclass handles SEL_SELECTION_REQUEST, send back None property here
72   - Update should only happen if widget is not in some sort of transaction.
73   - Not every widget needs help and tip data; move this down to buttons etc.
74   - Default constructors [for serialization] should initialize dynamic member
75     variables same as regular constructor.  Dynamic variables are those that
76     are not saved during serialization.
77   - If FLAG_DIRTY gets reset at the END of layout(), it will be safe to have
78     show() and hide() to call recalc(), in case they get called from the
79     application code.
80   - Use INCR mechanism if it gets large.
81   - Perhaps should post CLIPBOARD type list in advance also, just like windows insists.
82     We will need to keep this list some place [perhaps same place as XDND] and clean it
83     after we're done [This would imply the CLIPBOARD type list would be the same as the
84     XDND type list, which is probably OK].
85   - Add URL jump text also.
86   - Can we call parent->recalc() in the constructor?
87   - Need other focus models:
88       o click to focus (like we have now)
89       o focus only by tabs and arrows (buttons should not move focus when clicking)
90       o point to focus (useful for canvas type widgets)
91     Mouse wheel should probably not cause focus changes...
92   - Close v.s. delete messages are not consistent.
93 */
94 
95 #ifndef WIN32
96 
97 // Basic events
98 #define BASIC_EVENT_MASK   (StructureNotifyMask|ExposureMask|PropertyChangeMask|EnterWindowMask|LeaveWindowMask|KeyPressMask|KeyReleaseMask|KeymapStateMask)
99 //#define BASIC_EVENT_MASK   (StructureNotifyMask|ExposureMask|PropertyChangeMask|EnterWindowMask|LeaveWindowMask|KeyPressMask|KeyReleaseMask|KeymapStateMask|VisibilityChangeMask)
100 
101 // Additional events for shell widget events
102 #define SHELL_EVENT_MASK   (FocusChangeMask|StructureNotifyMask)
103 
104 // Additional events for enabled widgets
105 #define ENABLED_EVENT_MASK (ButtonPressMask|ButtonReleaseMask|PointerMotionMask)
106 
107 // These events are grabbed for mouse grabs
108 #define GRAB_EVENT_MASK    (ButtonPressMask|ButtonReleaseMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask)
109 
110 // Do not propagate mask
111 #define NOT_PROPAGATE_MASK (KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|ButtonMotionMask)
112 
113 #endif
114 
115 
116 // Side layout modes
117 #define LAYOUT_SIDE_MASK (LAYOUT_SIDE_LEFT|LAYOUT_SIDE_RIGHT|LAYOUT_SIDE_TOP|LAYOUT_SIDE_BOTTOM)
118 
119 
120 // Layout modes
121 #define LAYOUT_MASK (LAYOUT_SIDE_MASK|LAYOUT_RIGHT|LAYOUT_CENTER_X|LAYOUT_BOTTOM|LAYOUT_CENTER_Y|LAYOUT_FIX_X|LAYOUT_FIX_Y|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_DOCK_SAME|LAYOUT_DOCK_NEXT)
122 
123 
124 using namespace FX;
125 
126 /*******************************************************************************/
127 
128 namespace FX {
129 
130 // Map
131 FXDEFMAP(FXWindow) FXWindowMap[]={
132   FXMAPFUNC(SEL_UPDATE,0,FXWindow::onUpdate),
133   FXMAPFUNC(SEL_PAINT,0,FXWindow::onPaint),
134   FXMAPFUNC(SEL_MOTION,0,FXWindow::onMotion),
135   FXMAPFUNC(SEL_CONFIGURE,0,FXWindow::onConfigure),
136   FXMAPFUNC(SEL_MOUSEWHEEL,0,FXWindow::onMouseWheel),
137   FXMAPFUNC(SEL_MAP,0,FXWindow::onMap),
138   FXMAPFUNC(SEL_UNMAP,0,FXWindow::onUnmap),
139   FXMAPFUNC(SEL_DRAGGED,0,FXWindow::onDragged),
140   FXMAPFUNC(SEL_ENTER,0,FXWindow::onEnter),
141   FXMAPFUNC(SEL_LEAVE,0,FXWindow::onLeave),
142   FXMAPFUNC(SEL_DESTROY,0,FXWindow::onDestroy),
143   FXMAPFUNC(SEL_FOCUSIN,0,FXWindow::onFocusIn),
144   FXMAPFUNC(SEL_FOCUSOUT,0,FXWindow::onFocusOut),
145   FXMAPFUNC(SEL_SELECTION_LOST,0,FXWindow::onSelectionLost),
146   FXMAPFUNC(SEL_SELECTION_GAINED,0,FXWindow::onSelectionGained),
147   FXMAPFUNC(SEL_SELECTION_REQUEST,0,FXWindow::onSelectionRequest),
148   FXMAPFUNC(SEL_CLIPBOARD_LOST,0,FXWindow::onClipboardLost),
149   FXMAPFUNC(SEL_CLIPBOARD_GAINED,0,FXWindow::onClipboardGained),
150   FXMAPFUNC(SEL_CLIPBOARD_REQUEST,0,FXWindow::onClipboardRequest),
151   FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXWindow::onLeftBtnPress),
152   FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXWindow::onLeftBtnRelease),
153   FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,FXWindow::onMiddleBtnPress),
154   FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE,0,FXWindow::onMiddleBtnRelease),
155   FXMAPFUNC(SEL_RIGHTBUTTONPRESS,0,FXWindow::onRightBtnPress),
156   FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,0,FXWindow::onRightBtnRelease),
157   FXMAPFUNC(SEL_SPACEBALLMOTION,0,FXWindow::onSpaceBallMotion),
158   FXMAPFUNC(SEL_SPACEBALLBUTTONPRESS,0,FXWindow::onSpaceBallButtonPress),
159   FXMAPFUNC(SEL_SPACEBALLBUTTONRELEASE,0,FXWindow::onSpaceBallButtonRelease),
160   FXMAPFUNC(SEL_UNGRABBED,0,FXWindow::onUngrabbed),
161   FXMAPFUNC(SEL_KEYPRESS,0,FXWindow::onKeyPress),
162   FXMAPFUNC(SEL_KEYRELEASE,0,FXWindow::onKeyRelease),
163   FXMAPFUNC(SEL_DND_ENTER,0,FXWindow::onDNDEnter),
164   FXMAPFUNC(SEL_DND_LEAVE,0,FXWindow::onDNDLeave),
165   FXMAPFUNC(SEL_DND_DROP,0,FXWindow::onDNDDrop),
166   FXMAPFUNC(SEL_DND_MOTION,0,FXWindow::onDNDMotion),
167   FXMAPFUNC(SEL_DND_REQUEST,0,FXWindow::onDNDRequest),
168   FXMAPFUNC(SEL_FOCUS_SELF,0,FXWindow::onFocusSelf),
169   FXMAPFUNC(SEL_BEGINDRAG,0,FXWindow::onBeginDrag),
170   FXMAPFUNC(SEL_ENDDRAG,0,FXWindow::onEndDrag),
171   FXMAPFUNC(SEL_QUERY_TIP,0,FXWindow::onQueryTip),
172   FXMAPFUNC(SEL_QUERY_HELP,0,FXWindow::onQueryHelp),
173   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_SHOW,FXWindow::onCmdShow),
174   FXMAPFUNC(SEL_CHORE,FXWindow::ID_SHOW,FXWindow::onCmdShow),
175   FXMAPFUNC(SEL_TIMEOUT,FXWindow::ID_SHOW,FXWindow::onCmdShow),
176   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_HIDE,FXWindow::onCmdHide),
177   FXMAPFUNC(SEL_CHORE,FXWindow::ID_HIDE,FXWindow::onCmdHide),
178   FXMAPFUNC(SEL_TIMEOUT,FXWindow::ID_HIDE,FXWindow::onCmdHide),
179   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_TOGGLESHOWN,FXWindow::onUpdToggleShown),
180   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_TOGGLESHOWN,FXWindow::onCmdToggleShown),
181   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_RAISE,FXWindow::onCmdRaise),
182   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_LOWER,FXWindow::onCmdLower),
183   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_ENABLE,FXWindow::onCmdEnable),
184   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_DISABLE,FXWindow::onCmdDisable),
185   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_TOGGLEENABLED,FXWindow::onUpdToggleEnabled),
186   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_TOGGLEENABLED,FXWindow::onCmdToggleEnabled),
187   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_UPDATE,FXWindow::onCmdUpdate),
188   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_DELETE,FXWindow::onUpdYes),
189   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_DELETE,FXWindow::onCmdDelete),
190   FXMAPFUNC(SEL_CHORE,FXWindow::ID_DELETE,FXWindow::onCmdDelete),
191   FXMAPFUNC(SEL_TIMEOUT,FXWindow::ID_DELETE,FXWindow::onCmdDelete),
192   };
193 
194 
195 // Object implementation
196 FXIMPLEMENT(FXWindow,FXDrawable,FXWindowMap,ARRAYNUMBER(FXWindowMap))
197 
198 
199 /*******************************************************************************/
200 
201 
202 // Drag type names
203 const FXchar FXWindow::octetTypeName[]="application/octet-stream";
204 const FXchar FXWindow::deleteTypeName[]="DELETE";
205 const FXchar FXWindow::textTypeName[]="text/plain";
206 const FXchar FXWindow::colorTypeName[]="application/x-color";
207 const FXchar FXWindow::urilistTypeName[]="text/uri-list";
208 const FXchar FXWindow::utf8TypeName[]="UTF8_STRING";
209 const FXchar FXWindow::utf16TypeName[]="text/utf16";
210 const FXchar FXWindow::actionTypeName[]="application/x-kde-cutselection";
211 
212 
213 // Drag type atoms; first widget to need it should register the type
214 FXDragType FXWindow::octetType=0;
215 FXDragType FXWindow::deleteType=0;
216 FXDragType FXWindow::textType=0;
217 FXDragType FXWindow::colorType=0;
218 FXDragType FXWindow::urilistType=0;
219 FXDragType FXWindow::utf8Type=0;
220 FXDragType FXWindow::actionType=0;
221 
222 
223 // The string type is predefined and hardwired
224 #ifdef WIN32
225 const FXDragType FXWindow::stringType=CF_TEXT;
226 #else
227 const FXDragType FXWindow::stringType=XA_STRING;
228 #endif
229 
230 
231 // The image type is predefined and hardwired
232 #ifdef WIN32
233 const FXDragType FXWindow::imageType=CF_DIB;
234 #else
235 const FXDragType FXWindow::imageType=XA_PIXMAP;
236 #endif
237 
238 
239 // The UTF-16 string type is predefined and hardwired
240 #ifdef WIN32
241 FXDragType FXWindow::utf16Type=CF_UNICODETEXT;
242 #else
243 FXDragType FXWindow::utf16Type=0;
244 #endif
245 
246 
247 /*******************************************************************************/
248 
249 
250 // For deserialization; note that the deserialized window only
251 // becomes part of the widget tree after its loaded with load().
FXWindow()252 FXWindow::FXWindow(){
253   FXTRACE((100,"FXWindow::FXWindow %p\n",this));
254   parent=NULL;
255   owner=NULL;
256   first=NULL;
257   last=NULL;
258   next=NULL;
259   prev=NULL;
260   focus=NULL;
261   composeContext=NULL;
262   defaultCursor=NULL;
263   dragCursor=NULL;
264   accelTable=NULL;
265   target=NULL;
266   message=0;
267   xpos=0;
268   ypos=0;
269   backColor=0;
270   flags=FLAG_DIRTY|FLAG_UPDATE|FLAG_RECALC|FLAG_CURSOR;
271   options=0;
272   wk=0;
273   }
274 
275 
276 // Only used for the root window
FXWindow(FXApp * a,FXVisual * vis)277 FXWindow::FXWindow(FXApp* a,FXVisual *vis):FXDrawable(a,1,1){
278   FXTRACE((100,"FXWindow::FXWindow %p\n",this));
279   getApp()->windowCount++;
280   visual=vis;
281   parent=NULL;
282   owner=NULL;
283   first=last=NULL;
284   next=prev=NULL;
285   focus=NULL;
286   composeContext=NULL;
287   defaultCursor=getApp()->getDefaultCursor(DEF_ARROW_CURSOR);
288   dragCursor=getApp()->getDefaultCursor(DEF_ARROW_CURSOR);
289   accelTable=NULL;
290   target=NULL;
291   message=0;
292   xpos=0;
293   ypos=0;
294   backColor=0;
295   flags=FLAG_DIRTY|FLAG_SHOWN|FLAG_UPDATE|FLAG_RECALC|FLAG_CURSOR;
296   options=LAYOUT_FIX_X|LAYOUT_FIX_Y|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT;
297   wk=1;
298   }
299 
300 
301 // This constructor is used for shell windows
FXWindow(FXApp * a,FXWindow * own,FXuint opts,FXint x,FXint y,FXint w,FXint h)302 FXWindow::FXWindow(FXApp* a,FXWindow* own,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXDrawable(a,w,h){
303   FXTRACE((100,"FXWindow::FXWindow %p\n",this));
304   getApp()->windowCount++;
305   parent=a->root;
306   owner=own;
307   visual=getApp()->getDefaultVisual();
308   first=last=NULL;
309   prev=parent->last;
310   next=NULL;
311   parent->last=this;
312   if(prev){
313     wk=prev->wk+1;
314     prev->next=this;
315     }
316   else{
317     wk=1;
318     parent->first=this;
319     }
320   focus=NULL;
321   composeContext=NULL;
322   defaultCursor=getApp()->getDefaultCursor(DEF_ARROW_CURSOR);
323   dragCursor=getApp()->getDefaultCursor(DEF_ARROW_CURSOR);
324   accelTable=NULL;
325   target=NULL;
326   message=0;
327   xpos=x;
328   ypos=y;
329   backColor=getApp()->getBaseColor();
330   flags=FLAG_DIRTY|FLAG_UPDATE|FLAG_RECALC|FLAG_SHELL|FLAG_CURSOR;
331   options=opts;
332   }
333 
334 
335 // This constructor is used for all child windows
FXWindow(FXComposite * p,FXuint opts,FXint x,FXint y,FXint w,FXint h)336 FXWindow::FXWindow(FXComposite* p,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXDrawable(p->getApp(),w,h){
337   FXTRACE((100,"FXWindow::FXWindow %p\n",this));
338   getApp()->windowCount++;
339   parent=p;
340   owner=parent;
341   visual=parent->getVisual();
342   first=last=NULL;
343   prev=parent->last;
344   next=NULL;
345   parent->last=this;
346   if(prev){
347     wk=prev->wk+1;
348     prev->next=this;
349     }
350   else{
351     wk=1;
352     parent->first=this;
353     }
354   focus=NULL;
355   composeContext=NULL;
356   defaultCursor=getApp()->getDefaultCursor(DEF_ARROW_CURSOR);
357   dragCursor=getApp()->getDefaultCursor(DEF_ARROW_CURSOR);
358   accelTable=NULL;
359   target=NULL;
360   message=0;
361   xpos=x;
362   ypos=y;
363   backColor=getApp()->getBaseColor();
364   flags=FLAG_DIRTY|FLAG_UPDATE|FLAG_RECALC|FLAG_CURSOR;
365   options=opts;
366   }
367 
368 
369 /*******************************************************************************/
370 
371 // The idea is to recurse down, but not sideways or upward.  Recursing upward
372 // through the parent or owner, or sideways through the left and right sibling,
373 // carries the risk of serializing the entire widget tree instead of just the
374 // one widget and its children.
375 // Each widget only saves its own data and resources, and loops over its child
376 // widgets saving each one in turn. A final NULL child pointer is saved to
377 // indicate the end of the sequence.
378 // When loading back, we deserialize a child pointer and hang it in the widget
379 // tree under this widget.  We continue to deserialize child pointers until
380 // we find the NULL child pointer.
381 
382 
383 // Save window to stream
save(FXStream & store) const384 void FXWindow::save(FXStream& store) const {
385   FXWindow *child=getFirst();
386   FXDrawable::save(store);
387   while(child){
388     store << child;
389     child=child->getNext();
390     }
391   store << child;
392   store << accelTable;
393   store << defaultCursor;
394   store << dragCursor;
395   store << target;
396   store << message;
397   store << xpos;
398   store << ypos;
399   store << backColor;
400   store << tag;
401   store << options;
402   store << flags;
403   store << wk;
404   }
405 
406 
407 // Load window from stream
load(FXStream & store)408 void FXWindow::load(FXStream& store){
409   FXWindow *child=NULL;
410   FXDrawable::load(store);
411   getApp()->windowCount++;
412   store >> child;
413   while(child){
414     child->parent=this;
415     child->owner=this;
416     child->prev=last;
417     child->next=NULL;
418     if(last){
419       last->next=child;
420       }
421     else{
422       first=child;
423       }
424     last=child;
425     store >> child;
426     }
427   store >> accelTable;
428   store >> defaultCursor;
429   store >> dragCursor;
430   store >> target;
431   store >> message;
432   store >> xpos;
433   store >> ypos;
434   store >> backColor;
435   store >> tag;
436   store >> options;
437   store >> flags;       // FIXME
438   store >> wk;
439   }
440 
441 
442 // Get window class; most windows have normal class
getWindowClass() const443 FXWindow::WindowClass FXWindow::getWindowClass() const {
444   return ClassNormal;
445   }
446 
447 
448 /*******************************************************************************/
449 
450 
451 // Return a pointer to the shell window
getShell() const452 FXWindow* FXWindow::getShell() const {
453   FXWindow *win=(FXWindow*)this;
454   FXWindow *p;
455   while((p=win->parent)!=NULL && p->parent) win=p;
456   return win;
457   }
458 
459 
460 // Return a pointer to the root window
getRoot() const461 FXWindow* FXWindow::getRoot() const {
462   FXWindow *win=(FXWindow*)this;
463   while(win->parent) win=win->parent;
464   return win;
465   }
466 
467 
468 // Test if logically inside
contains(FXint parentx,FXint parenty) const469 FXbool FXWindow::contains(FXint parentx,FXint parenty) const {
470   return xpos<=parentx && parentx<xpos+width && ypos<=parenty && parenty<ypos+height;
471   }
472 
473 
474 // Return child window with given window key
getChildWithKey(FXuint k) const475 FXWindow* FXWindow::getChildWithKey(FXuint k) const {
476   for(FXWindow *child=first; child; child=child->next){
477     if(child->getKey()==k) return child;
478     }
479   return NULL;
480   }
481 
482 /*
483   /// Get window from Dewey decimal key
484   FXWindow *getChildFromKey(const FXString& key) const;
485 
486   /// Get Dewey decimal key from window
487   FXString getKeyFromChild(FXWindow* window) const;
488 
489 // Get window from Dewey decimal key
490 FXWindow *FXWindow::getChildFromKey(const FXString& key) const {
491   FXWindow *window=(FXWindow*)this;
492   const FXchar *s=key.text();
493   FXuint num;
494   do{
495     if(!('0'<=*s && *s<='9')) return NULL;
496     for(num=0; '0'<=*s && *s<='9'; s++){ num=10*num+*s-'0'; }
497     for(window=window->first; window && window->wk!=num; window=window->next);
498     }
499   while(*s++ == '.' && window);
500   return window;
501   }
502 
503 
504 // Get Dewey decimal key from window
505 FXString FXWindow::getKeyFromChild(FXWindow* window) const {
506   FXchar buf[1024];
507   FXchar *p=buf+1023;
508   FXuint num;
509   *p='\0';
510   while(window && window!=this && buf+10<=p){
511     num=window->getKey();
512     do{ *--p=num%10+'0'; num/=10; }while(num);
513     window=window->getParent();
514     *--p='.';
515     }
516   if(*p=='.') p++;
517   return p;
518   }
519 */
520 
521 
522 // Return true if this window contains child in its subtree
containsChild(const FXWindow * child) const523 FXbool FXWindow::containsChild(const FXWindow* child) const {
524   while(child){
525     if(child==this) return true;
526     child=child->parent;
527     }
528   return false;
529   }
530 
531 
532 // Return true if specified window is owned by this window
isOwnerOf(const FXWindow * window) const533 FXbool FXWindow::isOwnerOf(const FXWindow* window) const {
534   while(window){
535     if(window==this) return true;
536     window=window->owner;
537     }
538   return false;
539   }
540 
541 
542 // Return true if specified window is ancestor of this window
isChildOf(const FXWindow * window) const543 FXbool FXWindow::isChildOf(const FXWindow* window) const {
544   const FXWindow* child=this;
545   while(child){
546     child=child->parent;
547     if(child==window) return true;
548     }
549   return false;
550   }
551 
552 
553 // Get child at x,y
getChildAt(FXint x,FXint y) const554 FXWindow* FXWindow::getChildAt(FXint x,FXint y) const {
555   FXWindow *child;
556   if(0<=x && 0<=y && x<width && y<height){
557     for(child=last; child; child=child->prev){
558       if(child->shown() && child->xpos<=x && child->ypos<=y && x<child->xpos+child->width && y<child->ypos+child->height) return child;
559       }
560     }
561   return NULL;
562   }
563 
564 
565 // Count number of children
numChildren() const566 FXint FXWindow::numChildren() const {
567   const FXWindow *child=first;
568   FXint num=0;
569   while(child){
570     child=child->next;
571     num++;
572     }
573   return num;
574   }
575 
576 
577 // Get index of child window
indexOfChild(const FXWindow * window) const578 FXint FXWindow::indexOfChild(const FXWindow *window) const {
579   FXint index=0;
580   if(!window || window->parent!=this) return -1;
581   while(window->prev){
582     window=window->prev;
583     index++;
584     }
585   return index;
586   }
587 
588 
589 // Get child window at index
childAtIndex(FXint index) const590 FXWindow* FXWindow::childAtIndex(FXint index) const {
591   FXWindow* child=first;
592   if(index<0) return NULL;
593   while(index && child){
594     child=child->next;
595     index--;
596     }
597   return child;
598   }
599 
600 
601 // Find common ancestor between window a and b
commonAncestor(FXWindow * a,FXWindow * b)602 FXWindow* FXWindow::commonAncestor(FXWindow* a,FXWindow* b){
603   FXWindow *p1,*p2;
604   if(a || b){
605     if(!a) return b->getRoot();
606     if(!b) return a->getRoot();
607     p1=a;
608     while(p1){
609       p2=b;
610       while(p2){
611         if(p2==p1) return p1;
612         p2=p2->parent;
613         }
614       p1=p1->parent;
615       }
616     }
617   return NULL;
618   }
619 
620 
621 // Return true if sibling a <= sibling b in list
before(const FXWindow * a,const FXWindow * b)622 FXbool FXWindow::before(const FXWindow *a,const FXWindow* b){
623   while(a!=b && a) a=a->next;
624   return a==b;
625   }
626 
627 
628 // Return true if sibling a >= sibling b in list
after(const FXWindow * a,const FXWindow * b)629 FXbool FXWindow::after(const FXWindow *a,const FXWindow* b){
630   while(a!=b && b) b=b->next;
631   return a==b;
632   }
633 
634 
635 // Return true if window is a shell window
isShell() const636 FXbool FXWindow::isShell() const {
637   return (flags&FLAG_SHELL)!=0;
638   }
639 
640 
641 /*******************************************************************************/
642 
643 
644 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)645 long FXWindow::onPaint(FXObject*,FXSelector,void* ptr){
646   FXDCWindow dc(this,(FXEvent*)ptr);
647   dc.setForeground(backColor);
648   dc.fillRectangle(0,0,width,height);
649   return 1;
650   }
651 
652 
653 // Window was mapped to screen
onMap(FXObject *,FXSelector,void * ptr)654 long FXWindow::onMap(FXObject*,FXSelector,void* ptr){
655   FXTRACE((250,"%s::onMap %p\n",getClassName(),this));
656   return target && target->tryHandle(this,FXSEL(SEL_MAP,message),ptr);
657   }
658 
659 
660 // Window was unmapped; the grab is lost
onUnmap(FXObject *,FXSelector,void * ptr)661 long FXWindow::onUnmap(FXObject*,FXSelector,void* ptr){
662   FXTRACE((250,"%s::onUnmap %p\n",getClassName(),this));
663   if(getApp()->mouseGrabWindow==this) getApp()->mouseGrabWindow=NULL;
664   if(getApp()->keyboardGrabWindow==this) getApp()->keyboardGrabWindow=NULL;
665   return target && target->tryHandle(this,FXSEL(SEL_UNMAP,message),ptr);
666   }
667 
668 
669 // Handle configure notify
onConfigure(FXObject *,FXSelector,void * ptr)670 long FXWindow::onConfigure(FXObject*,FXSelector,void* ptr){
671   FXTRACE((250,"%s::onConfigure %p\n",getClassName(),this));
672   return target && target->tryHandle(this,FXSEL(SEL_CONFIGURE,message),ptr);
673   }
674 
675 
676 // The window was destroyed; the grab is lost
onDestroy(FXObject *,FXSelector,void *)677 long FXWindow::onDestroy(FXObject*,FXSelector,void*){
678   FXTRACE((250,"%s::onDestroy %p\n",getClassName(),this));
679   getApp()->hash.remove((FXptr)xid);
680   if(getApp()->mouseGrabWindow==this) getApp()->mouseGrabWindow=NULL;
681   if(getApp()->keyboardGrabWindow==this) getApp()->keyboardGrabWindow=NULL;
682   if(getApp()->cursorWindow==this) getApp()->cursorWindow=parent;
683   if(getApp()->activeWindow==this) getApp()->activeWindow=NULL;
684   flags&=~FLAG_FOCUSED;
685   xid=0;
686   return 1;
687   }
688 
689 
690 // Left button pressed
onLeftBtnPress(FXObject *,FXSelector,void * ptr)691 long FXWindow::onLeftBtnPress(FXObject*,FXSelector,void* ptr){
692   flags&=~FLAG_TIP;
693   handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
694   if(isEnabled()){
695     grab();
696     if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONPRESS,message),ptr)) return 1;
697     }
698   return 0;
699   }
700 
701 
702 // Left button released
onLeftBtnRelease(FXObject *,FXSelector,void * ptr)703 long FXWindow::onLeftBtnRelease(FXObject*,FXSelector,void* ptr){
704   if(isEnabled()){
705     ungrab();
706     if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONRELEASE,message),ptr)) return 1;
707     }
708   return 0;
709   }
710 
711 
712 // Middle button released
onMiddleBtnPress(FXObject *,FXSelector,void * ptr)713 long FXWindow::onMiddleBtnPress(FXObject*,FXSelector,void* ptr){
714   flags&=~FLAG_TIP;
715   handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
716   if(isEnabled()){
717     grab();
718     if(target && target->tryHandle(this,FXSEL(SEL_MIDDLEBUTTONPRESS,message),ptr)) return 1;
719     }
720   return 0;
721   }
722 
723 
724 // Middle button pressed
onMiddleBtnRelease(FXObject *,FXSelector,void * ptr)725 long FXWindow::onMiddleBtnRelease(FXObject*,FXSelector,void* ptr){
726   if(isEnabled()){
727     ungrab();
728     if(target && target->tryHandle(this,FXSEL(SEL_MIDDLEBUTTONRELEASE,message),ptr)) return 1;
729     }
730   return 0;
731   }
732 
733 
734 // Right button pressed
onRightBtnPress(FXObject *,FXSelector,void * ptr)735 long FXWindow::onRightBtnPress(FXObject*,FXSelector,void* ptr){
736   flags&=~FLAG_TIP;
737   handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
738   if(isEnabled()){
739     grab();
740     if(target && target->tryHandle(this,FXSEL(SEL_RIGHTBUTTONPRESS,message),ptr)) return 1;
741     }
742   return 0;
743   }
744 
745 
746 // Right button released
onRightBtnRelease(FXObject *,FXSelector,void * ptr)747 long FXWindow::onRightBtnRelease(FXObject*,FXSelector,void* ptr){
748   if(isEnabled()){
749     ungrab();
750     if(target && target->tryHandle(this,FXSEL(SEL_RIGHTBUTTONRELEASE,message),ptr)) return 1;
751     }
752   return 0;
753   }
754 
755 
756 // Mouse motion
onMotion(FXObject *,FXSelector,void * ptr)757 long FXWindow::onMotion(FXObject*,FXSelector,void* ptr){
758   return isEnabled() && target && target->tryHandle(this,FXSEL(SEL_MOTION,message),ptr);
759   }
760 
761 
762 // Mouse wheel
onMouseWheel(FXObject *,FXSelector,void * ptr)763 long FXWindow::onMouseWheel(FXObject*,FXSelector,void* ptr){
764   return isEnabled() && target && target->tryHandle(this,FXSEL(SEL_MOUSEWHEEL,message),ptr);
765   }
766 
767 
768 // Keyboard press
onKeyPress(FXObject *,FXSelector,void * ptr)769 long FXWindow::onKeyPress(FXObject*,FXSelector,void* ptr){
770   FXTRACE((200,"%s::onKeyPress %p keysym=0x%04x state=%04x\n",getClassName(),this,((FXEvent*)ptr)->code,((FXEvent*)ptr)->state));
771   return isEnabled() && target && target->tryHandle(this,FXSEL(SEL_KEYPRESS,message),ptr);
772   }
773 
774 
775 // Keyboard release
onKeyRelease(FXObject *,FXSelector,void * ptr)776 long FXWindow::onKeyRelease(FXObject*,FXSelector,void* ptr){
777   FXTRACE((200,"%s::onKeyRelease %p keysym=0x%04x state=%04x\n",getClassName(),this,((FXEvent*)ptr)->code,((FXEvent*)ptr)->state));
778   return isEnabled() && target && target->tryHandle(this,FXSEL(SEL_KEYRELEASE,message),ptr);
779   }
780 
781 
782 // Space ball motion
onSpaceBallMotion(FXObject *,FXSelector,void * ptr)783 long FXWindow::onSpaceBallMotion(FXObject*,FXSelector,void* ptr){
784   return isEnabled() && target && target->tryHandle(this,FXSEL(SEL_SPACEBALLMOTION,message),ptr);
785   }
786 
787 
788 // Space ball button press
onSpaceBallButtonPress(FXObject *,FXSelector,void * ptr)789 long FXWindow::onSpaceBallButtonPress(FXObject*,FXSelector,void* ptr){
790   return isEnabled() && target && target->tryHandle(this,FXSEL(SEL_SPACEBALLBUTTONPRESS,message),ptr);
791   }
792 
793 
794 // Space ball button release
onSpaceBallButtonRelease(FXObject *,FXSelector,void * ptr)795 long FXWindow::onSpaceBallButtonRelease(FXObject*,FXSelector,void* ptr){
796   return isEnabled() && target && target->tryHandle(this,FXSEL(SEL_SPACEBALLBUTTONRELEASE,message),ptr);
797   }
798 
799 
800 // Start a drag operation
onBeginDrag(FXObject *,FXSelector,void * ptr)801 long FXWindow::onBeginDrag(FXObject*,FXSelector,void* ptr){
802   return target && target->tryHandle(this,FXSEL(SEL_BEGINDRAG,message),ptr);
803   }
804 
805 
806 // End drag operation
onEndDrag(FXObject *,FXSelector,void * ptr)807 long FXWindow::onEndDrag(FXObject*,FXSelector,void* ptr){
808   return target && target->tryHandle(this,FXSEL(SEL_ENDDRAG,message),ptr);
809   }
810 
811 
812 // Dragged stuff around
onDragged(FXObject *,FXSelector,void * ptr)813 long FXWindow::onDragged(FXObject*,FXSelector,void* ptr){
814   return target && target->tryHandle(this,FXSEL(SEL_DRAGGED,message),ptr);
815   }
816 
817 
818 // Entering window
onEnter(FXObject *,FXSelector,void * ptr)819 long FXWindow::onEnter(FXObject*,FXSelector,void* ptr){
820   FXTRACE((150,"%s::onEnter %p (%s)\n",getClassName(),this, (((FXEvent*)ptr)->code==CROSSINGNORMAL) ? "CROSSINGNORMAL" : (((FXEvent*)ptr)->code==CROSSINGGRAB) ? "CROSSINGGRAB" : (((FXEvent*)ptr)->code==CROSSINGUNGRAB)? "CROSSINGUNGRAB" : "?"));
821   if(((FXEvent*)ptr)->code!=CROSSINGGRAB){
822     if(!(((FXEvent*)ptr)->state&(SHIFTMASK|CONTROLMASK|METAMASK|LEFTBUTTONMASK|MIDDLEBUTTONMASK|RIGHTBUTTONMASK))) flags|=FLAG_TIP;
823     flags|=FLAG_HELP;
824     }
825   if(isEnabled() && target){ target->tryHandle(this,FXSEL(SEL_ENTER,message),ptr); }
826   return 1;
827   }
828 
829 
830 // Leaving window
onLeave(FXObject *,FXSelector,void * ptr)831 long FXWindow::onLeave(FXObject*,FXSelector,void* ptr){
832   FXTRACE((150,"%s::onLeave %p (%s)\n",getClassName(),this, (((FXEvent*)ptr)->code==CROSSINGNORMAL) ? "CROSSINGNORMAL" : (((FXEvent*)ptr)->code==CROSSINGGRAB) ? "CROSSINGGRAB" : (((FXEvent*)ptr)->code==CROSSINGUNGRAB)? "CROSSINGUNGRAB" : "?"));
833   if(((FXEvent*)ptr)->code!=CROSSINGUNGRAB){
834     flags&=~(FLAG_TIP|FLAG_HELP);
835     }
836   if(isEnabled() && target){ target->tryHandle(this,FXSEL(SEL_LEAVE,message),ptr); }
837   return 1;
838   }
839 
840 
841 // We were asked about tip text
onQueryTip(FXObject * sender,FXSelector,void * ptr)842 long FXWindow::onQueryTip(FXObject* sender,FXSelector,void* ptr){
843   return (flags&FLAG_TIP) && target && target->tryHandle(sender,FXSEL(SEL_QUERY_TIP,message),ptr);
844   }
845 
846 
847 // We were asked about status text
onQueryHelp(FXObject * sender,FXSelector,void * ptr)848 long FXWindow::onQueryHelp(FXObject* sender,FXSelector,void* ptr){
849   return (flags&FLAG_HELP) && target && target->tryHandle(sender,FXSEL(SEL_QUERY_HELP,message),ptr);
850   }
851 
852 
853 // True if window under the cursor
underCursor() const854 FXbool FXWindow::underCursor() const {
855   return (getApp()->cursorWindow==this);
856   }
857 
858 
859 // Handle drag-and-drop enter
onDNDEnter(FXObject *,FXSelector,void * ptr)860 long FXWindow::onDNDEnter(FXObject*,FXSelector,void* ptr){
861   FXTRACE((150,"%s::onDNDEnter %p\n",getClassName(),this));
862   return target && target->tryHandle(this,FXSEL(SEL_DND_ENTER,message),ptr);
863   }
864 
865 
866 // Handle drag-and-drop leave
onDNDLeave(FXObject *,FXSelector,void * ptr)867 long FXWindow::onDNDLeave(FXObject*,FXSelector,void* ptr){
868   FXTRACE((150,"%s::onDNDLeave %p\n",getClassName(),this));
869   return target && target->tryHandle(this,FXSEL(SEL_DND_LEAVE,message),ptr);
870   }
871 
872 
873 // Handle drag-and-drop motion
onDNDMotion(FXObject *,FXSelector,void * ptr)874 long FXWindow::onDNDMotion(FXObject*,FXSelector,void* ptr){
875   FXTRACE((150,"%s::onDNDMotion %p\n",getClassName(),this));
876   return target && target->tryHandle(this,FXSEL(SEL_DND_MOTION,message),ptr);
877   }
878 
879 
880 // Handle drag-and-drop drop
onDNDDrop(FXObject *,FXSelector,void * ptr)881 long FXWindow::onDNDDrop(FXObject*,FXSelector,void* ptr){
882   FXTRACE((150,"%s::onDNDDrop %p\n",getClassName(),this));
883   return target && target->tryHandle(this,FXSEL(SEL_DND_DROP,message),ptr);
884   }
885 
886 
887 // Request for DND data
onDNDRequest(FXObject *,FXSelector,void * ptr)888 long FXWindow::onDNDRequest(FXObject*,FXSelector,void* ptr){
889   FXTRACE((150,"%s::onDNDRequest %p\n",getClassName(),this));
890   return target && target->tryHandle(this,FXSEL(SEL_DND_REQUEST,message),ptr);
891   }
892 
893 
894 // Show window
onCmdShow(FXObject *,FXSelector,void *)895 long FXWindow::onCmdShow(FXObject*,FXSelector,void*){
896   if(!shown()){ show(); recalc(); }
897   return 1;
898   }
899 
900 
901 // Hide window
onCmdHide(FXObject *,FXSelector,void *)902 long FXWindow::onCmdHide(FXObject*,FXSelector,void*){
903   if(shown()){ hide(); recalc(); }
904   return 1;
905   }
906 
907 // Hide or show window
onCmdToggleShown(FXObject *,FXSelector,void *)908 long FXWindow::onCmdToggleShown(FXObject*,FXSelector,void*){
909   shown() ? hide() : show();
910   recalc();
911   return 1;
912   }
913 
914 
915 // Update hide or show window
onUpdToggleShown(FXObject * sender,FXSelector,void *)916 long FXWindow::onUpdToggleShown(FXObject* sender,FXSelector,void*){
917   sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
918   sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
919   sender->handle(this,FXSEL(SEL_COMMAND,ID_SETVALUE),(void*)(FXuval)shown());
920   return 1;
921   }
922 
923 
924 // Raise window
onCmdRaise(FXObject *,FXSelector,void *)925 long FXWindow::onCmdRaise(FXObject*,FXSelector,void*){
926   raise();
927   return 1;
928   }
929 
930 
931 // Lower window
onCmdLower(FXObject *,FXSelector,void *)932 long FXWindow::onCmdLower(FXObject*,FXSelector,void*){
933   lower();
934   return 1;
935   }
936 
937 
938 // Delete window
onCmdDelete(FXObject *,FXSelector,void *)939 long FXWindow::onCmdDelete(FXObject*,FXSelector,void*){
940   delete this;
941   return 1;
942   }
943 
944 
945 // Enable window
onCmdEnable(FXObject *,FXSelector,void *)946 long FXWindow::onCmdEnable(FXObject*,FXSelector,void*){
947   enable();
948   return 1;
949   }
950 
951 
952 // Disable window
onCmdDisable(FXObject *,FXSelector,void *)953 long FXWindow::onCmdDisable(FXObject*,FXSelector,void*){
954   disable();
955   return 1;
956   }
957 
958 
959 // Disable or enable window
onCmdToggleEnabled(FXObject *,FXSelector,void *)960 long FXWindow::onCmdToggleEnabled(FXObject*,FXSelector,void*){
961   isEnabled() ? disable() : enable();
962   return 1;
963   }
964 
965 
966 // Update disable or enable window
onUpdToggleEnabled(FXObject * sender,FXSelector,void *)967 long FXWindow::onUpdToggleEnabled(FXObject* sender,FXSelector,void*){
968   sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
969   sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
970   sender->handle(this,FXSEL(SEL_COMMAND,ID_SETVALUE),(void*)(FXuval)isEnabled());
971   return 1;
972   }
973 
974 
975 // In combination with autograying/autohiding widgets,
976 // this could be used to ungray or show when you don't want
977 // to write a whole handler routine just to do this.
onUpdYes(FXObject * sender,FXSelector,void *)978 long FXWindow::onUpdYes(FXObject* sender,FXSelector,void*){
979   sender->handle(this,FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
980   sender->handle(this,FXSEL(SEL_COMMAND,ID_SHOW),NULL);
981   return 1;
982   }
983 
984 
985 // Update (repaint) window
onCmdUpdate(FXObject *,FXSelector,void *)986 long FXWindow::onCmdUpdate(FXObject*,FXSelector,void*){
987   update();
988   return 1;
989   }
990 
991 
992 /*******************************************************************************/
993 
994 // Gained focus
onFocusIn(FXObject *,FXSelector,void * ptr)995 long FXWindow::onFocusIn(FXObject*,FXSelector,void* ptr){
996   FXTRACE((150,"%s::onFocusIn %p\n",getClassName(),this));
997   flags|=FLAG_FOCUSED;
998   if(target){ target->tryHandle(this,FXSEL(SEL_FOCUSIN,message),ptr); }
999   if(composeContext){ composeContext->focusIn(); }
1000   if(focus){ focus->handle(focus,FXSEL(SEL_FOCUSIN,0),NULL); }
1001   return 1;
1002   }
1003 
1004 
1005 // Lost focus
onFocusOut(FXObject *,FXSelector,void * ptr)1006 long FXWindow::onFocusOut(FXObject*,FXSelector,void* ptr){
1007   FXTRACE((150,"%s::onFocusOut %p\n",getClassName(),this));
1008   if(focus){ focus->handle(focus,FXSEL(SEL_FOCUSOUT,0),NULL); }
1009   if(composeContext){ composeContext->focusOut(); }
1010   if(target){ target->tryHandle(this,FXSEL(SEL_FOCUSOUT,message),ptr); }
1011   flags&=~FLAG_FOCUSED;
1012   return 1;
1013   }
1014 
1015 
1016 // Focus on widget itself, if its enabled
onFocusSelf(FXObject *,FXSelector,void *)1017 long FXWindow::onFocusSelf(FXObject*,FXSelector,void*){
1018   FXTRACE((150,"%s::onFocusSelf %p\n",getClassName(),this));
1019   if(isEnabled() && canFocus()){ setFocus(); return 1; }
1020   return 0;
1021   }
1022 
1023 
1024 // Create compose context
createComposeContext()1025 void FXWindow::createComposeContext(){
1026   if(!composeContext){
1027     composeContext=new FXComposeContext(getApp(),this,0);
1028     composeContext->create();
1029     }
1030   }
1031 
1032 
1033 // Destroy compose context
destroyComposeContext()1034 void FXWindow::destroyComposeContext(){
1035   if(composeContext){
1036     delete composeContext;
1037     composeContext=NULL;
1038     }
1039   }
1040 
1041 
1042 // If window can have focus
canFocus() const1043 FXbool FXWindow::canFocus() const { return false; }
1044 
1045 
1046 // Has window the focus
hasFocus() const1047 FXbool FXWindow::hasFocus() const {
1048   return (flags&FLAG_FOCUSED)!=0;
1049   }
1050 
1051 
1052 // Window is in focus chain
inFocusChain() const1053 FXbool FXWindow::inFocusChain() const {
1054   return parent->focus==this;
1055   }
1056 
1057 
1058 // Set focus to this widget.
1059 // The chain of focus from shell down to a control is changed.
1060 // Widgets now in the chain may or may not gain real focus,
1061 // depending on whether parent window already had a real focus!
1062 // Setting the focus to a composite will cause descendants to loose it.
setFocus()1063 void FXWindow::setFocus(){
1064   FXTRACE((140,"%s::setFocus %p\n",getClassName(),this));
1065   if(parent && parent->focus!=this){
1066     if(parent->focus) parent->focus->killFocus(); else parent->setFocus();
1067     parent->changeFocus(this);
1068     if(parent->hasFocus()) handle(this,FXSEL(SEL_FOCUSIN,0),NULL);
1069     }
1070   flags|=FLAG_HELP;
1071   }
1072 
1073 
1074 // Kill focus to this widget.
killFocus()1075 void FXWindow::killFocus(){
1076   FXTRACE((140,"%s::killFocus %p\n",getClassName(),this));
1077   if(parent && parent->focus==this){
1078     if(focus) focus->killFocus();
1079     if(hasFocus()) handle(this,FXSEL(SEL_FOCUSOUT,0),NULL);
1080     parent->changeFocus(NULL);
1081     }
1082   flags&=~FLAG_HELP;
1083   }
1084 
1085 
1086 // Notification that focus moved to new child
changeFocus(FXWindow * child)1087 void FXWindow::changeFocus(FXWindow *child){
1088   FXTRACE((140,"%s::changeFocus: from %p to %p\n",getClassName(),focus,child));
1089   focus=child;
1090   }
1091 
1092 
1093 // Return true if widget is drawn as default
isDefault() const1094 FXbool FXWindow::isDefault() const {
1095   return (flags&FLAG_DEFAULT)!=0;
1096   }
1097 
1098 
1099 // Make widget drawn as default
setDefault(FXuchar flag)1100 void FXWindow::setDefault(FXuchar flag){
1101   FXWindow *win;
1102   switch(flag){
1103     case false:
1104       flags&=~FLAG_DEFAULT;
1105       break;
1106     case true:
1107       if(!(flags&FLAG_DEFAULT)){
1108         win=getShell()->findDefault();
1109         if(win) win->setDefault(false);
1110         flags|=FLAG_DEFAULT;
1111         }
1112       break;
1113     case maybe:
1114       if(flags&FLAG_DEFAULT){
1115         flags&=~FLAG_DEFAULT;
1116         win=getShell()->findInitial();
1117         if(win) win->setDefault(true);
1118         }
1119       break;
1120     }
1121   }
1122 
1123 // Find default window
findDefault() const1124 FXWindow* FXWindow::findDefault() const {
1125   FXWindow *win=(FXWindow*)this;
1126   while(1){
1127     if(win->isDefault()) return win;
1128     if(win->getFirst()){ win=win->getFirst(); continue; }
1129 nxt:if(win==this) break;
1130     if(win->getNext()){ win=win->getNext(); continue; }
1131     win=win->getParent();
1132     goto nxt;
1133     }
1134   return NULL;
1135   }
1136 
1137 
1138 
1139 // Return true if this is the initial default window
isInitial() const1140 FXbool FXWindow::isInitial() const {
1141   return (flags&FLAG_INITIAL)!=0;
1142   }
1143 
1144 
1145 // Make this window the initial default window
setInitial(FXbool flag)1146 void FXWindow::setInitial(FXbool flag){
1147   FXWindow *win;
1148   if((flags&FLAG_INITIAL) && !flag){
1149     flags&=~FLAG_INITIAL;
1150     }
1151   if(!(flags&FLAG_INITIAL) && flag){
1152     win=getShell()->findInitial();
1153     if(win) win->setInitial(false);
1154     flags|=FLAG_INITIAL;
1155     }
1156   }
1157 
1158 
1159 // Find initial window
findInitial() const1160 FXWindow* FXWindow::findInitial() const {
1161   FXWindow *win=(FXWindow*)this;
1162   while(1){
1163     if(win->isInitial()) return win;
1164     if(win->getFirst()){ win=win->getFirst(); continue; }
1165 nxt:if(win==this) break;
1166     if(win->getNext()){ win=win->getNext(); continue; }
1167     win=win->getParent();
1168     goto nxt;
1169     }
1170   return NULL;
1171   }
1172 
1173 /*******************************************************************************/
1174 
1175 
1176 #ifndef WIN32
1177 
1178 // Add this window to the list of colormap windows
addColormapWindows()1179 void FXWindow::addColormapWindows(){
1180   Window windows[2],*windowsReturn,*windowList;
1181   int countReturn,i;
1182 
1183   // Check to see if there is already a property
1184   Status status=XGetWMColormapWindows((Display*)getApp()->getDisplay(),getShell()->id(),&windowsReturn,&countReturn);
1185 
1186   // If no property, just create one
1187   if(!status){
1188     windows[0]=id();
1189     windows[1]=getShell()->id();
1190     XSetWMColormapWindows((Display*)getApp()->getDisplay(),getShell()->id(),windows,2);
1191     }
1192 
1193   // There was a property, add myself to the beginning
1194   else{
1195     windowList=(Window*)malloc((sizeof(Window))*(countReturn+1));
1196     windowList[0]=id();
1197     for(i=0; i<countReturn; i++) windowList[i+1]=windowsReturn[i];
1198     XSetWMColormapWindows((Display*)getApp()->getDisplay(),getShell()->id(),windowList,countReturn+1);
1199     XFree((char*)windowsReturn);
1200     free(windowList);
1201     }
1202   }
1203 
1204 
1205 // Remove it from colormap windows
remColormapWindows()1206 void FXWindow::remColormapWindows(){
1207   Window *windowsReturn;
1208   int countReturn,i;
1209   Status status=XGetWMColormapWindows((Display*)getApp()->getDisplay(),getShell()->id(),&windowsReturn,&countReturn);
1210   if(status){
1211     for(i=0; i<countReturn; i++){
1212       if(windowsReturn[i]==id()){
1213         for(i++; i<countReturn; i++) windowsReturn[i-1]=windowsReturn[i];
1214         XSetWMColormapWindows((Display*)getApp()->getDisplay(),getShell()->id(),windowsReturn,countReturn-1);
1215         break;
1216         }
1217       }
1218     XFree((char*)windowsReturn);
1219     }
1220   }
1221 
1222 #endif
1223 
1224 
1225 /*******************************************************************************/
1226 
1227 // Create X window
create()1228 void FXWindow::create(){
1229   if(!xid){
1230     if(getApp()->isInitialized()){
1231       FXTRACE((100,"%s::create %p\n",getClassName(),this));
1232 
1233       // Gotta have a parent already created!
1234       if(!parent->id()){ fxerror("%s::create: trying to create window before creating parent window.\n",getClassName()); }
1235 
1236       // If window has owner, owner should have been created already
1237       if(owner && !owner->id()){ fxerror("%s::create: trying to create window before creating owner window.\n",getClassName()); }
1238 
1239       // Got to have a visual
1240       if(!visual){ fxerror("%s::create: trying to create window without a visual.\n",getClassName()); }
1241 
1242       // Initialize visual
1243       visual->create();
1244 
1245       // Create default cursor
1246       if(defaultCursor) defaultCursor->create();
1247 
1248       // Create drag cursor
1249       if(dragCursor) dragCursor->create();
1250 
1251 #ifdef WIN32
1252       // Most windows use these style bits
1253       DWORD dwStyle=WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
1254       DWORD dwExStyle=WS_EX_NOPARENTNOTIFY;
1255       HWND hParent=(HWND)parent->id();
1256       if(isShell()){
1257         if(isMemberOf(FXMETACLASS(FXTopWindow))){
1258           dwStyle=WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
1259           }
1260         else if(doesOverrideRedirect()){
1261           // To control window placement or control decoration, a window manager
1262           // often needs to redirect map or configure requests. Popup windows, however,
1263           // often need to be mapped without a window manager getting in the way.
1264           dwStyle=WS_POPUP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
1265           dwExStyle=WS_EX_TOOLWINDOW;
1266           }
1267         else{
1268           // Other top-level shell windows (like dialogs)
1269           dwStyle=WS_POPUP|WS_CAPTION|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
1270           dwExStyle=WS_EX_DLGMODALFRAME|WS_EX_TOOLWINDOW;
1271           }
1272         if(owner) hParent=(HWND)owner->id();
1273         }
1274 
1275       // Create this window
1276       xid=CreateWindowEx(dwExStyle,(TCHAR*)GetClass(),NULL,dwStyle,xpos,ypos,FXMAX(width,1),FXMAX(height,1),hParent,NULL,(HINSTANCE)getApp()->getDisplay(),this);
1277 
1278       // Uh-oh, we failed
1279       if(!xid){ throw FXWindowException("unable to create window."); }
1280 
1281       // Store for xid to C++ object mapping
1282       getApp()->hash.insert((FXptr)xid,this);
1283 
1284       // We put the XdndAware property on all toplevel windows, so that
1285       // when dragging, we need to search no further than the toplevel window.
1286       if(isShell()){
1287         HANDLE propdata=(HANDLE)XDND_PROTOCOL_VERSION;
1288         SetProp((HWND)xid,(LPCTSTR)MAKELONG(getApp()->xdndAware,0),propdata);
1289         }
1290 
1291       // To keep it on top
1292       //SetWindowPos((HWND)xid,HWND_TOPMOST,xpos,ypos,FXMAX(width,1),FXMAX(height,1),0);
1293 
1294       // Disable if not enabled (FIXME this does not work)
1295       if(!isEnabled()){
1296  //       EnableWindow((HWND)xid,false);
1297         }
1298 
1299       // Show if it was supposed to be.  Apparently, initial state
1300       // is neither shown nor hidden, so an explicit hide is needed.
1301       // Patch thanks to "Glenn Shen" <shen@hks.com>
1302       if(shown())
1303         ShowWindow((HWND)xid,SW_SHOWNOACTIVATE);
1304       else
1305         ShowWindow((HWND)xid,SW_HIDE);
1306 
1307 #else                   // X11
1308 
1309       XSetWindowAttributes wattr;
1310       unsigned long mask;
1311 
1312       // Fill in the attributes
1313       mask=CWBackPixmap|CWWinGravity|CWBitGravity|CWBorderPixel|CWEventMask|CWDontPropagate|CWCursor|CWOverrideRedirect|CWSaveUnder|CWColormap;
1314 
1315       // Events for normal windows
1316       wattr.event_mask=BASIC_EVENT_MASK;
1317 
1318       // Events for shell windows
1319       if(isShell()) wattr.event_mask|=SHELL_EVENT_MASK;
1320 
1321       // If enabled, turn on some more events
1322       if(isEnabled()) wattr.event_mask|=ENABLED_EVENT_MASK;
1323 
1324       // For input methods
1325 //#ifndef NO_XIM
1326 //      if(getApp()->xic){
1327 //        long filterevents=0;
1328 //        XGetICValues((XIC)getApp()->xic,XNFilterEvents,&filterevents,NULL);
1329 //        wattr.event_mask|=filterevents;
1330 //        }
1331 //#endif
1332 
1333       // FOX will not propagate events to ancestor windows
1334       wattr.do_not_propagate_mask=NOT_PROPAGATE_MASK;
1335 
1336       // Obtain colormap
1337       wattr.colormap=visual->colormap;
1338 
1339       // This is needed for OpenGL
1340       wattr.border_pixmap=None;
1341       wattr.border_pixel=0;
1342 
1343       // Background
1344       //wattr.background_pixmap=ParentRelative;
1345       wattr.background_pixmap=None;
1346       wattr.background_pixel=0;
1347 
1348       // Preserving content during resize will be faster:- not turned
1349       // on yet as we will have to recode all widgets to decide when to
1350       // repaint or not to repaint the display when resized...
1351       wattr.bit_gravity=NorthWestGravity;
1352       wattr.bit_gravity=ForgetGravity;
1353 
1354       // The window gravity is NorthWestGravity, which means
1355       // if a child keeps same position relative to top/left
1356       // of its parent window, nothing extra work is incurred.
1357       wattr.win_gravity=NorthWestGravity;
1358 
1359       // Determine override redirect
1360       wattr.override_redirect=doesOverrideRedirect();
1361 
1362       // Backing store/planes/pixel not passed
1363       wattr.backing_store=0;
1364       wattr.backing_planes=0;
1365       wattr.backing_pixel=0;
1366 
1367       // Determine save-unders
1368       wattr.save_under=doesSaveUnder();
1369 
1370       // Set cursor
1371       wattr.cursor=defaultCursor->id();
1372 
1373       // Finally, create the window
1374       xid=XCreateWindow((Display*)getApp()->getDisplay(),parent->id(),xpos,ypos,FXMAX(width,1),FXMAX(height,1),0,visual->depth,InputOutput,(Visual*)visual->visual,mask,&wattr);
1375 
1376       // Uh-oh, we failed
1377       if(!xid){ throw FXWindowException("unable to create window."); }
1378 
1379       // Store for xid to C++ object mapping
1380       getApp()->hash.insert((FXptr)xid,this);
1381 
1382       // We put the XdndAware property on all toplevel windows, so that
1383       // when dragging, we need to search no further than the toplevel window.
1384       if(isShell()){
1385         Atom propdata=(Atom)XDND_PROTOCOL_VERSION;
1386         XChangeProperty((Display*)getApp()->getDisplay(),xid,getApp()->xdndAware,XA_ATOM,32,PropModeReplace,(unsigned char*)&propdata,1);
1387         }
1388 
1389       // If window is a shell and it has an owner, make it stay on top of the owner
1390       if(isShell() && owner){
1391         XSetTransientForHint((Display*)getApp()->getDisplay(),xid,owner->getShell()->id());
1392         }
1393 
1394       // If colormap different, set WM_COLORMAP_WINDOWS property properly
1395       if(visual->colormap!=DefaultColormap((Display*)getApp()->getDisplay(),DefaultScreen((Display*)getApp()->getDisplay()))){
1396         addColormapWindows();
1397         }
1398 
1399       // Show if it was supposed to be
1400       if(shown() && 0<width && 0<height) XMapWindow((Display*)getApp()->getDisplay(),xid);
1401 
1402 #endif
1403       flags|=FLAG_OWNED;
1404       }
1405     }
1406   }
1407 
1408 
1409 // Attach to a window belonging to another application
attach(FXID w)1410 void FXWindow::attach(FXID w){
1411   if(!xid){
1412     if(getApp()->isInitialized()){
1413       FXTRACE((100,"%s::attach %p\n",getClassName(),this));
1414 
1415       // Gotta have a parent already created!
1416       if(!parent->id()){ fxerror("%s::attach: trying to attach window before creating parent window.\n",getClassName()); }
1417 
1418       // If window has owner, owner should have been created already
1419       if(owner && !owner->id()){ fxerror("%s::attach: trying to attach window before creating owner window.\n",getClassName()); }
1420 
1421       // Got to have a visual
1422       if(!visual){ fxerror("%s::attach: trying to attach window without a visual.\n",getClassName()); }
1423 
1424       // Uh-oh, we failed
1425       if(!w){ throw FXWindowException("unable to attach window."); }
1426 
1427       // Initialize visual
1428       visual->create();
1429 
1430       // Create default cursor
1431       if(defaultCursor) defaultCursor->create();
1432 
1433       // Create drag cursor
1434       if(dragCursor) dragCursor->create();
1435 
1436       // Simply assign to xid
1437       xid=w;
1438 
1439       // Store for xid to C++ object mapping
1440       getApp()->hash.insert((FXptr)xid,this);
1441 
1442 #ifdef WIN32
1443 
1444       // Reparent under what WE think the parent is
1445       SetParent((HWND)xid,(HWND)parent->id());
1446 
1447 #else
1448 
1449       XSetWindowAttributes wattr;
1450       unsigned long mask;
1451       mask=CWEventMask|CWDontPropagate|CWCursor;
1452       wattr.event_mask=BASIC_EVENT_MASK;
1453       if(isEnabled()) wattr.event_mask|=ENABLED_EVENT_MASK;
1454       wattr.do_not_propagate_mask=NOT_PROPAGATE_MASK;
1455       wattr.cursor=defaultCursor->id();
1456       XChangeWindowAttributes((Display*)getApp()->getDisplay(),xid,mask,&wattr);
1457 
1458       // Reparent window
1459       XReparentWindow((Display*)getApp()->getDisplay(),xid,parent->id(),0,0);
1460 #endif
1461       flags&=~FLAG_OWNED;
1462       }
1463     }
1464   }
1465 
1466 
1467 // Detach window
detach()1468 void FXWindow::detach(){
1469   if(xid){
1470     if(getApp()->isInitialized()){
1471       FXTRACE((100,"%s::detach %p\n",getClassName(),this));
1472 
1473       // Remove from xid to C++ object mapping
1474       getApp()->hash.remove((FXptr)xid);
1475 
1476       // Detach visual
1477       visual->detach();
1478 
1479       // Detach default cursor
1480       if(defaultCursor) defaultCursor->detach();
1481 
1482       // Detach drag cursor
1483       if(dragCursor) dragCursor->detach();
1484       }
1485 
1486     // No longer grabbed
1487     if(getApp()->mouseGrabWindow==this) getApp()->mouseGrabWindow=NULL;
1488     if(getApp()->keyboardGrabWindow==this) getApp()->keyboardGrabWindow=NULL;
1489     if(getApp()->cursorWindow==this) getApp()->cursorWindow=parent;
1490     if(getApp()->activeWindow==this) getApp()->activeWindow=NULL;
1491     flags&=~FLAG_FOCUSED;
1492     flags&=~FLAG_OWNED;
1493     xid=0;
1494     }
1495   }
1496 
1497 
1498 // Destroy; only destroy window if we own it
destroy()1499 void FXWindow::destroy(){
1500   if(xid){
1501     if(getApp()->isInitialized()){
1502       FXTRACE((100,"%s::destroy %p\n",getClassName(),this));
1503 
1504       // Remove from xid to C++ object mapping
1505       getApp()->hash.remove((FXptr)xid);
1506 
1507       // Its our own window, so destroy it
1508       if(flags&FLAG_OWNED){
1509 #ifdef WIN32
1510         // Delete the XdndAware property
1511         if(isShell()){
1512           RemoveProp((HWND)xid,(LPCTSTR)MAKELONG(getApp()->xdndAware,0));
1513           }
1514 
1515         // Zap the window
1516         DestroyWindow((HWND)xid);
1517 #else
1518         // If colormap different, set WM_COLORMAP_WINDOWS property properly
1519         if(visual->colormap!=DefaultColormap((Display*)getApp()->getDisplay(),DefaultScreen((Display*)getApp()->getDisplay()))){
1520           remColormapWindows();
1521           }
1522 
1523         // Delete the XdndAware property
1524         if(isShell()){
1525           XDeleteProperty((Display*)getApp()->getDisplay(),xid,getApp()->xdndAware);
1526           }
1527 
1528         // Delete the window
1529         XDestroyWindow((Display*)getApp()->getDisplay(),xid);
1530 #endif
1531         }
1532       }
1533 
1534     // No longer grabbed
1535     if(getApp()->mouseGrabWindow==this) getApp()->mouseGrabWindow=NULL;
1536     if(getApp()->keyboardGrabWindow==this) getApp()->keyboardGrabWindow=NULL;
1537     if(getApp()->cursorWindow==this) getApp()->cursorWindow=parent;
1538     if(getApp()->activeWindow==this) getApp()->activeWindow=NULL;
1539     flags&=~FLAG_FOCUSED;
1540     flags&=~FLAG_OWNED;
1541     xid=0;
1542     }
1543   }
1544 
1545 
1546 #ifdef WIN32
1547 
1548 // Get this window's device context
GetDC() const1549 FXID FXWindow::GetDC() const {
1550   return ::GetDC((HWND)xid);
1551   }
1552 
1553 
1554 // Release it
ReleaseDC(FXID hdc) const1555 int FXWindow::ReleaseDC(FXID hdc) const {
1556   return ::ReleaseDC((HWND)xid,(HDC)hdc);
1557   }
1558 
1559 // Window class
GetClass() const1560 const void* FXWindow::GetClass() const { return TEXT("FXWindow"); }
1561 
1562 #endif
1563 
1564 
1565 /*******************************************************************************/
1566 
1567 
1568 // Set window shape by means of region
setShape(const FXRegion & region)1569 void FXWindow::setShape(const FXRegion& region){
1570   if(xid){
1571 #ifdef WIN32
1572     // Make a copy so as to leave original region intact
1573     HRGN rgn=CreateRectRgn(0,0,0,0);
1574     CombineRgn(rgn,(HRGN)region.region,rgn,RGN_COPY);
1575     SetWindowRgn((HWND)xid,rgn,false);
1576 #else
1577 #if defined(HAVE_XSHAPE_H)
1578     XShapeCombineRegion((Display*)getApp()->getDisplay(),xid,ShapeBounding,0,0,(Region)region.region,ShapeSet);
1579 #endif
1580 #endif
1581     }
1582   }
1583 
1584 
1585 // Builds a region from a bitmap
1586 #ifdef WIN32
makeregion(HDC hdc,FXint w,FXint h)1587 static HRGN makeregion(HDC hdc,FXint w,FXint h){
1588   const COLORREF clear=RGB(255,255,255);
1589   HRGN shape,run;
1590   FXint x,y,z;
1591   shape=CreateRectRgn(0,0,0,0);
1592   for(y=0; y<h; y++){
1593     for(x=0; x<w; ){
1594       while(x<w && GetPixel(hdc,x,y)==clear) ++x;
1595       z=x;
1596       while(x<w && GetPixel(hdc,x,y)!=clear) ++x;
1597       if(z<x){
1598         run=CreateRectRgn(z,y,x,y+1);
1599         CombineRgn(shape,shape,run,RGN_OR);
1600         DeleteObject(run);
1601         }
1602       }
1603     }
1604   return shape;
1605   }
1606 #endif
1607 
1608 
1609 // Set window shape by means of bitmap
setShape(FXBitmap * bitmap)1610 void FXWindow::setShape(FXBitmap* bitmap){
1611   if(!bitmap || !bitmap->id()){ fxerror("%s::setShape: illegal bitmap specified.\n",getClassName()); }
1612   if(xid){
1613 #ifdef WIN32
1614     HDC hdc=CreateCompatibleDC(NULL);
1615     SelectObject(hdc,bitmap->id());
1616     HRGN rgn=makeregion(hdc,bitmap->getWidth(),bitmap->getHeight());
1617     SetWindowRgn((HWND)xid,rgn,false);
1618     DeleteDC(hdc);
1619 #else
1620 #if defined(HAVE_XSHAPE_H)
1621     XShapeCombineMask((Display*)getApp()->getDisplay(),xid,ShapeBounding,0,0,bitmap->id(),ShapeSet);
1622 #endif
1623 #endif
1624     }
1625   }
1626 
1627 
1628 // Set window shape by means of bitmap
setShape(FXIcon * icon)1629 void FXWindow::setShape(FXIcon* icon){
1630   if(!icon || !icon->shape){ fxerror("%s::setShape: illegal icon specified.\n",getClassName()); }
1631   if(xid){
1632 #ifdef WIN32
1633     HDC hdc=CreateCompatibleDC(NULL);
1634     SelectObject(hdc,icon->shape);
1635     HRGN rgn=makeregion(hdc,icon->getWidth(),icon->getHeight());
1636     SetWindowRgn((HWND)xid,rgn,false);
1637     DeleteDC(hdc);
1638 #else
1639 #if defined(HAVE_XSHAPE_H)
1640     XShapeCombineMask((Display*)getApp()->getDisplay(),xid,ShapeBounding,0,0,icon->shape,ShapeSet);
1641 #endif
1642 #endif
1643     }
1644   }
1645 
1646 
1647 // Clear window shape to default rectangle
clearShape()1648 void FXWindow::clearShape(){
1649   if(xid){
1650 #ifdef WIN32
1651     SetWindowRgn((HWND)xid,NULL,false);
1652 #else
1653 #if defined(HAVE_XSHAPE_H)
1654     XShapeCombineMask((Display*)getApp()->getDisplay(),xid,ShapeBounding,0,0,None,ShapeSet);
1655 #endif
1656 #endif
1657     }
1658   }
1659 
1660 
1661 /*******************************************************************************/
1662 
1663 
1664 // Test if active
isActive() const1665 FXbool FXWindow::isActive() const {
1666   return (flags&FLAG_ACTIVE)!=0;
1667   }
1668 
1669 
1670 // Get default width
getDefaultWidth()1671 FXint FXWindow::getDefaultWidth(){
1672   return 1;
1673   }
1674 
1675 
1676 // Get default height
getDefaultHeight()1677 FXint FXWindow::getDefaultHeight(){
1678   return 1;
1679   }
1680 
1681 
1682 // Return width for given height
getWidthForHeight(FXint)1683 FXint FXWindow::getWidthForHeight(FXint){
1684   return getDefaultWidth();
1685   }
1686 
1687 
1688 // Return height for given width
getHeightForWidth(FXint)1689 FXint FXWindow::getHeightForWidth(FXint){
1690   return getDefaultHeight();
1691   }
1692 
1693 
1694 // Set X position
setX(FXint x)1695 void FXWindow::setX(FXint x){
1696   xpos=x;
1697   recalc();
1698   }
1699 
1700 
1701 // Set Y position
setY(FXint y)1702 void FXWindow::setY(FXint y){
1703   ypos=y;
1704   recalc();
1705   }
1706 
1707 
1708 // Set width
setWidth(FXint w)1709 void FXWindow::setWidth(FXint w){
1710   if(w<0) w=0;
1711   width=w;
1712   recalc();
1713   }
1714 
1715 
1716 // Set height
setHeight(FXint h)1717 void FXWindow::setHeight(FXint h){
1718   if(h<0) h=0;
1719   height=h;
1720   recalc();
1721   }
1722 
1723 
1724 // Change layout
setLayoutHints(FXuint lout)1725 void FXWindow::setLayoutHints(FXuint lout){
1726   FXuint opts=(options&~LAYOUT_MASK) | (lout&LAYOUT_MASK);
1727   if(options!=opts){
1728     options=opts;
1729     recalc();
1730     }
1731   }
1732 
1733 
1734 // Get layout hints
getLayoutHints() const1735 FXuint FXWindow::getLayoutHints() const {
1736   return (options&LAYOUT_MASK);
1737   }
1738 
1739 
1740 // Is widget a composite
isComposite() const1741 FXbool FXWindow::isComposite() const {
1742   return false;
1743   }
1744 
1745 
1746 // Window does override-redirect
doesOverrideRedirect() const1747 FXbool FXWindow::doesOverrideRedirect() const {
1748   return false;
1749   }
1750 
1751 
1752 // Window does save-unders
doesSaveUnder() const1753 FXbool FXWindow::doesSaveUnder() const {
1754   return false;
1755   }
1756 
1757 
1758 /*******************************************************************************/
1759 
1760 
1761 // Add hot key to closest ancestor's accelerator table
addHotKey(FXHotKey code)1762 void FXWindow::addHotKey(FXHotKey code){
1763   FXAccelTable *accel=NULL;
1764   FXWindow *win=this;
1765   while(win && (accel=win->getAccelTable())==NULL) win=win->parent;
1766   if(accel) accel->addAccel(code,this,FXSEL(SEL_KEYPRESS,ID_HOTKEY),FXSEL(SEL_KEYRELEASE,ID_HOTKEY));
1767   }
1768 
1769 
1770 // Remove hot key from closest ancestor's accelerator table
remHotKey(FXHotKey code)1771 void FXWindow::remHotKey(FXHotKey code){
1772   FXAccelTable *accel=NULL;
1773   FXWindow *win=this;
1774   while(win && (accel=win->getAccelTable())==NULL) win=win->parent;
1775   if(accel) accel->removeAccel(code);
1776   }
1777 
1778 
1779 /*******************************************************************************/
1780 
1781 
1782 // Is cursor shown
cursorShown() const1783 FXbool FXWindow::cursorShown() const {
1784   return (flags&FLAG_CURSOR)!=0;
1785   }
1786 
1787 
1788 // Show or hide the cursor
showCursor(FXbool flag)1789 void FXWindow::showCursor(FXbool flag){
1790   if(!cursorShown() && flag){
1791     if(xid){
1792 #ifdef WIN32
1793       ShowCursor(true);
1794 #else
1795       XDefineCursor((Display*)getApp()->getDisplay(),xid,defaultCursor->id());
1796 #endif
1797       }
1798     flags|=FLAG_CURSOR;
1799     }
1800   else if(cursorShown() && !flag){
1801     if(xid){
1802 #ifdef WIN32
1803       ShowCursor(false);
1804 #else
1805       XDefineCursor((Display*)getApp()->getDisplay(),xid,getApp()->getDefaultCursor(DEF_BLANK_CURSOR)->id());
1806 #endif
1807       }
1808     flags&=~FLAG_CURSOR;
1809     }
1810   }
1811 
1812 
1813 // Set cursor
setDefaultCursor(FXCursor * cur)1814 void FXWindow::setDefaultCursor(FXCursor* cur){
1815   if(defaultCursor!=cur){
1816     if(cur==NULL){ fxerror("%s::setDefaultCursor: NULL cursor argument.\n",getClassName()); }
1817     if(xid){
1818       if(cur->id()==0){ fxerror("%s::setDefaultCursor: Cursor has not been created yet.\n",getClassName()); }
1819       if(cursorShown()){
1820 #ifdef WIN32
1821         if(underCursor() && !grabbed()) SetCursor((HCURSOR)cur->id());
1822 #else
1823         XDefineCursor((Display*)getApp()->getDisplay(),xid,cur->id());
1824 #endif
1825         }
1826       }
1827     defaultCursor=cur;
1828     }
1829   }
1830 
1831 
1832 // Set drag cursor
setDragCursor(FXCursor * cur)1833 void FXWindow::setDragCursor(FXCursor* cur){
1834   if(dragCursor!=cur){
1835     if(cur==NULL){ fxerror("%s::setDragCursor: NULL cursor argument.\n",getClassName()); }
1836     if(xid){
1837       if(cur->id()==0){ fxerror("%s::setDragCursor: Cursor has not been created yet.\n",getClassName()); }
1838       if(grabbed()){
1839 #ifdef WIN32
1840         SetCursor((HCURSOR)cur->id());
1841 #else
1842         XChangeActivePointerGrab((Display*)getApp()->getDisplay(),GRAB_EVENT_MASK,cur->id(),CurrentTime);
1843 #endif
1844         }
1845       }
1846     dragCursor=cur;
1847     }
1848   }
1849 
1850 
1851 // Set window background
setBackColor(FXColor clr)1852 void FXWindow::setBackColor(FXColor clr){
1853   if(clr!=backColor){
1854     backColor=clr;
1855 //    if(xid){
1856 //#ifdef WIN32
1857 //      // FIXME //
1858 //#else
1859 //      XSetWindowBackground((Display*)getApp()->getDisplay(),xid,visual->getPixel(backColor));
1860 //#endif
1861 //      }
1862     update();
1863     }
1864   }
1865 
1866 
1867 
1868 /*******************************************************************************/
1869 
1870 
1871 // Lost the selection
onSelectionLost(FXObject *,FXSelector,void * ptr)1872 long FXWindow::onSelectionLost(FXObject*,FXSelector,void* ptr){
1873   FXTRACE((100,"%s::onSelectionLost %p\n",getClassName(),this));
1874   return target && target->tryHandle(this,FXSEL(SEL_SELECTION_LOST,message),ptr);
1875   }
1876 
1877 
1878 // Gained the selection
onSelectionGained(FXObject *,FXSelector,void * ptr)1879 long FXWindow::onSelectionGained(FXObject*,FXSelector,void* ptr){
1880   FXTRACE((100,"%s::onSelectionGained %p\n",getClassName(),this));
1881   return target && target->tryHandle(this,FXSEL(SEL_SELECTION_GAINED,message),ptr);
1882   }
1883 
1884 
1885 // Somebody wants our the selection
onSelectionRequest(FXObject *,FXSelector,void * ptr)1886 long FXWindow::onSelectionRequest(FXObject*,FXSelector,void* ptr){
1887   FXTRACE((100,"%s::onSelectionRequest %p\n",getClassName(),this));
1888   return target && target->tryHandle(this,FXSEL(SEL_SELECTION_REQUEST,message),ptr);
1889   }
1890 
1891 
1892 // Has this window the selection
hasSelection() const1893 FXbool FXWindow::hasSelection() const {
1894   return (getApp()->selectionWindow==this);
1895   }
1896 
1897 
1898 // Acquire the selection.
1899 // We always generate SEL_SELECTION_LOST and SEL_SELECTION_GAINED
1900 // because we assume the selection types may have changed, and want
1901 // to give target opportunity to allocate the new data for these types.
acquireSelection(const FXDragType * types,FXuint numtypes)1902 FXbool FXWindow::acquireSelection(const FXDragType *types,FXuint numtypes){
1903   if(!types || !numtypes){ fxerror("%s::acquireSelection: should have at least one type to select.\n",getClassName()); }
1904   if(getApp()->selectionWindow){
1905     getApp()->selectionWindow->handle(getApp(),FXSEL(SEL_SELECTION_LOST,0),&getApp()->event);
1906     getApp()->selectionWindow=NULL;
1907     freeElms(getApp()->xselTypeList);
1908     getApp()->xselNumTypes=0;
1909     }
1910   if(xid){
1911 #ifndef WIN32
1912     XSetSelectionOwner((Display*)getApp()->getDisplay(),XA_PRIMARY,xid,getApp()->event.time);
1913     if(XGetSelectionOwner((Display*)getApp()->getDisplay(),XA_PRIMARY)!=xid) return false;
1914 #endif
1915     }
1916   if(!getApp()->selectionWindow){
1917     getApp()->selectionWindow=this;
1918     getApp()->selectionWindow->handle(getApp(),FXSEL(SEL_SELECTION_GAINED,0),&getApp()->event);
1919     resizeElms(getApp()->xselTypeList,numtypes);
1920     memcpy(getApp()->xselTypeList,types,sizeof(FXDragType)*numtypes);
1921     getApp()->xselNumTypes=numtypes;
1922     }
1923   return true;
1924   }
1925 
1926 
1927 // Release the selection
releaseSelection()1928 FXbool FXWindow::releaseSelection(){
1929   if(getApp()->selectionWindow==this){
1930     getApp()->selectionWindow->handle(getApp(),FXSEL(SEL_SELECTION_LOST,0),&getApp()->event);
1931     getApp()->selectionWindow=NULL;
1932     freeElms(getApp()->xselTypeList);
1933     getApp()->xselNumTypes=0;
1934     if(xid){
1935 #ifndef WIN32
1936       XSetSelectionOwner((Display*)getApp()->getDisplay(),XA_PRIMARY,None,getApp()->event.time);
1937 #endif
1938       }
1939     return true;
1940     }
1941   return false;
1942   }
1943 
1944 
1945 /*******************************************************************************/
1946 
1947 
1948 // Lost the selection
onClipboardLost(FXObject *,FXSelector,void * ptr)1949 long FXWindow::onClipboardLost(FXObject*,FXSelector,void* ptr){
1950   FXTRACE((100,"%s::onClipboardLost %p\n",getClassName(),this));
1951   return target && target->tryHandle(this,FXSEL(SEL_CLIPBOARD_LOST,message),ptr);
1952   }
1953 
1954 
1955 // Gained the selection
onClipboardGained(FXObject *,FXSelector,void * ptr)1956 long FXWindow::onClipboardGained(FXObject*,FXSelector,void* ptr){
1957   FXTRACE((100,"%s::onClipboardGained %p\n",getClassName(),this));
1958   return target && target->tryHandle(this,FXSEL(SEL_CLIPBOARD_GAINED,message),ptr);
1959   }
1960 
1961 
1962 // Somebody wants our the selection
onClipboardRequest(FXObject *,FXSelector,void * ptr)1963 long FXWindow::onClipboardRequest(FXObject*,FXSelector,void* ptr){
1964   FXTRACE((100,"%s::onClipboardRequest %p\n",getClassName(),this));
1965   return target && target->tryHandle(this,FXSEL(SEL_CLIPBOARD_REQUEST,message),ptr);
1966   }
1967 
1968 
1969 // Has this window the selection
hasClipboard() const1970 FXbool FXWindow::hasClipboard() const {
1971   return (getApp()->clipboardWindow==this);
1972   }
1973 
1974 
1975 // Acquire the clipboard
1976 // We always generate SEL_CLIPBOARD_LOST and SEL_CLIPBOARD_GAINED
1977 // because we assume the clipboard types may have changed, and want
1978 // to give target opportunity to allocate the new data for these types.
acquireClipboard(const FXDragType * types,FXuint numtypes)1979 FXbool FXWindow::acquireClipboard(const FXDragType *types,FXuint numtypes){
1980   if(!types || !numtypes){ fxerror("%s::acquireClipboard: should have at least one type to select.\n",getClassName()); }
1981   if(getApp()->clipboardWindow){
1982     getApp()->clipboardWindow->handle(getApp(),FXSEL(SEL_CLIPBOARD_LOST,0),&getApp()->event);
1983     getApp()->clipboardWindow=NULL;
1984 #ifndef WIN32
1985     freeElms(getApp()->xcbTypeList);
1986     getApp()->xcbNumTypes=0;
1987 #endif
1988     }
1989   if(xid){
1990 #ifndef WIN32
1991     XSetSelectionOwner((Display*)getApp()->getDisplay(),getApp()->xcbSelection,xid,getApp()->event.time);
1992     if(XGetSelectionOwner((Display*)getApp()->getDisplay(),getApp()->xcbSelection)!=xid) return false;
1993 #else
1994     if(!OpenClipboard((HWND)xid)) return false;
1995     EmptyClipboard();
1996     for(FXuint i=0; i<numtypes; i++){ SetClipboardData(types[i],NULL); }
1997     CloseClipboard();
1998     if(GetClipboardOwner()!=xid) return false;
1999 #endif
2000     }
2001   if(!getApp()->clipboardWindow){
2002     getApp()->clipboardWindow=this;
2003     getApp()->clipboardWindow->handle(getApp(),FXSEL(SEL_CLIPBOARD_GAINED,0),&getApp()->event);
2004 #ifndef WIN32
2005     resizeElms(getApp()->xcbTypeList,numtypes);
2006     memcpy(getApp()->xcbTypeList,types,sizeof(FXDragType)*numtypes);
2007     getApp()->xcbNumTypes=numtypes;
2008 #endif
2009     }
2010   return true;
2011   }
2012 
2013 
2014 // Release the clipboard
releaseClipboard()2015 FXbool FXWindow::releaseClipboard(){
2016   if(getApp()->clipboardWindow==this){
2017     getApp()->clipboardWindow->handle(getApp(),FXSEL(SEL_CLIPBOARD_LOST,0),&getApp()->event);
2018     getApp()->clipboardWindow=NULL;
2019 #ifndef WIN32
2020     freeElms(getApp()->xcbTypeList);
2021     getApp()->xcbNumTypes=0;
2022 #endif
2023     if(xid){
2024 #ifndef WIN32
2025       XSetSelectionOwner((Display*)getApp()->getDisplay(),getApp()->xcbSelection,None,getApp()->event.time);
2026 #else
2027       if(OpenClipboard((HWND)xid)){EmptyClipboard();CloseClipboard();}
2028 #endif
2029       }
2030     return true;
2031     }
2032   return false;
2033   }
2034 
2035 
2036 /*******************************************************************************/
2037 
2038 
2039 // Get pointer location (in window coordinates)
getCursorPosition(FXint & x,FXint & y,FXuint & buttons) const2040 FXbool FXWindow::getCursorPosition(FXint& x,FXint& y,FXuint& buttons) const {
2041   if(xid){
2042 #ifdef WIN32
2043     POINT pt;
2044     GetCursorPos(&pt);
2045     ScreenToClient((HWND)xid,&pt);
2046     x=pt.x; y=pt.y;
2047     buttons=fxmodifierkeys();
2048     return true;
2049 #else
2050     Window dum; int rx,ry;
2051     return XQueryPointer((Display*)getApp()->getDisplay(),xid,&dum,&dum,&rx,&ry,&x,&y,&buttons);
2052 #endif
2053     }
2054   return false;
2055   }
2056 
2057 
2058 // Set pointer location (in window coordinates)
2059 // Contributed by David Heath <dave@hipgraphics.com>
setCursorPosition(FXint x,FXint y)2060 FXbool FXWindow::setCursorPosition(FXint x,FXint y){
2061   if(xid){
2062 #ifdef WIN32
2063     POINT pt;
2064     pt.x=x;
2065     pt.y=y;
2066     ClientToScreen((HWND)xid,&pt);
2067     SetCursorPos(pt.x,pt.y);
2068     return true;
2069 #else
2070     XWarpPointer((Display*)getApp()->getDisplay(),None,xid,0,0,0,0,x,y);
2071     return true;
2072 #endif
2073     }
2074   return false;
2075   }
2076 
2077 
2078 // Update this widget by sending SEL_UPDATE to its target.
2079 // If there is no target, onUpdate returns 0 on behalf of widgets
2080 // which have the autogray feature enabled.  If there is a target
2081 // but we're not updating because the user is manipulating the
2082 // widget, then onUpdate returns 1 to prevent it from graying
2083 // out during manipulation when the autogray feature is enabled.
2084 // Otherwise, onUpdate returns the value returned by the SEL_UPDATE
2085 // callback to the target.
onUpdate(FXObject *,FXSelector,void *)2086 long FXWindow::onUpdate(FXObject*,FXSelector,void*){
2087   return target && (!(flags&FLAG_UPDATE) || target->tryHandle(this,FXSEL(SEL_UPDATE,message),NULL));
2088   }
2089 
2090 
2091 // Perform layout immediately
layout()2092 void FXWindow::layout(){
2093   flags&=~FLAG_DIRTY;
2094   }
2095 
2096 
2097 // Mark this window's layout as dirty for later layout
recalc()2098 void FXWindow::recalc(){
2099   if(parent) parent->recalc();
2100   flags|=FLAG_DIRTY;
2101   }
2102 
2103 
2104 // Force GUI refresh of this window and all of its children
forceRefresh()2105 void FXWindow::forceRefresh(){
2106   FXWindow *win=this;
2107   while(1){
2108     win->handle(win,FXSEL(SEL_UPDATE,0),NULL);
2109     if(win->getFirst()){ win=win->getFirst(); continue; }
2110 nxt:if(win==this) break;
2111     if(win->getNext()){ win=win->getNext(); continue; }
2112     win=win->getParent();
2113     goto nxt;
2114     }
2115   }
2116 
2117 
2118 // Update dirty rectangle
update(FXint x,FXint y,FXint w,FXint h) const2119 void FXWindow::update(FXint x,FXint y,FXint w,FXint h) const {
2120   if(xid){
2121 
2122     // We toss out rectangles outside the visible area
2123     if(x>=width || y>=height || x+w<=0 || y+h<=0) return;
2124 
2125     // Intersect with the window
2126     if(x<0){w+=x;x=0;}
2127     if(y<0){h+=y;y=0;}
2128     if(x+w>width){w=width-x;}
2129     if(y+h>height){h=height-y;}
2130 
2131     // Append the rectangle; it is a synthetic expose event!!
2132     if(w>0 && h>0){
2133 #ifdef WIN32
2134       RECT r;
2135       r.left=x;
2136       r.top=y;
2137       r.right=x+w;
2138       r.bottom=y+h;
2139       InvalidateRect((HWND)xid,&r,true);
2140 #else
2141       getApp()->addRepaint(xid,x,y,w,h,true);
2142 #endif
2143       }
2144     }
2145   }
2146 
2147 
2148 // Update dirty window
update() const2149 void FXWindow::update() const {
2150   update(0,0,width,height);
2151   }
2152 
2153 
2154 // If marked but not yet painted, paint the given area
repaint(FXint x,FXint y,FXint w,FXint h) const2155 void FXWindow::repaint(FXint x,FXint y,FXint w,FXint h) const {
2156   if(xid){
2157 
2158     // We toss out rectangles outside the visible area
2159     if(x>=width || y>=height || x+w<=0 || y+h<=0) return;
2160 
2161     // Intersect with the window
2162     if(x<0){w+=x;x=0;}
2163     if(y<0){h+=y;y=0;}
2164     if(x+w>width){w=width-x;}
2165     if(y+h>height){h=height-y;}
2166 
2167     if(w>0 && h>0){
2168 #ifdef WIN32
2169       RECT r;
2170       r.left=x;
2171       r.top=y;
2172       r.right=x+w;
2173       r.bottom=y+h;
2174       RedrawWindow((HWND)xid,&r,NULL,RDW_UPDATENOW);
2175 #else
2176       getApp()->removeRepaints(xid,x,y,w,h);
2177 #endif
2178       }
2179     }
2180   }
2181 
2182 
2183 // If marked but not yet painted, paint the entire window
repaint() const2184 void FXWindow::repaint() const {
2185   repaint(0,0,width,height);
2186   }
2187 
2188 
2189 // Move window
move(FXint x,FXint y)2190 void FXWindow::move(FXint x,FXint y){
2191   FXTRACE((200,"%s::move: x=%d y=%d\n",getClassName(),x,y));
2192   if((flags&FLAG_DIRTY)||(x!=xpos)||(y!=ypos)){
2193     xpos=x;
2194     ypos=y;
2195     if(xid){
2196 
2197       // Similar as for position(), we have to generate protocol
2198       // here so as to make the display reflect reality...
2199 #ifdef WIN32
2200       SetWindowPos((HWND)xid,NULL,x,y,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
2201 #else
2202       XMoveWindow((Display*)getApp()->getDisplay(),xid,x,y);
2203 #endif
2204       if(flags&FLAG_DIRTY) layout();
2205       }
2206     }
2207   }
2208 
2209 
2210 // Move and resize
position(FXint x,FXint y,FXint w,FXint h)2211 void FXWindow::position(FXint x,FXint y,FXint w,FXint h){
2212   FXint ow=width;
2213   FXint oh=height;
2214   FXTRACE((200,"%s::position: x=%d y=%d w=%d h=%d\n",getClassName(),x,y,w,h));
2215   if(w<0) w=0;
2216   if(h<0) h=0;
2217   if((flags&FLAG_DIRTY)||(x!=xpos)||(y!=ypos)||(w!=ow)||(h!=oh)){
2218     xpos=x;
2219     ypos=y;
2220     width=w;
2221     height=h;
2222     if(xid){
2223 
2224       // Alas, we have to generate some protocol here even if the placement
2225       // as recorded in the widget hasn't actually changed.  This is because
2226       // there are ways to change the placement w/o going through position()!
2227 #ifdef WIN32
2228       SetWindowPos((HWND)xid,NULL,x,y,w,h,SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
2229 #else
2230       if(0<w && 0<h){
2231         if(shown() && (ow<=0 || oh<=0)){
2232           XMapWindow((Display*)getApp()->getDisplay(),xid);
2233           }
2234         XMoveResizeWindow((Display*)getApp()->getDisplay(),xid,x,y,w,h);
2235         }
2236       else if(0<ow && 0<oh){
2237         XUnmapWindow((Display*)getApp()->getDisplay(),xid);
2238         }
2239 #endif
2240 
2241       // We don't have to layout the interior of this widget unless
2242       // the size has changed or it was marked as dirty:- this is
2243       // a very good optimization as it's applied recursively!
2244       if((flags&FLAG_DIRTY)||(w!=ow)||(h!=oh)) layout();
2245       }
2246     }
2247   }
2248 
2249 
2250 // Resize
resize(FXint w,FXint h)2251 void FXWindow::resize(FXint w,FXint h){
2252   FXint ow=width;
2253   FXint oh=height;
2254   FXTRACE((200,"%s::resize: w=%d h=%d\n",getClassName(),w,h));
2255   if(w<0) w=0;
2256   if(h<0) h=0;
2257   if((flags&FLAG_DIRTY)||(w!=ow)||(h!=oh)){
2258     width=w;
2259     height=h;
2260     if(xid){
2261 
2262       // Similar as for position(), we have to generate protocol here..
2263 #ifdef WIN32
2264       SetWindowPos((HWND)xid,NULL,0,0,w,h,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
2265 #else
2266       if(0<w && 0<h){
2267         if(shown() && (ow<=0 || oh<=0)){
2268           XMapWindow((Display*)getApp()->getDisplay(),xid);
2269           }
2270         XResizeWindow((Display*)getApp()->getDisplay(),xid,w,h);
2271         }
2272       else if(0<ow && 0<oh){
2273         XUnmapWindow((Display*)getApp()->getDisplay(),xid);
2274         }
2275 #endif
2276 
2277       // And of course the size has changed so layout is needed
2278       layout();
2279       }
2280     }
2281   }
2282 
2283 
2284 // Scroll rectangle x,y,w,h by a shift of dx,dy
scroll(FXint x,FXint y,FXint w,FXint h,FXint dx,FXint dy) const2285 void FXWindow::scroll(FXint x,FXint y,FXint w,FXint h,FXint dx,FXint dy) const {
2286   if(xid && 0<w && 0<h && (dx || dy)){
2287 #ifdef WIN32
2288     RECT rect;
2289     rect.left=x;
2290     rect.top=y;
2291     rect.right=x+w;
2292     rect.bottom=y+h;
2293     ScrollWindowEx((HWND)xid,dx,dy,&rect,&rect,NULL,NULL,SW_INVALIDATE);
2294 #else
2295 
2296     // No overlap:- repaint the whole thing
2297     if((w<=FXABS(dx)) || (h<=FXABS(dy))){
2298       getApp()->addRepaint(xid,x,y,w,h,true);
2299       }
2300 
2301     // Has overlap, so blit contents and repaint the exposed parts
2302     else{
2303       FXint  tx,ty,fx,fy,ex,ey,ew,eh;
2304       XEvent event;
2305 
2306       // Force server to catch up
2307       XSync((Display*)getApp()->getDisplay(),False);
2308 
2309       // Pull any outstanding repaint events into our own repaint rectangle list
2310       while(XCheckWindowEvent((Display*)getApp()->getDisplay(),xid,ExposureMask,&event)){
2311         if(event.xany.type==NoExpose) continue;
2312         getApp()->addRepaint(xid,event.xexpose.x,event.xexpose.y,event.xexpose.width,event.xexpose.height,false);
2313         if(event.xgraphicsexpose.count==0) break;
2314         }
2315 
2316       // Scroll all repaint rectangles of this window by the dx,dy
2317       getApp()->scrollRepaints(xid,dx,dy);
2318 
2319       // Compute blitted area
2320       if(dx>0){             // Content shifted right
2321         fx=x;
2322         tx=x+dx;
2323         ex=x;
2324         ew=dx;
2325         }
2326       else{                 // Content shifted left
2327         fx=x-dx;
2328         tx=x;
2329         ex=x+w+dx;
2330         ew=-dx;
2331         }
2332       if(dy>0){             // Content shifted down
2333         fy=y;
2334         ty=y+dy;
2335         ey=y;
2336         eh=dy;
2337         }
2338       else{                 // Content shifted up
2339         fy=y-dy;
2340         ty=y;
2341         ey=y+h+dy;
2342         eh=-dy;
2343         }
2344 
2345       // BLIT the contents
2346       XCopyArea((Display*)getApp()->getDisplay(),xid,xid,(GC)visual->scrollgc,fx,fy,w-ew,h-eh,tx,ty);
2347 
2348       // Post additional rectangles for the uncovered areas
2349       if(dy){
2350         getApp()->addRepaint(xid,x,ey,w,eh,true);
2351         }
2352       if(dx){
2353         getApp()->addRepaint(xid,ex,y,ew,h,true);
2354         }
2355       }
2356 #endif
2357     }
2358   }
2359 
2360 
2361 // Check if logically shown
shown() const2362 FXbool FXWindow::shown() const {
2363   return (flags&FLAG_SHOWN)!=0;
2364   }
2365 
2366 
2367 // Show window
show()2368 void FXWindow::show(){
2369   FXTRACE((160,"%s::show %p\n",getClassName(),this));
2370   if(!shown()){
2371     flags|=FLAG_SHOWN;
2372     if(xid){
2373 #ifdef WIN32
2374       ShowWindow((HWND)xid,SW_SHOWNOACTIVATE);
2375 #else
2376       if(0<width && 0<height) XMapWindow((Display*)getApp()->getDisplay(),xid);
2377 #endif
2378       }
2379     }
2380   }
2381 
2382 
2383 // Hide window
hide()2384 void FXWindow::hide(){
2385   FXTRACE((160,"%s::hide %p\n",getClassName(),this));
2386   if(shown()){
2387     killFocus();
2388     flags&=~FLAG_SHOWN;
2389     if(xid){
2390 #ifdef WIN32
2391       if(getApp()->mouseGrabWindow==this){
2392         ReleaseCapture();
2393         SetCursor((HCURSOR)defaultCursor->id());
2394         handle(this,FXSEL(SEL_UNGRABBED,0),&getApp()->event);
2395         getApp()->mouseGrabWindow=NULL;
2396         }
2397       if(getApp()->keyboardGrabWindow==this){
2398         getApp()->keyboardGrabWindow=NULL;
2399         }
2400       ShowWindow((HWND)xid,SW_HIDE);
2401 #else
2402       if(getApp()->mouseGrabWindow==this){
2403         XUngrabPointer((Display*)getApp()->getDisplay(),CurrentTime);
2404         XFlush((Display*)getApp()->getDisplay());
2405         handle(this,FXSEL(SEL_UNGRABBED,0),&getApp()->event);
2406         getApp()->mouseGrabWindow=NULL;
2407         }
2408       if(getApp()->keyboardGrabWindow==this){
2409         XUngrabKeyboard((Display*)getApp()->getDisplay(),getApp()->event.time);
2410         XFlush((Display*)getApp()->getDisplay());
2411         getApp()->keyboardGrabWindow=NULL;
2412         }
2413       XUnmapWindow((Display*)getApp()->getDisplay(),xid);
2414 #endif
2415       }
2416     }
2417   }
2418 
2419 
2420 // Reparent window under a new parent
reparent(FXWindow * father,FXWindow * other)2421 void FXWindow::reparent(FXWindow* father,FXWindow* other){
2422   FXbool hadfocus=inFocusChain();
2423   if(father==NULL){ fxerror("%s::reparent: NULL parent specified.\n",getClassName()); }
2424   if(parent==NULL){ fxerror("%s::reparent: cannot reparent root window.\n",getClassName()); }
2425   if(parent==getRoot() || father==getRoot()){ fxerror("%s::reparent: cannot reparent toplevel window.\n",getClassName()); }
2426   if(other && father!=other->getParent()){ fxerror("%s::reparent: other window has different parent.\n",getClassName()); }
2427   if(this!=other){
2428 
2429     // Check for funny cases
2430     if(containsChild(father)){ fxerror("%s::reparent: new parent is child of window.\n",getClassName()); }
2431 
2432     // Both windows created or both non-created
2433     if(xid && !father->id()){ fxerror("%s::reparent: new parent not created yet.\n",getClassName()); }
2434     if(!xid && father->id()){ fxerror("%s::reparent: window not created yet.\n",getClassName()); }
2435 
2436     // Kill focus chain through this window
2437     if(hadfocus) killFocus();
2438 
2439     // Recalc old path
2440     recalc();
2441 
2442     // Unlink from old parent
2443     if(prev) prev->next=next; else parent->first=next;
2444     if(next) next->prev=prev; else parent->last=prev;
2445 
2446     // Link to new parent
2447     if(other){
2448       next=other;
2449       prev=other->prev;
2450       other->prev=this;
2451       }
2452     else{
2453       next=NULL;
2454       prev=father->last;
2455       father->last=this;
2456       }
2457     if(prev){
2458       prev->next=this;
2459       }
2460     else{
2461       father->first=this;
2462       }
2463 
2464     // Moved between parents
2465     if(parent!=father){
2466 
2467       // New parent and owner
2468       parent=father;
2469       owner=father;
2470 
2471       // Hook up to new window in server too
2472       if(xid && parent->id()){
2473 #ifdef WIN32
2474         SetParent((HWND)xid,(HWND)parent->id());
2475 #else
2476         // See remarks in FXToolBarGrip
2477         XReparentWindow((Display*)getApp()->getDisplay(),xid,parent->id(),0,0);
2478         XFlush((Display*)getApp()->getDisplay());
2479 #endif
2480         }
2481       }
2482 
2483     // Set focus back if we had it
2484     if(hadfocus) setFocus();
2485 
2486     // Recalc new path
2487     recalc();
2488     }
2489   }
2490 
2491 
2492 // Is window enabled
isEnabled() const2493 FXbool FXWindow::isEnabled() const {
2494   return (flags&FLAG_ENABLED)!=0;
2495   }
2496 
2497 
2498 // Enable the window
enable()2499 void FXWindow::enable(){
2500   if(!isEnabled()){
2501     flags|=FLAG_ENABLED;
2502     if(xid){
2503 #ifdef WIN32
2504       EnableWindow((HWND)xid,true);
2505 #else
2506       FXuint events=BASIC_EVENT_MASK|ENABLED_EVENT_MASK;
2507       if(isShell()) events|=SHELL_EVENT_MASK;
2508       XSelectInput((Display*)getApp()->getDisplay(),xid,events);
2509 #endif
2510       }
2511     }
2512   }
2513 
2514 
2515 // Disable the window
disable()2516 void FXWindow::disable(){
2517   killFocus();
2518   if(isEnabled()){
2519     flags&=~FLAG_ENABLED;
2520     if(xid){
2521 #ifdef WIN32
2522       EnableWindow((HWND)xid,false);
2523       if(getApp()->mouseGrabWindow==this){
2524         ReleaseCapture();
2525         SetCursor((HCURSOR)defaultCursor->id());
2526         handle(this,FXSEL(SEL_UNGRABBED,0),&getApp()->event);
2527         getApp()->mouseGrabWindow=NULL;
2528         }
2529       if(getApp()->keyboardGrabWindow==this){
2530         getApp()->keyboardGrabWindow=NULL;
2531         }
2532 #else
2533       FXuint events=BASIC_EVENT_MASK;
2534       if(isShell()) events|=SHELL_EVENT_MASK;
2535       XSelectInput((Display*)getApp()->getDisplay(),xid,events);
2536       if(getApp()->mouseGrabWindow==this){
2537         XUngrabPointer((Display*)getApp()->getDisplay(),CurrentTime);
2538         XFlush((Display*)getApp()->getDisplay());
2539         handle(this,FXSEL(SEL_UNGRABBED,0),&getApp()->event);
2540         getApp()->mouseGrabWindow=NULL;
2541         }
2542       if(getApp()->keyboardGrabWindow==this){
2543         XUngrabKeyboard((Display*)getApp()->getDisplay(),getApp()->event.time);
2544         XFlush((Display*)getApp()->getDisplay());
2545         getApp()->keyboardGrabWindow=NULL;
2546         }
2547 #endif
2548       }
2549     }
2550   }
2551 
2552 
2553 // Raise (but do not activate!)
raise()2554 void FXWindow::raise(){
2555   if(xid){
2556 #ifdef WIN32
2557     SetWindowPos((HWND)xid,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
2558 #else
2559     XRaiseWindow((Display*)getApp()->getDisplay(),xid);
2560 #endif
2561     }
2562   }
2563 
2564 
2565 // Lower
lower()2566 void FXWindow::lower(){
2567   if(xid){
2568 #ifdef WIN32
2569     SetWindowPos((HWND)xid,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
2570 #else
2571     XLowerWindow((Display*)getApp()->getDisplay(),xid);
2572 #endif
2573     }
2574   }
2575 
2576 
2577 // Get coordinates from another window (for symmetry)
translateCoordinatesFrom(FXint & tox,FXint & toy,const FXWindow * fromwindow,FXint fromx,FXint fromy) const2578 void FXWindow::translateCoordinatesFrom(FXint& tox,FXint& toy,const FXWindow* fromwindow,FXint fromx,FXint fromy) const {
2579   if(fromwindow==NULL){ fxerror("%s::translateCoordinatesFrom: from-window is NULL.\n",getClassName()); }
2580   if(xid && fromwindow->id()){
2581 #ifdef WIN32
2582     POINT pt;
2583     pt.x=fromx;
2584     pt.y=fromy;
2585     ClientToScreen((HWND)fromwindow->id(),&pt);
2586     ScreenToClient((HWND)xid,&pt);
2587     tox=pt.x;
2588     toy=pt.y;
2589 #else
2590     Window tmp;
2591     XTranslateCoordinates((Display*)getApp()->getDisplay(),fromwindow->id(),xid,fromx,fromy,&tox,&toy,&tmp);
2592 #endif
2593     }
2594   }
2595 
2596 
2597 // Get coordinates to another window (for symmetry)
translateCoordinatesTo(FXint & tox,FXint & toy,const FXWindow * towindow,FXint fromx,FXint fromy) const2598 void FXWindow::translateCoordinatesTo(FXint& tox,FXint& toy,const FXWindow* towindow,FXint fromx,FXint fromy) const {
2599   if(towindow==NULL){ fxerror("%s::translateCoordinatesTo: to-window is NULL.\n",getClassName()); }
2600   if(xid && towindow->id()){
2601 #ifdef WIN32
2602     POINT pt;
2603     pt.x=fromx;
2604     pt.y=fromy;
2605     ClientToScreen((HWND)xid,&pt);
2606     ScreenToClient((HWND)towindow->id(),&pt);
2607     tox=pt.x;
2608     toy=pt.y;
2609 #else
2610     Window tmp;
2611     XTranslateCoordinates((Display*)getApp()->getDisplay(),xid,towindow->id(),fromx,fromy,&tox,&toy,&tmp);
2612 #endif
2613     }
2614   }
2615 
2616 
2617 /*******************************************************************************/
2618 
2619 
2620 // Return true if active grab is in effect
grabbed() const2621 FXbool FXWindow::grabbed() const {
2622   return getApp()->mouseGrabWindow==this;
2623   }
2624 
2625 
2626 // Acquire grab; also switches to the drag cursor
grab()2627 void FXWindow::grab(){
2628   if(xid){
2629     FXTRACE((150,"%s::grab %p\n",getClassName(),this));
2630     if(dragCursor->id()==0){ fxerror("%s::grab: Cursor has not been created yet.\n",getClassName()); }
2631     if(!shown()){ fxwarning("%s::grab: Window is not visible.\n",getClassName()); }
2632 #ifdef WIN32
2633     SetCapture((HWND)xid);
2634     if(GetCapture()!=(HWND)xid){
2635       SetCapture((HWND)xid);
2636       }
2637     SetCursor((HCURSOR)dragCursor->id());
2638 #else
2639     if(GrabSuccess!=XGrabPointer((Display*)getApp()->getDisplay(),xid,false,GRAB_EVENT_MASK,GrabModeAsync,GrabModeAsync,None,dragCursor->id(),getApp()->event.time)){
2640       XGrabPointer((Display*)getApp()->getDisplay(),xid,false,GRAB_EVENT_MASK,GrabModeAsync,GrabModeAsync,None,dragCursor->id(),CurrentTime);
2641       }
2642 #endif
2643     getApp()->mouseGrabWindow=this;
2644     }
2645   }
2646 
2647 
2648 // Release grab; also switches back to the normal cursor
ungrab()2649 void FXWindow::ungrab(){
2650   if(xid){
2651     FXTRACE((150,"%s::ungrab %p\n",getClassName(),this));
2652     getApp()->mouseGrabWindow=NULL;
2653 #ifdef WIN32
2654     ReleaseCapture();
2655     SetCursor((HCURSOR)defaultCursor->id());
2656 #else
2657     XUngrabPointer((Display*)getApp()->getDisplay(),getApp()->event.time);
2658     XFlush((Display*)getApp()->getDisplay());
2659 #endif
2660     }
2661   }
2662 
2663 
2664 // Return true if active grab is in effect
grabbedKeyboard() const2665 FXbool FXWindow::grabbedKeyboard() const {
2666   return getApp()->keyboardGrabWindow==this;
2667   }
2668 
2669 
2670 // Grab keyboard device; note grabbing keyboard generates
2671 // SEL_FOCUSIN on the grab-window and SEL_FOCUSOUT on the old
2672 // focus-window
grabKeyboard()2673 void FXWindow::grabKeyboard(){
2674   if(xid){
2675     FXTRACE((150,"%s::grabKeyboard %p\n",getClassName(),this));
2676     if(!shown()){ fxwarning("%s::ungrabKeyboard: Window is not visible.\n",getClassName()); }
2677 #ifdef WIN32
2678     SetActiveWindow((HWND)xid); // FIXME Check this
2679 #else
2680     XGrabKeyboard((Display*)getApp()->getDisplay(),xid,false,GrabModeAsync,GrabModeAsync,getApp()->event.time);
2681 #endif
2682     getApp()->keyboardGrabWindow=this;
2683     }
2684   }
2685 
2686 
2687 // Ungrab keyboard device; note ungrabbing keyboard generates
2688 // SEL_FOCUSOUT on the grab-window and SEL_FOCUSIN on the
2689 // current focus-window
ungrabKeyboard()2690 void FXWindow::ungrabKeyboard(){
2691   if(xid){
2692     FXTRACE((150,"%s::ungrabKeyboard %p\n",getClassName(),this));
2693     getApp()->keyboardGrabWindow=NULL;
2694 #ifndef WIN32
2695     XUngrabKeyboard((Display*)getApp()->getDisplay(),getApp()->event.time);
2696 #endif
2697     }
2698   }
2699 
2700 
2701 // The widget lost the grab for some reason [Windows].
2702 // Subclasses should try to clean up the mess...
onUngrabbed(FXObject *,FXSelector,void * ptr)2703 long FXWindow::onUngrabbed(FXObject*,FXSelector,void* ptr){
2704   FXTRACE((150,"%s::onUngrabbed\n",getClassName()));
2705   if(target) target->tryHandle(this,FXSEL(SEL_UNGRABBED,message),ptr);
2706 //#ifdef WIN32
2707 //  SetCursor((HCURSOR)defaultCursor->id());    // FIXME Maybe should be done with WM_SETCURSOR?
2708 //#endif
2709   return 1;
2710   }
2711 
2712 
2713 /*******************************************************************************/
2714 
2715 
2716 // Translate message
tr(const FXchar * text,const FXchar * hint,FXint count) const2717 const FXchar* FXWindow::tr(const FXchar* text,const FXchar* hint,FXint count) const {
2718   FXTranslator *translator=getApp()->getTranslator();
2719   if(translator){
2720     return translator->tr(getClassName(),text,hint,count);
2721     }
2722   return text;
2723   }
2724 
2725 
2726 /*******************************************************************************/
2727 
2728 
2729 // Is window drop enabled
isDropEnabled() const2730 FXbool FXWindow::isDropEnabled() const {
2731   return (flags&FLAG_DROPTARGET)!=0;
2732   }
2733 
2734 
2735 // Enable widget as drop target
dropEnable()2736 void FXWindow::dropEnable(){
2737   flags|=FLAG_DROPTARGET;
2738   }
2739 
2740 
2741 // Disable widget as drop target
dropDisable()2742 void FXWindow::dropDisable(){
2743   flags&=~FLAG_DROPTARGET;
2744   }
2745 
2746 
2747 // Set drag rectangle to block events while inside
setDragRectangle(FXint x,FXint y,FXint w,FXint h,FXbool wantupdates) const2748 void FXWindow::setDragRectangle(FXint x,FXint y,FXint w,FXint h,FXbool wantupdates) const {
2749   if(xid==0){ fxerror("%s::setDragRectangle: window has not yet been created.\n",getClassName()); }
2750 #ifdef WIN32
2751   POINT pt;
2752   pt.x=x;
2753   pt.y=y;
2754   ClientToScreen((HWND)parent->id(),&pt);
2755   getApp()->xdndRect.x=(short)pt.x;
2756   getApp()->xdndRect.y=(short)pt.y;
2757 #else
2758   Window tmp;
2759   int tox,toy;
2760   XTranslateCoordinates((Display*)getApp()->getDisplay(),xid,XDefaultRootWindow((Display*)getApp()->getDisplay()),x,y,&tox,&toy,&tmp);
2761   getApp()->xdndRect.x=tox;
2762   getApp()->xdndRect.y=toy;
2763   getApp()->xdndWantUpdates=wantupdates;
2764 #endif
2765   getApp()->xdndRect.w=w;
2766   getApp()->xdndRect.h=h;
2767   }
2768 
2769 
2770 // Clear drag rectangle
clearDragRectangle() const2771 void FXWindow::clearDragRectangle() const {
2772   if(xid==0){ fxerror("%s::clearDragRectangle: window has not yet been created.\n",getClassName()); }
2773   getApp()->xdndRect.x=0;
2774   getApp()->xdndRect.y=0;
2775   getApp()->xdndRect.w=0;
2776   getApp()->xdndRect.h=0;
2777 #ifndef WIN32
2778   getApp()->xdndWantUpdates=true; // Isn't this bullshit?
2779 #endif
2780   }
2781 
2782 
2783 // Get dropped data; called in response to DND enter or DND drop
getDNDData(FXDNDOrigin origin,FXDragType targettype,FXuchar * & ptr,FXuint & size) const2784 FXbool FXWindow::getDNDData(FXDNDOrigin origin,FXDragType targettype,FXuchar*& ptr,FXuint& size) const {
2785   if(xid==0){ fxerror("%s::getDNDData: window has not yet been created.\n",getClassName()); }
2786   switch(origin){
2787     case FROM_DRAGNDROP:
2788       getApp()->dragdropGetData(this,targettype,ptr,size);
2789       break;
2790     case FROM_CLIPBOARD:
2791       getApp()->clipboardGetData(this,targettype,ptr,size);
2792       break;
2793     case FROM_SELECTION:
2794       getApp()->selectionGetData(this,targettype,ptr,size);
2795       break;
2796     }
2797   return ptr!=NULL;
2798   }
2799 
2800 
2801 // Get dropped string; called in response to DND enter or DND drop
getDNDData(FXDNDOrigin origin,FXDragType targettype,FXString & string) const2802 FXbool FXWindow::getDNDData(FXDNDOrigin origin,FXDragType targettype,FXString& string) const {
2803   FXchar *ptr; FXuint size;
2804   string=FXString::null;
2805   if(getDNDData(origin,targettype,reinterpret_cast<FXuchar*&>(ptr),size)){
2806     if(targettype==utf16Type){                                  // UTF16
2807       FXUTF16LECodec unicode;
2808       string.length(unicode.mb2utflen(ptr,size));
2809       unicode.mb2utf(string.text(),string.length(),ptr,size);
2810       }
2811     else if(targettype==textType || targettype==stringType){    // ASCII
2812       FX88591Codec ascii;
2813       string.length(ascii.mb2utflen(ptr,size));
2814       ascii.mb2utf(string.text(),string.length(),ptr,size);
2815       }
2816     else{                                                       // AS-IS
2817       string.assign(ptr,size);
2818       }
2819     freeElms(ptr);
2820     return true;
2821     }
2822   return false;
2823   }
2824 
2825 
2826 // Set drop data; data array will be deleted by the system automatically!
setDNDData(FXDNDOrigin origin,FXDragType targettype,FXuchar * ptr,FXuint size) const2827 FXbool FXWindow::setDNDData(FXDNDOrigin origin,FXDragType targettype,FXuchar* ptr,FXuint size) const {
2828   if(xid==0){ fxerror("%s::setDNDData: window has not yet been created.\n",getClassName()); }
2829   switch(origin){
2830     case FROM_DRAGNDROP:
2831       getApp()->dragdropSetData(this,targettype,ptr,size);
2832       break;
2833     case FROM_CLIPBOARD:
2834       getApp()->clipboardSetData(this,targettype,ptr,size);
2835       break;
2836     case FROM_SELECTION:
2837       getApp()->selectionSetData(this,targettype,ptr,size);
2838       break;
2839     }
2840   return true;
2841   }
2842 
2843 
2844 // Set drop data; data array will be deleted by the system automatically!
setDNDData(FXDNDOrigin origin,FXDragType targettype,const FXString & string) const2845 FXbool FXWindow::setDNDData(FXDNDOrigin origin,FXDragType targettype,const FXString& string) const {
2846   FXchar* ptr; FXuint size;
2847   if(targettype==utf16Type){                                    // UTF16
2848     FXUTF16LECodec unicode;
2849     size=unicode.utf2mblen(string.text(),string.length());
2850     if(callocElms(ptr,size+2)){
2851       unicode.utf2mb(ptr,size,string.text(),string.length());
2852       return setDNDData(origin,targettype,reinterpret_cast<FXuchar*>(ptr),size);
2853 //      return setDNDData(origin,targettype,reinterpret_cast<FXuchar*>(ptr),size+2);
2854       }
2855     }
2856   else if(targettype==textType || targettype==stringType){      // ASCII
2857     FX88591Codec ascii;
2858     size=ascii.utf2mblen(string.text(),string.length());
2859     if(callocElms(ptr,size+2)){
2860       ascii.utf2mb(ptr,size,string.text(),string.length());
2861       return setDNDData(origin,targettype,reinterpret_cast<FXuchar*>(ptr),size);
2862 //      return setDNDData(origin,targettype,reinterpret_cast<FXuchar*>(ptr),size+1);
2863       }
2864     }
2865   else{                                                         // AS-IS
2866     size=string.length();
2867     if(callocElms(ptr,size+2)){
2868       memcpy(ptr,string.text(),string.length());
2869       return setDNDData(origin,targettype,reinterpret_cast<FXuchar*>(ptr),size);
2870 //      return setDNDData(origin,targettype,reinterpret_cast<FXuchar*>(ptr),size);
2871       }
2872     }
2873   return false;
2874   }
2875 
2876 
2877 // Inquire about types being dragged or available on the clipboard or selection
inquireDNDTypes(FXDNDOrigin origin,FXDragType * & types,FXuint & numtypes) const2878 FXbool FXWindow::inquireDNDTypes(FXDNDOrigin origin,FXDragType*& types,FXuint& numtypes) const {
2879   if(xid==0){ fxerror("%s::inquireDNDTypes: window has not yet been created.\n",getClassName()); }
2880   switch(origin){
2881     case FROM_DRAGNDROP:
2882       getApp()->dragdropGetTypes(this,types,numtypes);
2883       break;
2884     case FROM_CLIPBOARD:
2885       getApp()->clipboardGetTypes(this,types,numtypes);
2886       break;
2887     case FROM_SELECTION:
2888       getApp()->selectionGetTypes(this,types,numtypes);
2889       break;
2890     }
2891   return types!=NULL;
2892   }
2893 
2894 
2895 // Is a certain type being offered via drag and drop, clipboard, or selection?
offeredDNDType(FXDNDOrigin origin,FXDragType type) const2896 FXbool FXWindow::offeredDNDType(FXDNDOrigin origin,FXDragType type) const {
2897   if(xid==0){ fxerror("%s::offeredDNDType: window has not yet been created.\n",getClassName()); }
2898   FXbool offered=false;
2899   FXDragType *types;
2900   FXuint i,ntypes;
2901   if(inquireDNDTypes(origin,types,ntypes)){
2902     for(i=0; i<ntypes; i++){
2903       if(type==types[i]){ offered=true; break; }
2904       }
2905     freeElms(types);
2906     }
2907   return offered;
2908   }
2909 
2910 
2911 // Target accepts or rejects drop, and may suggest different action
acceptDrop(FXDragAction action) const2912 void FXWindow::acceptDrop(FXDragAction action) const {
2913   getApp()->ansAction=DRAG_REJECT;
2914   if(action!=DRAG_REJECT){
2915     getApp()->ansAction=getApp()->ddeAction;
2916     if(action!=DRAG_ACCEPT) getApp()->ansAction=action;
2917     }
2918   }
2919 
2920 
2921 // Sent by the drop target
dropFinished(FXDragAction action) const2922 void FXWindow::dropFinished(FXDragAction action) const {
2923   if(!getApp()->xdndFinishSent){
2924     if(action==DRAG_ACCEPT) action=getApp()->ansAction;
2925 #ifdef WIN32
2926     PostMessage((HWND)getApp()->xdndSource,WM_DND_FINISH_REJECT+action,0,(LPARAM)xid);
2927 #else
2928     XEvent se;
2929     se.xclient.type=ClientMessage;
2930     se.xclient.display=(Display*)getApp()->getDisplay();
2931     se.xclient.message_type=getApp()->xdndFinished;
2932     se.xclient.format=32;
2933     se.xclient.window=getApp()->xdndSource;
2934     se.xclient.data.l[0]=xid;
2935     se.xclient.data.l[1]=(action==DRAG_REJECT)?0:1;
2936     se.xclient.data.l[2]=getApp()->xdndActionList[action];
2937     se.xclient.data.l[3]=0;
2938     se.xclient.data.l[4]=0;
2939     XSendEvent((Display*)getApp()->getDisplay(),getApp()->xdndSource,True,NoEventMask,&se);
2940     XFlush((Display*)getApp()->getDisplay());
2941 #endif
2942     getApp()->xdndFinishSent=true;
2943     }
2944   }
2945 
2946 
2947 // Target wants to know drag action of source
inquireDNDAction() const2948 FXDragAction FXWindow::inquireDNDAction() const {
2949   return getApp()->ddeAction;
2950   }
2951 
2952 
2953 // Source wants to find out if target accepted
didAccept() const2954 FXDragAction FXWindow::didAccept() const {
2955   return getApp()->ansAction;
2956   }
2957 
2958 
2959 // True if we're in a drag operation
isDragging() const2960 FXbool FXWindow::isDragging() const {
2961   return (getApp()->dragWindow==this);
2962   }
2963 
2964 
2965 // True if this window is drop target
isDropTarget() const2966 FXbool FXWindow::isDropTarget() const {
2967   return (getApp()->dropWindow==this);
2968   }
2969 
2970 
2971 // Start a drag on the types mentioned
beginDrag(const FXDragType * types,FXuint numtypes)2972 FXbool FXWindow::beginDrag(const FXDragType *types,FXuint numtypes){
2973   if(xid==0){ fxerror("%s::beginDrag: window has not yet been created.\n",getClassName()); }
2974   if(!isDragging()){
2975     if(types==NULL || numtypes<1){ fxerror("%s::beginDrag: should have at least one type to drag.\n",getClassName()); }
2976 #ifdef WIN32
2977     getApp()->xdndTypes=CreateFileMappingA(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,(numtypes+1)*sizeof(FXDragType),"XdndTypeList");
2978     if(getApp()->xdndTypes){
2979       FXDragType *dragtypes=(FXDragType*)MapViewOfFile(getApp()->xdndTypes,FILE_MAP_WRITE,0,0,0);
2980       if(dragtypes){
2981         dragtypes[0]=numtypes;
2982         memcpy(&dragtypes[1],types,numtypes*sizeof(FXDragType));
2983         UnmapViewOfFile(dragtypes);
2984         }
2985       }
2986     getApp()->xdndTarget=0;
2987     getApp()->ansAction=DRAG_REJECT;
2988     getApp()->xdndStatusPending=false;
2989     getApp()->xdndStatusReceived=false;
2990     getApp()->xdndRect.x=0;
2991     getApp()->xdndRect.y=0;
2992     getApp()->xdndRect.w=0;
2993     getApp()->xdndRect.h=0;
2994 #else
2995     XSetSelectionOwner((Display*)getApp()->getDisplay(),getApp()->xdndSelection,xid,getApp()->event.time);
2996     if(XGetSelectionOwner((Display*)getApp()->getDisplay(),getApp()->xdndSelection)!=xid){
2997       fxwarning("%s::beginDrag: failed to acquire DND selection.\n",getClassName());
2998       return false;
2999       }
3000     resizeElms(getApp()->xdndTypeList,numtypes);
3001     memcpy(getApp()->xdndTypeList,types,sizeof(FXDragType)*numtypes);
3002     getApp()->xdndNumTypes=numtypes;
3003     XChangeProperty((Display*)getApp()->getDisplay(),xid,getApp()->xdndTypes,XA_ATOM,32,PropModeReplace,(unsigned char*)getApp()->xdndTypeList,getApp()->xdndNumTypes);
3004     XChangeProperty((Display*)getApp()->getDisplay(),xid,getApp()->xdndActions,XA_ATOM,32,PropModeReplace,(unsigned char*)getApp()->xdndActionList,6);
3005     getApp()->xdndTarget=0;
3006     getApp()->xdndProxyTarget=0;
3007     getApp()->ansAction=DRAG_REJECT;
3008     getApp()->xdndStatusPending=false;
3009     getApp()->xdndStatusReceived=false;
3010     getApp()->xdndWantUpdates=true;
3011     getApp()->xdndRect.x=0;
3012     getApp()->xdndRect.y=0;
3013     getApp()->xdndRect.w=0;
3014     getApp()->xdndRect.h=0;
3015 #endif
3016     getApp()->dragWindow=this;
3017     return true;
3018     }
3019   return false;
3020   }
3021 
3022 
3023 // Drag to new position
handleDrag(FXint x,FXint y,FXDragAction action)3024 FXbool FXWindow::handleDrag(FXint x,FXint y,FXDragAction action){
3025   if(xid==0){ fxerror("%s::handleDrag: window has not yet been created.\n",getClassName()); }
3026   if(action<DRAG_ASK || DRAG_PRIVATE<action){ fxerror("%s::handleDrag: illegal drag action.\n",getClassName()); }
3027   if(isDragging()){
3028 
3029 #ifdef WIN32            // WINDOWS
3030 
3031     HANDLE version=0;
3032     FXbool forcepos=false;
3033     POINT point;
3034     HWND window;
3035 
3036     // Get drop window
3037     point.x=x;
3038     point.y=y;
3039     window=WindowFromPoint(point);      // FIXME wrong for disabled windows
3040     while(window){
3041 //      version=(FXuint)GetProp(window,(LPCTSTR)MAKELONG(getApp()->xdndAware,0));
3042       version=GetProp(window,(LPCTSTR)MAKELONG(getApp()->xdndAware,0));
3043       if(version) break;
3044       window=GetParent(window);
3045       }
3046 
3047     // Changed windows
3048     if(window!=getApp()->xdndTarget){
3049 
3050       // Moving OUT of XDND aware window?
3051       if(getApp()->xdndTarget!=0){
3052         PostMessage((HWND)getApp()->xdndTarget,WM_DND_LEAVE,0,(LPARAM)xid);
3053         }
3054 
3055       // Reset XDND variables
3056       getApp()->xdndTarget=window;
3057       getApp()->ansAction=DRAG_REJECT;
3058       getApp()->xdndStatusPending=false;
3059       getApp()->xdndStatusReceived=false;
3060       getApp()->xdndRect.x=x;
3061       getApp()->xdndRect.y=y;
3062       getApp()->xdndRect.w=1;
3063       getApp()->xdndRect.h=1;
3064 
3065       // Moving INTO XDND aware window?
3066       if(getApp()->xdndTarget!=0){
3067         PostMessage((HWND)getApp()->xdndTarget,WM_DND_ENTER,0,(LPARAM)xid);
3068         forcepos=true;
3069         }
3070       }
3071 
3072     // Now send a position message
3073     if(getApp()->xdndTarget!=0){
3074 
3075       // Send position if we're outside the mouse box or ignoring it
3076      if(forcepos || x<getApp()->xdndRect.x || y<getApp()->xdndRect.y || getApp()->xdndRect.x+getApp()->xdndRect.w<=x || getApp()->xdndRect.y+getApp()->xdndRect.h<=y){
3077 
3078         // No outstanding status message, so send new pos right away
3079         if(!getApp()->xdndStatusPending){
3080           PostMessage((HWND)getApp()->xdndTarget,WM_DND_POSITION_REJECT+action,MAKELONG(x,y),(LPARAM)xid);
3081           getApp()->xdndStatusPending=true;       // Waiting for the other app to respond
3082           }
3083         }
3084       }
3085 
3086 #else                   // X11
3087 
3088     Window proxywindow,window,child,win,proxywin,root;
3089     unsigned long ni,ba;
3090     unsigned char *ptr1;
3091     unsigned char *ptr2;
3092     unsigned char *ptr3;
3093     Atom    typ;
3094     int     fmt;
3095     Atom    version;
3096     int     dropx;
3097     int     dropy;
3098     XEvent  se;
3099     FXbool    forcepos=false;
3100 
3101     // Find XDND aware window at the indicated location
3102     root=XDefaultRootWindow((Display*)getApp()->getDisplay());
3103     window=0;
3104     proxywindow=0;
3105     version=0;
3106     win=root;
3107     while(1){
3108       if(!XTranslateCoordinates((Display*)getApp()->getDisplay(),root,win,x,y,&dropx,&dropy,&child)) break;
3109       proxywin=win;
3110       if(XGetWindowProperty((Display*)getApp()->getDisplay(),win,getApp()->xdndProxy,0,1,False,AnyPropertyType,&typ,&fmt,&ni,&ba,&ptr1)==Success){
3111         if(typ==XA_WINDOW && fmt==32 && ni>0){
3112           if(XGetWindowProperty((Display*)getApp()->getDisplay(),*((Window*)ptr1),getApp()->xdndProxy,0,1,False,AnyPropertyType,&typ,&fmt,&ni,&ba,&ptr2)==Success){
3113             if(typ==XA_WINDOW && fmt==32 && ni>0 && *((Window*)ptr2) == *((Window*)ptr1)){
3114               proxywin=*((Window*)ptr1);
3115               }
3116             XFree(ptr2);
3117             }
3118           }
3119         XFree(ptr1);
3120         }
3121       if(XGetWindowProperty((Display*)getApp()->getDisplay(),proxywin,getApp()->xdndAware,0,1,False,AnyPropertyType,&typ,&fmt,&ni,&ba,&ptr3)==Success){
3122         if(typ==XA_ATOM && fmt==32 && ni>0 && *((Atom*)ptr3)>=3){
3123           window=win;
3124           proxywindow=proxywin;
3125           version=FXMIN(*((Atom*)ptr3),XDND_PROTOCOL_VERSION);
3126           if(window!=root){XFree(ptr3);break;}
3127           }
3128         XFree(ptr3);
3129         }
3130       if(child==None) break;
3131       win=child;
3132       }
3133 
3134     // Changed windows
3135     if(window!=getApp()->xdndTarget){
3136 
3137       // Moving OUT of XDND aware window?
3138       if(getApp()->xdndTarget!=0){
3139         se.xclient.type=ClientMessage;
3140         se.xclient.display=(Display*)getApp()->getDisplay();
3141         se.xclient.message_type=getApp()->xdndLeave;
3142         se.xclient.format=32;
3143         se.xclient.window=getApp()->xdndTarget;
3144         se.xclient.data.l[0]=xid;
3145         se.xclient.data.l[1]=0;
3146         se.xclient.data.l[2]=0;
3147         se.xclient.data.l[3]=0;
3148         se.xclient.data.l[4]=0;
3149         XSendEvent((Display*)getApp()->getDisplay(),getApp()->xdndProxyTarget,True,NoEventMask,&se);
3150         }
3151 
3152       // Reset XDND variables
3153       getApp()->xdndTarget=window;
3154       getApp()->xdndProxyTarget=proxywindow;
3155       getApp()->ansAction=DRAG_REJECT;
3156       getApp()->xdndStatusPending=false;
3157       getApp()->xdndStatusReceived=false;
3158       getApp()->xdndWantUpdates=true;
3159       getApp()->xdndRect.x=x;
3160       getApp()->xdndRect.y=y;
3161       getApp()->xdndRect.w=1;
3162       getApp()->xdndRect.h=1;
3163 
3164       // Moving INTO XDND aware window?
3165       if(getApp()->xdndTarget!=0){
3166         se.xclient.type=ClientMessage;
3167         se.xclient.display=(Display*)getApp()->getDisplay();
3168         se.xclient.message_type=getApp()->xdndEnter;
3169         se.xclient.format=32;
3170         se.xclient.window=getApp()->xdndTarget;
3171         se.xclient.data.l[0]=xid;
3172         se.xclient.data.l[1]=version<<24;
3173         se.xclient.data.l[2]=getApp()->xdndNumTypes>=1 ? getApp()->xdndTypeList[0] : None;
3174         se.xclient.data.l[3]=getApp()->xdndNumTypes>=2 ? getApp()->xdndTypeList[1] : None;
3175         se.xclient.data.l[4]=getApp()->xdndNumTypes>=3 ? getApp()->xdndTypeList[2] : None;
3176         if(getApp()->xdndNumTypes>3) se.xclient.data.l[1]|=1;
3177         XSendEvent((Display*)getApp()->getDisplay(),getApp()->xdndProxyTarget,True,NoEventMask,&se);
3178         forcepos=true;
3179         }
3180       }
3181 
3182     // Now send a position message
3183     if(getApp()->xdndTarget!=0){
3184 
3185       // Send position if we're outside the mouse box or ignoring it
3186       if(forcepos || getApp()->xdndRect.w==0 || getApp()->xdndRect.h==0 || getApp()->xdndWantUpdates || x<getApp()->xdndRect.x || y<getApp()->xdndRect.y || getApp()->xdndRect.x+getApp()->xdndRect.w<=x || getApp()->xdndRect.y+getApp()->xdndRect.h<=y){
3187 
3188         // No outstanding status message, so send new pos right away
3189         if(!getApp()->xdndStatusPending){
3190           se.xclient.type=ClientMessage;
3191           se.xclient.display=(Display*)getApp()->getDisplay();
3192           se.xclient.message_type=getApp()->xdndPosition;
3193           se.xclient.format=32;
3194           se.xclient.window=getApp()->xdndTarget;
3195           se.xclient.data.l[0]=xid;
3196           se.xclient.data.l[1]=0;
3197           se.xclient.data.l[2]=MKUINT(y,x);                               // Coordinates
3198           se.xclient.data.l[3]=getApp()->event.time;                      // Time stamp
3199           se.xclient.data.l[4]=getApp()->xdndActionList[action];
3200           XSendEvent((Display*)getApp()->getDisplay(),getApp()->xdndProxyTarget,True,NoEventMask,&se);
3201           getApp()->xdndStatusPending=true;       // Waiting for the other app to respond
3202           }
3203         }
3204       }
3205 
3206 #endif
3207 
3208     return true;
3209     }
3210   return false;
3211   }
3212 
3213 
3214 #ifndef WIN32
3215 
3216 struct XDNDMatch {
3217   Atom xdndStatus;
3218   Atom xdndPosition;
3219   Atom xdndFinished;
3220   Atom xdndDrop;
3221   Atom xdndEnter;
3222   Atom xdndLeave;
3223   };
3224 
3225 
3226 // Scan event queue for XDND messages or selection requests
matchxdnd(Display *,XEvent * event,XPointer ptr)3227 static Bool matchxdnd(Display*,XEvent* event,XPointer ptr){
3228   XDNDMatch *m=(XDNDMatch*)ptr;
3229   return event->type==SelectionRequest || (event->type==ClientMessage && (event->xclient.message_type==m->xdndStatus || event->xclient.message_type==m->xdndPosition || event->xclient.message_type==m->xdndFinished || event->xclient.message_type==m->xdndDrop || event->xclient.message_type==m->xdndEnter || event->xclient.message_type==m->xdndLeave));
3230   }
3231 
3232 #endif
3233 
3234 
3235 // Terminate the drag; if drop flag is false, don't drop even if accepted.
endDrag(FXbool drop)3236 FXDragAction FXWindow::endDrag(FXbool drop){
3237   FXDragAction action=DRAG_REJECT;
3238   if(xid==0){ fxerror("%s::endDrag: window has not yet been created.\n",getClassName()); }
3239   if(isDragging()){
3240 
3241 #if defined(WIN32)      // WINDOWS
3242 
3243     FXbool nodrop=true;
3244     FXuint loops;
3245     MSG msg;
3246 
3247     // Ever received a status
3248     if(getApp()->xdndStatusReceived && drop){
3249 
3250       // If a status message is still pending, wait for it
3251       if(getApp()->xdndStatusPending){
3252         loops=1000;
3253         do{
3254           FXTRACE((100,"Waiting for XdndStatus\n"));
3255           if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
3256             getApp()->dispatchEvent(msg);
3257 
3258             // We got the status update, finally
3259             if(WM_DND_STATUS_REJECT<=msg.message && msg.message<=WM_DND_STATUS_PRIVATE){
3260               FXTRACE((100,"Got XdndStatus\n"));
3261               getApp()->xdndStatusPending=false;
3262               break;
3263               }
3264 
3265             // We got a selection request message, so there is still hope that
3266             // the target is functioning; lets give it a bit more time...
3267             if(msg.message==WM_DND_REQUEST){
3268               FXTRACE((100,"Got SelectionRequest\n"));
3269               loops=1000;
3270               }
3271             }
3272           FXThread::sleep(10000000);
3273           }
3274         while(--loops);
3275         FXTRACE((100,"Waiting for pending XdndStatus\n"));
3276         getApp()->xdndStatusPending=false;
3277         }
3278 
3279       // Got our status message
3280       if(!getApp()->xdndStatusPending && getApp()->ansAction!=DRAG_REJECT){
3281 
3282         FXTRACE((100,"Sending XdndDrop\n"));
3283         PostMessage((HWND)getApp()->xdndTarget,WM_DND_DROP,0,(LPARAM)xid);
3284 
3285         // Wait until the target has processed the drop; since the
3286         // target may be us, we keep processing all XDND related messages
3287         // while we're waiting here.  After some time, we assume the target
3288         // may have core dumped and we fall out of the loop.....
3289         loops=1000;
3290         do{
3291           FXTRACE((100,"Waiting for XdndFinish\n"));
3292           if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
3293             getApp()->dispatchEvent(msg);
3294 
3295             // Got the finish message; we now know which action was taken
3296             if(WM_DND_FINISH_REJECT<=msg.message && msg.message<=WM_DND_FINISH_PRIVATE){
3297               action=(FXDragAction)(msg.message-WM_DND_FINISH_REJECT);
3298               FXTRACE((100,"Got XdndFinish action=%d\n",action));
3299               break;
3300               }
3301 
3302             // We got a selection request message, so there is still hope that
3303             // the target is functioning; lets give it a bit more time...
3304             if(msg.message==WM_DND_REQUEST){
3305               FXTRACE((100,"Got SelectionRequest\n"));
3306               loops=1000;
3307               }
3308             }
3309           FXThread::sleep(10000000);
3310           }
3311         while(--loops);
3312 
3313         // We tried a drop
3314         nodrop=false;
3315         }
3316       }
3317 
3318     // Didn't drop, or didn't get any response, so just send a leave
3319     if(nodrop){
3320       FXTRACE((100,"Sending XdndLeave\n"));
3321       PostMessage((HWND)getApp()->xdndTarget,WM_DND_LEAVE,0,(LPARAM)xid);
3322       }
3323 
3324 
3325     // Get rid of the shared memory block containing the types list
3326     if(getApp()->xdndTypes) CloseHandle(getApp()->xdndTypes);
3327     getApp()->xdndTypes=NULL;
3328 
3329     // Clean up
3330     getApp()->xdndTarget=0;
3331     getApp()->ansAction=DRAG_REJECT;
3332     getApp()->xdndStatusPending=false;
3333     getApp()->xdndStatusReceived=false;
3334     getApp()->xdndRect.x=0;
3335     getApp()->xdndRect.y=0;
3336     getApp()->xdndRect.w=0;
3337     getApp()->xdndRect.h=0;
3338     getApp()->dragWindow=NULL;
3339 
3340 #else                   // X11
3341 
3342     FXbool nodrop=true;
3343     XEvent se;
3344     FXuint loops;
3345     XDNDMatch match;
3346 
3347     // Fill up match struct
3348     match.xdndStatus=getApp()->xdndStatus;
3349     match.xdndPosition=getApp()->xdndPosition;
3350     match.xdndFinished=getApp()->xdndFinished;
3351     match.xdndDrop=getApp()->xdndDrop;
3352     match.xdndEnter=getApp()->xdndEnter;
3353     match.xdndLeave=getApp()->xdndLeave;
3354 
3355     // Ever received a status
3356     if(getApp()->xdndStatusReceived && drop){
3357 
3358       // If a status message is still pending, wait for it
3359       if(getApp()->xdndStatusPending){
3360         loops=1000;
3361         do{
3362           FXTRACE((100,"Waiting for pending XdndStatus\n"));
3363           if(XCheckIfEvent((Display*)getApp()->getDisplay(),&se,matchxdnd,(char*)&match)){
3364             getApp()->dispatchEvent(se);
3365 
3366             // We got the status update, finally
3367             if(se.xclient.type==ClientMessage && se.xclient.message_type==getApp()->xdndStatus){
3368               FXTRACE((100,"Got XdndStatus\n"));
3369               getApp()->xdndStatusPending=false;
3370               break;
3371               }
3372 
3373             // We got a selection request message, so there is still hope that
3374             // the target is functioning; lets give it a bit more time...
3375             if(se.xselection.type==SelectionRequest && se.xselectionrequest.selection==getApp()->xdndSelection){
3376               FXTRACE((100,"Got SelectionRequest\n"));
3377               loops=1000;
3378               }
3379             }
3380           FXThread::sleep(10000000);
3381           }
3382         while(--loops);
3383         }
3384 
3385       // Got our status message
3386       if(!getApp()->xdndStatusPending && getApp()->ansAction!=DRAG_REJECT){
3387 
3388         FXTRACE((100,"Sending XdndDrop\n"));
3389         se.xclient.type=ClientMessage;
3390         se.xclient.display=(Display*)getApp()->getDisplay();
3391         se.xclient.message_type=getApp()->xdndDrop;
3392         se.xclient.format=32;
3393         se.xclient.window=getApp()->xdndTarget;
3394         se.xclient.data.l[0]=xid;
3395         se.xclient.data.l[1]=0;
3396         se.xclient.data.l[2]=getApp()->event.time;
3397         se.xclient.data.l[3]=0;
3398         se.xclient.data.l[4]=0;
3399         XSendEvent((Display*)getApp()->getDisplay(),getApp()->xdndProxyTarget,True,NoEventMask,&se);
3400 
3401         // Wait until the target has processed the drop; since the
3402         // target may be us, we keep processing all XDND related messages
3403         // while we're waiting here.  After some time, we assume the target
3404         // may have core dumped and we fall out of the loop.....
3405         loops=1000;
3406         do{
3407           FXTRACE((100,"Waiting for XdndFinish\n"));
3408           if(XCheckIfEvent((Display*)getApp()->getDisplay(),&se,matchxdnd,(char*)&match)){
3409             getApp()->dispatchEvent(se);
3410 
3411             // Got the finish message; we now know the drop has been completed and processed
3412             if(se.xclient.type==ClientMessage && se.xclient.message_type==getApp()->xdndFinished){
3413               if(se.xclient.data.l[1]&1){
3414                 action=DRAG_ACCEPT;
3415                 if((FXID)se.xclient.data.l[2]==getApp()->xdndActionList[DRAG_ASK]) action=DRAG_ASK;
3416                 else if((FXID)se.xclient.data.l[2]==getApp()->xdndActionList[DRAG_MOVE]) action=DRAG_MOVE;
3417                 else if((FXID)se.xclient.data.l[2]==getApp()->xdndActionList[DRAG_COPY]) action=DRAG_COPY;
3418                 else if((FXID)se.xclient.data.l[2]==getApp()->xdndActionList[DRAG_LINK]) action=DRAG_LINK;
3419                 else if((FXID)se.xclient.data.l[2]==getApp()->xdndActionList[DRAG_PRIVATE]) action=DRAG_PRIVATE;
3420                 }
3421               FXTRACE((100,"Got XdndFinish action=%u\n",action));
3422               break;
3423               }
3424 
3425             // We got a selection request message, so there is still hope that
3426             // the target is functioning; lets give it a bit more time...
3427             if(se.xselection.type==SelectionRequest && se.xselectionrequest.selection==getApp()->xdndSelection){
3428               FXTRACE((100,"Got SelectionRequest\n"));
3429               loops=1000;
3430               }
3431             }
3432           FXThread::sleep(10000000);
3433           }
3434         while(--loops);
3435 
3436         // We tried a drop but failed
3437         nodrop=false;
3438         }
3439       }
3440 
3441     // Didn't drop, or didn't get any response, so just send a leave
3442     if(nodrop){
3443       FXTRACE((100,"Sending XdndLeave\n"));
3444       se.xclient.type=ClientMessage;
3445       se.xclient.display=(Display*)getApp()->getDisplay();
3446       se.xclient.message_type=getApp()->xdndLeave;
3447       se.xclient.format=32;
3448       se.xclient.window=getApp()->xdndTarget;
3449       se.xclient.data.l[0]=xid;
3450       se.xclient.data.l[1]=0;
3451       se.xclient.data.l[2]=0;
3452       se.xclient.data.l[3]=0;
3453       se.xclient.data.l[4]=0;
3454       XSendEvent((Display*)getApp()->getDisplay(),getApp()->xdndProxyTarget,True,NoEventMask,&se);
3455       }
3456 
3457     // Clean up
3458     XSetSelectionOwner((Display*)getApp()->getDisplay(),getApp()->xdndSelection,None,getApp()->event.time);
3459     XDeleteProperty((Display*)getApp()->getDisplay(),xid,getApp()->xdndTypes);
3460     XDeleteProperty((Display*)getApp()->getDisplay(),xid,getApp()->xdndActions);
3461     freeElms(getApp()->xdndTypeList);
3462     getApp()->xdndNumTypes=0;
3463     getApp()->xdndTarget=0;
3464     getApp()->xdndProxyTarget=0;
3465     getApp()->ansAction=DRAG_REJECT;
3466     getApp()->xdndStatusPending=false;
3467     getApp()->xdndStatusReceived=false;
3468     getApp()->xdndWantUpdates=true;
3469     getApp()->xdndRect.x=0;
3470     getApp()->xdndRect.y=0;
3471     getApp()->xdndRect.w=0;
3472     getApp()->xdndRect.h=0;
3473     getApp()->dragWindow=NULL;
3474 #endif
3475     }
3476   return action;
3477   }
3478 
3479 
3480 /*******************************************************************************/
3481 
3482 
3483 // Delete window
~FXWindow()3484 FXWindow::~FXWindow(){
3485   FXTRACE((100,"FXWindow::~FXWindow %p\n",this));
3486   getApp()->windowCount--;
3487   destroy();
3488   delete accelTable;
3489   delete composeContext;
3490   if(prev) prev->next=next; else if(parent) parent->first=next;
3491   if(next) next->prev=prev; else if(parent) parent->last=prev;
3492   if(parent && parent->focus==this) parent->changeFocus(NULL);
3493   if(getApp()->activeWindow==this) getApp()->activeWindow=NULL;
3494   if(getApp()->cursorWindow==this) getApp()->cursorWindow=parent;
3495   if(getApp()->mouseGrabWindow==this) getApp()->mouseGrabWindow=NULL;
3496   if(getApp()->keyboardGrabWindow==this) getApp()->keyboardGrabWindow=NULL;
3497   if(getApp()->keyWindow==this) getApp()->keyWindow=NULL;
3498   if(getApp()->selectionWindow==this) getApp()->selectionWindow=NULL;
3499   if(getApp()->clipboardWindow==this) getApp()->clipboardWindow=NULL;
3500   if(getApp()->dragWindow==this) getApp()->dragWindow=NULL;
3501   if(getApp()->dropWindow==this) getApp()->dropWindow=NULL;
3502   if(getApp()->refresherstop==this) getApp()->refresherstop=parent;
3503   if(getApp()->refresher==this) getApp()->refresher=parent;
3504   if(parent) parent->recalc();
3505   parent=(FXWindow*)-1L;
3506   owner=(FXWindow*)-1L;
3507   first=last=(FXWindow*)-1L;
3508   next=prev=(FXWindow*)-1L;
3509   focus=(FXWindow*)-1L;
3510   composeContext=(FXComposeContext*)-1L;
3511   defaultCursor=(FXCursor*)-1L;
3512   dragCursor=(FXCursor*)-1L;
3513   accelTable=(FXAccelTable*)-1L;
3514   target=(FXObject*)-1L;
3515   }
3516 
3517 }
3518