Minor fixes to comments.
[AROS.git] / rom / intuition / sysrequest_intern.c
blob6d0c34b81a2d657ff347086aa34ad0067ea226e0
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 Copyright © 2001-2003, The MorphOS Development Team. All Rights Reserved.
4 $Id$
5 */
7 #define DEBUG_BUILDSYSREQUEST(x)
8 #define DEBUG_FREESYSREQUEST(x)
9 #define DEBUG_SYSREQHANDLER(x)
11 /**********************************************************************************************/
12 #include <proto/exec.h>
13 #include <proto/intuition.h>
14 #include <proto/graphics.h>
15 #include <proto/keymap.h>
16 #include <proto/utility.h>
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #include <clib/macros.h>
21 #include <exec/memory.h>
22 #include <intuition/gadgetclass.h>
23 #include <intuition/imageclass.h>
24 #include <intuition/screens.h>
25 #include <graphics/rastport.h>
26 #include <graphics/gfxmacros.h>
27 #include <utility/tagitem.h>
28 #include "intuition_intern.h"
30 extern UWORD BgPattern[];
32 /**********************************************************************************************/
34 struct sysreqdims
36 UWORD width; /* width of the requester */
37 UWORD height; /* height of the requester */
38 UWORD fontheight; /* height of the default font */
39 UWORD itextleft;
40 int gadgets; /* number of gadgets */
41 UWORD gadgetwidth; /* width of a gadget */
44 /**********************************************************************************************/
46 static BOOL buildsysreq_calculatedims(struct sysreqdims *dims,
47 struct Screen *scr,
48 struct IntuiText *itext,
49 STRPTR *gadgetlabels,
50 struct IntuitionBase *IntuitionBase);
51 static struct Gadget *buildsysreq_makegadgets(struct sysreqdims *dims,
52 STRPTR *gadgetlabels,
53 struct Screen *scr,
54 struct IntuitionBase *IntuitionBase);
55 static void buildsysreq_draw(struct sysreqdims *dims, struct IntuiText *itext,
56 struct Window *win, struct Screen *scr,
57 struct Gadget *gadgets,
58 struct IntuitionBase *IntuitionBase);
60 static void ReqITextSize(struct Screen *scr, struct IntuiText *itext,
61 WORD *width, WORD *height,
62 struct IntuitionBase *IntuitionBase);
64 static void ReqPrintIText(struct Screen *scr, struct DrawInfo *dri,
65 struct RastPort *rp, struct IntuiText *itext, WORD x, WORD y,
66 struct IntuitionBase *IntuitionBase);
68 /**********************************************************************************************/
70 struct Window *buildsysreq_intern(struct Window *window, STRPTR reqtitle, struct IntuiText *bodytext,
71 struct IntuiText *postext, struct IntuiText *negtext,
72 ULONG IDCMPFlags, WORD width, WORD height, struct IntuitionBase *IntuitionBase)
74 struct Screen *scr = NULL, *lockedscr = NULL;
75 struct Window *req;
76 struct Gadget *gadgets;
77 STRPTR gadgetlabels[3];
78 struct sysreqdims dims;
79 struct IntRequestUserData *requserdata;
81 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: window 0x%p body <%s> postext <%s> negtext <%s> IDCMPFlags 0x%lx width %ld height %ld\n",
82 window,
83 bodytext ? (char *) bodytext->IText : "<NULL>",
84 (postext && postext->IText) ? (char *) postext->IText : "<NULL>",
85 (negtext && negtext->IText) ? (char *) negtext->IText : "<NULL>",
86 IDCMPFlags,
87 (LONG) width,
88 (LONG) height));
90 /* negtext and bodytest must be specified, postext is optional */
91 if (!negtext || !bodytext) return NULL;
93 /* get requester title */
94 if (!reqtitle)
95 reqtitle = window ? window->Title : (STRPTR)"System Request"; /* stegerg: should be localized */
97 /* get screen and screendrawinfo */
98 if (window)
99 scr = window->WScreen;
100 if (!scr)
102 scr = LockPubScreen(NULL);
103 if (!scr)
104 return NULL;
105 lockedscr = scr;
108 if (postext)
110 dims.gadgets = 2;
112 gadgetlabels[0] = postext->IText;
113 gadgetlabels[1] = negtext->IText;
114 gadgetlabels[2] = NULL;
116 else
118 dims.gadgets = 1;
120 gadgetlabels[0] = negtext->IText;
121 gadgetlabels[1] = NULL;
124 /* EXPERIMENTAL: Obey user-supplied size if the text fits into it. Processed in buildsysreq_calculatedims().
125 This is experimental. Currently DisplayAlert() relies on ability to specify requester size.
126 Requester size actually determines inner text box size - sonic. */
127 dims.width = width;
128 dims.height = height;
130 /* create everything */
132 if (buildsysreq_calculatedims(&dims, scr,
133 bodytext, gadgetlabels, IntuitionBase))
135 gadgets = buildsysreq_makegadgets(&dims, gadgetlabels, scr, IntuitionBase);
136 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: gadgets 0x%p\n", gadgets));
137 if (gadgets)
139 requserdata = AllocVec(sizeof(struct IntRequestUserData),
140 MEMF_ANY|MEMF_CLEAR);
141 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: requserdata 0x%p\n", requserdata));
142 if (requserdata)
144 struct TagItem win_tags[] =
146 {WA_Width , dims.width },
147 {WA_Height , dims.height },
148 {WA_Left , (scr->Width/2) - (dims.width/2) },
149 {WA_Top , (scr->Height/2) - (dims.height/2) },
150 {WA_IDCMP , (IDCMP_GADGETUP | IDCMP_RAWKEY | (IDCMPFlags & ~IDCMP_VANILLAKEY))},
151 {WA_Gadgets , (IPTR)gadgets },
152 {WA_Title , (IPTR)reqtitle },
153 {(lockedscr ? WA_PubScreen : WA_CustomScreen) , (IPTR)scr },
154 {WA_Flags , WFLG_DRAGBAR |
155 WFLG_DEPTHGADGET |
156 WFLG_ACTIVATE |
157 WFLG_RMBTRAP /*|
158 WFLG_SIMPLE_REFRESH*/ },
159 {TAG_DONE }
162 req = OpenWindowTagList(NULL, win_tags);
163 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: req 0x%p\n", req));
164 if (req)
166 if (lockedscr) UnlockPubScreen(NULL, lockedscr);
168 req->UserData = (BYTE *)requserdata;
169 requserdata->IDCMP = IDCMPFlags;
170 requserdata->GadgetLabels = NULL;
171 requserdata->Gadgets = gadgets;
172 requserdata->NumGadgets = dims.gadgets;
173 buildsysreq_draw(&dims, bodytext,
174 req, scr, gadgets, IntuitionBase);
175 DEBUG_BUILDSYSREQUEST(dprintf("intrequest_buildsysrequest: gadgets 0x%p\n", gadgets));
177 return req;
180 /* opening requester failed -> free everything */
181 FreeVec(requserdata);
183 intrequest_freegadgets(gadgets, IntuitionBase);
187 if (lockedscr) UnlockPubScreen(NULL, lockedscr);
189 return NULL;
192 /**********************************************************************************************/
194 LONG sysreqhandler_intern(struct Window *window, ULONG *IDCMPFlagsPtr, BOOL WaitInput, struct IntuitionBase *IntuitionBase)
196 struct Library *KeymapBase = GetPrivIBase(IntuitionBase)->KeymapBase;
197 struct Library *UtilityBase = GetPrivIBase(IntuitionBase)->UtilityBase;
198 struct IntuiMessage *msg;
199 LONG result;
201 DEBUG_SYSREQHANDLER(dprintf("SysReqHandler: window 0x%lx IDCMPPtr 0x%lx WaitInput 0x%lx\n",
202 (ULONG) window,
203 (ULONG) IDCMPFlagsPtr,
204 (ULONG) WaitInput));
206 if (window == 0)
208 result = 0;
210 else if (window == (struct Window *)1)
212 result = 1;
214 else
216 result = -2;
218 if (WaitInput)
220 WaitPort(window->UserPort);
222 while ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)))
224 DEBUG_SYSREQHANDLER(dprintf("SysReqHandler: msg 0x%lx class 0x%lx\n", (ULONG) msg, msg->Class));
225 switch (msg->Class)
227 /* we don't use VANILLA (filtered from useridcmp!) to get
228 all events we need */
229 case IDCMP_RAWKEY:
231 #define RKBUFLEN 1
233 struct InputEvent ie;
234 char rawbuffer[RKBUFLEN];
236 ie.ie_Class = IECLASS_RAWKEY;
237 ie.ie_SubClass = 0;
238 ie.ie_Code = msg->Code;
239 ie.ie_Qualifier = 0;
240 ie.ie_EventAddress = (APTR *) *((IPTR *)msg->IAddress);
242 if (KeymapBase && MapRawKey(&ie,rawbuffer,RKBUFLEN,0))
244 if (msg->Qualifier & IEQUALIFIER_LCOMMAND)
246 if (ToUpper(rawbuffer[0]) == ToUpper(GetPrivIBase(IntuitionBase)->IControlPrefs.ic_ReqTrue))
248 if (((struct IntRequestUserData *)window->UserData)->NumGadgets > 1)
250 result = 1;
252 else
254 result = 0;
258 if (ToUpper(rawbuffer[0]) == ToUpper(GetPrivIBase(IntuitionBase)->IControlPrefs.ic_ReqFalse))
260 result = 0;
264 break;
267 case IDCMP_GADGETUP:
268 result = ((struct Gadget *)msg->IAddress)->GadgetID;
269 break;
271 default:
272 DEBUG_SYSREQHANDLER(dprintf("SysReqHandler: unknown IDCMP\n"));
273 if (result == -2)
275 if (msg->Class & ((struct IntRequestUserData *)window->UserData)->IDCMP)
277 if (IDCMPFlagsPtr) *IDCMPFlagsPtr = msg->Class;
278 result = -1;
281 break;
283 ReplyMsg((struct Message *)msg);
285 } /* while ((msg = (struct IntuiMessage *)GetMsg(window->UserPort))) */
287 } /* real window */
289 DEBUG_SYSREQHANDLER(dprintf("SysReqHandler: Result 0x%lx\n",result));
291 return result;
294 /**********************************************************************************************/
296 void freesysreq_intern(struct Window *window, struct IntuitionBase *IntuitionBase)
298 struct Gadget *gadgets;
299 STRPTR *gadgetlabels;
300 struct IntRequestUserData *requserdata;
302 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: window 0x%lx\n", (ULONG) window));
304 if ((window == NULL) || (window == (void *)1L))
305 return;
307 requserdata = (struct IntRequestUserData *)window->UserData;
309 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: requserdata 0x%lx\n", (ULONG) requserdata));
311 gadgets = requserdata->Gadgets;
313 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: gadgets 0x%lx\n", (ULONG) gadgets));
315 /* Remove gadgets before closing window to avoid conflicts with system gadgets */
316 RemoveGList(window, gadgets, requserdata->NumGadgets);
318 gadgetlabels = requserdata->GadgetLabels;
320 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: gadgetlabels 0x%lx\n", (ULONG) gadgetlabels));
322 window->UserData = 0;
323 CloseWindow(window);
324 intrequest_freegadgets(gadgets, IntuitionBase);
325 intrequest_freelabels(gadgetlabels, IntuitionBase);
327 #ifdef SKINS
328 DEBUG_FREESYSREQUEST(dprintf("intrequest_freesysrequest: freeitext 0x%lx\n", (ULONG) requserdata->freeitext));
329 if (requserdata->freeitext) intrequest_freeitext(requserdata->Text,IntuitionBase);
330 if (requserdata->backfilldata.image) int_FreeCustomImage(TYPE_REQUESTERCLASS,requserdata->dri,IntuitionBase);
331 if (requserdata->Logo) int_FreeCustomImage(TYPE_REQUESTERCLASS,requserdata->dri,IntuitionBase);
332 if (requserdata->ReqGadgets) FreeVec(requserdata->ReqGadgets);
333 if (requserdata->dri) FreeScreenDrawInfo(requserdata->ReqScreen,(struct DrawInfo *)requserdata->dri);
334 #endif
335 FreeVec(requserdata);
336 } /* FreeSysRequest */
338 /**********************************************************************************************/
340 /* draw the contents of the requester */
341 static void buildsysreq_draw(struct sysreqdims *dims, struct IntuiText *itext,
342 struct Window *req, struct Screen *scr,
343 struct Gadget *gadgets,
344 struct IntuitionBase *IntuitionBase)
346 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
347 struct TagItem frame_tags[] =
349 {IA_Left , req->BorderLeft + OUTERSPACING_X },
350 {IA_Top , req->BorderTop + OUTERSPACING_Y },
351 {IA_Width , req->Width - req->BorderLeft - req->BorderRight - OUTERSPACING_X * 2 },
352 {IA_Height , req->Height - req->BorderTop - req->BorderBottom -
353 dims->fontheight - OUTERSPACING_Y * 2 -
354 TEXTGADGETSPACING - BUTTONBORDER_Y * 2 },
355 {IA_Recessed , TRUE },
356 {IA_EdgesOnly , FALSE },
357 {TAG_DONE }
359 struct DrawInfo *dri;
360 struct Image *frame;
362 dri = GetScreenDrawInfo(scr);
363 if (!dri)
364 return;
366 SetFont(req->RPort, dri->dri_Font);
368 /* draw background pattern */
369 SetABPenDrMd(req->RPort,
370 dri->dri_Pens[SHINEPEN], dri->dri_Pens[BACKGROUNDPEN],
371 JAM1);
372 SetAfPt(req->RPort, BgPattern, 1);
373 RectFill(req->RPort, req->BorderLeft,
374 req->BorderTop,
375 req->Width - req->BorderRight,
376 req->Height - req->BorderBottom);
377 SetAfPt(req->RPort, NULL, 0);
379 /* draw textframe */
380 frame = (struct Image *)NewObjectA(NULL, FRAMEICLASS, frame_tags);
381 if (frame)
383 DrawImageState(req->RPort, frame, 0, 0, IDS_NORMAL, dri);
384 DisposeObject((Object *)frame);
387 /* draw text */
388 ReqPrintIText(scr, dri, req->RPort, itext,
389 dims->itextleft, req->BorderTop + OUTERSPACING_Y + TEXTBOXBORDER_Y,
390 IntuitionBase);
392 /* draw gadgets */
393 RefreshGList(gadgets, req, NULL, -1L);
395 FreeScreenDrawInfo(scr, dri);
398 /**********************************************************************************************/
400 /* calculate dimensions of the requester */
401 static BOOL buildsysreq_calculatedims(struct sysreqdims *dims,
402 struct Screen *scr,
403 struct IntuiText *itext,
404 STRPTR *gadgetlabels,
405 struct IntuitionBase *IntuitionBase)
408 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
409 LONG currentgadget = 0;
410 WORD itextwidth, itextheight;
411 UWORD textboxwidth = 0, gadgetswidth; /* width of upper/lower part */
412 UWORD textboxheight;
414 /* calculate height of requester */
415 dims->fontheight = scr->RastPort.Font->tf_YSize;
417 ReqITextSize(scr, itext, &itextwidth, &itextheight, IntuitionBase);
419 textboxheight = scr->WBorTop + dims->fontheight + 1 +
420 OUTERSPACING_Y +
421 TEXTBOXBORDER_Y +
422 itextheight +
423 TEXTBOXBORDER_Y +
424 TEXTGADGETSPACING +
425 BUTTONBORDER_Y +
426 dims->fontheight +
427 BUTTONBORDER_Y +
428 OUTERSPACING_Y +
429 scr->WBorBottom;
432 * Ensure that text fits into requested height.
433 * Note that calculated size will override user-supplied size if the latter
434 * is not large enough, but not vice versa.
435 * This behavior is experimental. DisplayAlert() currently relies on it - sonic
436 * See also similar check for width below.
438 if (textboxheight > dims->height)
439 dims->height = textboxheight;
441 if (dims->height > scr->Height)
442 return FALSE;
444 textboxwidth = itextwidth + TEXTBOXBORDER_X * 2;
446 /* calculate width of gadgets */
447 dims->gadgetwidth = 0;
448 while (gadgetlabels[currentgadget])
450 UWORD gadgetwidth; /* width of current gadget */
452 gadgetwidth = TextLength(&scr->RastPort, gadgetlabels[currentgadget],
453 strlen(gadgetlabels[currentgadget]));
454 if (gadgetwidth > dims->gadgetwidth)
455 dims->gadgetwidth = gadgetwidth;
456 currentgadget++;
458 dims->gadgetwidth += BUTTONBORDER_X * 2;
459 gadgetswidth = (dims->gadgetwidth + GADGETGADGETSPACING) * dims->gadgets - GADGETGADGETSPACING;
461 /* calculate width of requester and req text position */
462 dims->itextleft = scr->WBorLeft + OUTERSPACING_X + TEXTBOXBORDER_X;
463 if (textboxwidth <= gadgetswidth)
465 dims->itextleft += (gadgetswidth - textboxwidth) / 2;
466 textboxwidth = gadgetswidth;
469 /* EXPERIMENTAL: Ensure that text fits into requested width */
470 if (textboxwidth > dims->width)
471 dims->width = textboxwidth;
473 dims->width += OUTERSPACING_X * 2 + scr->WBorLeft + scr->WBorRight;
474 if (dims->width > scr->Width)
475 return FALSE;
477 return TRUE;
480 /**********************************************************************************************/
482 /* make all the gadgets */
483 static struct Gadget *buildsysreq_makegadgets(struct sysreqdims *dims,
484 STRPTR *gadgetlabels,
485 struct Screen *scr,
486 struct IntuitionBase *IntuitionBase)
488 struct TagItem frame_tags[] =
490 {IA_FrameType, FRAME_BUTTON },
491 {IA_Width , dims->gadgetwidth },
492 {IA_Height , dims->fontheight + BUTTONBORDER_Y * 2},
493 {TAG_DONE }
495 struct Gadget *gadgetlist, *thisgadget = NULL;
496 struct Image *gadgetframe;
497 WORD currentgadget;
498 UWORD xoffset, restwidth;
500 if (gadgetlabels[0] == NULL)
501 return NULL;
503 gadgetframe = (struct Image *)NewObjectA(NULL, FRAMEICLASS, frame_tags);
504 if (!gadgetframe)
505 return NULL;
507 restwidth = dims->width - scr->WBorLeft - scr->WBorRight - OUTERSPACING_X * 2;
508 if (dims->gadgets == 1)
509 xoffset = scr->WBorLeft + OUTERSPACING_X + (restwidth - dims->gadgetwidth) / 2;
510 else
512 xoffset = scr->WBorLeft + OUTERSPACING_X;
513 restwidth -= dims->gadgets * dims->gadgetwidth;
516 gadgetlist = NULL;
518 for (currentgadget = 0; gadgetlabels[currentgadget]; currentgadget++)
520 WORD gadgetid = (currentgadget == (dims->gadgets - 1)) ? 0 : currentgadget + 1;
521 struct TagItem gad_tags[] =
523 {GA_ID , gadgetid },
524 {GA_Previous , (IPTR)thisgadget },
525 {GA_Left , xoffset },
526 {GA_Top , dims->height -
527 scr->WBorBottom - dims->fontheight -
528 OUTERSPACING_Y - BUTTONBORDER_Y * 2 },
529 {GA_Image , (IPTR)gadgetframe },
530 {GA_RelVerify , TRUE },
531 {TAG_DONE }
533 struct TagItem gad2_tags[] =
535 {GA_Text , (IPTR)gadgetlabels[currentgadget] },
536 {TAG_DONE }
539 thisgadget = NewObjectA(NULL, FRBUTTONCLASS, gad_tags);
542 if (currentgadget == 0)
543 gadgetlist = thisgadget;
545 if (!thisgadget)
547 intrequest_freegadgets(gadgetlist, IntuitionBase);
548 return NULL;
551 SetAttrsA(thisgadget, gad2_tags);
553 if ((currentgadget + 1) != dims->gadgets)
555 xoffset += dims->gadgetwidth +
556 restwidth / (dims->gadgets - currentgadget - 1);
557 restwidth -= restwidth / (dims->gadgets - currentgadget - 1);
561 return gadgetlist;
564 /**********************************************************************************************/
566 static void ReqITextSize(struct Screen *scr, struct IntuiText *itext,
567 WORD *width, WORD *height,
568 struct IntuitionBase *IntuitionBase)
570 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
571 WORD w, h;
573 *width = 0;
574 *height = 0;
576 while(itext)
578 w = TextLength(&scr->RastPort, itext->IText, strlen(itext->IText));
579 h = scr->RastPort.Font->tf_YSize;
581 if (itext->LeftEdge > 0) w += itext->LeftEdge;
582 if (itext->TopEdge > 0) h += itext->TopEdge;
584 if (w > *width) *width = w;
585 if (h > *height) *height = h;
587 itext = itext->NextText;
591 /**********************************************************************************************/
593 static void ReqPrintIText(struct Screen *scr, struct DrawInfo *dri,
594 struct RastPort *rp, struct IntuiText *itext, WORD x, WORD y,
595 struct IntuitionBase *IntuitionBase)
597 struct GfxBase *GfxBase = GetPrivIBase(IntuitionBase)->GfxBase;
599 SetDrMd(rp, JAM1);
600 SetAPen(rp, dri->dri_Pens[TEXTPEN]);
602 /* Experimental: obey font specified in supplied IntuiText structures.
603 Makes sense because coordinates specified in these structures are taken
604 into account, but i guess they are specified according to font size.
605 Currently DisplayAlert() relies on this behavior - sonic.
606 while(itext)
608 Move(rp, x + itext->LeftEdge,
609 y + itext->TopEdge + scr->RastPort.Font->tf_Baseline);
610 Text(rp, itext->IText, strlen(itext->IText));
612 itext = itext->NextText;
614 int_PrintIText(rp, itext, x, y, TRUE, IntuitionBase);
617 /**********************************************************************************************/