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