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