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