#ifndef sun #else /* @(#)guiSubr.c 1.10 11/12/92 * Author: Roger A. Cole * Date: 02-08-91 * * Experimental Physics and Industrial Control System (EPICS) * * Copyright 1991-92, the Regents of the University of California, * and the University of Chicago Board of Governors. * * This software was produced under U.S. Government contracts: * (W-7405-ENG-36) at the Los Alamos National Laboratory, * and (W-31-109-ENG-38) at Argonne National Laboratory. * * Initial development by: * The Controls and Automation Group (AT-8) * Ground Test Accelerator * Accelerator Technology Division * Los Alamos National Laboratory * * Co-developed with * The Controls and Computing Group * Accelerator Systems Division * Advanced Photon Source * Argonne National Laboratory * * Modification Log: * ----------------- * .00 02-08-91 rac initial version * .01 07-30-91 rac installed in SCCS * .02 08-14-91 rac add guiNoticeName; add more documentation * .03 09-06-91 rac add GuiCheckbox..., guiGetNameFromSeln * .04 10-23-91 rac allow window manager to position command * frames; add file selector routine; add * guiInit, guiFileSelect, guiShellCmd; add * guiTextswXxx; don't specify position for * frames * .05 02-25-92 rac add a text editor command frame; guiInit * now gets host name and user name; add a * printer command frame and print routine; * add "puts" for text subwindows * .06 03-15-92 rac add guiLock as a locking mechanism * .07 03-23-92 rac add guiTimer; fix guiEditorCreate for sane behavior; * add guiXxxPrintf routines; assume make for XVIEW; * add guiCanvas; rearrange guiEditor panel and add * a status message; add guiCFshow and guiCFshowPin; * change guiCFShow so that it will expose hidden * command frames (this requires OpenWindows Version 3); * for guiGetNameFromSeln, require that selection be * in caller's window; * .08 08-26-92 rac fix a bug in guiEditorUpdateSet; * .09 09-30-92 rac allow a bigger buffer for browser; change extension * on edit lock file * */ #if 0 /* allow embedding comments in the header below */ /*+/mod*********************************************************************** * TITLE guiSubr.c - general gui routines for xview * * DESCRIPTION * These routines comprise an initial attempt to provide gui capabilities * in a generic way. At present, the routines are heavily xview * oriented. The routines will probably evolve, especially with * regard to xview item typedef usage (e.g., Panel, Xv_opaque, etc.). * * For more information, see USAGE, below. * * QUICK REFERENCE * #include * * Textsw guiBrowser(parent, panel, nCol, nLines, fileName) * Panel_item guiButton(label, panel, <>pX, pY, <>pHt, proc, menu, * key1, val1, key2, val2) * void guiButtonCenter(button1, button2, panel) * Canvas guiCanvas(parentFrame, x, y, proc, >pBgColor, >pFgColor, * key1, val1, key2, val2) * void guiCFdismiss_xvo(item) * void guiCFshow(frame) * void guiCFshowPin(frame) * void guiCFshow_mi(menu, menuItem) * void guiCFshow_xvo(item) * void guiCFshowPin_mi(menu, menuItem) * void guiCFshowPin_xvo(item) * Panel_item guiCheckbox(label, panel, nItems, <>pX, pY, <>pHt, proc, * key1, val1, key2, val2) * void guiCheckboxItem(label,checkbox,itemNum,dfltFlag,<>pX,pY,<>pHt) * Panel_item guiChoice(label, item1, item2, ..., NULL, panel, excl, nRow, nCol, * <>pX, pY, <>pHt, proc, key1, val1, key2, val2) * GUI_EDIT *guiEditor(pGuiCtx, title, dirName, fileName, pPrtCtx, * addExtrasFn, addExtrasArg) * void addExtrasFn(pGuiCtx, pEdit, panel, pX,pY,pHt, addExtrasArg) * char *guiEditorGets(pEditor, pBuf, dim, <>pCharPos) * void guiEditorLoadFile(pEditor, dirName, fileName) * void guiEditorNewEntry_pb(item) * void guiEditorPrintf(pEditor, fmt, ...) * int guiEditorPuts(pEditor, pBuf, <>pCharPos) * void guiEditorReset(pEditor) * void guiEditorShowCF(pEditor) * void guiEditorShowCF_mi(menu, menuItem) * void guiEditorShowCF_xvo(item) * void guiEditorStatusPrintf(pEditor, fmt, ...) * char *guiFileSelect(pGuiCtx, title, dir, file, dim, callbackFn, pArg) * void callbackFn(pArg, newPath, newDir, newFileName); * Frame guiFrame(label, x, y, width, height, >ppDisp, >pServer) * Frame guiFrameCmd(label, parentFrame, pPanel, resizeProc) * char *guiGetNameFromSeln(pGuiCtx, textSw, headFlag, tailFlag) * char *guiGetSelnInTextsw(pGuiCtx, textSw) * Icon guiIconCreate(frame, iconBits) * Panel guiInit(pGuiCtx, pArgc, argv, label, x, y, width, height) * int guiLock(pGuiCtx, text, lockPath, flag) * flag is 0,1 to reset/set the lock * Menu guiMenu(proc, key1, val1, key2, val2) * Menu_item guiMenuItem(label, menu, proc, inact, dflt, * key1, val1, key2, val2) * Panel_item guiMessage(label, panel, <>pX, pY, <>pHt) * void guiMessagePrintf(Panel_item, fmt, ...) * void guiNotice(pGuiCtx, msg) * void guiNoticeFile(pGuiCtx, msg, fName) * void guiNoticeName(pGuiCtx, msg, name) * void guiNoticePrintf(pGuiCtx, fmt, ...) * GUI_PRT *guiPrinter(pGuiCtx, parentFrame, title, useEnscript) * void guiPrinterShowCF_mi(menu, menuItem) * void guiPrinterShowCF_xvo(Xv_opaque) * void guiPrintFile(pPrtCtx, path) * void guiPrintGetCmd(pPrtCtx, path, commandBuf) * void guiShellCmd(pGuiCtx, cmdBuf, clientNum, callbackFn, callbackArg) * void callbackFn(callbackArg, resultBuf) * Panel_item guiTextField(label, panel, <>pX, pY, <>pHt, proc, nStr, nDsp, * key1, val1, key2, val2) * void guiTextFieldPrintf(Panel_item, fmt, ...) * char *guiTextswGets(textsw, pBuf, dim, <>pCharPos) * void guiTextswPrintf(textsw, fmt, ...) * int guiTextswPuts(textsw, pBuf, <>pCharPos) * void guiTextswReset(textsw) * void guiTimer(seconds, callbackFn, callbackArg) * * NOTES * 1. Many guiXxx routines have <>pX,pY,<>pHt as arguments. pX,pY specifies * the desired position, in pixels, of the item within the panel. pX * is modified to be a suitable x position for an item following on * the same line. pHt is modified to be the height, in pixels, of the * item, if its height exceeds the present value of pHt. * * BUGS * o although they provide some isolation, these routines are still heavily * XView specific * o there is no "signal handler" routine to allow trapping a window * manager forced exit * * USAGE * In the synopsis for each routine, the `pGuiCtx' is intended to be * &guiContext, (or whatever name is chosen for the GUI_CTX in the * program). * * EXAMPLE PROGRAM * This example shows some of the features of these routines. It * produces a program which can be used as a computerized logbook. * In addition to an editor and a "directory lister", the program * has a button which starts a new logbook entry with time, date, * and user name. * * This example assumes that the icon editor has been used to make * an icon for the program. * * #include * #include * #include * #include * #include * #include * * /*-------------------------------------------------------------------------- * * This is a "context" structure for the program. It is used to * * organize information about the gui operations. * *-------------------------------------------------------------------------*/ * typedef struct { * GUI_CTX guiCtx; /* context block for the gui routines */ * GUI_EDIT *pEditor; /* context block for the guiEditor */ * GUI_PRT *pPrt; /* context block for the guiPrinter */ * } TEST_CTX; * * /*-------------------------------------------------------------------------- * * Some identifiers for XV_KEY_DATA arguments are usually needed. * * The "user" identifiers can start at values of 100 and above. * *-------------------------------------------------------------------------*/ * typedef enum { * PCTX=100, /* TEST context */ * PCMD, /* TEST shell command string */ * } TEST_XV_KEY_DATA; * * void edit_pb(); * void quit_pb(); * void extra(); * * /*-------------------------------------------------------------------------- * * The main program * *-------------------------------------------------------------------------*/ * main(argc, argv) * int argc; * char *argv[]; * { * TEST_CTX testCtx; * static short icon_bits[]={ * #include "guiTest.icon" /* this file was created with the icon editor */ * }; * Panel panel; * int y=5, x=5, ht=0; * * panel = guiInit(&testCtx.guiCtx, * &argc, argv, "gui test program", 100, 100, 0,0); * guiIconCreate(testCtx.guiCtx.baseFrame, icon_bits); * * testCtx.pEditor = NULL; * testCtx.pPrt = guiPrinter(&testCtx.guiCtx, * testCtx.guiCtx.baseFrame, "test: printer setup", 1); * * guiButton("Edit", panel, &x,&y,&ht, edit_pb, NULL, PCTX,&testCtx,0,NULL); * guiButton("Quit", panel, &x,&y,&ht, quit_pb, NULL, PCTX,&testCtx,0,NULL); * * window_fit(panel); * window_fit(testCtx.guiCtx.baseFrame); * xv_main_loop(testCtx.guiCtx.baseFrame); * printf("exiting\n"); * return 0; * } * * /*-------------------------------------------------------------------------- * * subroutine to handle the "Edit" button. This routine asks guiEditor * * to call the extra() function below to add a "New entry" button to * * the editor panel. * * * * Common practice is to use suffixes on subroutine names when they * * are called as a result of activating various gui items. This allows * * signifying what sort of arguments are needed. * * _pb indicates a routine called from a panel button * * void subr_pb(item) * * Panel_item item; * * { * * program statements * * } * * _mi indicates a routine called from a menu item * * void subr_mi(menu, item) * * Menu menu; * * Menu_item item; * * { * * program statements * * } * * _xvo indicates a generic "one argument" callback routine * * void subr_xvo(item) * * Xv_opaque item; * * { * * program statements * * } * *-------------------------------------------------------------------------*/ * static void edit_pb(item) * Panel_item item; * { TEST_CTX *pCtx=(TEST_CTX *)xv_get(item, XV_KEY_DATA, PCTX); * if (pCtx->pEditor == NULL) { * pCtx->pEditor = guiEditor(&pCtx->guiCtx, "test", * pCtx->guiCtx.pwd, NULL, pCtx->pPrt, extra, pCtx); * } * * guiEditorShowCF(pCtx->pEditor); * } * * void extra(pGuiCtx, pEditor, panel, pX,pY,pHt, pCtx) * GUI_CTX *pGuiCtx; * GUI_EDIT *pEditor; * Panel panel; * int *pX,*pY,*pHt; * TEST_CTX *pCtx; * { * *pX = 5; *pY += *pHt + 10; *pHt = 0; * guiButton("New entry", panel, pX,pY,pHt, guiEditorNewEntry_pb, NULL, * GUI_PCTX, pGuiCtx, GUI_PEDIT, pEditor); * } * * /*-------------------------------------------------------------------------- * * subroutine to handle the "Quit" button. This is where various * * cleanup activities would normally occur. * *-------------------------------------------------------------------------*/ * static void quit_pb(item) * Panel_item item; * { TEST_CTX *pCtx=(TEST_CTX *)xv_get(item, XV_KEY_DATA, PCTX); * * xv_destroy_safe(pCtx->guiCtx.baseFrame); * } * *-***************************************************************************/ #endif #include #include #include #include #include #include /* for use with notifier */ #include #include /* for use with notifier */ #include /* for use with notifier */ #define XVIEW #if defined XVIEW # include # include # include # include # include # include # include # include # include # include # include /* for */ #endif #include #include void guiShellCmd_work(); Notify_value guiCmdRead(), guiCmdSigchld(); static int callbackNum=-1; struct callbackStruct { Notify_client clientNum; void (*callbackFn)(); void *callbackArg; char result[GUI_TDIM]; int readDone; int sigChldDone; int pipe_io; }; static struct callbackStruct callback[100]; #if GUI_TEST typedef struct { GUI_CTX guiCtx; GUI_EDIT *pEditor; GUI_PRT *pPrt; } TEST_CTX; typedef enum { PCTX=100, /* TEST context */ PCMD, /* TEST shell command string */ } TEST_XV_KEY_DATA; void edit_pb(); void quit_pb(); void extra(); void testTime(); /*+/subr********************************************************************** * NAME main - test program * *-*/ main(argc, argv) int argc; char *argv[]; { TEST_CTX testCtx; static short icon_bits[]={ #include "guiTest.icon" }; Panel panel; Panel_item choice; int y=5, x=5, ht=0; int x1; panel = guiInit(&testCtx.guiCtx, &argc, argv, "gui test program", 100, 100, 0,0); guiIconCreate(testCtx.guiCtx.baseFrame, icon_bits); testCtx.pEditor = NULL; testCtx.pPrt = guiPrinter(&testCtx.guiCtx, testCtx.guiCtx.baseFrame, "test: printer setup", 1); guiButton("Edit", panel, &x,&y,&ht, edit_pb, NULL, PCTX,&testCtx,0,NULL); guiButton("Quit", panel, &x,&y,&ht, quit_pb, NULL, PCTX,&testCtx,0,NULL); y += 5 + ht; x = 5; ht = 0; choice = guiChoice("exclusive ", "abc", "def", "ghi", "jkl", "mno", NULL, panel, 1, 0, 2, &x,&y,&ht, NULL, 0,NULL,0,NULL); y += 5 + ht; x = 5; ht = 0; choice = guiChoice("non-exclusive", "abc", "def", "ghi", "jkl", "mno", NULL, panel, 0, 2, 0, &x,&y,&ht, NULL, 0,NULL,0,NULL); y += 5 + ht; x = 5; ht = 0; guiMessage("exclusive", panel, &x,&y,&ht); x1 = 150; choice = guiChoice("", "abc", "def", "ghi", "jkl", "mno", NULL, panel, 1, 0, 2, &x1,&y,&ht, NULL, 0,NULL,0,NULL); y += 5 + ht; x = 5; ht = 0; guiMessage("non-exclusive", panel, &x,&y,&ht); x1 = 150; choice = guiChoice("", "abc", "def", "ghi", "jkl", "mno", NULL, panel, 0, 2, 0, &x1,&y,&ht, NULL, 0,NULL,0,NULL); window_fit(panel); window_fit(testCtx.guiCtx.baseFrame); guiTimer(10., testTime, &testCtx); xv_main_loop(testCtx.guiCtx.baseFrame); printf("exiting\n"); return 0; } static void edit_pb(item) Panel_item item; { TEST_CTX *pCtx=(TEST_CTX *)xv_get(item, XV_KEY_DATA, PCTX); if (pCtx->pEditor == NULL) { pCtx->pEditor = guiEditor(&pCtx->guiCtx, "test", pCtx->guiCtx.pwd, "test", pCtx->pPrt, extra, pCtx); } guiEditorShowCF(pCtx->pEditor); } void extra(pGuiCtx, pEditor, panel, pX,pY,pHt, pCtx) GUI_CTX *pGuiCtx; GUI_EDIT *pEditor; Panel panel; int *pX,*pY,*pHt; TEST_CTX *pCtx; { *pX = 5; *pY += *pHt + 10; *pHt = 0; guiButton("New entry", panel, pX,pY,pHt, guiEditorNewEntry_pb, NULL, GUI_PCTX, pGuiCtx, GUI_PEDIT, pEditor); } static void quit_pb(item) Panel_item item; { TEST_CTX *pCtx=(TEST_CTX *)xv_get(item, XV_KEY_DATA, PCTX); xv_destroy_safe(pCtx->guiCtx.baseFrame); } void testTime(pCtx, dummy) TEST_CTX *pCtx; int dummy; { printf("timer %x\n", pCtx); } #endif /*+/internal****************************************************************** * NAME guiAbove - move a frame "above" in the stacking order * * BUGS * o this doesn't work under OpenWindows version 2; under version 3, * the function can actually be invoked. * *-*/ guiAbove(frame) Frame frame; { #if 0 XWindowChanges chg; Display *pDisp=(Display *)xv_get(frame, XV_DISPLAY); Window win=(Window)xv_get(frame, XV_XID); chg.stack_mode = TopIf; XConfigureWindow(pDisp, win, CWStackMode, &chg); #if 0 XRaiseWindow(pDisp, win); #endif #endif if ((int)xv_get(frame, XV_SHOW) == 0) xv_set(frame, XV_SHOW, TRUE, NULL); } /*+/subr********************************************************************** * NAME guiBrowser - create a browsing text subwindow * * DESCRIPTION * * RETURNS * * *-*/ Textsw guiBrowser(parentFrame, panel, nCol, nLines, fileName) Frame parentFrame; /* I parent of text subwindow */ Panel panel; /* I panel preceding textsw */ int nCol; /* I number of columns wide for text */ int nLines; /* I number of lines long for text */ char *fileName; /* I file to load, or NULL */ { Textsw textsw; textsw = (Textsw)xv_create(parentFrame, TEXTSW, XV_X, 0, WIN_BELOW, panel, WIN_COLUMNS, nCol, WIN_ROWS, nLines, TEXTSW_BROWSING, TRUE, TEXTSW_DISABLE_CD, TRUE, TEXTSW_DISABLE_LOAD, TRUE, TEXTSW_MEMORY_MAXIMUM, 200000, TEXTSW_FILE, fileName, NULL); if (textsw == NULL) { (void)printf("error creating browser text subwindow\n"); exit(1); } xv_set(textsw, WIN_WIDTH, WIN_EXTEND_TO_EDGE, NULL); return textsw; } /*+/subr********************************************************************** * NAME guiButton - create a button on a panel * * DESCRIPTION * * RETURNS * Panel_item handle * *-*/ Panel_item guiButton(label, panel, pX, pY, pHt, proc, menu, key1, val1, key2, val2) char *label; /* I label for button */ Panel panel; /* I handle of panel containing button */ int *pX; /* IO pointer to x position in panel, in pixels */ int *pY; /* I pointer to y position in panel, in pixels */ int *pHt; /* IO ptr to height used, in pixels, or NULL */ void (*proc)(); /* I pointer to procedure to handle button push */ Menu menu; /* I handle of button menu, or NULL */ enum key1; /* I key for context information for object */ void *val1; /* I value associated with key */ enum key2; /* I key for context information for object */ void *val2; /* I value associated with key */ { Panel_item button; int height; button = (Panel_item)xv_create(panel, PANEL_BUTTON, PANEL_LABEL_STRING, label, XV_X, *pX, XV_Y, *pY, NULL); if (button == NULL) { (void)printf("error creating \"%s\" button\n", label); exit(1); } if (proc != NULL) { if (xv_set(button, PANEL_NOTIFY_PROC, proc, NULL) != XV_OK) { (void)printf("error adding proc to \"%s\" button\n", label); exit(1); } } if (menu != NULL) { if (xv_set(button, PANEL_ITEM_MENU, menu, NULL) != XV_OK) { (void)printf("error adding menu to \"%s\" button\n", label); exit(1); } } if (key1 != 0) { if (xv_set(button, XV_KEY_DATA, key1, val1, NULL) != XV_OK) { (void)printf("error adding key1 to \"%s\" button\n", label); exit(1); } } if (key2 != 0) { if (xv_set(button, XV_KEY_DATA, key2, val2, NULL) != XV_OK) { (void)printf("error adding key2 to \"%s\" button\n", label); exit(1); } } *pX += (int)xv_get(button, XV_WIDTH) + 10; if (pHt != NULL) { height = xv_get(button, XV_HEIGHT); if (height > *pHt) *pHt = height; } return button; } /*+/subr********************************************************************** * NAME guiButtonCenter - center one or two buttons within a panel * * DESCRIPTION * * RETURNS * void * * EXAMPLE * Panel_item button1, button2; * * button1 = guiButton(... * button2 = guiButton(... * * window_fit(panel) * guiButtonCenter(button1, button2, panel); * *-*/ void guiButtonCenter(button1, button2, panel) Panel_item button1; /* I first button */ Panel_item button2; /* I second button, or NULL */ Panel panel; /* I panel containing button(s) */ { int width1, width2, x, panelWidth, y; panelWidth = (int)xv_get(panel, XV_WIDTH); width1 = (int)xv_get(button1, XV_WIDTH); y = (int)xv_get(button1, XV_Y); if (button2 != NULL) { width2 = (int)xv_get(button2, XV_WIDTH); if ((x = (panelWidth - width1 - width2 - 20) / 2) > 0) { xv_set(button1, XV_X, x, XV_Y, y, NULL); x += width1 + 20; xv_set(button2, XV_X, x, XV_Y, y, NULL); } } else if ((x = (panelWidth - width1) / 2) > 0) xv_set(button1, XV_X, x, XV_Y, y, NULL); } /*+/subr********************************************************************** * NAME guiCanvas - create a canvas within a frame * * DESCRIPTION * * RETURNS * Canvas handle * * EXAMPLE * Canvas canvas; * * canvas = guiCanvas(baseFrame, 0, 100, canvasEvent, NULL, NULL, * 0,NULL,0,NULL); * * void * canvasEvent(canvas, event) * Canvas canvas; * Event *event; * { * if (event_id(event) == WIN_REPAINT) { * repaint activity * } * else if (event_id(event) == MS_LEFT && event_is_up(event)) { * left mouse release activity * } * { *-*/ Canvas guiCanvas(parentFrame, x, y, proc, pBgColor, pFgColor, key1, val1, key2, val2) Frame parentFrame; /* I parent frame to contain canvas */ int x; /* I x position in frame, in pixels */ int y; /* I y position in frame, in pixels */ void (*proc)(); /* I pointer to procedure to handle resize & events */ unsigned long *pBgColor;/* O pointer to background pixel value, or NULL */ unsigned long *pFgColor;/* O pointer to foreground pixel value, or NULL */ enum key1; /* I key for context information for canvas */ void *val1; /* I value associated with key */ enum key2; /* I key for context information for canvas */ void *val2; /* I value associated with key */ { Canvas canvas; Xv_window paintWin; unsigned long *colors; canvas = (Canvas)xv_create(parentFrame, CANVAS, XV_X, x, XV_Y, y, CANVAS_X_PAINT_WINDOW, TRUE, CANVAS_FIXED_IMAGE, FALSE, WIN_RETAINED, FALSE, CANVAS_AUTO_CLEAR, TRUE, CANVAS_AUTO_SHRINK, TRUE, CANVAS_AUTO_EXPAND, TRUE, NULL); if (canvas == NULL) { (void)printf("error creating canvas\n"); exit(1); } paintWin = canvas_paint_window(canvas); if (xv_set(paintWin, WIN_COLLAPSE_EXPOSURES, TRUE, WIN_CONSUME_EVENTS, WIN_MOUSE_BUTTONS, WIN_REPAINT, NULL, NULL) != XV_OK) { (void)printf("error setting events for canvas\n"); exit(1); } if (proc != NULL) { if (xv_set(paintWin, WIN_EVENT_PROC, proc, NULL) != XV_OK) { (void)printf("error adding event procedure for canvas\n"); exit(1); } } if (key1 != 0) { if (xv_set(paintWin, XV_KEY_DATA, key1, val1, NULL) != XV_OK) { (void)printf("error adding key1 to canvas\n"); exit(1); } } if (key2 != 0) { if (xv_set(paintWin, XV_KEY_DATA, key2, val2, NULL) != XV_OK) { (void)printf("error adding key2 to canvas\n"); exit(1); } } colors = (unsigned long *)xv_get(paintWin, WIN_X_COLOR_INDICES); if (pBgColor != NULL) *pBgColor=colors[(unsigned long)xv_get(paintWin,WIN_BACKGROUND_COLOR)]; if (pFgColor != NULL) *pFgColor=colors[(unsigned long)xv_get(paintWin,WIN_FOREGROUND_COLOR)]; return canvas; } /*+/subr********************************************************************** * NAME guiCF - command frame dismiss and show routines * * DESCRIPTION * * RETURNS * * BUGS * o text * * SEE ALSO * guiFrameCmd * * EXAMPLES * guiButton("Dismiss", panel, ... * guiCFdismiss_xvo, NULL, GUI_CF, cmdFrame, 0, NULL); * * menu = guiMenu(..., GUI_PCTX, pGuiCtx...); * menuItem = guiMenuItem("label", menu, guiCFshow_mi, ..., * GUI_CF, frame...); * * guiButton("Show...", panel, ..., guiCFshow_xvo, ..., * GUI_PCTX, pGuiCtx, GUI_CF, frame); * * menu = guiMenu(..., GUI_PCTX, pGuiCtx...); * menuItem = guiMenuItem("label", menu, guiCFshowPin_mi, ..., * GUI_CF, frame...); * * guiButton("Show...", panel, ..., guiCFshowPin_xvo, ..., * GUI_PCTX, pGuiCtx, GUI_CF, frame); * *-*/ void guiCFdismiss_xvo(item) Xv_opaque item; { Frame frame=(Frame)xv_get(item, XV_KEY_DATA, GUI_CF); xv_set(frame, XV_SHOW, FALSE, FRAME_CMD_PUSHPIN_IN, FALSE, NULL); } void guiCFshow(frame) Frame frame; { if ((int)xv_get(frame, XV_SHOW) == TRUE) guiAbove(frame); else xv_set(frame, XV_SHOW, TRUE, NULL); } void guiCFshowPin(frame) Frame frame; { if ((int)xv_get(frame, XV_SHOW) == TRUE) guiAbove(frame); else xv_set(frame, XV_SHOW, TRUE, FRAME_CMD_PUSHPIN_IN, TRUE, NULL); } void guiCFshow_mi(menu, menuItem) Menu menu; Menu_item menuItem; { guiCFshow_xvo(menuItem); } void guiCFshow_xvo(item) Xv_opaque item; { GUI_CTX *pGuiCtx=(GUI_CTX *)xv_get(item, XV_KEY_DATA, GUI_PCTX); Frame frame=(Frame)xv_get(item, XV_KEY_DATA, GUI_CF); guiCFshow(frame); } void guiCFshowPin_mi(menu, menuItem) Menu menu; Menu_item menuItem; { guiCFshowPin_xvo(menuItem); } void guiCFshowPin_xvo(item) Xv_opaque item; { GUI_CTX *pGuiCtx=(GUI_CTX *)xv_get(item, XV_KEY_DATA, GUI_PCTX); Frame frame=(Frame)xv_get(item, XV_KEY_DATA, GUI_CF); guiCFshowPin(frame); } /*+/subr********************************************************************** * NAME guiCheckbox - create an empty checkbox list * * DESCRIPTION * Creates the framework for an empty checkbox selection list. The * actual checkbox items must be filled in by calls to * guiCheckboxItem. * * Checkbox lists have a fixed number of items--the number of items * can't be increased or decreased after the empty list is created. * Individual items on a list can be changed at any time, however. * * RETURNS * Panel_item for the checkbox * * BUGS * o list can't dynamically grow and shrink * o the maximum size for a checkbox list is 10 items * * SEE ALSO * guiCheckboxItem * * EXAMPLE * Set up a 3-item checkbox. Each of the first two items is to have * an associated status message. The appearance of the setup will * resemble the following: * * Retrieve from: * [] text file ________status message________ * [] binary file ________status message________ * [] Channel Access * * The third item will be the default. When any of the items are * selected, choose_xvo() is to be called; that routine uses a pointer * to a `myStruct' structure for its operations. * * struct myStruct { * Panel_item textStatus; status for text file * Panel_item binStatus; status for binary file * } context; *#define PCTX 101 (a unique integer for identifying myStruct) * Panel_item ckbx; * int x=5, y=5, ht=0; * int x1, x2, y1, y2; (for aligning buttons and status messages) * * ckbx = guiCheckbox("Retrieve from:", panel, 3, &x, &y, &ht, * choose_xvo, PCTX, &context, 0, NULL); * y += ht + 5; x = 5; ht = 0; * guiCheckboxItem("text file", ckbx, 0, 0, &x, &y, &ht); * x1 = x; y1 =y; * y += ht + 5; x = 5; ht = 0; * guiCheckboxItem("binary file", ckbx, 1, 0, &x, &y, &ht); * x2 = x; y2 =y; * y += ht + 5; x = 5; ht = 0; * guiCheckboxItem("Channel Access", ckbx, 2, 1, &x, &y, &ht); * y += ht + 5; x = 5; ht = 0; * if (x1 < x2) x1 = x2; (which extends further right?) * else x2 = x1; * context.textStatus = guiMessage("", panel, &x1, &y1, &ht); * context.binStatus = guiMessage("", panel, &x2, &y2, &ht); * *-*/ Panel_item guiCheckbox(label, panel, nItems, pX, pY, pHt, proc, key1, val1, key2, val2) char *label; /* I label for checkbox list */ Panel panel; /* I handle of panel containing checkbox list */ int nItems; /* I the number of items to be held by the list */ int *pX; /* IO pointer to x position in panel, in pixels */ int *pY; /* I pointer to y position in panel, in pixels */ int *pHt; /* IO ptr to height used by label, in pixels, or NULL */ void (*proc)(); /* I pointer to procedure to handle making a choice */ enum key1; /* I key for context information for object */ void *val1; /* I value associated with key */ enum key2; /* I key for context information for object */ void *val2; /* I value associated with key */ { Panel_item checkbox; int height; /*----------------------------------------------------------------------------- * NOTE: the kludgey way this is done is because XView in SunOS 4.1 can't * seem to handle defining the number of items except at compile time *----------------------------------------------------------------------------*/ #define GUI_CHK checkbox=xv_create(panel,PANEL_CHECK_BOX,PANEL_CHOICE_STRINGS, if (nItems == 1) GUI_CHK "", NULL,NULL); else if (nItems == 2) GUI_CHK "","", NULL,NULL); else if (nItems == 3) GUI_CHK "","","", NULL,NULL); else if (nItems == 4) GUI_CHK "","","","", NULL,NULL); else if (nItems == 5) GUI_CHK "","","","","", NULL,NULL); else if (nItems == 6) GUI_CHK "","","","","","", NULL,NULL); else if (nItems == 7) GUI_CHK "","","","","","","", NULL,NULL); else if (nItems == 8) GUI_CHK "","","","","","","","", NULL,NULL); else if (nItems == 9) GUI_CHK "","","","","","","","","", NULL,NULL); else if (nItems == 10) GUI_CHK "","","","","","","","","","", NULL,NULL); else { (void)printf("guiCheckbox can only handle up to 10 items\n"); exit(1); } if (checkbox == NULL) { (void)printf("error creating \"%s\"s checkbox list\n", label); exit(1); } xv_set(checkbox, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOOSE_ONE, TRUE, PANEL_CHOOSE_NONE, TRUE, NULL); xv_set(checkbox, PANEL_VALUE, -1, NULL); if (proc != NULL) { if (xv_set(checkbox, PANEL_NOTIFY_PROC, proc, NULL) != XV_OK) { (void)printf("error adding proc to \"%s\"s checkbox list\n", label); exit(1); } } if (key1 != 0) { if (xv_set(checkbox, XV_KEY_DATA, key1, val1, NULL) != XV_OK) { (void)printf("error adding key1 to \"%s\" checkbox list\n", label); exit(1); } } if (key2 != 0) { if (xv_set(checkbox, XV_KEY_DATA, key2, val2, NULL) != XV_OK) { (void)printf("error adding key2 to \"%s\" checkbox list\n", label); exit(1); } } guiMessage(label, panel, pX, pY, pHt); return checkbox; } /*+/subr********************************************************************** * NAME guiCheckboxItem - create an item in a checkbox list * * DESCRIPTION * Change one of the items in a checkbox list. This may be either * setting the item following the creation of the list with guiCheckbox, * or a subsequent change to an item. * * RETURNS * void * * SEE ALSO * guiCheckbox * *-*/ void guiCheckboxItem(label, checkbox, itemNum, dfltFlag, pX, pY, pHt) char *label; /* I label for item */ Panel_item checkbox; /* I handle of checkbox list */ int itemNum; /* I number (starting with 0) within checkbox list */ int dfltFlag; /* I if 1, then this item will be pre-selected */ int *pX; /* IO pointer to x position in panel, in pixels */ int *pY; /* I pointer to y position in panel, in pixels */ int *pHt; /* IO ptr to height used by label, in pixels, or NULL */ { Panel panel=(Panel)xv_get(checkbox, PANEL_PARENT_PANEL); xv_set(checkbox, PANEL_CHOICE_X, itemNum, *pX, PANEL_CHOICE_Y, itemNum, *pY-5, NULL); *pX += 40; *pHt = 20; guiMessage(label, panel, pX, pY, pHt); if (dfltFlag) xv_set(checkbox, PANEL_VALUE, itemNum, NULL); } #if 0 /*+/macros******************************************************************** * NAME guiChoice - set up a choice list * * SYNOPSIS * Panel_item * guiChoice(label, item1, item2, ..., NULL, panel, excl, nRow, nCol, * pX,pY,pHt, proc, key1, val1, key2, val2) * char *label; /* I label for choice list */ * char *item1; /* I label for first choice item */ * char *item2; /* I label for second choice item */ * ... * Panel panel; /* I handle of panel containing choice list */ * int excl; /* I 1 for exclusive choice list, else 0 */ * int nRow; /* I number of rows for organizing buttons */ * int nCol; /* I number of columns for organizing buttons */ * int *pX; /* IO pointer to x position in panel, in pixels */ * int *pY; /* I pointer to y position in panel, in pixels */ * int *pHt; /* IO ptr to height used by label, in pixels, or NULL */ * void (*proc)();/* I pointer to procedure to handle making a choice */ * enum key1; /* I key for context information for object */ * void *val1; /* I value associated with key */ * enum key2; /* I key for context information for object */ * void *val2; /* I value associated with key */ * *-*/ #endif Panel_item guiChoice(va_alist) va_dcl { va_list pArg; Panel_item item; int height, lastItem; char *label, *I[100]; Panel panel; int excl, nRow, nCol; int *pX; int *pY; int *pHt; void (*proc)(); int key1; void *val1; int key2; void *val2; typedef void FN(); int type, df; va_start(pArg); label = va_arg(pArg, char *); for (lastItem=0; lastItem<100; lastItem++) { I[lastItem] = va_arg(pArg, char *); if (I[lastItem] == NULL) break; } panel = va_arg(pArg, Panel); excl = va_arg(pArg, int); nRow = va_arg(pArg, int); nCol = va_arg(pArg, int); pX = va_arg(pArg, int *); pY = va_arg(pArg, int *); pHt = va_arg(pArg, int *); proc = va_arg(pArg, FN *); key1 = va_arg(pArg, int); val1 = va_arg(pArg, void *); key2 = va_arg(pArg, int); val2 = va_arg(pArg, void *); va_end(pArg); if (excl == 1) type = TRUE, df = 0; else type = FALSE, df = 1; #define Ps xv_create(panel,PANEL_CHOICE,PANEL_CHOOSE_ONE,type,\ PANEL_VALUE,df,PANEL_LABEL_STRING,label,PANEL_CHOICE_STRINGS, #define Pe , NULL, XV_X, *pX, XV_Y, *pY, NULL); break; switch (lastItem) { case 1: item = Ps I[0] Pe case 2: item = Ps I[0],I[1] Pe case 3: item = Ps I[0],I[1],I[2] Pe case 4: item = Ps I[0],I[1],I[2],I[3] Pe case 5: item = Ps I[0],I[1],I[2],I[3],I[4] Pe case 6: item = Ps I[0],I[1],I[2],I[3],I[4],I[5] Pe case 7: item = Ps I[0],I[1],I[2],I[3],I[4],I[5],I[6] Pe case 8: item = Ps I[0],I[1],I[2],I[3],I[4],I[5],I[6],I[7] Pe case 9: item = Ps I[0],I[1],I[2],I[3],I[4],I[5],I[6],I[7],I[8] Pe case 10: item = Ps I[0],I[1],I[2],I[3],I[4],I[5],I[6],I[7],I[8],I[9] Pe dflt: printf("can't handle more than 10 choices right now\n"); exit(1); } if (item == NULL) { (void)printf("error creating choice\n"); exit(1); } if (nRow > 0) xv_set(item, PANEL_CHOICE_NROWS, nRow, NULL); else if (nCol > 0) xv_set(item, PANEL_CHOICE_NCOLS, nCol, NULL); if (proc != NULL) { if (xv_set(item, PANEL_NOTIFY_PROC, proc, NULL) != XV_OK) { (void)printf("error adding proc to choice\n"); exit(1); } } if (key1 != 0) { if (xv_set(item, XV_KEY_DATA, key1, val1, NULL) != XV_OK) { (void)printf("error adding key1 to choice\n"); exit(1); } } if (key2 != 0) { if (xv_set(item, XV_KEY_DATA, key2, val2, NULL) != XV_OK) { (void)printf("error adding key2 to choice\n"); exit(1); } } *pX += (int)xv_get(item, XV_WIDTH); if (pHt != NULL) { height = xv_get(item, XV_HEIGHT); if (height > *pHt) *pHt = height; } return item; } void guiEditorCancelFile_mi(); void guiEditorCreateFile_mi(); char *guiEditorGetPath(); void guiEditorLoadFile_1(); void guiEditorLoadFile_mi(); void guiEditorPickFile_mi(); void guiEditorPick_callback(); void guiEditorPrintFile_mi(); void guiEditorSaveFile_mi(); void guiEditorUpdateSet(); void guiEditorUpdateRst(); void guiEditorUpdate_mi(); /*+/subr********************************************************************** * NAME guiEditor - create a text editor command frame * * DESCRIPTION * Creates a text editor command frame with amenities to support good * editing practice: * o allow specifying directory and file * o support easy access to a list of directory contents * o easy choice of file name from directory list * o "locking" of file under edit, with corresponding notification * to users who try to edit a locked file * o support for caller to add items to the text editor panel * o check for write permission before allowing editing * * If the caller specifies a file name, then that file will be loaded * automatically into the text subwindow. (If the file doesn't * exist, a notice will pop up.) * * If the caller specifies a function to be called to add items to * the editor panel, the function will be called as follows: * * void addExtrasFn(pGuiCtx, pEdit, panel, pX,pY,pHt, addExtrasArg) * * RETURNS * GUI_EDIT *, or * NULL * * BUGS * o doesn't allow printing "memory" copy of file, and insists that user * save the file if it has been modified * o doesn't provide a way to save updates if the program aborts * *-*/ GUI_EDIT * guiEditor(pGuiCtx, title, dir, file, pPrtCtx, addExtrasFn, arg) GUI_CTX *pGuiCtx; /* I pointer to gui context */ char *title; /* I text for command frame title bar */ char *dir; /* I directory of file to load, or NULL */ char *file; /* I file to load, or NULL */ GUI_PRT *pPrtCtx; /* I pointer to printer context, or NULL */ void (*addExtrasFn)();/* I pointer to function to add extra stuff to editor panel, or NULL*/ void *arg; /* I argument to pass to addExtrasFn */ { GUI_EDIT *pEdit; Panel panel; Menu menu; Textsw textsw; Panel_item ck; int y=5, x=5, ht=0, ht1; /*----------------------------------------------------------------------------- * Dir: [<]_____________________[>] File: [<]_______________[>] * File v Edit v status...... * load edit * save read-only * list dir... discard edits * create * print * printer setup... *----------------------------------------------------------------------------*/ if ((pEdit=(GUI_EDIT *)malloc(sizeof(GUI_EDIT))) == NULL) return NULL; bzero((char *)pEdit, sizeof(*pEdit)); pEdit->pGuiCtx = pGuiCtx; pEdit->pPrtCtx = pPrtCtx; pEdit->edit_CF = guiFrameCmd(title, pGuiCtx->baseFrame, &panel, NULL); pEdit->loaded = 0; pEdit->updFlag = 0; strcpy(pEdit->title, title); pEdit->dir_PT = guiTextField("Dir:", panel, &x,&y,&ht, NULL, GUI_TDIM-1, 40, 0, NULL, 0, NULL); pEdit->file_PT = guiTextField("File:", panel, &x,&y,&ht, NULL, GUI_TDIM-1, 20, 0, NULL, 0, NULL); if (dir == NULL) dir = pGuiCtx->pwd; xv_set(pEdit->dir_PT, PANEL_VALUE, dir, NULL); xv_set(pEdit->file_PT, PANEL_VALUE, file, NULL); y += ht + 5; x = 5; ht = 0; menu = guiMenu(NULL, 0, NULL, 0, NULL); guiMenuItem("Load", menu, guiEditorLoadFile_mi, 0, 1, GUI_PCTX, pGuiCtx, GUI_PEDIT, pEdit); guiMenuItem("Save", menu, guiEditorSaveFile_mi, 0, 0, GUI_PCTX, pGuiCtx, GUI_PEDIT, pEdit); guiMenuItem("List dir...", menu, guiEditorPickFile_mi, 0, 0, GUI_PCTX, pGuiCtx, GUI_PEDIT, pEdit); guiMenuItem("Create", menu, guiEditorCreateFile_mi, 0, 0, GUI_PCTX, pGuiCtx, GUI_PEDIT, pEdit); if (pPrtCtx != NULL) { guiMenuItem("Print file", menu, guiEditorPrintFile_mi, 0, 0, GUI_PEDIT, pEdit, GUI_PPRT, pEdit->pPrtCtx); guiMenuItem("Printer setup...", menu, guiPrinterShowCF_mi, 0, 0, GUI_PPRT, pEdit->pPrtCtx, 0, NULL); } guiButton("File", panel, &x, &y, &ht, NULL, menu, 0,NULL,0,NULL); menu = guiMenu(NULL, 0, NULL, 0, NULL); guiMenuItem("set edit mode", menu, guiEditorUpdate_mi, 0, 1, GUI_PEDIT, pEdit, GUI_INT, 1); guiMenuItem("set read-only mode", menu, guiEditorUpdate_mi, 0, 0, GUI_PEDIT, pEdit, GUI_INT, 0); guiMenuItem("discard edits", menu, guiEditorCancelFile_mi, 0, 0, GUI_PCTX, pGuiCtx, GUI_PEDIT, pEdit); guiButton("Edit", panel, &x, &y, &ht, NULL, menu, 0,NULL,0,NULL); pEdit->status_PM = guiMessage("", panel, &x, &y, &ht); y += ht + 5; x = 5; ht = 0; if (addExtrasFn != NULL) addExtrasFn(pGuiCtx, pEdit, panel, &x,&y,&ht, arg); y += ht + 5; x = 5; ht = 0; window_fit(panel); xv_set(panel, WIN_WIDTH, WIN_EXTEND_TO_EDGE, NULL); pEdit->text_TSW = (Textsw)xv_create(pEdit->edit_CF, TEXTSW, XV_X, 0, WIN_BELOW, panel, WIN_COLUMNS, 80, WIN_ROWS, 40, TEXTSW_BROWSING, TRUE, TEXTSW_DISABLE_CD, TRUE, TEXTSW_DISABLE_LOAD, TRUE, NULL); if (pEdit->text_TSW == NULL) { (void)printf("error creating editor text subwindow\n"); exit(1); } guiEditorGetPath(pEdit, 0); xv_set(pEdit->text_TSW, WIN_WIDTH, WIN_EXTEND_TO_EDGE, NULL); window_fit(pEdit->edit_CF); if (file != NULL && file[0] != '\0') guiEditorLoadFile_1(pEdit); return pEdit; } /*+/internal****************************************************************** * NAME guiEditorCancelFile_mi * *-*/ static void guiEditorCancelFile_mi(menu, item) Menu menu; Menu_item item; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); if (pEdit->loaded == 0) return; textsw_reset(pEdit->text_TSW, 0, 0); guiEditorUpdateRst(pEdit); guiEditorLoadFile_1(pEdit); guiMessagePrintf(pEdit->status_PM, "updates discarded; read-only mode"); } /*+/internal****************************************************************** * NAME guiEditorCreateFile_mi * *-*/ static void guiEditorCreateFile_mi(menu, item) Menu menu; Menu_item item; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); FILE *pFile; int fd; char path[GUI_TDIM*3]; int upd=pEdit->updFlag; path[0] = '\0'; textsw_append_file_name(pEdit->text_TSW, path); #if 0 if (pEdit->loaded) guiEditorUpdateRst(pEdit); if (pEdit->updFlag) goto createFail; #endif if (guiEditorGetPath(pEdit, 1) == NULL) goto createFail; if ((pFile = fopen(pEdit->path, "r")) != NULL) { fclose(pFile); guiNoticeFile(pEdit->pGuiCtx, "file already exists:", pEdit->path); goto createFail; } if ((fd = open(pEdit->path, O_WRONLY|O_CREAT, 0664)) < 0) { guiNoticeFile(pEdit->pGuiCtx, "couldn't create file:", pEdit->path); goto createFail; } close(fd); if (pEdit->updFlag == 1) { pEdit->updFlag = 0; guiLock(pEdit->pGuiCtx, pEdit->file, pEdit->lockFile, 0); } if (pEdit->loaded) textsw_store_file(pEdit->text_TSW, pEdit->path, 0, 0); guiEditorLoadFile_1(pEdit); guiEditorUpdateSet(pEdit); if (upd) { guiMessagePrintf(pEdit->status_PM, "%s created from %s; edit mode", pEdit->file, path); } else guiMessagePrintf(pEdit->status_PM,"%s created; edit mode",pEdit->file); return; createFail: guiMessagePrintf(pEdit->status_PM, "create failed"); } /*+/internal****************************************************************** * NAME guiEditorGetPath * *-*/ static char * guiEditorGetPath(pEdit, notice) GUI_EDIT *pEdit; int notice; /* 1 if want you want a notice issued on problems */ { char *name, *dir; dir = (char *)xv_get(pEdit->dir_PT, PANEL_VALUE); name = (char *)xv_get(pEdit->file_PT, PANEL_VALUE); strcpy(pEdit->file, name); strcpy(pEdit->dir, dir); if (name[0] == '\0') { if (notice) guiNotice(pEdit->pGuiCtx, "no file name specified"); return NULL; } strcpy(pEdit->path, dir); if (strlen(pEdit->path) > 0) strcat(pEdit->path, "/"); strcat(pEdit->path, name); return pEdit->path; } /*+/subr********************************************************************** * NAME guiEditorGets - get the next '\n' terminated string from editor * * DESCRIPTION * Reads the next string from the editor text subwindow into the caller's * buffer. Reading stops when a newline is encountered or when the * caller's buffer is full; the newline IS stored in the buffer. * The string in the buffer is always null terminated. * * The caller must supply the character index (starting with 0) of * the position in the textsw where reading is to start. On return, * the caller's index is set to the next available character for * reading. * * RETURNS * pointer to string, or * NULL if there are no more characters in text subwindow * *-*/ char * guiEditorGets(pEdit, pBuf, dim, pCharPos) GUI_EDIT *pEdit; /* I pointer to guiEditor */ char *pBuf; /* I pointer to buffer to receive string */ int dim; /* I dimension of buffer */ int *pCharPos; /* IO index of character to start reading */ { Textsw textsw=pEdit->text_TSW; Textsw_index nextPos; int i; char *pStr; if (pEdit->loaded == 0) { guiNotice(pEdit->pGuiCtx, "no file loaded"); return NULL; } nextPos = (Textsw_index)xv_get(textsw, TEXTSW_CONTENTS, *pCharPos, pBuf, dim-1); if (nextPos == *pCharPos) return NULL; for (i=0; i= nextPos) { pBuf[i] = '\0'; return pBuf; } (*pCharPos)++; if (pBuf[i] == '\n') { pBuf[i+1] = '\0'; return pBuf; } } pBuf[i] = '\0'; return pBuf; } /*+/internal****************************************************************** * NAME guiEditorLoadFile_mi * *-*/ static void guiEditorLoadFile_mi(menu, item) Menu menu; Menu_item item; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); guiEditorLoadFile_1(pEdit); } /*+/subr********************************************************************** * NAME guiEditorLoadFile - load a file for editing * * DESCRIPTION * Loads the specified file into the editor window. If the editor * window already holds a file which has been edited, a notice pops * up and the load of the new file is not performed. * *-*/ void guiEditorLoadFile(pEdit, dir, file) GUI_EDIT *pEdit; /* I pointer to guiEditor */ char *dir; /* I directory */ char *file; /* I file name */ { guiEditorShowCF(pEdit); guiEditorUpdateRst(pEdit); if (pEdit->updFlag == 1) { guiMessagePrintf(pEdit->status_PM, "%s not loaded", file); return; } xv_set(pEdit->dir_PT, PANEL_VALUE, dir, NULL); xv_set(pEdit->file_PT, PANEL_VALUE, file, NULL); guiEditorLoadFile_1(pEdit); } /*+/internal****************************************************************** * NAME guiEditorLoadFile_1 * *-*/ static void guiEditorLoadFile_1(pEdit) GUI_EDIT *pEdit; { Textsw_status status; if ((int)xv_get(pEdit->text_TSW, TEXTSW_MODIFIED)) { guiNotice(pEdit->pGuiCtx, "text has been modified; use \"Save\" or \"discard edits\""); goto loadFailed; } if (guiEditorGetPath(pEdit, 1) == NULL) goto loadFailed; if (pEdit->updFlag) { guiEditorUpdateRst(pEdit); pEdit->updFlag = 0; } xv_set(pEdit->text_TSW, TEXTSW_STATUS, &status, TEXTSW_FILE, pEdit->path, NULL); if (status == TEXTSW_STATUS_OKAY) { guiEditorUpdateRst(pEdit); pEdit->loaded = 1; } else { guiNoticeFile(pEdit->pGuiCtx, "couldn't open file", pEdit->path); pEdit->loaded = 0; goto loadFailed; } guiMessagePrintf(pEdit->status_PM, "%s loaded; read-only mode set", pEdit->file); return; loadFailed: guiMessagePrintf(pEdit->status_PM, "load failed"); } /*+/subr********************************************************************** * NAME guiEditorNewEntry_pb * * DESCRIPTION * * RETURNS * void * * void addExtrasFn(pGuiCtx, panel, pX,pY,pHt, addExtrasArg) * * EXAMPLE * Add an extra button to a text editor to allow adding a new entry * (as for a "log book") to a file. The new entry will have the form: * * == Mar 06, 1992 07:27:31 userName == * * * TEST_CTX *pCtx; * GUI_CTX *pGui; * GUI_EDIT *pEdit; * void extra(); * * pEdit = guiEditor(pGui, ".", NULL, NULL, extra, pCtx); * * * * void extra(pGuiCtx, pEditor, panel, pX,pY,pHt, pCtx) * GUI_CTX *pGuiCtx; * GUI_EDIT *pEditor; * Panel panel; * int *pX,*pY,*pHt; * TEST_CTX *pCtx; * { * *pX = 5; *pY += *pHt + 10; *pHt = 0; * guiButton("New entry", panel, pX,pY,pHt, guiEditorNewEntry_pb, NULL, * GUI_PCTX, pGuiCtx, GUI_PEDIT, pEditor); * } *-*/ void guiEditorNewEntry_pb(item) Panel_item item; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); Textsw tsw=pEdit->text_TSW; TS_STAMP nowTs; char now[32]; int i; if (!pEdit->loaded) { guiNotice(pEdit->pGuiCtx, "no file has been loaded"); return; } if (pEdit->updFlag == 0) { guiNotice(pEdit->pGuiCtx, "edit mode must be set"); return; } xv_set(tsw, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, NULL); textsw_possibly_normalize(tsw, (Textsw_index)xv_get(tsw, TEXTSW_INSERTION_POINT)); tsLocalTime(&nowTs); tsStampToText(&nowTs, TS_TEXT_MONDDYYYY, now); now[21] = '\0'; /* don't print fractions of sec */ guiEditorPrintf(pEdit, "\n== %s %s ==\n", now, pEdit->pGuiCtx->user); } /*+/internal****************************************************************** * NAME guiEditorPickFile_mi * *-*/ static void guiEditorPickFile_mi(menu, item) Menu menu; Menu_item item; { GUI_CTX *pGuiCtx=(GUI_CTX *)xv_get(item, XV_KEY_DATA, GUI_PCTX); GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); char title[GUI_TDIM*2]; sprintf(title, "%s: %s", pEdit->title, "List dir"); guiEditorGetPath(pEdit, 0); guiFileSelect(pGuiCtx, title, pEdit->dir, pEdit->file, GUI_TDIM, guiEditorPick_callback, pEdit); } /*+/internal****************************************************************** * NAME guiEditorPick_callback * *-*/ static void guiEditorPick_callback(pEdit, newPath, newDir, newFileName) GUI_EDIT *pEdit; char *newPath; char *newDir; char *newFileName; { xv_set(pEdit->dir_PT, PANEL_VALUE, newDir, NULL); xv_set(pEdit->file_PT, PANEL_VALUE, newFileName, NULL); guiEditorLoadFile_1(pEdit); guiMessagePrintf(pEdit->status_PM, "%s loaded; read-only mode set", newFileName); } /*+/internal****************************************************************** * NAME guiEditorPrintFile_mi * *-*/ static void guiEditorPrintFile_mi(menu, item) Menu menu; Menu_item item; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); if (!pEdit->loaded) { guiNotice(pEdit->pGuiCtx, "no file has been loaded"); goto printFailed; } if ((int)xv_get(pEdit->text_TSW, TEXTSW_MODIFIED)) { guiNotice(pEdit->pGuiCtx, "file is modified; save before printing"); goto printFailed; } guiPrintFile(pEdit->pPrtCtx, pEdit->path); guiMessagePrintf(pEdit->status_PM, "printout sent to %s", (char *)xv_get(pEdit->pPrtCtx->printer_PT, PANEL_VALUE)); return; printFailed: guiMessagePrintf(pEdit->status_PM, "print failed"); } #if 0 /*+/macros******************************************************************** * NAME guiEditorPrintf - do a printf to a guiEditor * * SYNOPSIS * void * guiEditorPrintf(pEdit, fmt, ...) * GUI_EDIT *pEdit;/* I pointer to guiEditor */ * char *fmt; /* I printf format string */ * ... /* I other arguments, for printing */ * *-*/ #endif void guiEditorPrintf(va_alist) va_dcl { va_list pArgs; GUI_EDIT *pEdit; Textsw textsw; char *fmt; char message[500]; int n, L; va_start(pArgs); pEdit = va_arg(pArgs, GUI_EDIT *); if (pEdit->loaded == 0) { guiNotice(pEdit->pGuiCtx, "no file loaded"); return; } textsw = pEdit->text_TSW; fmt = va_arg(pArgs, char *); vsprintf(message, fmt, pArgs); va_end(pArgs); L = strlen(message); n = textsw_insert(textsw, message, L); if (n != L) return; n = (int)xv_get(textsw, TEXTSW_INSERTION_POINT); textsw_possibly_normalize(textsw, n); } /*+/subr********************************************************************** * NAME guiEditorPuts - write string to guiEditor * * DESCRIPTION * Writes the string to the text subwindow of a guiEditor. * * The caller must supply the character index (starting with 0) of * the position in the textsw where writing is to start. On return, * the caller's index is set to the next available character for * writing. * * RETURNS * 0, or * EOF if an error occurs during the write * *-*/ int guiEditorPuts(pEdit, pBuf, pCharPos) GUI_EDIT *pEdit; /* I pointer to guiEditor */ char *pBuf; /* I pointer to buffer to write to text subwindow */ int *pCharPos; /* IO index of character position to start writing */ { Textsw textsw=pEdit->text_TSW; Textsw_index n; int L=strlen(pBuf); if (pEdit->loaded == 0) { guiNotice(pEdit->pGuiCtx, "no file loaded"); return EOF; } xv_set(textsw, TEXTSW_INSERTION_POINT, *pCharPos, NULL); n = textsw_insert(textsw, pBuf, L); if (n != L) return EOF; *pCharPos = (int)xv_get(textsw, TEXTSW_INSERTION_POINT); textsw_possibly_normalize(textsw, *pCharPos); return 0; } /*+/subr********************************************************************** * NAME guiEditorReset - reset an editor text subwindow, discarding contents * * DESCRIPTION * * RETURNS * void * *-*/ void guiEditorReset(pEdit) GUI_EDIT *pEdit; /* I pointer to guiEditor */ { Textsw textsw=pEdit->text_TSW; if (pEdit->loaded == 0) return; textsw_reset(textsw, 0, 0); guiEditorUpdateRst(pEdit); } /*+/internal****************************************************************** * NAME guiEditorSaveFile_mi * *-*/ static void guiEditorSaveFile_mi(menu, item) Menu menu; Menu_item item; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); unsigned stat; if (!pEdit->loaded) { guiNotice(pEdit->pGuiCtx, "no file has been loaded"); return; } if ((int)xv_get(pEdit->text_TSW, TEXTSW_MODIFIED)) { if (guiEditorGetPath(pEdit, 1) != NULL) { stat = textsw_store_file(pEdit->text_TSW, pEdit->path, 0, 0); if (stat != 0) { guiNoticeFile(pEdit->pGuiCtx,"unable to save in:",pEdit->path); guiMessagePrintf(pEdit->status_PM, "save failed"); return; } } } guiEditorUpdateRst(pEdit); guiMessagePrintf(pEdit->status_PM, "saved in %s", pEdit->file); } #if 0 /*+/macros******************************************************************** * NAME guiEditorShowCF - show the command frame containing the editor * * DESCRIPTION * Make an editor command frame visible. There are several versions * of this routine available, to accomodate the different methods of * calling it: * * void guiEditorShowCF(pEdit) call directly * GUI_EDIT *pEdit; /* I pointer to editor context */ * * void guiEditorShowCF_mi(menu, item) call from a menu item * Menu menu; /* I menu handle */ * Menu_item item; /* I menu item handle--must have * XV_KEY_DATA of GUI_PEDIT, pEdit */ * * void guiEditorShowCF_xvo(item) call from a button item * Xv_opaque item; /* I item handle--must have * XV_KEY_DATA of GUI_PEDIT, pEdit */ *-*/ #endif void guiEditorShowCF(pEdit) GUI_EDIT *pEdit; /* I pointer to editor context */ { if ((int)xv_get(pEdit->edit_CF, XV_SHOW) == TRUE) guiAbove(pEdit->edit_CF); else xv_set(pEdit->edit_CF, XV_SHOW, TRUE, FRAME_CMD_PUSHPIN_IN, TRUE, NULL); } void guiEditorShowCF_mi(menu, menuItem) Menu menu; Menu_item menuItem; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(menuItem, XV_KEY_DATA, GUI_PEDIT); guiEditorShowCF(pEdit); } void guiEditorShowCF_xvo(item) Xv_opaque item; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); guiEditorShowCF(pEdit); } #if 0 /*+/macro********************************************************************* * NAME guiEditorStatusPrintf - do a printf to the guiEditor status line * * SYNOPSIS * void * guiEditorStatusPrintf(pEdit, fmt, ...) * GUI_EDIT *pEdit;/* I pointer to guiEditor */ * char *fmt; /* I printf format string */ * ... /* I other arguments, for printing */ * *-*/ #endif void guiEditorStatusPrintf(va_alist) va_dcl { GUI_EDIT *pEdit; va_list pArgs; Xv_opaque item; char *fmt; char message[500]; va_start(pArgs); pEdit = va_arg(pArgs, GUI_EDIT *); fmt = va_arg(pArgs, char *); vsprintf(message, fmt, pArgs); va_end(pArgs); xv_set(pEdit->status_PM, PANEL_LABEL_STRING, message, NULL); } /*+/internal****************************************************************** * NAME guiEditorUpdate_mi * *-*/ void guiEditorUpdate_mi(menu, item) Menu menu; Menu_item item; { GUI_EDIT *pEdit=(GUI_EDIT *)xv_get(item, XV_KEY_DATA, GUI_PEDIT); int value=(int)xv_get(item, XV_KEY_DATA, GUI_INT); if (value == 0) guiEditorUpdateRst(pEdit); else guiEditorUpdateSet(pEdit); } /*+/internal****************************************************************** * NAME guiEditorUpdateRst * *-*/ void guiEditorUpdateRst(pEdit) GUI_EDIT *pEdit; { if ((int)xv_get(pEdit->text_TSW, TEXTSW_MODIFIED)) guiNotice(pEdit->pGuiCtx, "text has been modified; use \"Save\" or \"discard edits\""); else { xv_set(pEdit->text_TSW, TEXTSW_BROWSING, TRUE, NULL); if (pEdit->updFlag == 1) { pEdit->updFlag = 0; guiLock(pEdit->pGuiCtx, pEdit->file, pEdit->lockFile, 0); } } if (pEdit->updFlag == 1) guiMessagePrintf(pEdit->status_PM, "edit mode"); else guiMessagePrintf(pEdit->status_PM, "read-only mode"); } /*+/internal****************************************************************** * NAME guiEditorUpdateSet * *-*/ void static guiEditorUpdateSet(pEdit) GUI_EDIT *pEdit; { Textsw tsw=pEdit->text_TSW; int top; char lockFile[2*GUI_TDIM + 5]; FILE *pFile; if (pEdit->updFlag == 1) { guiEditorUpdateRst(pEdit); goto updateDone; } if (!pEdit->loaded) { guiNotice(pEdit->pGuiCtx, "no file has been loaded"); guiEditorUpdateRst(pEdit); return; } if ((pFile = fopen(pEdit->path, "r+")) == NULL) { guiNoticeFile(pEdit->pGuiCtx, "file isn't writeable:", pEdit->file); guiEditorUpdateRst(pEdit); goto updateDone; } fclose(pFile); top = (int)xv_get(tsw, TEXTSW_FIRST_LINE); top += 2; strcpy(lockFile, pEdit->path); strcat(lockFile, ".editLock"); if (guiLock(pEdit->pGuiCtx, pEdit->file, lockFile, 1) != 1) { guiEditorUpdateRst(pEdit); /* lock attempt didn't succeed */ goto updateDone; } xv_set(tsw, TEXTSW_FIRST_LINE, top, NULL); xv_set(tsw, TEXTSW_BROWSING, FALSE, NULL); pEdit->updFlag = 1; strcpy(pEdit->lockFile, lockFile); updateDone: if (pEdit->updFlag == 1) guiMessagePrintf(pEdit->status_PM, "edit mode"); else guiMessagePrintf(pEdit->status_PM, "read-only mode"); } void guiFileSelCom_mi(); void guiFileSelLs_mi(); void guiFileSelLsDone(); /*+/subr********************************************************************** * NAME guiFileSelect - select a file from a group * * DESCRIPTION * Present a list of files in a directory and allow the user to * choose one of them. Support is given for changing directory. * * Only one file select command frame can be active at a given time-- * each call to this routine will result in wrapping up any * previous call to it. * * The callback routine will be called if the user requests a change * in file path. The callback routine is called with 4 arguments: * * callback(pArg, newPath, newDir, newFileName); * * BUGS * o doesn't support wildcard lists (e.g., ls *.c) * *-*/ void guiFileSelect(pGuiCtx, title, dir, file, dim, callback, pArg) GUI_CTX *pGuiCtx; /* I pointer to gui context */ char *title; /* I title for command frame title bar */ char *dir; /* I directory */ char *file; /* I file name */ int dim; /* I dimension of the dir & file arrays */ void (*callback)(); /* I routine to call if user changes file/dir */ void *pArg; /* I argument to pass to callback routine */ { Frame frame; Panel panel; Menu menu; int x=5, y=5, ht=0; char message[GUI_TDIM*3]; pGuiCtx->fsCallFn = callback; pGuiCtx->fsCallArg = pArg; if (pGuiCtx->fsFrame != NULL) { frame = pGuiCtx->fsFrame; xv_set(frame, FRAME_LABEL, title, NULL); } else { frame = guiFrameCmd(title, pGuiCtx->baseFrame, &panel, NULL); xv_set(frame, XV_KEY_DATA, GUI_PCTX, pGuiCtx, NULL); pGuiCtx->fsFrame = frame; pGuiCtx->fsDir_PT = guiTextField("Dir:", panel, &x,&y,&ht, NULL, dim-1, 40, 0, NULL, 0, NULL); pGuiCtx->fsFile_PT = guiTextField("File:", panel, &x,&y,&ht, NULL, dim-1, 20, 0, NULL, 0, NULL); y += ht + 10; x = 5; ht = 0; menu = guiMenu(NULL, 0, NULL, 0, NULL); guiMenuItem("Load", menu, guiFileSelCom_mi, 0, 1, GUI_PCTX, pGuiCtx, 0, NULL); guiMenuItem("List dir...", menu, guiFileSelLs_mi, 0, 0, GUI_PCTX, pGuiCtx, 0, NULL); guiButton("File", panel, &x, &y, &ht, NULL, menu, 0,NULL,0,NULL); pGuiCtx->fsStatus_PM = guiMessage(" ", panel, &x, &y, &ht); y += ht + 5; x = 5; ht = 0; window_fit(panel); pGuiCtx->fsTextsw = guiBrowser(frame, panel, 60, 30, NULL); } xv_set(pGuiCtx->fsDir_PT, PANEL_VALUE, dir, NULL); xv_set(pGuiCtx->fsFile_PT, PANEL_VALUE, file, NULL); window_fit(frame); xv_set(frame, XV_SHOW, TRUE, NULL); if (dir[0] == '\0') { guiNotice(pGuiCtx, "directory must be specified"); return; } sprintf(pGuiCtx->fsLsFile, "/tmp/guiFileSel%d.ls.tmp", getpid()); unlink(pGuiCtx->fsLsFile); sprintf(message, "cd %s; ls -l >%s", dir, pGuiCtx->fsLsFile); guiShellCmd_work(pGuiCtx, message, GUI_FILE_SEL_CLIENT, guiFileSelLsDone, pGuiCtx, 0); sprintf(message, "processing names in %s", dir); xv_set(pGuiCtx->fsStatus_PM, PANEL_LABEL_STRING, message, NULL); } /*+/internal****************************************************************** * NAME guiFileSelCom_mi * *-*/ static void guiFileSelCom_mi(menu, item) Menu menu; Menu_item item; { GUI_CTX *pGuiCtx=(GUI_CTX *)xv_get(item, XV_KEY_DATA, GUI_PCTX); char *pSel, *dir, *file, path[240]; /*----------------------------------------------------------------------------- * if there's selected text, use it for file name. If it's in the * window listing the files, get the file name from the end of the * line containing the selected text. *----------------------------------------------------------------------------*/ pSel = guiGetNameFromSeln(pGuiCtx, pGuiCtx->fsTextsw, 0, 1); if (pSel != NULL) xv_set(pGuiCtx->fsFile_PT, PANEL_VALUE, pSel, NULL); dir = (char *)xv_get(pGuiCtx->fsDir_PT, PANEL_VALUE); file = (char *)xv_get(pGuiCtx->fsFile_PT, PANEL_VALUE); if (strlen(file) > 0) { sprintf(path, "%s/%s", dir, file); pGuiCtx->fsCallFn(pGuiCtx->fsCallArg, path, dir, file); #if 0 xv_set(pGuiCtx->fsFrame, XV_SHOW, FALSE, FRAME_CMD_PUSHPIN_IN, FALSE, NULL); #endif } else guiNotice(pGuiCtx, "file name is blank; select file or use Cancel"); } /*+/internal****************************************************************** * NAME guiFileSelLs_mi * *-*/ static void guiFileSelLs_mi(menu, item) Menu menu; Menu_item item; { GUI_CTX *pGuiCtx=(GUI_CTX *)xv_get(item, XV_KEY_DATA, GUI_PCTX); char message[GUI_TDIM]; char *dir=(char *)xv_get(pGuiCtx->fsDir_PT, PANEL_VALUE); unlink(pGuiCtx->fsLsFile); sprintf(message, "cd %s; ls -l >%s", dir, pGuiCtx->fsLsFile); guiShellCmd_work(pGuiCtx, message, GUI_FILE_SEL_CLIENT, guiFileSelLsDone, pGuiCtx, 0); sprintf(message, "processing names in %s", dir); xv_set(pGuiCtx->fsStatus_PM, PANEL_LABEL_STRING, message, NULL); } /*+/internal****************************************************************** * NAME guiFileSelLsDone * *-*/ static void guiFileSelLsDone(pGuiCtx) GUI_CTX *pGuiCtx; { char *dir=(char *)xv_get(pGuiCtx->fsDir_PT, PANEL_VALUE); char message[GUI_TDIM]; xv_set(pGuiCtx->fsTextsw, TEXTSW_FILE, pGuiCtx->fsLsFile, NULL); unlink(pGuiCtx->fsLsFile); if ((int)xv_get(pGuiCtx->fsTextsw, TEXTSW_LENGTH) <= 0) sprintf(message, "there are no files in %s", dir); else sprintf(message, "size and modification date are shown"); xv_set(pGuiCtx->fsStatus_PM, PANEL_LABEL_STRING, message, NULL); } /*+/subr********************************************************************** * NAME guiFrame - create a base frame * * DESCRIPTION * Create a base frame. The frame will have have the specified label * in its title bar, as well as for its icon. The frame will have * resize corners. If height and width are specified, they will * determine the size of the frame; otherwise, it will have a * default size. * * If pointers are specified in the call, then the X11 display and * the XView server are passed back to the caller. * * RETURNS * Frame handle * * SEE ALSO * guiFrameCmd, guiIconCreate *-*/ Frame guiFrame(label, x, y, width, height, ppDisp, pServer) char *label; /* I label for frame and icon */ int x; /* I x coordinate for frame, in pixels */ int y; /* I y coordinate for frame, in pixels */ int width; /* I width of frame, in pixels, or 0 */ int height; /* I height of frame, in pixels, or 0 */ Display **ppDisp; /* O pointer to X display pointer, or NULL */ Xv_server *pServer; /* O pointer to xview server handle, or NULL */ { Icon icon; Frame frame; icon = (Icon)xv_create(NULL, ICON, ICON_LABEL, label, NULL); if (icon == NULL) { (void)printf("error creating \"%s\" icon\n", label); exit(1); } frame = (Frame)xv_create(NULL, FRAME, FRAME_LABEL, label, FRAME_ICON, icon, WIN_X, x, WIN_Y, y, NULL); if (frame == NULL) { (void)printf("error creating \"%s\" frame\n", label); exit(1); } if (width > 0) xv_set(frame, XV_WIDTH, width, NULL); if (height > 0) xv_set(frame, XV_HEIGHT, height, NULL); if (ppDisp != NULL) *ppDisp = (Display *)xv_get(frame, XV_DISPLAY); if (pServer != NULL) *pServer = (Xv_server)xv_get(xv_get(frame, XV_SCREEN), SCREEN_SERVER); return frame; } /*+/subr********************************************************************** * NAME guiFrameCmd - create a command frame * * DESCRIPTION * Create a command frame and an associated panel. * * If a procedure is specified for handling resize, then the frame * is set to receive resize events. (The frame will have resize * corners regardless of whether a procedure is specified.) * * RETURNS * Frame handle * * NOTES * 1. For command frames with text subwindows, the resize procedure can * be omitted, and the text subwindow will be automatically resized * when the command frame is resized. * *-*/ Frame guiFrameCmd(label, parentFrame, pPanel, resizeProc) char *label; /* I label for command frame */ Frame parentFrame; /* I parent frame for command frame */ Panel *pPanel; /* O ptr to default panel of command frame, or NULL */ void (*resizeProc)();/* I function to handle resize, or NULL */ { Frame frame; if (resizeProc == NULL) { frame = (Frame)xv_create(parentFrame, FRAME_CMD, FRAME_LABEL, label, FRAME_SHOW_RESIZE_CORNER, TRUE, XV_SHOW, FALSE, NULL); } else { frame = (Frame)xv_create(parentFrame, FRAME_CMD, FRAME_LABEL, label, FRAME_SHOW_RESIZE_CORNER, TRUE, WIN_EVENT_PROC, resizeProc, WIN_CONSUME_EVENTS, WIN_RESIZE, NULL, XV_SHOW, FALSE, NULL); } if (frame == NULL) { (void)printf("error creating \"%s\" command frame\n", label); exit(1); } if (pPanel != NULL) { *pPanel = (Panel)xv_get(frame, FRAME_CMD_PANEL); if (*pPanel == NULL) { (void)printf("error getting default panel for \"%s\"\n", label); exit(1); } xv_set(*pPanel, WIN_WIDTH, WIN_EXTEND_TO_EDGE, NULL); } return frame; } /*+/subr********************************************************************** * NAME guiGetNameFromSeln - get a name from a line of selected text * * DESCRIPTION * Examines the selected text to extract a name to return to the caller. * A `name' is considered to be a string of characters delimited by * white space. The entire line containing the selection is treated * as being selected. * * The selected text must be within the caller's text subwindow. * * The actual action taken depends on the arguments: * * head tail pointer is returned to: * ---- ---- ----------------------------------------------- * 0 0 entire line containing selection * 1 0 first word of line containing selection * 0 1 last word of line containing selection * * RETURNS * char * to name * * BUGS * o this routine isn't reentrant * o if the caller wants a permanent copy of the name, it must be copied * prior to the next call to guiGetNameFromSeln * *-*/ char * guiGetNameFromSeln(pGuiCtx, textSw, headFlag, tailFlag) GUI_CTX *pGuiCtx; /* I pointer to gui context */ Textsw textSw; /* I handle to text subwindow to treat special */ int headFlag; /* I 1 to return only the head of the line */ int tailFlag; /* I 1 to return only the tail of the line */ { int i, bufLen; char *pSel, *buf; buf = pSel = guiGetSelnInTextsw(pGuiCtx, textSw); if (pSel == NULL) return NULL; bufLen = strlen(pSel); if (headFlag) { /*----------------------------------------------------------------------------- * skip leading blanks, then look for the first white space; return * what's in between to the caller *----------------------------------------------------------------------------*/ pSel = buf; while (*pSel == ' ') { pSel++; /* skip leading blanks */ bufLen--; } i = 0; while (i < bufLen-1) { if (isspace(pSel[i])) break; i++; } pSel[i] = '\0'; } else if (tailFlag) { /*----------------------------------------------------------------------------- * looking backward from end, find the first white space; return the * "tail" of the line to the caller *----------------------------------------------------------------------------*/ i = bufLen - 1; while (i > 0) { if (buf[i] == '\n') buf[i] = '\0'; else if (isspace(buf[i])) { i++; break; } i--; } pSel = &buf[i]; } return pSel; } /*+/subr********************************************************************** * NAME guiGetSelnInTextsw - get selected text if it's in callers textsw * * DESCRIPTION * Checks to see if there's a text selection in the caller's text * subwindow. If so, a pointer to it is returned. * * RETURNS * char * to selected text * * BUGS * o this routine isn't reentrant * o if the caller wants a permanent copy of the name, it must be copied * prior to the next call to guiGetSelnInTextsw * *-*/ char * guiGetSelnInTextsw(pGuiCtx, textSw) GUI_CTX *pGuiCtx; /* I pointer to gui context */ Textsw textSw; /* I handle to text subwindow to treat special */ { Seln_holder holder; Seln_request *pResponse; static char buf[GUI_TDIM*2]; int bufLen; char *pSel; holder = selection_inquire(pGuiCtx->server, SELN_PRIMARY); pResponse = selection_ask(pGuiCtx->server, &holder, SELN_REQ_CONTENTS_ASCII, NULL, NULL); pSel = pResponse->data + sizeof(SELN_REQ_CONTENTS_ASCII); bufLen = strlen(pSel); if (bufLen == 0) pSel = NULL; /* no selection */ else if (seln_holder_same_client(&holder, textSw)) { pResponse = selection_ask(pGuiCtx->server, &holder, SELN_REQ_FAKE_LEVEL, SELN_LEVEL_LINE, SELN_REQ_CONTENTS_ASCII, NULL, NULL); pSel = pResponse->data; pSel += sizeof(SELN_REQ_FAKE_LEVEL); pSel += sizeof(SELN_LEVEL_LINE); pSel += sizeof(SELN_REQ_CONTENTS_ASCII); bufLen = strlen(pSel); if (bufLen > sizeof(buf)-1) { guiNotice(pGuiCtx, "too much text selected"); return (char *)NULL; } strcpy(buf, pSel); } else pSel = NULL; return pSel; } /*+/subr********************************************************************** * NAME guiIconCreate - create an icon to attach to a frame * * DESCRIPTION * Using the bit image for an icon, creates the internal structure * needed to draw the icon. The icon is then associated with the * specified frame. * * RETURNS * Icon handle * * BUGS * o assumes an icon size of 64x64 * * EXAMPLE * Associate the icon in "../src/myIcon.icon" with the base frame. * (myIcon.icon was produced with the OpenLook "iconedit" program.) * * #include * * myIcon_bits[]={ * #include "../src/myIcon.icon" * }; * * Icon myIcon; * * myIcon = (Icon)guiIconCreate(pGuiCtx->baseFrame, myIcon_bits); * *-*/ Icon guiIconCreate(frame, iconBits) Frame frame; /* I handle for frame to receive the icon */ short *iconBits; /* I array of bits for the icon (64 by 64 assuemd) */ { Server_image icon_image; Icon icon; icon_image = (Server_image)xv_create(NULL, SERVER_IMAGE, XV_WIDTH, 64, XV_HEIGHT, 64, SERVER_IMAGE_BITS, iconBits, NULL); icon = (Icon)xv_create(frame, ICON, ICON_IMAGE, icon_image, ICON_TRANSPARENT, TRUE, NULL); xv_set(frame, FRAME_ICON, icon, NULL); return icon; } /*+/subr********************************************************************** * NAME guiInit - initialize the gui routines * * DESCRIPTION * Sets up for gui operations, including: * o connecting to X11 * o assimilating X11 options from the command line * o creating a base frame * o creating a panel within the base frame * o initializing the gui context block with: * .user user name * .host host name (or X server name if different) * .pwd working directory * .baseFrame Xview Frame of main program window * .pDisp the X Display pointer * .server the Xview server handle * * RETURNS * Panel handle * *-*/ Panel guiInit(pGuiCtx, pArgc, argv, label, x, y, width, height) GUI_CTX *pGuiCtx; /* I pointer to gui context */ int *pArgc; /* I pointer to number of command line args */ char *argv[]; /* I command line args */ char *label; /* I label for frame and icon */ int x; /* I x coordinate for frame, in pixels */ int y; /* I y coordinate for frame, in pixels */ int width; /* I width of frame, in pixels, or 0 */ int height; /* I height of frame, in pixels, or 0 */ { char *user, *pwd; xv_init(XV_INIT_ARGC_PTR_ARGV, pArgc, argv, 0); pGuiCtx->baseFrame = guiFrame(label, x, y, width, height, &pGuiCtx->pDisp, &pGuiCtx->server); pGuiCtx->fsFrame = NULL; strcpy(pGuiCtx->host, pGuiCtx->pDisp->display_name); pwd = getenv("PWD"); strncpy(pGuiCtx->pwd, pwd, GUI_TDIM-1); user = getenv("USER"); strncpy(pGuiCtx->user, user, GUI_TDIM-1); if (pGuiCtx->host[0] == '\0' || pGuiCtx->host[0] == ':' || strncmp(pGuiCtx->host, "unix", 4) == 0) { gethostname(pGuiCtx->host, GUI_TDIM); } return (Panel)xv_create(pGuiCtx->baseFrame, PANEL, XV_X, 0, XV_Y, 0, PANEL_LAYOUT, PANEL_HORIZONTAL, NULL); } /*+/subr********************************************************************** * NAME guiLock - provide a "global" lock and unlock mechanism * * DESCRIPTION * * RETURNS * 1 if lock succeeds * 0 if unlock succeeds * -1 if either operation fails * *-*/ int guiLock(pGuiCtx, text, lockPath, lock) GUI_CTX *pGuiCtx; /* I pointer to gui context block */ char *text; /* I name or description for error messages */ char *lockPath; /* I pointer to path for lock file */ int lock; /* I 0,1 to reset,set the lock */ { FILE *pFile; char msgLock[2*GUI_TDIM]; char msgWho[2*GUI_TDIM]; TS_STAMP ts; char tsText[32]; int noticeVal; if (lock) { if ((pFile = fopen(lockPath, "r+")) != NULL) { fread(msgWho, GUI_TDIM, 1, pFile); fclose(pFile); if (strncmp(msgWho, "unlocked", 8) != 0) { sprintf(msgLock, "%s is locked:", text); noticeVal = notice_prompt(pGuiCtx->baseFrame, NULL, NOTICE_MESSAGE_STRINGS, msgLock, msgWho, "you can cancel the operation or force an unlock", NULL, NOTICE_BUTTON_YES, "Cancel", NOTICE_BUTTON_NO, "Unlock", NULL); if (noticeVal == NOTICE_YES) return -1; } } } if ((pFile = fopen(lockPath, "w+")) == NULL) { guiNoticeFile(pGuiCtx, "couldn't open lock file", lockPath); return -1; } if (lock) { tsLocalTime(&ts); tsStampToText(&ts, TS_TEXT_MONDDYYYY, tsText); sprintf(msgWho, "by:%s on:%s at:%.21s", pGuiCtx->user, pGuiCtx->host, tsText); fwrite(msgWho, strlen(msgWho)+1, 1, pFile); fclose(pFile); return 1; } else { fwrite("unlocked", 9, 1, pFile); fclose(pFile); unlink(lockPath); return 0; } } /*+/subr********************************************************************** * NAME guiMenu - create a menu * * DESCRIPTION * * RETURNS * Menu handle * *-*/ Menu guiMenu(proc, key1, val1, key2, val2) void (*proc)(); /* I pointer to procedure to handle menu selection */ enum key1; /* I key for context information for object */ void *val1; /* I value associated with key */ enum key2; /* I key for context information for object */ void *val2; /* I value associated with key */ { Menu menu; menu = (Menu)xv_create(NULL, MENU, NULL); if (menu == NULL) { (void)printf("error creating menu\n"); exit(1); } if (proc != NULL) { if (xv_set(menu, MENU_NOTIFY_PROC, proc, NULL) != XV_OK) { (void)printf("error adding proc to menu\n"); exit(1); } } if (key1 != 0) { if (xv_set(menu, XV_KEY_DATA, key1, val1, NULL) != XV_OK) { (void)printf("error adding key1 to menu\n"); exit(1); } } if (key2 != 0) { if (xv_set(menu, XV_KEY_DATA, key2, val2, NULL) != XV_OK) { (void)printf("error adding key2 to menu\n"); exit(1); } } return menu; } /*+/subr********************************************************************** * NAME guiMenuItem - add a menu item to a menu * * DESCRIPTION * * RETURNS * Menu_item handle * *-*/ Menu_item guiMenuItem(label, menu, proc, inact, dflt, key1, val1, key2, val2) char *label; /* I label for menu item */ Menu menu; /* I menu on which to add item */ void (*proc)(); /* I pointer to procedure to handle menu selection */ int inact; /* I 0,1 for item active,inactive */ int dflt; /* I 0,1 for item isn't,is the default */ enum key1; /* I key for context information for object */ void *val1; /* I value associated with key */ enum key2; /* I key for context information for object */ void *val2; /* I value associated with key */ { Menu_item menuItem; menuItem = (Menu_item)xv_create(NULL, MENUITEM, MENU_STRING, label, MENU_RELEASE, NULL); if (menuItem == NULL) { (void)printf("error creating \"%s\" menu item\n", label); exit(1); } if (xv_set(menu, MENU_APPEND_ITEM, menuItem, NULL) != XV_OK) { (void)printf("error adding \"%s\" menu item to menu\n", label); exit(1); } if (proc != NULL) { if (xv_set(menuItem, MENU_NOTIFY_PROC, proc, NULL) != XV_OK) { (void)printf("error adding proc to \"%s\" menu item\n", label); exit(1); } } if (inact) { if (xv_set(menuItem, MENU_INACTIVE, TRUE, NULL) != XV_OK) { (void)printf("error setting \"%s\" menu item inactive\n", label); exit(1); } } if (dflt) { if (xv_set(menu, MENU_DEFAULT_ITEM, menuItem, NULL) != XV_OK) { (void)printf("error setting \"%s\" menu item default\n", label); exit(1); } } if (key1 != 0) { if (xv_set(menuItem, XV_KEY_DATA, key1, val1, NULL) != XV_OK) { (void)printf("error adding key1 to \"%s\" menu item\n", label); exit(1); } } if (key2 != 0) { if (xv_set(menuItem, XV_KEY_DATA, key2, val2, NULL) != XV_OK) { (void)printf("error adding key2 to \"%s\" menu item\n", label); exit(1); } } return menuItem; } /*+/subr********************************************************************** * NAME guiMessage - create a text message object * * DESCRIPTION * * RETURNS * Panel_item handle to message * * BUGS * o text * * SEE ALSO * guiMessagePrintf * * EXAMPLE * *-*/ Panel_item guiMessage(label, panel, pX, pY, pHt) char *label; /* I label for button */ Panel panel; /* I handle of panel containing message */ int *pX; /* IO pointer to x position in panel, in pixels */ int *pY; /* I pointer to y position in panel, in pixels */ int *pHt; /* IO ptr to height of message, in pixels, or NULL */ { Panel_item item; int height; item = (Panel_item)xv_create(panel, PANEL_MESSAGE, PANEL_LABEL_STRING, label, XV_X, *pX, XV_Y, *pY, NULL); if (item == NULL) { (void)printf("error creating message object\n"); exit(1); } *pX += (int)xv_get(item, XV_WIDTH) + 10; if (pHt != NULL) { height = xv_get(item, XV_HEIGHT); if (height > *pHt) *pHt = height; } return item; } #if 0 /*+/macro********************************************************************* * NAME guiMessagePrintf - do a printf to a guiMessage object * * SYNOPSIS * void * guiMessagePrintf(panelMessage, fmt, ...) * Panel_item panelMessage;/* I handle from guiMessage */ * char *fmt; /* I printf format string */ * ... /* I other arguments, for printing */ * *-*/ #endif void guiMessagePrintf(va_alist) va_dcl { va_list pArgs; Xv_opaque item; char *fmt; char message[500]; va_start(pArgs); item = va_arg(pArgs, Xv_opaque); fmt = va_arg(pArgs, char *); vsprintf(message, fmt, pArgs); va_end(pArgs); xv_set(item, PANEL_LABEL_STRING, message, NULL); } /*+/macro********************************************************************* * NAME guiNotice - display a pop-up notice * * DESCRIPTION * Display a pop-up notice with a "continue" button. Several different * routines are available: * * guiNotice(pGuiCtx, message) simply displays the message * * guiNoticeFile(pGuiCtx, message, filePath) calls "perror()" to print * the Unix error message and file name to stdout, then * displays the message and file path in the pop-up * * guiNoticeName(pGuiCtx, message, name) displays the message and the * name (usually for a channel or file) in the pop-up * * In each case, the first argument is a GUI_CTX * pointing to a * gui context block. The other arguments are char * pointing to * text strings. * * RETURNS * void * *-*/ void guiNotice(pGuiCtx, msg) GUI_CTX *pGuiCtx; /* I pointer to gui context */ char *msg; { notice_prompt(pGuiCtx->baseFrame, NULL, NOTICE_MESSAGE_STRINGS, msg, NULL, NOTICE_BUTTON_YES, "Continue", NULL); return; } void guiNoticeFile(pGuiCtx, msg, fName) GUI_CTX *pGuiCtx; /* I pointer to gui context */ char *msg; char *fName; { perror(fName); notice_prompt(pGuiCtx->baseFrame, NULL, NOTICE_MESSAGE_STRINGS, msg, fName, NULL, NOTICE_BUTTON_YES, "Continue", NULL); return; } void guiNoticeName(pGuiCtx, msg, name) GUI_CTX *pGuiCtx; /* I pointer to gui context */ char *msg; char *name; { char myName[GUI_TDIM], *pName; if (strlen(name) < GUI_TDIM-3){ sprintf(myName, "\"%s\"", name); pName = myName; } else pName = name; notice_prompt(pGuiCtx->baseFrame, NULL, NOTICE_MESSAGE_STRINGS, msg, pName, NULL, NOTICE_BUTTON_YES, "Continue", NULL); return; } #if 0 /*+/macro********************************************************************* * NAME guiNoticePrintf - do a printf to a guiNotice * * SYNOPSIS * void * guiNoticePrintf(pGuiCtx, fmt, ...) * GUI_CTX *pGuiCTx;/* I pointer to gui context */ * char *fmt; /* I printf format string */ * ... /* I other arguments, for printing */ * *-*/ #endif void guiNoticePrintf(va_alist) va_dcl { va_list pArgs; GUI_CTX *pCtx; char *fmt; char message[500]; va_start(pArgs); pCtx = va_arg(pArgs, GUI_CTX *); fmt = va_arg(pArgs, char *); vsprintf(message, fmt, pArgs); va_end(pArgs); guiNotice(pCtx, message); } /*+/subr********************************************************************** * NAME guiPrinter - create a printer context and command frame * * DESCRIPTION * Create a printer context block and command frame for handling * printer operations. The amenities provided include: * * o grabbing the PRINTER environment variable to set the default * printer to use * o allowing user to choose point size of font * o allowing user to choose page orientation * o allowing user to choose whether to use enscript or lpr for * the printing operation * * The printer context block can be used in the guiEditor call to * enable the "Print" button for the editor. * * RETURNS * GUI_PRT *, or * NULL * * SEE ALSO * guiPrintFile, guiPrinterShowCF_mi, guiPrinterShowCF_xvo * guiEditor * *-*/ GUI_PRT * guiPrinter(pGuiCtx, parentFrame, title, useEnscript) GUI_CTX *pGuiCtx; /* I pointer to gui context */ Frame parentFrame; /* I parent of editor command frame */ char *title; /* I text for command frame title bar */ int useEnscript; /* I 0,1 to use lpr,enscript for printing */ { GUI_PRT *pPrt; Panel panel; Panel_item item; char *printer; Panel_item ck; int y=10, x=5, ht=0; /*----------------------------------------------------------------------------- * Printer: ______ point size: __ v portrait v enscript * landscape lpr * ..................status message.............................. *----------------------------------------------------------------------------*/ if ((pPrt=(GUI_PRT *)malloc(sizeof(GUI_PRT))) == NULL) { return NULL; } bzero((char *)pPrt, sizeof(GUI_PRT)); pPrt->pGuiCtx = pGuiCtx; pPrt->print_CF = guiFrameCmd(title, parentFrame, &panel, NULL); pPrt->printer_PT = guiTextField("Printer:", panel, &x,&y,&ht, NULL, 19, 8, 0, NULL, 0, NULL); xv_set(pPrt->printer_PT, PANEL_VALUE, getenv("PRINTER"), NULL); pPrt->point_PT = guiTextField("point size:", panel, &x,&y,&ht, NULL, 2, 2, 0, NULL, 0, NULL); xv_set(pPrt->point_PT, PANEL_VALUE, "8", NULL); pPrt->landscape_PCS = item = xv_create(panel, PANEL_CHOICE_STACK, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "portrait","landscape",NULL, PANEL_VALUE, 0, XV_X, x, XV_Y, y-5, NULL); x += (int)xv_get(item, XV_WIDTH) + 5; pPrt->prog_PCS = item = xv_create(panel, PANEL_CHOICE_STACK, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "enscript","lpr",NULL, PANEL_VALUE, 0, XV_X, x, XV_Y, y-5, NULL); x += (int)xv_get(item, XV_WIDTH) + 5; y += ht + 5; x = 5; ht = 0; window_fit(panel); window_fit(pPrt->print_CF); return pPrt; } /*+/subr********************************************************************** * NAME guiPrintFile * * DESCRIPTION * Print a file using the settings in the printer context block. * * RETURNS * void * * SEE ALSO * guiPrinter * *-*/ void guiPrintFile(pPrtCtx, path) GUI_PRT *pPrtCtx; /* I pointer to printer context */ char *path; /* I pathname of file to be printed */ { char command[GUI_TDIM*3]; guiPrintGetCmd(pPrtCtx, path, command); guiShellCmd(pPrtCtx->pGuiCtx, command, GUI_PRINT_CLIENT, NULL, NULL); } /*+/subr********************************************************************** * NAME guiPrintGetCmd * * DESCRIPTION * Get a print command, using the settings in the printer context block. * * RETURNS * void * * SEE ALSO * guiPrinter * *-*/ void guiPrintGetCmd(pPrtCtx, path, command) GUI_PRT *pPrtCtx; /* I pointer to printer context */ char *path; /* I pathname of file to be printed, or NULL */ { char mode[8]; if ((int)xv_get(pPrtCtx->landscape_PCS, PANEL_VALUE) == 0) strcpy(mode, ""); /* portrait mode */ else strcpy(mode, "-r"); /* rotate to landscape mode */ if ((int)xv_get(pPrtCtx->prog_PCS, PANEL_VALUE) == 0) { sprintf(command, "enscript -fCourier%s -q -P%s %s %s", (char *)xv_get(pPrtCtx->point_PT, PANEL_VALUE), (char *)xv_get(pPrtCtx->printer_PT, PANEL_VALUE), mode, path); } else { if (mode[0] != '\0') guiNotice(pPrtCtx->pGuiCtx, "landscape is ignored when using lpr"); sprintf(command, "lpr -P%s %s", (char *)xv_get(pPrtCtx->printer_PT, PANEL_VALUE), path); } } /*+/macros******************************************************************** * NAME guiPrinterShowCF_... - make printer command frame visible * * DESCRIPTION * Make the printer setup command frame visible, so that the user * can modify print parameters. * * There are two forms of this routine. The first is to be called * from a menu; the second is to be called from other objects, such * as a button. * guiPrinterShowCF_mi(menu, item); * guiPrinterShowCF_xvo(item); * * RETURNS * void * * SEE ALSO * guiPrinter, guiPrintFile * * EXAMPLE * Set up a button with a two-item menu--the first item will print * a file (whose name is in the program's context block), and the * second item will call this routine. Make the first item the * default. * * Menu menu; * void print_mi(); * * menu = guiMenu(NULL, 0, NULL, 0, NULL); * guiMenuItem("Print file", menu, print_mi, 0,1, * PCTX, pCtx, GUI_PPRT, pEdit->pPrtCtx); * guiMenuItem("Printer setup...", menu, guiPrinterShowCF_mi, 0,0, * GUI_PPRT, pEdit->pPrtCtx, 0, NULL); * guiButton("Print", panel, &x, &y, &ht, NULL, menu, 0, NULL, 0, NULL); * * * void print_mi(menu, item) * Menu menu; * Menu_item item; * { GUI_PRT *pPrt=(GUI_PRT *)xv_get(item, XV_KEY_DATA, GUI_PPRT); * TEST_CTX *pCtx=(TEST_CTX *)xv_get(item, XV_KEY_DATA, PCTX); * * guiPrintFile(pPrt, pCtx->file); * } * *-*/ void guiPrinterShowCF_mi(menu, item) Menu menu; Menu_item item; { GUI_PRT *pPrtCtx=(GUI_PRT *)xv_get(item, XV_KEY_DATA, GUI_PPRT); if ((int)xv_get(pPrtCtx->print_CF, XV_SHOW) == TRUE) guiAbove(pPrtCtx->print_CF); else xv_set(pPrtCtx->print_CF, XV_SHOW, TRUE, NULL); } /*+/internal****************************************************************** * NAME guiPrinterShowCF_xvo * *-*/ void guiPrinterShowCF_xvo(item) Xv_opaque item; { GUI_PRT *pPrtCtx=(GUI_PRT *)xv_get(item, XV_KEY_DATA, GUI_PPRT); if ((int)xv_get(pPrtCtx->print_CF, XV_SHOW) == TRUE) guiAbove(pPrtCtx->print_CF); else xv_set(pPrtCtx->print_CF, XV_SHOW, TRUE, NULL); } /*+/subr********************************************************************** * NAME guiShellCmd - issue a shell command, cooperating with the notifier * * DESCRIPTION * This routine issues a shell command under the auspices of the * xview notifier. The command is issued following a fork, with a * popen call. The critical issue is that the fork results in a * SIGCHLD signal which the notifier must handle. * * The callback routine has the following form: * void callback(callbackArg, resultBuf) * resultBuf is a pointer to the text produced by the command (limited to * a single line) * * RETURNS * void * * BUGS * o when running under dbx, the child process always results in a * core dump * *-*/ void guiShellCmd(pGuiCtx, cmdBuf, clientNum, callbackFn, callbackArg) GUI_CTX *pGuiCtx; /* I pointer to gui context */ char *cmdBuf; /* I the command string to give the shell */ Notify_client clientNum;/* I a unique value in the range 100 to 200 to be used by guiCmdSigchld when the child is done processing the command */ void (*callbackFn)();/* I pointer to function for guiCmdSigchld to call */ void *callbackArg; /* I arg to pass to callbackFn */ { guiShellCmd_work(pGuiCtx, cmdBuf, clientNum, callbackFn, callbackArg, 0); } void guiShellCmd_execv_argv(pGuiCtx, argv, clientNum, callbackFn, callbackArg) GUI_CTX *pGuiCtx; /* I pointer to gui context */ char *argv; /* I arguments to give the shell */ Notify_client clientNum;/* I a unique value in the range 100 to 200 to be used by guiCmdSigchld when the child is done processing the command */ void (*callbackFn)();/* I pointer to function for guiCmdSigchld to call */ void *callbackArg; /* I arg to pass to callbackFn */ { guiShellCmd_work(pGuiCtx, argv, clientNum, callbackFn, callbackArg, 2); } void guiShellCmd_work(pGuiCtx, cmdBuf, clientNum, callbackFn, callbackArg, mode) GUI_CTX *pGuiCtx; /* I pointer to gui context */ char *cmdBuf; /* I the command string to give the shell (or pointer to argv list if mode==2)*/ Notify_client clientNum;/* I a unique value in the range 100 to 200 to be used by guiCmdSigchld when the child is done processing the command */ void (*callbackFn)();/* I pointer to function for guiCmdSigchld to call */ void *callbackArg; /* I arg to pass to callbackFn */ int mode; /* I 0,1,2 for popen,execvp,execvp_with_argv */ { FILE *fp; int i, pid, cbNum; int pipe_io[2][2]; char resultBuf[GUI_TDIM]; char *argv[20], *buf, *pBuf, dlm; cbNum = callbackNum; while (cbNum >= 0 && callback[cbNum].clientNum != clientNum) cbNum--; if (cbNum < 0) { if (++cbNum < 100) { callbackNum = cbNum; callback[cbNum].clientNum = clientNum; } else { guiNotice(pGuiCtx, "guiShellCmd: overflow of client number table"); return; } } callback[cbNum].callbackFn = callbackFn; callback[cbNum].callbackArg = callbackArg; callback[cbNum].result[0] = '\0'; callback[cbNum].readDone = 0; callback[cbNum].sigChldDone = 0; /*----------------------------------------------------------------------------- * blatantly stolen from "XView Programming Manual", Dan Heller, O'Reilly & * Associates, Inc., July 1990, pp.386-389; section 19.8.2, Reading and * Writing on Pipes; Example 19-4. The ntfy_pipe.c program * * child reads: |<=========== pipe_io[0] <===========| parent writes: * pipe_io[0][0] pipe_io[0][1] * * parent reads: |<=========== pipe_io[1] <===========| child writes: * pipe_io[1][0] pipe_io[1][1] *----------------------------------------------------------------------------*/ if (mode == 1) { pBuf = buf = (char *)malloc(strlen(cmdBuf)+1); strcpy(pBuf, cmdBuf); for (i=0; i<19; i++) { if (nextNonSpaceField(&pBuf, &argv[i], &dlm) <= 1) break; } argv[i] = NULL; } pipe(pipe_io[0]); pipe(pipe_io[1]); if ((pid = fork()) == -1) { perror("error executing shell command"); close(pipe_io[0][0]); close(pipe_io[0][1]); close(pipe_io[1][0]); close(pipe_io[1][1]); if (mode == 1) free(buf); return; } else if (pid == 0) { /* child process */ dup2(pipe_io[0][0], 0); /* stdin */ dup2(pipe_io[1][1], 1); /* stdout */ dup2(pipe_io[1][1], 2); /* stderr */ for (i=getdtablesize(); i>2; i--) close(i); /* close the pipe fd's */ for (i=0; i 0) fwrite(resultBuf, 1, i, stdout); _exit(0); } } if (mode == 1) free(buf); close(pipe_io[0][0]); close(pipe_io[0][1]); close(pipe_io[1][1]); callback[cbNum].pipe_io = pipe_io[1][0]; notify_set_input_func(clientNum, guiCmdRead, pipe_io[1][0]); notify_set_wait3_func(clientNum, guiCmdSigchld, pid); } Notify_value guiCmdRead(client, fd) Notify_client client; int fd; { char buf[GUI_TDIM]; int nBytes, i; int j, thisNum=-1; for (j=0; j<=callbackNum; j++) { if (client == callback[j].clientNum) { thisNum = j; break; } } if (ioctl(fd, FIONREAD, &nBytes) == 0) { while (nBytes > 0) { if ((i = read(fd, buf, sizeof(buf)-1)) > 0) { buf[i] = '\0'; if (thisNum >= 0) strcpy(callback[thisNum].result, buf); nBytes -= i; } } } if (thisNum >= 0) { callback[thisNum].readDone = 1; notify_set_input_func(client, NOTIFY_FUNC_NULL, callback[thisNum].pipe_io); close(fd); if (callback[thisNum].sigChldDone) { if (callback[thisNum].callbackFn != NULL) { callback[thisNum].callbackFn(callback[thisNum].callbackArg, callback[thisNum].result); } } } return NOTIFY_DONE; } /*/subhead guiCmdSigchld------------------------------------------------------- * When the child process gets done creating a file, it will die, * producing SIGCHLD. At that time, call the callback function. *----------------------------------------------------------------------------*/ Notify_value guiCmdSigchld(client, pid, status) Notify_client client; int pid; union wait *status; { Notify_value i=NOTIFY_IGNORED; int j; for (j=0; j<=callbackNum; j++) { if (client == callback[j].clientNum) { callback[j].sigChldDone = 1; if (WIFEXITED(*status)) { if (callback[j].readDone) { if (callback[j].callbackFn != NULL) { callback[j].callbackFn(callback[j].callbackArg, callback[j].result); } } i = NOTIFY_DONE; } return i; } } return i; } /*+/subr********************************************************************** * NAME guiTextField - create a text entry field * * DESCRIPTION * * RETURNS * Panel_item handle for text field * *-*/ Panel_item guiTextField(label, panel, pX, pY, pHt, proc, nStored, nShown, key1, val1, key2, val2) char *label; /* I label for text field */ Panel panel; /* I handle of panel containing text field */ int *pX; /* IO pointer to x position in panel, in pixels */ int *pY; /* I pointer to y position in panel, in pixels */ int *pHt; /* IO ptr to height used by field, in pixels, or NULL */ void (*proc)(); /* I pointer to procedure to handle carriage return */ int nStored; /* I number of characters to store in field */ int nShown; /* I number of characters to show on screen */ enum key1; /* I key for context information for object */ void *val1; /* I value associated with key */ enum key2; /* I key for context information for object */ void *val2; /* I value associated with key */ { Panel_item item; int height; item = (Panel_item)xv_create(panel, PANEL_TEXT, PANEL_LABEL_STRING, label, PANEL_VALUE_STORED_LENGTH, nStored, PANEL_VALUE_DISPLAY_LENGTH, nShown, XV_X, *pX, XV_Y, *pY, NULL); if (item == NULL) { (void)printf("error creating \"%s\" text field\n", label); exit(1); } if (proc != NULL) { if (xv_set(item, PANEL_NOTIFY_LEVEL, PANEL_SPECIFIED, PANEL_NOTIFY_PROC, proc, NULL) != XV_OK) { (void)printf("error setting PANEL_SPECIFIED for \"%s\"\n",label); exit(1); } } if (key1 != 0) { if (xv_set(item, XV_KEY_DATA, key1, val1, NULL) != XV_OK) { (void)printf("error setting XV_KEY_DATA for \"%s\"\n",label); exit(1); } } if (key2 != 0) { if (xv_set(item, XV_KEY_DATA, key2, val2, NULL) != XV_OK) { (void)printf("error setting XV_KEY_DATA for \"%s\"\n",label); exit(1); } } *pX += (int)xv_get(item, XV_WIDTH) + 10; if (pHt != NULL) { height = (int)xv_get(item, XV_HEIGHT); if (height > *pHt) *pHt = height; } return item; } #if 0 /*+/macro********************************************************************* * NAME guiTextFieldPrintf - do a printf to a text entry field * * SYNOPSIS * void * guiTextFieldPrintf(panelItem, fmt, ...) * Panel_item panelItem;/* I handle from guiTextField */ * char *fmt; /* I printf format string */ * ... /* I other arguments, for printing */ * *-*/ #endif void guiTextFieldPrintf(va_alist) va_dcl { va_list pArgs; Xv_opaque item; char *fmt; char message[500]; va_start(pArgs); item = va_arg(pArgs, Xv_opaque); fmt = va_arg(pArgs, char *); vsprintf(message, fmt, pArgs); va_end(pArgs); xv_set(item, PANEL_VALUE, message, NULL); } /*+/subr********************************************************************** * NAME guiTextswGets - get the next '\n' terminated string from textsw * * DESCRIPTION * Reads the next string from the text subwindow into the caller's * buffer. Reading stops when a newline is encountered or when the * caller's buffer is full; the newline IS stored in the buffer. * The string in the buffer is always null terminated. * * The caller must supply the character index (starting with 0) of * the position in the textsw where reading is to start. On return, * the caller's index is set to the next available character for * reading. * * RETURNS * pointer to string, or * NULL if there are no more characters in text subwindow * *-*/ char * guiTextswGets(textsw, pBuf, dim, pCharPos) Textsw textsw; /* I the text subwindow */ char *pBuf; /* I pointer to buffer to receive string */ int dim; /* I dimension of buffer */ int *pCharPos; /* IO index of character to start reading */ { Textsw_index nextPos; int i; char *pStr; nextPos = (Textsw_index)xv_get(textsw, TEXTSW_CONTENTS, *pCharPos, pBuf, dim-1); if (nextPos == *pCharPos) return NULL; for (i=0; i= nextPos) { pBuf[i] = '\0'; return pBuf; } (*pCharPos)++; if (pBuf[i] == '\n') { pBuf[i+1] = '\0'; return pBuf; } } pBuf[i] = '\0'; return pBuf; } #if 0 /*+/macro********************************************************************* * NAME guiTextswPrintf - do a printf to a guiTextsw * * SYNOPSIS * void * guiTextswPrintf(textsw, fmt, ...) * Textsw textsw; /* I handle from guiTextsw */ * char *fmt; /* I printf format string */ * ... /* I other arguments, for printing */ * *-*/ #endif void guiTextswPrintf(va_alist) va_dcl { va_list pArgs; Textsw textsw; char *fmt; char message[500]; int n, L; va_start(pArgs); textsw = va_arg(pArgs, Textsw); fmt = va_arg(pArgs, char *); vsprintf(message, fmt, pArgs); va_end(pArgs); L = strlen(message); n = textsw_insert(textsw, message, L); if (n != L) return; n = (int)xv_get(textsw, TEXTSW_INSERTION_POINT); textsw_possibly_normalize(textsw, n); } /*+/subr********************************************************************** * NAME guiTextswPuts - write string into textsw * * DESCRIPTION * Writes the string to the text subwindow. * * The caller must supply the character index (starting with 0) of * the position in the textsw where writing is to start. On return, * the caller's index is set to the next available character for * writing. * * RETURNS * 0, or * EOF if an error occurs during the write * *-*/ int guiTextswPuts(textsw, pBuf, pCharPos) Textsw textsw; /* I the text subwindow */ char *pBuf; /* I pointer to buffer to write to text subwindow */ int *pCharPos; /* IO index of character position to start writing */ { Textsw_index n; int L=strlen(pBuf); xv_set(textsw, TEXTSW_INSERTION_POINT, *pCharPos, NULL); n = textsw_insert(textsw, pBuf, L); if (n != L) return EOF; *pCharPos = (int)xv_get(textsw, TEXTSW_INSERTION_POINT); textsw_possibly_normalize(textsw, *pCharPos); return 0; } /*+/subr********************************************************************** * NAME guiTextswReset - reset a text subwindow, discarding its contents * * DESCRIPTION * * RETURNS * void * *-*/ void guiTextswReset(textsw) Textsw textsw; /* I the text subwindow */ { textsw_reset(textsw, 0, 0); } /*+/subr********************************************************************** * NAME guiTimer - create a timer * * DESCRIPTION * Creates and starts an interval timer. The interval may include * fractions of seconds. * * The timer callback function has the form of the usual Unix itimer * function: * * void callbackFn(callbackArg, dummy) * void *callbackArg * int dummy; * { * } * * BUGS * o a mechanism for cancelling the timer or changing its interval isn't * yet part of guiSubr * *-*/ void guiTimer(seconds, callbackFn, callbackArg) double seconds; /* I number of seconds for timer interval */ void (*callbackFn)();/* I name of callback function */ void *callbackArg; /* I argument to pass to callback function */ { struct itimerval t; t.it_interval.tv_sec = t.it_value.tv_sec = (int)aint(seconds); t.it_interval.tv_usec = t.it_value.tv_usec = (int)(fmod(seconds, 1.)*1000000.); notify_set_itimer_func(callbackArg, callbackFn, ITIMER_REAL, &t, NULL); } #endif