Menus and Dialog Boxes: 4.5 Supplemental Usage: Thread Blocking Routines

Up: GEOS SDK TechDocs | Up | Prev: 4.4 Managing Input | Next: 5 Interaction Commands

Occasionally, you may need a response from the user before continuing with a thread of execution. In these cases, you should use a dialog box to prompt the user for the needed response. However, you also need a means to block the thread of execution until the user responds to this dialog box. The routines UserDoDialog() , UserStandardDialog() , and UserStandardDialogOptr() provide this functionality.

UserDoDialog()

UserDoDialog(), UserCreateDialog(), UserDestroyDialog()

You may bring dialog boxes on-screen with several routines. The most common and easiest to use of these routines is UserDoDialog() . UserDoDialog() only operates on GIV_DIALOG Interactions set both GIA_MODAL and GIA_INITIATED_WITH_USER_DO_DIALOG.

This routine, when passed the optr of a dialog box, will bring the dialog Interaction on-screen. In addition to bringing up a dialog, however, UserDoDialog() will also block the calling thread until a response trigger in the dialog is activated by the user. When this happens, UserDoDialog() returns a value representing the response trigger selected. This return value is usually an InteractionCommand .

The dialog may contain any UI gadgetry but must have response triggers with valid InteractionCommand s to terminate the dialog box. These triggers should have a null output and message and have ATTR_GEN_TRIGGER_INTERACTION_COMMAND vardata set to the proper InteractionCommand s. (See the GenTrigger chapter.) This InteractionCommand will be the response value returned by UserDoDialog() when that trigger is activated. This can be one of the predefined InteractionCommand s or an application-defined one with IC_CUSTOM_START.

The response triggers should also have the attribute GA_SIGNAL_INTERACTION_COMPLETE set to ensure that the dialog will be dismissed when they are activated. (This may be omitted to gain manual control over dismissal over the dialog, but you still must provide a way to dismiss the dialog.) Any response triggers in the dialog should have the hint HINT_SEEK_REPLY_BAR to place the triggers within the dialog's reply bar, but this is not necessary.

Because the calling thread is blocked by UserDoDialog() , views run by that thread will not be updated when exposed.

Code Display 7-18 Using UserDoDialog()

/* This dialog box asks for confirmation before beginning a delete file operation.
 * Therefore, it is advisable to block threads before beginning this operation. The
 * dialog using UserDoDialog() should be marked both GIA_MODAL and
 * GIA_INITIATED_VIA_USER_DO_DIALOG. */
@object GenInteractionClass ConfirmDeleteBox = {
    GI_comp = @ConfirmDeleteText;
    GII_type = GIT_AFFIRMATION;
    GII_visibility = GIV_DIALOG;
    GII_attrs = @default | GIA_INITIATED_VIA_USER_DO_DIALOG | GIA_MODAL;
}
@object GenTextClass ConfirmDeleteText = {
    GTI_text = "Are you sure you want to delete this file?";
}
/* This dialog box is displayed through a normal routine call with
 * the optr of the dialog box as its one argument. */
/* Check for positive response. */
if (UserDoDialog(@ConfirmDeleteBox) == IC_YES) {
    /* delete file. */
}

UserDoDialog() may also return IC_NULL to indicate that the modal dialog has been dismissed by the system, so it is always a good idea to check for and act on positive responses even if only one response is possible (such as in a GIT_NOTIFICATION dialog box).

UserCreateDialog() duplicates a dialog box to initiate later with UserDoDialog() . Typically, the dialog box duplicated is within a template object block; the dialog box must be both not GS_USABLE and not attached to the generic tree when created. The dialog box must also be marked GIA_INITIATED_VIA_USER_DO_DIALOG.

The template block that contains the dialog box and its children must be sharable and read-only. UserCreateDialog() duplicates a template dialog box, attaches the dialog box to the GenApplication object and sets it fully GS_USABLE; it may then be called with UserDoDialog() . When you no longer have a need for the dialog box, send it UserDestroyDialog() .

