Code:
// Name : Motif Text Editor
// Author : Terrence Ma
// Email : terrence@terrence.com
// Web : http://www.terrence.com
// Date : V1.0 11/16/2002
// Modified : CDE and Motif, scrolled.c p.225
/*
* Program: scrolledtext - This program illustrates the use of a
* scrolled text widget.
*
* Author : Antonino N. Mione
*
* Date : 22-Nov-1995
*
*/
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/* X and Motif headers */
#include <X11/Intrinsic.h>
#include <Xm/Label.h>
#include <Xm/MainW.h>
#include <Xm/Form.h>
#include <Xm/MessageB.h>
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#include <Xm/Text.h>
#include <Xm/Separator.h>
#include <Xm/FileSB.h>
#include <Xm/Xm.h>
/*
* Some commonly used buffer sizes for strings and data.
*/
#define SMALL_BUF_SIZE 64
#define LARGE_BUF_SIZE 256
#define HUGE_BUF_SIZE 1024
#define MAX_BUTTONS 3
#define MAX_READ 2048
#define MAX_WRITE 2048
/* Some key X, toolkit, and Motif variables */
/* Widget ids */
Widget toplevel; /* toplevel shell widget id */
Widget buttons[ MAX_BUTTONS ]; /* Buttons for functions: WorkingDialog, etc. */
Widget mainw; /* Main window to hold everything */
Widget form; /* Form widget */
Widget scrolledtext; /* Scrolled Text widget */
Widget separate; /* Separator widget */
Widget rowcol; /* Rowcol for quit button */
Widget filesb; /* File selection box widget */
Widget msgtext; /* Text widget for the message area */
XtAppContext app_context; /* Application context info (used by toolkit) */
/*
* Following are button labels and enumerated variables for button
* choices.
*/
char *buttonlabels[] = { "Open", "Save", "Quit" };
enum button_nums { opOpen=1, opSave, opQuit };
#define open_button 0
#define save_button 1
#define quit_button 2
enum file_operations { none, openning, saving };
enum file_operations fileop;
#define okButton 0
#define cancelButton 1
FILE *filehandle;
/* Prototypes */
void msgText ( char * );
Boolean read_file ( FILE *filehandle );
Boolean save_file ( FILE *filehandle );
void buttonCallback ( Widget, XtPointer, XtPointer );
void filesbButtonCallback ( Widget, XtPointer, XtPointer );
void init_widgets ( void );
int main ( int, char ** );
/*
* procedure : msgText - Write a message to the message area.
*
* arguments : msg ( in / (char *) ) - Text to be written to message area.
*
* return : void
*
* side effects :
*/
void msgText ( char *msg )
{
XmTextPosition text_pos; /* Last position in text area */
/*
* Find last position used in the message area and insert the new message
* there.
*/
text_pos = XmTextGetLastPosition ( msgtext );
XmTextInsert ( msgtext, text_pos, msg );
}
/*
* procedure : read_file - This procedure reads a file into the
* scrolled text widget.
*
* arguments : filehandle - The filehandle from which to read.
*
* return : True/False indicating the success of the operation.
*
* side effects : none.
*/
Boolean read_file ( FILE *filehandle )
{
XmTextPosition pos = 0; /* Last position filled in text widget */
char buf[ MAX_READ ]; /* Buffer for reading characters from file */
/*
* Clear any text in the scrolled text widget.
*/
XmTextSetString ( scrolledtext, "" );
/*
* As long as fgets succeeds, continue appending what is read to the
* scrolled text widget's value. Use pos to track last filled position
* so the XmTextInsert function appends to the existing value.
*/
while ( fgets ( buf, MAX_READ, filehandle ) != NULL )
{
XmTextInsert ( scrolledtext, pos, buf );
pos += strlen ( buf );
}
return True;
}
/*
* procedure : save_file - This procedure writes the contents of the
* scrolled text widget into a file.
*
* arguments : filehandle - The filehandle to which to write.
*
* return : True/False indicating the success of the operation.
*
* side effects : none.
*/
Boolean save_file ( FILE *filehandle )
{
char *stext_string; /* Temporary storage for text widgets' value */
int status; /* Status returned from fputs */
/*
* Fetch the entire text value from the widget and write it to the file
* in one operation.
*/
stext_string = XmTextGetString ( scrolledtext );
status = fputs ( stext_string, filehandle );
XtFree ( stext_string );
/*
* Check the return status from the file write. If it succeeded, clear
* the widget's value and return true. Otherwise, return false.
*/
if ( status )
{
XmTextSetString ( scrolledtext, "" );
return True;
}
else
{
return False;
}
}
/*
* procedure : buttonCallback - Callback when user activates a button.
*
* arguments : widgetId ( in / (Widget) ) - widgetId of widget causing
* the callback.
* clientData ( in / (XtPointer) ) - value passed to routine
* by the widget.
* cbr ( in / (XtPointer) ) - the callbackRecord. This
* contains additional information pertinent to the
* event causing the callback.
*
* return : none.
*
* side effects : none.
*/
void buttonCallback ( Widget widgetId,
XtPointer clientData,
XtPointer cbr )
{
/* Cast callback record and client data to the correct type. */
XmPushButtonCallbackStruct *callbackRecord =
(XmPushButtonCallbackStruct *) cbr;
enum button_nums button_num = (enum button_nums) clientData;
XmString tempCString;
Arg args[ 10 ];
Cardinal arg_count;
/*
* Select process based on button number.
*/
switch ( button_num )
{
case opOpen: /* Open a file */
fileop = openning;
/*
* Configure the file selection dialog and post it.
*/
#if XmVERSION >= 2
tempCString = XmStringGenerate ( "File to open",
NULL,
XmCHARSET_TEXT,
NULL );
#else
tempCString = XmStringCreateLocalized ( "File to open" );
#endif
XtVaSetValues ( filesb,
XmNselectionLabelString, tempCString,
NULL );
XtManageChild ( filesb );
XmStringFree ( tempCString );
break;
case opSave: /* Save text to a file */
fileop = saving;
/*
* Configure the file selection dialog and post it.
*/
#if XmVERSION >= 2
tempCString = XmStringGenerate ( "File to save",
NULL,
XmCHARSET_TEXT,
NULL );
#else
tempCString = XmStringCreateLocalized ( "File to save" );
#endif
XtVaSetValues ( filesb,
XmNselectionLabelString, tempCString,
NULL );
XtManageChild ( filesb );
XmStringFree ( tempCString );
break;
case opQuit: /* Exit the application */
exit ( 0 );
break;
}
return;
}
/*
* procedure : filesbButtonCallback - This routine is called when a
* file selection box button has been
* activated.
*
* arguments : none
*
* return : void
*
* side effects : none
*/
void filesbButtonCallback ( Widget widgetId,
XtPointer clientData,
XtPointer cbr )
{
/* Cast callback record and client data to the correct type. */
XmFileSelectionBoxCallbackStruct *callbackRecord =
(XmFileSelectionBoxCallbackStruct *) cbr;
int button_num = (int) clientData;
char *filename;
Boolean status;
/* Convert the filename to ascii */
status = XmStringGetLtoR ( callbackRecord->value, XmFONTLIST_DEFAULT_TAG, &filename );
/*
* If there was an error retrieving the filename, ring the bell and return.
* If the filename was empty, do the same.
*/
if ( !status )
{
XBell ( XtDisplay ( toplevel ), 50 );
return;
}
if ( !*filename )
{
XtFree ( filename );
XBell ( XtDisplay ( toplevel ), 50 );
return;
}
/*
* If the user clicked 'ok', check whether we are openning or saving to
* the file. Perform the appropriate operations for each.
*/
if ( button_num == okButton )
{
if ( fileop == openning )
{
filehandle = fopen ( filename, "r" );
read_file ( filehandle );
fclose ( filehandle );
}
else
{
filehandle = fopen ( filename, "w" );
save_file ( filehandle );
fclose ( filehandle );
}
fileop = none;
}
}
/*
* procedure : init_widgets - This routine initializes all of the
* widgets for the application.
*
* arguments : none
*
* return : void
*
* side effects : none
*/
void init_widgets ( void )
{
Arg args[ 10 ]; /* Argument array for widget creation */
Cardinal arg_count; /* Count of valid arguments */
char tempName[ LARGE_BUF_SIZE ]; /* Work space to build widget names */
int temp_idx; /* Loop index */
int button_num; /* Button num for activate callback */
Widget temp_id_hs, temp_id_vs;
/*
* Create a main window.
*/
arg_count = 0;
mainw = XmCreateMainWindow ( toplevel,
"mainw",
args,
arg_count );
/*
* Create the form to hold everything else.
*/
arg_count = 0;
form = XmCreateForm ( mainw,
"form",
args,
arg_count );
/*
XtManageChild ( form );
*/
/*
* Create a scrolled text widget as a child of the form.
* Make it an editable Multi-line text widget (24x80).
*/
arg_count = 0;
/*
XtSetArg ( args[ arg_count ], XmNrows, 24 );
arg_count++;
XtSetArg ( args[ arg_count ], XmNcolumns, 80 );
arg_count++;
*/
XtSetArg ( args[ arg_count ], XmNeditMode, XmMULTI_LINE_EDIT );
arg_count++;
XtSetArg ( args[ arg_count ], XmNeditable, True );
arg_count++;
XtSetArg ( args[ arg_count ], XmNtopAttachment, XmATTACH_FORM );
arg_count++;
XtSetArg ( args[ arg_count ], XmNleftAttachment, XmATTACH_FORM );
arg_count++;
XtSetArg ( args[ arg_count ], XmNrightAttachment, XmATTACH_FORM );
arg_count++;
XtSetArg ( args[ arg_count ], XmNbottomAttachment, XmATTACH_NONE );
arg_count++;
scrolledtext = XmCreateScrolledText ( form,
"scrolledtext",
args,
arg_count );
/* Manage the scrolledtext widget */
XtManageChild ( scrolledtext );
/*
* Create a separator to separate the scrolledtext and rowcolumn widgets.
*/
arg_count = 0;
XtSetArg ( args[ arg_count ], XmNtopAttachment, XmATTACH_WIDGET );
arg_count++;
XtSetArg ( args[ arg_count ], XmNtopWidget, scrolledtext );
arg_count++;
XtSetArg ( args[ arg_count ], XmNleftAttachment, XmATTACH_FORM );
arg_count++;
XtSetArg ( args[ arg_count ], XmNrightAttachment, XmATTACH_FORM );
arg_count++;
XtSetArg ( args[ arg_count ], XmNbottomAttachment, XmATTACH_NONE );
arg_count++;
separate = XmCreateSeparator ( form,
"separate",
args,
arg_count );
XtManageChild ( separate );
/*
* Create a rowcolumn widget as a child of the main window to hold any
* buttons.
*/
arg_count = 0;
XtSetArg ( args[ arg_count ], XmNtopAttachment, XmATTACH_WIDGET );
arg_count++;
XtSetArg ( args[ arg_count ], XmNtopWidget, separate );
arg_count++;
XtSetArg ( args[ arg_count ], XmNleftAttachment, XmATTACH_FORM );
arg_count++;
XtSetArg ( args[ arg_count ], XmNrightAttachment, XmATTACH_FORM );
arg_count++;
XtSetArg ( args[ arg_count ], XmNbottomAttachment, XmATTACH_FORM );
arg_count++;
XtSetArg ( args[ arg_count ], XmNorientation, XmHORIZONTAL );
arg_count++;
rowcol = XmCreateRowColumn ( form,
"rowcol",
args,
arg_count );
XtManageChild ( rowcol );
/*
* For each item in buttonlabels,
* - generate a name for the new button widget.
* - create a button child for the rowcolumn
* - add an activate callback.
* - manage the new button.
*/
for ( temp_idx = 0; temp_idx < XtNumber ( buttonlabels ); temp_idx++ )
{
button_num = temp_idx + 1;
sprintf ( tempName, "button_%d", button_num );
arg_count = 0;
buttons[ temp_idx ] = XmCreatePushButton ( rowcol,
tempName,
args,
arg_count );
XtAddCallback ( buttons[ temp_idx ],
XmNactivateCallback,
buttonCallback,
(XtPointer) button_num );
XtManageChild ( buttons[ temp_idx ] );
}
/*
* Create a text widget for the message area.
*/
arg_count = 0;
XtSetArg ( args[ arg_count ], XmNeditMode, XmMULTI_LINE_EDIT );
arg_count++;
XtSetArg ( args[ arg_count ], XmNeditable, False );
arg_count++;
msgtext = XmCreateText ( mainw,
"msgtext",
args,
arg_count );
XtManageChild ( msgtext );
/*
* Set the various areas for the main window. Also, since we are using
* a scrolled text widget, we do not need the Main Window's scrollbars
* so unmanage them as well.
*/
XtVaSetValues ( mainw,
XmNmessageWindow, msgtext,
XmNworkWindow, form,
XmNshowSeparator, True,
NULL );
XtVaGetValues ( mainw,
XmNhorizontalScrollBar, &temp_id_hs,
XmNverticalScrollBar, &temp_id_vs,
NULL );
XtUnmanageChild ( temp_id_hs );
XtUnmanageChild ( temp_id_vs );
XtManageChild ( form );
/*
XtUnmanageChild ( XtNameToWidget ( mainw, "*HorScrollBar" ) );
XtUnmanageChild ( XtNameToWidget ( mainw, "*VertScrollBar" ) );
*/
/*
* Create (but don't manage) a file selection box. This dialog will be
* used to get filenames for read and save operations.
*/
arg_count = 0;
XtSetArg ( args[ arg_count ], XmNautoUnmanage, True );
arg_count++;
filesb = XmCreateFileSelectionDialog ( toplevel,
"filesb",
args,
arg_count );
XtAddCallback ( filesb, XmNokCallback, filesbButtonCallback, (XtPointer) okButton );
XtAddCallback ( filesb, XmNcancelCallback, filesbButtonCallback, (XtPointer) cancelButton );
XtManageChild ( mainw );
}
/*
* procedure : main - The main routine. This is where it all begins.
*
* arguments : argc (in / (int)) - number of command line arguments.
* argv (in / (char **)) - pointer to the argument strings.
*
* return : (int) - status value. success/failure of program
*
* side effects : lots
*/
int main ( int argc, char *argv[] )
{
/*
* In case the app-defaults file is not there, these resources will make
* the application usable.
*/
String fallbacks[] = { "Scrolledtext*separate.shadowThickness: 3",
"Scrolledtext*separate.SeparatorType: SHADOW_ETCHED_IN_DASH",
"Scrolledtext*separate.topOffset: 5",
"Scrolledtext*scrolledtext.rows: 24",
"Scrolledtext*scrolledtext.columns: 80",
"Scrolledtext*scrolledtextSW.scrollingPolicy: AUTOMATIC",
"Scrolledtext*scrolledtextSW.visualPolicy: CONSTANT",
"Scrolledtext*scrolledtextSW.scrollBarDisplayPolicy: AS_NEEDED",
"Scrolledtext*button_1.labelString: Open",
"Scrolledtext*button_2.labelString: Save",
"Scrolledtext*button_3.labelString: Quit",
"Scrolledtext*filesb.dialogTitle: File Open/Save dialog",
(char *) NULL };
toplevel = XtAppInitialize ( &app_context, /* Application context */
"Scrolledtext", /* Application class string */
NULL, /* Options */
0, /* Number of Options */
&argc, /* Command line arg cnt in/out */
argv, /* Command line args in/out */
fallbacks, /* Fallback (last chance) resources */
NULL, /* Arguments */
0 ); /* Number of Arguments */
init_widgets (); /* Build the interface */
fileop = none; /* Currently not reading or saving any file */
XtRealizeWidget ( toplevel ); /* Realize the widgets (i.e. create
the widget data structures */
XtAppMainLoop ( app_context ); /* Jump into the main loop.
This never returns. */
}