quieten debug
[aros:aros.git] / AROS / rom / intuition / inputhandler_support.c
1 /*
2     Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3     Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
4     $Id$
5
6     Support functions for InputHandler.
7 */
8
9 /****************************************************************************************/
10
11 #include <proto/exec.h>
12 #include <proto/intuition.h>
13 #include <proto/alib.h>
14 #include <proto/layers.h>
15 #include <proto/graphics.h>
16 #include <proto/utility.h>
17 #include <proto/keymap.h>
18 #include <exec/memory.h>
19 #include <exec/alerts.h>
20 #include <exec/interrupts.h>
21 #include <exec/ports.h>
22 #include <intuition/intuition.h>
23 #include <intuition/intuitionbase.h>
24 #include <intuition/gadgetclass.h>
25 #include <intuition/cghooks.h>
26 #include <intuition/sghooks.h>
27 #include <devices/inputevent.h>
28 #include <hidd/graphics.h>
29 #include <string.h>
30
31 #include "inputhandler.h"
32
33 #include "boopsigadgets.h"
34 #include "boolgadgets.h"
35 #include "propgadgets.h"
36 #include "strgadgets.h"
37 #include "gadgets.h"
38 #include "intuition_intern.h" /* EWFLG_xxx */
39 #include "inputhandler_actions.h"
40 #include "inputhandler_support.h"
41 #include "menus.h"
42
43 #ifdef SKINS
44 #   include "mosmisc.h"
45 #endif
46
47 #undef DEBUG
48 #define DEBUG 0
49 #include <aros/debug.h>
50
51 #define DEBUG_WINDOWNEEDSREFRESH(x) ;
52 #define DEBUG_DOGPINPUT(x)      ;
53 #define DEBUG_HANDLECUSTOMRETVAL(x) ;
54 #define DEBUG_ACTIVATEGADGET(x)     ;
55 #define DEBUG_FIREINTUIMSG(x)       ;
56 #define DEBUG_CLICK(x)
57
58 #include <stddef.h>
59
60 /****************************************************************************************/
61
62 /*
63   All screens and windows on active monitor will be updated with the current position of
64   the mouse pointer. Windows will receive relative mouse coordinates.
65 */
66
67 /****************************************************************************************/
68
69 void notify_mousemove_screensandwindows(struct IntuitionBase * IntuitionBase)
70 {
71     LONG               lock = LockIBase(0);
72     struct Screen *scr;
73
74     for (scr = IntuitionBase->FirstScreen; scr; scr = scr->NextScreen)
75     {
76         struct Window *win;
77
78         /* Ignore screens which are not on our current monitor */
79         if (GetPrivScreen(scr)->IMonitorNode != GetPrivIBase(IntuitionBase)->ActiveMonitor)
80             continue;
81
82         scr->MouseX = IntuitionBase->MouseX - scr->LeftEdge;
83         scr->MouseY = IntuitionBase->MouseY - scr->TopEdge;
84
85         /* update windows belonging to this screen */
86         for (win = scr->FirstWindow; win; win = win->NextWindow)
87         {
88             UpdateMouseCoords(win);
89         }
90     }
91
92     UnlockIBase(lock);
93 }
94
95 /****************************************************************************************/
96
97 void send_intuimessage(struct IntuiMessage *imsg, struct Window *w,
98                        struct IntuitionBase *IntuitionBase)
99 {
100     SendIntuiMessage(w, imsg);
101 }
102
103 /****************************************************************************************/
104
105 void free_intuimessage(struct IntuiMessage *imsg,
106                        struct IntuitionBase *IntuitionBase)
107 {
108     FreeIntuiMessage(imsg);
109 }
110
111 /****************************************************************************************/
112
113 struct IntuiMessage *alloc_intuimessage(struct Window *w,
114                                 struct IntuitionBase *IntuitionBase)
115 {
116     struct IntuiMessage *imsg;
117
118     imsg = AllocIntuiMessage(w);
119     if (imsg)
120     {
121         if (w)
122         {
123             if (w->IDCMPFlags & IDCMP_DELTAMOVE)
124             {
125                 struct IIHData *iihd = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
126
127                 imsg->MouseX = iihd->DeltaMouseX;
128                 imsg->MouseY = iihd->DeltaMouseY;
129             }
130             else
131             {
132                 imsg->MouseX = w->MouseX;
133                 imsg->MouseY = w->MouseY;
134             }
135         }
136         CurrentTime(&imsg->Seconds, &imsg->Micros);
137     }
138
139     return imsg;
140 }
141
142 /****************************************************************************************/
143
144 BOOL fire_intuimessage(struct Window *w,
145                        ULONG Class,
146                        UWORD Code,
147                        APTR IAddress,
148                        struct IntuitionBase *IntuitionBase)
149 {
150     struct IntuiMessage *imsg;
151     BOOL                     result = FALSE;
152
153     if ((w->IDCMPFlags & Class) && (w->UserPort))
154     {
155         if ((imsg = alloc_intuimessage(w, IntuitionBase)))
156         {
157             struct IIHData *iihd = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
158
159             imsg->Class =    Class;
160             imsg->Code      = Code;
161             imsg->Qualifier = iihd->ActQualifier;
162             if (Class == IDCMP_RAWKEY)
163             {
164                 INT_INTUIMESSAGE(imsg)->prevCodeQuals = IAddress;
165                 imsg->IAddress = &INT_INTUIMESSAGE(imsg)->prevCodeQuals;
166             }
167             else
168             {
169                 imsg->IAddress = IAddress;
170             }
171
172             send_intuimessage(imsg, w, IntuitionBase);
173
174             result = TRUE;
175         }
176         else
177         {
178             DEBUG_FIREINTUIMSG(dprintf("fire_intuimessage: can't alloc imsg\n"));
179         }
180     }
181     else
182     {
183         DEBUG_FIREINTUIMSG(dprintf("fire_intuimessage: no Userport or masked out idcmpflags\n"));
184     }
185
186     return result;
187 }
188
189 BOOL fire_message(struct Window *w,ULONG Class, UWORD Code, APTR IAddress, struct IntuitionBase *IntuitionBase)
190 {
191     struct Library         *UtilityBase = GetPrivIBase(IntuitionBase)->UtilityBase;
192     struct ExtIntuiMessage *imsg;
193     BOOL                        result = FALSE;
194
195     if ((w->IDCMPFlags & Class) && (w->UserPort))
196     {
197         if ((imsg = (struct ExtIntuiMessage *)alloc_intuimessage(w, IntuitionBase)))
198         {
199             struct IIHData *iihdata = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
200
201             imsg->eim_IntuiMessage.Class     = Class;
202             imsg->eim_IntuiMessage.Code      = Code;
203             imsg->eim_IntuiMessage.Qualifier = iihdata->ActQualifier;
204             if (Class == IDCMP_RAWKEY)
205             {
206                 INT_INTUIMESSAGE(imsg)->prevCodeQuals = IAddress;
207                 imsg->eim_IntuiMessage.IAddress = &INT_INTUIMESSAGE(imsg)->prevCodeQuals;
208             }
209             else
210             {
211                 imsg->eim_IntuiMessage.IAddress = IAddress;
212             }
213
214             if (iihdata->ActEventTablet && (w->MoreFlags & WMFLG_TABLETMESSAGES))
215             {
216                 if ((imsg->eim_TabletData = AllocPooled(GetPrivIBase(IntuitionBase)->IDCMPPool,sizeof (struct TabletData))))
217                 {
218                     memclr(imsg->eim_TabletData,sizeof (struct TabletData));
219                     imsg->eim_TabletData->td_XFraction = iihdata->ActEventTablet->ient_ScaledXFraction;
220                     imsg->eim_TabletData->td_YFraction = iihdata->ActEventTablet->ient_ScaledYFraction;
221                     imsg->eim_TabletData->td_TabletX = iihdata->ActEventTablet->ient_TabletX;
222                     imsg->eim_TabletData->td_TabletY = iihdata->ActEventTablet->ient_TabletY;
223                     imsg->eim_TabletData->td_RangeX = iihdata->ActEventTablet->ient_RangeX;
224                     imsg->eim_TabletData->td_RangeY = iihdata->ActEventTablet->ient_RangeY;
225                     imsg->eim_TabletData->td_TagList = CloneTagItems(iihdata->ActEventTablet->ient_TagList);
226                 }
227             }
228
229             send_intuimessage((struct IntuiMessage *)imsg, w, IntuitionBase);
230
231             result = TRUE;
232         }
233         else
234         {
235             DEBUG_FIREINTUIMSG(dprintf("fire_intuimessage: can't alloc imsg\n"));
236         }
237     }
238     else
239     {
240         DEBUG_FIREINTUIMSG(dprintf("fire_intuimessage: no Userport or masked out idcmpflags\n"));
241     }
242
243     return result;
244 }
245
246 /****************************************************************************************/
247
248 /*
249    use ih_fire_intuimessage if A) the inputevent because of which
250    you call this function might have to be eaten or modified
251    by Intuition or B) an inputevent might have to be created
252    by Intuition because of a deferred action.
253
254    In any case this function may be called only from inside Intuition's
255    InputHandler!!!!!!
256 */
257
258 /****************************************************************************************/
259
260 BOOL ih_fire_intuimessage(struct Window * w,
261                           ULONG Class,
262                           UWORD Code,
263                           APTR IAddress,
264                           struct IntuitionBase *IntuitionBase)
265 {
266     struct IIHData    *iihd = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
267     struct InputEvent *ie/* = iihd->ActInputEvent*/;
268
269     BOOL result;
270
271     DEBUG_FIREINTUIMSG(dprintf("ih_fire_intuimessage: win 0x%lx class 0x%lx code 0x%lx IAddress 0x%lx\n",
272                                w,
273                                Class,
274                                Code,
275                                IAddress));
276
277     result = fire_message(w, Class, Code, IAddress, IntuitionBase);
278
279     DEBUG_FIREINTUIMSG(dprintf("ih_fire_intuimessage: fire_intuimessage result 0x%lx\n",
280                 result));
281
282     if (result /*&& ie*/)
283     {
284         /* was sent as IDCMP to window so eat inputevent */
285
286         //ie->ie_Class = IECLASS_NULL;
287
288     }
289
290 #if 0
291     else if (ie/* && (ie->ie_Class != IECLASS_NULL) && !iihd->ActInputEventUsed*/)
292     {
293
294         /* ih_fire_intuimessage was called from inside Intuition's event handling loop */
295
296         //iihd->ActInputEventUsed = TRUE;
297
298         ie->ie_SubClass     = 0;
299         ie->ie_Code             = Code;
300       //ie->ie_Qualifier    = iihd->ActQualifier;
301         ie->ie_EventAddress = IAddress;
302
303         switch(Class)
304         {
305         case IDCMP_GADGETUP:
306             /* Note: on the Amiga if a boopsi Gadget which is GA_Immediate
307                and GA_RelVerify immediately in GM_GOACTIVE returns GMR_VERIFY,
308                then this sends IDCMP_GADGETDOWN + IDCMP_GADGETUP. AROS does
309                the same. But for changed inputevents (if window does not have this
310                IDCMP Flags set) there will be only one IECLASS_GADGETDOWN
311             */
312
313             ie->ie_Class = IECLASS_GADGETUP;
314             break;
315
316         case IDCMP_GADGETDOWN:
317             ie->ie_Class = IECLASS_GADGETDOWN;
318             break;
319
320         case IDCMP_ACTIVEWINDOW:
321             ie->ie_Class = IECLASS_ACTIVEWINDOW;
322             break;
323
324         case IDCMP_INACTIVEWINDOW:
325             ie->ie_Class = IECLASS_INACTIVEWINDOW;
326             break;
327
328         case IDCMP_CLOSEWINDOW:
329             ie->ie_Class = IECLASS_CLOSEWINDOW;
330             break;
331
332         case IDCMP_MENUHELP:
333             ie->ie_Class = IECLASS_MENUHELP;
334             break;
335
336         case IDCMP_MENUPICK:
337             ie->ie_Class = IECLASS_MENULIST;
338             break;
339
340         case IDCMP_MOUSEBUTTONS:
341         case IDCMP_MOUSEMOVE:
342         case IDCMP_RAWKEY:
343         case IDCMP_VANILLAKEY:
344             break;
345
346         default:
347             D(bug("ih_fireintuimessage: unexpected IDCMP (%x) for an inputevent-handling-fireintuimessage!\n", Class));
348             break;
349
350         }
351     }
352 #endif
353     else //if (!ie)
354     {
355         /* ih_fire_intuimessage was called from inside Intuition's defered action handling routines */
356
357         if ((ie = AllocInputEvent(iihd)))
358         {
359             switch(Class)
360             {
361             case IDCMP_NEWSIZE:
362                 ie->ie_Class = IECLASS_SIZEWINDOW;
363                 break;
364
365             case IDCMP_CHANGEWINDOW:
366                 ie->ie_Class = IECLASS_CHANGEWINDOW;
367                 break;
368
369             case IDCMP_ACTIVEWINDOW:
370                 ie->ie_Class = IECLASS_ACTIVEWINDOW;
371                 break;
372
373             case IDCMP_INACTIVEWINDOW:
374                 ie->ie_Class = IECLASS_INACTIVEWINDOW;
375                 break;
376
377             case IDCMP_CLOSEWINDOW:
378                 ie->ie_Class = IECLASS_CLOSEWINDOW;
379                 break;
380
381             case IDCMP_GADGETUP:
382                 ie->ie_Class = IECLASS_GADGETUP;
383                 break;
384
385             case IDCMP_GADGETDOWN:
386                 ie->ie_Class = IECLASS_GADGETDOWN;
387                 break;
388
389             case IDCMP_REFRESHWINDOW:
390                 ie->ie_Class = IECLASS_REFRESHWINDOW;
391                 break;
392
393             case IDCMP_MENUHELP:
394                 ie->ie_Class = IECLASS_MENUHELP;
395                 break;
396
397             case IDCMP_MENUPICK:
398                 ie->ie_Class = IECLASS_MENULIST;
399                 break;
400
401             default:
402                 D(bug("ih_fireintuimessage: unexpected IDCMP (0x%X) for a deferred-action-fireintuimessage!\n", Class));
403                 break;
404
405             } /* switch(Class) */
406
407             ie->ie_Code             = Code;
408             ie->ie_Qualifier    = iihd->ActQualifier;
409             ie->ie_EventAddress = IAddress;
410             CurrentTime(&ie->ie_TimeStamp.tv_secs, &ie->ie_TimeStamp.tv_micro);
411
412             D(bug("ih_fireintuimessage: generated InputEvent. Class = 0x%X  Code = %d  EventAddress = 0x%X\n",
413                   ie->ie_Class,
414                   ie->ie_Code,
415                   ie->ie_EventAddress));
416
417         } /* if ((ie = AllocInputEvent(iihd))) */
418     }
419
420     DEBUG_FIREINTUIMSG(dprintf("ih_fire_intuimessage: result 0x%lx\n",
421                 result));
422
423     return result;
424 }
425
426 /*********************************************************************/
427
428 /* This function must never be called with the layer/layerinfo locked,
429  * otherwise a deadlock with ObtainGIRPort can happen.
430  */
431 IPTR Locked_DoMethodA (struct Window *w, struct Gadget *g, Msg message, struct IntuitionBase *IntuitionBase)
432 {
433     struct LayersBase *LayersBase = GetPrivIBase(IntuitionBase)->LayersBase;
434     IPTR rc;
435     BOOL lock = w && (g->GadgetType & GTYP_SYSGADGET &&
436             ((g->GadgetType & GTYP_SYSTYPEMASK) == GTYP_WDRAGGING ||
437              (g->GadgetType & GTYP_SYSTYPEMASK) == GTYP_SIZING));
438
439     if (lock)
440     {
441         LOCK_REFRESH(w->WScreen);
442     }
443     
444     LOCKGADGET(IntuitionBase)
445     rc = Custom_DoMethodA(IntuitionBase, g, message);   
446     UNLOCKGADGET(IntuitionBase)
447
448     if (lock)
449     {
450         UNLOCK_REFRESH(w->WScreen);
451     }
452
453     return rc;
454 }
455
456 /*********************************************************************/
457
458 IPTR Custom_DoMethodA (struct IntuitionBase *IntuitionBase, struct Gadget *g, Msg message)
459 {
460     if (g->MutualExclude)
461     {
462         return AROS_UFC4(IPTR, ((struct Hook *)g->MutualExclude)->h_Entry,
463                  AROS_UFCA(struct Hook *, (struct Hook *)g->MutualExclude, A0),
464                  AROS_UFCA(struct Gadget *, g, A2),
465                  AROS_UFCA(APTR, message, A1),
466                  AROS_UFCA(struct IntuitionBase *, IntuitionBase, A6));
467     }
468     else /* Not needed since gadgetclass sets MutualExclude, but doesn't hurt. */
469         return DoMethodA((Object *)g, message);
470 }
471
472 /****************************************************************************************/
473
474 void NotifyDepthArrangement(struct Window *w, struct IntuitionBase *IntuitionBase)
475 {
476     if(w->MoreFlags & WMFLG_NOTIFYDEPTH)
477     {
478         ih_fire_intuimessage(w,
479                              IDCMP_CHANGEWINDOW,
480                              CWCODE_DEPTH,
481                              0,
482                              IntuitionBase);
483     }
484 }
485
486
487 /****************************************************************************************/
488
489 void PrepareGadgetInfo(struct GadgetInfo *gi, struct Screen *scr, struct Window *win,
490                        struct Requester *req)
491 {
492     gi->gi_Screen                 = scr;
493     gi->gi_Window                 = win;
494     gi->gi_Requester        = req;
495     gi->gi_RastPort               = 0;
496     gi->gi_Pens.DetailPen   = scr->DetailPen;
497     gi->gi_Pens.BlockPen    = scr->BlockPen;
498     gi->gi_DrInfo                 = (APTR)&(((struct IntScreen *)gi->gi_Screen)->DInfo);
499 }
500
501 /****************************************************************************************/
502
503 void SetGadgetInfoGadget(struct GadgetInfo *gi, struct Gadget *gad,
504                          struct IntuitionBase *IntuitionBase)
505 {
506     struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
507     struct IIHData *iihd = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
508
509     SET_GI_RPORT(gi, gi->gi_Window, gi->gi_Requester, gad);
510     InitRastPort(&iihd->GadgetInfoRastPort);
511
512     iihd->GadgetInfoRastPort.Layer = gi->gi_RastPort->Layer;
513     iihd->GadgetInfoRastPort.BitMap = gi->gi_RastPort->BitMap;
514
515     SetFont(&iihd->GadgetInfoRastPort, gi->gi_DrInfo->dri_Font);
516
517     gi->gi_Layer = gi->gi_RastPort->Layer;
518     gi->gi_RastPort = &iihd->GadgetInfoRastPort;
519
520     GetGadgetDomain(gad, gi->gi_Screen, gi->gi_Window, gi->gi_Requester, &gi->gi_Domain);
521 }
522
523 /****************************************************************************************/
524
525 void SetGPIMouseCoords(struct gpInput *gpi, struct Gadget *gad)
526 {
527     struct GadgetInfo *gi = gpi->gpi_GInfo;
528
529     WORD mousex, mousey;
530
531     if (IS_SCREEN_GADGET(gad) || !gi->gi_Window)
532     {
533         mousex = gi->gi_Screen->MouseX;
534         mousey = gi->gi_Screen->MouseY;
535     }
536     else
537     {
538
539         mousex = gi->gi_Window->MouseX;
540         mousey = gi->gi_Window->MouseY;
541     }
542
543     gpi->gpi_Mouse.X = mousex - gi->gi_Domain.Left - GetGadgetLeft(gad, gi->gi_Screen, gi->gi_Window, gi->gi_Requester);
544     gpi->gpi_Mouse.Y = mousey - gi->gi_Domain.Top  - GetGadgetTop(gad, gi->gi_Screen, gi->gi_Window, gi->gi_Requester);
545
546 }
547
548 /****************************************************************************************/
549
550 void HandleSysGadgetVerify(struct GadgetInfo *gi, struct Gadget *gadget,
551                            struct IntuitionBase *IntuitionBase)
552 {
553     struct LayersBase *LayersBase = GetPrivIBase(IntuitionBase)->LayersBase;
554     struct Screen *scr;
555     struct IIHData *iihd = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
556
557     switch(gadget->GadgetType & GTYP_SYSTYPEMASK)
558     {
559     case GTYP_CLOSE:
560 #ifdef __MORPHOS__
561         if (((struct IntWindow *)(gi->gi_Window))->specialflags & SPFLAG_IAMDEAD)
562         {
563             CrashedDispose(gi->gi_Window,IntuitionBase);
564         }
565         else
566         {
567 #endif
568             ih_fire_intuimessage(gi->gi_Window,
569                          IDCMP_CLOSEWINDOW,
570                          0,
571                          gi->gi_Window,
572                          IntuitionBase);
573 #ifdef __MORPHOS__
574         }
575 #endif
576         break;
577
578     case GTYP_WDEPTH:
579         if (!IsLayerHiddenBySibling(WLAYER(gi->gi_Window), FALSE)
580             || (iihd->ActQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0)
581         {
582             /* Send window to back */
583             WindowToBack(gi->gi_Window);
584         }
585         else
586         {
587             /* Send window to front */
588             WindowToFront(gi->gi_Window);
589         }
590         break;
591
592     case GTYP_WZOOM:
593         ZipWindow(gi->gi_Window);
594         break;
595
596     case GTYP_SDEPTH:
597         scr = FindFirstScreen(GetPrivIBase(IntuitionBase)->ActiveMonitor, IntuitionBase);
598         if (gi->gi_Screen == scr
599             || (iihd->ActQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0)
600         {
601             ScreenToBack(gi->gi_Screen);
602         }
603         else
604         {
605             ScreenToFront(gi->gi_Screen);
606         }
607         break;
608
609     } /* switch(gad->GadgetType & GTYP_SYSTYPEMASK) */
610 }
611
612 /****************************************************************************************/
613
614 struct Gadget *HandleCustomGadgetRetVal(IPTR retval, struct GadgetInfo *gi, struct Gadget *gadget,
615                                 ULONG termination, BOOL *reuse_event,
616                                 struct IntuitionBase *IntuitionBase)
617 {
618     struct IIHData  *iihdata = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
619
620     DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: retval %ld gi 0x%lx gadget 0x%lx termination %ld reuse %ld\n",
621                      retval,
622                      gi,
623                      gadget,
624                      termination,
625                      *reuse_event));
626
627     if (retval != GMR_MEACTIVE)
628     {
629         struct gpGoInactive gpgi;
630
631         DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: !GMR_MEACTIVE\n"));
632
633         if (retval & GMR_REUSE)
634         {
635             DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: GMR_REUSE\n"));
636             *reuse_event = TRUE;
637         }
638
639         if (retval & GMR_VERIFY)
640         {
641             DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: GMR_VERIFY\n"));
642             if (IS_SYS_GADGET(gadget))
643             {
644                 DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: SysGad\n"));
645                 HandleSysGadgetVerify(gi, gadget, IntuitionBase);
646             }
647             else
648             {
649                 /* Not a system gadget. Send IDCMP_GADGETUP, but not
650                    if it is a screen gadget where gi->gi_Window would
651                    be NULL */
652
653                 DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: no sysgad\n"));
654                 if ((gadget->Activation & GACT_RELVERIFY) &&
655                     (gi->gi_Window))
656                 {
657                     DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: Send IDCMP_GADGETUP\n"));
658                     ih_fire_intuimessage(gi->gi_Window,
659                                  IDCMP_GADGETUP,
660                                  termination & 0x0000FFFF,
661                                  gadget,
662                                  IntuitionBase);
663                 }
664
665             } /* switch(gad->GadgetType & GTYP_SYSTYPEMASK) */
666
667         } /* if (retval & GMR_VERIFY) */
668
669         DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: Send GM_GOINACTIVE\n"));
670
671         gpgi.MethodID   = GM_GOINACTIVE;
672         gpgi.gpgi_GInfo = gi;
673         gpgi.gpgi_Abort = 0;
674
675         Locked_DoMethodA(gi->gi_Window, gadget, (Msg)&gpgi, IntuitionBase);
676
677         if (SYSGADGET_ACTIVE)
678         {
679             /* Switch back from Master Drag or Size Gadget to
680                real/original/app Size or Drag Gadget */
681
682             DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: SYSGADGET_ACTIVE\n"));
683             gadget = iihdata->ActiveSysGadget;
684             iihdata->ActiveSysGadget = NULL;
685
686             if (IS_BOOPSI_GADGET(gadget))
687             {
688                 Locked_DoMethodA(gi->gi_Window, gadget, (Msg)&gpgi, IntuitionBase);
689             }
690
691             #ifdef __MORPHOS__
692             if ((gadget->GadgetType & GTYP_SYSTYPEMASK) == GTYP_WDRAGGING2)
693             {
694                 ih_fire_intuimessage(gi->gi_Window,
695                                      IDCMP_GADGETUP,
696                                      0,
697                                      gadget,
698                                      IntuitionBase);
699             }
700             #endif
701
702             retval = 0;
703         }
704
705         if (retval & GMR_VERIFY && gi->gi_Requester && gadget->Activation & GACT_ENDGADGET)
706         {
707             DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: EndRequest\n"));
708             EndRequest(gi->gi_Requester, gi->gi_Window);
709             retval = 0;
710         }
711
712         gadget->Activation &= ~GACT_ACTIVEGADGET;
713
714         DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: TabCycle 0x%lx retval 0x%lx\n",
715                                          (gadget->Flags & GFLG_TABCYCLE),
716                                          retval));
717
718         if ((gadget->Flags & GFLG_TABCYCLE) && (retval & GMR_NEXTACTIVE))
719         {
720             DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: TabCycle+GMR_NEXTACTIVE\n"));
721             gadget = FindCycleGadget(gi->gi_Window, gi->gi_Requester, gadget, GMR_NEXTACTIVE);
722         }
723         else if ((gadget->Flags & GFLG_TABCYCLE) && (retval & GMR_PREVACTIVE))
724         {
725             DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: TabCycle+GMR_PREVACTIVE\n"));
726             gadget = FindCycleGadget(gi->gi_Window, gi->gi_Requester, gadget, GMR_PREVACTIVE);
727         }
728         else
729         {
730             gadget = NULL;
731             DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: No gadget\n"));
732         }
733
734         if (gadget)
735         {
736             DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: activate gadget 0x%lx\n",gadget));
737             gadget = DoActivateGadget(gi->gi_Window, gi->gi_Requester, gadget, IntuitionBase);
738         }
739
740     } /* if (retval != GMR_MEACTIVE) */
741     else
742     {
743         DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: set GACT_ACTIVEGADGET\n"));
744         gadget->Activation |= GACT_ACTIVEGADGET;
745     }
746
747     DEBUG_HANDLECUSTOMRETVAL(dprintf("HandleCustomGadgetRetVal: return 0x%x\n", gadget));
748     return gadget;
749 }
750
751 /****************************************************************************************/
752
753 /* This function must never be called with the layer/layerinfo locked,
754  * otherwise a deadlock with ObtainGIRPort can happen.
755  */
756 struct Gadget *DoGPInput(struct GadgetInfo *gi, struct Gadget *gadget,
757                          struct InputEvent *ie, STACKULONG methodid,
758                          BOOL *reuse_event, struct IntuitionBase *IntuitionBase)
759 {
760     struct IIHData  *iihdata = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
761     struct gpInput   gpi;
762     IPTR             retval;
763     ULONG            termination;
764     ie->ie_Qualifier = iihdata->ActQualifier;
765
766     gpi.MethodID            = methodid;
767     gpi.gpi_GInfo           = gi;
768     gpi.gpi_IEvent          = ie;
769     gpi.gpi_Termination = &termination;
770     gpi.gpi_TabletData  = NULL;
771
772     SetGPIMouseCoords(&gpi, gadget);
773
774     retval = Locked_DoMethodA (gi->gi_Window, gadget, (Msg)&gpi, IntuitionBase);
775
776     DEBUG_DOGPINPUT(dprintf("DoGPInput: Locked_DoMethod gadget %p method 0x%lx retval %ld termination 0x%lx\n",
777                 gadget, methodid, retval, termination));
778
779     return HandleCustomGadgetRetVal(retval, gi, gadget, termination,
780                     reuse_event, IntuitionBase);
781
782 }
783
784 /****************************************************************************************/
785
786 struct Gadget * FindGadget (struct Screen *scr, struct Window * window,
787                             struct Requester * req, int x, int y,
788                             struct GadgetInfo * gi,BOOL sysonly,
789                             struct IntuitionBase *IntuitionBase)
790 {
791     struct Gadget           *gadget, *firstgadget, *draggadget = 0;
792     struct gpHitTest     gpht;
793     struct IBox              ibox;
794     WORD                     xrel, yrel;
795     BOOL                     sys_only = sysonly;
796
797     DEBUG_CLICK(bug("[Inputhandler] FindGadget(0x%p, 0x%p, 0x%p, %d, %d, %d)\n", scr, window, req, x, y, sysonly));
798     gpht.MethodID     = GM_HITTEST;
799     gpht.gpht_GInfo   = gi;
800
801     while (req || window || scr)
802     {
803         if (req)
804         {
805             firstgadget = req->ReqGadget;
806         }
807         else if (window)
808         {
809             firstgadget = window->FirstGadget;
810         }
811         else
812         {
813             if (draggadget) return draggadget;
814             firstgadget = scr->FirstGadget;
815         }
816
817         for (gadget = firstgadget; gadget; gadget = gadget->NextGadget)
818         {
819             if (!(gadget->Flags & GFLG_DISABLED) &&
820                 (!sys_only ||
821                  (gadget->GadgetType & GTYP_SYSGADGET &&
822                    ((gadget->GadgetType & GTYP_SYSTYPEMASK) == GTYP_SIZING ||
823                    (gadget->GadgetType & GTYP_SYSTYPEMASK) == GTYP_WDRAGGING ||
824                    (gadget->GadgetType & GTYP_SYSTYPEMASK) == GTYP_WDEPTH ||
825                    (gadget->GadgetType & GTYP_SYSTYPEMASK) == GTYP_SDEPTH ||
826                    (gadget->GadgetType & GTYP_SYSTYPEMASK) == GTYP_WZOOM ||
827                    (gadget->GadgetType & GTYP_SYSTYPEMASK) == GTYP_CLOSE))))
828             {
829                 /* stegerg: domain depends on gadgettype and windowflags! */
830                 GetGadgetDomain(gadget, scr, window, req, &gi->gi_Domain);
831
832                 /* Get coords relative to window */
833
834                 GetGadgetIBox(gadget, gi, &ibox);
835
836                 xrel = x - gi->gi_Domain.Left;
837                 yrel = y - gi->gi_Domain.Top;
838
839                 /*if (req)
840             {
841                     xrel -= req->LeftEdge + window->BorderLeft;
842                     yrel -= req->TopEdge + window->BorderTop;
843             }*/
844
845                 if (window)
846                 {
847                     xrel -= window->LeftEdge;
848                     yrel -= window->TopEdge;
849                 }
850
851                 if ((xrel >= ibox.Left) &&
852                     (yrel >= ibox.Top) &&
853                     (xrel < ibox.Left + ibox.Width) &&
854                     (yrel < ibox.Top  + ibox.Height))
855                 {
856                     if ((gadget->GadgetType & GTYP_SYSTYPEMASK) == GTYP_WDRAGGING)
857                     {
858                         if (!draggadget) draggadget = gadget;
859                     }
860                     else
861                     {
862
863                         if ((gadget->GadgetType & GTYP_GTYPEMASK) == GTYP_CUSTOMGADGET)
864                         {
865
866                             gpht.gpht_Mouse.X = xrel - ibox.Left;
867                             gpht.gpht_Mouse.Y = yrel - ibox.Top;
868
869                             /* jDc: don't check for == GMR_GADGETHIT since some reaction classes*/
870                             /* (BURN IN HELL!) return TRUE here (related to imageclass HITEST?)*/
871                             if (Locked_DoMethodA (window, gadget, (Msg)&gpht, IntuitionBase))
872                                 return (gadget);
873                         }
874                         else
875                         {
876                             return (gadget);
877                         }
878                     }
879                 }
880
881             } /* if (!(gadget->Flags & GFLG_DISABLED)) */
882
883         } /* for (gadget = window->FirstGadget; gadget; gadget = gadget->NextGadget) */
884
885         sys_only = sysonly;
886
887         if (req)
888         {
889             req = NULL;
890             sys_only = TRUE;
891         }
892         else if (window)
893         {
894             #ifdef SKINS
895             draggadget = findbordergadget(window,draggadget,IntuitionBase);
896             #endif
897             window = NULL;
898         }
899         else
900             scr = NULL;
901     }
902
903     return (draggadget);
904
905 } /* FindGadget */
906
907
908 /****************************************************************************************/
909
910 struct Gadget * FindHelpGadget (struct Window * window,
911                             int x, int y, struct IntuitionBase *IntuitionBase)
912 {
913     struct Gadget           *gadget, *firstgadget;
914     struct Requester    *req = window->FirstRequest;
915
916     while (req || window)
917     {
918         if (req)
919         {
920             firstgadget = req->ReqGadget;
921         }
922         else
923         {
924             firstgadget = window->FirstGadget;
925         }
926
927         for (gadget = firstgadget; gadget; gadget = gadget->NextGadget)
928         {
929             if ((gadget->Flags & GFLG_EXTENDED) &&
930                 (((struct ExtGadget *)gadget)->MoreFlags & GMORE_GADGETHELP))
931             {
932                 if (InsideGadget(window->WScreen, window, req, gadget, x, y))
933                 {
934                     return (gadget);
935                 }
936             }
937
938         }
939
940         if (req)
941             req = req->OlderRequest;
942         else
943             window = NULL;
944     }
945
946     return (NULL);
947
948 } /* FindHelpGadget */
949
950
951 /****************************************************************************************/
952
953 BOOL InsideGadget(struct Screen *scr, struct Window *win, struct Requester *req,
954                   struct Gadget *gad, WORD x, WORD y)
955 {
956     struct IBox box;
957     BOOL            rc = FALSE;
958
959     GetScrGadgetIBox(gad, scr, win, req, &box);
960
961     if ((x >= box.Left) &&
962         (y >= box.Top)  &&
963         (x < box.Left + box.Width) &&
964         (y < box.Top + box.Height))
965     {
966         rc = TRUE;
967     }
968
969     return rc;
970 }
971
972 /****************************************************************************************/
973
974 struct Gadget *DoActivateGadget(struct Window *win, struct Requester *req, struct Gadget *gad,
975                                     struct IntuitionBase *IntuitionBase)
976 {
977     struct IIHData          *iihd = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
978     struct GadgetInfo   *gi = &iihd->GadgetInfo;
979     struct Gadget           *result = NULL;
980
981     DEBUG_ACTIVATEGADGET(dprintf("DoActivateGadget: Window 0x%lx Req 0x%lx Gadget 0x%lx\n",
982                                  win,
983                                  req,
984                                  gad));
985
986     DEBUG_ACTIVATEGADGET(dprintf("DoActivateGadget: Activation 0x%lx\n",
987                                          gad->Activation));
988
989     if (gad->Activation & GACT_IMMEDIATE)
990     {
991         DEBUG_ACTIVATEGADGET(dprintf("DoActivateGadget: Send GADGETDOWN msg\n"));
992         ih_fire_intuimessage(win,
993                              IDCMP_GADGETDOWN,
994                              0,
995                              gad,
996                              IntuitionBase);
997     }
998
999     PrepareGadgetInfo(gi, win->WScreen, win, req);
1000     SetGadgetInfoGadget(gi, gad, IntuitionBase);
1001
1002     DEBUG_ACTIVATEGADGET(dprintf("DoActivateGadget: Type 0x%lx\n",
1003                     gad->GadgetType & GTYP_GTYPEMASK));
1004
1005     switch(gad->GadgetType & GTYP_GTYPEMASK)
1006     {
1007         case GTYP_STRGADGET:
1008         {
1009             struct StringInfo *si = (struct StringInfo *)gad->SpecialInfo;
1010             
1011             DEBUG_ACTIVATEGADGET(dprintf("DoActivateGadget: GTYP_STRGADGET\n"));
1012
1013             gad->Flags |= GFLG_SELECTED;
1014             if (si && si->UndoBuffer)
1015             {
1016                     strcpy(si->UndoBuffer, si->Buffer);
1017             }
1018
1019             gad->Activation |= GACT_ACTIVEGADGET;
1020             UpdateStrGadget(gad, win, req, IntuitionBase);
1021             result = gad;
1022             break;
1023             }
1024         
1025         case GTYP_CUSTOMGADGET:
1026         {
1027             struct gpInput  gpi;
1028             ULONG           termination;
1029             IPTR            retval;
1030             BOOL            reuse_event;
1031
1032             DEBUG_ACTIVATEGADGET(dprintf("DoActivateGadget: GTYP_CUSTOMGADGET\n"));
1033             
1034             gpi.MethodID            = GM_GOACTIVE;
1035             gpi.gpi_GInfo           = gi;
1036             gpi.gpi_IEvent          = NULL;
1037             gpi.gpi_Termination = &termination;
1038             gpi.gpi_Mouse.X         = win->MouseX - gi->gi_Domain.Left - GetGadgetLeft(gad, gi->gi_Screen, gi->gi_Window, NULL);
1039             gpi.gpi_Mouse.Y         = win->MouseY - gi->gi_Domain.Top  - GetGadgetTop(gad, gi->gi_Screen, gi->gi_Window, NULL);
1040             gpi.gpi_TabletData  = NULL;
1041
1042             retval = Locked_DoMethodA (win, gad, (Msg)&gpi, IntuitionBase);
1043
1044             gad = HandleCustomGadgetRetVal(retval, gi, gad,termination,
1045                                &reuse_event, IntuitionBase);
1046
1047             if (gad)
1048             {
1049                 gad->Activation |= GACT_ACTIVEGADGET;
1050                 result = gad;
1051             }
1052             break;
1053         }
1054
1055     } /* switch(gad->GadgetType & GTYP_GTYPEMASK) */
1056
1057     DEBUG_ACTIVATEGADGET(dprintf("DoActivateGadget: result 0x%lx\n",
1058                     result));
1059
1060     if (result) iihd->ActiveGadget = result;
1061
1062     return result;
1063 }
1064
1065
1066 /****************************************************************************************/
1067
1068 struct Gadget *FindCycleGadget(struct Window *win, struct Requester *req,
1069                                struct Gadget *gad, WORD direction)
1070 {
1071     struct Gadget *g = NULL, *gg, *prev, *first;
1072
1073     D(bug("FindCycleGadget: win = %p  req %p gad = %p  direction = %d\n", win, req, gad, direction));
1074
1075     if (req)
1076         first = req->ReqGadget;
1077     else
1078         first = win->FirstGadget;
1079
1080     switch(direction)
1081     {
1082     case GMR_NEXTACTIVE:
1083         g = gad->NextGadget;
1084         if (!g) g = first;
1085
1086         while(g)
1087         {
1088             if (g == gad)
1089             {
1090                 if (!(gad->Flags & GFLG_TABCYCLE) || (gad->Flags & GFLG_DISABLED))
1091                 {
1092                     /* should never happen */
1093                     g = NULL;
1094                 }
1095                 break;
1096             }
1097             if (!(g->Flags & GFLG_DISABLED) && (g->Flags & GFLG_TABCYCLE)) break;
1098
1099             g = g->NextGadget;
1100             if (!g) g = first;
1101         }
1102         break;
1103
1104     case GMR_PREVACTIVE:
1105         prev = 0;
1106         g = 0;
1107         gg = first;
1108
1109         /* find a TABCYCLE gadget which is before gad in window's gadgetlist */
1110         while (gg)
1111         {
1112             if (gg == gad)
1113             {
1114                 if (prev) g = prev;
1115                 break;
1116             }
1117             if (!(gg->Flags & GFLG_DISABLED) && (gg->Flags & GFLG_TABCYCLE)) prev = gg;
1118             gg = gg->NextGadget;
1119         }
1120
1121         if (gg && !g)
1122         {
1123             /* There was no TABCYCLE gadget before gad in window's gadgetlist */
1124
1125             gg = gg->NextGadget;
1126             if (!gg)
1127             {
1128                 if (!(gad->Flags & GFLG_DISABLED) && (gad->Flags & GFLG_TABCYCLE)) g = gad;
1129                 break;
1130             }
1131             prev = 0;
1132
1133             while(gg)
1134             {
1135                 if (!(gg->Flags & GFLG_DISABLED) && (gg->Flags & GFLG_TABCYCLE)) prev = gg;
1136                 gg = gg->NextGadget;
1137             }
1138
1139             if (prev)
1140             {
1141                 g = prev;
1142             }
1143             else
1144             {
1145                 if (!(gad->Flags & GFLG_DISABLED) && (gad->Flags & GFLG_TABCYCLE)) g = gad;
1146             }
1147         }
1148
1149
1150         break;
1151
1152     default: /* Unused, but well... */
1153         g = first;
1154         break;
1155
1156     } /* switch(direction) */
1157
1158     return g;
1159 }
1160
1161 /****************************************************************************************/
1162
1163 void FixWindowCoords(struct Window *win, LONG *left, LONG *top, LONG *width, LONG *height,struct IntuitionBase *IntuitionBase)
1164 {
1165     struct Screen *scr = win->WScreen;
1166
1167     if (*width < 1) *width = 1;
1168     if (*height < 1) *height = 1;
1169
1170     if (*width > scr->Width) *width = scr->Width;
1171     if (*height > scr->Height) *height = scr->Height;
1172
1173     if ((GetPrivIBase(IntuitionBase)->IControlPrefs.ic_Flags & ICF_OFFSCREENLAYERS) && (win->WScreen->LayerInfo.Flags & LIFLG_SUPPORTS_OFFSCREEN_LAYERS))
1174     {
1175         if (*left > scr->Width - 1) *left = scr->Width - 1;
1176         if (*top > scr->Height - 1) *top = scr->Height -1;
1177     }
1178     else
1179     {
1180
1181         if ((*left + *width) > scr->Width)
1182         {
1183             *left = scr->Width - *width;
1184         }
1185         else if (*left < 0)
1186         {
1187             *left = 0;
1188         }
1189
1190         if ((*top + *height) > scr->Height)
1191         {
1192             *top = scr->Height - *height;
1193         }
1194         else if (*top < 0)
1195         {
1196             *top = 0;
1197         }
1198     }
1199 }
1200
1201 /****************************************************************************************/
1202
1203 void WindowNeedsRefresh(struct Window * w,
1204                         struct IntuitionBase * IntuitionBase )
1205 {
1206     /* Supposed to send a message to this window, saying that it needs a
1207        refresh. I will check whether there is no such a message queued in
1208        its messageport, though. It only needs one such message!
1209     */
1210
1211     /* Refresh the window's gadgetry ...
1212        ... stegerg: and in the actual implementation
1213        call RefreshWindowFrame first, as the border gadgets don't
1214        cover the whole border area.*/
1215
1216     /*
1217         jDc: in actual implementation sizeevent means that we need to send
1218         idcmp, etc and do not clear the flag for smart_refresh window that
1219         has no idcmp_refreshwindow, otherwise we clear the flag!
1220     */
1221
1222     DEBUG_WINDOWNEEDSREFRESH(dprintf("WindowNeedsRefresh: window 0x%lx gzz %d nocarerefresh %d\n",
1223                      w, IS_GZZWINDOW(w), IS_NOCAREREFRESH(w)));
1224
1225     //trashregion means that we use delayed refreshing!
1226
1227     if (
1228     #ifdef DAMAGECACHE
1229         (!IW(w)->trashregion) ||
1230     #else
1231         (!(w->Flags & WFLG_SIMPLE_REFRESH)) ||
1232     #endif
1233          IS_NOCAREREFRESH(w))
1234     {
1235
1236         Gad_BeginUpdate(WLAYER(w), IntuitionBase);
1237
1238         if (IS_NOCAREREFRESH(w) || (!((!(w->Flags & WFLG_SIMPLE_REFRESH)) && (!(IW(w)->specialflags & SPFLAG_LAYERRESIZED)))))
1239         {
1240             if (!IS_GZZWINDOW(w))
1241             {
1242                 if (w->Flags & WFLG_BORDERLESS)
1243                 {
1244                     int_refreshglist(w->FirstGadget, w, NULL, -1, 0, 0, IntuitionBase);
1245                 }
1246                 else
1247                 {
1248                     int_refreshwindowframe(w,0,0,IntuitionBase);
1249                 }
1250             }
1251             else
1252             {
1253                 /* refresh all gadgets except border gadgets */
1254                 int_refreshglist(w->FirstGadget, w, NULL, -1, 0, REFRESHGAD_BORDER, IntuitionBase);
1255             }
1256             IW(w)->specialflags &= ~SPFLAG_LAYERRESIZED;
1257         }
1258
1259         if (IS_NOCAREREFRESH(w)) WLAYER(w)->Flags &= ~LAYERREFRESH;
1260
1261         Gad_EndUpdate(WLAYER(w), IS_NOCAREREFRESH(w) ? TRUE : FALSE, IntuitionBase);
1262
1263     } else {
1264     #ifdef DAMAGECACHE
1265         struct Rectangle rect;
1266         BOOL doclear = (w->Flags & WFLG_BORDERLESS) ? FALSE : TRUE;
1267
1268         rect.MinX = w->BorderLeft;
1269         rect.MinY = w->BorderTop;
1270         rect.MaxX = w->Width - w->BorderRight - 1;
1271         rect.MaxY = w->Height - w->BorderBottom - 1;
1272     #endif
1273
1274     #ifndef BEGINUPDATEGADGETREFRESH
1275         Gad_BeginUpdate(WLAYER(w), IntuitionBase);
1276     #else
1277     #ifdef DAMAGECACHE
1278         LockLayer(0,WLAYER(w));
1279     #endif
1280     #endif
1281     
1282     #ifndef BEGINUPDATEGADGETREFRESH
1283         if (!IS_GZZWINDOW(w))
1284         {
1285             if (w->Flags & WFLG_BORDERLESS)
1286             {
1287                 int_refreshglist(w->FirstGadget, w, NULL, -1, 0, 0, IntuitionBase);
1288             }
1289             else
1290             {
1291                 int_refreshwindowframe(w,0,0,IntuitionBase);
1292             }
1293         }
1294         else
1295         {
1296             /* refresh all gadgets except border and gadtools gadgets */
1297             int_refreshglist(w->FirstGadget, w, NULL, -1, 0, REFRESHGAD_BORDER , IntuitionBase);
1298         }
1299     #endif
1300
1301     #ifdef DAMAGECACHE
1302         //add rects to trashregion here
1303         OrRegionRegion(WLAYER(w)->DamageList,IW(w)->trashregion);
1304
1305         if (doclear)
1306         {
1307             ClearRectRegion(IW(w)->trashregion,&rect);
1308             AndRectRegion(WLAYER(w)->DamageList,&rect);
1309         }
1310
1311         IW(w)->specialflags |= SPFLAG_LAYERREFRESH;
1312     #else
1313     #ifdef BEGINUPDATEGADGETREFRESH
1314         IW(w)->specialflags |= SPFLAG_LAYERREFRESH;
1315     #endif
1316     #endif
1317
1318     #ifndef BEGINUPDATEGADGETREFRESH
1319         Gad_EndUpdate(WLAYER(w), FALSE, IntuitionBase);
1320     #else
1321     #ifdef DAMAGECACHE
1322         UnlockLayer(WLAYER(w));
1323     #endif
1324     #endif
1325
1326     }
1327
1328     if (IS_DOCAREREFRESH(w))
1329     {
1330         if (w->UserPort && (w->IDCMPFlags & IDCMP_REFRESHWINDOW))
1331         {
1332             struct IntuiMessage *IM;
1333             BOOL                         found = FALSE;
1334
1335             /* Can use Forbid() for this */
1336             Forbid();
1337
1338             IM = (struct IntuiMessage *)w->UserPort->mp_MsgList.lh_Head;
1339
1340             ForeachNode(&w->UserPort->mp_MsgList, IM)
1341             {
1342                 /* Does the window already have such a message? */
1343                 if (IDCMP_REFRESHWINDOW == IM->Class && IM->IAddress == w)
1344                 {
1345                     DEBUG_WINDOWNEEDSREFRESH(dprintf("WindowNeedsRefresh: refresh pending\n"));
1346                     D(bug("Window %s already has a refresh message pending!!\n",
1347                           w->Title ? w->Title : (STRPTR)"<NONAME>"));
1348                     found = TRUE;
1349                     break;
1350                 }
1351             }
1352
1353             Permit();
1354
1355             if (!found)
1356             {
1357                 struct InputEvent *new_ie;
1358                 struct IIHData    *iihdata = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
1359
1360                 D(bug("Sending a refresh message to window %s  %d %d %d %d!!\n",
1361                       w->Title ? w->Title : (STRPTR)"<NONAME>",
1362                       w->LeftEdge,
1363                       w->TopEdge,
1364                       w->Width,
1365                       w->Height));
1366
1367                 DEBUG_WINDOWNEEDSREFRESH(dprintf("WindowNeedsRefresh: sending idcmp message\n"));
1368
1369                 if ((new_ie = AllocInputEvent(iihdata)))
1370                 {
1371                     new_ie->ie_Class             = IECLASS_EVENT;
1372                     new_ie->ie_Code             = IECODE_REFRESH;
1373                     new_ie->ie_EventAddress = w;
1374                     CurrentTime(&new_ie->ie_TimeStamp.tv_secs, &new_ie->ie_TimeStamp.tv_micro);
1375                 }
1376
1377                 fire_intuimessage(w,
1378                                   IDCMP_REFRESHWINDOW,
1379                                   0,
1380                                   w,
1381                                   IntuitionBase);
1382             } /* if (!found) */
1383
1384         } /* if (w->UserPort && (w->IDCMPFlags & IDCMP_REFRESHWINDOW)) */
1385         else
1386         {
1387             struct IIHData *iihdata = (struct IIHData *)GetPrivIBase(IntuitionBase)->InputHandler->is_Data;
1388
1389             if (FindTask(NULL) == iihdata->InputDeviceTask)
1390             {
1391                 struct InputEvent *new_ie;
1392
1393                 D(bug("Sending a refresh message to window %s  %d %d %d %d!!\n",
1394                       w->Title ? w->Title : (STRPTR)"<NONAME>",
1395                       w->LeftEdge,
1396                       w->TopEdge,
1397                       w->Width,
1398                       w->Height));
1399                 DEBUG_WINDOWNEEDSREFRESH(dprintf("WindowNeedsRefresh: sending inputevent\n"));
1400
1401                 if ((new_ie = AllocInputEvent(iihdata)))
1402                 {
1403                     new_ie->ie_Class = IECLASS_EVENT;
1404                     new_ie->ie_Code = IECODE_REFRESH;
1405                     new_ie->ie_EventAddress = w;
1406                     CurrentTime(&new_ie->ie_TimeStamp.tv_secs, &new_ie->ie_TimeStamp.tv_micro);
1407                 }
1408
1409                 ih_fire_intuimessage(w,
1410                              IDCMP_REFRESHWINDOW,
1411                              0,
1412                              w,
1413                              IntuitionBase);
1414             }
1415         }
1416
1417     } /* if (!IS_NOCAREREFRESH(w)) */
1418
1419 }
1420
1421 /****************************************************************************************/
1422
1423 struct Screen *FindHighestScreen(struct IntuitionBase *IntuitionBase)
1424 {
1425     struct Screen *scr, *highest = IntuitionBase->FirstScreen;
1426
1427     for (scr = highest; scr; scr = scr->NextScreen) {
1428         /* We only check screens that are on this monitor */
1429         if (GetPrivScreen(scr)->IMonitorNode
1430             != GetPrivIBase(IntuitionBase)->ActiveMonitor)
1431             continue;
1432
1433         /* Check if top of screen is highest so far */
1434         if (scr->TopEdge < highest->TopEdge)
1435             highest = scr;
1436     }
1437     return highest;
1438 }
1439
1440 /****************************************************************************************/
1441
1442 struct Screen *FindActiveScreen(struct IntuitionBase *IntuitionBase)
1443 {
1444     struct Screen *scr;
1445     WORD MinX, MinY, MaxX, MaxY;
1446     ULONG compflags;
1447
1448     for (scr = IntuitionBase->FirstScreen; scr; scr = scr->NextScreen) {
1449         /* We check only screens which are on this monitor */
1450         if (GetPrivScreen(scr)->IMonitorNode != GetPrivIBase(IntuitionBase)->ActiveMonitor)
1451             continue;
1452
1453         compflags = GetPrivScreen(scr)->SpecialFlags >> 8;
1454
1455         /* adjust screen bounds if compositing */
1456         if (compflags & COMPF_ABOVE)
1457             MinY = 0;
1458         else
1459             MinY = -(scr->TopEdge);
1460
1461         if (compflags & COMPF_BELOW)
1462             MaxY = scr->Height;
1463         else
1464             MaxY = scr->MouseY + 1;
1465
1466         if (compflags & COMPF_LEFT)
1467             MinX = 0;
1468         else
1469             MinX = -(scr->LeftEdge);
1470
1471         if (compflags & COMPF_RIGHT)
1472             MaxX = scr->Width;
1473         else
1474             MaxX = scr->MouseX + 1;
1475
1476         D(bug("[Intuition] Bounds %d,%d->%d,%d\n", MinX, MinY, MaxX, MaxY));
1477         /* If the mouse is inside screen's bounds, we found it */
1478         if ((scr->MouseX >= MinX) && (scr->MouseY >= MinY) &&
1479            ((scr->MouseX < MaxX) && scr->MouseY < MaxY))
1480                break;
1481     }
1482     return scr;
1483 }
1484
1485 /****************************************************************************************/
1486
1487 struct Window *FindActiveWindow(struct InputEvent *ie, struct Screen *scr, ULONG *stitlebarhit,
1488                             struct IntuitionBase *IntuitionBase)
1489 {
1490     /* The caller has checked that the input event is a IECLASS_RAWMOUSE, SELECTDOWN event */
1491     /* NOTE: may be called with NULL ie ptr! */
1492     struct LayersBase *LayersBase = GetPrivIBase(IntuitionBase)->LayersBase;
1493     struct Layer    *l;
1494     struct Window   *new_w;
1495     ULONG            lock;
1496
1497     lock = LockIBase(0UL);
1498
1499     new_w = IntuitionBase->ActiveWindow;
1500
1501     UnlockIBase(lock);
1502
1503     D(bug("FindActiveWindow: scr %p win %p\n",scr,new_w));
1504
1505     if (stitlebarhit) *stitlebarhit = FALSE;
1506
1507     if (scr)
1508     {
1509         D(bug("FindActiveWindow: Click at (%d,%d)\n",scr->MouseX,scr->MouseY));
1510
1511         /* What layer ? */
1512         LockLayerInfo(&scr->LayerInfo);
1513
1514         l = WhichLayer(&scr->LayerInfo, scr->MouseX, scr->MouseY);
1515
1516         UnlockLayerInfo(&scr->LayerInfo);
1517
1518         if (NULL == l)
1519         {
1520             new_w = NULL;
1521             D(bug("FindActiveWindow: Click not inside layer\n"));
1522         }
1523         else if (l == scr->BarLayer)
1524         {
1525             D(bug("FindActiveWindow: Click on screen bar layer -> active window stays the same\n"));
1526             if (stitlebarhit) *stitlebarhit = TRUE;
1527         }
1528         else
1529         {
1530             new_w = (struct Window *)l->Window;
1531             if (!new_w)
1532             {
1533                 D(bug("FindActiveWindow: Selected layer is not a window\n"));
1534             }
1535
1536             D(bug("FindActiveWindow: Found layer %p\n", l));
1537         }
1538     }
1539
1540     D(bug("FindActiveWindow: New window %p\n", new_w));
1541     return new_w;
1542 }
1543
1544 /****************************************************************************************/
1545
1546 struct Window *FindDesktopWindow(struct Screen *screen,struct IntuitionBase *IntuitionBase)
1547 {
1548     struct Window *win;
1549     
1550     for (win = screen->FirstWindow; win; win = win->NextWindow)
1551     {
1552         if (win->Flags & WFLG_BACKDROP &&
1553             win->Width == screen->Width &&
1554             win->Height >= screen->Height - (screen->BarHeight + 2))
1555         {
1556             return win;
1557         }
1558     }
1559     
1560     return NULL;
1561 }
1562
1563
1564 /****************************************************************************************/
1565
1566 struct InputEvent *AllocInputEvent(struct IIHData *iihdata)
1567 {
1568     struct GeneratedInputEvent  *gie;
1569     struct InputEvent               *ie;
1570
1571     /* There might be an inputevent from someone else that our handler discarded.
1572      * We may as well use it. This can only happen inside our main loop.
1573      */
1574     ie = iihdata->FreeInputEvents;
1575     if (ie)
1576     {
1577         iihdata->FreeInputEvents = ie->ie_NextEvent;
1578         DEBUG_INPUTEVENT(dprintf("AllocInputEvent: reuse 0x%lx event\n", ie));
1579     }
1580     else
1581     {
1582         gie = AllocPooled(iihdata->InputEventMemPool, sizeof(struct GeneratedInputEvent));
1583         if (gie)
1584         {
1585             /* Allocated events are put in the list of events that have not yet been
1586              * propagated.
1587              */
1588             AddTail((struct List *)&iihdata->NewAllocatedInputEventList, (struct Node *)gie);
1589             ie = &gie->ie;
1590         }
1591         DEBUG_INPUTEVENT(dprintf("AllocInputEvent: allocated 0x%lx (0x%lx)\n", ie, gie));
1592     }
1593
1594     if (ie)
1595     {
1596         *iihdata->EndInputEventChain = ie;
1597         iihdata->EndInputEventChain = &ie->ie_NextEvent;
1598     }
1599
1600     return ie;
1601 }
1602
1603 /****************************************************************************************/
1604
1605 void FreeGeneratedInputEvents(struct IIHData *iihdata)
1606 {
1607     struct Node             *node, *succ;
1608
1609     /* Free the list of allocated events that have already been propagated. */
1610     ForeachNodeSafe(&iihdata->AllocatedInputEventList, node, succ)
1611     {
1612         DEBUG_INPUTEVENT(dprintf("FreeGeneratedInputEvent: free 0x%lx\n", node));
1613         FreePooled(iihdata->InputEventMemPool, node, sizeof(struct GeneratedInputEvent));
1614     }
1615
1616     /* The list is not in a valid state at this point, and NewList() should
1617      * be called, but since we won't use it until the list of not-yet-propagated
1618      * events is copied in it, we won't bother.
1619      */
1620     //NEWLIST(&iihdata->AllocatedInputEventList);
1621 }
1622
1623 /****************************************************************************************/
1624
1625 BOOL FireMenuMessage(WORD code, struct Window *win,
1626                      struct InputEvent *ie, struct IntuitionBase *IntuitionBase)
1627 {
1628     struct MenuMessage *msg;
1629     BOOL                      result = FALSE;
1630
1631     if ((msg = AllocMenuMessage(IntuitionBase)))
1632     {
1633         msg->code = code;
1634         msg->win  = win;
1635         if (ie) msg->ie = *ie;
1636         SendMenuMessage(msg, IntuitionBase);
1637
1638         result = TRUE;
1639     }
1640
1641     return result;
1642 }
1643
1644 /****************************************************************************************/
1645
1646 LONG Gad_BeginUpdate(struct Layer *layer, struct IntuitionBase *IntuitionBase)
1647 {
1648     struct LayersBase *LayersBase = GetPrivIBase(IntuitionBase)->LayersBase;
1649
1650     /* Must lock GadgetLock to avoid deadlocks with ObtainGirPort
1651        from other tasks, because ObtainGirPort first obtains
1652        GadgetLock and then layer lock through LockLayer!!!! */
1653     LOCKGADGET(IntuitionBase)
1654     return BeginUpdate(layer);
1655 }
1656
1657 /****************************************************************************************/
1658
1659 void Gad_EndUpdate(struct Layer *layer, UWORD flag, struct IntuitionBase *IntuitionBase)
1660 {
1661     struct LayersBase *LayersBase = GetPrivIBase(IntuitionBase)->LayersBase;
1662
1663     EndUpdate(layer, flag);
1664     UNLOCKGADGET(IntuitionBase)
1665 }
1666
1667 /****************************************************************************************/