fcaggian@kepler.com (Frank Caggiano) (11/22/90)
1) Intro
I have enclosed code for eiffel which implements the resource
mangment concept used in X. This class will allow the application to
parse the comand line, get application defaults from a file and use
resources attached to the server (via xrdb). It uses the same format
as X (resource seperator resource: value). As explained in section 2
below some modification to the standard graphic classes is required
to make maximum use of this.
My configuration is Sun Sparc running 4.0.3c, X11R4 and Eiffel
2.3.4. I have not tested this code on any other system. (however I
did start developing this under 2.2 and it did work).
Also note while this all works here I don't consider it as
finished code. I present it more as a starting point for discussions
concerning eiffel code and codeing practices. Specifically just how
much modification of the standard ISE distribution is acceptable.
While I would be very hesitant to modify the kernel, support and even
the structures libraries I feel the graphics library is far game. How
are others using the graphics library?
As an aside to Mr. Johnson who said that his company would not
allow him to post source for fear of losing 'competitive advantage'.
It seems to me that with a technology as new as this the amount of
information you stand to gain by seeing what others are doing and by
having what you are doing examined by others far outweighs any lost
you would incure. Of course one could just sit back and examine what
others post without posting but that wouldn't really be cricket, would
it. :-) .
2) Use
In order to make the most use of class RESOURCE it is necesary
to modifiy a few of the standard ISE graphic classes.
I wanted to accomplish the automatic creation of the resource
databases at the time is was needed. The normal procedure in X is to
first parse the command line to get the display variable if specified,
open the display and then merge the rest of the resource options into
one database.
The way I accomplished this was to add `resource' as an
attribute of DEVICE and to add Resource as a once funtion to DEV_CONST
(just as Black_color is now). I then modified the create procedure
for DEVICE to first call resource.create. This parses the command
line and sets up the display name. I also modified device_imp and the
x device open in window_x.c to use the display name. After the open
merge is called on Resource to setup the application database.
By installing it this way it doesn't matter in what order you
access the device or resources. If you decide not to install it this
way remember that merge must be called after the device is opened (it
needs the x handle of the display).
Once all this is accomplised it is possible to get the
resource values by calls to resource.get("name"). So given an object
which inherited from DEV_CONST it is possible to set its resources by
calls such as:
if Resource.get(".font") = true then
set_font(Resource.value)
else
set_font(whatever);
end;
Or using the Xt idea lets say something like (for a command button):
if Resource.get("*cmdbut.select_color") == true then
.... etc
end;
if Resource.get("*cmdbut.font") == true then
.......
end;
3) Open Issues
The application porgramer needs to create a C file with the
option table array and size (see example at end) run cc -c on the file and
specify the .o file in the .eiffel file on the EXTERNAL line. I
couldn't think of a good way to put this knowladge into eiffel. If
anyone has any ideas I'd like ot hear from you. I would like to get
this into eiffel possibly bypassing ParseCmd altogether and parsing
the command line internally.
If you use this class you shouldn't use the ARGUMENTS
class in the same system, they will probably conflict.
The resource looked up is limited. By this I mean the resource
name and its class (the x class) are identical. Xt allows for classes
and names to be different so that for example you can ask for
emacs.font and Editors.Fonts. So if a specific font is not set for
emacs you get the fonts used by editors.
If anyone makes use of this I would appreciate hearing from
you. Also if you have nay suggestions or enhancments let me know.
I have been specifically vague about how to modify the ISE
classes to hook this in tight. I am not sure of the possible
consequences of telling people how to do this. The changes are fairly
simple if you have been poking around the graphics library.
-----------------------------------------------------------------------
Frank Caggiano INTERNET: fcaggian@kepler.com
Kepler Financial Management, Ltd. UUCP: ..!uunet!kepler1!fcaggian
100 North Country Rd. fax: (516) 751-8678
Setauket, NY 11733 voice: (516) 689-6300
-----------------------------------------------------------------------
--
-- class RESOURCE
-- Managed X options and resources.
--
-- Copyright (c) 1990 Kepler Financial Mgmt.
--
-- Permission is granted to anyone to make or distribute
-- copies of this software provided that the
-- copyright notice and this permission notice are preserved.
-- Ownership remains with Kepler Financial Mgmt.
--
-- Frank Caggiano
-- Tue Nov 19 13:12:08 EST 1990
--
class RESOURCE export
value, get, set_xclass_name, other_args,
parse_geometry, width_hint, height_hint, x_hint, y_hint,
Xdisplay, Application_name, Xclass_name,
set_application_name, set_other_args,
merge,
create_other_arg_array
inherit
BASIC_ROUT;
EXCEPTIONS
feature
--
-- The first three should probably go into a CONST file
--
Env_display: STRING is "DISPLAY";
-- For getenv call to get display name.
Resource_display: STRING is ".display";
-- For resource lookup of display name.
Apps_db_dir: STRING is "/usr/lib/X11/app-defaults";
-- Directory of application resource files.
value: STRING;
-- last resource gotten from db with get_resource.
Xdisplay: STRING;
-- X display string used in Xopen call.
Application_name: STRING;
-- argv[0] of command minus leading directory pathnames.
-- Set by x_parse_command.
Xclass_name: STRING;
-- X class name for resource managment. First character is
-- uppercase.
set_xclass_name (xc: STRING) is
-- set x class name. Set first character of name to upper case.
require
a_class: not s.void
local
a: ASCII;
c: CHARACTER;
s: STRING;
do
s := xc.duplicate;
a.Create;
if s.item_code(1) >= a.Lower_a and s.item_code(1) <= a.Lower_z then
c := charconv(s.item_code(1) - 32);
s.put(c,1);
end;
Xclass_name := s;
ensure
Xclass_name = s
end;
application_db: INTEGER;
-- DB of final merged application resources.
other_args: ARRAY[STRING];
-- Any command line arguments not parsed by the X routines are
-- placed here.
Create is
-- Read in options from command line. Get display variable for xopen.
-- The addresses of the routines are passed so that they will not be
-- optimized out if creating a C_PACKAGE.
external
x_parse_command: INTEGER language "C";
x_get_resource: STRING language "C";
getenv: INTEGER language "C"
local
c_ptr: INTEGER;
do
application_db := x_parse_command( Current,
@set_application_name,
@create_other_arg_array,
@set_other_args
);
set_xclass_name(Application_name.duplicate);
if application_db /= 0 then
Xdisplay := x_get_resource ( application_db,
Application_name.to_c,
Xclass_name.to_c,
Resource_display.to_c
);
end;
if Xdisplay.void then
c_ptr := getenv(Env_display.to_c);
if c_ptr = 0 then
raise ("failure to get Xdisplay name");
else
Xdisplay.Create(1);
Xdisplay.from_c(c_ptr);
end;
end;
end;
--
-- If you do not modify the ISE classes to use RESOURCE's. change
-- merge so that it doesn't require the xdevice and change the call to
-- x_merger_db(), remove xdevice. Then see xresource.c
--
merge (xdevice: INTEGER) is
-- Merge all resource DB into apllication_db.
require
xdevice_realized: xdevice /= 0
external
x_merge_db: INTEGER language "C"
do
Apps_db_dir.extend('/');
if Xclass_name.void then
Apps_db_dir.append("Eiffel")
else
Apps_db_dir.append(Xclass_name);
end;
application_db := x_merge_db(xdevice, Apps_db_dir.to_c);
end;
get(resource: STRING): BOOLEAN is
-- Get the 'resource' from the application db.
-- Return true if found.
require
db_open: application_db /= 0;
valid_res: not resource.void
external
x_get_resource: STRING language "C"
do
value := x_get_resource( application_db,
Application_name.to_c,
Xclass_name.to_c ,
resource.to_c
);
if not value.void then
Result := true
end;
end;
parse_geometry(geos: STRING) is
require
a_geometry: not geos.void
external
x_parse_geometry language "C"
do
-- NOT implemented yet
end;
width_hint, height_hint: INTEGER;
-- From resource DB. Requested widht and height.
-- set by parse_geometry.
x_hint, y_hint: INTEGER;
-- From resource DB. Requested x,y position.
-- set by parse_geometry.
--
-- Private routines for the "C" "X" interface.
-- These routines are only used by external C code.
--
set_application_name (s: STRING) is
-- Used by c routine x_parse_command
require
an_application: not s.void
do
Application_name := s
ensure
Application_name = s
end;
create_other_arg_array(cnt: INTEGER) is
-- Used by C routine x_parse_command.
require
valid_count: cnt > 0
do
other_args.Create(1,cnt);
ensure
not other_args.void;
other_args.count = cnt
end;
set_other_args(arg: STRING; cnt: INTEGER) is
-- Used by C routine x_parse_command.
require
arg_realized: not other_args.void and not arg.void;
valid_cnt: cnt > 0 and cnt <= other_args.count
do
other_args.put(arg, cnt)
end;
end; -- class RESOURCE
-- Begin xresource.c --
#ifndef lint
static char *sccsid = "@(#)xresource,c:1.3 11/17/90";
#endif
/*
-- Copyright (c) 1990 Kepler Financial Mgmt.
--
-- Permission is granted to anyone to make or distribute
-- copies of this software provided that the
-- copyright notice and this permission notice are preserved.
-- Ownership remains with Kepler Financial Mgmt.
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include "/usr/local/Eiffel/files/_eiffel.h"
/*
* These are defined by the applications programmer in a seperate .o file
* and linked it at compile time. (Some day, hopefully they will be put into
* eiffel).
*/
extern XrmOptionDescRec opTable[]; /* X option table. command line args to parse */
extern int opTableEntries; /* Number of entries in above */
static XrmDatabase finalDB, cmdDB; /* Private */
x_parse_command(current, set_app_name, create_arg_array, set_args)
OBJPTR current;
ROUT_PTR set_app_name, create_arg_array, set_args;
{
ROUT_PTR tmp;
OBJPTR obj;
char **argv_get(), *rindex(), **cp, *s, *args[20];
int n, cnt;
n = argc_get(); /* from Eiffel runtime lib; original argc count */
cp = argv_get(); /* from Eiffel runtime lib; orignal argv array */
for(cnt = 0; cnt < n; cnt++)
args[cnt] = *(cp + cnt);
args[cnt] = 0;
XrmInitialize(); /* Open X data base routiines */
XrmParseCommand(&cmdDB, opTable, opTableEntries, args[0], &n, args); /* Xlib call */
/*
* Set the command name of the application .....
*/
if((s = rindex(*cp,'/')) != NULL) /* argv[0] has pathname, strip it */
s++;
else
s = *cp;
obj = (OBJPTR) eif_create("string",strlen(s) + 1);
tmp = (ROUT_PTR) eif_rout(obj,"from_c");
(*tmp) (obj, s);
(*set_app_name) (current, obj);
/*
* Now set up to send back unparsed command line args.
*
* Create other_arg array in RESOURCE with a size of 'n' ; then
* loop through the arguments creating a string object for each, copying in the
* argument and linking the STRING into the array.
*/
if (n > 1) {
(*create_arg_array) (current, n - 1);
for(cnt = 1; cnt < n ; cnt++) {
obj = (OBJPTR) eif_create("string", strlen(args[cnt] + 1) );
tmp = (ROUT_PTR) eif_rout(obj,"from_c");
(*tmp) (obj, args[cnt]);
(*set_args) (current, obj, cnt);
}
}
return(1);
}
/*
* Get the requested 'resource' for application 'name' and 'class' from the X database 'db'.
*
* Return a string object containing the resource or VOID object if not found.
*/
OBJPTR x_get_resource(db, name, class, resource)
int db;
char *name, *class, *resource;
{
XrmValue value;
char *str_type[20], hold[80];
char _name[50], _class[50];
OBJPTR obj;
ROUT_PTR tmp;
strcpy(_name,name); /* for db access */
strcat(_name,resource);
strcpy(_class,class);
strcat(_class,resource);
obj = 0;
if(db == 1)
db = XrmGetResource(cmdDB, _name, _class, str_type, &value);
else
db = XrmGetResource(finalDB, _name, _class, str_type, &value);
if(db == True) {
strncpy(hold,value.addr,(int)value.size);
hold[(int)value.size] = '\0';
obj = (OBJPTR) eif_create("string",(int)value.size + 1);
tmp = (ROUT_PTR) eif_rout(obj,"from_c");
(*tmp) (obj, hold);
}
return(obj);
}
/*
* Merge all resource databases into on application database.
* Return the final database.
*
* For now we merge in: (in this order)
* 1) the application file 'appsFile'.
* 2) The resources in the server 'xdevice'.
* 3) THe command line arguments.
*
* The users .Xdefault file is not currentlly done.
*/
#ifdef notmodified
/*
* If you chose not to modify the ISE graphic classes to use resource
* this should work. It is untested in the non-modified position.
*/
extern Display *X_display;
x_merge_db(appsFile)
#else
x_merge_db(X_display, appsFile)
Display *X_display;
#endif
char *appsFile;
{
XrmDatabase fDB, ffDB, XrmGetFileDatabase(), XrmGetStringDatadase();
if ((fDB = XrmGetFileDatabase (appsFile)) != NULL)
XrmMergeDatabases(fDB,&finalDB);
if(X_display->xdefaults != NULL) {
if((ffDB = XrmGetStringDatabase(xdevice->xdefaults)) != NULL)
XrmMergeDatabases(ffDB,&finalDB);
}
XrmMergeDatabases(cmdDB, &finalDB);
return (2);
}
x_parse_geometry(obj, s)
OBJPTR obj;
char *s;
{
}
-- Sample command line options file --
/*
* aplication agument table
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
int opTableEntries = 10;
XrmOptionDescRec opTable[] = {
{ "-bg", "*background", XrmoptionSepArg, (caddr_t) NULL},
{ "-bitmap", ".bitmap", XrmoptionSepArg, (caddr_t) NULL},
{ "-display", ".display", XrmoptionSepArg, (caddr_t) NULL},
{ "-fg", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
{ "-fn", "*font", XrmoptionSepArg, (caddr_t) NULL},
{ "-m", ".mon", XrmoptionSepArg, (caddr_t) NULL},
{ "-y", ".yr", XrmoptionSepArg, (caddr_t) NULL},
{ "-tri", ".tri*background", XrmoptionSepArg, (caddr_t) NULL},
{ "-sq", ".sq.background", XrmoptionSepArg, (caddr_t) NULL},
{ "=", "*geometry", XrmoptionIsArg, (caddr_t) NULL},
};
--
Frank Caggiano INTERNET: fcaggian@kepler.com
Kepler Financial Management, Ltd. UUCP: ..!uunet!kepler1!fcaggian
100 North Country Rd. fax: (516) 751-8678
Sekauket, NY 11733 voice: (516) 689-6300 fcaggian@kepler.com (Frank Caggiano) (11/29/90)
There is a bug in xresource.c which prevents the command line
from being parsed if a program is run using a leading path. To correct
this problem do:
In xresource.c move the call to XrmParseCommand() to AFTER the
test of argv[0] for a leading path.
In the call to XrmParseCommand(), replace argv[0] with s;
The code should look like this:
XrmInitialize(); /* Open X data base routiines */
/*
* Set the command name of the application .....
*/
if((s = rindex(*cp,'/')) != NULL) /* argv[0] has pathname, strip it */
s++;
else
s = *cp;
XrmParseCommand(&cmdDB, opTable, opTableEntries, s, &n, args); /* Xlib call */
Recompile and relink.
Frank Caggiano
--
Frank Caggiano INTERNET: fcaggian@kepler.com
Kepler Financial Management, Ltd. UUCP: ..!uunet!kepler1!fcaggian
100 North Country Rd. fax: (516) 751-8678
Sekauket, NY 11733 voice: (516) 689-6300 fcaggian@kepler.com (Frank Caggiano) (11/29/90)
I removed the geometry parsing from resource.e and xresource.c
and made it a seperate class.
Not sure if sending the address of the integers to
XParseGeometry using the '@' operator is considered ok. It works here.
Anyone have any comments?
This is useable without modification to any of the standard ISE
classes. Setting x and y in the root window before the first display
will position the window on the screen. Also the screen size is
avaliable in Device.width and Device.height to allow for relative
positioning from the right or bottom edge of the screen.
If you use this remove parse_geometry from resource.e.
--
-- class GEOMETRY
-- class for parsing the X geometry string.
--
-- Copyright (c) Kepler Financial Mgmt.
--
-- Frank Caggiano
-- Tue Nov 6 13:12:08 EST 1990
--
class GEOMETRY export
parse_geometry, width_hint, height_hint, x_hint, y_hint,
feature
parse_geometry(geos: STRING) is
-- parse X geometry string in the form:
-- =<width>x<height>{+-}<xoffset>{+-}<yoffset>
require
a_geometry: not geos.void
external
x_parse_geometry:INTEGER name "XParseGeometry" language "C"
local
x: INTEGER
do
x := x_parse_geometry(geos.to_c, @x_hint, @y_hint,
@width_hint, @height_hint);
end; -- Create
width_hint, height_hint: INTEGER;
-- From parsed string, width and height values.
x_hint, y_hint: INTEGER;
-- From parse stringd, x,y screen position.
end; -- GEOMETRY
--
Frank Caggiano INTERNET: fcaggian@kepler.com
Kepler Financial Management, Ltd. UUCP: ..!uunet!kepler1!fcaggian
100 North Country Rd. fax: (516) 751-8678
Sekauket, NY 11733 voice: (516) 689-6300