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