These routines are useful for conserving memory space; they only take up space when actually being used. In some cases, you may need to use these routines. For example, within libraries, dialog boxes must be duplicated before being used because multiple applications may require their own copy of the dialog box template.

Code Display 7-19 Using UserCreateDialog(), UserDestroyDialog()

/* 
 * The template dialog box must not be GS_USABLE. The object must also be marked 
 * GIA_INITIATED_VIA_USER_DO_DIALOG. The block must be sharable, read-only, and 
 * the top GenInteraction must not be linked into the generic tree.
 */
@object GenInteractionClass MyDialogTemplate = {
    GI_visMoniker = "Template";
    GI_states = @default & ~GS_USABLE;
    GII_visibility = GIV_DIALOG;
    GII_attrs = @default | GIA_INITIATED_VIA_USER_DO_DIALOG | 
	GIA_NOT_USER_INITIATABLE | GIA_MODAL;
    GII_type = GIT_NOTIFICATION;
    GI_comp = @NotificationGlyph;
}
@method SomeProcessClass, MSG_BRING_UP_DUPLICATED_DIALOG
{
    optr		newDialog;
    newDialog = UserCreateDialog(@MyDialogTemplate);
    if (UserDoDialog(@newDialog) == IC_OK) {
	/*** code ***/
    }
    UserDestroyDialog(@newDialog);
}

UserStandardDialog()

UserStandardDialog(), UserStandardDialogOptr(), CustomDialogBoxFlags

UserStandardDialog() displays standardized dialog boxes. The dialog is standardized in that it has a text area, an icon glyph representing the type of situation that caused the dialog to be displayed, and one or more response triggers. Like UserDoDialog() , UserStandardDialog() blocks the calling thread until the user activates one of the response triggers. Unlike UserDoDialog() , however, UserStandardDialog() does not need an application-defined dialog box. UserStandardDialog() builds a dialog box at run-time following the specifications passed.

UserStandardDialog() passes a number of parameters:

CDBF_SYSTEM_MODAL indicates that the dialog box brought up by UserDoDialog() should not only be application modal but also system modal.
CDBF_DESTRUCTIVE_ACTION indicates that an affirmative response by the user to the dialog box denotes a destructive action, and thus should not be made the default.
CDBF_DIALOG_TYPE indicates the type of situation creating the dialog box. This type determines the icon glyph that represents what caused the dialog to be displayed. The available types ( CustomDialogType ) are:
CDT_QUESTION: Ask the user a question;
CDT_WARNING: Warn the user of a potential problem;
CDT_NOTIFICATION: Notify the user of some event;
CDT_ERROR: Report an error to the user.
The Specific UI will determine the appropriate icon glyph to use for each dialog type. For example, in OSF/Motif, a CDT_QUESTION icon glyph is a graphic question mark.
The system will also issue a beep when a CDT_ERROR dialog is displayed.
CDBF_INTERACTION_TYPE indicates the type of GenInteraction being initiated. This type specifies what response triggers should be built and is a sub-set of the supplied GenInteractionType enums. The available types are:
GIT_NOTIFICATION
The specific UI will supply a standard response trigger that has the IC_OK response value.
GIT_AFFIRMATION
The specific UI will supply standard response triggers that have the IC_YES and IC_NO response values.
GIT_MULTIPLE_RESPONSE
The application must provide its own trigger monikers and response values. If this value is set, you will have to pass the array of custom triggers.

Code Display 7-20 Using UserStandardDialog()

/* 
 * This simple example uses no help context, custom triggers, or string arguments. 
 */
if ((UserStandardDialog(			(char *)0,
			(char *)0,
			(char *)0,
			(char *)0,
			"Do you wish to continue?",
			((CDT_QUESTION << CDBF_DIALOG_TYPE_OFFSET) |
			(GIT_AFFIRMATION << CDBF_INTERACTION_TYPE_OFFSET))
			) == IC_YES)) {
	/* code to perform on a positive response. */
    }
