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