home *** CD-ROM | disk | FTP | other *** search
- /*
- * Task Priority Manager
- * Copyright 1993, 1994 Barry McConnell
- * bmccnnll@tcd.ie
- *
- * Code to open the main window, settings window, and build the task list.
- *
- * Set tab stops to 4 when editing this file.
- */
-
- #include "PriMan.h"
-
- /*
- * Layout the gadgets for the main window, and open it.
- */
- void OpenMainWindow(void)
- {
- WORD buttonText, /* width of Settings button */
- sizeHeight, /* height of window size gadget */
- spacing, /* spacing between buttons */
-
- /*
- * The next few variables hold various window
- * sizes, explained later.
- */
- listWidth, listHeight, gadHeight, width1, width2;
-
- BOOL fontError; /* already warned user about font error */
-
- struct TextExtent fontSize; /* structure containing font size */
- struct RastPort myRast; /* used to check widths of text strings */
- struct DrawInfo *drawInfo; /* BOOPSI needs this */
- struct Image *sizeImage; /* window size gadget image */
- struct NewGadget myGad; /* structure used when creating gadgets */
- struct Gadget *prevGad; /* last gadget created */
-
- struct NewMenu menu[] = /* the main window's menu structure */
- {
- { NM_TITLE, "Project", 0, 0, 0, 0 },
- { NM_ITEM, "Settings...", "S", 0, 0, 0 },
- { NM_ITEM, NM_BARLABEL, 0, 0, 0, 0 },
- { NM_ITEM, "About...", "?", 0, 0, 0 },
- { NM_ITEM, "Help...", 0, 0, 0, 0 },
- { NM_ITEM, NM_BARLABEL, 0, 0, 0, 0 },
- { NM_ITEM, "Hide", "H", 0, 0, 0 },
- { NM_ITEM, "Quit", "Q", 0, 0, 0 },
- { NM_TITLE, "Task", 0, 0, 0, 0 },
- { NM_ITEM, "Update List", "U", 0, 0, 0 },
- { NM_ITEM, NM_BARLABEL, 0, 0, 0, 0 },
- { NM_ITEM, "Kill...", "K", 0, 0, 0 },
- { NM_ITEM, NM_BARLABEL, 0, 0, 0, 0 },
- { NM_ITEM, "Signal...", 0, 0, 0, 0 },
- { NM_SUB, "Ctrl-C", 0, 0, 0, (APTR)SIGBREAKF_CTRL_C },
- { NM_SUB, "Ctrl-D", 0, 0, 0, (APTR)SIGBREAKF_CTRL_D },
- { NM_SUB, "Ctrl-E", 0, 0, 0, (APTR)SIGBREAKF_CTRL_E },
- { NM_SUB, "Ctrl-F", 0, 0, 0, (APTR)SIGBREAKF_CTRL_F },
- { NM_ITEM, "Priority", 0, 0, 0, 0 },
- { NM_SUB, "-5", "-", 0, 0, (APTR)-5 },
- { NM_SUB, "-1", 0, 0, 0, (APTR)-1 },
- { NM_SUB, "0", "=", 0, 0, (APTR)0 },
- { NM_SUB, "+1", 0, 0, 0, (APTR)+1 },
- { NM_SUB, "+5", "+", 0, 0, (APTR)+5 },
- { NM_ITEM, NM_BARLABEL, 0, 0, 0, 0 },
- { NM_ITEM, "Frozen", "F", CHECKIT | MENUTOGGLE, 0, 0 },
- { NM_ITEM, NM_BARLABEL, 0, 0, 0, 0 },
- { NM_ITEM, "Wide Slider", "W", CHECKIT | MENUTOGGLE, 0, 0 },
- { NM_END, NULL, 0, 0, 0, 0 }
- };
-
- /*
- * Message that appears when one of the fonts couldn't be opened.
- */
- struct EasyStruct font =
- {
- sizeof(struct EasyStruct),
- 0,
- "PriMan trouble",
- "Can't open %s -\ndefaulting to Topaz 8.",
- "Okay"
- };
-
- /*
- * Perform all the necessary stuff before opening any windows, such as
- * locking the public screen and getting the fonts. If the window is
- * already open, this step is not necessary.
- */
- if (!mainWindow)
- {
- if (myScreen = LockOurScreen(TRUE))
- {
- if ((visInfo) = GetVisualInfo(myScreen, TAG_END))
- {
- /*
- * If the first character of the font name is 0, or the
- * height is 0, it means the user never gave a font name on
- * startup. In this case, we use the Preferences fonts.
- */
- if (!propName[0] || !propTA.ta_YSize)
- {
- strcpy(propName, myScreen -> Font -> ta_Name);
- propTA.ta_YSize = myScreen -> Font -> ta_YSize;
- }
-
- if (!monoName[0] || !monoTA.ta_YSize)
- {
- strcpy(monoName, GfxBase -> DefaultFont -> tf_Message.mn_Node.ln_Name);
- monoTA.ta_YSize = GfxBase -> DefaultFont -> tf_YSize;
- }
-
- /*
- * Now we try to open the fonts. If either font fails to
- * open, we attempt to fall back on Topaz 8. fontError is
- * set if there is a problem with the Gadget font, so we
- * know not to bother the user with a second requester if
- * we can't open the List font either.
- */
- fontError = FALSE;
-
- if (!(propFont = OpenDiskFont(&propTA)))
- {
- SimpleRequest(&font, propName);
- fontError = TRUE;
-
- propTA.ta_YSize = 8;
- strcpy(propName, "topaz.font");
- propFont = OpenDiskFont(&propTA);
- }
-
- if (!(monoFont = OpenDiskFont(&monoTA)))
- {
- if (!fontError)
- SimpleRequest(&font, monoName);
-
- monoTA.ta_YSize = 8;
- strcpy(monoName, "topaz.font");
- monoFont = OpenDiskFont(&monoTA);
- }
-
- /*
- * If both fonts opened okay, we figure out their sizes in
- * pixels. Else, we abort - but Topaz 8 *should* be around!
- */
- if (propFont && monoFont)
- {
- FontExtent(propFont, &fontSize);
- height = fontSize.te_Height;
- FontExtent(monoFont, &fontSize);
- sysHeight = fontSize.te_Height;
- sysWidth = fontSize.te_Width;
-
- /*
- * If this is the very first time the main window has
- * been opened, and the user did not supply any default
- * dimensions, we estimate a good size. The height will
- * will be 2/3 the screen height, and the width will
- * be half the height. The top and left positions will
- * be chosen so as to centre the window on the screen.
- */
- if (!winHeight)
- winHeight = myScreen -> Height * 2 / 3;
- if (!winWidth)
- winWidth = winHeight / 2;
- if (winTop == -1)
- winTop = (myScreen -> Height - winHeight) / 2;
- if (winLeft == -1)
- winLeft = (myScreen -> Width - winWidth) / 2;
- }
- else
- error = FONT_ERROR;
- }
- else
- error = VISINFO_ERROR;
- }
- else
- error = LOCK_ERROR;
- }
-
- if (!error)
- {
- /*
- * Calculate the width of the widest button. This is done using a
- * dummy RastPort for getting string lengths.
- */
- InitRastPort(&myRast);
- myRast.Font = propFont;
- buttonText = TextLength(&myRast, "Settings...", 11) + INTERWIDTH * 2;
-
- /*
- * Calculate the height of the bottom window border. This is
- * dependent on the dimensions of the size gadget, which can
- * change using sysihack.
- */
- drawInfo = GetScreenDrawInfo(myScreen);
- sizeImage = (struct Image *)NewObject(NULL, "sysiclass",
- SYSIA_DrawInfo, drawInfo,
- SYSIA_Which, SIZEIMAGE,
- SYSIA_Size, SYSISIZE_MEDRES,
- TAG_END);
- sizeHeight = sizeImage -> Height;
- DisposeObject((APTR)sizeImage);
- FreeScreenDrawInfo(myScreen, drawInfo);
-
- /*
- * Here we calculate the minimum window size we need to fit all
- * the gadgets. We need to see if the minimum space the ListView
- * needs is larger or smaller than the minimum space occupied by
- * the buttons.
- *
- * windowTop is the size of the window's top border plus the title
- * bar font.
- *
- * listWidth is the width of the window using a ListView with no
- * characters in it. It takes into account the gap needed between
- * the window borders on either side, and the width of the
- * ListView's own borders. A bug in 2.x clips the ListView text
- * too early (before the right border) when using certain fonts, so
- * we must allow for that.
- *
- * listHeight allows for one or two elements in the ListView. It
- * takes into account the space occupied by the ListView's borders,
- * and the fact that under 2.x extra space is taken up by the name
- * of the currently-selected entry being displayed below.
- *
- * gadHeight is the vertical space occupied by everything *else* in
- * the window, namely the slider gadget, the row of buttons, the
- * spacing between everything, and the size gadget in the bottom
- * border.
- *
- * width1 is the width of the window using the smallest possible
- * ListView. It uses the ListView's "baggage" plus the space taken
- * by enough characters in it to contain the first letter of each
- * task name along with the priority. Worst case here would be a
- * frozen task (e.g. Workbench) running at a high priority: we need
- * to have enough room for "(W) -128", i.e. 8 characters.
- *
- * width2 is simply the width of the three buttons with spacing
- * between them and on either side.
- */
- windowTop = (myScreen -> WBorTop) + myScreen -> Font -> ta_YSize + 1;
- listWidth = INTERWIDTH + (osver < 39 ? ListEarlyClip : 0) + INTERWIDTH + ScrollBarWidth + INTERWIDTH;
- listHeight = INTERHEIGHT + sysHeight * (osver < 39 ? 4 : 2);
- gadHeight = windowTop + INTERHEIGHT + /* ListView */ INTERHEIGHT + (sysHeight + INTERHEIGHT) + INTERHEIGHT +
- (height + INTERHEIGHT) + INTERHEIGHT + sizeHeight;
- width1 = sysWidth * 8 + listWidth;
- width2 = INTERWIDTH + (buttonText + INTERWIDTH) * 3;
- minWidth = width1 > width2 ? width1 : width2;
- minHeight = gadHeight + listHeight;
-
- /*
- * Even using a 24-point font, a minimally-sized PriMan window can
- * still fit on a 640*200 screen. Therefore, there is no need to
- * ever drop down to Topaz 8 to "force" it to fit - making the
- * window smaller will always suffice. (Using a 50-point font on a
- * low-res screen would be plain silly!) Here we also make sure the
- * window is going to be at least as large as the minimum size
- * needed. If the window has already been opened, these lines are
- * not necessary since it's guaranteed to fit already, so instead
- * we take the opportunity to copy the physical window dimensions
- * into the variables.
- */
- if (mainWindow)
- GetPos();
- else
- {
- /*
- * Make sure window dimensions fall within the accepted range.
- */
- Range(&winWidth, minWidth, myScreen -> Width);
- Range(&winHeight, minHeight, myScreen -> Height);
- }
-
- /*
- * Now that we know the true width of the window we can, firstly,
- * calculate how many characters will fit in the ListView...
- */
- taskLength = (winWidth - listWidth) / sysWidth;
-
- /*
- * ...and, secondly, calculate the spacing between each button.
- * This is done by taking the window width, subtracting the amount
- * taken up by the buttons themselves and the border space, then
- * dividing by one less than the number of buttons on the row.
- */
- spacing = (winWidth - buttonText * 3 - INTERWIDTH * 2) / 2;
-
- /*
- * Now we have to create all the gadgets. We use prevGad to link
- * them together. If one call fails, then this will become NULL,
- * and the succeeding calls will automatically fail. Thus we need
- * only check prevGad after attempting to create all the gadgets.
- */
- mainGads = NULL;
- prevGad = CreateContext(&mainGads);
-
- /*
- * Create the ListView.
- */
- myGad.ng_LeftEdge = INTERWIDTH;
- myGad.ng_TopEdge = windowTop + INTERHEIGHT; /* leave a gap below title bar */
- myGad.ng_Width = winWidth - INTERWIDTH * 2; /* leave a gap on either side */
- myGad.ng_Height = winHeight - gadHeight; /* maximum space left over for ListView */
- myGad.ng_GadgetText = NULL;
- myGad.ng_TextAttr = &monoTA;
- myGad.ng_GadgetID = LISTGAD;
- myGad.ng_Flags = 0;
- myGad.ng_VisualInfo = visInfo;
-
- prevGad = listGad = CreateGadget(LISTVIEW_KIND, prevGad, &myGad,
- GTLV_Labels, NULL,
- GTLV_ShowSelected, NULL,
- TAG_END);
-
- /*
- * The ListView may get shrunk slightly, to accomodate an exact
- * number of lines. If the window has not already been opened, we
- * can check the created ListView's height, and shrink the window
- * appropriately. Under 2.x, the correct height does not get filled
- * into the Gadget structure, so this only works under 3.x.
- */
- if (!(mainWindow || osver < 39))
- {
- winHeight += (listGad) -> Height - myGad.ng_Height;
- myGad.ng_Height = (listGad) -> Height;
- }
-
- /*
- * Create the slider. Even though it gets enabled or disabled as
- * necessary later on, we assume the currently-selected task (if
- * any) will remain valid, and enable or disable it as necessary
- * here. This prevents it "flashing" when the window gets resized.
- */
- myGad.ng_LeftEdge += sysWidth * 4 + INTERWIDTH; /* allow room for the label */
- myGad.ng_TopEdge += myGad.ng_Height + INTERHEIGHT;
- myGad.ng_Width = winWidth - INTERWIDTH - myGad.ng_LeftEdge;
- myGad.ng_Height = sysHeight + INTERHEIGHT;
- myGad.ng_GadgetID = SLIDERGAD;
-
- prevGad = sliderGad = CreateGadget(SLIDER_KIND, prevGad, &myGad,
- GTSL_Min, -25,
- GTSL_Max, 25,
- GTSL_Level, 0,
- GTSL_LevelFormat, "%4ld",
- GTSL_MaxLevelLen, 4,
- GTSL_LevelPlace, PLACETEXT_LEFT,
- GA_RelVerify, TRUE,
- GA_Disabled, pos == -1,
- TAG_END);
-
- /*
- * Create the Break button.
- */
- myGad.ng_LeftEdge = INTERWIDTH;
- myGad.ng_TopEdge += myGad.ng_Height + INTERHEIGHT;
- myGad.ng_Width = buttonText;
- myGad.ng_Height = height + INTERHEIGHT;
- myGad.ng_GadgetText = "_Break";
- myGad.ng_TextAttr = &propTA;
- myGad.ng_GadgetID = BREAKGAD;
-
- prevGad = breakGad = CreateGadget(BUTTON_KIND, prevGad, &myGad,
- GT_Underscore, '_',
- GA_Disabled, pos == -1,
- TAG_END);
-
- /*
- * Create the Kill button, using the spacing variable to decide how
- * far right it goes relative to the Break button.
- */
- myGad.ng_LeftEdge += buttonText + spacing;
- myGad.ng_GadgetText = "_Kill";
- myGad.ng_GadgetID = KILLGAD;
-
- prevGad = killGad = CreateGadget(BUTTON_KIND, prevGad, &myGad,
- GT_Underscore, '_',
- GA_Disabled, pos == -1,
- TAG_END);
-
- /*
- * Create the Settings button. This always goes relative to the
- * right window border.
- */
- myGad.ng_LeftEdge = winWidth - INTERWIDTH - buttonText;
- myGad.ng_GadgetText = "_Settings...";
- myGad.ng_GadgetID = SETTINGSGAD;
-
- prevGad = setGad = CreateGadget(BUTTON_KIND, prevGad, &myGad,
- GT_Underscore, '_',
- TAG_END);
-
- /*
- * Once we've got this far, we need to check if all the gadgets
- * actually got created. Next, if the window was was already open
- * (i.e. this function was called because of a resize), any
- * remaining imagery inside its borders will need clearing, and we
- * can simply add the gadgets straight in. The alternative requires
- * opening the window and attaching the menu strip.
- */
- if (prevGad)
- {
- if (mainWindow)
- {
- /*
- * When clearing the window's old imagery, everything
- * should be wiped except the following:
- *
- * - Title bar and space underneath it
- * - Left border and space inside it
- * - Right border
- * - Bottom border
- */
- blank.Width = winWidth - INTERWIDTH - INTERWIDTH / 2;
- blank.Height = winHeight - windowTop - INTERHEIGHT - sizeHeight;
- EraseImage(mainWindow -> RPort, &blank, INTERWIDTH, windowTop + INTERHEIGHT);
-
- AddGList(mainWindow, mainGads, ~0, -1, NULL);
- RefreshGList(mainGads, mainWindow, NULL, -1);
- GT_RefreshWindow(mainWindow, NULL);
- CreateList(&memoryKey);
- }
- else
- {
- if (mainWindow = OpenWindowTags(NULL,
- WA_Title, "PriMan",
- WA_ScreenTitle, "Task Priority Manager "VERSION" - Copyright 1994 Barry McConnell",
- WA_Gadgets, mainGads,
- WA_Left, winLeft,
- WA_Top, winTop,
- WA_Width, winWidth,
- WA_Height, winHeight,
- WA_MinWidth, minWidth,
- WA_MinHeight, minHeight,
- WA_MaxWidth, ~0,
- WA_MaxHeight, ~0,
- WA_DragBar, TRUE,
- WA_DepthGadget, TRUE,
- WA_CloseGadget, TRUE,
- WA_SizeGadget, TRUE,
- WA_SizeBBottom, TRUE,
- WA_Activate, TRUE,
- WA_NewLookMenus, TRUE,
- refresh == SIMPLEWINDOW ? WA_SimpleRefresh : WA_SmartRefresh, TRUE,
- WA_PubScreen, myScreen,
- TAG_END))
- {
- if (menuStrip = CreateMenus(menu, TAG_END))
- {
- /*
- * We want to get the initial state of the "..."
- * after the Kill and Signal menu items right, so
- * we use this function, which also attaches the
- * menu strip to our window. If there is an error
- * here, the tidyup routine will free up the menu
- * strip for us, since the main window is already
- * open.
- */
- MenuEllipsis(menuStrip, FALSE);
- if (!error)
- {
- /*
- * If we're not running as a Commodity and
- * can't be iconified, there is no point in
- * allowing the user to select the Hide menu
- * item!
- */
- if (!(iconify || commodity))
- OffMenu(mainWindow, FULLMENUNUM(M_PROJECT, I_HIDE, NOSUB));
-
- /*
- * Set up the message port, refresh the window,
- * add in the task list, and make sure our
- * screen is visible.
- */
- mainWindow -> UserPort = winPort;
- ModifyIDCMP(mainWindow, WINDOWIDCMP);
- GT_RefreshWindow(mainWindow, NULL);
- CreateList(&memoryKey);
- ScreenToFront(myScreen);
- }
- }
- else
- error = MENU_ERROR;
- }
- else
- error = MAIN_ERROR;
- }
- }
- else
- error = GADGET_ERROR;
- }
- }
-
-
- /*
- * Layout the gadgets for the settings window, and open it. There are
- * actually going to be three sets of gadgets for this window, with the
- * user selecting one set at a time. So we create all three sets here, and
- * then use the one which the user had selected the last time this window
- * was open.
- */
- void OpenSettingsWindow(void)
- {
- WORD oldPage, /* last gadget page showing when settings window was opened */
-
- /*
- * These relate to the size of the checkbox gadget,
- * and are explained later.
- */
- size, offset, max,
-
- /*
- * These relate to the window dimensions, and are
- * also explained later.
- */
- buttonWidth, textWidth, cancelWidth, spacing, intWidth, innerWidth, setWidth,
-
- /*
- * End of each page of gadgets. gadgetEnd itself is
- * the lowest position the gadgets reach to.
- */
- gadgetEnd1, gadgetEnd2, gadgetEnd3, gadgetEnd;
-
- struct RastPort myRast; /* used to check widths of text strings */
- struct NewGadget myGad; /* structure used when creating gadgets */
- struct Gadget *prevGad1, /* last gadget created - one for each page of gadgets */
- *prevGad2, *prevGad3, *prevGad4;
-
- /*
- * These contain the text for the three cycle gadgets.
- */
- static char *pageText[] = { "Interface", "Commodity", "General", NULL };
- static char *refreshText[] = { "Smart Refresh", "Simple Refresh", NULL };
- static char *openText[] = { "Default Screen", "Front Screen", NULL };
-
- /*
- * Here we remember the original settings of everything, so they can be
- * restored if the user clicks Cancel.
- */
- newPropFont = newMonoFont = FALSE;
- tempRefresh = refresh;
- tempOpen = open;
- tempConfirm = confirm;
- tempIconify = iconify;
- tempCommodity = commodity;
- tempPopup = popup;
-
- FontString(&propTA, propString); /* initial setting for the text box */
- FontString(&monoTA, monoString);
-
- strcpy(tempPropName, propName); /* initial settings for the font requesters */
- strcpy(tempMonoName, monoName);
- tempPropSize = propTA.ta_YSize;
- tempMonoSize = monoTA.ta_YSize;
-
- InitRastPort(&myRast);
- myRast.Font = propFont;
-
- /*
- * Under 3.x, we can scale the checkboxes to match the font size. The
- * following variables are used:
- *
- * size holds the actual height of the checkbox. It takes into account
- * whether or not it can be scaled, and has a minimum size.
- *
- * offset is non-zero if the font is taller than the checkbox, and
- * gives the extra amount the checkbox will need to be moved down to be
- * centred with respect to its label.
- *
- * max is the actual height taken by the checkbox and label
- * side-by-side, and is just the maximum of their respective heights,
- * used for lining up gadgetry below them.
- */
- size = osver < 39 ? 11 : (height > 10 ? height : 11);
- offset = height > size ? (height - size) / 2 : 0;
- max = height > size ? height : size;
-
- /*
- * Now we calculate the widths of a few things, to help us lay out the
- * interface:
- *
- * buttonWidth is the width of each Font button.
- *
- * textWidth is the width of the text boxes beside the buttons. For
- * want of anything better to base this on, we'll use the width of the
- * two cycle gadget below it for this.
- *
- * cancelWidth is the width of the Save, Use and Cancel buttons.
- *
- * spacing is the distance between these three buttons.
- *
- * intWidth is the size of any integer boxes (enough to hold "-128"
- * plus the cursor).
- *
- * innerWidth is the width of the portion of the window inside the
- * bevel box, allowing a gap.
- *
- * setWidth is the width of the whole window, basically just allowing
- * a gap for the bevel box.
- */
- buttonWidth = TextLength(&myRast, "Gadget Font...", 14) + INTERWIDTH * 2;
- textWidth = TextLength(&myRast, "Simple Refresh", 14) + INTERWIDTH * 2 + CycleWidth;
- cancelWidth = TextLength(&myRast, "Cancel", 6) + INTERWIDTH * 2;
- intWidth = TextLength(&myRast, "-9999", 5) + INTERWIDTH * 2;
- innerWidth = INTERWIDTH + buttonWidth + INTERWIDTH + textWidth + INTERWIDTH;
- setWidth = INTERWIDTH + innerWidth + INTERWIDTH;
- spacing = (setWidth - INTERWIDTH * 2 - cancelWidth * 3) / 2;
-
- /*
- * Create and link all the gadgets, as before. Each set of gadgets is
- * pointed to from an array.
- */
- setGads[3] = NULL;
- prevGad1 = CreateContext(&(setGads[3]));
-
- /*
- * Create the cycle gadget at the top of the window. This is stretched
- * to be as wide as possible.
- */
- myGad.ng_LeftEdge = INTERWIDTH + TextLength(&myRast, "Page", 4) + INTERWIDTH;
- myGad.ng_TopEdge = windowTop + INTERHEIGHT;
- myGad.ng_Width = setWidth - myGad.ng_LeftEdge - INTERWIDTH;
- myGad.ng_Height = height + INTERHEIGHT + 2;
- myGad.ng_GadgetText = "_Page";
- myGad.ng_GadgetID = PAGEGAD;
- myGad.ng_TextAttr = &propTA;
- myGad.ng_Flags = PLACETEXT_LEFT;
- myGad.ng_VisualInfo = visInfo;
-
- prevGad1 = pageGad = CreateGadget(CYCLE_KIND, prevGad1, &myGad,
- GT_Underscore, '_',
- GTCY_Labels, pageText,
- GTCY_Active, page,
- TAG_END);
-
- setGadStart = myGad.ng_TopEdge + myGad.ng_Height + INTERHEIGHT * 3;
-
- /*
- * We want a separate set of gadgets for Interface.
- */
- setGads[0] = NULL;
- prevGad2 = CreateContext(&(setGads[0]));
-
- /*
- * Create the Gadget Font button.
- */
- myGad.ng_LeftEdge = INTERWIDTH * 2;
- myGad.ng_TopEdge = setGadStart;
- myGad.ng_Width = buttonWidth;
- myGad.ng_Height = height + INTERHEIGHT;
- myGad.ng_GadgetText = "_Gadget Font...";
- myGad.ng_GadgetID = GFONTGAD;
- myGad.ng_Flags = 0;
-
- prevGad2 = propFontButGad = CreateGadget(BUTTON_KIND, prevGad2, &myGad,
- GT_Underscore, '_',
- TAG_END);
-
- /*
- * Create the Gadget Font text box.
- */
- myGad.ng_LeftEdge += myGad.ng_Width + INTERWIDTH;
- myGad.ng_Width = textWidth;
- myGad.ng_GadgetText = NULL;
- myGad.ng_GadgetID = GBOXGAD;
-
- prevGad2 = propFontGad = CreateGadget(TEXT_KIND, prevGad2, &myGad,
- GTTX_Border, TRUE,
- GTTX_Text, propString,
- TAG_END);
-
- /*
- * Create the List Font button.
- */
- myGad.ng_LeftEdge = INTERWIDTH * 2;
- myGad.ng_TopEdge += myGad.ng_Height + INTERHEIGHT;
- myGad.ng_Width = buttonWidth;
- myGad.ng_GadgetText = "_List Font...";
- myGad.ng_GadgetID = LFONTGAD;
-
- prevGad2 = monoFontButGad = CreateGadget(BUTTON_KIND, prevGad2, &myGad,
- GT_Underscore, '_',
- TAG_END);
-
- /*
- * Create the List Font text box.
- */
- myGad.ng_LeftEdge += myGad.ng_Width + INTERWIDTH;
- myGad.ng_Width = textWidth;
- myGad.ng_GadgetText = NULL;
- myGad.ng_GadgetID = LBOXGAD;
-
- prevGad2 = monoFontGad = CreateGadget(TEXT_KIND, prevGad2, &myGad,
- GTTX_Border, TRUE,
- GTTX_Text, monoString,
- TAG_END);
-
- /*
- * Create the Refresh cycle gadget, lined up just below the text boxes
- * above.
- */
- myGad.ng_TopEdge += myGad.ng_Height + INTERHEIGHT;
- myGad.ng_Height += 2; /* looks better with an extra couple of pixels! */
- myGad.ng_GadgetText = "_Window Type";
- myGad.ng_GadgetID = REFRESHGAD;
- myGad.ng_Flags = PLACETEXT_LEFT;
-
- prevGad2 = refreshGad = CreateGadget(CYCLE_KIND, prevGad2, &myGad,
- GT_Underscore, '_',
- GTCY_Labels, refreshText,
- GTCY_Active, refresh,
- TAG_END);
-
- /*
- * Create the Open On cycle gadget, lining it up as above.
- */
- myGad.ng_TopEdge += myGad.ng_Height + INTERHEIGHT;
- myGad.ng_GadgetText = "_Open On";
- myGad.ng_GadgetID = OPENGAD;
-
- prevGad2 = openGad = CreateGadget(CYCLE_KIND, prevGad2, &myGad,
- GT_Underscore, '_',
- GTCY_Labels, openText,
- GTCY_Active, open,
- TAG_END);
-
-
- gadgetEnd1 = myGad.ng_TopEdge + myGad.ng_Height;
-
- /*
- * Here's a new set of gadgets for Commodity.
- */
- setGads[1] = NULL;
- prevGad4 = CreateContext(&(setGads[1]));
-
- /*
- * Create the Install checkbox.
- */
- myGad.ng_LeftEdge = INTERWIDTH * 2;
- myGad.ng_TopEdge = setGadStart + offset;
- myGad.ng_Width = 26;
- myGad.ng_Height = size;
- myGad.ng_GadgetText = "_Install as a Commodity";
- myGad.ng_GadgetID = COMGAD;
- myGad.ng_Flags = PLACETEXT_RIGHT;
-
- prevGad4 = comGad = CreateGadget(CHECKBOX_KIND, prevGad4, &myGad,
- GT_Underscore, '_',
- GTCB_Scaled, TRUE,
- GTCB_Checked, commodity,
- TAG_END);
-
- /*
- * Create the Popup checkbox. Disable it (and the rest) if PriMan is
- * not running as a Commodity.
- */
- myGad.ng_TopEdge += max + INTERHEIGHT; /* offset was already added in for us */
- myGad.ng_GadgetText = "Popup When _Launched";
- myGad.ng_GadgetID = POPUPGAD;
-
- prevGad4 = popupGad = CreateGadget(CHECKBOX_KIND, prevGad4, &myGad,
- GT_Underscore, '_',
- GTCB_Scaled, TRUE,
- GTCB_Checked, popup,
- GA_Disabled, !commodity,
- TAG_END);
-
- /*
- * Create the Hotkey text box.
- */
- myGad.ng_LeftEdge += TextLength(&myRast, "Priority", 8) + INTERWIDTH;
- myGad.ng_TopEdge += max - offset + INTERHEIGHT;
- myGad.ng_Width = innerWidth - myGad.ng_LeftEdge;
- myGad.ng_Height = height + INTERHEIGHT + 2;
- myGad.ng_GadgetText = "_Hotkey";
- myGad.ng_GadgetID = HOTKEYGAD;
- myGad.ng_Flags = PLACETEXT_LEFT;
-
- prevGad4 = hotkeyGad = CreateGadget(STRING_KIND, prevGad4, &myGad,
- GT_Underscore, '_',
- GTST_String, hotkey,
- GTST_MaxChars, MaxHotkey,
- GA_Disabled, !commodity,
- TAG_END);
-
- /*
- * Create the Commodity Priority integer box.
- */
- myGad.ng_TopEdge += myGad.ng_Height + INTERHEIGHT;
- myGad.ng_Width = intWidth;
- myGad.ng_GadgetText = "Priorit_y";
- myGad.ng_GadgetID = PRIORITYGAD;
-
- prevGad4 = priorityGad = CreateGadget(INTEGER_KIND, prevGad4, &myGad,
- GT_Underscore, '_',
- GTIN_Number, priority,
- GTIN_MaxChars, 4, /* e.g., -128 */
- GA_Disabled, !commodity,
- TAG_END);
-
- gadgetEnd3 = myGad.ng_TopEdge + myGad.ng_Height;
-
- /*
- * Here's a new set of gadgets for General.
- */
- setGads[2] = NULL;
- prevGad3 = CreateContext(&(setGads[2]));
-
- /*
- * Create the Task Priority integer box, initialising it to our current
- * priority.
- */
- myGad.ng_LeftEdge = INTERWIDTH * 2 + TextLength(&myRast, "Task Priority", 13) + INTERWIDTH;
- myGad.ng_TopEdge = setGadStart;
- myGad.ng_GadgetText = "Task Priorit_y";
- myGad.ng_GadgetID = TOOLPRIGAD;
-
- prevGad3 = toolpriGad = CreateGadget(INTEGER_KIND, prevGad3, &myGad,
- GT_Underscore, '_',
- GTIN_Number, FindTask(NULL) -> tc_Node.ln_Pri,
- GTIN_MaxChars, 4, /* e.g., -128 */
- TAG_END);
-
- /*
- * Create the Confirm Actions checkbox.
- */
- myGad.ng_LeftEdge = INTERWIDTH * 2;
- myGad.ng_TopEdge += myGad.ng_Height + INTERHEIGHT + offset;
- myGad.ng_Width = 26;
- myGad.ng_Height = size;
- myGad.ng_GadgetText = "Confirm _Actions";
- myGad.ng_GadgetID = CONFIRMGAD;
- myGad.ng_Flags = PLACETEXT_RIGHT;
-
- prevGad3 = confirmGad = CreateGadget(CHECKBOX_KIND, prevGad3, &myGad,
- GT_Underscore, '_',
- GTCB_Scaled, TRUE, /* new in 3.0 */
- GTCB_Checked, confirm,
- TAG_END);
-
- /*
- * Create the Iconify checkbox.
- */
- myGad.ng_TopEdge += max + INTERHEIGHT;
- myGad.ng_GadgetText = "_Iconify When Closed";
- myGad.ng_GadgetID = ICONIFYGAD;
-
- prevGad3 = iconifyGad = CreateGadget(CHECKBOX_KIND, prevGad3, &myGad,
- GT_Underscore, '_',
- GTCB_Scaled, TRUE,
- GTCB_Checked, iconify,
- TAG_END);
-
- gadgetEnd2 = myGad.ng_TopEdge + max - offset;
-
- /*
- * Now that we have laid out the three sets of gadgets, we know exactly
- * how big the window must be. We calculate the true end of the
- * gadgets, and then place the Save, Use & Cancel buttons below this.
- */
- gadgetEnd = gadgetEnd1 > gadgetEnd2 ? gadgetEnd1 : gadgetEnd2;
- gadgetEnd = gadgetEnd > gadgetEnd3 ? gadgetEnd : gadgetEnd3;
- setGadHeight = gadgetEnd - setGadStart;
-
- /*
- * Create the Save button. Disable it if PriMan's .info file cannot be
- * found, since we won't have any icon in which to store the ToolTypes!
- */
- myGad.ng_LeftEdge = INTERWIDTH;
- myGad.ng_TopEdge = gadgetEnd + INTERHEIGHT * 3;
- myGad.ng_Width = cancelWidth;
- myGad.ng_Height = height + INTERHEIGHT;
- myGad.ng_GadgetText = "_Save";
- myGad.ng_Flags = 0;
- myGad.ng_GadgetID = SAVEGAD;
-
- prevGad1 = saveGad = CreateGadget(BUTTON_KIND, prevGad1, &myGad,
- GT_Underscore, '_',
- GA_Disabled, myIcon == NULL,
- TAG_END);
-
- /*
- * Create the Use button, evenly distributing the spacing between the
- * three buttons.
- */
- myGad.ng_LeftEdge += myGad.ng_Width + spacing;
- myGad.ng_GadgetText = "_Use";
- myGad.ng_GadgetID = USEGAD;
-
- prevGad1 = useGad = CreateGadget(BUTTON_KIND, prevGad1, &myGad,
- GT_Underscore, '_',
- TAG_END);
-
- /*
- * Create the Cancel button.
- */
- myGad.ng_LeftEdge += cancelWidth + (setWidth - INTERWIDTH * 2 - cancelWidth * 3) / 2;
- myGad.ng_GadgetText = "_Cancel";
- myGad.ng_GadgetID = CANCELGAD;
-
- prevGad1 = cancelGad = CreateGadget(BUTTON_KIND, prevGad1, &myGad,
- GT_Underscore, '_',
- TAG_END);
-
- if (prevGad1 && prevGad2 && prevGad3 && prevGad4)
- {
- /*
- * The Settings window is offset from the main window a little -
- * moved down and across by the dimensions of the window's close
- * gadget.
- */
- if (setWindow = OpenWindowTags(NULL,
- WA_Title, "PriMan Settings",
- WA_Gadgets, setGads[3],
- WA_Left, mainWindow -> LeftEdge + CloseBoxWidth,
- WA_Top, mainWindow -> TopEdge + windowTop,
- WA_Width, setWidth,
- WA_Height, myGad.ng_TopEdge + myGad.ng_Height + INTERHEIGHT + myScreen -> WBorBottom,
- WA_DragBar, TRUE,
- WA_DepthGadget, TRUE,
- WA_Activate, TRUE,
- WA_RMBTrap, TRUE,
- refresh ? WA_SimpleRefresh : WA_SmartRefresh, TRUE,
- WA_PubScreen, myScreen,
- TAG_END))
- {
- setWindow -> UserPort = winPort;
- ModifyIDCMP(setWindow, WINDOWIDCMP);
- DrawSettingsBox();
- GT_RefreshWindow(setWindow, NULL);
- oldPage = page; /* take a copy of the gadget page that was last showing */
- page = -1; /* next function will see that no gadgets are currently visible */
- NewPage(oldPage); /* display whatever the user last saw */
- }
- else
- error = SETTINGS_ERROR;
- }
- else
- error = GADGET_ERROR;
- }
-
-
- /*
- * Generate the task list, and place it in the main window's ListView. If
- * the task has an appropriate CLI number, that will be added in before its
- * name. If it is frozen, its name will be bracketed. If a task was already
- * selected, we will attempt to keep it selected.
- */
- void CreateList(struct Remember **memoryKey)
- {
- int i; /* task count */
-
- struct Node *execNode; /* index into Exec's task list */
- struct ListType *taskNode; /* storage space for task info */
- struct Task *taskArray[MaxTasks]; /* pointers to task info */
-
- /*
- * The main window's titlebar is actually set here.
- */
- static char *title = "PriMan - 999 tasks";
-
- /*
- * This is the error message the user sees if there are more tasks in
- * the system than our hard-coded maximum (very unlikely!).
- */
- struct EasyStruct task =
- {
- sizeof(struct EasyStruct),
- 0,
- "PriMan trouble",
- "Too many tasks in system -\nlist may be incomplete.",
- "Okay"
- };
-
- /*
- * If we haven't yet established what the top entry in the ListView was
- * (top is -1), now would be a good time. (The code that handles window
- * resizing gets the top itself since it causes the whole ListView to
- * be freed up before it gets this far.) If this is our first time
- * here, top will be 0 which is what we want anyway.
- */
- if (top == -1)
- GetListTop();
-
- /*
- * Here we remove the old task list from the ListView, and free up the
- * memory it occupied (we can do the freeing even if the memory key was
- * NULL already).
- */
- GT_SetGadgetAttrs(listGad, mainWindow, NULL,
- GTLV_Labels, ~0,
- TAG_END);
- FreeRemember(memoryKey, TRUE);
-
- /*
- * We are going to do three passes through the task list:
- *
- * 1. Fill taskArray with a list of task addresses. We do this while
- * interrupts are disabled, so the pointers remain valid and the
- * task lists don't get modified. Hence it must happen very fast!
- * The very first entry will be this task, since it doesn't appear
- * on either the Ready or Waiting queues. taskCount is the next
- * entry to be filled in the array.
- *
- * 2. Copy the task names and priorities into individual columnised
- * strings inside ListType structures, using the pointers we placed
- * in taskArray above. This happens while interrupts are enabled
- * but multitasking disabled, so that vital things such as timer and
- * serial interrupts can happen. Since multitasking is disabled, no
- * tasks can actually exit (so our pointers remain valid), although
- * it is possible for the task lists to be resorted (something which
- * we don't need to worry about since we already walked them above).
- *
- * 3. After enabling multitasking, we can set about the time-consuming
- * business of sorting the task list. Since we already have the
- * names and priorities, we don't care what happens to the physical
- * tasks from here on.
- *
- * Here is the first pass...
- */
- taskArray[0] = FindTask(NULL);
- taskCount = 1;
-
- /*
- * Remember that we want to disable interrupts during the first
- * pass, and just multitasking during the second pass. So we'll
- * nest the Forbid() and Disable() statements, allowing us to
- * simply do an Enable() after the first pass to enable interrupts,
- * but leave multitasking disabled.
- */
- Forbid();
- Disable();
-
- /*
- * Here we walk both the Ready and Waiting queues, copying the task
- * pointers in each into the array. The loop can prematurely abort
- * if we reach the maximum allowable number of tasks (array size).
- */
- for (execNode = SysBase -> TaskReady.lh_Head;
- execNode -> ln_Succ && taskCount < MaxTasks;
- execNode = execNode -> ln_Succ)
- taskArray[taskCount++] = (struct Task *)execNode;
-
- for (execNode = SysBase -> TaskWait.lh_Head;
- execNode -> ln_Succ && taskCount < MaxTasks;
- execNode = execNode -> ln_Succ)
- taskArray[taskCount++] = (struct Task *)execNode;
-
- /*
- * This Enable() will allow interrupts to continue, but not
- * multitasking (remember we also did a Forbid()), so the data in
- * the task lists will remain static.
- */
- Enable();
-
- /*
- * We're now onto the second pass. We allocate a Node for each task
- * processed (we actually use our ListType structure, which is a
- * superset of a Node), and enough memory to fit taskLength characters
- * which is where our complete task name and priority (two columns)
- * will be put. We use a Remember structure since that's the easiest
- * way of keeping track of all these small memory allocations, and
- * freeing them later on.
- */
- for (i = 0; i < taskCount && !error; i++)
- {
- if ((taskNode = AllocRemember(memoryKey, sizeof(struct ListType), MEMF_ANY))
- && (taskNode -> mainNode.ln_Name = AllocRemember(memoryKey, taskLength + 1, MEMF_ANY)))
- {
- /*
- * Here we make a copy of the original pointer to the task
- * (so we can later kill it, change its priority, etc.), copy
- * its priority into the Node structure, fill in the neatly-
- * joined name and priority using another function, and finally
- * update its pointer in taskArray to point to the Node
- * structure, since that's what we'll be using in future.
- */
- taskNode -> mainTask = taskArray[i];
- taskNode -> mainNode.ln_Pri = taskArray[i] -> tc_Node.ln_Pri;
- CreateString(taskArray[i], taskNode -> mainNode.ln_Name);
- taskArray[i] = (struct Task *)taskNode;
- }
- else
- {
- /*
- * We ran out of memory trying to allocate memory for a single
- * Node structure. Panic!!
- */
- error = TASK_ERROR;
- FreeRemember(memoryKey, TRUE);
- }
- }
-
- /*
- * We need nothing more from Exec's goldmine of information, so
- * allow things to continue normally and hope that the machine was
- * not locked up for a noticeable period of time! After that, we only
- * continue if the second pass went okay.
- */
- Permit();
-
- if (!error)
- {
- /*
- * The third pass involves creating a List structure, suitable for
- * adding to the ListView. Into that structure we sort all the Node
- * structures created above. The first thing to do is get a clean
- * List...
- */
- taskList.lh_Head = (struct Node *) &(taskList.lh_Tail);
- taskList.lh_Tail = NULL;
- taskList.lh_TailPred = (struct Node *) &(taskList.lh_Head);
-
- /*
- * Now we go through all the entries in taskArray, adding them to
- * this List structure in alphabetical order. For each entry, we go
- * around in a loop as long as there are more tasks to compare
- * against in the list and the current task in the list is
- * alphabetically earlier than the one we're working on now. We use
- * a special version of strcmp() which is case-insensitive and
- * skips over leading brackets. Unfortunately, it doesn't sort CLI
- * tasks properly (10 will come before 2) - sorry!
- */
- for (i = 0; i < taskCount; i++)
- {
- for (execNode = taskList.lh_Head;
- (execNode -> ln_Succ) &&
- CompareTasks(execNode -> ln_Name, ((struct ListType *)taskArray[i]) -> mainNode.ln_Name) < 0;
- execNode = execNode -> ln_Succ)
- ; /* empty body */
-
- /*
- * Once the loop has ended, we have just passed the position
- * where we want to insert our task.
- */
- Insert(&taskList, (struct Node *)(taskArray[i]), execNode -> ln_Pred);
- }
-
- /*
- * If there was a task already selected, we want to find it in the
- * new ListView, and reselect it. Recall that current points to the
- * selected ListView entry, currentTask points to the task
- * structure, and pos is the ordinal number of the selection. If no
- * task has been selected, current is NULL, pos is -1, and
- * currentTask is undefined.
- */
- if (current)
- for (execNode = taskList.lh_Head, current = NULL, pos = 0;
- execNode -> ln_Succ;
- execNode = execNode -> ln_Succ, pos++)
- if (((struct ListType *)execNode) -> mainTask == currentTask)
- {
- current = execNode;
- break;
- }
-
- /*
- * If current is still NULL down here, it means there was
- * either no task selected before, or else the one selected could
- * no longer be found. Otherwise, we still have a selected task,
- * and need to update the slider gadget and menu items, just in
- * case its priority has changed in the meantime.
- */
- if (current)
- OnTask();
- else
- OffTask();
-
- /*
- * We need to move the currently-selected entry into view. We
- * use the GTLV_Top tag for starters, since we'll always have a
- * reasonable value for that.
- */
- GT_SetGadgetAttrs(listGad, mainWindow, NULL,
- GTLV_Labels, &taskList,
- GTLV_Selected, pos,
- GTLV_Top, top,
- TAG_END);
-
- /*
- * If there is a task selected, we also use the GTLV_MakeVisible
- * tag (which only works under 3.x) to try even harder to restore
- * the ListView to its original position. We need to do this in a
- * separate step to the first call above, since the second tag
- * completely overrides the first if they are used together.
- */
- if (current)
- GT_SetGadgetAttrs(listGad, mainWindow, NULL,
- GTLV_MakeVisible, pos,
- TAG_END);
-
- /*
- * Now we invalidate "top", so we'll know whether or not to fill it
- * in at the start of this function the next time round.
- */
- top = -1;
-
- /*
- * Here we update PriMan's title bar to reflect the number of tasks
- * listed.
- */
- sprintf(title, "PriMan - %ld tasks", taskCount);
- SetWindowTitles(mainWindow, title, (UBYTE *)~0);
-
- /*
- * If necessary, we need to disable the slider, break and kill
- * gadgets, and associated menu items.
- */
- GT_SetGadgetAttrs(sliderGad, mainWindow, NULL,
- GA_Disabled, pos == -1,
- TAG_END);
- GT_SetGadgetAttrs(breakGad, mainWindow, NULL,
- GA_Disabled, pos == -1,
- TAG_END);
- GT_SetGadgetAttrs(killGad, mainWindow, NULL,
- GA_Disabled, pos == -1,
- TAG_END);
-
- /*
- * We allow the situation where there were more tasks than our
- * hard-coded maximum. Since this isn't the user's fault (he
- * didn't run out of memory; we're just being lazy!), it's probably
- * polite to let him know that the list will be incomplete.
- */
- if (taskCount == MaxTasks)
- SimpleRequest(&task, NULL);
- }
- }
-
-
- /*
- * Given a Task structure, extract the name and priority, then join them
- * together to fit exactly in taskLength characters.
- *
- * It is possible that the task is actually a CLI process, in which case
- * we need to add "CLI #x" before it.
- *
- * If the task is frozen, the portion of its name that is visible must be
- * bracketed. Our task (excuse the pun) is made easier since we know that
- * there is always enough space in the ListView for at least one letter of
- * the task name.
- *
- * There must be at least length+1 bytes free in dest, because of the \0
- * character.
- */
- void CreateString(struct Task *task, char *dest)
- {
- int taskChars, /* max number of chars of the task name we can use */
- length, /* length of task name */
- i, j; /* index into task name */
-
- LONG cli; /* task's CLI process number */
-
- BOOL frozen; /* task is frozen */
-
- char digits[5], /* enough to hold "-128" and \0 char */
- cliText[11], /* enough to hold "CLI #999: " and \0 char */
- *name; /* pointer to task name */
-
- APTR bstr; /* BCPL structs are used if task is a CLI process */
-
- /*
- * The first thing we'll do is convert the task priority into a
- * sequence of characters. This will allow us to see exactly how many
- * letters in the task name we can fit. Recall that sprintf() returns
- * the number of characters it processes. We also allow room for a
- * space character between the name and priority.
- */
- sprintf(digits, "%ld", task -> tc_Node.ln_Pri);
- taskChars = taskLength - strlen(digits) - 1;
-
- /*
- * If the task was frozen, we want to bracket its name. Here we insert
- * the opening bracket, set a flag to remind us to close it again, and
- * then update taskChars if necessary to allow for the brackets.
- */
- if (Frozen(task))
- {
- (*dest++) = '(';
- frozen = TRUE;
- taskChars -= 2;
- }
- else
- frozen = FALSE;
-
- /*
- * Now we obtain a pointer to the task name and get its length, in
- * preparation for copying it. If the task is a process and has a CLI
- * attached, we fill in the cliText variable and use that first when
- * copying.
- */
- if (((task -> tc_Node.ln_Type) == NT_PROCESS) &&
- (cli = ((struct Process *)task) -> pr_TaskNum))
- {
- sprintf(cliText, "CLI #%ld: ", cli);
- /*
- * This next bit is hairy, thanks to BCPL. The CLI name is
- * actually a BCPL string, i.e. it has the length in its
- * first byte, and doesn't contain a string terminator. So
- * we need to walk through some BCPL structures to find the
- * CLI name, and then extract its length from that.
- */
- bstr = BADDR(((struct CommandLineInterface *)
- (BADDR(((struct Process *)task) -> pr_CLI))) -> cli_CommandName);
- name = (char *)(bstr) + 1;
- length = *((BYTE *)bstr);
- }
- else
- {
- /*
- * Tasks without a CLI structure have it much easier! We just need
- * to remember to add a \0 character to the start of cliText so we
- * don't try copying it later.
- */
- name = task -> tc_Node.ln_Name;
- length = strlen(name);
- cliText[0] = '\0';
- }
-
- /*
- * Copying the task name involves a character-by-character copy of
- * both the "CLI #x" text if applicable, and the task name. The loop
- * ends when:
- *
- * - We run out of space in dest (taskChars reaches 0), or;
- *
- * - We have finished copying both the CLI text (character at current
- * position is \0), and the task name (length reaches 0).
- */
- i = j = 0;
- while (taskChars-- && (cliText[i] || length))
- if (cliText[i])
- *(dest++) = cliText[i++];
- else
- {
- *(dest++) = name[j++];
- length--; /* only decrement this if we've moved onto the task name! */
- }
-
- /*
- * We mustn't forget to close our brackets if the task was frozen.
- */
- if (frozen)
- *(dest++) = ')';
-
- /*
- * At this point, we might have finished copying the task name, but we
- * still need extra spacing characters. We'll add 2 to taskChars - one
- * extra obligatory space (accounted for at the start of the function),
- * and one to counter the effect of it reaching -1 at the end of the
- * previous loop (instead of 0).
- */
- taskChars += 2;
- while (taskChars--)
- *(dest++) = ' ';
-
- /*
- * Adding the priority is easy, since we know we're at the exact right
- * position for it now. A \0 char will get added on automatically here.
- */
- strcpy(dest, digits);
- }
-