2 Copyright 1995-2010, The AROS Development Team. All rights reserved.
3 Copyright 2001-2003, The MorphOS Development Team. All Rights Reserved.
6 Responsible for executing deferred Intuition actions like MoveWindow,
7 SizeWindow, ActivateWindow, etc.
10 #include <proto/exec.h>
11 #include <proto/intuition.h>
12 #include <proto/alib.h>
13 #include <proto/layers.h>
14 #include <proto/graphics.h>
15 #include <proto/keymap.h>
16 #include <proto/input.h>
17 #include <exec/memory.h>
18 #include <exec/alerts.h>
19 #include <exec/interrupts.h>
20 #include <exec/ports.h>
21 #include <intuition/intuition.h>
22 #include <intuition/intuitionbase.h>
23 #include <intuition/gadgetclass.h>
24 #include <intuition/cghooks.h>
25 #include <intuition/sghooks.h>
26 #include <devices/input.h>
27 #include <devices/inputevent.h>
28 #include "inputhandler.h"
30 #include "boopsigadgets.h"
31 #include "boolgadgets.h"
32 #include "propgadgets.h"
33 #include "strgadgets.h"
35 #include "intuition_intern.h" /* EWFLG_xxx */
36 #include "inputhandler_support.h"
37 #include "inputhandler_actions.h"
42 #include <aros/debug.h>
44 #define LOCK_ACTIONS() ObtainSemaphore(&GetPrivIBase(IntuitionBase)->IntuiActionLock);
45 #define UNLOCK_ACTIONS() ReleaseSemaphore(&GetPrivIBase(IntuitionBase)->IntuiActionLock);
48 static void move_family(struct Window
*, int , int);
51 /*******************************************************************************************************/
53 static void CheckLayerRefresh(struct Layer
*lay
, struct Screen
*targetscreen
,
54 struct IntuitionBase
*IntuitionBase
)
56 //if (lay->Flags & LAYERREFRESH)
58 struct Window
*win
= (struct Window
*)lay
->Window
;
60 if (lay
== targetscreen
->BarLayer
)
62 RenderScreenBar(targetscreen
, TRUE
, IntuitionBase
);
66 /* Does it belong to a GZZ window and is it
67 the outer window of that GZZ window? */
68 if (IS_GZZWINDOW(win
) && (lay
== BLAYER(win
)))
70 /* simply refresh that window's frame */
71 Gad_BeginUpdate(lay
, IntuitionBase
);
72 int_refreshwindowframe(win
,REFRESHGAD_BORDER
,0,IntuitionBase
);
73 lay
->Flags
&= ~LAYERREFRESH
;
74 Gad_EndUpdate(lay
, TRUE
, IntuitionBase
);
76 /* Is it the window layer ? */
77 else if (lay
== WLAYER(win
))
79 WindowNeedsRefresh(win
, IntuitionBase
);
81 /* Otherwise, it's a requester. */
84 struct Requester
*req
;
86 for (req
= win
->FirstRequest
; req
&& req
->ReqLayer
!= lay
; req
= req
->OlderRequest
);
90 /* FIXME: should send an IDCMP refresh message too. */
91 Gad_BeginUpdate(lay
, IntuitionBase
);
92 render_requester(req
, IntuitionBase
);
93 lay
->Flags
&= ~LAYERREFRESH
;
94 Gad_EndUpdate(lay
, TRUE
, IntuitionBase
);
99 } /* if (lay->Flags & LAYERREFRESH) */
102 /*******************************************************************************************************/
104 void CheckLayers(struct Screen
*screen
, struct IntuitionBase
*IntuitionBase
)
108 LOCK_REFRESH(screen
);
110 for (L
= screen
->LayerInfo
.top_layer
; L
; L
= L
->back
)
112 if (L
->Flags
& LAYERREFRESH
)
114 CheckLayerRefresh(L
, screen
, IntuitionBase
);
118 UNLOCK_REFRESH(screen
);
121 void WindowSizeWillChange(struct Window
*targetwindow
, WORD dx
, WORD dy
,
122 struct IntuitionBase
*IntuitionBase
)
124 struct Rectangle
*clipto
= NULL
;
125 struct Rectangle final_innerrect
;
127 /* Erase the old frame on the right/lower side if
128 new size is bigger than old size
131 D(bug("********* WindowSizeWillChange ******** dx = %d dy = %d\n", dx
, dy
));
133 if (AVOID_WINBORDERERASE
)
135 final_innerrect
.MinX
= targetwindow
->BorderLeft
;
136 final_innerrect
.MinY
= targetwindow
->BorderTop
;
137 final_innerrect
.MaxX
= targetwindow
->Width
+ dx
- 1 - targetwindow
->BorderRight
;
138 final_innerrect
.MaxY
= targetwindow
->Height
+ dy
- 1 - targetwindow
->BorderBottom
;
139 clipto
= &final_innerrect
;
142 if ( ((dx
> 0) && (targetwindow
->BorderRight
> 0)) ||
143 ((dy
> 0) && (targetwindow
->BorderBottom
> 0)) )
145 struct RastPort
*rp
= targetwindow
->BorderRPort
;
146 struct Layer
*L
= (BLAYER(targetwindow
)) ? BLAYER(targetwindow
) : WLAYER(targetwindow
);
147 struct Rectangle rect
;
148 struct Region
*oldclipregion
;
153 ** In case a clip region is installed then I have to
154 ** install the regular cliprects of the layer
155 ** first. Otherwise the frame might not get cleared correctly.
160 oldclipregion
= InstallClipRegion(L
, NULL
);
162 ScrollX
= L
->Scroll_X
;
163 ScrollY
= L
->Scroll_Y
;
168 if ((dx
> 0) && (targetwindow
->BorderRight
> 0))
170 rect
.MinX
= targetwindow
->Width
- targetwindow
->BorderRight
;
172 rect
.MaxX
= targetwindow
->Width
- 1;
173 rect
.MaxY
= targetwindow
->Height
- 1;
175 OrRectRegion(L
->DamageList
, &rect
);
176 L
->Flags
|= LAYERREFRESH
;
178 if (!AVOID_WINBORDERERASE
|| AndRectRect(&rect
, &final_innerrect
, &rect
))
180 EraseRect(rp
, rect
.MinX
, rect
.MinY
, rect
.MaxX
, rect
.MaxY
);
185 if ((dy
> 0) && (targetwindow
->BorderBottom
> 0))
189 rect
.MinY
= targetwindow
->Height
- targetwindow
->BorderBottom
;
190 rect
.MaxX
= targetwindow
->Width
- 1;
191 rect
.MaxY
= targetwindow
->Height
- 1;
193 OrRectRegion(L
->DamageList
, &rect
);
194 L
->Flags
|= LAYERREFRESH
;
196 if (!AVOID_WINBORDERERASE
|| AndRectRect(&rect
, &final_innerrect
, &rect
))
198 EraseRect(rp
, rect
.MinX
, rect
.MinY
, rect
.MaxX
, rect
.MaxY
);
204 ** Reinstall the clipregions rectangles if there are any.
206 if (NULL
!= oldclipregion
)
208 InstallClipRegion(L
, oldclipregion
);
211 L
->Scroll_X
= ScrollX
;
212 L
->Scroll_Y
= ScrollY
;
216 } /* if ( ((dx > 0) && (targetwindow->BorderRight > 0)) || ((dy > 0) && (targetwindow->BorderBottom > 0)) ) */
218 /* Before resizing the layers eraserect the area of all
219 GFLG_REL??? gadgets and add the area to the damagelist */
221 EraseRelGadgetArea(targetwindow
, clipto
, FALSE
, IntuitionBase
);
225 /*******************************************************************************************************/
227 void WindowSizeHasChanged(struct Window
*targetwindow
, WORD dx
, WORD dy
,
228 BOOL is_sizewindow
, struct IntuitionBase
*IntuitionBase
)
230 struct IIHData
*iihdata
= (struct IIHData
*)GetPrivIBase(IntuitionBase
)->InputHandler
->is_Data
;
233 D(bug("********* WindowSizeHasChanged ********\n"));
235 lay
= (BLAYER(targetwindow
)) ? BLAYER(targetwindow
) : WLAYER(targetwindow
);
237 /* Fix GadgetInfo domain if there is an active gadget in window
240 if ((iihdata
->ActiveGadget
) && (targetwindow
== iihdata
->GadgetInfo
.gi_Window
))
242 /* In case of active window drag/size gadget the master drag/size gadget never
243 has GZZ flag set, so pass in real gadget (ActiveSysGadget) */
245 GetGadgetDomain(iihdata
->ActiveSysGadget
? iihdata
->ActiveSysGadget
: iihdata
->ActiveGadget
,
246 iihdata
->GadgetInfo
.gi_Screen
,
247 iihdata
->GadgetInfo
.gi_Window
,
249 &iihdata
->GadgetInfo
.gi_Domain
);
252 /* Relayout GFLG_REL??? gadgets */
253 DoGMLayout(targetwindow
->FirstGadget
, targetwindow
, NULL
, -1, FALSE
, IntuitionBase
);
255 /* Add the new area of all GFLG_REL??? gadgets to the damagelist, but
256 don't EraseRect() as the gadgets will be re-rendered at their new
260 struct Rectangle innerrect
;
262 innerrect
.MinX
= targetwindow
->BorderLeft
;
263 innerrect
.MinY
= targetwindow
->BorderTop
;
264 innerrect
.MaxX
= targetwindow
->Width
- 1 - targetwindow
->BorderRight
;
265 innerrect
.MaxY
= targetwindow
->Height
- 1 - targetwindow
->BorderBottom
;
267 EraseRelGadgetArea(targetwindow
, AVOID_WINBORDERERASE
? &innerrect
: NULL
, TRUE
, IntuitionBase
);
270 /* If new size is smaller than old size add right/bottom
271 frame to damagelist */
272 if ( ((dx
< 0) && (targetwindow
->BorderRight
> 0)) ||
273 ((dx
> 0) && (targetwindow
->BorderTop
> 0)) ||
274 ((dy
< 0) && (targetwindow
->BorderBottom
> 0)) )
276 struct Rectangle rect
;
280 if ((dx
< 0) && (targetwindow
->BorderRight
> 0))
282 rect
.MinX
= targetwindow
->Width
- targetwindow
->BorderRight
;
284 rect
.MaxX
= targetwindow
->Width
- 1;
285 rect
.MaxY
= targetwindow
->Height
- 1;
287 OrRectRegion(lay
->DamageList
, &rect
);
288 lay
->Flags
|= LAYERREFRESH
;
291 if ((dx
> 0) && (targetwindow
->BorderTop
> 0))
295 rect
.MaxX
= targetwindow
->Width
- 1;
296 rect
.MaxY
= targetwindow
->BorderTop
- 1;
298 OrRectRegion(lay
->DamageList
, &rect
);
299 lay
->Flags
|= LAYERREFRESH
;
302 if ((dy
< 0) && (targetwindow
->BorderBottom
> 0))
305 rect
.MinY
= targetwindow
->Height
- targetwindow
->BorderBottom
;
306 rect
.MaxX
= targetwindow
->Width
- 1;
307 rect
.MaxY
= targetwindow
->Height
- 1;
309 OrRectRegion(lay
->DamageList
, &rect
);
310 lay
->Flags
|= LAYERREFRESH
;
315 } /* if ( ((dx < 0) && (targetwindow->BorderRight > 0)) || ((dy < 0) && (targetwindow->BorderBottom > 0)) ) */
317 ((struct IntWindow
*)(targetwindow
))->specialflags
|= SPFLAG_LAYERRESIZED
;
320 if (IS_GZZWINDOW(targetwindow
))
322 lay
= targetwindow
->BorderRPort
->Layer
;
324 if (lay
->Flags
& LAYERREFRESH
)
326 Gad_BeginUpdate(lay
, IntuitionBase
);
327 RefreshWindowFrame(targetwindow
);
328 lay
->Flags
&= ~LAYERREFRESH
;
329 Gad_EndUpdate(lay
, TRUE
, IntuitionBase
);
332 lay
= targetwindow
->WLayer
;
334 if (lay
->Flags
& LAYERREFRESH
)
336 Gad_BeginUpdate(lay
, IntuitionBase
);
337 int_refreshglist(targetwindow
->FirstGadget
, targetwindow
, NULL
, -1, 0, REFRESHGAD_BORDER
, IntuitionBase
);
338 Gad_EndUpdate(lay
, IS_NOCAREREFRESH(targetwindow
), IntuitionBase
);
344 lay
= targetwindow
->WLayer
;
346 if (lay
->Flags
& LAYERREFRESH
)
348 Gad_BeginUpdate(lay
, IntuitionBase
);
349 RefreshWindowFrame(targetwindow
);
350 int_refreshglist(targetwindow
->FirstGadget
, targetwindow
, NULL
, -1, 0, REFRESHGAD_BORDER
, IntuitionBase
);
351 Gad_EndUpdate(lay
, IS_NOCAREREFRESH(targetwindow
), IntuitionBase
);
355 lay
= targetwindow
->WLayer
;
357 if (IS_NOCAREREFRESH(targetwindow
))
360 lay
->Flags
&= ~LAYERREFRESH
;
368 /* Send IDCMP_NEWSIZE to resized window */
370 ih_fire_intuimessage(targetwindow
,
377 if (ie
= AllocInputEvent(iihdata
))
379 ie
->ie_Class
= IECLASS_EVENT
;
380 ie
->ie_Code
= IECODE_NEWSIZE
;
381 ie
->ie_EventAddress
= targetwindow
;
382 CurrentTime(&ie
->ie_TimeStamp
.tv_secs
, &ie
->ie_TimeStamp
.tv_micro
);
385 /* Send IDCMP_CHANGEWINDOW to resized window */
387 ih_fire_intuimessage(targetwindow
,
396 /*******************************************************************************************************/
398 void DoMoveSizeWindow(struct Window
*targetwindow
, LONG NewLeftEdge
, LONG NewTopEdge
,
399 LONG NewWidth
, LONG NewHeight
, BOOL send_newsize
, struct IntuitionBase
*IntuitionBase
)
401 struct IIHData
*iihdata
= (struct IIHData
*)GetPrivIBase(IntuitionBase
)->InputHandler
->is_Data
;
402 //struct IntWindow *w = (struct IntWindow *)targetwindow;
403 struct Layer
*targetlayer
= WLAYER(targetwindow
)/*, *L*/;
404 struct Requester
*req
;
405 struct InputEvent
*ie
;
406 LONG OldLeftEdge
= targetwindow
->LeftEdge
;
407 LONG OldTopEdge
= targetwindow
->TopEdge
;
408 LONG OldWidth
= targetwindow
->Width
;
409 LONG OldHeight
= targetwindow
->Height
;
410 LONG pos_dx
, pos_dy
, size_dx
, size_dy
;
412 /* correct new window coords if necessary */
414 FixWindowCoords(targetwindow
, &NewLeftEdge
, &NewTopEdge
, &NewWidth
, &NewHeight
,IntuitionBase
);
416 D(bug("DoMoveSizeWindow to %d,%d %d x %d\n", NewLeftEdge
, NewTopEdge
, NewWidth
, NewHeight
));
418 pos_dx
= NewLeftEdge
- OldLeftEdge
;
419 pos_dy
= NewTopEdge
- OldTopEdge
;
420 size_dx
= NewWidth
- OldWidth
;
421 size_dy
= NewHeight
- OldHeight
;
423 LOCK_REFRESH(targetwindow
->WScreen
);
425 /* jDc: intuition 68k doesn't care about that */
426 // if (pos_dx || pos_dy || size_dx || size_dy)
429 if (size_dx
|| size_dy
)
431 WindowSizeWillChange(targetwindow
, size_dx
, size_dy
, IntuitionBase
);
434 targetwindow
->LeftEdge
+= pos_dx
;
435 targetwindow
->TopEdge
+= pos_dy
;
437 targetwindow
->RelLeftEdge
+= pos_dx
;
438 targetwindow
->RelTopEdge
+= pos_dy
;
441 targetwindow
->Width
= NewWidth
;
442 targetwindow
->Height
= NewHeight
;
443 targetwindow
->GZZWidth
= targetwindow
->Width
- targetwindow
->BorderLeft
- targetwindow
->BorderRight
;
444 targetwindow
->GZZHeight
= targetwindow
->Height
- targetwindow
->BorderTop
- targetwindow
->BorderBottom
;
446 /* check for GZZ window */
447 if (BLAYER(targetwindow
))
449 /* move outer window first */
450 MoveSizeLayer(BLAYER(targetwindow
), pos_dx
, pos_dy
, size_dx
, size_dy
);
453 MoveSizeLayer(targetlayer
, pos_dx
, pos_dy
, size_dx
, size_dy
);
455 for (req
= targetwindow
->FirstRequest
; req
; req
= req
->OlderRequest
)
457 struct Layer
*layer
= req
->ReqLayer
;
462 int left
, top
, right
, bottom
;
464 left
= NewLeftEdge
+ req
->LeftEdge
;
465 top
= NewTopEdge
+ req
->TopEdge
;
466 right
= left
+ req
->Width
- 1;
467 bottom
= top
+ req
->Height
- 1;
469 if (left
> NewLeftEdge
+ NewWidth
- 1)
470 left
= NewLeftEdge
+ NewWidth
- 1;
472 if (top
> NewTopEdge
+ NewHeight
- 1)
473 top
= NewTopEdge
+ NewHeight
- 1;
475 if (right
> NewLeftEdge
+ NewWidth
- 1)
476 right
= NewLeftEdge
+ NewWidth
- 1;
478 if (bottom
> NewTopEdge
+ NewHeight
- 1)
479 bottom
= NewTopEdge
+ NewHeight
- 1;
481 dx
= left
- layer
->bounds
.MinX
;
482 dy
= top
- layer
->bounds
.MinY
;
483 dw
= right
- left
- layer
->bounds
.MaxX
+ layer
->bounds
.MinX
;
484 dh
= bottom
- top
- layer
->bounds
.MaxY
+ layer
->bounds
.MinY
;
486 MoveSizeLayer(layer
, dx
, dy
, dw
, dh
);
491 if (w
->ZipLeftEdge
!= ~0) w
->ZipLeftEdge
= OldLeftEdge
;
492 if (w
->ZipTopEdge
!= ~0) w
->ZipTopEdge
= OldTopEdge
;
493 if (w
->ZipWidth
!= ~0) w
->ZipWidth
= OldWidth
;
494 if (w
->ZipHeight
!= ~0) w
->ZipHeight
= OldHeight
;
497 if (pos_dx
|| pos_dy
)
499 UpdateMouseCoords(targetwindow
);
501 if (HAS_CHILDREN(targetwindow
))
502 move_family(targetwindow
, pos_dx
, pos_dy
);
506 // } /* if (pos_dx || pos_dy || size_dx || size_dy) */
508 if (size_dx
|| size_dy
)
510 WindowSizeHasChanged(targetwindow
, size_dx
, size_dy
, FALSE
, IntuitionBase
);
513 ih_fire_intuimessage(targetwindow
,
521 /* Send IDCMP_NEWSIZE and IDCMP_CHANGEWINDOW to resized window, even
522 if there was no resizing/position change at all. BGUI for example
525 ih_fire_intuimessage(targetwindow
,
531 if ((ie
= AllocInputEvent(iihdata
)))
533 ie
->ie_Class
= IECLASS_EVENT
;
534 ie
->ie_Code
= IECODE_NEWSIZE
;
535 ie
->ie_EventAddress
= targetwindow
;
536 CurrentTime(&ie
->ie_TimeStamp
.tv_secs
, &ie
->ie_TimeStamp
.tv_micro
);
540 // jDc: CheckLayers calls LOCK_REFRESH, so there's no reason to UNLOCK here!
541 // UNLOCK_REFRESH(targetwindow->WScreen);
543 CheckLayers(targetwindow
->WScreen
, IntuitionBase
);
545 UNLOCK_REFRESH(targetwindow
->WScreen
);
548 if (size_dx
|| size_dy
)
550 if (!(((struct IntWindow
*)targetwindow
)->CustomShape
))
552 struct wdpWindowShape shapemsg
;
553 struct Region
*shape
;
554 shapemsg
.MethodID
= WDM_WINDOWSHAPE
;
555 shapemsg
.wdp_Width
= targetwindow
->Width
;
556 shapemsg
.wdp_Height
= targetwindow
->Height
;
557 shapemsg
.wdp_Window
= targetwindow
;
558 shapemsg
.wdp_TrueColor
= (((struct IntScreen
*)targetwindow
->WScreen
)->DInfo
.dri
.dri_Flags
& DRIF_DIRECTCOLOR
);
559 shapemsg
.wdp_UserBuffer
= ((struct IntWindow
*)targetwindow
)->DecorUserBuffer
;
560 shape
= DoMethodA(((struct IntScreen
*)(targetwindow
->WScreen
))->WinDecorObj
, (Msg
)&shapemsg
);
562 if (((struct IntWindow
*)targetwindow
)->OutlineShape
) DisposeRegion(((struct IntWindow
*)targetwindow
)->OutlineShape
);
563 ((struct IntWindow
*)targetwindow
)->OutlineShape
= shape
;
564 ChangeWindowShape(targetwindow
, shape
, NULL
);
565 ((struct IntWindow
*)targetwindow
)->CustomShape
= FALSE
;
572 /*******************************************************************************************************/
574 void DoSyncAction(void (*func
)(struct IntuiActionMsg
*, struct IntuitionBase
*),
575 struct IntuiActionMsg
*msg
,
576 struct IntuitionBase
*IntuitionBase
)
578 struct IIHData
*iihd
= (struct IIHData
*)GetPrivIBase(IntuitionBase
)->InputHandler
->is_Data
;
579 struct Task
*me
= FindTask(NULL
);
581 if (me
== iihd
->InputDeviceTask
)
583 func(msg
, IntuitionBase
);
589 struct InputEvent ie
;
595 ObtainSemaphore(&GetPrivIBase(IntuitionBase
)->IntuiActionLock
);
596 AddTail((struct List
*)GetPrivIBase(IntuitionBase
)->IntuiActionQueue
, (struct Node
*)msg
);
597 ReleaseSemaphore(&GetPrivIBase(IntuitionBase
)->IntuiActionLock
);
599 port
.mp_Flags
= PA_SIGNAL
;
600 port
.mp_SigTask
= me
;
601 port
.mp_SigBit
= SIGB_INTUITION
;
602 NEWLIST(&port
.mp_MsgList
);
604 req
.io_Message
.mn_ReplyPort
= &port
;
605 req
.io_Device
= GetPrivIBase(IntuitionBase
)->InputIO
->io_Device
;
606 req
.io_Unit
= GetPrivIBase(IntuitionBase
)->InputIO
->io_Unit
;
607 req
.io_Command
= IND_WRITEEVENT
;
608 req
.io_Length
= sizeof(ie
);
611 ie
.ie_Class
= IECLASS_NULL
;
618 Wait(SIGF_INTUITION
);
624 /*******************************************************************************************************/
626 BOOL
DoASyncAction(void (*func
)(struct IntuiActionMsg
*, struct IntuitionBase
*),
627 struct IntuiActionMsg
*msg
, ULONG size
,
628 struct IntuitionBase
*IntuitionBase
)
630 struct IIHData
*iihd
= (struct IIHData
*)GetPrivIBase(IntuitionBase
)->InputHandler
->is_Data
;
631 struct Task
*me
= FindTask(NULL
);
632 struct IntuiActionMsg
*new_msg
;
634 if (me
== iihd
->InputDeviceTask
)
636 func(msg
, IntuitionBase
);
639 else if ((new_msg
= AllocVecPooled(iihd
->ActionsMemPool
,size
)))
641 new_msg
->handler
= func
;
642 new_msg
->task
= NULL
;
643 if (size
> sizeof(*msg
))
645 CopyMem(msg
+ 1, new_msg
+ 1, size
- sizeof(*msg
));
648 ObtainSemaphore(&GetPrivIBase(IntuitionBase
)->IntuiActionLock
);
649 AddTail((struct List
*)GetPrivIBase(IntuitionBase
)->IntuiActionQueue
, (struct Node
*)new_msg
);
650 ReleaseSemaphore(&GetPrivIBase(IntuitionBase
)->IntuiActionLock
);
660 /*******************************************************************************************************/
662 void HandleIntuiActions(struct IIHData
*iihdata
,
663 struct IntuitionBase
*IntuitionBase
)
665 struct IntuiActionMsg
*am
;
667 D(bug("Handle Intuition action messages\n"));
669 if (iihdata
->ActiveSysGadget
)
671 D(bug("Handle Intuition action messages. Doing nothing because of active drag or resize gadget!\n"));
678 am
= (struct IntuiActionMsg
*)RemHead((struct List
*)&iihdata
->IntuiActionQueue
);
684 am
->handler(am
, IntuitionBase
);
690 Signal(am
->task
, SIGF_INTUITION
);
695 FreeVecPooled(iihdata
->ActionsMemPool
,am
);
699 D(bug("Intuition action messages handled\n"));
703 static void move_family(struct Window
* w
, int dx
, int dy
)
705 struct Window
* _w
= w
->firstchild
;
711 if (HAS_CHILDREN(_w
))
712 move_family(_w
,dx
,dy
);