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