Aros/Developer/Docs/Libraries/Intuition
Introduction
edit- V34 = Amiga OS1.3
- V36 = Amiga OS2.x
- V37 = Amiga OS3.0
- V40 = Amiga OS3.1 AROS starting compatibility level
- V44 = Amiga OS3.5 OS3.9
- V45 = Amiga OS4
A typical application or game will involve...
- Setup any libraries, screen(s), windows.
- Setup any required intuition-based gadgets, menus and requesters or zune (mui based) gadgets, menus and requesters.
- Wait() for a message from Intuition/Zune about user activity or other events.
- Copy needed data from the message and tell Intuition/Zune you received it by replying. Look at the data and take the appropriate action. e.g. (presses a key on the keyboard, moves the mouse, gadgets hits, menu item selection, time elapsing, disk insertion, disk removal, and window rearrangement.)
- Repeat until the user wants to quit. (then closes windows, screen(s) and libraries)
Screens
editMost of the time, you will not need to setup a screen as you will frequently use an already in use public screen (Wanderer, Scalos or another WB replacement), so you can jump to opening windows on that screen.
AROS (like Amigas before) supports a concept called screens, each screen can be setup with a specific resolution and color depth, limited by the monitor drivers or CRT or LCD display used.
- Own public screen where main application can "host" additional modules with same screen specs etc. if needed
- Default shared public screen (NULL usually known as Wanderer, Scalos or Workbook) means multiple applications reside on the same screen which saves memory
- Last option, is a custom screen creates a new display for each application, i.e. if you want a specific resolution and color depth. Opening any new screen uses memory.
Opening a Screen using OpenScreenTags()
editBelow is the public structure that is already setup inside AROS, a template as such, for quick use in programming.
struct Screen {
struct Screen *NextScreen; /* linked list of screens */
struct Window *FirstWindow; /* linked list Screen's Windows */
WORD LeftEdge, TopEdge; /* parameters of the screen */
WORD Width, Height; /* parameters of the screen */
WORD MouseY, MouseX; /* position relative to upper-left */
UWORD Flags; /* see definitions below */
UBYTE *Title; /* null-terminated Title text */
UBYTE *DefaultTitle; /* for Windows without ScreenTitle */
/* Bar sizes for this Screen and all Window's in this Screen */
BYTE BarHeight, BarVBorder, BarHBorder, MenuVBorder, MenuHBorder;
BYTE WBorTop, WBorLeft, WBorRight, WBorBottom;
struct TextAttr *Font; /* this screen's default font */
/* the display data structures for this Screen */
struct ViewPort ViewPort; /* underlying graphics struct for each screen (&my_screen->ViewPort) */
struct RastPort RastPort; /* allow direct rendering into the screen (not useful) &my_screen->RastPort) */
struct BitMap BitMap; /* Screen->RastPort.BitMap in place of &Screen->BitMap whenever possible */
struct Layer_Info LayerInfo; /* each screen gets a LayerInfo */
/* Only system gadgets may be attached to a screen. The standard system Screen Gadgets automatically */
struct Gadget *FirstGadget;
UBYTE DetailPen, BlockPen; /* for bar/border/gadget rendering */
/* the following variable(s) are maintained by Intuition to support the DisplayBeep() color flashing technique */
UWORD SaveColor0;
/* This layer is for the Screen and Menu bars */
struct Layer *BarLayer;
UBYTE *ExtData;
UBYTE *UserData; /* general-purpose pointer to User data extension */
};
Each line adds and stores a bit of information about the screen in use. Each additional struct inside the Screen struct is an already existing 'blob' of pre-defined data storage inside AROS. A lot of AROS depends on struct's being used inside newer struct's to aid and speed up development.
every screen has a struct ViewPort (screen represent by graphics library) and each screen has a drawinfo (high level) and struct RastPort (low level handle that graphics library uses to draw on that screen). View is the whole display, including all visible screens accessed by ViewAddress()
Tags are a list of parameter names followed comma and then by a value. For example, to specify the DefaultTitle of a screen you use the SA_Title followed a comma and then by the title in quotes and there are many other tags that can be used to define bits of a screen, see later for a list. The last tag item should always be TAG_DONE.
The title bar of the screen, not the title bar of the window, is drawn in front of the window. If moving the window from its default 0,0 position with WA_Top and/or WA_Left (SA_ShowTitle is FALSE of course), just ignore those tags in fullscreen mode instead of setting them to 0.
// Opens a PubScreen. The name can be given as argument.
// Default name is "MYPUBSCREEN".
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <stdlib.h>
#include <stdio.h>
struct Screen *myscreen;
struct Window *mywindow;
BYTE signalnum;
void clean_exit(STRPTR txt)
{
if (mywindow) CloseWindow(mywindow);
if (myscreen) CloseScreen(myscreen);
FreeSignal(signalnum);
if (txt)
{
PutStr(txt);
exit(RETURN_FAIL);
}
exit(RETURN_OK);
}
int main(int argc, char **argv)
{
BOOL done = FALSE;
BOOL closewindow = FALSE;
ULONG signals, winsig, pubsig;
struct IntuiMessage *message;
char *name;
if (argc == 2)
{
name = argv[1];
}
else
{
name = "MYPUBSCREEN";
}
if ((signalnum = AllocSignal(-1)) == -1)
{
clean_exit("Can't allocate signal\n");
}
if
(
(
myscreen = OpenScreenTags
(
NULL,
SA_PubName, name,
SA_PubSig, signalnum,
SA_LikeWorkbench, TRUE,
SA_Title, name,
TAG_DONE
)
) == NULL
)
{
clean_exit("Can't open screen\n");
}
if
(
(
mywindow = OpenWindowTags
(
NULL,
WA_Left, 30,
WA_Top, 30,
WA_Width, 250,
WA_Height, 100,
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_Activate, TRUE,
WA_Title, "Close me to close the screen",
WA_IDCMP, IDCMP_CLOSEWINDOW,
WA_PubScreen, myscreen,
TAG_DONE
)
) == NULL
)
{
clean_exit("Can't open window\n");
}
if ((PubScreenStatus(myscreen, 0) & 1) == 0)
{
clean_exit("Can't make screen public");
}
winsig = 1L << mywindow->UserPort->mp_SigBit;
pubsig = 1L << signalnum;
while (!done)
{
signals = Wait(winsig | pubsig);
if (mywindow && (signals & winsig))
{
while (NULL != (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort)))
{
if (message->Class == IDCMP_CLOSEWINDOW)
{
closewindow = TRUE;
}
ReplyMsg((struct Message *)message);
}
}
if (signals & pubsig)
{
if (PubScreenStatus(myscreen, PSNF_PRIVATE) & 1)
{
done = TRUE;
}
else
{
PutStr("Failed to make screen private\n");
}
}
if (closewindow)
{
if (mywindow) CloseWindow(mywindow);
winsig = 0;
mywindow = NULL;
closewindow = FALSE;
}
}
clean_exit(NULL);
return 0;
}
#include <proto/intuition.h>
#include <proto/dos.h>
#include <intuition/screens.h>
int main() {
/* makes a copy of the Screen struct(ure) and calls that copy myScreen, changes are made to this copy */
struct Screen *myScreen;
/* you can call the copy 'myScreen' any name you like, as long as you use it throughout the program consistently */
/* describe how 'myScreen' looks like by using tags SA_? */
myScreen = OpenScreenTags(NULL,
SA_Left, 0, SA_Top, 0, SA_Width, 640, SA_Height, 480,
SA_Depth, 8, SA_Title, "My New Screen",
SA_Type, PUBLICSCREEN,
SA_SysFont, 1,
TAG_DONE);
Delay(500);
/* check if screen open, returns TRUE for success and FALSE for failure, if so, use CloseScreen() command to close */
if (myScreen) CloseScreen(myScreen);
}
#include <proto/intuition.h>
#include <proto/dos.h>
#include <intuition/screens.h>
#include <proto/graphics.h>
int main (void)
{
struct Screen *scr;
struct Window *win;
struct RastPort *rp;
if (scr = OpenScreenTags (NULL,SA_LikeWorkbench,TRUE,TAG_END)) /* open RTG screen */
{
Delay (50); /* one second */
if (win = OpenWindowTags (NULL,
WA_CustomScreen,scr,
WA_Left,100,WA_Top,100,
WA_Width,200,WA_Height,100,
TAG_END))
{
rp = win->RPort;
Move (rp,20,40);
Text (rp,"Beep !",6); /* you won't see DisplayBeep on a RTG screen */
Delay (50); /* one second */
CloseWindow (win);
}
Delay (100); /* two seconds */
CloseScreen (scr);
}
return (0);
}
Opening or Locking a Public Screen
editIf you do not wish to use a custom screen, then you can use an existing public screen such as Wanderer. Screens can be closed at any time, so to prevent that, the public screen should be locked while the application is running. You can do this using the LockPubScreen function.
myScreen = LockPubScreen(name)
where name is the name of the Public Screen to lock.If no name (NULL) is given then it will use the Workbench public screen. Once done with the Public screen you can then Unlock it
UnlockPubScreen(NULL, myScreen);
#include <proto/intuition.h>
#include <intuition/screens.h>
#include <proto/dos.h>
#include <stdio.h>
int main(void) {
struct Screen *myScreen;
if (myScreen = LockPubScreen(NULL)) {
printf("Public Screen locked.\n");
Delay(100);
UnlockPubScreen(NULL, myScreen);
printf("Public Screen unlocked.\n");
}
return 0;
}
if ((scr->screen = LockPubScreen(PROGNAME)))
{
scr->screentype = PUBLICSCREEN;
success = TRUE;
scr->modeID = GetVPModeID(&scr->screen->ViewPort);
}
else
{
if (id != INVALID_ID)
{
UWORD empty = 0xffff;
if ((scr->screen = OpenScreenTags(NULL,
SA_Width, width,
SA_Height, height
SA_Depth, depth,
SA_DisplayID, id,
SA_Type, PUBLICSCREEN,
SA_AutoScroll, TRUE,
SA_Title, (IPTR)PROGNAME,
SA_PubName, (IPTR)PROGNAME,
SA_ShowTitle, FALSE,
SA_LikeWorkbench, TRUE,
SA_FullPalette, TRUE,
SA_SharePens, TRUE,
SA_Pens, (IPTR)&empty,
TAG_DONE)))
{
PubScreenStatus(scr->screen, 0);
scr->screentype = CUSTOMSCREEN;
scr->modeID = id;
success = TRUE;
}
}
}
if (defscreen)
{
UnlockPubScreen(NULL, defscreen);
}
}
//else
if (!success)
{
if (!success)
{
if (mvs->scropenmode == SCROPENMODE_PUBLIC)
{
if ((scr->screen = LockPubScreen(mvs->pubscreen)))
{
ScreenToFront(scr->screen);
success = TRUE;
}
}
}
if (!success)
{
success = !!(scr->screen = LockPubScreen(NULL));
}
if (success)
{
scr->screentype = PUBLICSCREEN;
scr->modeID = GetVPModeID(&scr->screen->ViewPort);
}
}
Screen Reference
editScreen Tags
editSA_Left - Default is 0 SA_Top - Default is 0 SA_Width - Default depends on display SA_Height - Default depends on display SA_Depth - Select depth of screen. This specifies how many colors the screen can display. Default 1 SA_DetailPen - Pen number for details. Default is 0 (obsolete) SA_BlockPen - Pen number for block fills. Default is 1 (obsolete) SA_Title (STRPTR) - Default NULL SA_Font (struct TextAttr *) - user's preferred monospace font. Default NULL SA_BitMap (struct BitMap *) - Provide a bitmap SA_ShowTitle (BOOL) - Default TRUE SA_Behind (BOOL) - Screen will be created behind other open screens. Default is FALSE SA_Quiet (BOOL) - Intuition does not draw any system gadgets and screen title. Defaults is FALSE SA_Type - PUBLICSCREEN or CUSTOMSCREEN SA_DisplayID - 32-bit display mode ID SA_Overscan - Set an overscan mode. Possible values OSCAN_TEXT (default) - OSCAN_STANDARD - OSCAN_MAX - OSCAN_VIDEO SA_DClip (struct Rectangle *) - Define a DisplayClip region - see SA_Overscan above SA_AutoScroll (BOOL) - Screens can be larger than the DisplayClip region. Set this tag TRUE if automatic scrolling SA_PubName (STRPTR) - Make this screen a public screen with the given name. Screen is opened in "private" mode SA_PubTask (struct Task *) - Task to be signalled, when last visitor window of a public screen is closed SA_PubSig (UBYTE) - Signal number used to notify a task when the last visitor window of a public screen is closed SA_Colors (struct ColorSpec *) - Screen's initial color palette. Array must be terminated with ColorIndex = -1 SA_FullPalette (BOOL) - Intuition maintains a set of 32 preference colors. Default is FALSE SA_ErrorCode (ULONG *) - OSERR_NOMONITOR, OSERR_NOCHIPS, OSERR_NOMEM, OSERR_NOCHIPMEM, OSERR_PUBNOTUNIQUE, OSERR_UNKNOWNMODE, OSERR_TOODEEP, OSERR_ATTACHFAIL SA_SysFont - Select screen font type. overwrites SA_Font. 0=Fixed-width font, 1=Font set by font prefs SA_Parent (struct Screen *) - Attach the screen to the given parent screen SA_FrontChild (struct Screen *) - Attach given child screen to this screen SA_BackChild (struct Screen *) - Attach given child screen to this screen SA_BackFill (struct Hook *) - Backfill hook (see layers library) SA_Draggable (BOOL) - Make screen movable. Default is TRUE SA_Exclusive (BOOL) - False (default) but if TRUE screen must not share the display with other screens SA_Pens (UWORD *) - Define the pen array for struct DrawInfo. This enables the 3D look - terminates with 0 SA_SharePens (BOOL) - if FALSE (default) obtains the pens of a public screen with PENF_EXCLUSIVE. if TRUE pens are not set SA_Colors32 (ULONG *) - Data is sent to graphics.library/LoadRGB32(). Overwrites values which were set by SA_Colors SA_Interleaved (BOOL) - Request interleaved bitmap. It this fails a non-interleaved bitmap will be allocated SA_VideoControl (struct TagItem *) - Taglist which will be passed to VideoControl() after the screen is open SA_ColorMapEntries = Number of entries of the ColorMap. Default 1<<depth, but not less than 32 SA_LikeWorkbench (BOOL) - Inherit depth, colors, pen-array, screen mode, etc. from the WB replacement screen SA_MinimizeISG (BOOL) - Minimize the Inter-Screen Gap
Windows
editBelow is another public structure that is already setup inside AROS, a template as such, for quick use in programming.
struct Window { struct Window *NextWindow; /* for the linked list to next Window */ WORD LeftEdge, TopEdge, Width, Height; /* window dimensions */ WORD MouseY, MouseX; /* relative top top-left corner */ WORD MinWidth, MinHeight; /* minimum sizes */ UWORD MaxWidth, MaxHeight; /* maximum sizes */ ULONG Flags; struct Menu *MenuStrip; /* first in a list of menu headers */ UBYTE *Title; /* title text for the Window */ struct Requester *FirstRequest, *DMRequest; /* first in linked list of active reqs - the double-menu Requester */ WORD ReqCount; /* number of Requesters blocking this Window */ struct Screen *WScreen; /* this Window's Screen */ /* Each window has one RastPort but within each RastPort a BitMap pointer. */ struct RastPort *RPort; BYTE BorderLeft, BorderTop, BorderRight, BorderBottom; struct RastPort *BorderRPort; struct Gadget *FirstGadget; /* these are for opening/closing the windows */ struct Window *Parent, *Descendant; /* sprite data information for your own Pointer set these AFTER you Open the Window by calling SetPointer() */ UWORD *Pointer; BYTE PtrHeight, PtrWidth; BYTE XOffset, YOffset; /* the IDCMP Flags and User's and Intuition's Message Ports */ ULONG IDCMPFlagS; struct MsgPort *UserPort, *WindowPort; struct IntuiMessage *MessageKey; UBYTE DetailPen, BlockPen; /* the CheckMark is a pointer to the imagery that will be used when rendering MenuItems of this Window checkmarked - if this is equal to NULL, you'll get the default imagery */ struct Image *CheckMark; /* if non-null, Screen title when Window is active */ UBYTE *ScreenTitle; WORD GZZMouseX, GZZMouseY, GZZWidth, GZZHeight; ; general-purpose pointer to User data extension UBYTE *ExtData; BYTE *UserData; struct Layer *WLayer; /* stash of Window.RPort->Layer */ struct TextFont *IFont; ULONG MoreFlags; };
Having set a screen, you can now have as many windows on that screen as you want.
Opening Windows is very similar to opening screens, OpenWindowTags() with window tags as well...
As Screen tags started with SA_, Window tags start with WA_ and in the case of WA_IDCMP and WA_Flags have further sub-tags. A list follows later...
So when I do window->Width / rport->TxWidth, the number of columns ends up being greater than the visible area, so text goes off screen, same for height. Is there a way to get the window size less the attached gadgets/widgets? For a non borderless window (aka normal window ), the usable width is w->Width - w->BorderLeft - w->BorderRight, and the height, w->Height - w->BorderTop - w->BorderBottom.
For a GimmeZeroZero window, use w->GZZWidth and w->GZZHeight instead w->Width and w->Height. GZZWidth and GZZHeight are maintained for non-GZZ windows, too. You don't need to calculate them yourself.
To be able to resize a window you need to set WA_MinWidth, WA_MinHeight, WA_MaxWidth and WA_MaxHeight because they all default to WA_Width resp. WA_Height.
Window Example
editFor AROS you should omit all the usual #?Base (GfxBase, IntuitionBase, DOSBase,... ) declarations and "OpenLibrary() & CloseLibrary()" calls for them because AROS GCC compiler opens and closes them automatically for you when it sees a reference. Most of the core libraries are auto opened by the compiler.
This is for background knowledge only. When a library is opened, it will return a pointer to a Library structure or a Base structure specific to that library otherwise it will return a NULL value. Converting old Commodore examples is probably a good way to get understanding of Amiga program to AROS program differences. NOTE those old examples need editing because of OpenLibrary, CloseLibrary and #?base stuff... In the past, to close a library, use the CloseLibrary() function and provide the pointer to the Library or Base structure which was returned in the OpenLibrary(). It is normal practice to test that the library was opened before trying to close it.
See AROS website examples, Aros/Developer/Docs/Examples/SimpleWindowIntuition and here
#include <proto/exec.h>
#include <exec/libraries.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <intuition/intuition.h>
int main(int argc, char *argv[])
{
int error = RETURN_OK;
/* makes a copy of the Window struct(ure) and calls that copy win, changes are made to this copy */
struct Window *win;
/* describe the copy window 'win' looks like by using tags WA_?, this is separate from the struct stuff above */
win = OpenWindowTags
(
NULL, WA_Width, 200, WA_Height, 100,
WA_Title, "Hello World!", TAG_DONE
);
if( win )
{
/* Now wait for two seconds, so we can look at our nice window.
*/
Delay(100);
/* We close our window again. */
CloseWindow(win);
}
return error;
}
Windows Reference
editstruct TagItem + OpenWindowTagList() Open a window. Not used much see below... OpenWindowTags() Alternate calling sequence for OpenWindowTagList(). CloseWindow() Close a window. BeginRefresh() Turn on optimized window refresh mode. EndRefresh() Turn off optimized window refresh mode. RefreshWindowFrame() Redraw the borders and border gadgets of an open window. ActivateWindow() Make an open window active. SizeWindow() Change the size of an open window. MoveWindow() Change the position of an open window. ChangeWindowBox() Change the size and position of an open window. WindowLimits() Change the minimum and maximum sizes of an open window. WindowToBack() Move a window behind all other windows. WindowToFront() Move a window in front of all other windows. MoveWindowInFrontOf() Move a window in front of another window. ZipWindow() Change the size of window to its alternate size. SetWindowTitles() Change the window titles for the window and the screen. SetPointer() Set up a custom pointer to display whenever the window is active. ClearPointer() Restore the mouse pointer to its default imagery.
Windows Tags
editWA_Left - Left edge of the window WA_Top - Top edge of the window WA_Width - Width of the window WA_Height - Height of the window WA_DetailPen - Pen number for window details (obsolete) WA_BlockPen - Pen number for filled blocks (obsolete) WA_IDCMP - Define what events should send messages to your task IDCMP_CLOSEWINDOW - Check if the Window Close button has been pressed. If so, then close down program IDCMP_GADGETUP - Check to see if a Gadget has been pressed AND released IDCMP_GADGETDOWN - Check to see if a Gadget has been pressed (but not released yet) - Not often used IDCMP_MENUPICK - Check to see if a menu item has been selected IDCMP_ACTIVEWINDOW - Check to see if Window has been activated (clicked on title bar) IDCMP_MOUSEMOVE - Check if mouse moves (useful to keep track of x,y position) IDCMP_NEWSIZE - Check to see if window has been resized IDCMP_VANILLAKEY - Check to see if a key on keyboard has been pressed IDCMP_RAWKEY - IDCMP_NEWPREFS - IDCMP_DISKINSERTED - Check to see if a floppy disk has been inserted, probably ready for saving IDCMP_DISKREMOVED - message type is broadcast to all IDCMP that have this flag set, not just active win IDCMP_INTUITICKS - IDCMP_IDCMPUPDATE - IDCMP_CHANGEWINDOW - IDCMP_LONELYMESSAGE - system use only WA_Flags - WFLG_SIZEGADGET, WFLG_DRAGBAR, WFLG_DEPTHGADGET, WFLG_CLOSEGADGET WFLG_BORDERLESS, WFLG_ACTIVATE, WFLG_NEWLOOKMENUS WA_Gadgets (struct Gadget *) - Pointer to a linked list of gadgets (WB 2.0 only) WA_Title (STRPTR) - Window title string WA_CustomScreen (struct Screen *) - Open window on the given screen WA_MinWidth WA_MinHeight WA_MaxWidth WA_MaxHeight WA_SizeGadget (BOOL) - Make window resizeable WA_DragBar (BOOL) - Make window dragable WA_DepthGadget (BOOL) - Add a depth gadget WA_CloseGadget (BOOL) - Add a close gadget WA_Backdrop (BOOL) - Create a window which is placed behind other windows WA_ReportMouse (BOOL) - Store mouse position in struct Window WA_NoCareRefresh (BOOL) - Use this if you don't want to be responsible for calling BeginRefresh()/EndRefresh() WA_Borderless (BOOL) - Create borderless window WA_Activate (BOOL) - Make this window the active one, i.e. it receives the input from mouse and keyboard WA_RMBTrap (BOOL) - Set to TRUE if you want to get button events events for the right mouse button WA_SimpleRefresh (BOOL) - Enable simplerefresh mode. Only specify if TRUE WA_SmartRefresh (BOOL) - Enable smartrefresh mode. Only specify if TRUE WA_SuperBitMap (struct BitMap *) - Create window with superbitmap refreshing, 0 to keep the current size as limit WA_SizeBRight (BOOL) - Place size gadget in right window border WA_SizeBBottom (BOOL) - Place size gadget in bottom window border WA_GimmeZeroZero (BOOL) - Create a GimmeZeroZero window WA_NewLookMenus (BOOL) - Use DrawInfo colors for rendering the menu bar WA_ScreenTitle (STRPTR) - Screen title which is shown when window is active WA_AutoAdjust (BOOL) - usually TRUE make the window to fit on the screen, wrt WA_MinWidth and WA_MinHeight WA_InnerWidth WA_InnerHeight - Dimensions of the interior region of the window - this restricts border gadgets GACT_LEFTBORDER gadgets can't be GFLG_RELWIDTH if WA_InnerWidth is used GACT_RIGHTBORDER gadgets must be GFLG_RELRIGHT if WA_InnerWidth is used GACT_TOPBORDER gadgets can't be GFLG_RELHEIGHT if WA_InnerHeight is used GACT_BOTTOMBORDER gadgets must be GFLG_RELBOTTOM if WA_InnerHeight is used WA_PubScreen (struct Screen *) - Open the window on the public screen - NULL being WB replacement WA_PubScreenName (STRPTR) - Open the window on the public screen (name) WA_PubScreenFallBack (BOOL) - if TRUE fallback to default public screen if other public screen is not available WA_Zoom (WORD *) - 4 WORDs set Left Top Width Height of the other zoom position - also adds zoom gadget WA_MouseQueue - Limits the number of possible mousemove messages. Can be changed with SetMouseQueue() WA_RptQueue - Limits the number of possible repeated IDCMP_RAWKEY, IDCMP_VANILLAKEY and IDCMP_IDCMPUPDATE messages WA_BackFill (struct Hook *) - Function to be called for backfilling WA_MenuHelp (BOOL) - Enables menuhelp. Pressing the help key during menu handling sends IDCMP_MENUHELP messages. WA_NotifyDepth (BOOL) - If TRUE send IDCMP_CHANGEWINDOW events when window is depth arranged. Code field=CWCODE_DEPTH WA_Checkmark (struct Image *) - Image to use as a checkmark in menus WA_AmigaKey (struct Image *) - Image to use as the Amiga-key symbol in menus WA_Pointer (APTR) - The pointer to associate with the window. Use NULL for the Preferences default pointer WA_BusyPointer (BOOL) - Enable the Preferences busy-pointer. Default is FALSE WA_PointerDelay (BOOL) - Set this to TRUE to delay change of the pointer image - prevents flickering WA_HelpGroup (ULONG) - Get IDCMP_GADGETHELP messages from the active window and all other windows WA_HelpGroupWindow (struct Window *) - Similar for WA_HelpGroup. Use the helpgroup of another window WA_TabletMessages (BOOL) - Request extended tablet data - Default is FALSE WA_ToolBox (BOOL) - Make this window a toolbox window WA_Parent (struct Window *) - Make the window a child of the given window. WA_Visible (BOOL) - Make window visible Default is TRUE WA_Shape (struct Region *) - WA_ShapeHook (struct Hook *) -
Event Handling
editA window can receive events destined for it. The usual way is for the application to ask Intuition to send it messages which are based on the input event that Intuition has processed. These messages, called IntuiMessages, are standard Amiga Exec messages, and are sent to a port called an Intuition Direct Communications Message Port, or IDCMP. Every window may have an IDCMP associated with it. Although AmigaOS(TM) started with intuition events, AROS has incorporated these as well for backwards compatibility purposes but recommends using Zune instead, see here Zune
a) Wait for signal from the current Active Window b) If a signal has been sent, get the Message data structure c) Reply to the message, so that message is removed from the queue and is being dealt with. d) Determine the message class (or gadget or event) occurred by comparing class value with IDCMP flags e) Do some user processing with that event.
Input = Hardware Device -> HIDD or .device -> Event Handler -> IDCMP or Console -> Application
Output = Application -> Console or intuition -> graphics library -> display monitor
IDCMP
editAn application will have messages sent to it by any intuition event. These messages, IntuiMessages, are standard Exec messages, and are sent to a port called an IDCMP. Every window may/will have an IDCMP associated with it (Window->UserPort). Keys will not work automatically in a window. You must setup it by WA_IDCMP, tags.
struct IntuiMessage { struct Message ExecMessage; ULONG Class; UWORD Code; UWORD Qualifier; APTR IAddress; WORD MouseX, MouseY; ULONG Seconds, Micros; struct Window *IDCMPWindow; struct IntuiMessage *SpecialLink; };
- IDCMP_VANILLAKEY - events provide for simple ASCII text and standard control keys like space, return and backspace
- IDCMP_RAWKEY - returns all keycodes, both key-up and key-down, including function keys (it's mean keyboards, moving, gadget (close/resize) and many other things)
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
int main (void)
{
/* set up variables to be used in this function */
struct Window *win;
struct IntuiMessage *mess;
BOOL cont;
BOOL lbutton;
BOOL rbutton;
long old_x;
long old_y;
long x;
long y;
win = OpenWindowTags (NULL,
WA_Left,112,
WA_Top,84,
WA_Width,800,
WA_Height,600,
WA_Flags,WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_SIZEGADGET | WFLG_RMBTRAP | WFLG_REPORTMOUSE | WFLG_ACTIVATE | WFLG_GIMMEZEROZERO | WFLG_NOCAREREFRESH,
WA_IDCMP,IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE,
WA_MinWidth,80,WA_MinHeight,40,
WA_MaxWidth,-1,WA_MaxHeight,-1,
TAG_END);
/* if (win==NULL) { */
if (!win)
{
Printf ("cannot open window\n");
return (RETURN_FAIL);
}
rbutton = FALSE;
lbutton = FALSE;
x = win->MouseX;
y = win->MouseY;
old_x = x;
old_y = y;
cont = TRUE;
do {
if (Wait ((1L << win->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
cont = FALSE;
while (mess = (struct IntuiMessage *) GetMsg (win->UserPort))
{
switch (mess->Class)
{
case IDCMP_MOUSEMOVE:
x = mess->MouseX - win->BorderLeft;;
y = mess->MouseY - win->BorderTop;
break;
case IDCMP_MOUSEBUTTONS:
switch (mess->Code)
{
case SELECTDOWN:
lbutton = TRUE;
break;
case SELECTUP:
lbutton = FALSE;
break;
case MENUDOWN:
rbutton = TRUE;
break;
case MENUUP:
rbutton = FALSE;
break;
}
break;
case IDCMP_VANILLAKEY:
if (mess->Code == 0x1b) /* Esc */
cont = FALSE;
break;
case IDCMP_CLOSEWINDOW:
cont = FALSE;
break;
}
ReplyMsg ((struct Message *)mess);
}
if (x != old_x || y != old_y)
{
if (rbutton && lbutton)
{
SetAPen (win->RPort,3);
Move (win->RPort,old_x,old_y);
Draw (win->RPort,x,y);
}
else if (rbutton)
{
SetAPen (win->RPort,2);
Move (win->RPort,old_x,old_y);
Draw (win->RPort,x,y);
}
else if (lbutton)
{
SetAPen (win->RPort,1);
Move (win->RPort,old_x,old_y);
Draw (win->RPort,x,y);
}
old_x = x;
old_y = y;
}
}
while (cont);
CloseWindow (win);
return (RETURN_OK);
}
- Look here for more about keycodes http://en.wikibooks.org/wiki/Aros/Developer/Docs/Libraries/Keymap
/* loop for each frame */
while (loop) {
/* check for input */
while ((msg = (struct IntuiMessage *)GetMsg (w->UserPort)) != NULL) {
/* After we have successfully collected the message we can read */
/* it, and save any important values which we maybe want to check later */
class = msg->Class; /* IDCMP flag */
code = msg->Code;
/* After we have read it we reply as fast as possible: */
/* REMEMBER! Do never try to read a message after you have replied! */
/* (Some other process has maybe changed it.) */
ReplyMsg ((struct Message *)msg);
switch (class) {
case IDCMP_VANILLAKEY:
switch (code) {
case 0x03: /* CTRL/C */
case 0x1b: /* ESC */
case 'q': /* q */
case 'Q': /* Q */
break;
default:
break;
}
break;
case IDCMP_RAWKEY:
switch (code) {
case 0x11: /* W */
break;
case 0x20: /* A */
break;
case 0x21: /* S */
break;
case 0x22: /* D */
break;
case 0x50: /* F1 */
break;
case 0x51: /* F2 */
break;
case 0x52: /* F3 */
break;
case 0x53: /* F4 */
break;
case 0x54: /* F5 */
break;
case 0x55: /* F6 */
break;
case 0x56: /* F7 */
break;
case 0x57: /* F8 */
break;
case 0x58: /* F9 */
break;
case 0x59: /* F10 */
break;
default:
break;
}
break;
case IDCMP_MOUSEBUTTONS:
if (code == MENUDOWN)
loop = FALSE;
break;
default:
break;
}
}
INTUITICKS
editBasically, creating an IDCMP loop to check for user input and/or timer events. Then you probably set up a timer device call that will give you those events. You have to update your window content with the help of IDCMP_INTUITICKS ("ticks" roughly ten times a second). These tick events are to be used as wake up call, and not as timers.
case IDCMP_GADGETUP: gadget_down_happened=FALSE; break; case IDCMP_GADGETDOWN: gadget_down_happened=TRUE; break; case IDCMP_INTUITICKS: if(gadget_down_happened) { update_window_contents(); } break;
case IDCMP_INTUITICKS:
/*
* If the user is NOT holding the LMB down, then we'll
* report this event back to the program in order not to confuse
* the select box drawing routines.
*/
if( !(imsg->Qualifier & IEQUALIFIER_LEFTBUTTON))
method = GID_DW_INTUITICKS;
break;
Of course you might want to only update the content every 3rd intuitick for example and only, if the proportional gadget has changed etc.
Tablets
editold and new style tablets events as defined in Intuition
System support for tablets started on WB 2.x. At that time, tablet drivers were supposed to send informations to the input device as events such as (X,Y) range and coordinates plus the pressure. This method is known today as old style tablet events.
Starting from WB3.0, a new kind of tablet events has been defined to support more tablet's features such as proximity, tilt, etc. This method is known as new style tablet events.
All IntuiMessages are now slightly extended. The ExtIntuiMessage structure has an additional field for tablet data, which is usually NULL. If a tablet driver which is sending IESUBCLASS_NEWTABLET events is installed in the system, windows with the WA_TabletMessages property set will find that eim_TabletData points to the TabletData structure. Applications must first check that this field is non-NULL; it will be NULL for certain kinds of message, including mouse activity generated from other than the tablet (i.e. the keyboard equivalents or the mouse itself).
struct IntuiMessage { struct Message ExecMessage; ULONG Class; UWORD Code; UWORD Qualifier; APTR IAddress; WORD MouseX, MouseY; ULONG Seconds, Micros; struct Window *IDCMPWindow; struct IntuiMessage *SpecialLink; };
struct ExtIntuiMessage { struct IntuiMessage eim_IntuiMessage; struct TabletData *eim_TabletData; };
WA_TabletMessages - (BOOL) Set to TRUE to request extended IntuiMessages for your window. If a tablet driver is generating IESUBCLASS_NEWTABLET input events, you will be able to receive extended tablet information with most IntuiMessages. See the eim_TabletData field of the ExtIntuiMessage structure. Defaults to FALSE. (V39)
#define WA_TabletMessages TRUE
(WA_Dummy + 0x37) is a boolean. Set to TRUE to request that tablet information be included in IntuiMessages sent to your window. Requires that something (i.e. a tablet driver) feed IESUBCLASS_NEWTABLET InputEvents into the system. For a pointer to the TabletData, examine the ExtIntuiMessage->eim_TabletData field.
struct TabletData { UWORD td_XFraction; UWORD td_YFraction; ULONG td_TabletX; ULONG td_TabletY; ULONG td_RangeX; ULONG td_RangeY; struct TagItem * td_TagList; /* see below */ }; /* Tags */ #define TABLETA_Dummy (TAG_USER + 0x3A000) #define TABLETA_TabletZ (TABLETA_Dummy + 0x01) #define TABLETA_RangeZ (TABLETA_Dummy + 0x02) #define TABLETA_AngleX (TABLETA_Dummy + 0x03) #define TABLETA_AngleY (TABLETA_Dummy + 0x04) #define TABLETA_AngleZ (TABLETA_Dummy + 0x05) #define TABLETA_Pressure (TABLETA_Dummy + 0x06) #define TABLETA_ButtonBits (TABLETA_Dummy + 0x07) #define TABLETA_InProximity (TABLETA_Dummy + 0x08) #define TABLETA_ResolutionX (TABLETA_Dummy + 0x09) #define TABLETA_ResolutionY (TABLETA_Dummy + 0x0a) struct TabletHookData { struct Screen * thd_Screen; ULONG thd_Width; ULONG thd_Height; LONG thd_ScreenChanged; };
Intuition supports the IESUBCLASS_NEWTABLET subclass of the IECLASS_NEWPOINTERPOS event. The ie_EventAddress of such an event points to a TabletData structure
The TabletData structure contains certain elements including a taglist. The taglist can be used for special tablet parameters. A tablet driver should include only those tag-items the tablet supports. An application can listen for any tag-items that interest it. Note: an application must set the WA_TabletMessages attribute to TRUE to receive this extended information in its IntuiMessages.
The definitions given here MUST be followed. Pay careful attention to normalization and the interpretation of signs.
TABLETA_TabletZ: the current value of the tablet in the Z direction. This unsigned value should typically be in the natural units of the tablet. You should also provide TABLETA_RangeZ.
TABLETA_RangeZ: the maximum value of the tablet in the Z direction. Normally specified along with TABLETA_TabletZ, this allows the application to scale the actual Z value across its range.
TABLETA_AngleX: the angle of rotation or tilt about the X-axis. This number should be normalized to fill a signed long integer. Positive values imply a clockwise rotation about the X-axis when viewing from +X towards the origin.
TABLETA_AngleY: the angle of rotation or tilt about the Y-axis. This number should be normalized to fill a signed long integer. Positive values imply a clockwise rotation about the Y-axis when viewing from +Y towards the origin.
TABLETA_AngleZ: the angle of rotation or tilt about the Z axis. This number should be normalized to fill a signed long integer. Positive values imply a clockwise rotation about the Z-axis when viewing from +Z towards the origin.
Note: a stylus that supports tilt should use the TABLETA_AngleX and TABLETA_AngleY attributes. Tilting the stylus so the tip points towards increasing or decreasing X is actually a rotation around the Y-axis. Thus, if the stylus tip points towards positive X, then that tilt is represented as a negative TABLETA_AngleY. Likewise, if the stylus tip points towards positive Y, that tilt is represented by positive TABLETA_AngleX.
TABLETA_Pressure: the pressure reading of the stylus. The pressure should be normalized to fill a signed long integer. Typical devices won't generate negative pressure, but the possibility is not precluded. The pressure threshold which is considered to cause a button-click is expected to be set in a Preferences program supplied by the tablet vendor. The tablet driver would send IECODE_LBUTTON-type events as the pressure crossed that threshold.
TABLETA_ButtonBits: ti_Data is a long integer whose bits are to be interpreted at the state of the first 32 buttons of the tablet.
TABLETA_InProximity: ti_Data is a boolean. For tablets that support proximity, they should send the TABLETA_InProximity,FALSE} tag item when the stylus is out of proximity. Can be used as a mouse-blanking commodity which keys off this to blank the mouse. When this tag is absent, the stylus is assumed to be in proximity.
TABLETA_ResolutionX: ti_Data is an unsigned long integer which is the x-axis resolution in dots per inch.
TABLETA_ResolutionY: ti_Data is an unsigned long integer which is the y-axis resolution in dots per inch.
Text
editIntuiText
editstruct IntuiText
{
UBYTE FrontPen, BackPen; /* the pen numbers for the rendering */
UBYTE DrawMode; /* the mode for rendering the text */
WORD LeftEdge; /* relative start location for the text */
WORD TopEdge; /* relative start location for the text */
struct TextAttr *ITextFont; /* if NULL, you accept the default */
UBYTE *IText; /* pointer to null-terminated text */
struct IntuiText *NextText; /* pointer to another IntuiText to render */
};
dri_Pens[TEXTPEN];
myBACKGROUNDPEN = drawinfo->dri_Pens[BACKGROUNDPEN];
/* create a TextAttr that matches the specified font. */
myTextAttr.ta_Name = drawinfo->dri_Font->tf_Message.mn_Node.ln_Name;
myTextAttr.ta_YSize = drawinfo->dri_Font->tf_YSize;
myTextAttr.ta_Style = drawinfo->dri_Font->tf_Style;
myTextAttr.ta_Flags = drawinfo->dri_Font->tf_Flags;
/* open a simple window on the workbench screen for displaying a text string.
An application would probably never use such a window, but it is useful for demonstrating graphics...
*/
if ((win = OpenWindowTags(NULL,
WA_PubScreen, (IPTR)screen,
WA_RMBTrap, TRUE,
WA_IDCMP, IDCMP_RAWKEY,
TAG_END)))
{
myIText.FrontPen = myTEXTPEN;
myIText.BackPen = myBACKGROUNDPEN;
myIText.DrawMode = JAM2;
myIText.LeftEdge = MYTEXT_LEFT;
myIText.TopEdge = MYTEXT_TOP;
myIText.ITextFont = &myTextAttr;
myIText.IText = "Hello, World. ;-)";
myIText.NextText = NULL;
/* Draw the text string at 10,10 */
PrintIText(win->RPort,&myIText,10,10);
/* Wait for keypress */
Wait (1L << win->UserPort->mp_SigBit);
CloseWindow(win);
}
FreeScreenDrawInfo(screen,drawinfo);
}
UnlockPubScreen(NULL,screen);
}
return 0;
}
GUI Systems
editAlthough AmigaOS(TM) started out with intuition based Menus, Gadgets, Requesters and Events.
The Amiga has introduced many alternatives like GadTools, BOOPSI, ASL, BGui, ReqTools, ClassAct and MUI. AROS has chosen a MUI rewrite (Zune) to be the default GUI tool set, for example Zune (MUI) Menus.
The rest of this page contains information (intuition based only) and is of backwards compatibility only.
Defining Menus
editIf you want to define your own menus, then I think intuition.library also covers you there, although menus are best left till later as IMHO they are overly complex & error prone.
For each main menu heading (i.e. top option) in the menu bar, you declare one Menu structure for each. For each item or sub-item within a menu, you declare one a MenuItem structure for each. You should use more MenuItem than Menu. Text-based menus require an additional IntuiText structure for each menu and (sub)item. (they appear the most). Image menus require the image struct.
To use Menus you need to use the Menu and MenuItem structures, and then attached them to a Window. Please note than the IntuiTexts and Image structure should be defined before the MenuItem structures that are calling them.
struct Menu
{
struct Menu *NextMenu; /* same level */
WORD LeftEdge, TopEdge; /* position of the select box */
WORD Width, Height; /* dimensions of the select box */
UWORD Flags; /* flag definitions*/
BYTE *MenuName; /* text for this Menu Header */
struct MenuItem *FirstItem; /* pointer to first in chain */
};
struct MenuItem
{
struct MenuItem *NextItem; /* pointer to next in chained list */
WORD LeftEdge, TopEdge; /* position of the select box */
WORD Width, Height; /* dimensions of the select box */
UWORD Flags; /* see the defines below */
LONG MutualExclude; /* set bits mean this item excludes that */
IPTR ItemFill; /* points to Image, IntuiText, or NULL */
IPTR SelectFill; /* points to Image, IntuiText, or NULL */
BYTE Command; /* only if appliprog sets the COMMSEQ flag */
struct MenuItem *SubItem; /* if non-zero, points to MenuItem for submenu */
UWORD NextSelect; /* Menu no of next selected item when drag-selecting items */
};
struct Image
{
WORD LeftEdge; /* starting offset relative to some origin */
WORD TopEdge; /* starting offsets relative to some origin */
WORD Width; /* pixel size (though data is word-aligned) */
WORD Height;
WORD Depth; /* >= 0, for images you create */
UWORD *ImageData; /* pointer to the actual word-aligned bits */
UBYTE PlanePick, PlaneOnOff;
struct Image *NextImage;
};
Adding and Removing Menus from a Window
editTo add or remove a menu from a window, you need to use the following commands:
BOOL SetMenuStrip( struct Window *window, struct Menu *menu )
void ClearMenuStrip( struct Window *window )
Use the SetMenuStrip command after the Window has been defined and opened and provide the address of the Window and the address of the last Menu structure in the linked list. Before closing a window, you must use ClearMenuStrip command first to remove the menu from the screen before closing a Window. Attaching menus to windows rather than screens can allow your program to have flexibility so if you had multiple windows open you can customise the menu to suit the appropriate window, for example, in a paint package or video program you can have smaller windows with their own menus.
Enabling and Disabling Menu Items
editIt is possible to enable or disable menu items, when you don`t wish a user to have access to a menu function. This can be done with the OnMenu and OffMenu functions:
void OffMenu( struct Window *window, unsigned long menuNumber)
void OnMenu( struct Window *window, unsigned long menuNumber )
Just provide the menu number of the item to enable or disable. If you change the CHECKED or ITEMENABLED values of menu items then you can refresh the menu using ResetMenuStrip command which is similar and faster than using SetMenuStrip command.
Menu Example
editRequesters
editAROS supports several types of requesters: original system (intuition) and ASL, ReqTools and MUI (recommended). The intuition AutoRequest() and Request() functions are now deprecated.
Doesn't the file requester returns a full path? Requires extra steps.
EasyRequest
editEasyRequest() provides a simple way to make a requester that allows the user to select one of a limited number of choices
LONG EasyRequest( struct Window *window, struct EasyStruct *easyStruct, ULONG *idcmpPtr, APTR argl, ... );
LONG EasyRequestArgst struct Window *window, struct EasyStruct *easyStruct, ULONG *idcmpPtr, APTR ergs );
struct EasyStruct { ULONG es_StructSize; ULONG es_Flags; UBYTE *es_Title; UBYTE *es_TextFormat; UBYTE *es_GadgetFormat; };
Requester Example
editASL
editTake a look here as well
int amiga_filereq(char *buffer, int len, ...)
{
va_list args;
LONG result;
if (FileReq == 0)
{
if ((FileReq = AllocAslRequestTags(ASL_FileRequest,
ASLFR_SleepWindow,1,
ASLFR_RejectIcons,1,TAG_DONE)) == 0)
{
return 0;
}
}
va_start(args,len);
result = AslRequest(FileReq,(struct TagItem *)args);
va_end(args);
if (result)
{
strncpy(buffer,FileReq->fr_Drawer,len);
AddPart(buffer,FileReq->fr_File,len);
return 1;
}
return 0;
}
MUI
edit/* Chaos: The Chess HAppening Organisation System V5.3
Copyright (C) 1993 Jochen Wiedmann
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$RCSfile: ProjectAmi.c,v $
$Revision: 3.4 $
$Date: 1994/11/19 19:32:01 $
This file contains the system dependent functions that support the
Project menu.
Computer: Amiga 1200 Compiler: Dice 2.07.54 (3.0)
Author: Jochen Wiedmann
Am Eisteich 9
72555 Metzingen
Tel. 07123 / 14881
Internet: jochen.wiedmann@zdv.uni-tuebingen.de
*/
#ifndef CHAOS_H
#include "chaos.h"
#endif
#ifdef AMIGA
#include <libraries/asl.h>
#include <libraries/gadtools.h>
#include <libraries/dos.h>
#include <proto/asl.h>
#include <proto/icon.h>
#endif /* AMIGA */
/*
FileRequest() creates a file requester which reads a file name.
Inputs: defaultfile a pointer to a string containing the default name
title a pointer to a string containing the requester's
title. This may be NULL, in which case
MSG_CDAT_SELECTION is assumed.
ending a pointer to a string containing the default ending.
This may be NULL, in which case "#?.cdat" is assumed.
Note, that this MUST be something like "#?.xxx" on
the Amiga!
savemode TRUE, if non-existing files may be selected.
Result: Full path name of the file, that was selected or NULL, if the
user cancelled.
*/
char *FileRequest(char *defaultfile, char *title, char *ending, int savemode)
#ifdef AMIGA
{ struct FileRequester *requester;
char pattern[20];
char *result = NULL;
char *filename, *pathname, *endptr;
BPTR dir;
static char FileRequestName[TRNFILENAME_LEN+1];
static char PathName[TRNFILENAME_LEN+1];
struct Window *window;
/*
Bring up default settings, if needed.
*/
if (title == NULL)
{ title = (char *) MSG_CDAT_SELECTION;
}
if (ending == NULL)
{ ending = "#?.cdat";
}
/*
Get Intuition window pointer from MUI window, allocate Filerequester
and parse the ending for wildcards.
*/
get(MainWnd, MUIA_Window_Window, &window);
if ((requester = (struct FileRequester *)
MUI_AllocAslRequest(ASL_FileRequest, NULL)) == NULL)
{ MemError();
return(NULL);
}
ParsePatternNoCase((UBYTE *) ending, (UBYTE *) pattern, sizeof(pattern));
/*
Get default file- and drawername.
*/
if (defaultfile && *defaultfile != '\0')
{ strcpy(FileRequestName, defaultfile);
}
else
{ if (TrnFileName != '\0')
{ strcpy(FileRequestName, TrnFileName);
}
else
{ sprintf(FileRequestName, savemode ? "chaos.%d.cdat" : "", NumRounds);
}
}
filename = (char *) FilePart((STRPTR) FileRequestName);
strcpy(PathName, FileRequestName);
*(pathname = (char *) PathPart((STRPTR) PathName)) = '\0';
/*
Make the drawername absolute.
*/
dir = Lock((STRPTR) PathName, SHARED_LOCK);
NameFromLock(dir, (STRPTR) PathName, sizeof(PathName));
UnLock(dir);
/*
Ensure, that the default filename has the right ending.
*/
if (ending != NULL && (endptr = strrchr(filename, '.')) != NULL)
{ strcpy(endptr, ending+2);
}
/*
Bring up the requester
*/
#ifdef V39_INCLUDES
if (MUI_AslRequestTags(requester,
ASLFR_Window, window,
ASLFR_PrivateIDCMP, TRUE,
ASLFR_SleepWindow, TRUE,
ASLFR_TitleText, title,
ASLFR_InitialFile, filename,
ASLFR_InitialDrawer, PathName,
ASLFR_InitialPattern, ending,
ASLFR_DoSaveMode, savemode,
ASLFR_RejectIcons, TRUE,
ASLFR_AcceptPattern, pattern,
TAG_DONE) != FALSE &&
requester->fr_File != NULL && requester->fr_File != '\0')
{ strcpy(FileRequestName, (char *) requester->fr_Drawer);
AddPart((STRPTR) FileRequestName, requester->fr_File,
sizeof(FileRequestName));
result = FileRequestName;
}
#else
if (MUI_AslRequestTags(requester,
ASL_Window, window,
ASL_Hail, title
ASL_File, filename,
ASL_Dir, PathName,
TAG_DONE) == FALSE &&
requester->rf_File != NULL && requester->rf_File != '\0')
{ strcpy(FileRequestName, (char *) requester->rf_Dir);
AddPart((STRPTR) FileRequestName, (STRPTR) requester->rf_File,
sizeof(FileRequestName));
result = FileRequestName;
}
#endif
MUI_FreeAslRequest((APTR) requester);
return (result);
}
#endif /* AMIGA */
/*
CreateIcon() puts an icon to a recently saved file.
Inputs: name of the file just created; must not be NULL
*/
void CreateIcon(char *name)
#ifdef AMIGA
{ extern int MakeIcons;
/*
Does the user want to have an icon?
*/
if (MakeIcons)
{ /*
Yes, get a diskobject
*/
struct DiskObject *dobj;
char *olddeftool;
int len = strlen(IconName);
/*
Icon.library doesn't like a trailing ".info" when calling
GetDiskObject().
*/
if (len >= 5 &&
Stricmp((STRPTR) IconName+len-5, (STRPTR) ".info") == 0)
{ IconName[len-5] = '\0';
}
if ((dobj = GetDiskObject((STRPTR) IconName)) != NULL ||
(dobj = GetDiskObject((STRPTR) "s:Chaos_Project")) != NULL ||
(dobj = GetDefDiskObject(WBPROJECT)) != NULL)
{ /*
Put the right settings into the diskobject and save it.
*/
dobj->do_Type = WBPROJECT;
olddeftool = dobj->do_DefaultTool;
dobj->do_DefaultTool = ProgName;
dobj->do_CurrentX = dobj->do_CurrentY = NO_ICON_POSITION;
if (dobj->do_StackSize < 20000)
{ dobj->do_StackSize = 20000;
}
PutDiskObject((STRPTR) name, dobj);
dobj->do_DefaultTool = olddeftool;
FreeDiskObject(dobj);
}
}
}
#else /* !AMIGA */
{ /*
There is nothing to be done on other systems.
*/
}
#endif /* !AMIGA */
/*
AskSave brings up a requester asking the user, if he wants to save
first.
*/
int AskSave(void)
#ifdef AMIGA
{
switch (MUI_RequestA(App, MainWnd, 0,
(char *) MSG_ATTENTION,
(char *) MSG_YES_NO_CANCEL,
(char *) MSG_CHANGES_MADE, NULL))
{ case 2:
return(TRUE);
case 1:
return(SaveTournament(NULL));
}
return(FALSE);
}
#endif /* AMIGA */
/*
The TerminateTrnWnd() function closes the tournament input window.
*/
#ifdef AMIGA
static APTR TrnWnd = NULL; /* Tournament window */
static APTR TrnOkGad; /* Ok gadget (tournament window) */
static APTR TrnCancelGad; /* Cancel gadget (tournament window) */
static APTR TrnNameGad; /* Tournament name gadget */
static APTR WinnerPointsGad; /* Winner points gadget */
static APTR DrawPointsGad; /* Draw points gadget */
void TerminateTrnWnd(void)
{ if (TrnWnd)
{ set(TrnWnd, MUIA_Window_Open, FALSE);
DoMethod(App, OM_REMMEMBER, TrnWnd);
MUI_DisposeObject(TrnWnd);
TrnWnd = NULL;
}
}
#endif /* AMIGA */
/*
The InitTrnWnd() function brings up a window, that allows to input
tournament data.
Inputs: name pointer to a buffer, that can hold the tournament name
winnerpoints current number of points for winning a game
drawpoints current number of points for a draw
Results: TRUE, if successful, FALSE otherwise
*/
#ifdef AMIGA
#define ID_TrnWnd_Cancel 201
#define ID_TrnWnd_Ok 202
int InitTrnWnd(char *buffer, int winnerpoints, int drawpoints)
{ ULONG open;
int OK_SC = *MSG_OK_SC;
int Cancel_SC = *MSG_CANCEL_SC;
/*
Open the window and check for success.
*/
TrnWnd = WindowObject,
MUIA_Window_ID, MAKE_ID('T','R','N','I'),
MUIA_Window_Title, MSG_TOURNAMENT_INPUT_TITLE,
MUIA_Window_Width, MUIV_Window_Width_MinMax(40),
WindowContents, VGroup,
Child, HGroup,
Child, Label2(MSG_TOURNAMENT_NAME_OUTPUT),
Child, TrnNameGad = StringObject,
StringFrame,
MUIA_String_MaxLen, TRNNAME_LEN+1,
MUIA_String_Contents, buffer,
End,
End,
Child, VSpace(0),
Child, HGroup,
Child, VGroup,
Child, Label2(MSG_WINNERPOINTS),
Child, Label2(MSG_DRAWPOINTS),
End,
Child, VGroup,
Child, WinnerPointsGad = StringObject,
StringFrame,
MUIA_String_MaxLen, 3,
MUIA_String_Accept, "0123456789 ",
MUIA_String_Integer, winnerpoints,
End,
Child, DrawPointsGad = StringObject,
StringFrame,
MUIA_String_MaxLen, 3,
MUIA_String_Accept, "0123456789 ",
MUIA_String_Integer, drawpoints,
End,
End,
Child, HSpace(0),
End,
Child, VSpace(0),
Child, HGroup,
MUIA_Group_SameSize, TRUE,
Child, TrnOkGad = KeyButton(MSG_OK, OK_SC),
Child, HSpace(0),
Child, TrnCancelGad = KeyButton(MSG_CANCEL_INPUT, Cancel_SC),
End,
End,
End;
if (!TrnWnd)
{ return(FALSE);
}
DoMethod(App, OM_ADDMEMBER, TrnWnd);
DoMethod(TrnWnd, MUIM_Window_SetCycleChain, TrnNameGad, TrnOkGad,
TrnCancelGad, NULL);
set(TrnWnd, MUIA_Window_ActiveObject, TrnNameGad);
/*
Setting up the notification events for the tournament input window:
CloseWindow, Ok- and Cancel Gadget
*/
DoMethod(TrnWnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, App, 2,
MUIM_Application_ReturnID, ID_TrnWnd_Cancel);
DoMethod(TrnWnd, MUIM_Notify, MUIA_Window_InputEvent, "ctrl return",
App, 2, MUIM_Application_ReturnID, ID_TrnWnd_Ok);
DoMethod(TrnOkGad, MUIM_Notify, MUIA_Pressed, FALSE, App, 2,
MUIM_Application_ReturnID, ID_TrnWnd_Ok);
DoMethod(TrnCancelGad, MUIM_Notify, MUIA_Pressed, FALSE, App, 2,
MUIM_Application_ReturnID, ID_TrnWnd_Cancel);
DoMethod(TrnWnd, MUIM_Window_SetCycleChain,
TrnNameGad, WinnerPointsGad, DrawPointsGad, TrnOkGad, TrnCancelGad,
NULL);
DoMethod(TrnNameGad, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
TrnWnd, 3, MUIM_Set, MUIA_Window_ActiveObject, WinnerPointsGad);
DoMethod(WinnerPointsGad, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
TrnWnd, 3, MUIM_Set, MUIA_Window_ActiveObject, DrawPointsGad);
DoMethod(DrawPointsGad, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
TrnWnd, 3, MUIM_Set, MUIA_Window_ActiveObject, TrnNameGad);
set(TrnWnd, MUIA_Window_Open, TRUE);
get(TrnWnd, MUIA_Window_Open, &open);
if (!open)
{ MUIError((char *) ERRMSG_CANNOT_OPEN_WINDOW);
TerminateTrnWnd();
return(FALSE);
}
set(TrnWnd, MUIA_Window_ActiveObject, TrnNameGad);
set(MainWnd, MUIA_Window_Open, FALSE);
return(TRUE);
}
#endif /* AMIGA */
/*
The ProcessTrnWnd() function waits for user actions concerning
the tournament input window.
Inputs: buffer pointer to a string, that holds the users input.
(Not needed on the Amiga.)
winnerpoints pointer to an int where to store the
number of points for winning a game
game
drawpoints pointer to an int where to store the
number of points for a draw
Results: 0 Indicates, that the user has cancelled.
1 Indicates, that this has to be called again.
-1 Terminating via Ok-Gadget, okay
*/
int ProcessTrnWnd(char *buffer, int *winnerpoints, int *drawpoints)
#ifdef AMIGA
{ ULONG Signal;
char *name;
/*
Check for user actions
*/
switch (DoMethod(App, MUIM_Application_Input, &Signal))
{ case MUIV_Application_ReturnID_Quit:
if (TestSaved())
{ exit(0);
}
break;
case ID_TrnWnd_Cancel:
return(0);
case ID_TrnWnd_Ok:
/*
Get the final state of the tournament name gadget.
*/
if (buffer)
{ get(TrnNameGad, MUIA_String_Contents, &name);
strcpy (buffer, name);
get(WinnerPointsGad, MUIA_String_Integer, winnerpoints);
get(DrawPointsGad, MUIA_String_Integer, drawpoints);
}
return(-1);
}
if (Signal)
{ Wait(Signal);
}
return(1);
}
#endif
Intuition
editIt is a very easy to use and just needs a Window with which to attach, a structure, a pointer to a list of IDCMP flags and optional arguments.
struct Requester { struct Requester *OlderRequest; WORD LeftEdge, TopEdge; WORD Width, Height; WORD RelLeft, RelTop; struct Gadget *ReqGadget; struct Border *ReqBorder; struct IntuiText *ReqText; UWORD Flags; POINTREL PREDRAWN NOISYREQ USEREQIMAGE NOREQBACKFILL REQOFFWINDOW (the following are library called) REQACTIVE SYSREQUEST UBYTE Backfill; struct Layer *ReqLayer; UBYTE ReqPad1[32]; struct BitMap *ImageBMap; struct Window *RWindow; struct Image *ReqImage; UBYTE ReqPad2[32]; };
Requester Reference
editBuildSysRequest(Window)
FreeSysRequest (Window)
AutoRequest( Window, BodyText, PosText, NegText, PosFlags, NegFlags, Width, Height)
Gadgets
editEach gadget (used in a window or requester) creates a separate Gadget struct
struct Gadget { struct Gadget *NextGadget; WORD LeftEdge, TopEdge; WORD Width, Height; UWORD Flags; UWORD Activation; UWORD GadgetType; GTYP_BOOLGADGET - Boolean gadget type. GTYP_STRGADGET - String gadget type. For an integer gadget, also set the GACT_LONGINT flag. GTYP_PROPGADGET - Proportional gadget type. GTYP_CUSTOMGADGET - Normally not set by the application. Used by custom BOOPSI gadget types. GTYP_GZZGADGET - If the gadget is placed in a GimmeZeroZero window, will place the gadget in the border layer. GTYP_REQGADGET - Set this bit if this gadget is placed in a requester. APTR GadgetRender; APTR SelectRender; struct IntuiText *GadgetText; IPTR MutualExclude; /* changed from LONG used by BOOPSI gadgets to store dispatcher address */ APTR SpecialInfo; UWORD GadgetID; APTR UserData; };
Highlighting flags
GFLG_GADGHNONE - GFLG_GADGHCOMP - GFLG_GADGHBOX - GFLG_GADGHIMAGE -
In addition to the highlighting flags, these other values may be set in the Flags field of the Gadget structure.
GFLG_GADGIMAGE - GFLG_RELBOTTOM - GFLG_RELRIGHT - GFLG_RELWIDTH - GFLG_RELHEIGHT - GFLG_SELECTED - GFLG_DISABLED - GFLG_STRINGEXTEND - GFLG_TABCYCLE -
Gadget Activation Flags - may be set in the Activation field of the Gadget structure.
GACT_TOGGLESELECT GACT_IMMEDIATE GACT_RELVERIFY GACT_ENDGADGET GACT_FOLLOWMOUSE
Border Flags
GACT_RIGHTBORDER GACT_LEFTBORDER GACT_TOPBORDER GACT_BOTTOMBORDER
The following flags apply only to string gadgets:
GACT_STRINGCENTER GACT_STRINGRIGHT GACT_STRINGLEFT GACT_LONGINT GACT_ALTKEYMAP GACT_BOOLEXTEND GACT_STRINGEXTEND
If you use old-fashioned struct Gadget, you need to calculate and set BODY and POT fields of the PropInfo structure appropriately.
Read more gadtools.library.
String
editString gadgets require their own special structure called the StringInfo structure. For a string gadget, set the GadgetType field in the Gadget structure to GTYP_STRGADGET. Set the SpecialInfo field to point to an instance of a StringInfo structure, which must be initialized by the application.
struct StringInfo { UBYTE *Buffer; UBYTE *UndoBuffer; WORD BufferPos; WORD MaxChars; WORD DispPos; WORD UndoPos; WORD NumChars; WORD DispCount; WORD CLeft, CTop; struct StringExtend *Extension; LONG LongInt; struct KeyMap *AltKeyMap; };
Custom
editCustom string editing
struct SGWork { struct Gadget *Gadget; struct StringInfo *StringInfo; UBYTE *WorkBuffer; UBYTE *PrevBuffer; ULONG Modes; struct InputEvent *IEvent; UWORD Code; WORD BufferPos; WORD NumChars; ULONG Actions; LONG LongInt; struct GadgetInfo *GadgetInfo; UWORD EditOp; };
EditOp Action Taken by Global Hook ------ --------------------------- EO_NOOP Did nothing. EO_DELBACKWARD Deleted some chars (possibly 0). EO_DELFORWARD Deleted some characters under and in front of the cursor. EO_MOVECURSOR Moved the cursor. EO_ENTER Enter or Return key, terminate. EO_RESET Current Intuition-style undo. EO_REPLACECHAR Replaced one character and (maybe) advanced cursor. EO_INSERTCHAR Inserted one character into string or added one at end. EO_BADFORMAT Didn't like the text data, e.g., alpha characters in a GACT_LONGINT type. EO_BIGCHANGE Complete or major change to the text, e.g. new string. EO_UNDO Some other style of undo. EO_CLEAR Clear the string. EO_SPECIAL An operation that doesn't fit into the categories here. These are the actions to be taken by Intuition after the hook returns. Actions Flag Purpose ------------ ------- SGA_USE If set, use contents of SGWork. SGA_END Terminate gadget, Code field is sent to application in IDCMP_GADGETUP event code field. SGA_BEEP Beep (i.e., flash) the screen. SGA_REUSE Reuse the input event. Only valid with SGA_END. SGA_REDISPLAY Gadget visuals have changed, update on screen. SGA_NEXTACTIVE Make next possible gadget active SGA_PREVACTIVE Make previous possible gadget active
Proportional
editstruct PropInfo { UWORD Flags; PROPBORDERLESS - AUTOKNOB - FREEHORIZ and FREEVERT PROPNEWLOOK KNOBHIT UWORD HorizPot; UWORD VertPot; UWORD HorizBody; UWORD VertBody; UWORD Cwidth; UWORD Cheight; UWORD HPotRes, VPotRes; UWORD LeftBorder; UWORD TopBorder; };
In the Gadget structure, set the GadgetType field to GTYP_PROPGADGET and place the address of the PropInfo structure in the SpecialInfo field.
To change the flags and the pot and body variables after the gadget is displayed, the program can call NewModifyProp().
void NewModifyProp( struct Gadget *gadget, struct Window *window, struct Requester *requester,
unsigned long flags, unsigned long horizPot, unsigned long vertPot, unsigned long horizBody, unsigned long vertBody, long numGad );
BOOPSI
editBOOPSI is great for GUI stuff and runtime class loading/method dispatching. It's written in C and the designers made a *very* good job when you realise the limitations of the language for this kind of system. But consider if we had decent C++ support since the start of Amigas, sure BOOPSI would have been written in it.
The thing is, BOOPSI lends itself well to event-driven code (such as a GUI) where the users interaction is rate determining. However, the method dispatch mechanisms and data access methods are vastly slower (by virtue of how they work) than a C++ virtual function call, let alone a non-virtual or static member func.
You wouldn't want to rely on BOOPSI for all your OOP needs. Imagine the speed penalty of the method calls used in a time critical loop. Ouch :-)
If you use BOOPSI scrollers, you can set Total, Visible and Top attributes. And you can let it send you messages when the user moves the bar. Intuition comes with its own BOOPSI scroller class - the propgclass. It is better integrated inside the window border.
Classes
editMisc
editThere also seems to be a problem with sending the SA_PubSig signal to the SA_PubTask. The SA_PubTask gets the signal, if UnlockPubScreen is called and this was the last lock. This is independent of the number of windows on the screen.
So this can happen:
- Open Pubscreen - Lock Pubscreen - Open window on Pubscreen - UnlockPubscreen - SA_PubSig is sent!! - .... - Close Window
As you can see in, it seems to be not necessary to lock a pubscreen to open a window on it, at least, if you own it.
LockPubScreen() Find Workbench or any other public screen; prevent it from closing while a window is opened or its attributes copied. UnlockPubScreen() Release the lock allowing the screen to later be closed. struct Screen *LockPubScreen( UBYTE * ) VOID UnlockPubScreen( UBYTE * , struct Screen *) SetDefaultPubScreen() Establishes a given public screen as the default. GetDefaultPubScreen() Copies the name of the default screen to a user supplied buffer for use by the screen manager utility (the name is not needed by normal applications, use LockPubScreen(NULL) instead). PubScreenStatus() Converts a screen to private or public status. SetPubScreenModes() Controls the public screen global mode bits. WBenchToBack() Move the Workbench screen behind all other screens. WBenchToFront() Move the Workbench screen in front of all other screens. OpenWorkBench() Open the Workbench screen. If the screen is already open, this call has no effect. This call will re-awaken the Workbench application if it was active when CloseWorkBench() was called. CloseWorkBench() Attempt to reclaim memory used for the Workbench screen. If successful, this call closes the screen and puts the Workbench application to sleep. This call fails if any application has windows open or locks on the Workbench screen. LockPubScreenList() Lock the public screen list maintained by intuition so that it may be quickly copied. UnlockPubScreenList() Release the lock on the public screen list. NextPubScreen() Find the next screen in the public screen list.
Starting from
editshell-only applications
editOn AROS, you have your normal entry point as main(int argc, char **argv).
If argc == 0, then argv actually points to a struct WBStartup.
If argc > 0, then the program was started from CLI.
There are two ways to start a program - CLI method & WB method - from shell or from workbench. The shell method is easier. For apps you send two arguments, the program name & filename to open. So argc = 2, argv[ 0 ] = program name & argv[ 1 ] = full path.
But when you start from workbench the shell argc = 0. But workbench (Wanderer or Magellan) sends a WB message. In the message argc = 2. Again argv[ 0 ] = program name & argv[ 1 ] = full path. But the way workbench deals with the path is different. Just like using a file requester there is a PathPart & FilePart. Yo can grab the FilePart without the PathPart. So when the picture file & program are in the same directory no problem. It doesn't need a full path.
So to resolve the issue, need to revise the code in main for the WB message to get the PathPart & then use AddPart to combine PathPart + FilePart to get a full path not just a filename.
However, programs run from CLI *MUST* call Permit() for each Forbid() since the final 'rts' drops back to shell, and does not terminate the process.
Semaphores should be used when possible. Forbid()/Permit() should only be used when there is no alternative. Semaphores can be very useful for things like access to memory pools, lists that could be modified by other threads, etc. etc.
Some programs use the technique of starting a new process and clearing cli_Module in order to detach from the shell they are run from. At least for FileX (see contrib/aminet/disk/moni/filex/main.c), this doesn't seem to work anymore. FileX only works if the SYNC argument is used to disable this behaviour.
Does the standard startup code or shell support detaching like this? Perhaps the seglist is being unloaded regardless of the value placed in cli_Module.
Would it be feasible to keep libraries open at exit if cli_Module has been cleared by the program? And could they then be closed when the detached process exits? Not really because it wouldn't fix more common "split segment list" way of detaching.
How does that differ from what FileX does? :-| I presume the similarity of the SegmentSplit() function name is misleading. Yeah, FileX does not do any segment split tricks (perhaps it originally did?), it only clears cli_Module. "Standard" segment list split is to have 2 (or more) segments, code in first segment unlinks following segment(s) from single linked segment list -> only first segment is freed by dos.
It is aroscbase that is set to NULL (guess it is also freed) when original process exists. Which is of course still in use by detached process.. Ouch. I guess FileX doesn't use detach.o? It should to avoid such problems.
It implies to include aros/detach.h and to not link against the standard startup module but against detach.o as Fabio just said. It is done in the mmakefile.src by detach=yes assertion. One can even choose where the detachment has to occur by using the Detach() function.
AmigaOS libnix opens own console only for libc I/O. It does not reassign default dos.library streams to it. In other words: when the program is started from CLI, libc I/O (printf(), write(), stdin, stdout, etc.) is directed into dos.library default streams. When program is started from Workbench, libc opens own window for own I/O, but does not touch dos.library streams. As a consequence, when started from WB, printf() will send a string to __stdiowin, but Printf() will send it to NIL:.
#include <proto/exec.h> #include <proto/dos.h> int __stack = 0x500000; /* 5 MiB */ int real_main (int argc, char *argv[]); int main (int argc, char *argv[]) { struct Task *mytask = FindTask(NULL); ULONG stacksize = mytask->tc_SPUpper - mytask->tc_SPLower; int rc = 1; int i; Printf("stack desired: %lu current %lun", __stack, stacksize); Printf("SPUpper %lu SPLower %lu SPReg %lun", mytask->tc_SPUpper, mytask->tc_SPLower, mytask->tc_SPReg); Printf("argc %d argv %pn", argc, argv); for (i = 0; i < argc; i++) Printf("argv[%d] = %sn", i, argv[i]); if (stacksize >= __stack) { Printf("no stack adjustment is necessaryn"); rc = real_main(argc, argv); } else { struct StackSwapArgs swapargs; struct StackSwapStruct stack; swapargs.Args[0] = argc; swapargs.Args[1] = (IPTR) argv; Printf("stack was too small, stackswappingn"); if (stack.stk_Lower = AllocVec(__stack, MEMF_PUBLIC)) { stack.stk_Upper = stack.stk_Lower + __stack; stack.stk_Pointer = stack.stk_Upper; rc = NewStackSwap(&stack, real_main, &swapargs); FreeVec(stack.stk_Lower); } else { Printf("Couldn't allocate %d bytes for stack.n", __stack); } } return rc; } int real_main (int argc, char *argv[]) { int i; struct Task *mytask = FindTask(NULL); ULONG stacksize = mytask->tc_SPUpper - mytask->tc_SPLower; Printf("New stack size: %lun", stacksize); Printf("SPUpper %lu SPLower %lu SPReg %lun", mytask->tc_SPUpper, mytask->tc_SPLower, mytask->tc_SPReg); Printf("argc %d argv %pn", argc, argv); for (i = 0; i < argc; i++) Printf("argv[%d] = %sn", i, argv[i]); return RETURN_OK; }
Wanderer
editstart:
wbmsg = NULL;
task = FindTask(NULL)
if (task->pr_CLI == 0 )
{
WaitPort(&task->pr_MsgPort);
wbmsg = GetMsg(&task->pr_MsgPort);
}
; your code here
if ( wbmsg != NULL )
{
Forbid();
ReplyMsg(wbmsg);
}
return return_code;
That final Forbid() guarantees the Workbench don't have a change to UnLoadSeg() the seglist of the program while the program is still executes.
If there is no Forbid(), the ReplyMsg() results in task scheduling, and Workbench get change to run. Workbench UnLoadSeg() the seglist, and the last few instructions are executed on unallocated memory. This will lead into crashes.
There is no need for final Permit(), since the process will RemTask(NULL) itself eventually (default Task EndPC), and this completely removes the process anyway.
{
struct WBStartup *wbmsg;
BPTR win;
if (argc != 0)
{
Printf ("This program cannot be run in DOS mode :-)\n");
return (RETURN_ERROR);
}
wbmsg = (struct WBStartup *)argv;
if (win = Open ("con:0/0/640/400/WB Icon/CLOSE/WAIT",MODE_NEWFILE))
{
char buffer[256];
long i;
NameFromLock (wbmsg->sm_ArgList->wa_Lock,buffer,256);
AddPart (buffer,wbmsg->sm_ArgList->wa_Name,256);
FPrintf (win,"Program name: <%s>\n",buffer);
for (i = 1; i < wbmsg->sm_NumArgs; i++)
{
NameFromLock (wbmsg->sm_ArgList[i].wa_Lock,buffer,256);
AddPart (buffer,wbmsg->sm_ArgList[i].wa_Name,256);
FPrintf (win,"Argument #%ld: <%s>\n",i,buffer);
}
Close (win);
}
return (RETURN_OK);
}
Using Screens
edituse intuition.library/StartScreenNotifyTagList() in order to allow screen preferences changes without having to close/reopen it
There are some additional functions you can use to manipulate screens.
void DisplayBeep(struct Screen *) This function will flash the specified screen, for example, to indicate an error. e.g. DisplayBeep(myScreen); void MoveScreen(struct Screen *, WORD dx, WORD dy) This function will move the current screen to the specified pixel co-ordinates. This is similar to dragging the screen bar to a new location. e.g. MoveScreen(myScreen, 0, 100); /* Move screen down to y co-ord 100 */ void ScreenToBack(struct Screen *) void ScreenToFront(struct Screen *) If you have multiple screens open, then you can switch between screens using these functions. ScreenToFront will make a screen the visible screen. e.g. ScreenToFront(myScreen); void MakeScreen(struct Screen *) e.g. MakeScreen(myScreen); void ShowTitle(struct Screen *, BOOL) Specifies whether to show the screen's title bar or not. e.g. ShowTitle(myScreen, FALSE);
See Intuition Reference documentation for further commands.
GetScreenDrawInfo() Get the DrawInfo information for an open screen. FreeScreenDrawInfo() Free the DrawInfo information for a screen. MakeScreen() Low level screen handling--rebuild Copper list. RethinkDisplay() Low level screen handling--incorporate Copper list changes. RemakeDisplay() MakeScreen() for all screens, then RethinkDisplay(). ScreenNotify() Private function
Backfill Hook
editsee this thread
AROS_UFH3(void ,sbackfillfunc, AROS_UFHA(struct Hook *,hook,a0), AROS_UFHA(struct RastPort *,frp,a2), AROS_UFHA(struct BackfillMsg *,bfm,a1)) { AROS_USERFUNC_INIT struct RastPort rp; CopyMem(frp, &rp, sizeof(struct RastPort)); rp.Layer = NULL; FillPixelArray( &rp, bfm->rect.MinX, bfm->rect.MinY, bfm->rect.MaxX - bfm->rect.MinX + 1, bfm->rect.MaxY - bfm->rect.MinY + 1, 0x00000000); AROS_USERFUNC_EXIT } struct Hook sbackfillhook;
And here the open screen call:
sbackfillhook.h_Entry = (HOOKFUNC) sbackfillfunc; info->screen = OpenScreenTags( NULL, SA_Width, target_width, SA_Height, target_height, SA_Depth, target_depth, SA_Quiet, TRUE, SA_ShowTitle, FALSE, SA_Type, CUSTOMSCREEN, SA_DisplayID, dispid, SA_BackFill, (ULONG) &sbackfillhook, TAG_DONE);
SA_BackFill, (ULONG) &sbackfillhook,
Please don't use ULONG's to store/cast pointers in your code. use APTR/IPTR where appropriate.
If the code you posted is the code in its entirety, then the reason why it doesn't work maybe because of the way you have filled sbackfillhook. in Demos/scrbackfill the hook is filled like:
static void InitBackfillHook(void) { backfillhook.h_Entry = HookEntry; backfillhook.h_SubEntry = (HOOKFUNC)MyBackfillFunc; }
HookEntry is defined in clib/alib_protos.h and MyBackfillFunc is:
static void MyBackfillFunc(struct Hook *hook,struct RastPort *rp, struct LayerHookMsg *msg);
Or just look in Demos/scrbackfill.c
struct DrawInfo { UWORD dri_Version; /* will be DRI_VERSION */ UWORD dri_NumPens; /* guaranteed to be >= 9 */ UWORD *dri_Pens; /* pointer to pen array */ struct TextFont *dri_Font; /* screen default font */ UWORD dri_Depth; /* (initial) depth of screen bitmap */ struct { /* from DisplayInfo database for initial display mode */ UWORD X; UWORD Y; } dri_Resolution; ULONG dri_Flags; /* defined below */ /* New for V39: dri_CheckMark, dri_AmigaKey. */ struct Image *dri_CheckMark; /* pointer to scaled checkmark image * Will be NULL if DRI_VERSION < 2 */ struct Image *dri_AmigaKey; /* pointer to scaled Amiga-key image * Will be NULL if DRI_VERSION < 2 */ ULONG dri_Reserved[5]; /* avoid recompilation ;^) */ }; #define DRIF_NEWLOOK 0x00000001L /* specified SA_Pens, full treatment */ /* rendering pen number indexes into DrawInfo.dri_Pens[] */ #define DETAILPEN (0x0000) /* compatible Intuition rendering pens */ #define BLOCKPEN (0x0001) /* compatible Intuition rendering pens */ #define TEXTPEN (0x0002) /* text on background */ #define SHINEPEN (0x0003) /* bright edge on 3D objects */ #define SHADOWPEN (0x0004) /* dark edge on 3D objects */ #define FILLPEN (0x0005) /* active-window/selected-gadget fill */ #define FILLTEXTPEN (0x0006) /* text over FILLPEN */ #define BACKGROUNDPEN (0x0007) /* may not always be color 0 */ #define HIGHLIGHTTEXTPEN (0x0008) /* special color text, on background */ /* New for V39, only present if DRI_VERSION >= 2: */ #define BARDETAILPEN (0x0009) /* text/detail in screen-bar/menus */ #define BARBLOCKPEN (0x000A) /* screen-bar/menus fill */ #define BARTRIMPEN (0x000B) /* trim under screen-bar */ #define NUMDRIPENS (0x000C) /* New for V39: It is sometimes useful to specify that a pen value * is to be the complement of color zero to three. The "magic" numbers * serve that purpose: */ #define PEN_C3 0xFEFC /* Complement of color 3 */ #define PEN_C2 0xFEFD /* Complement of color 2 */ #define PEN_C1 0xFEFE /* Complement of color 1 */ #define PEN_C0 0xFEFF /* Complement of color 0 */
Windows Misc
editTo hide a window (and make in reappear again!), use ChangeWindowShape(). Still have no idea, how to make a window opened with WA_Visible=FALSE visible again ;)
If we get a MENUVERIFY message, we look at the according open window. If it has WFLG_RMBTRAP cleared at the time of the mouse click, we display an according AROS intuition menu.
the busy pointer, I have tried adding ..
SetWindowPointer( win, WA_BusyPointer, TRUE, WA_PointerDelay, TRUE, TAG_DONE ); SetWindowPointer( win, TAG_DONE );
as I will only get the default pointer and not the current one that might be set by an application using SetWindowPointer() or SetPointer() functions.
Is there a way to get the current pointer bitmap? You could always patch the necessary function at runtime so that your own routine would be called with the necessary information, and then do what you need (as well as call the original function to actually set the visible pointer).
- intercept the call,
- copy the bitmap so that I can use it for my own purpose
- forward the call to the original function
Digging into it is seems that it's not SetWindowPointerA that I shall patch but rather ChangeExtSpriteA. SetWindowPointer is used when a new pointer is set for a window, this pointer will therefore be used when the window is active. But ChangeExtSprite is called each time the pointer changes, i.e. also when active window is changing.
Is there a way to get notification of the current pointer change? An application can change the pointer image at any time by calling SetWindowPointer(), for example to show the busy pointer. These changes are not reflected by a file change and will not cause a DOS notification.
UWORD AddGadget(struct Window *window, struct Gadget *gadget, ULONG position) (A0, A1, D0) BOOL ClearDMRequest(struct Window *window) (A0) void ClearMenuStrip(struct Window *window) (A0) void ClearPointer(struct Window *window) (A0) BOOL CloseScreen(struct Screen *screen) (A0) void CloseWindow(struct Window *window) (A0) LONG CloseWorkBench() () void CurrentTime(ULONG *seconds, ULONG *micros) (A0, A1) BOOL DisplayAlert(ULONG alertnumber, UBYTE *string, UWORD height) (D0, A0, D1) void DisplayBeep(struct Screen *screen) (A0) BOOL DoubleClick(ULONG sSeconds, ULONG sMicros, ULONG cSeconds, ULONG cMicros) (D0, D1, D2, D3) void DrawBorder(struct RastPort *rp, struct Border *border, LONG leftOffset, LONG topOffset) (A0, A1, D0, D1) void DrawImage(struct RastPort *rp, struct Image *image, LONG leftOffset, LONG topOffset) (A0, A1, D0, D1) void EndRequest(struct Requester *requester, struct Window *window) (A0, A1) struct Preferences *GetDefPrefs(struct Preferences *prefbuffer, WORD size) (A0, D0) struct Preferences *GetPrefs(struct Preferences *prefbuffer, WORD size) (A0, D0) void InitRequester(struct Requester *requester) (A0) struct MenuItem *ItemAddress(struct Menu *menustrip, UWORD menunumber) (A0, D0) BOOL ModifyIDCMP(struct Window *window, ULONG flags) (A0, D0) void ModifyProp(struct Gadget *gadget, struct Window *window, struct Requester *requester, ULONG flags, ULONG horizPot, ULONG vertPot, ULONG horizBody, ULONG vertBody) (A0, A1, A2, D0, D1, D2, D3, D4) void MoveScreen(struct Screen *screen, LONG dx, LONG dy) (A0, D0, D1) void MoveWindow(struct Window *window, LONG dx, LONG dy) (A0, D0, D1) void OffGadget(struct Gadget *gadget, struct Window *window, struct Requester *requester) (A0, A1, A2) void OffMenu(struct Window *window, UWORD menunumber) (A0, D0) void OnGadget(struct Gadget *gadget, struct Window *window, struct Requester *requester) (A0, A1, A2) void OnMenu(struct Window *window, UWORD menunumber) (A0, D0) struct Screen *OpenScreen(struct NewScreen *newScreen) (A0) struct Window *OpenWindow(struct NewWindow *newWindow) (A0) IPTR OpenWorkBench() () void PrintIText(struct RastPort *rp, struct IntuiText *iText, LONG leftOffset, LONG topOffset) (A0, A1, D0, D1) void RefreshGadgets(struct Gadget *gadgets, struct Window *window, struct Requester *requester) (A0, A1, A2) UWORD RemoveGadget(struct Window *window, struct Gadget *gadget) (A0, A1) void ReportMouse(LONG flag, struct Window *window) (D0, A0) BOOL Request(struct Requester *requester, struct Window *window) (A0, A1) void ScreenToBack(struct Screen *screen) (A0) void ScreenToFront(struct Screen *screen) (A0) BOOL SetDMRequest(struct Window *window, struct Requester *dmrequest) (A0, A1) BOOL SetMenuStrip(struct Window *window, struct Menu *menu) (A0, A1) void SetPointer(struct Window *window, UWORD *pointer, LONG height, LONG width, LONG xOffset, LONG yOffset) (A0, A1, D0, D1, D2, D3) void SetWindowTitles(struct Window *window, CONST_STRPTR windowTitle, CONST_STRPTR screenTitle) (A0, A1, A2) void ShowTitle(struct Screen *screen, BOOL ShowIt) (A0, D0) void SizeWindow(struct Window *window, LONG dx, LONG dy) (A0, D0, D1) struct View *ViewAddress() () struct ViewPort *ViewPortAddress(struct Window *Window) (A0) void WindowToBack(struct Window *window) (A0) void WindowToFront(struct Window *window) (A0) BOOL WindowLimits(struct Window *window, WORD MinWidth, WORD MinHeight, UWORD MaxWidth, UWORD MaxHeight) (A0, D0, D1, D2, D3) struct Preferences *SetPrefs(struct Preferences *prefbuffer, LONG size, BOOL inform) (A0, D0, D1) LONG IntuiTextLength(struct IntuiText *iText) (A0) BOOL WBenchToBack() () BOOL WBenchToFront() () BOOL AutoRequest(struct Window *window, struct IntuiText *body, struct IntuiText *posText, struct IntuiText *negText, ULONG pFlag, ULONG nFlag, ULONG width, ULONG height) (A0, A1, A2, A3, D0, D1, D2, D3) void BeginRefresh(struct Window *window) (A0) struct Window *BuildSysRequest(struct Window *window, struct IntuiText *bodytext, struct IntuiText *postext, struct IntuiText *negtext, ULONG IDCMPFlags, WORD width, WORD height) (A0, A1, A2, A3, D0, D2, D3) void EndRefresh(struct Window *window, BOOL complete) (A0, D0) void FreeSysRequest(struct Window *window) (A0) LONG MakeScreen(struct Screen *screen) (A0) LONG RemakeDisplay() () LONG RethinkDisplay() () APTR AllocRemember(struct Remember **rememberKey, ULONG size, ULONG flags) (A0, D0, D1) void AlohaWorkbench(struct MsgPort *wbmsgport) (A0) void FreeRemember(struct Remember **rememberKey, LONG reallyForget) (A0, D0) ULONG LockIBase(ULONG What) (D0) void UnlockIBase(ULONG ibLock) (A0) LONG GetScreenData(APTR buffer, ULONG size, ULONG type, struct Screen *screen) (A0, D0, D1, A1) void RefreshGList(struct Gadget *gadgets, struct Window *window, struct Requester *requester, LONG numGad) (A0, A1, A2, D0) UWORD AddGList(struct Window *window, struct Gadget *gadget, ULONG position, LONG numGad, struct Requester *requester) (A0, A1, D0, D1, A2) UWORD RemoveGList(struct Window *remPtr, struct Gadget *gadget, LONG numGad) (A0, A1, D0) void ActivateWindow(struct Window *window) (A0) void RefreshWindowFrame(struct Window *window) (A0) BOOL ActivateGadget(struct Gadget *gadget, struct Window *window, struct Requester *requester) (A0, A1, A2) void NewModifyProp(struct Gadget *gadget, struct Window *window, struct Requester *requester, ULONG flags, ULONG horizPot, ULONG vertPot, ULONG horizBody, ULONG vertBody, LONG numGad) (A0, A1, A2, D0, D1, D2, D3, D4, D5) LONG QueryOverscan(ULONG displayid, struct Rectangle *rect, WORD oscantype) (A0, A1, D0) void MoveWindowInFrontOf(struct Window *window, struct Window *behindwindow) (A0, A1) void ChangeWindowBox(struct Window *window, LONG left, LONG top, LONG width, LONG height) (A0, D0, D1, D2, D3) struct Hook *SetEditHook(struct Hook *hook) (A0) LONG SetMouseQueue(struct Window *window, UWORD queuelength) (A0, D0) void ZipWindow(struct Window *window) (A0) struct Screen *LockPubScreen(CONST_STRPTR name) (A0) void UnlockPubScreen(UBYTE *name, struct Screen *screen) (A0, A1) struct List *LockPubScreenList() () void UnlockPubScreenList() () UBYTE *NextPubScreen(struct Screen *screen, UBYTE *namebuff) (A0, A1) void SetDefaultPubScreen(UBYTE *name) (A0) UWORD SetPubScreenModes(UWORD modes) (D0) UWORD PubScreenStatus(struct Screen *Scr, UWORD StatusFlags) (A0, D0) struct RastPort *ObtainGIRPort(struct GadgetInfo *gInfo) (A0) void ReleaseGIRPort(struct RastPort *rp) (A0) void GadgetMouse(struct Gadget *gadget, struct GadgetInfo *ginfo, WORD *mousepoint) (A0, A1, A2) ULONG SetIPrefs(APTR data, ULONG length, ULONG type) (A0, D0, D1) struct Screen *GetDefaultPubScreen(UBYTE *nameBuffer) (A0) LONG EasyRequestArgs(struct Window *window, struct EasyStruct *easyStruct, ULONG *IDCMP_ptr, APTR argList) (A0, A1, A2, A3) struct Window *BuildEasyRequestArgs(struct Window *RefWindow, struct EasyStruct *easyStruct, ULONG IDCMP, APTR Args) (A0, A1, D0, A3) LONG SysReqHandler(struct Window *window, ULONG *IDCMPFlagsPtr, BOOL WaitInput) (A0, A1, D0) struct Window *OpenWindowTagList(struct NewWindow *newWindow, struct TagItem *tagList) (A0, A1) struct Screen *OpenScreenTagList(struct NewScreen *newScreen, struct TagItem *tagList) (A0, A1) void DrawImageState(struct RastPort *rp, struct Image *image, LONG leftOffset, LONG topOffset, ULONG state, struct DrawInfo *drawInfo) (A0, A1, D0, D1, D2, A2) BOOL PointInImage(ULONG point, struct Image *image) (D0, A0) void EraseImage(struct RastPort *rp, struct Image *image, LONG leftOffset, LONG topOffset) (A0, A1, D0, D1) APTR NewObjectA(struct IClass *classPtr, UBYTE *classID, struct TagItem *tagList) (A0, A1, A2) void DisposeObject(APTR object) (A0) IPTR SetAttrsA(APTR object, struct TagItem *tagList) (A0, A1) ULONG GetAttr(ULONG attrID, Object *object, IPTR *storagePtr) (D0, A0, A1) IPTR SetGadgetAttrsA(struct Gadget *gadget, struct Window *window, struct Requester *requester, struct TagItem *tagList) (A0, A1, A2, A3) APTR NextObject(APTR objectPtrPtr) (A0) struct IClass *FindClass(ClassID classID) (A0) struct IClass *MakeClass(ClassID classID, ClassID superClassID, struct IClass *superClassPtr, ULONG instanceSize, ULONG flags) (A0, A1, A2, D0, D1) void AddClass(struct IClass *classPtr) (A0) struct DrawInfo *GetScreenDrawInfo(struct Screen *screen) (A0) void FreeScreenDrawInfo(struct Screen *screen, struct DrawInfo *drawInfo) (A0, A1) BOOL ResetMenuStrip(struct Window *window, struct Menu *menu) (A0, A1) void RemoveClass(struct IClass *classPtr) (A0) BOOL FreeClass(struct IClass *iclass) (A0) struct ScreenBuffer *AllocScreenBuffer(struct Screen *screen, struct BitMap *bitmap, ULONG flags) (A0, A1, D0) void FreeScreenBuffer(struct Screen *screen, struct ScreenBuffer *screenbuffer) (A0, A1) ULONG ChangeScreenBuffer(struct Screen *screen, struct ScreenBuffer *screenbuffer) (A0, A1) void ScreenDepth(struct Screen *screen, ULONG flags, APTR reserved) (A0, D0, A1) void ScreenPosition(struct Screen *screen, ULONG flags, LONG x1, LONG y1, LONG x2, LONG y2) (A0, D0, D1, D2, D3, D4) void ScrollWindowRaster(struct Window *win, WORD dx, WORD dy, WORD xmin, WORD ymin, WORD xmax, WORD ymax) (A1, D0, D1, D2, D3, D4, D5) void LendMenus(struct Window *fromwindow, struct Window *towindow) (A0, A1) IPTR DoGadgetMethodA(struct Gadget *gad, struct Window *win, struct Requester *req, Msg msg) (A0, A1, A2, A3) void SetWindowPointerA(struct Window *window, struct TagItem *taglist) (A0, A1) BOOL TimedDisplayAlert(ULONG alertnumber, UBYTE *string, UWORD height, ULONG time) (D0, A0, D1, A1) void HelpControl(struct Window *window, ULONG flags) (A0, D0) LONG IsWindowVisible(struct Window *window) (A0) void ShowWindow(struct Window *window) (A0) void HideWindow(struct Window *window) (A0) struct Region *ChangeWindowShape(struct Window *window, struct Region *newshape, struct Hook *callback) (A0, A1, A2) void SetDefaultScreenFont(struct TextFont *textfont) (A0) IPTR DoNotify(Class *cl, Object *o, struct ICData *ic, struct opUpdate *msg) (A0, A1, A2, A3) void FreeICData(struct ICData *icdata) (A0) struct IntuiMessage *AllocIntuiMessage(struct Window *window) (A0) void FreeIntuiMessage(struct IntuiMessage *imsg) (A0) void SendIntuiMessage(struct Window *window, struct IntuiMessage *imsg) (A0, A1) void ChangeDecoration(ULONG ID, struct NewDecorator *decor) (D0, A0) void WindowAction(struct Window *window, ULONG action, struct TagItem *tags) (A0, D0, A1) void ScrollWindowRasterNoFill(struct Window *win, WORD dx, WORD dy, WORD xmin, WORD ymin, WORD xmax, WORD ymax) (A1, D0, D1, D2, D3, D4, D5) ULONG SetPointerBounds(struct Screen *screen, struct Rectangle *rect, ULONG reserved, struct TagItem *tags) (A0, A1, D0, A2) IPTR StartScreenNotifyTagList(struct TagItem *tags) (A0) BOOL EndScreenNotify(IPTR notify) (A0) Object **GetMonitorList(struct TagItem *tags) (A1) void FreeMonitorList(Object **list) (A1)