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