home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tk42r2s.zip
/
tk4.2
/
os2
/
tkOS2Dialog.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-07-26
|
23KB
|
801 lines
/*
* tkOS2Dialog.c --
*
* Contains the OS/2 implementation of the common dialog boxes.
*
* Copyright (c) 1996 Sun Microsystems, Inc.
* Copyright (c) 1998 Illya Vaes
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tkOS2Dialog.c 1.5 96/09/11 19:24:28
*
*/
#include "tkOS2Int.h"
#include "tkFileFilter.h"
#if ((TK_MAJOR_VERSION == 4) && (TK_MINOR_VERSION <= 2))
/*
* The following function is implemented on tk4.3 and after only
*/
#define Tk_GetHWND TkOS2GetHWND
#endif
#define SAVE_FILE 0
#define OPEN_FILE 1
/*----------------------------------------------------------------------
* MsgTypeInfo --
*
* This structure stores the type of available message box in an
* easy-to-process format. Used by the Tk_MessageBox() function
*----------------------------------------------------------------------
*/
typedef struct MsgTypeInfo {
char * name;
int type;
int numButtons;
char * btnNames[3];
} MsgTypeInfo;
#define NUM_TYPES 6
static MsgTypeInfo msgTypeInfo[NUM_TYPES] = {
{"abortretryignore", MB_ABORTRETRYIGNORE, 3, {"abort", "retry", "ignore"}},
{"ok", MB_OK, 1, {"ok" }},
{"okcancel", MB_OKCANCEL, 2, {"ok", "cancel" }},
{"retrycancel", MB_RETRYCANCEL, 2, {"retry", "cancel" }},
{"yesno", MB_YESNO, 2, {"yes", "no" }},
{"yesnocancel", MB_YESNOCANCEL, 3, {"yes", "no", "cancel"}}
};
static int GetFileName _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int argc, char **argv,
int isOpen));
static int MakeFilter _ANSI_ARGS_((Tcl_Interp *interp,
FILEDLG *fdlgPtr, char * string,
FileFilterList *flistPtr));
static int ParseFileDlgArgs _ANSI_ARGS_((Tcl_Interp * interp,
FILEDLG *fdlgPtr, int argc, char ** argv,
int isOpen, HWND *hwndParent,
FileFilterList *flistPtr));
static int ProcessError _ANSI_ARGS_((Tcl_Interp * interp,
ERRORID lastError, HWND hWnd));
/*
*----------------------------------------------------------------------
*
* EvalArgv --
*
* Invokes the Tcl procedure with the arguments. argv[0] is set by
* the caller of this function. It may be different than cmdName.
* The TCL command will see argv[0], not cmdName, as its name if it
* invokes [lindex [info level 0] 0]
*
* Results:
* TCL_ERROR if the command does not exist and cannot be autoloaded.
* Otherwise, return the result of the evaluation of the command.
*
* Side effects:
* The command may be autoloaded.
*
*----------------------------------------------------------------------
*/
static int EvalArgv(interp, cmdName, argc, argv)
Tcl_Interp *interp; /* Current interpreter. */
char * cmdName; /* Name of the TCL command to call */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
Tcl_CmdInfo cmdInfo;
if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) {
char * cmdArgv[2];
/*
* This comand is not in the interpreter yet -- looks like we
* have to auto-load it
*/
if (!Tcl_GetCommandInfo(interp, "auto_load", &cmdInfo)) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "cannot execute command \"auto_load\"",
NULL);
return TCL_ERROR;
}
cmdArgv[0] = "auto_load";
cmdArgv[1] = cmdName;
if ((*cmdInfo.proc)(cmdInfo.clientData, interp, 2, cmdArgv)!= TCL_OK){
return TCL_ERROR;
}
if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "cannot auto-load command \"",
cmdName, "\"",NULL);
return TCL_ERROR;
}
}
return (*cmdInfo.proc)(cmdInfo.clientData, interp, argc, argv);
}
/*
*----------------------------------------------------------------------
*
* Tk_ChooseColorCmd --
*
* This procedure implements the color dialog box for the OS/2
* platform. See the user documentation for details on what it
* does.
*
* Results:
* See user documentation.
*
* Side effects:
* A dialog window is created the first time this procedure is called.
* This window is not destroyed and will be reused the next time the
* application invokes the "tk_chooseColor" command.
*
*----------------------------------------------------------------------
*/
int
Tk_ChooseColorCmd(clientData, interp, argc, argv)
ClientData clientData; /* Main window associated with interpreter. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
return EvalArgv(interp, "tkColorDialog", argc, argv);
}
/*
*----------------------------------------------------------------------
*
* Tk_GetOpenFileCmd --
*
* This procedure implements the "open file" dialog box for the
* OS/2 platform. See the user documentation for details on what
* it does.
*
* Results:
* See user documentation.
*
* Side effects:
* A dialog window is created the first this procedure is called.
* This window is not destroyed and will be reused the next time
* the application invokes the "tk_getOpenFile" or
* "tk_getSaveFile" command.
*
*----------------------------------------------------------------------
*/
int
Tk_GetOpenFileCmd(clientData, interp, argc, argv)
ClientData clientData; /* Main window associated with interpreter. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
/* "Unix look-and-feel"
return EvalArgv(interp, "tkFDialog", argc, argv);
*/
return GetFileName(clientData, interp, argc, argv, OPEN_FILE);
}
/*
*----------------------------------------------------------------------
*
* Tk_GetSaveFileCmd --
*
* Same as Tk_GetOpenFileCmd but opens a "save file" dialog box
* instead
*
* Results:
* Same as Tk_GetOpenFileCmd.
*
* Side effects:
* Same as Tk_GetOpenFileCmd.
*
*----------------------------------------------------------------------
*/
int
Tk_GetSaveFileCmd(clientData, interp, argc, argv)
ClientData clientData; /* Main window associated with interpreter. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
/* "Unix look-and-feel"
return EvalArgv(interp, "tkFDialog", argc, argv);
*/
return GetFileName(clientData, interp, argc, argv, SAVE_FILE);
}
/*
*----------------------------------------------------------------------
*
* GetFileName --
*
* Create File Open or File Save Dialog.
*
* Results:
* See user documentation.
*
* Side effects:
* See user documentation.
*
*----------------------------------------------------------------------
*/
static int GetFileName(clientData, interp, argc, argv, isOpen)
ClientData clientData; /* Main window associated with interpreter. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
int isOpen; /* true if we should open a file,
* false if we should save a file */
{
FILEDLG fileDlg;
int tclCode;
ULONG length = MAX_PATH+1;
ULONG curDrive, logical;
char buffer[MAX_PATH+1];
HWND hwndParent, hwndDlg;
ERRORID errorId = NO_ERROR;
FileFilterList flist;
TkInitFileFilters(&flist);
/*
* 1. Parse the arguments.
*/
if (ParseFileDlgArgs(interp, &fileDlg, argc, argv, isOpen, &hwndParent,
&flist) != TCL_OK) {
TkFreeFileFilters(&flist);
return TCL_ERROR;
}
/*
* 2. Call the common dialog function.
*/
rc = DosQueryCurrentDisk(&curDrive, &logical);
rc = DosQueryCurrentDir(0, (PBYTE)&buffer, &length);
TkOS2EnterModalLoop(interp);
hwndDlg = WinFileDlg(HWND_DESKTOP, hwndParent, &fileDlg);
if (fileDlg.lReturn == 0) {
errorId = WinGetLastError(hab);
}
TkOS2LeaveModalLoop(interp);
TkFreeFileFilters(&flist);
rc = DosSetDefaultDisk(curDrive);
rc = DosSetCurrentDir(buffer);
if (fileDlg.papszITypeList) {
ckfree((char*)fileDlg.papszITypeList);
}
if (fileDlg.papszIDriveList) {
ckfree((char*)fileDlg.papszIDriveList);
}
/*
* 3. Process the results.
*/
if (hwndDlg && (fileDlg.lReturn == DID_OK)) {
char *p;
Tcl_ResetResult(interp);
for (p = fileDlg.szFullFile; p && *p; p++) {
/*
* Change the pathname to the Tcl "normalized" pathname, where
* back slashes are used instead of forward slashes
*/
if (*p == '\\') {
*p = '/';
}
}
Tcl_AppendResult(interp, fileDlg.szFullFile, NULL);
tclCode = TCL_OK;
} else {
if (fileDlg.lReturn == DID_CANCEL) {
/* User hit Cancel */
tclCode = TCL_OK;
} else {
tclCode = ProcessError(interp, errorId, hwndParent);
}
}
return tclCode;
}
/*
*----------------------------------------------------------------------
*
* ParseFileDlgArgs --
*
* Parses the arguments passed to tk_getOpenFile and tk_getSaveFile.
*
* Results:
* A standard TCL return value.
*
* Side effects:
* The FILEDLG structure is initialized and modified according
* to the arguments.
*
*----------------------------------------------------------------------
*/
static int ParseFileDlgArgs(interp, fdlgPtr, argc, argv, isOpen, hwndParent,
flistPtr)
Tcl_Interp * interp; /* Current interpreter. */
FILEDLG *fdlgPtr; /* Info about the file dialog */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
int isOpen; /* true if we should call GetOpenFileName(),
* false if we should call GetSaveFileName() */
HWND *hwndParent; /* Parent for dialog (output) */
FileFilterList *flistPtr; /* Filters to be used */
{
int i;
Tk_Window parent = Tk_MainWindow(interp);
int doneFilter = 0;
BOOL hadInitialFile = FALSE;
/* Fill in the FILEDLG structure */
memset(fdlgPtr, 0, sizeof(FILEDLG));
fdlgPtr->cbSize = sizeof(FILEDLG);
if (isOpen) {
fdlgPtr->fl = FDS_OPEN_DIALOG | FDS_CENTER | FDS_ENABLEFILELB |
FDS_FILTERUNION | FDS_PRELOAD_VOLINFO;
} else {
fdlgPtr->fl = FDS_SAVEAS_DIALOG | FDS_CENTER | FDS_ENABLEFILELB |
FDS_FILTERUNION | FDS_PRELOAD_VOLINFO;
}
for (i=1; i<argc; i+=2) {
int v = i+1;
int len = strlen(argv[i]);
char *defExt = "";
if (strncmp(argv[i], "-defaultextension", len)==0) {
if (v==argc) {goto arg_missing;}
/*
fdlgPtr->lpstrDefExt = argv[v];
strcpy(fdlgPtr->szFullFile, argv[v]);
sprintf(fdlgPtr->szFullFile, "*%s", argv[v]);
*/
if (hadInitialFile) {
/* Add default extension if necessary */
if (strchr(fdlgPtr->szFullFile, '.') == NULL) {
/* No extension given */
strcat(fdlgPtr->szFullFile, argv[v]);
}
} else {
/* Remember for if we get an initialfile argument */
defExt = argv[v];
}
}
else if (strncmp(argv[i], "-filetypes", len)==0) {
if (v==argc) {goto arg_missing;}
if (MakeFilter(interp, fdlgPtr, argv[v], flistPtr) != TCL_OK) {
return TCL_ERROR;
}
doneFilter = 1;
}
else if (strncmp(argv[i], "-initialdir", len)==0) {
ULONG diskNum;
if (v==argc) {goto arg_missing;}
/*
fdlgPtr->lpstrInitialDir = argv[v];
*/
diskNum = (ULONG) argv[v][0] - 'A' + 1;
if (argv[v][0] >= 'a') {
diskNum -= ('a' - 'A');
}
rc = DosSetDefaultDisk(diskNum);
rc = DosSetCurrentDir(argv[v] + 2);
}
else if (strncmp(argv[i], "-initialfile", len)==0) {
if (v==argc) {goto arg_missing;}
hadInitialFile = TRUE;
strncpy(fdlgPtr->szFullFile, argv[v], MAX_PATH);
if (strchr(fdlgPtr->szFullFile, '.') == NULL) {
/* No extension given */
strcat(fdlgPtr->szFullFile, defExt);
}
}
else if (strncmp(argv[i], "-parent", len)==0) {
if (v==argc) {goto arg_missing;}
parent = Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp));
if (parent == NULL) {
return TCL_ERROR;
}
}
else if (strncmp(argv[i], "-title", len)==0) {
if (v==argc) {goto arg_missing;}
fdlgPtr->pszTitle = argv[v];
}
else {
Tcl_AppendResult(interp, "unknown option \"",
argv[i], "\", must be -defaultextension, ",
"-filetypes, -initialdir, -initialfile, -parent or -title",
NULL);
return TCL_ERROR;
}
}
if (!doneFilter) {
if (MakeFilter(interp, fdlgPtr, "", flistPtr) != TCL_OK) {
return TCL_ERROR;
}
}
if (Tk_WindowId(parent) == None) {
Tk_MakeWindowExist(parent);
}
*hwndParent = Tk_GetHWND(Tk_WindowId(parent));
return TCL_OK;
arg_missing:
Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing",
NULL);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* MakeFilter --
*
* Allocate a buffer to store the filters and types in a format
* understood by OS/2
*
* Results:
* A standard TCL return value.
*
* Side effects:
* fdlgPtr->pszIType, papszITypeList, szFullFile are modified.
*
*----------------------------------------------------------------------
*/
static int MakeFilter(interp, fdlgPtr, string, flistPtr)
Tcl_Interp *interp; /* Current interpreter. */
FILEDLG *fdlgPtr; /* Info about the file dialog */
char *string; /* String value of the -filetypes option */
FileFilterList *flistPtr; /* Filters to be used */
{
CHAR *filterStr;
char *p;
FileFilter *filterPtr;
if (TkGetFileFilters(interp, flistPtr, string, 1) != TCL_OK) {
return TCL_ERROR;
}
/*
* Since the full file name only contains CCHMAXPATH characters, we
* don't need (cannot) to allocate more space.
*/
filterStr = (CHAR *) ckalloc(CCHMAXPATH);
if (filterStr == (CHAR *)NULL) {
return TCL_ERROR;
}
if (flistPtr->filters == NULL) {
/*
* Use "All Files" (*.*) as the default filter is none is specified
*/
char *defaultFilter = "*.*";
strcpy(filterStr, defaultFilter);
} else {
/*
* We put the filter types in a table, and format the extension
* into the full filename field.
* BEWARE! Specifying the same extension twice gets you a crash
* in PMCTLS.DLL, so make sure that doesn't happen.
*/
char *sep;
int typeCounter;
filterStr[0] = '\0';
/* Table of extended-attribute types, *END WITH NULL!* */
fdlgPtr->papszITypeList = (PAPSZ) ckalloc(flistPtr->numFilters *
sizeof(PSZ) + 1);
if (fdlgPtr->papszITypeList == (PAPSZ)NULL) {
ckfree((char *)filterStr);
return TCL_ERROR;
}
sep = "";
for (filterPtr = flistPtr->filters, typeCounter=0, p = filterStr;
filterPtr; filterPtr = filterPtr->next, typeCounter++) {
FileFilterClause *clausePtr;
/*
* First, put in the name of the file type
*/
*(fdlgPtr->papszITypeList)[typeCounter] = (PSZ)filterPtr->name;
/* We format the extensions in the filter pattern field */
for (clausePtr=filterPtr->clauses;clausePtr;
clausePtr=clausePtr->next) {
GlobPattern *globPtr;
for (globPtr=clausePtr->patterns; globPtr;
globPtr=globPtr->next) {
char *sub = strstr(filterStr, globPtr->pattern);
/*
* See if pattern is already in filterStr. Watch out for
* it being there as a substring of another pattern!
* eg. *.c is part of *.cpp
*/
if (sub == NULL ||
(*(sub+strlen(globPtr->pattern)) != ';' &&
*(sub+strlen(globPtr->pattern)) != '\0')) {
/*
if (strncmp(globPtr->pattern, "*.*", 3) !=0 ) {
*/
strcpy(p, sep);
p+= strlen(sep);
strcpy(p, globPtr->pattern);
p+= strlen(globPtr->pattern);
sep = ";";
/*
}
*/
}
}
}
}
/* End table with NULL! */
*(fdlgPtr->papszITypeList)[typeCounter] = (PSZ)NULL;
/* Don't specify initial type, so extensions can play too */
}
if (strlen(fdlgPtr->szFullFile) == 0) {
strcpy(fdlgPtr->szFullFile, filterStr);
}
ckfree((char *)filterStr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tk_MessageBoxCmd --
*
* This procedure implements the MessageBox window for the
* OS/2 platform. See the user documentation for details on what
* it does.
*
* Results:
* See user documentation.
*
* Side effects:
* None. The MessageBox window will be destroy before this procedure
* returns.
*
*----------------------------------------------------------------------
*/
int
Tk_MessageBoxCmd(clientData, interp, argc, argv)
ClientData clientData; /* Main window associated with interpreter. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
int flags;
Tk_Window parent = Tk_MainWindow(interp);
HWND hWnd;
char *message = "";
char *title = "";
int icon = MB_INFORMATION;
int type = MB_OK;
int i, j;
char *result;
int code;
char *defaultBtn = NULL;
int defaultBtnIdx = -1;
for (i=1; i<argc; i+=2) {
int v = i+1;
int len = strlen(argv[i]);
if (strncmp(argv[i], "-default", len)==0) {
if (v==argc) {goto arg_missing;}
defaultBtn = argv[v];
}
else if (strncmp(argv[i], "-icon", len)==0) {
if (v==argc) {goto arg_missing;}
if (strcmp(argv[v], "error") == 0) {
icon = MB_ERROR;
}
else if (strcmp(argv[v], "info") == 0) {
icon = MB_INFORMATION;
}
else if (strcmp(argv[v], "question") == 0) {
icon = MB_ICONQUESTION;
}
else if (strcmp(argv[v], "warning") == 0) {
icon = MB_WARNING;
}
else {
Tcl_AppendResult(interp, "invalid icon \"", argv[v],
"\", must be error, info, question or warning", NULL);
return TCL_ERROR;
}
}
else if (strncmp(argv[i], "-message", len)==0) {
if (v==argc) {goto arg_missing;}
message = argv[v];
}
else if (strncmp(argv[i], "-parent", len)==0) {
if (v==argc) {goto arg_missing;}
parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp));
if (parent == NULL) {
return TCL_ERROR;
}
}
else if (strncmp(argv[i], "-title", len)==0) {
if (v==argc) {goto arg_missing;}
title = argv[v];
}
else if (strncmp(argv[i], "-type", len)==0) {
int found = 0;
if (v==argc) {goto arg_missing;}
for (j=0; j<NUM_TYPES; j++) {
if (strcmp(argv[v], msgTypeInfo[j].name) == 0) {
type = msgTypeInfo[j].type;
found = 1;
break;
}
}
if (!found) {
Tcl_AppendResult(interp, "invalid message box type \"",
argv[v], "\", must be abortretryignore, ok, ",
"okcancel, retrycancel, yesno or yesnocancel", NULL);
return TCL_ERROR;
}
}
else {
Tcl_AppendResult(interp, "unknown option \"",
argv[i], "\", must be -default, -icon, ",
"-message, -parent, -title or -type", NULL);
return TCL_ERROR;
}
}
/* Make sure we have a valid hWnd to act as the parent of this message box
*/
if (Tk_WindowId(parent) == None) {
Tk_MakeWindowExist(parent);
}
hWnd = Tk_GetHWND(Tk_WindowId(parent));
if (defaultBtn != NULL) {
for (i=0; i<NUM_TYPES; i++) {
if (type == msgTypeInfo[i].type) {
for (j=0; j<msgTypeInfo[i].numButtons; j++) {
if (strcmp(defaultBtn, msgTypeInfo[i].btnNames[j])==0) {
defaultBtnIdx = j;
break;
}
}
if (defaultBtnIdx < 0) {
Tcl_AppendResult(interp, "invalid default button \"",
defaultBtn, "\"", NULL);
return TCL_ERROR;
}
break;
}
}
switch (defaultBtnIdx) {
case 0: flags = MB_DEFBUTTON1; break;
case 1: flags = MB_DEFBUTTON2; break;
case 2: flags = MB_DEFBUTTON3; break;
/*
case 3: flags = MB_DEFBUTTON4; break;
*/
default: flags = MB_DEFBUTTON1; break;
}
} else {
flags = 0;
}
flags |= icon | type;
TkOS2EnterModalLoop(interp);
/* Windows Port uses SYSTEM modal dialog, I use application modal */
code = WinMessageBox(HWND_DESKTOP, hWnd, message, title, 0,
flags|MB_APPLMODAL);
TkOS2LeaveModalLoop(interp);
/* Format the result in string form */
switch (code) {
case MBID_ABORT: result = "abort"; break;
case MBID_CANCEL: result = "cancel"; break;
case MBID_IGNORE: result = "ignore"; break;
case MBID_NO: result = "no"; break;
case MBID_OK: result = "ok"; break;
case MBID_RETRY: result = "retry"; break;
case MBID_YES: result = "yes"; break;
default: result = "";
}
Tcl_AppendResult(interp, result, NULL);
return TCL_OK;
arg_missing:
Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing",
NULL);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* ProcessError --
*
* This procedure gets called if a OS/2-specific error message
* has occurred during the execution of a common dialog or the
* user has pressed the CANCEL button.
*
* Results:
* If an error has indeed happened, returns a standard TCL result
* that reports the error code in string format. If the user has
* pressed the CANCEL button (lastError == 0), resets
* interp->result to the empty string.
*
* Side effects:
* interp->result is changed.
*
*----------------------------------------------------------------------
*/
static int ProcessError(interp, lastError, hWnd)
Tcl_Interp * interp; /* Current interpreter. */
ERRORID lastError; /* The OS/2 PM-specific error code */
HWND hWnd; /* window in which the error happened*/
{
/*
char *string;
*/
char string[257];
Tcl_ResetResult(interp);
switch(lastError) {
case 0:
return TCL_OK;
default:
sprintf(string, "unknown error, %lx", (ULONG) lastError);
}
Tcl_AppendResult(interp, "OS/2 internal error: ", string, NULL);
return TCL_ERROR;
}