1 /********************************************************************************
2 *                                                                               *
3 *          M u l t i p l e   D o c u m e n t   C l i e n t   W i n d o w        *
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: FXMDIClient.cpp,v 1.57 2005/01/16 16:06:07 fox Exp $                     *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXThread.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXObjectList.h"
35 #include "FXRegistry.h"
36 #include "FXAccelTable.h"
37 #include "FXApp.h"
38 #include "FXId.h"
39 #include "FXDrawable.h"
40 #include "FXImage.h"
41 #include "FXIcon.h"
42 #include "FXWindow.h"
43 #include "FXFrame.h"
44 #include "FXLabel.h"
45 #include "FXButton.h"
46 #include "FXMenuButton.h"
47 #include "FXComposite.h"
48 #include "FXShell.h"
49 #include "FXPopup.h"
50 #include "FXMenuPane.h"
51 #include "FXMDIButton.h"
52 #include "FXPacker.h"
53 #include "FXHorizontalFrame.h"
54 #include "FXToolBar.h"
55 #include "FXMenuBar.h"
56 #include "FXMDIChild.h"
57 #include "FXMDIClient.h"
58 #include "FXDialogBox.h"
59 #include "FXVerticalFrame.h"
60 #include "FXList.h"
61 
62 
63 /*
64   Notes:
65   - This brings up the question of the cascade design.  Do you want the windows
66     to be cascaded/tiled in the order that they were created, or do you want them
67     to be cascaded in some sort of focus order, with the one that had the focus
68     to be on top,  keeping its focus.
69     In the test app, if you click within any of the child windows, it pops to
70     the top with the focus, with the exception of "TEST3", which has a button.
71     If this button is clicked, that window dos not pop to the top when it
72     gets the focus.  Seems like it should...
73   - Minor problems with mdi.  When a window is maximized and then
74     deleted, the next window that is created is created in "normal" mode.
75     When any adjustment is made to the size of the new window, it pops to
76     "almost" maximized mode.  (The child frame is visible, but as large as
77     possible).  Seems like the child windows should be created maximized if
78     the mdi is in maximized mode.  Also, if there are two windows and one
79     gets maximized and then deleted, the second window pops to "almost"
80     maximixed mode.
81   - We make MDIClient get a first crack at the messages, so that the MDIChild
82     can not shadow any messages really directed at the MDIClient.
83   - Need ``arrange icons'' feature.
84   - When switching active MDIChild windows, we pass the old to the new and vice
85     versa; this allows the MDIChild's target to determine if we switched windows
86     only, or if we switched between one document and another at the same time
87 */
88 
89 #define HORZ_PAD      12
90 #define VERT_PAD      2
91 
92 #define CASCADE_XOFF  24
93 #define CASCADE_YOFF  24
94 
95 #define CLIENT_MIN_WIDTH  16
96 #define CLIENT_MIN_HEIGHT 16
97 
98 
99 using namespace FX;
100 
101 /*******************************************************************************/
102 
103 namespace FX {
104 
105 
106 FXDEFMAP(FXMDIClient) FXMDIClientMap[]={
107   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_NEXT,FXMDIClient::onUpdActivateNext),
108   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_PREV,FXMDIClient::onUpdActivatePrev),
109   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_TILEHORIZONTAL,FXMDIClient::onUpdTileHorizontal),
110   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_TILEVERTICAL,FXMDIClient::onUpdTileVertical),
111   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_CASCADE,FXMDIClient::onUpdCascade),
112   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_CLOSE,FXMDIClient::onUpdClose),
113   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MINIMIZE,FXMDIClient::onUpdMinimize),
114   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_RESTORE,FXMDIClient::onUpdRestore),
115   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MAXIMIZE,FXMDIClient::onUpdMaximize),
116   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MENURESTORE,FXMDIClient::onUpdMenuRestore),
117   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MENUCLOSE,FXMDIClient::onUpdMenuClose),
118   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MENUMINIMIZE,FXMDIClient::onUpdMenuMinimize),
119   FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MENUWINDOW,FXMDIClient::onUpdMenuWindow),
120   FXMAPFUNC(SEL_UPDATE,FXMDIClient::ID_MDI_ANY,FXMDIClient::onUpdAnyWindows),
121   FXMAPFUNCS(SEL_UPDATE,FXMDIClient::ID_MDI_1,FXMDIClient::ID_MDI_10,FXMDIClient::onUpdWindowSelect),
122   FXMAPFUNCS(SEL_UPDATE,FXMDIClient::ID_MDI_OVER_1,FXMDIClient::ID_MDI_OVER_10,FXMDIClient::onUpdOthersWindows),
123   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_NEXT,FXMDIClient::onCmdActivateNext),
124   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_PREV,FXMDIClient::onCmdActivatePrev),
125   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_TILEHORIZONTAL,FXMDIClient::onCmdTileHorizontal),
126   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_TILEVERTICAL,FXMDIClient::onCmdTileVertical),
127   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_CASCADE,FXMDIClient::onCmdCascade),
128   FXMAPFUNCS(SEL_COMMAND,FXMDIClient::ID_MDI_1,FXMDIClient::ID_MDI_10,FXMDIClient::onCmdWindowSelect),
129   FXMAPFUNCS(SEL_COMMAND,FXMDIClient::ID_MDI_OVER_1,FXMDIClient::ID_MDI_OVER_10,FXMDIClient::onCmdOthersWindows),
130   };
131 
132 
133 // Object implementation
FXIMPLEMENT(FXMDIClient,FXComposite,FXMDIClientMap,ARRAYNUMBER (FXMDIClientMap))134 FXIMPLEMENT(FXMDIClient,FXComposite,FXMDIClientMap,ARRAYNUMBER(FXMDIClientMap))
135 
136 
137 // Construct and init
138 FXMDIClient::FXMDIClient(){
139   flags|=FLAG_SHOWN;
140   active=NULL;
141   cascadex=CASCADE_XOFF;
142   cascadey=CASCADE_YOFF;
143   }
144 
145 
146 // Construct and init
FXMDIClient(FXComposite * p,FXuint opts,FXint x,FXint y,FXint w,FXint h)147 FXMDIClient::FXMDIClient(FXComposite* p,FXuint opts,FXint x,FXint y,FXint w,FXint h):
148   FXComposite(p,opts,x,y,w,h){
149   flags|=FLAG_SHOWN;
150   backColor=getApp()->getShadowColor();
151   active=NULL;
152   cascadex=CASCADE_XOFF;
153   cascadey=CASCADE_YOFF;
154   }
155 
156 
157 // Get width
getDefaultWidth()158 FXint FXMDIClient::getDefaultWidth(){
159   return CLIENT_MIN_WIDTH;
160   }
161 
162 
163 // Get height
getDefaultHeight()164 FXint FXMDIClient::getDefaultHeight(){
165   return CLIENT_MIN_HEIGHT;
166   }
167 
168 
169 // Recalculate layout
layout()170 void FXMDIClient::layout(){
171   register FXMDIChild* child;
172   register FXint xx,yy,ww,hh;
173 
174   // Place children
175   for(child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
176     if(child->shown()){
177       if(child->isMaximized()){
178         xx=0;
179         yy=0;
180         ww=width;
181         hh=height;
182         }
183       else if(child->isMinimized()){
184         xx=child->getX();
185         yy=child->getY();
186         ww=child->getDefaultWidth();
187         hh=child->getDefaultHeight();
188         }
189       else{
190         xx=child->getX();
191         yy=child->getY();
192         ww=child->getWidth();
193         hh=child->getHeight();
194         }
195       child->position(xx,yy,ww,hh);
196       }
197     }
198 
199   // Raise active child
200   if(active && active->shown()) active->raise();
201 
202   // No more dirty
203   flags&=~FLAG_DIRTY;
204   }
205 
206 
207 // Cascade windows
cascade(FXbool notify)208 void FXMDIClient::cascade(FXbool notify){
209   register FXMDIChild* child;
210   FXint childx,childy,childw,childh;
211   childx=5;
212   childy=5;
213   childw=(2*width)/3;
214   childh=(2*height)/3;
215   for(child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
216     if(child==active) continue;
217     if(child->shown() && !child->isMinimized()){
218       child->restore(notify);
219       child->position(childx,childy,childw,childh);
220       child->raise();
221       childx+=cascadex;
222       childy+=cascadey;
223       if(childx+child->getWidth()>width){ childx=5; childy=5; }
224       if(childy+child->getHeight()>height){ childy=5; }
225       }
226     }
227   if(active && active->shown() && !active->isMinimized()){
228     active->restore(notify);
229     active->position(childx,childy,childw,childh);
230     active->raise();
231     }
232   }
233 
234 
235 // Layout horizontally
horizontal(FXbool notify)236 void FXMDIClient::horizontal(FXbool notify){
237   register FXMDIChild* child;
238   register FXint n,nr,nc,hroom,vroom,r,c;
239   for(n=0,child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
240     if(child->shown() && !child->isMinimized()) n++;
241     }
242   nr=n;
243   nc=1;
244   if(n>3){
245     nc=(int)sqrt((double)n);
246     nr=(n+nc-1)/nc;
247     }
248   hroom=0;
249   vroom=0;
250   if(nc>0) hroom=width/nc;
251   if(nr>0) vroom=height/nr;
252   for(child=(FXMDIChild*)getFirst(),n=0; child; child=(FXMDIChild*)child->getNext()){
253     if(child->shown() && !child->isMinimized()){
254       r=n/nc;
255       c=n%nc;
256       child->restore(notify);
257       child->position(c*hroom,r*vroom,hroom,vroom);
258       n++;
259       }
260     }
261   if(active && active->shown()) active->raise();
262   }
263 
264 
265 // Layout vertically
vertical(FXbool notify)266 void FXMDIClient::vertical(FXbool notify){
267   register FXMDIChild* child;
268   register FXint n,nr,nc,hroom,vroom,r,c;
269   for(n=0,child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
270     if(child->shown() && !child->isMinimized()) n++;
271     }
272   nc=n;
273   nr=1;
274   if(n>3){
275     nr=(int)sqrt((double)n);
276     nc=(n+nr-1)/nr;
277     }
278   hroom=0;
279   vroom=0;
280   if(nc>0) hroom=width/nc;
281   if(nr>0) vroom=height/nr;
282   for(child=(FXMDIChild*)getFirst(),n=0; child; child=(FXMDIChild*)child->getNext()){
283     if(child->shown() && !child->isMinimized()){
284       r=n/nc;
285       c=n%nc;
286       child->restore(notify);
287       child->position(c*hroom,r*vroom,hroom,vroom);
288       n++;
289       }
290     }
291   if(active && active->shown()) active->raise();
292   }
293 
294 
295 // User clicks on one of the window menus
onCmdWindowSelect(FXObject *,FXSelector sel,void *)296 long FXMDIClient::onCmdWindowSelect(FXObject*,FXSelector sel,void*){
297   setActiveChild((FXMDIChild*)childAtIndex(FXSELID(sel)-ID_MDI_1),TRUE);
298   return 1;
299   }
300 
301 
302 // Update handler for window menus
onUpdWindowSelect(FXObject * sender,FXSelector sel,void *)303 long FXMDIClient::onUpdWindowSelect(FXObject *sender,FXSelector sel,void*){
304   FXint which=FXSELID(sel)-ID_MDI_1;
305   FXMDIChild *child=(FXMDIChild*)childAtIndex(which);
306   if(child){
307     FXString string;
308     if(which<9)
309       string.format("&%d %s",which+1,child->getTitle().text());
310     else
311       string.format("1&0 %s",child->getTitle().text());
312     sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETSTRINGVALUE),(void*)&string);
313     sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SHOW),NULL);
314     if(child==active)
315       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_CHECK),NULL);
316     else
317       sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
318     }
319   else{
320     sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_HIDE),NULL);
321     }
322   return 1;
323   }
324 
325 
326 
327 // Show a menu of other MDI child windows
onCmdOthersWindows(FXObject *,FXSelector,void *)328 long FXMDIClient::onCmdOthersWindows(FXObject*,FXSelector,void*){
329   FXDialogBox choose(this,"Select Window",DECOR_TITLE|DECOR_BORDER|DECOR_RESIZE,0,0,300,200,10,10,10,10, 10,10);
330   FXHorizontalFrame* buttons=new FXHorizontalFrame(&choose,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH|PACK_UNIFORM_HEIGHT,0,0,0,0,0,0,0,0);
331   new FXButton(buttons,"&OK",NULL,&choose,FXDialogBox::ID_ACCEPT,BUTTON_INITIAL|BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
332   new FXButton(buttons,"&Cancel",NULL,&choose,FXDialogBox::ID_CANCEL,BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
333   FXVerticalFrame* mdilistframe=new FXVerticalFrame(&choose,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,0,0,0,0,0,0);
334   FXList* mdilist=new FXList(mdilistframe,NULL,0,LIST_BROWSESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y);
335   mdilist->setNumVisible(10);
336   for(FXMDIChild *child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
337     mdilist->appendItem(child->getTitle(),child->getIcon(),child);
338     if(child==active) mdilist->setCurrentItem(mdilist->getNumItems()-1);
339     }
340   if(choose.execute(PLACEMENT_OWNER)){
341     FXASSERT(mdilist->getCurrentItem()>=0);
342     setActiveChild((FXMDIChild*)mdilist->getItemData(mdilist->getCurrentItem()));
343     }
344   return 1;
345   }
346 
347 
348 // Update button to show menu of other MDI child windows when more than N windows
onUpdOthersWindows(FXObject * sender,FXSelector sel,void *)349 long FXMDIClient::onUpdOthersWindows(FXObject *sender,FXSelector sel,void*){
350   sender->handle(this,((FXSELID(sel)-ID_MDI_OVER_1)<numChildren())?FXSEL(SEL_COMMAND,FXWindow::ID_SHOW):FXSEL(SEL_COMMAND,FXWindow::ID_HIDE),NULL);
351   return 1;
352   }
353 
354 
355 // Show or hide depending on whether there are any windows
onUpdAnyWindows(FXObject * sender,FXSelector,void *)356 long FXMDIClient::onUpdAnyWindows(FXObject *sender,FXSelector,void*){
357   sender->handle(this,getFirst()?FXSEL(SEL_COMMAND,ID_SHOW):FXSEL(SEL_COMMAND,ID_HIDE),NULL);
358   return 1;
359   }
360 
361 
362 // Update restore; gray if no active
onUpdRestore(FXObject * sender,FXSelector sel,void * ptr)363 long FXMDIClient::onUpdRestore(FXObject* sender,FXSelector sel,void* ptr){
364   if(active) return active->handle(sender,sel,ptr);
365   sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
366   return 1;
367   }
368 
369 
370 // Update maximized; gray if no active
onUpdMaximize(FXObject * sender,FXSelector sel,void * ptr)371 long FXMDIClient::onUpdMaximize(FXObject* sender,FXSelector sel,void* ptr){
372   if(active) return active->handle(sender,sel,ptr);
373   sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
374   return 1;
375   }
376 
377 
378 // Update minimized
onUpdMinimize(FXObject * sender,FXSelector sel,void * ptr)379 long FXMDIClient::onUpdMinimize(FXObject* sender,FXSelector sel,void* ptr){
380   if(active) return active->handle(sender,sel,ptr);
381   sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
382   return 1;
383   }
384 
385 
386 // Update close active child
onUpdClose(FXObject * sender,FXSelector sel,void * ptr)387 long FXMDIClient::onUpdClose(FXObject* sender,FXSelector sel,void* ptr){
388   if(active) return active->handle(sender,sel,ptr);
389   sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
390   return 1;
391   }
392 
393 
394 // Update menu's restore button
onUpdMenuWindow(FXObject * sender,FXSelector sel,void * ptr)395 long FXMDIClient::onUpdMenuWindow(FXObject* sender,FXSelector sel,void* ptr){
396   if(active) return active->handle(sender,sel,ptr);
397   sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),NULL);
398   return 1;
399   }
400 
401 
402 // Update menu's restore button
onUpdMenuRestore(FXObject * sender,FXSelector sel,void * ptr)403 long FXMDIClient::onUpdMenuRestore(FXObject* sender,FXSelector sel,void* ptr){
404   if(active) return active->handle(sender,sel,ptr);
405   sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),NULL);
406   return 1;
407   }
408 
409 
410 // Update menu's minimized button
onUpdMenuMinimize(FXObject * sender,FXSelector sel,void * ptr)411 long FXMDIClient::onUpdMenuMinimize(FXObject* sender,FXSelector sel,void* ptr){
412   if(active) return active->handle(sender,sel,ptr);
413   sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),NULL);
414   return 1;
415   }
416 
417 
418 // Update menu's close button
onUpdMenuClose(FXObject * sender,FXSelector sel,void * ptr)419 long FXMDIClient::onUpdMenuClose(FXObject* sender,FXSelector sel,void* ptr){
420   if(active) return active->handle(sender,sel,ptr);
421   sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),NULL);
422   return 1;
423   }
424 
425 
426 // Set the active child
setActiveChild(FXMDIChild * child,FXbool notify)427 FXbool FXMDIClient::setActiveChild(FXMDIChild* child,FXbool notify){
428   FXbool wasmax=FALSE;
429   if(active!=child){
430 
431     if(active){
432 
433       // Was it maximized?
434       wasmax=active->isMaximized();
435 
436       // Deactivate old MDIChild
437       active->handle(this,FXSEL(SEL_DESELECTED,0),(void*)child);     // FIXME should call member function
438 
439       // Restore to normal size if it was maximized
440       if(wasmax) active->restore(notify);
441       }
442 
443     if(child){
444 
445       // Activate new MDIChild
446       child->handle(this,FXSEL(SEL_SELECTED,0),(void*)active);     // FIXME should call member function
447 
448       // Maximize because the old MDIChild was maximized
449       if(wasmax) child->maximize(notify);
450 
451       // Raise it
452       child->raise();
453       }
454 
455     active=child;
456 
457     // Need layout
458     recalc();
459 
460     // GUI update will be needed
461     getApp()->refresh();
462 
463     // Notify target
464     if(notify && target){ target->tryHandle(this,FXSEL(SEL_CHANGED,message),child); }
465 
466     return TRUE;
467     }
468   return FALSE;
469   }
470 
471 
472 // Tile horizontally (actually, prefer wider windows)
onCmdTileHorizontal(FXObject *,FXSelector,void *)473 long FXMDIClient::onCmdTileHorizontal(FXObject*,FXSelector,void*){
474   horizontal(TRUE);
475   return 1;
476   }
477 
478 
479 // Update tile horizontally
onUpdTileHorizontal(FXObject * sender,FXSelector,void *)480 long FXMDIClient::onUpdTileHorizontal(FXObject* sender,FXSelector,void*){
481   sender->handle(this,getFirst()?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
482   return 1;
483   }
484 
485 
486 // Tile vertically (actually, prefer taller windows)
onCmdTileVertical(FXObject *,FXSelector,void *)487 long FXMDIClient::onCmdTileVertical(FXObject*,FXSelector,void*){
488   vertical(TRUE);
489   return 1;
490   }
491 
492 
493 // Update tile vertically
onUpdTileVertical(FXObject * sender,FXSelector,void *)494 long FXMDIClient::onUpdTileVertical(FXObject* sender,FXSelector,void*){
495   sender->handle(this,getFirst()?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
496   return 1;
497   }
498 
499 
500 // Cascade windows
onCmdCascade(FXObject *,FXSelector,void *)501 long FXMDIClient::onCmdCascade(FXObject*,FXSelector,void*){
502   cascade(TRUE);
503   return 1;
504   }
505 
506 
507 // Update cascade
onUpdCascade(FXObject * sender,FXSelector,void *)508 long FXMDIClient::onUpdCascade(FXObject* sender,FXSelector,void*){
509   sender->handle(this,getFirst()?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
510   return 1;
511   }
512 
513 
514 // Pass message to all MDI windows; the crufty loop is because
515 // it is possible for the child receiving the message to be deleted
forallWindows(FXObject * sender,FXSelector sel,void * ptr)516 long FXMDIClient::forallWindows(FXObject* sender,FXSelector sel,void* ptr){
517   register FXWindow *child,*nextchild;
518   for(child=getFirst(); child; child=nextchild){
519     nextchild=child->getNext();
520     if(!child->handle(sender,sel,ptr)) return 0;
521     }
522   return 1;
523   }
524 
525 
526 // Pass message to all different documents; here the complication
527 // is that the whole group of child windows sharing the same
528 // document may be deleted; also, we want to send only ONE of the
529 // document-sharing children a message.
forallDocuments(FXObject * sender,FXSelector sel,void * ptr)530 long FXMDIClient::forallDocuments(FXObject* sender,FXSelector sel,void* ptr){
531   register FXWindow *child,*nextchild,*ch;
532   for(child=getFirst(); child; child=nextchild){
533     nextchild=child->getNext();
534 x:  if(nextchild && nextchild->getTarget()){
535       for(ch=child; ch; ch=ch->getPrev()){
536         if(ch->getTarget()==nextchild->getTarget()){
537           nextchild=nextchild->getNext();
538           goto x;
539           }
540         }
541       }
542     if(!child->handle(sender,sel,ptr)) return 0;
543     }
544   return 1;
545   }
546 
547 
548 // Pass message to all MDI windows whose target is document;
549 // note that the child may be deleted as a result of the message.
forallDocWindows(FXObject * document,FXObject * sender,FXSelector sel,void * ptr)550 long FXMDIClient::forallDocWindows(FXObject* document,FXObject* sender,FXSelector sel,void* ptr){
551   register FXWindow *child,*nextchild;
552   for(child=getFirst(); child; child=nextchild){
553     nextchild=child->getNext();
554     if(child->getTarget()==document){
555       if(!child->handle(sender,sel,ptr)) return 0;
556       }
557     }
558   return 1;
559   }
560 
561 
562 // Activate next child
onCmdActivateNext(FXObject *,FXSelector,void *)563 long FXMDIClient::onCmdActivateNext(FXObject*,FXSelector,void*){
564   if(active && active->getNext()) setActiveChild((FXMDIChild*)active->getNext(),TRUE);
565   return 1;
566   }
567 
568 
569 // Activate next child
onUpdActivateNext(FXObject * sender,FXSelector,void *)570 long FXMDIClient::onUpdActivateNext(FXObject* sender,FXSelector,void*){
571   sender->handle(this,(active && active->getNext())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
572   return 1;
573   }
574 
575 
576 // Activate previous child
onCmdActivatePrev(FXObject *,FXSelector,void *)577 long FXMDIClient::onCmdActivatePrev(FXObject*,FXSelector,void*){
578   if(active && active->getPrev()) setActiveChild((FXMDIChild*)active->getPrev(),TRUE);
579   return 1;
580   }
581 
582 
583 // Activate previous child
onUpdActivatePrev(FXObject * sender,FXSelector,void *)584 long FXMDIClient::onUpdActivatePrev(FXObject* sender,FXSelector,void*){
585   sender->handle(this,(active && active->getPrev())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
586   return 1;
587   }
588 
589 
590 // Delegate all other messages to active child
onDefault(FXObject * sender,FXSelector sel,void * ptr)591 long FXMDIClient::onDefault(FXObject* sender,FXSelector sel,void* ptr){
592   return active && active->handle(sender,sel,ptr);
593   }
594 
595 
596 // Save object to stream
save(FXStream & store) const597 void FXMDIClient::save(FXStream& store) const {
598   FXComposite::save(store);
599   store << active;
600   store << cascadex;
601   store << cascadey;
602   }
603 
604 
605 // Load object from stream
load(FXStream & store)606 void FXMDIClient::load(FXStream& store){
607   FXComposite::load(store);
608   store >> active;
609   store >> cascadex;
610   store >> cascadey;
611   }
612 
613 
614 // Destruct thrashes object
~FXMDIClient()615 FXMDIClient::~FXMDIClient(){
616   active=(FXMDIChild*)-1L;
617   }
618 
619 }
620