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