else {
	/* code to perform on a negative response. */
    }

You may also use UserStandardDialogOptr() for cases in which the strings are referenced through optrs rather than pointers.

Code Display 7-21 A ConfirmDeleteBox with explicit monikers

/* For this case, since we want to provide explicit monikers, we must use the
 * GIT_MULTIPLE_RESPONSE interaction type. Using this allows us to pass in the
 * monikers and response values for the response triggers for the dialog. This is
 * done by passing a pointer to a table consisting of the number of triggers in the
 * dialog and a StandardDialogResponseTriggerEntry for each trigger. Each entry
 * contains an optr of the moniker to use and the response value for the trigger.
 * The moniker may be simple text or a graphics string. The response value may be
 * one of the predefined InteractionCommands or an application-defined value based
 * on IC_CUSTOM_START. */
@visMoniker ConfirmYesMoniker = "Delete this file";
@visMoniker ConfirmNoMoniker = "Skip this file";
/* Create a table to hold the trigger data. */
static const StandardDialog2ResponseTriggerTable confirmResponseTable [] = {
    2,				/* SD2RTT_numTriggers */
	/* WRT_trigger1 */
    {ConfirmYesMoniker,				/* SDRTE_moniker */
	IC_YES}, 			/* SDRTE_responseValue */
	/* WRT_trigger2 */
    {ConfirmNoMoniker,				/* SDRTE_moniker */
	IC_NO}			/* SDRTE_responseValue */
};
/* Display the dialog with UserStandardDialog(). */
if (UserStandardDialog(			(char *)0,
			(char *)&confirmResponseTable,
			(char *)0,
			(char *)0,
			"Are you sure you want to delete this file?",
			((CDT_QUESTION << CDBF_DIALOG_TYPE_OFFSET) |
			/* interaction type - application supplied trigger */
			(GIT_MULTIPLE_RESPONSE << CBDF_INTERACTION_TYPE_OFFSET)))
		== IC_YES) {
	/* delete file */
}

Code Display 7-22 A IC_CUSTOM_START Interaction

#define SAVE_CHANGES				IC_CUSTOM_START+0
#define ABORT_CHANGES				IC_CUSTOM_START+1
#define CANCEL_CLOSE				IC_CUSTOM_START+2
@visMoniker CloseSaveMoniker = "Save Changes";
@visMoniker CloseAbortMoniker = "Abort Changes":
@visMoniker CloseCancelMoniker = "Cancel Close";
static const StandardDialog3ResponseTriggerTable closeResponseTable [] = {
     3, 					/* SD3RTT_numTriggers */
	/* WRT_trigger1 */
    {CloseSaveMoniker,					/* SDRTE_moniker */
    IC_YES},					/* SDRTE_responseValue */
	/* WRT_trigger2 */
    {CloseAbortMoniker,					/* SDRTE_moniker */
    IC_YES},					/* SDRTE_responseValue */
	/* WRT_trigger3 */
    {CloseCancelMoniker,					/* SDRTE_moniker */
    IC_NO}					/* SDRTE_responseValue */
};
closeWithChangesResponse = 
	(UserStandardDialog(
		(char *)0,
		(char *)&closeResponseTable,
		(char *)0,
		(char *)0,
		((CDT_QUESTION << CDBF_DIALOG_TYPE_OFFSET) |
		/* interaction type - application supplied triggers */
		(GIT_MULTIPLE_RESPONSE << CDBF_INTERACTION_TYPE_OFFSET)),
		(char *)0);
switch (closeWithChangesResponse) {
    case SAVE_CHANGES:
	/* save changes */
    case ABORT_CHANGES:
	/* abort changes */
    case IC_CANCEL_CLOSE:
	/* cancel close */
    case IC_NULL:
	/* IC_NULL is always a potential response */
}

Up: GEOS SDK TechDocs | Up | Prev: 4.4 Managing Input | Next: 5 Interaction Commands