1 /********************************************************************************
2 *                                                                               *
3 *                         T o p   W i n d o w   O b j e c t                     *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1998,2005 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: FXTopWindow.cpp,v 1.149.2.5 2005/10/25 12:34:28 fox Exp $                    *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxpriv.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXRegistry.h"
36 #include "FXAccelTable.h"
37 #include "FXApp.h"
38 #include "FXDCWindow.h"
39 #include "FXCursor.h"
40 #include "FXIcon.h"
41 #include "FXTopWindow.h"
42 #include "FXMainWindow.h"
43 #include "FXToolBar.h"
44 #include "FXToolBarGrip.h"
45 
46 /*
47   Notes:
48   - Handle zero width/height case similar to FXWindow.
49   - Pass Size Hints to Window Manager as per ICCCM.
50   - Add padding options, as this is convenient for FXDialogBox subclasses;
51     for FXTopWindow/FXMainWindow, padding should default to 0, for FXDialogBox,
52     default to something easthetically pleasing...
53   - Now observes LAYOUT_FIX_X and LAYOUT_FIX_Y hints.
54   - LAYOUT_FIX_WIDTH and LAYOUT_FIX_HEIGHT take precedence over PACK_UNIFORM_WIDTH and
55     PACK_UNIFORM_HEIGHT!
56 */
57 
58 // Definitions for Motif-style WM Hints.
59 #ifndef WIN32
60 #define MWM_HINTS_FUNCTIONS	(1L << 0)       // Definitions for FXMotifHints.flags
61 #define MWM_HINTS_DECORATIONS	(1L << 1)
62 #define MWM_HINTS_INPUT_MODE	(1L << 2)
63 #define MWM_HINTS_ALL           (MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS|MWM_HINTS_INPUT_MODE)
64 
65 #define MWM_FUNC_ALL		(1L << 0)       // Definitions for FXMotifHints.functions
66 #define MWM_FUNC_RESIZE		(1L << 1)
67 #define MWM_FUNC_MOVE		(1L << 2)
68 #define MWM_FUNC_MINIMIZE	(1L << 3)
69 #define MWM_FUNC_MAXIMIZE	(1L << 4)
70 #define MWM_FUNC_CLOSE		(1L << 5)
71 
72 #define MWM_DECOR_ALL		(1L << 0)       // Definitions for FXMotifHints.decorations
73 #define MWM_DECOR_BORDER	(1L << 1)
74 #define MWM_DECOR_RESIZEH	(1L << 2)
75 #define MWM_DECOR_TITLE		(1L << 3)
76 #define MWM_DECOR_MENU		(1L << 4)
77 #define MWM_DECOR_MINIMIZE	(1L << 5)
78 #define MWM_DECOR_MAXIMIZE	(1L << 6)
79 
80 #define MWM_INPUT_MODELESS		    0   // Values for FXMotifHints.inputmode
81 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
82 #define MWM_INPUT_SYSTEM_MODAL		    2
83 #define MWM_INPUT_FULL_APPLICATION_MODAL    3
84 #endif
85 
86 
87 // Side layout modes
88 #define LAYOUT_SIDE_MASK (LAYOUT_SIDE_LEFT|LAYOUT_SIDE_RIGHT|LAYOUT_SIDE_TOP|LAYOUT_SIDE_BOTTOM)
89 
90 // Layout modes
91 #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)
92 
93 #define DISPLAY(app) ((Display*)((app)->display))
94 
95 using namespace FX;
96 
97 
98 /*******************************************************************************/
99 
100 namespace FX {
101 
102 // Map
103 FXDEFMAP(FXTopWindow) FXTopWindowMap[]={
104   FXMAPFUNC(SEL_CLOSE,0,FXTopWindow::onCmdClose),
105   FXMAPFUNC(SEL_FOCUS_UP,0,FXTopWindow::onFocusUp),
106   FXMAPFUNC(SEL_FOCUS_DOWN,0,FXTopWindow::onFocusDown),
107   FXMAPFUNC(SEL_FOCUS_LEFT,0,FXTopWindow::onFocusLeft),
108   FXMAPFUNC(SEL_FOCUS_RIGHT,0,FXTopWindow::onFocusRight),
109   FXMAPFUNC(SEL_CHORE,FXTopWindow::ID_CLOSE,FXTopWindow::onCmdClose),
110   FXMAPFUNC(SEL_SIGNAL,FXTopWindow::ID_CLOSE,FXTopWindow::onCmdClose),
111   FXMAPFUNC(SEL_TIMEOUT,FXTopWindow::ID_CLOSE,FXTopWindow::onCmdClose),
112   FXMAPFUNC(SEL_COMMAND,FXTopWindow::ID_CLOSE,FXTopWindow::onCmdClose),
113   FXMAPFUNC(SEL_COMMAND,FXTopWindow::ID_MAXIMIZE,FXTopWindow::onCmdMaximize),
114   FXMAPFUNC(SEL_COMMAND,FXTopWindow::ID_MINIMIZE,FXTopWindow::onCmdMinimize),
115   FXMAPFUNC(SEL_COMMAND,FXTopWindow::ID_RESTORE,FXTopWindow::onCmdRestore),
116   FXMAPFUNC(SEL_COMMAND,FXTopWindow::ID_SETSTRINGVALUE,FXTopWindow::onCmdSetStringValue),
117   FXMAPFUNC(SEL_COMMAND,FXTopWindow::ID_GETSTRINGVALUE,FXTopWindow::onCmdGetStringValue),
118   FXMAPFUNC(SEL_COMMAND,FXTopWindow::ID_SETICONVALUE,FXTopWindow::onCmdSetIconValue),
119   FXMAPFUNC(SEL_COMMAND,FXTopWindow::ID_GETICONVALUE,FXTopWindow::onCmdGetIconValue),
120   };
121 
122 
123 // Object implementation
FXIMPLEMENT_ABSTRACT(FXTopWindow,FXShell,FXTopWindowMap,ARRAYNUMBER (FXTopWindowMap))124 FXIMPLEMENT_ABSTRACT(FXTopWindow,FXShell,FXTopWindowMap,ARRAYNUMBER(FXTopWindowMap))
125 
126 
127 // Create toplevel window object & add to toplevel window list
128 FXTopWindow::FXTopWindow(FXApp* ap,const FXString& name,FXIcon *ic,FXIcon *mi,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs):
129   FXShell(ap,opts,x,y,w,h){
130   title=name;
131   icon=ic;
132   miniIcon=mi;
133   accelTable=new FXAccelTable;
134   padtop=pt;
135   padbottom=pb;
136   padleft=pl;
137   padright=pr;
138   hspacing=hs;
139   vspacing=vs;
140   }
141 
142 
143 // Create toplevel window object & add to toplevel window list
FXTopWindow(FXWindow * ow,const FXString & name,FXIcon * ic,FXIcon * mi,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs)144 FXTopWindow::FXTopWindow(FXWindow* ow,const FXString& name,FXIcon *ic,FXIcon *mi,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs):
145   FXShell(ow,opts,x,y,w,h){
146   title=name;
147   icon=ic;
148   miniIcon=mi;
149   accelTable=new FXAccelTable;
150   padtop=pt;
151   padbottom=pb;
152   padleft=pl;
153   padright=pr;
154   hspacing=hs;
155   vspacing=vs;
156   }
157 
158 
159 #ifdef WIN32
GetClass() const160 const char* FXTopWindow::GetClass() const { return "FXTopWindow"; }
161 #endif
162 
163 
164 // Create window
create()165 void FXTopWindow::create(){
166   FXShell::create();
167 
168   // Create icons
169   if(icon) icon->create();
170   if(miniIcon) miniIcon->create();
171 
172   if(xid){
173     if(getApp()->isInitialized()){
174 
175 #ifndef WIN32
176       // Catch delete window
177       Atom protocols[2];
178       protocols[0]=getApp()->wmDeleteWindow;
179       protocols[1]=getApp()->wmTakeFocus;
180       XSetWMProtocols(DISPLAY(getApp()),xid,protocols,2);
181 
182       // Set position for Window Manager
183       XSizeHints size;
184 
185       size.flags=USSize|PSize|PWinGravity;      // Let Window Manager place it
186       size.x=0;
187       size.y=0;
188       //if(xpos!=0 || ypos!=0){                   // Force explicit position
189         size.flags|=USPosition|PPosition;
190       //  }
191         size.x=xpos;
192         size.y=ypos;
193       size.min_width=0;
194       size.min_height=0;
195       size.base_width=0;
196       size.base_height=0;
197       if(!(options&DECOR_SHRINKABLE)){          // Can not shrink, so set min size
198         size.flags|=PMinSize|PBaseSize;
199         size.min_width=getDefaultWidth();
200         size.min_height=getDefaultHeight();
201         size.base_width=width;
202         size.base_height=height;
203         }
204       size.max_width=0;
205       size.max_height=0;
206       if(!(options&DECOR_STRETCHABLE)){         // Can not grow, so set max size
207         size.flags|=PMaxSize;
208         size.max_width=getDefaultWidth();
209         size.max_height=getDefaultHeight();
210         }
211       size.width=width;
212       size.height=height;
213       size.width_inc=0;
214       size.height_inc=0;
215       size.min_aspect.x=0;
216       size.min_aspect.y=0;
217       size.max_aspect.x=0;
218       size.max_aspect.y=0;
219       size.win_gravity=NorthWestGravity;        // Tim Alexeevsky <realtim@mail.ru>
220       size.win_gravity=StaticGravity;           // Account for border (ICCCM)
221 
222       // Set hints
223       XSetWMNormalHints(DISPLAY(getApp()),xid,&size);
224 
225 #endif
226 
227       // Set title
228       settitle();
229 
230       // Set decorations
231       setdecorations();
232 
233       // Set icon for X-Windows
234       seticons();
235 
236       // Tweak needed because the options affect window size
237 #ifdef WIN32
238       RECT rect;
239       SetRect(&rect,xpos,ypos,xpos+width,ypos+height);
240       DWORD dwStyle=GetWindowLong((HWND)xid,GWL_STYLE);
241       DWORD dwExStyle=GetWindowLong((HWND)xid,GWL_EXSTYLE);
242       AdjustWindowRectEx(&rect,dwStyle,FALSE,dwExStyle);
243       SetWindowPos((HWND)xid,NULL,rect.left,rect.top,FXMAX(rect.right-rect.left,1),FXMAX(rect.bottom-rect.top,1),SWP_NOZORDER|SWP_NOOWNERZORDER);
244 #endif
245       }
246     }
247   }
248 
249 
250 // Detach window
detach()251 void FXTopWindow::detach(){
252   FXShell::detach();
253   if(icon) icon->detach();
254   if(miniIcon) miniIcon->detach();
255   }
256 
257 
258 // Focus to this toplevel window
setFocus()259 void FXTopWindow::setFocus(){
260   FXShell::setFocus();
261   if(xid){
262 #ifndef WIN32
263     XSetInputFocus(DISPLAY(getApp()),xid,RevertToPointerRoot,CurrentTime);
264 #else
265     SetActiveWindow((HWND)xid);
266     //SetFocus((HWND)xid);
267 #endif
268     }
269   }
270 
271 
272 // Focus away from this toplevel window
killFocus()273 void FXTopWindow::killFocus(){
274   FXShell::killFocus();
275   if(xid){
276 #ifndef WIN32
277     Window win;
278     int    dum;
279     XGetInputFocus(DISPLAY(getApp()),&win,&dum);
280     if(win==xid){
281       if(getOwner() && getOwner()->id()){
282         FXTRACE((100,"focus back to owner\n"));
283         XSetInputFocus(DISPLAY(getApp()),getOwner()->id(),RevertToPointerRoot,CurrentTime);
284         }
285       else{
286         FXTRACE((100,"focus back to NULL\n"));
287         XSetInputFocus(DISPLAY(getApp()),PointerRoot,RevertToPointerRoot,CurrentTime);
288         }
289       }
290 #else
291 /*
292     if(GetFocus()==(HWND)xid){
293       if(getOwner() && getOwner()->id()){
294         FXTRACE((100,"focus back to owner\n"));
295         SetFocus((HWND)getOwner()->id());
296         }
297       else{
298         FXTRACE((100,"focus back to NULL\n"));
299         SetFocus((HWND)NULL);
300         }
301       }
302 */
303     if(GetActiveWindow()==(HWND)xid){
304       if(getOwner() && getOwner()->id()){
305         FXTRACE((100,"focus back to owner\n"));
306         SetActiveWindow((HWND)getOwner()->id());
307         }
308       }
309 #endif
310     }
311   }
312 
313 
314 // Show and raise window
show()315 void FXTopWindow::show(){
316   FXShell::show();
317   raise();
318   }
319 
320 
321 
322 // Show and raise window, placed properly on the screen
show(FXuint placement)323 void FXTopWindow::show(FXuint placement){
324   place(placement);
325   FXShell::show();
326   raise();
327   }
328 
329 
330 
331 // Hide window
hide()332 void FXTopWindow::hide(){
333   if(flags&FLAG_SHOWN){
334     killFocus();
335     flags&=~FLAG_SHOWN;
336     if(xid){
337 #ifndef WIN32
338       XWithdrawWindow(DISPLAY(getApp()),xid,DefaultScreen(DISPLAY(getApp())));
339 #else
340       ShowWindow((HWND)xid,SW_HIDE);
341 #endif
342       }
343     }
344   }
345 
346 
347 // Raise and make foreground window
raise()348 void FXTopWindow::raise(){
349   FXShell::raise();
350   if(xid){
351 #ifdef WIN32
352     SetForegroundWindow((HWND)xid);
353 #endif
354     }
355   }
356 
357 
358 // Position the window based on placement
place(FXuint placement)359 void FXTopWindow::place(FXuint placement){
360   FXint rx,ry,rw,rh,ox,oy,ow,oh,wx,wy,ww,wh,x,y;
361   FXuint state;
362   FXWindow *over;
363 
364   // Default placement:- leave it where it was
365   wx=getX();
366   wy=getY();
367   ww=getWidth();
368   wh=getHeight();
369 
370   // Get root window size
371 #ifndef WIN32
372   rx=getRoot()->getX();
373   ry=getRoot()->getY();
374   rw=getRoot()->getWidth();
375   rh=getRoot()->getHeight();
376 #else
377   RECT rect;
378 //OSVERSIONINFO vinfo;
379 //memset(&vinfo,0,sizeof(vinfo));
380 //vinfo.dwOSVersionInfoSize=sizeof(vinfo);
381 //GetVersionEx(&vinfo);
382 #if (WINVER >= 0x500) || ((defined _WIN32_WINDOWS) && (_WIN32_WINDOWS >= 0x410))
383   HINSTANCE user32;
384   typedef BOOL (WINAPI* PFN_GETMONITORINFOA)(HMONITOR, LPMONITORINFO);
385   typedef HMONITOR (WINAPI* PFN_MONITORFROMRECTA)(LPRECT, DWORD);
386   PFN_GETMONITORINFOA GetMonitorInfoA;
387   PFN_MONITORFROMRECTA MonitorFromRectA;
388 
389   // Suggested by "Daniel Gehriger" <gehriger@linkcad.com>
390   // The API does not exist on older Windows NT and 95, so
391   // We can't even link it, let alone call it.
392   // The solution is to ask the DLL if the function exists.
393   // And another patch from Lothar Scholtz; now it works!
394   if((user32=LoadLibrary("User32")) && (GetMonitorInfoA=reinterpret_cast<PFN_GETMONITORINFOA>(GetProcAddress(user32,"GetMonitorInfoA"))) && (MonitorFromRectA=reinterpret_cast<PFN_MONITORFROMRECTA>(GetProcAddress(user32,"MonitorFromRect")))){
395     MONITORINFOEX minfo;
396     HMONITOR hMon;
397     if(placement == PLACEMENT_CURSOR){
398       // Use mouse position to select screen.
399       getRoot()->getCursorPosition(x,y,state);
400       rect.left=x;
401       rect.right=x+1;
402       rect.top=y;
403       rect.bottom=y+1;
404       }
405     else{
406       // Use owner to select screen.
407       over=getOwner()?getOwner():getRoot();
408       over->translateCoordinatesTo(ox,oy,getRoot(),0,0);
409       ow=over->getWidth();
410       oh=over->getHeight();
411       rect.left=ox;
412       rect.right=ox+ow;
413       rect.top=oy;
414       rect.bottom=oy+oh;
415       }
416     hMon=MonitorFromRectA(&rect,MONITOR_DEFAULTTOPRIMARY);
417     memset(&minfo,0,sizeof(minfo));
418     minfo.cbSize=sizeof(minfo);
419     GetMonitorInfoA(hMon,&minfo);
420     rx=minfo.rcWork.left;
421     ry=minfo.rcWork.top;
422     rw=minfo.rcWork.right-minfo.rcWork.left;
423     rh=minfo.rcWork.bottom-minfo.rcWork.top;
424     }
425   else
426 #endif
427     {
428     // On Win95 and WinNT, we have to use the following
429     SystemParametersInfo(SPI_GETWORKAREA,sizeof(RECT),&rect,0);
430     rx=rect.left;
431     ry=rect.top;
432     rw=rect.right-rect.left;
433     rh=rect.bottom-rect.top;
434     }
435 #endif
436 
437   // Placement policy
438   switch(placement){
439 
440     // Place such that it contains the cursor
441     case PLACEMENT_CURSOR:
442 
443       // Get dialog location in root coordinates
444       translateCoordinatesTo(wx,wy,getRoot(),0,0);
445 
446       // Where's the mouse?
447       getRoot()->getCursorPosition(x,y,state);
448 
449       // Place such that mouse in the middle, placing it as
450       // close as possible in the center of the owner window.
451       // Don't move the window unless the mouse is not inside.
452       if(!shown() || x<wx || y<wy || wx+ww<=x || wy+wh<=y){
453 
454         // Get the owner
455         over=getOwner()?getOwner():getRoot();
456 
457         // Get owner window size
458         ow=over->getWidth();
459         oh=over->getHeight();
460 
461         // Owner's coordinates to root coordinates
462         over->translateCoordinatesTo(ox,oy,getRoot(),0,0);
463 
464         // Adjust position
465         wx=ox+(ow-ww)/2;
466         wy=oy+(oh-wh)/2;
467 
468         // Move by the minimal amount
469         if(x<wx) wx=x-20; else if(wx+ww<=x) wx=x-ww+20;
470         if(y<wy) wy=y-20; else if(wy+wh<=y) wy=y-wh+20;
471         }
472 
473       // Adjust so dialog is fully visible
474       if(wx<rx) wx=rx+10;
475       if(wy<ry) wy=ry+10;
476       if(wx+ww>rw) wx=rw-ww-10;
477       if(wy+wh>rh) wy=rh-wh-10;
478       break;
479 
480     // Place centered over the owner
481     case PLACEMENT_OWNER:
482 
483       // Get the owner
484       over=getOwner()?getOwner():getRoot();
485 
486       // Get owner window size
487       ow=over->getWidth();
488       oh=over->getHeight();
489 
490       // Owner's coordinates to root coordinates
491       over->translateCoordinatesTo(ox,oy,getRoot(),0,0);
492 
493       // Adjust position
494       wx=ox+(ow-ww)/2;
495       wy=oy+(oh-wh)/2;
496 
497       // Adjust so dialog is fully visible
498       if(wx<rx) wx=rx+10;
499       if(wy<ry) wy=ry+10;
500       if(wx+ww>rw) wx=rw-ww-10;
501       if(wy+wh>rh) wy=rh-wh-10;
502       break;
503 
504     // Place centered on the screen
505     case PLACEMENT_SCREEN:
506 
507       // Adjust position
508       wx=rx+(rw-ww)/2;
509       wy=ry+(rh-wh)/2;
510       break;
511 
512     // Place to make it fully visible
513     case PLACEMENT_VISIBLE:
514 
515       // Adjust so dialog is fully visible
516       if(wx<rx) wx=rx+10;
517       if(wy<ry) wy=ry+10;
518       if(wx+ww>rw) wx=rw-ww-10;
519       if(wy+wh>rh) wy=rh-wh-10;
520       break;
521 
522     // Place maximized
523     case PLACEMENT_MAXIMIZED:
524       wx=rx;
525       wy=ry;
526       ww=rw;                // Yes, I know:- we should substract the borders;
527       wh=rh;                // trouble is, no way to know how big those are....
528       break;
529 
530     // Default placement
531     case PLACEMENT_DEFAULT:
532     default:
533       break;
534     }
535 
536   // Place it
537   position(wx,wy,ww,wh);
538   }
539 
540 
541 #ifdef WIN32
542 
543 
544 // Make HICON from FXIcon
makeicon(FXIcon * icon)545 void* FXTopWindow::makeicon(FXIcon* icon){
546   ICONINFO iconinfo;
547   iconinfo.fIcon=TRUE;
548   iconinfo.xHotspot=0;
549   iconinfo.yHotspot=0;
550   iconinfo.hbmMask=(HBITMAP)icon->shape;
551   iconinfo.hbmColor=(HBITMAP)icon->id();
552   return (void*)CreateIconIndirect(&iconinfo);
553   }
554 
555 
556 #endif
557 
558 
559 
560 // Set large icon(s)
seticons()561 void FXTopWindow::seticons(){
562 
563   // Set icon for X-Windows
564 #ifndef WIN32
565   FXWindow *own=this;
566   XWMHints  wmhints;
567   wmhints.flags=InputHint|StateHint;
568   wmhints.input=TRUE;       // True, but ICCCM says it should be FALSE....
569   wmhints.initial_state=NormalState;
570   if(icon){
571     if(!icon->xid || !icon->shape){ fxerror("%s::setIcon: illegal icon specified.\n",getClassName()); }
572     wmhints.flags|=IconPixmapHint|IconMaskHint;
573     wmhints.icon_pixmap=icon->xid;
574     wmhints.icon_mask=icon->shape;
575     }
576   else if(miniIcon){
577     if(!miniIcon->xid || !miniIcon->shape){ fxerror("%s::setMiniIcon: illegal icon specified.\n",getClassName()); }
578     wmhints.flags|=IconPixmapHint|IconMaskHint;
579     wmhints.icon_pixmap=miniIcon->xid;
580     wmhints.icon_mask=miniIcon->shape;
581     }
582   while(own->getOwner()){   // Find the ultimate owner of the whole chain
583     own=own->getOwner();
584     }
585   if(own && own->id()){     // Set the window_group id; all windows in the group should be iconified together
586     wmhints.flags|=WindowGroupHint;
587     wmhints.window_group=own->id();
588     }
589   XSetWMHints(DISPLAY(getApp()),xid,&wmhints);
590 
591   // Set both large and mini icon for MS-Windows
592 #else
593   HICON icold,icnew;
594   icnew=NULL;
595   if(icon){
596     ICONINFO iconinfo;
597     iconinfo.fIcon=TRUE;
598     iconinfo.xHotspot=0;
599     iconinfo.yHotspot=0;
600     iconinfo.hbmMask=(HBITMAP)icon->shape;
601     iconinfo.hbmColor=(HBITMAP)icon->xid;
602     icnew=CreateIconIndirect(&iconinfo);
603     }
604   if((icold=(HICON)SendMessage((HWND)xid,WM_SETICON,ICON_BIG,(LPARAM)icnew))!=0){
605     DestroyIcon(icold);
606     }
607   icnew=NULL;
608   if(miniIcon){
609     ICONINFO iconinfo;
610     iconinfo.fIcon=TRUE;
611     iconinfo.xHotspot=0;
612     iconinfo.yHotspot=0;
613     iconinfo.hbmMask=(HBITMAP)miniIcon->shape;
614     iconinfo.hbmColor=(HBITMAP)miniIcon->xid;
615     icnew=CreateIconIndirect(&iconinfo);
616     }
617   if((icold=(HICON)SendMessage((HWND)xid,WM_SETICON,ICON_SMALL,(LPARAM)icnew))!=0){
618     DestroyIcon(icold);
619     }
620 #endif
621   }
622 
623 
624 // Set title
settitle()625 void FXTopWindow::settitle(){
626   if(!title.empty()){
627 #ifndef WIN32
628     XTextProperty t;
629     char *s;
630     s=(char*)title.text();
631     if(XStringListToTextProperty((char**)&s,1,&t)){
632       XSetWMIconName(DISPLAY(getApp()),xid,&t);
633       XSetWMName(DISPLAY(getApp()),xid,&t);
634       XFree(t.value);
635       }
636 #else
637     SetWindowText((HWND)xid,title.text());
638 #endif
639     }
640   }
641 
642 
643 
644 // Set decorations
setdecorations()645 void FXTopWindow::setdecorations(){
646 #ifndef WIN32
647   struct {
648     long flags;
649     long functions;
650     long decorations;
651     long inputmode;
652     } prop;
653   prop.flags=MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS|MWM_HINTS_INPUT_MODE;
654   prop.decorations=0;
655   prop.functions=MWM_FUNC_MOVE;
656   prop.inputmode=MWM_INPUT_MODELESS;
657   if(options&DECOR_TITLE){
658     prop.decorations|=MWM_DECOR_TITLE;
659     }
660   if(options&DECOR_MINIMIZE){
661     prop.decorations|=MWM_DECOR_MINIMIZE;
662     prop.functions|=MWM_FUNC_MINIMIZE;
663     }
664   if(options&DECOR_MAXIMIZE){
665     prop.decorations|=MWM_DECOR_MAXIMIZE;
666     prop.functions|=MWM_FUNC_MAXIMIZE;
667     }
668   if(options&DECOR_CLOSE){
669     prop.functions|=MWM_FUNC_CLOSE;
670     }
671   if(options&DECOR_BORDER){
672     prop.decorations|=MWM_DECOR_BORDER;
673     }
674   if(options&(DECOR_SHRINKABLE|DECOR_STRETCHABLE)){
675     if(options&DECOR_BORDER) prop.decorations|=MWM_DECOR_RESIZEH;       // Only grips if border
676     prop.functions|=MWM_FUNC_RESIZE;
677     }
678   if(options&DECOR_MENU){
679     prop.decorations|=MWM_DECOR_MENU;
680     prop.functions|=MWM_FUNC_RESIZE;
681     }
682   XChangeProperty(DISPLAY(getApp()),xid,getApp()->wmMotifHints,getApp()->wmMotifHints,32,PropModeReplace,(unsigned char*)&prop,4);
683 #else
684 
685   // Get old style
686   DWORD dwStyle=GetWindowLong((HWND)xid,GWL_STYLE);
687   RECT rect;
688 
689   // Moved here just in case the size changes behind our backs
690   SetRect(&rect,0,0,width,height);
691 
692   // Change style setting; note, under Windows, if we want a minimize,
693   // maximize, or close button, we also need a window menu style as well.
694   // Also, if you want a title, you will need a border.
695   if(options&DECOR_BORDER) dwStyle|=WS_BORDER; else dwStyle&=~WS_BORDER;
696   if(options&DECOR_TITLE) dwStyle|=WS_CAPTION; else dwStyle&=~WS_DLGFRAME;
697   if(options&DECOR_RESIZE) dwStyle|=WS_THICKFRAME; else dwStyle&=~WS_THICKFRAME;
698   if(options&DECOR_MENU) dwStyle|=WS_SYSMENU; else dwStyle&=~WS_SYSMENU;
699   if(options&DECOR_CLOSE) dwStyle|=WS_SYSMENU;
700   if(options&DECOR_MINIMIZE) dwStyle|=(WS_MINIMIZEBOX|WS_SYSMENU); else dwStyle&=~WS_MINIMIZEBOX;
701   if(options&DECOR_MAXIMIZE) dwStyle|=(WS_MAXIMIZEBOX|WS_SYSMENU); else dwStyle&=~WS_MAXIMIZEBOX;
702 
703   // Set new style
704   SetWindowLong((HWND)xid,GWL_STYLE,dwStyle);
705 
706   // Patch from Stephane Ancelot <sancelot@wanadoo.fr> and Sander Jansen <sander@knology.net>
707   HMENU sysmenu=GetSystemMenu((HWND)xid,FALSE);
708   if(sysmenu){
709     if(options&DECOR_CLOSE)
710       EnableMenuItem(sysmenu,SC_CLOSE,MF_ENABLED);
711     else
712       EnableMenuItem(sysmenu,SC_CLOSE,MF_GRAYED);
713     }
714 
715   // Moved here just in case SetWindowLong GWL_STYLE has changed
716   // the GWL_EXSTYLE behind the scenes...
717   DWORD dwExStyle=GetWindowLong((HWND)xid,GWL_EXSTYLE);
718 
719   // Adjust non-client area size based on new style
720   AdjustWindowRectEx(&rect,dwStyle,FALSE,dwExStyle);
721   SetWindowPos((HWND)xid,NULL,0,0,FXMAX(rect.right-rect.left,1),FXMAX(rect.bottom-rect.top,1),SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER);
722   RedrawWindow((HWND)xid,NULL,NULL,RDW_FRAME|RDW_INVALIDATE);
723 #endif
724   }
725 
726 
727 // Obtain border sizes added to our window by the window manager
getWMBorders(FXint & left,FXint & right,FXint & top,FXint & bottom)728 FXbool FXTopWindow::getWMBorders(FXint& left,FXint& right,FXint& top,FXint& bottom){
729   left=right=top=bottom=0;
730   if(xid){
731 #ifdef WIN32
732 #if(WINVER >= 0x0500)
733     WINDOWINFO wi;
734     GetWindowInfo((HWND)xid,&wi);
735     left=wi.rcClient.left-wi.rcWindow.left;
736     top=wi.rcClient.top-wi.rcWindow.top;
737     right=wi.rcWindow.right-wi.rcClient.right;
738     bottom=wi.rcWindow.bottom-wi.rcClient.bottom;
739 #endif
740 #else
741     unsigned int sx,sy,msx,msy,cn,border,depth;
742     Window w,rw,pw,*cw;
743     int ox,oy;
744     w=xid;
745     XGetGeometry(DISPLAY(getApp()),w,&rw,&ox,&oy,&msx,&msy,&border,&depth);
746     do{
747       XQueryTree(DISPLAY(getApp()),w,&rw,&pw,&cw,&cn);
748       XFree(cw);
749       XGetGeometry(DISPLAY(getApp()),w,&rw,&ox,&oy,&sx,&sy,&border,&depth);
750       if(pw!=rw){
751         left+=ox;
752         top+=oy;
753         }
754       w=pw;
755       }
756     while(w!=rw);
757     right=(sx-msx-left);
758     bottom=(sy-msy-top);
759 #endif
760     return TRUE;
761     }
762   return FALSE;
763   }
764 
765 
766 // Change decorations
setDecorations(FXuint decorations)767 void FXTopWindow::setDecorations(FXuint decorations){
768   FXuint opts=(options&~DECOR_ALL) | (decorations&DECOR_ALL);
769   if(options!=opts){
770     options=opts;
771     if(xid) setdecorations();
772     recalc();
773     }
774   }
775 
776 
777 // Get decorations
getDecorations() const778 FXuint FXTopWindow::getDecorations() const {
779   return options&DECOR_ALL;
780   }
781 
782 
783 // Iconify window
maximize(FXbool notify)784 FXbool FXTopWindow::maximize(FXbool notify){
785   if(!isMaximized()){
786     if(xid){
787 #ifndef WIN32
788       XEvent se;
789 
790       // Maximize
791       se.xclient.type=ClientMessage;
792       se.xclient.display=DISPLAY(getApp());
793       se.xclient.message_type=getApp()->wmNetState;
794       se.xclient.format=32;
795       se.xclient.window=xid;
796       se.xclient.data.l[0]=2;   // 0=_NET_WM_STATE_REMOVE, 1=_NET_WM_STATE_ADD, 2=_NET_WM_STATE_TOGGLE
797       se.xclient.data.l[1]=getApp()->wmNetHMaximized;
798       se.xclient.data.l[2]=getApp()->wmNetVMaximized;
799       se.xclient.data.l[3]=0;
800       se.xclient.data.l[4]=0;
801       XSendEvent(DISPLAY(getApp()),XDefaultRootWindow(DISPLAY(getApp())),False,SubstructureRedirectMask|SubstructureNotifyMask,&se);
802 
803       // Restore from minimized
804       XMapWindow(DISPLAY(getApp()),xid);
805 #else
806       ShowWindow((HWND)xid,SW_MAXIMIZE);
807 #endif
808       }
809     if(notify && target){target->tryHandle(this,FXSEL(SEL_MAXIMIZE,message),NULL);}
810     return TRUE;
811     }
812   return FALSE;
813   }
814 
815 
816 // Miminize or iconify window
minimize(FXbool notify)817 FXbool FXTopWindow::minimize(FXbool notify){
818   if(!isMinimized()){
819     if(xid){
820 #ifndef WIN32
821       XIconifyWindow(DISPLAY(getApp()),xid,DefaultScreen(DISPLAY(getApp())));
822 #else
823       ShowWindow((HWND)xid,SW_MINIMIZE);
824 #endif
825       }
826     if(notify && target){target->tryHandle(this,FXSEL(SEL_MINIMIZE,message),NULL);}
827     return TRUE;
828     }
829   return FALSE;
830   }
831 
832 
833 // Restore window
restore(FXbool notify)834 FXbool FXTopWindow::restore(FXbool notify){
835   if(isMinimized() || isMaximized()){
836     if(xid){
837 #ifndef WIN32
838       XEvent se;
839 
840       // Restore from maximized
841       se.xclient.type=ClientMessage;
842       se.xclient.display=DISPLAY(getApp());
843       se.xclient.message_type=getApp()->wmNetState;
844       se.xclient.format=32;
845       se.xclient.window=xid;
846       se.xclient.data.l[0]=0;   // 0=_NET_WM_STATE_REMOVE, 1=_NET_WM_STATE_ADD, 2=_NET_WM_STATE_TOGGLE
847       se.xclient.data.l[1]=getApp()->wmNetHMaximized;
848       se.xclient.data.l[2]=getApp()->wmNetVMaximized;
849       se.xclient.data.l[3]=0;
850       se.xclient.data.l[4]=0;
851       XSendEvent(DISPLAY(getApp()),XDefaultRootWindow(DISPLAY(getApp())),False,SubstructureRedirectMask|SubstructureNotifyMask,&se);
852 
853       // Restore from minimized
854       XMapWindow(DISPLAY(getApp()),xid);
855 #else
856       ShowWindow((HWND)xid,SW_RESTORE);
857 #endif
858       }
859     if(notify && target){target->tryHandle(this,FXSEL(SEL_RESTORE,message),NULL);}
860     return TRUE;
861     }
862   return FALSE;
863   }
864 
865 
866 // Attempt to close the window, return TRUE if actually closed
close(FXbool notify)867 FXbool FXTopWindow::close(FXbool notify){
868   register FXWindow *window;
869 
870   // Ask target if desired
871   if(!notify || !target || !target->tryHandle(this,FXSEL(SEL_CLOSE,message),NULL)){
872 
873     // Target will receive no further messages from us
874     setTarget(NULL);
875     setSelector(0);
876 
877     // If there was another main level window still visible, that's all we do
878     for(window=getRoot()->getFirst(); window; window=window->getNext()){
879       if(window!=this && window->isMemberOf(FXMETACLASS(FXMainWindow))){
880         goto x;
881         }
882       }
883 
884     // We've just hidden the last remaining top level window:- quit the application
885     getApp()->handle(this,FXSEL(SEL_COMMAND,FXApp::ID_QUIT),NULL);
886 
887     // Self destruct
888 x:  delete this;
889 
890     // Was closed
891     return TRUE;
892     }
893   return FALSE;
894   }
895 
896 
897 // Return TRUE if window has been maximized
isMaximized() const898 FXbool FXTopWindow::isMaximized() const {
899   FXbool maximized=FALSE;
900   if(xid){
901 #ifndef WIN32
902     unsigned long nitems,after,i;
903     FXID *netstate;
904     Atom actualtype;
905     int actualformat;
906 
907     // For Window Managers supporting the Extended Window Manager Hints
908     // See http://www.freedesktop.org/ for the official documentation of EWMH
909     if(Success==XGetWindowProperty(DISPLAY(getApp()),xid,getApp()->wmNetState,0,2,FALSE,AnyPropertyType,&actualtype,&actualformat,&nitems,&after,(unsigned char**)&netstate)){
910       if(actualtype==XA_ATOM && actualformat==32){
911         FXTRACE((100,"got _NET_WM_STATE property\n"));
912         for(i=0; i<nitems; i++){
913           if(netstate[i]==getApp()->wmNetHMaximized) maximized=TRUE;
914           if(netstate[i]==getApp()->wmNetVMaximized) maximized=TRUE;
915           }
916         FXTRACE((100,"maximized=%d\n",maximized));
917         }
918       XFree((char*)netstate);
919       }
920 #else
921     maximized=IsZoomed((HWND)xid);
922 #endif
923     }
924   return maximized;
925   }
926 
927 
928 // Return TRUE if window has been minimized
isMinimized() const929 FXbool FXTopWindow::isMinimized() const {
930   FXbool minimized=FALSE;
931   if(xid){
932 #ifndef WIN32
933     unsigned long length,after;
934     unsigned char *prop;
935     Atom actualtype;
936     int actualformat;
937 
938     // This is ICCCM compliant method to ask about WM_STATE
939     if(Success==XGetWindowProperty(DISPLAY(getApp()),xid,getApp()->wmState,0,2,FALSE,AnyPropertyType,&actualtype,&actualformat,&length,&after,&prop)){
940       if(actualformat==32){
941         minimized=(IconicState==*((FXuint*)prop));
942         }
943       XFree((char*)prop);
944       }
945 #else
946     minimized=IsIconic((HWND)xid);
947 #endif
948     }
949   return minimized;
950   }
951 
952 
953 // Request for toplevel window move
move(FXint x,FXint y)954 void FXTopWindow::move(FXint x,FXint y){
955   if((x!=xpos) || (y!=ypos)){
956     xpos=x;
957     ypos=y;
958     if(xid){
959 #ifndef WIN32
960       XWindowChanges cw;
961       cw.x=xpos;
962       cw.y=ypos;
963       XReconfigureWMWindow(DISPLAY(getApp()),xid,DefaultScreen(DISPLAY(getApp())),CWX|CWY,&cw);
964 #else
965       // Calculate the required window position based on the desired
966       // position of the *client* rectangle.
967       RECT rect;
968       SetRect(&rect,xpos,ypos,0,0);
969       DWORD dwStyle=GetWindowLong((HWND)xid,GWL_STYLE);
970       DWORD dwExStyle=GetWindowLong((HWND)xid,GWL_EXSTYLE);
971       AdjustWindowRectEx(&rect,dwStyle,FALSE,dwExStyle);
972       SetWindowPos((HWND)xid,NULL,rect.left,rect.top,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER);
973 #endif
974       }
975     }
976   }
977 
978 
979 // Request for toplevel window resize
resize(FXint w,FXint h)980 void FXTopWindow::resize(FXint w,FXint h){
981   if((flags&FLAG_DIRTY) || (w!=width) || (h!=height)){
982     width=FXMAX(w,1);
983     height=FXMAX(h,1);
984     if(xid){
985 #ifndef WIN32
986       XWindowChanges cw;
987       cw.width=width;
988       cw.height=height;
989       XReconfigureWMWindow(DISPLAY(getApp()),xid,DefaultScreen(DISPLAY(getApp())),CWWidth|CWHeight,&cw);
990 #else
991       // Calculate the required window size based on the desired
992       // size of the *client* rectangle.
993       RECT rect;
994       SetRect(&rect,0,0,width,height);
995       DWORD dwStyle=GetWindowLong((HWND)xid,GWL_STYLE);
996       DWORD dwExStyle=GetWindowLong((HWND)xid,GWL_EXSTYLE);
997       AdjustWindowRectEx(&rect,dwStyle,FALSE,dwExStyle);
998       SetWindowPos((HWND)xid,NULL,0,0,FXMAX(rect.right-rect.left,1),FXMAX(rect.bottom-rect.top,1),SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER);
999 #endif
1000       layout();
1001       }
1002     }
1003   }
1004 
1005 
1006 // Request for toplevel window reposition
position(FXint x,FXint y,FXint w,FXint h)1007 void FXTopWindow::position(FXint x,FXint y,FXint w,FXint h){
1008   if((flags&FLAG_DIRTY) || (x!=xpos) || (y!=ypos) || (w!=width) || (h!=height)){
1009     xpos=x;
1010     ypos=y;
1011     width=FXMAX(w,1);
1012     height=FXMAX(h,1);
1013     if(xid){
1014 #ifndef WIN32
1015       XWindowChanges cw;
1016       cw.x=xpos;
1017       cw.y=ypos;
1018       cw.width=width;
1019       cw.height=height;
1020       XReconfigureWMWindow(DISPLAY(getApp()),xid,DefaultScreen(DISPLAY(getApp())),CWX|CWY|CWWidth|CWHeight,&cw);
1021 #else
1022       // Calculate the required window position & size based on the desired
1023       // position & size of the *client* rectangle.
1024       RECT rect;
1025       SetRect(&rect,xpos,ypos,xpos+width,ypos+height);
1026       DWORD dwStyle=GetWindowLong((HWND)xid,GWL_STYLE);
1027       DWORD dwExStyle=GetWindowLong((HWND)xid,GWL_EXSTYLE);
1028       AdjustWindowRectEx(&rect,dwStyle,FALSE,dwExStyle);
1029       SetWindowPos((HWND)xid,NULL,rect.left,rect.top,FXMAX(rect.right-rect.left,1),FXMAX(rect.bottom-rect.top,1),SWP_NOZORDER|SWP_NOOWNERZORDER);
1030 #endif
1031       layout();
1032       }
1033     }
1034   }
1035 
1036 
1037 // Compute minimum width based on child layout hints
getDefaultWidth()1038 FXint FXTopWindow::getDefaultWidth(){
1039   register FXint w,wcum,wmax,mw=0;
1040   register FXWindow* child;
1041   register FXuint hints;
1042   wmax=wcum=0;
1043   if(options&PACK_UNIFORM_WIDTH) mw=maxChildWidth();
1044   for(child=getLast(); child; child=child->getPrev()){
1045     if(child->shown()){
1046       hints=child->getLayoutHints();
1047       if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
1048       else if(options&PACK_UNIFORM_WIDTH) w=mw;
1049       else w=child->getDefaultWidth();
1050       if((hints&LAYOUT_RIGHT)&&(hints&LAYOUT_CENTER_X)){    // Fixed X
1051         w=child->getX()+w;
1052         if(w>wmax) wmax=w;
1053         }
1054       else if(hints&LAYOUT_SIDE_LEFT){                      // Left or right
1055         if(child->getNext()) wcum+=hspacing;
1056         wcum+=w;
1057         }
1058       else{
1059         if(w>wcum) wcum=w;
1060         }
1061       }
1062     }
1063   return padleft+padright+FXMAX(wcum,wmax);
1064   }
1065 
1066 
1067 // Compute minimum height based on child layout hints
getDefaultHeight()1068 FXint FXTopWindow::getDefaultHeight(){
1069   register FXint h,hcum,hmax,mh=0;
1070   register FXWindow* child;
1071   register FXuint hints;
1072   hmax=hcum=0;
1073   if(options&PACK_UNIFORM_HEIGHT) mh=maxChildHeight();
1074   for(child=getLast(); child; child=child->getPrev()){
1075     if(child->shown()){
1076       hints=child->getLayoutHints();
1077       if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
1078       else if(options&PACK_UNIFORM_HEIGHT) h=mh;
1079       else h=child->getDefaultHeight();
1080       if((hints&LAYOUT_BOTTOM)&&(hints&LAYOUT_CENTER_Y)){   // Fixed Y
1081         h=child->getY()+h;
1082         if(h>hmax) hmax=h;
1083         }
1084       else if(!(hints&LAYOUT_SIDE_LEFT)){                   // Top or bottom
1085         if(child->getNext()) hcum+=vspacing;
1086         hcum+=h;
1087         }
1088       else{
1089         if(h>hcum) hcum=h;
1090         }
1091       }
1092     }
1093   return padtop+padbottom+FXMAX(hcum,hmax);
1094   }
1095 
1096 
1097 // Recalculate layout
layout()1098 void FXTopWindow::layout(){
1099   register FXint left,right,top,bottom,x,y,w,h;
1100   register FXint mw=0,mh=0;
1101   register FXWindow* child;
1102   register FXuint hints;
1103 
1104   // Placement rectangle; right/bottom non-inclusive
1105   left=padleft;
1106   right=width-padright;
1107   top=padtop;
1108   bottom=height-padbottom;
1109 
1110   // Get maximum child size
1111   if(options&PACK_UNIFORM_WIDTH) mw=maxChildWidth();
1112   if(options&PACK_UNIFORM_HEIGHT) mh=maxChildHeight();
1113 
1114   // Pack them in the cavity
1115   for(child=getFirst(); child; child=child->getNext()){
1116     if(child->shown()){
1117       hints=child->getLayoutHints();
1118       x=child->getX();
1119       y=child->getY();
1120 
1121       // Vertical
1122       if(hints&LAYOUT_SIDE_LEFT){
1123 
1124         // Height
1125         if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
1126         else if(options&PACK_UNIFORM_HEIGHT) h=mh;
1127         else if(hints&LAYOUT_FILL_Y) h=bottom-top;
1128         else h=child->getDefaultHeight();
1129 
1130         // Width
1131         if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
1132         else if(options&PACK_UNIFORM_WIDTH) w=mw;
1133         else if(hints&LAYOUT_FILL_X) w=right-left;
1134         else w=child->getWidthForHeight(h);             // Width is a function of height!
1135 
1136         // Y
1137         if(!((hints&LAYOUT_BOTTOM)&&(hints&LAYOUT_CENTER_Y))){
1138           if(hints&LAYOUT_CENTER_Y) y=top+(bottom-top-h)/2;
1139           else if(hints&LAYOUT_BOTTOM) y=bottom-h;
1140           else y=top;
1141           }
1142 
1143         // X
1144         if(!((hints&LAYOUT_RIGHT)&&(hints&LAYOUT_CENTER_X))){
1145           if(hints&LAYOUT_CENTER_X) x=left+(right-left-w)/2;
1146           else if(hints&LAYOUT_SIDE_BOTTOM){            // Right
1147             x=right-w;
1148             right-=(w+hspacing);
1149             }
1150           else{                                         // Left
1151             x=left;
1152             left+=(w+hspacing);
1153             }
1154           }
1155         }
1156 
1157       // Horizontal
1158       else{
1159 
1160         // Width
1161         if(hints&LAYOUT_FIX_WIDTH) w=child->getWidth();
1162         else if(options&PACK_UNIFORM_WIDTH) w=mw;
1163         else if(hints&LAYOUT_FILL_X) w=right-left;
1164         else w=child->getDefaultWidth();
1165 
1166         // Height
1167         if(hints&LAYOUT_FIX_HEIGHT) h=child->getHeight();
1168         else if(options&PACK_UNIFORM_HEIGHT) h=mh;
1169         else if(hints&LAYOUT_FILL_Y) h=bottom-top;
1170         else h=child->getHeightForWidth(w);             // Height is a function of width!
1171 
1172         // X
1173         if(!((hints&LAYOUT_RIGHT)&&(hints&LAYOUT_CENTER_X))){
1174           if(hints&LAYOUT_CENTER_X) x=left+(right-left-w)/2;
1175           else if(hints&LAYOUT_RIGHT) x=right-w;
1176           else x=left;
1177           }
1178 
1179         // Y
1180         if(!((hints&LAYOUT_BOTTOM)&&(hints&LAYOUT_CENTER_Y))){
1181           if(hints&LAYOUT_CENTER_Y) y=top+(bottom-top-h)/2;
1182           else if(hints&LAYOUT_SIDE_BOTTOM){            // Bottom
1183             y=bottom-h;
1184             bottom-=(h+vspacing);
1185             }
1186           else{                                         // Top
1187             y=top;
1188             top+=(h+vspacing);
1189             }
1190           }
1191         }
1192       child->position(x,y,w,h);
1193       }
1194     }
1195   flags&=~FLAG_DIRTY;
1196   }
1197 
1198 
1199 // Update value from a message
onCmdSetStringValue(FXObject *,FXSelector,void * ptr)1200 long FXTopWindow::onCmdSetStringValue(FXObject*,FXSelector,void* ptr){
1201   setTitle(*((FXString*)ptr));
1202   return 1;
1203   }
1204 
1205 
1206 // Obtain value from text field
onCmdGetStringValue(FXObject *,FXSelector,void * ptr)1207 long FXTopWindow::onCmdGetStringValue(FXObject*,FXSelector,void* ptr){
1208   *((FXString*)ptr)=getTitle();
1209   return 1;
1210   }
1211 
1212 
1213 // Update icon from a message
onCmdSetIconValue(FXObject *,FXSelector,void * ptr)1214 long FXTopWindow::onCmdSetIconValue(FXObject*,FXSelector,void* ptr){
1215   setMiniIcon(*((FXIcon**)ptr));
1216   return 1;
1217   }
1218 
1219 
1220 // Obtain icon from text field
onCmdGetIconValue(FXObject *,FXSelector,void * ptr)1221 long FXTopWindow::onCmdGetIconValue(FXObject*,FXSelector,void* ptr){
1222   *((FXIcon**)ptr)=getMiniIcon();
1223   return 1;
1224   }
1225 
1226 
1227 // Maximize the window
onCmdMaximize(FXObject *,FXSelector,void *)1228 long FXTopWindow::onCmdMaximize(FXObject*,FXSelector,void*){
1229   maximize(TRUE);
1230   return 1;
1231   }
1232 
1233 
1234 // Minimize or iconify the window
onCmdMinimize(FXObject *,FXSelector,void *)1235 long FXTopWindow::onCmdMinimize(FXObject*,FXSelector,void*){
1236   minimize(TRUE);
1237   return 1;
1238   }
1239 
1240 
1241 // Restore the window
onCmdRestore(FXObject *,FXSelector,void *)1242 long FXTopWindow::onCmdRestore(FXObject*,FXSelector,void*){
1243   restore(TRUE);
1244   return 1;
1245   }
1246 
1247 
1248 // Close window; ask target before doing close
onCmdClose(FXObject *,FXSelector,void *)1249 long FXTopWindow::onCmdClose(FXObject*,FXSelector,void*){
1250   close(TRUE);
1251   return 1;
1252   }
1253 
1254 
1255 // Focus moved up
onFocusUp(FXObject *,FXSelector,void * ptr)1256 long FXTopWindow::onFocusUp(FXObject*,FXSelector,void* ptr){
1257   FXWindow *child,*c;
1258   FXint cury,childy;
1259   if(getFocus()){
1260     cury=getFocus()->getY();
1261     while(1){
1262       child=NULL;
1263       childy=-10000000;
1264       for(c=getFirst(); c; c=c->getNext()){
1265         if(c->shown() && c->getY()<cury && childy<c->getY()){ childy=c->getY(); child=c; }
1266         }
1267       if(!child) return 0;
1268       if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
1269       if(child->handle(this,FXSEL(SEL_FOCUS_UP,0),ptr)) return 1;
1270       cury=childy;
1271       }
1272     }
1273   else{
1274     child=getLast();
1275     while(child){
1276       if(child->shown()){
1277         if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
1278         if(child->handle(this,FXSEL(SEL_FOCUS_UP,0),ptr)) return 1;
1279         }
1280       child=child->getPrev();
1281       }
1282     }
1283   return 0;
1284   }
1285 
1286 
1287 // Focus moved down
onFocusDown(FXObject *,FXSelector,void * ptr)1288 long FXTopWindow::onFocusDown(FXObject*,FXSelector,void* ptr){
1289   FXWindow *child,*c;
1290   FXint cury,childy;
1291   if(getFocus()){
1292     cury=getFocus()->getY();
1293     while(1){
1294       child=NULL;
1295       childy=10000000;
1296       for(c=getFirst(); c; c=c->getNext()){
1297         if(c->shown() && cury<c->getY() && c->getY()<childy){ childy=c->getY(); child=c; }
1298         }
1299       if(!child) return 0;
1300       if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
1301       if(child->handle(this,FXSEL(SEL_FOCUS_DOWN,0),ptr)) return 1;
1302       cury=childy;
1303       }
1304     }
1305   else{
1306     child=getFirst();
1307     while(child){
1308       if(child->shown()){
1309         if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
1310         if(child->handle(this,FXSEL(SEL_FOCUS_DOWN,0),ptr)) return 1;
1311         }
1312       child=child->getNext();
1313       }
1314     }
1315   return 0;
1316   }
1317 
1318 
1319 // Focus moved to left
onFocusLeft(FXObject *,FXSelector,void * ptr)1320 long FXTopWindow::onFocusLeft(FXObject*,FXSelector,void* ptr){
1321   FXWindow *child,*c;
1322   FXint curx,childx;
1323   if(getFocus()){
1324     curx=getFocus()->getX();
1325     while(1){
1326       child=NULL;
1327       childx=-10000000;
1328       for(c=getFirst(); c; c=c->getNext()){
1329         if(c->shown() && c->getX()<curx && childx<c->getX()){ childx=c->getX(); child=c; }
1330         }
1331       if(!child) return 0;
1332       if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
1333       if(child->handle(this,FXSEL(SEL_FOCUS_LEFT,0),ptr)) return 1;
1334       curx=childx;
1335       }
1336     }
1337   else{
1338     child=getLast();
1339     while(child){
1340       if(child->shown()){
1341         if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
1342         if(child->handle(this,FXSEL(SEL_FOCUS_LEFT,0),ptr)) return 1;
1343         }
1344       child=child->getPrev();
1345       }
1346     }
1347   return 0;
1348   }
1349 
1350 
1351 // Focus moved to right
onFocusRight(FXObject *,FXSelector,void * ptr)1352 long FXTopWindow::onFocusRight(FXObject*,FXSelector,void* ptr){
1353   FXWindow *child,*c;
1354   FXint curx,childx;
1355   if(getFocus()){
1356     curx=getFocus()->getX();
1357     while(1){
1358       child=NULL;
1359       childx=10000000;
1360       for(c=getFirst(); c; c=c->getNext()){
1361         if(c->shown() && curx<c->getX() && c->getX()<childx){ childx=c->getX(); child=c; }
1362         }
1363       if(!child) return 0;
1364       if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
1365       if(child->handle(this,FXSEL(SEL_FOCUS_RIGHT,0),ptr)) return 1;
1366       curx=childx;
1367       }
1368     }
1369   else{
1370     child=getFirst();
1371     while(child){
1372       if(child->shown()){
1373         if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
1374         if(child->handle(this,FXSEL(SEL_FOCUS_RIGHT,0),ptr)) return 1;
1375         }
1376       child=child->getNext();
1377       }
1378     }
1379   return 0;
1380   }
1381 
1382 
1383 
1384 // Change regular icon
setIcon(FXIcon * ic)1385 void FXTopWindow::setIcon(FXIcon* ic){
1386   if(icon!=ic){
1387     icon=ic;
1388     if(xid) seticons();
1389     }
1390   }
1391 
1392 
1393 // Change mini icon
setMiniIcon(FXIcon * ic)1394 void FXTopWindow::setMiniIcon(FXIcon *ic){
1395   if(miniIcon!=ic){
1396     miniIcon=ic;
1397     if(xid) seticons();
1398     }
1399   }
1400 
1401 
1402 // Set new window title
setTitle(const FXString & name)1403 void FXTopWindow::setTitle(const FXString& name){
1404   if(title!=name){
1405     title=name;
1406     if(xid) settitle();
1407     }
1408   }
1409 
1410 
1411 // Change packing hints
setPackingHints(FXuint ph)1412 void FXTopWindow::setPackingHints(FXuint ph){
1413   FXuint opts=(options&~(PACK_UNIFORM_HEIGHT|PACK_UNIFORM_WIDTH)) | (ph&(PACK_UNIFORM_HEIGHT|PACK_UNIFORM_WIDTH));
1414   if(opts!=options){
1415     options=opts;
1416     recalc();
1417     update();
1418     }
1419   }
1420 
1421 
1422 // Get packing hints
getPackingHints() const1423 FXuint FXTopWindow::getPackingHints() const {
1424   return (options&(PACK_UNIFORM_HEIGHT|PACK_UNIFORM_WIDTH));
1425   }
1426 
1427 
1428 // Change top padding
setPadTop(FXint pt)1429 void FXTopWindow::setPadTop(FXint pt){
1430   if(padtop!=pt){
1431     padtop=pt;
1432     recalc();
1433     update();
1434     }
1435   }
1436 
1437 
1438 // Change bottom padding
setPadBottom(FXint pb)1439 void FXTopWindow::setPadBottom(FXint pb){
1440   if(padbottom!=pb){
1441     padbottom=pb;
1442     recalc();
1443     update();
1444     }
1445   }
1446 
1447 
1448 // Change left padding
setPadLeft(FXint pl)1449 void FXTopWindow::setPadLeft(FXint pl){
1450   if(padleft!=pl){
1451     padleft=pl;
1452     recalc();
1453     update();
1454     }
1455   }
1456 
1457 
1458 // Change right padding
setPadRight(FXint pr)1459 void FXTopWindow::setPadRight(FXint pr){
1460   if(padright!=pr){
1461     padright=pr;
1462     recalc();
1463     update();
1464     }
1465   }
1466 
1467 
1468 // Change horizontal spacing
setHSpacing(FXint hs)1469 void FXTopWindow::setHSpacing(FXint hs){
1470   if(hspacing!=hs){
1471     hspacing=hs;
1472     recalc();
1473     update();
1474     }
1475   }
1476 
1477 
1478 // Change vertical spacing
setVSpacing(FXint vs)1479 void FXTopWindow::setVSpacing(FXint vs){
1480   if(vspacing!=vs){
1481     vspacing=vs;
1482     recalc();
1483     update();
1484     }
1485   }
1486 
1487 // Save object to stream
save(FXStream & store) const1488 void FXTopWindow::save(FXStream& store) const {
1489   FXShell::save(store);
1490   store << title;
1491   store << icon;
1492   store << miniIcon;
1493   store << padtop << padbottom << padleft << padright;
1494   store << hspacing << vspacing;
1495   }
1496 
1497 
1498 // Load object from stream
load(FXStream & store)1499 void FXTopWindow::load(FXStream& store){
1500   FXShell::load(store);
1501   store >> title;
1502   store >> icon;
1503   store >> miniIcon;
1504   store >> padtop >> padbottom >> padleft >> padright;
1505   store >> hspacing >> vspacing;
1506   }
1507 
1508 
1509 // Remove this one from toplevel window list
~FXTopWindow()1510 FXTopWindow::~FXTopWindow(){
1511 #ifdef WIN32
1512   HICON icold;
1513   if((icold=(HICON)SendMessage((HWND)xid,WM_SETICON,ICON_BIG,0))!=0){
1514     DestroyIcon(icold);
1515     }
1516   if((icold=(HICON)SendMessage((HWND)xid,WM_SETICON,ICON_SMALL,0))!=0){
1517     DestroyIcon(icold);
1518     }
1519 #endif
1520   icon=(FXIcon*)-1L;
1521   miniIcon=(FXIcon*)-1L;
1522   }
1523 
1524 }
1525