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