_screen is only valid between show/hide.
[AROS.git] / rom / intuition / closewindow.c
blob31dcab4c7a6f1341b639dcbd0d9c3f9c4e6e158a
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
4 $Id$
5 */
7 #include <proto/exec.h>
8 #include <proto/graphics.h>
9 #include <proto/layers.h>
10 #include <proto/timer.h>
11 #include "intuition_intern.h"
12 #include "inputhandler.h"
13 #include "inputhandler_actions.h"
14 #include "inputhandler_support.h"
15 //#include "segtracker.h"
16 #include <intuition/gadgetclass.h>
18 #ifndef DEBUG_CloseWindow
19 # define DEBUG_CloseWindow 1
20 #endif
21 #undef DEBUG
22 #if DEBUG_CloseWindow
23 # define DEBUG 1
24 #endif
25 # include <aros/debug.h>
27 /******************************************************************************/
29 #define MUST_UNLOCK_SCREEN(window,screen) (((GetPrivScreen(screen)->pubScrNode != NULL) && \
30 (window->MoreFlags & WMFLG_DO_UNLOCKPUBSCREEN)) ? TRUE : FALSE)
32 struct CloseWindowActionMsg
34 struct IntuiActionMsg msg;
35 struct Window *window;
38 VOID int_closewindow(struct CloseWindowActionMsg *msg,
39 struct IntuitionBase *IntuitionBase);
41 /*****************************************************************************
43 NAME */
44 #include <proto/intuition.h>
46 AROS_LH1(void, CloseWindow,
48 /* SYNOPSIS */
49 AROS_LHA(struct Window *, window, A0),
51 /* LOCATION */
52 struct IntuitionBase *, IntuitionBase, 12, Intuition)
54 /* FUNCTION
55 Closes a window. Depending on the display, this might not happen
56 at the time when this function returns, but you must not use
57 the window pointer after this function has been called.
59 INPUTS
60 window - The window to close
62 RESULT
63 None.
65 NOTES
66 The window might not have disappeared when this function returns.
68 EXAMPLE
70 BUGS
72 SEE ALSO
73 OpenWindow(), OpenWindowTagList()
75 INTERNALS
77 *****************************************************************************/
79 AROS_LIBFUNC_INIT
81 struct CloseWindowActionMsg msg;
82 struct MsgPort *userport;
83 #if USE_IDCMPUPDATE_MESSAGECACHE
84 struct IntuiMessage *messagecache;
85 #endif
86 struct Screen *screen;
87 BOOL do_unlockscreen;
89 DEBUG_CLOSEWINDOW(dprintf("CloseWindow: Window 0x%lx\n", window));
91 D(bug("CloseWindow (%p)\n", window));
93 if ( window == NULL )
95 ReturnVoid ("CloseWindow");
98 FireScreenNotifyMessage((IPTR) window, SNOTIFY_BEFORE_CLOSEWINDOW, IntuitionBase);
101 screen = window->WScreen;
102 do_unlockscreen = MUST_UNLOCK_SCREEN(window, screen);
104 #ifndef __MORPHOS__
105 /* We take a very simple approach to avoid race conditions with the
106 intuition input handler running on input.device's task:
107 We just send it a msg about closing the window
109 if (HAS_CHILDREN(window))
111 struct Window * cw = window->firstchild;
113 * First close all its children, we could also return
114 * a failure value which newer apps that use child windows
115 * have to look at.
117 while (cw)
119 struct Window * _cw;
121 _cw = cw->nextchild;
122 CloseWindow(cw);
123 cw = _cw;
128 if (IS_CHILD(window))
131 * Unlink the window from its parent or
132 * out of the list of child windows.
134 if (window->parent->firstchild == window)
135 window->parent->firstchild = window->nextchild;
136 else
137 window->prevchild->nextchild = window->nextchild;
139 if (window->nextchild)
140 window->nextchild->prevchild = window->prevchild;
143 #endif
145 /* We must save this here, because after we have returned from
146 the Wait() the window is gone */
147 userport = window->UserPort;
149 #if USE_IDCMPUPDATE_MESSAGECACHE
150 messagecache = IW(window)->messagecache;
151 #endif
153 DEBUG_CLOSEWINDOW(dprintf("CloseWindow: Userport 0x%lx\n", userport));
155 DEBUG_CLOSEWINDOW(dprintf("CloseWindow: DoSyncAction\n"));
157 #ifdef USEWINDOWLOCK
158 /* wait until other open/close && move/size && menus actions are finished */
159 if (!(FindTask(0) == ((struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data)->InputDeviceTask))
161 ObtainSemaphore(&GetPrivIBase(IntuitionBase)->WindowLock);
163 #endif
165 msg.window = window;
166 DoSyncAction((APTR)int_closewindow, &msg.msg, IntuitionBase);
168 #ifdef USEWINDOWLOCK
169 if (!(FindTask(0) == ((struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data)->InputDeviceTask))
171 ReleaseSemaphore(&GetPrivIBase(IntuitionBase)->WindowLock);
173 #endif
175 if (do_unlockscreen) UnlockPubScreen(NULL, screen);
177 /* As of now intuition has removed us from the list of
178 windows, and we will receive no more messages
180 #if USE_IDCMPUPDATE_MESSAGECACHE
181 if (messagecache)
183 messagecache->IDCMPWindow = 0;//zero or we'll trash mem in inputhandler!
184 messagecache->Code = 0;
185 messagecache->Qualifier = 0;
186 ReplyMsg(&messagecache->ExecMessage);
188 #endif
190 if (userport)
192 struct IntuiMessage *im;
194 DEBUG_CLOSEWINDOW(dprintf("CloseWindow: Reply UserPort Msgs\n"));
195 while ((im = (struct IntuiMessage *) GetMsg (userport)))
197 im->IDCMPWindow = 0;
198 im->Code = 0;
199 im->Qualifier = 0;
200 ReplyMsg ((struct Message *)im);
203 /* Delete message port */
204 DeleteMsgPort (userport);
207 FireScreenNotifyMessage((IPTR) window, SNOTIFY_AFTER_CLOSEWINDOW, IntuitionBase);
209 DEBUG_CLOSEWINDOW(dprintf("CloseWindow: done\n"));
210 ReturnVoid ("CloseWindow");
211 AROS_LIBFUNC_EXIT
212 } /* CloseWindow */
214 /******************************************************************************/
217 /* This is called from the intuition input handler */
218 VOID int_closewindow(struct CloseWindowActionMsg *msg,
219 struct IntuitionBase *IntuitionBase)
221 /* Free everything except the application's messageport */
222 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
223 struct LayersBase *LayersBase = GetPrivIBase(IntuitionBase)->LayersBase;
224 struct Window *window, *win2;
225 struct Screen *screen;
226 struct IIHData *iihd;
227 ULONG lock;
229 window = msg->window;
231 D(bug("CloseWindow (%p)\n", window));
233 RemoveResourceFromList(window, RESOURCE_WINDOW, IntuitionBase);
235 iihd = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
237 /* if there is an active gadget in the window being closed, then make
238 it inactive */
239 if (iihd->ActiveGadget &&
240 !IS_SCREEN_GADGET(iihd->ActiveGadget) &&
241 (iihd->GadgetInfo.gi_Window == window))
243 struct Gadget *gadget = iihd->ActiveGadget;
245 switch(gadget->GadgetType & GTYP_GTYPEMASK)
247 case GTYP_CUSTOMGADGET:
249 struct gpGoInactive gpgi;
251 gpgi.MethodID = GM_GOINACTIVE;
252 gpgi.gpgi_GInfo = &iihd->GadgetInfo;
253 gpgi.gpgi_Abort = 1;
255 Locked_DoMethodA(window, gadget, (Msg)&gpgi, IntuitionBase);
257 if (iihd->ActiveSysGadget)
259 gadget = iihd->ActiveSysGadget;
260 iihd->ActiveSysGadget = NULL;
262 if (IS_BOOPSI_GADGET(gadget))
264 Locked_DoMethodA(window, gadget, (Msg)&gpgi, IntuitionBase);
268 break;
270 case GTYP_STRGADGET:
271 case GTYP_BOOLGADGET:
272 gadget->Flags &= ~GFLG_SELECTED;
273 break;
276 gadget->Activation &= ~GACT_ACTIVEGADGET;
278 iihd->ActiveGadget = NULL;
281 /* Need this in case of a window created under the input.device task context */
282 screen = window->WScreen;
284 /* Check if there are still some requesters */
285 //jDc: do NOT use this! if there is a requester without ACTIVE flag set this routine will buysloop!
286 //jDc: moved this stuff down to layer dispose stuff!
287 /* while (window->FirstRequest)
288 EndRequest(window->FirstRequest, window);*/
290 lock = LockIBase (0);
292 if (window == IntuitionBase->ActiveWindow)
293 IntuitionBase->ActiveWindow = NULL;
294 if (window == iihd->NewActWindow) iihd->NewActWindow = NULL;
296 /* Remove window from the parent/descendant chain and find next active window
299 ** before: parent win xyz
300 ** \
301 ** \
302 ** deadwindow window
303 ** /
304 ** /
305 ** /
306 ** descendant win abc
308 ** after: parent win xyz
309 ** |
310 ** |
311 ** |
312 ** descendant win abc
316 if (window->Descendant)
317 window->Descendant->Parent = window->Parent;
318 if (window->Parent)
319 window->Parent->Descendant = window->Descendant;
321 /* Was this the active window? */
322 if (!IntuitionBase->ActiveWindow)
324 /* If so, we need to find out which window to make
325 active now. We first check whether we have a "parent",
326 which is a window that was open before the one we're closing. */
327 if (window->Parent)
328 ActivateWindow (window->Parent);
329 else
330 /* Otherwise, we find out which was the latest one, and activate it.
331 It's debatable whether this is the best policy, but this is how
332 AmigaOS(TM) does it. */
333 if ((win2 = window->Descendant))
335 for (;win2->Descendant; win2 = win2->Descendant);
336 ActivateWindow (win2);
340 /* Make sure the Screen's window list is still valid */
342 if (window == window->WScreen->FirstWindow)
344 window->WScreen->FirstWindow = window->NextWindow;
346 else if ((win2 = window->WScreen->FirstWindow))
348 while (win2->NextWindow)
350 if (win2->NextWindow == window)
352 win2->NextWindow = window->NextWindow;
353 break;
355 win2 = win2->NextWindow;
359 UnlockIBase (lock);
361 #ifdef TIMEVALWINDOWACTIVATION
362 if (window->WScreen->FirstWindow && !IntuitionBase->ActiveWindow)
364 struct Window *neww = 0,*scanw = 0;
366 for (scanw = window->WScreen->FirstWindow; scanw ; scanw = scanw->NextWindow)
368 if (neww)
370 if ((IW(scanw)->activationtime.tv_secs > IW(neww)->activationtime.tv_secs) ||
371 ((IW(scanw)->activationtime.tv_secs == IW(neww)->activationtime.tv_secs) && (IW(scanw)->activationtime.tv_micro > IW(neww)->activationtime.tv_micro)))
373 neww = scanw;
377 if (!neww) neww = scanw;
380 if (neww) ActivateWindow(neww);
383 #endif
385 /* Free resources */
387 LOCK_REFRESH(screen);
389 /* IFont may be NULL if we are called from an OpenWindow failure */
390 if (window->IFont)
391 CloseFont (window->IFont);
393 #ifdef DAMAGECACHE
394 if (IW(window)->trashregion) DisposeRegion(IW(window)->trashregion);
395 #endif
397 if (window->FirstRequest)
399 struct Requester *r = window->FirstRequest;
401 while (r)
403 if (r->ReqLayer) DeleteLayer(0,r->ReqLayer);
404 r->ReqLayer = 0;
405 r = r->OlderRequest;
409 // remove transparency!
410 #ifdef SKINS
411 if (WLAYER(window))
413 InstallTransparentRegionHook(WLAYER(window),NULL);
414 InstallTransparentRegion(WLAYER(window),NULL);
417 if (((struct IntWindow *)(window))->transpregion) DisposeRegion(((struct IntWindow *)(window))->transpregion);
418 #endif
420 /* Let the driver clean up. Driver will dealloc window's rastport */
421 intui_CloseWindow (window, IntuitionBase);
423 /* jDc: trash the screen pointer to avoid unnecessary checks in WindowValid() and
424 memory corruption */
425 window->WScreen = (struct Screen *)0xC0DEBAD0;
427 /* Remove the Window Outline Shape */
428 if (((struct IntWindow *)window)->OutlineShape) DisposeRegion(((struct IntWindow *)window)->OutlineShape);
429 /* Push ExitScreen Message to the Screensdecoration Class */
430 struct wdpExitWindow wemsg;
432 wemsg.MethodID = WDM_EXITWINDOW;
433 wemsg.wdp_UserBuffer = ((struct IntWindow *)window)->DecorUserBuffer;
434 wemsg.wdp_TrueColor = (((struct IntScreen *)screen)->DInfo.dri_Flags & DRIF_DIRECTCOLOR) ? TRUE : FALSE;
436 DoMethodA(((struct IntScreen *)(screen))->WinDecorObj, (Msg)&wemsg);
438 if (((struct IntWindow *)window)->DecorUserBuffer)
440 FreeMem((APTR)((struct IntWindow *)window)->DecorUserBuffer, ((struct IntWindow *)window)->DecorUserBufferSize);
444 /* Free memory for the window */
445 FreeMem (window, sizeof(struct IntWindow));
447 CheckLayers(screen, IntuitionBase);
449 UNLOCK_REFRESH(screen);
450 } /* int_closewindow */
453 /**********************************************************************************/
456 void intui_CloseWindow (struct Window * w,
457 struct IntuitionBase * IntuitionBase)
459 struct LayersBase *LayersBase = GetPrivIBase(IntuitionBase)->LayersBase;
460 KillWinSysGadgets(w, IntuitionBase);
462 if (0 == (w->Flags & WFLG_GIMMEZEROZERO))
464 /* not a GZZ window */
465 if (WLAYER(w))
466 DeleteLayer(0, WLAYER(w));
467 DeinitRastPort(w->BorderRPort);
468 FreeMem(w->BorderRPort, sizeof(struct RastPort));
470 else
472 /* a GZZ window */
473 /* delete inner window */
474 if (NULL != WLAYER(w))
475 DeleteLayer(0, WLAYER(w));
477 /* delete outer window */
478 if (NULL != BLAYER(w))
479 DeleteLayer(0, BLAYER(w));
482 if (IW(w)->free_pointer)
483 DisposeObject(IW(w)->pointer);