Refactor replicant system a bit

This commit is contained in:
Sasha Koshka 2023-11-14 00:18:51 -05:00
parent a6fa746ef3
commit 192aa666ca
3 changed files with 64 additions and 57 deletions

View File

@ -15,7 +15,7 @@ typedef int (*XmdReplicantFnVersion) ();
typedef void (*XmdReplicantFnConstruct) (); typedef void (*XmdReplicantFnConstruct) ();
typedef void (*XmdReplicantFnDestruct) (); typedef void (*XmdReplicantFnDestruct) ();
typedef Widget (*XmdReplicantFnCreate) ( typedef Widget (*XmdReplicantFnCreate) (
Widget parent, XmdReplicantState *state); XtAppContext application, Widget parent, XmdReplicantState *state);
/* XmdReplicantOpen opens a replicant from the file located at path. Replicant /* XmdReplicantOpen opens a replicant from the file located at path. Replicant
files hold state and point to shared object files containing their code. files hold state and point to shared object files containing their code.
@ -41,15 +41,16 @@ typedef Widget (*XmdReplicantFnCreate) (
different API version will refuse to load it. different API version will refuse to load it.
void NAME_XmdReplicantConstruct (); void NAME_XmdReplicantConstruct ();
Construct is called when the shared object is loaded. Optional. Construct is called when the shared object is loaded.
void NAME_XmdReplicantDestruct (); void NAME_XmdReplicantDestruct ();
Descruct is called before the shared object is unloaded. Optional. Descruct is called before the shared object is unloaded.
Widget NAME_XmdReplicantCreate (Widget parent, XmdReplicantState *state); Widget NAME_XmdReplicantCreate (
XtAppContext application, Widget parent, XmdReplicantState *state);
Create instantiates a new widget representing the replicant given by state. Create instantiates a new widget representing the replicant given by state.
*/ */
Widget XmdReplicantOpen (Widget parent, ConstString path); Widget XmdReplicantOpen (XtAppContext app, Widget parent, ConstString path);
/* XmdReplicantResolveName returns the file path of the given replicant shared /* XmdReplicantResolveName returns the file path of the given replicant shared
object name according to $XMD_REPLICANT_PATH. The returned string must be object name according to $XMD_REPLICANT_PATH. The returned string must be

View File

@ -21,80 +21,81 @@ typedef struct {
XmdReplicantFnDestruct destruct; XmdReplicantFnDestruct destruct;
XmdReplicantFnCreate create; XmdReplicantFnCreate create;
} symbols; } symbols;
} XmdReplicantSource; } replicantSource;
struct _XmdReplicantState { struct _XmdReplicantState {
String file; String file;
String sourceName; String sourceName;
XmdReplicantSource *source; replicantSource *source;
XmdStringMap *map; XmdStringMap *map;
}; };
static void XmdReplicantHandleDestroy ( /* internal function prototypes */
Widget replicant, static void handleDestroy (Widget, XtPointer, XtPointer);
XtPointer clientData, static XmdError stateSave (XmdReplicantState *state);
XtPointer callData); static XmdError stateLoad (XmdReplicantState *state);
static XmdError XmdReplicantStateSave (XmdReplicantState *state); static XmdReplicantState *stateNew ();
static XmdError XmdReplicantStateLoad (XmdReplicantState *state); static void stateFree (XmdReplicantState *state);
static XmdReplicantState *XmdReplicantStateNew (); static replicantSource *sourceOpen (ConstString name);
static void XmdReplicantStateFree (XmdReplicantState *state); static void sourceClose (replicantSource *source);
static XmdReplicantSource *XmdReplicantSourceOpen (ConstString name); static replicantSource *sourceGet (ConstString name);
static void XmdReplicantSourceClose (XmdReplicantSource *source); static String scanDir (ConstString path, ConstString name);
static XmdReplicantSource *XmdReplicantSourceGet (ConstString name); static void ensure ();
static String XmdReplicantScanDir ( static String readEscapedMapString (FILE *, char);
ConstString path, static void writeEscapedMapString (FILE *, ConstString);
ConstString name); static Bool freeMapValue (XmdStringMap *, ConstString, void *, void *);
static void XmdReplicantEnsure (); static Bool writeMapValue (XmdStringMap *, ConstString, void *, void *);
/* resident maps source names to source structs */
static XmdStringMap *resident = NULL;
static const String defaultReplicantPath = static const String defaultReplicantPath =
"/usr/lib/Xmd/replicants:" "/usr/local/lib/Xmd/replicants:"
"/usr/local/lib/Xmd/replicants"; "/usr/lib/Xmd/replicants";
static XmdStringMap *resident = NULL; /* source names to source structs */
Widget XmdReplicantOpen (Widget parent, ConstString path) { Widget XmdReplicantOpen (XtAppContext app, Widget parent, ConstString path) {
/* create and load the state */ /* create and load the state */
XmdReplicantState *state = XmdReplicantStateNew(); XmdReplicantState *state = stateNew();
if (state == NULL) goto fail; if (state == NULL) goto fail;
state->file = XtNewString(path); state->file = XtNewString(path);
if (state->file == NULL) goto fail; if (state->file == NULL) goto fail;
XmdReplicantStateLoad(state); stateLoad(state);
/* retrieve the replicant's source */ /* retrieve the replicant's source */
XmdReplicantSource *source = XmdReplicantSourceGet(state->sourceName); replicantSource *source = sourceGet(state->sourceName);
if (source == NULL) goto fail; if (source == NULL) goto fail;
source->references ++; source->references ++;
state->source = source; state->source = source;
/* create replicant and bind its state */ /* create replicant and bind its state */
Widget replicant = source->symbols.create(parent, state); Widget replicant = source->symbols.create(app, parent, state);
XtAddCallback ( XtAddCallback (
replicant, XmNdestroyCallback, replicant, XmNdestroyCallback,
XmdReplicantHandleDestroy, state); handleDestroy, state);
return replicant; return replicant;
fail: fail:
XmdReplicantStateFree(state); stateFree(state);
return NULL; return NULL;
} }
static void XmdReplicantHandleDestroy ( static void handleDestroy (
Widget replicant, Widget replicant,
XtPointer clientData, XtPointer clientData,
XtPointer callData XtPointer callData
) { ) {
(void)(replicant); (void)(replicant);
(void)(callData); (void)(callData);
XmdReplicantEnsure(); ensure();
XmdReplicantState *state = clientData; XmdReplicantState *state = clientData;
if (state == NULL) return; if (state == NULL) return;
state->source->references --; state->source->references --;
if (state->source->references < 1) { if (state->source->references < 1) {
XmdReplicantSourceClose ( sourceClose (
XmdStringMapSet(resident, state->sourceName, NULL)); XmdStringMapSet(resident, state->sourceName, NULL));
} }
XmdReplicantStateFree(state); stateFree(state);
} }
String XmdReplicantResolveName (ConstString rawName) { String XmdReplicantResolveName (ConstString rawName) {
@ -114,7 +115,7 @@ String XmdReplicantResolveName (ConstString rawName) {
XmdBufferPush(dirBuffer, &null); XmdBufferPush(dirBuffer, &null);
String dir = XmdBufferBreak(dirBuffer); String dir = XmdBufferBreak(dirBuffer);
dirBuffer = NULL; dirBuffer = NULL;
file = XmdReplicantScanDir(dir, name); file = scanDir(dir, name);
XtFree(dir); XtFree(dir);
} else { } else {
XmdBufferPush(dirBuffer, &ch); XmdBufferPush(dirBuffer, &ch);
@ -135,7 +136,7 @@ void XmdReplicantStateStore (
) { ) {
String old = XmdStringMapSet(state->map, name, XtNewString(value)); String old = XmdStringMapSet(state->map, name, XtNewString(value));
XtFree(old); XtFree(old);
XmdReplicantStateSave(state); stateSave(state);
} }
static void writeEscapedMapString (FILE *file, ConstString string) { static void writeEscapedMapString (FILE *file, ConstString string) {
@ -180,7 +181,7 @@ static Bool writeMapValue (
return True; return True;
} }
static XmdError XmdReplicantStateSave (XmdReplicantState *state) { static XmdError stateSave (XmdReplicantState *state) {
FILE *file = fopen(state->file, "w"); FILE *file = fopen(state->file, "w");
if (file == NULL) return XmdErrorCantOpenFile; if (file == NULL) return XmdErrorCantOpenFile;
fprintf(file, "[%s]\n", state->sourceName); fprintf(file, "[%s]\n", state->sourceName);
@ -217,7 +218,7 @@ static String readEscapedMapString (FILE *file, char delimiter) {
return XmdBufferBreak(string); return XmdBufferBreak(string);
} }
static XmdError XmdReplicantStateLoad (XmdReplicantState *state) { static XmdError stateLoad (XmdReplicantState *state) {
if (state->sourceName != NULL) XtFree(state->sourceName); if (state->sourceName != NULL) XtFree(state->sourceName);
state->sourceName = NULL; state->sourceName = NULL;
@ -256,7 +257,7 @@ static XmdError XmdReplicantStateLoad (XmdReplicantState *state) {
} }
} }
static XmdReplicantState *XmdReplicantStateNew () { static XmdReplicantState *stateNew () {
XmdReplicantState *state = XtNew(XmdReplicantState); XmdReplicantState *state = XtNew(XmdReplicantState);
if (state == NULL) return NULL; if (state == NULL) return NULL;
@ -266,7 +267,7 @@ static XmdReplicantState *XmdReplicantStateNew () {
return state; return state;
fail: fail:
XmdReplicantStateFree(state); stateFree(state);
return NULL; return NULL;
} }
@ -282,7 +283,7 @@ static Bool freeMapValue (
return True; return True;
} }
static void XmdReplicantStateFree (XmdReplicantState *state) { static void stateFree (XmdReplicantState *state) {
if (state == NULL) return; if (state == NULL) return;
XtFree(state->file); XtFree(state->file);
XtFree(state->sourceName); XtFree(state->sourceName);
@ -291,11 +292,11 @@ static void XmdReplicantStateFree (XmdReplicantState *state) {
XtFree((char *)(state)); XtFree((char *)(state));
} }
static XmdReplicantSource *XmdReplicantSourceOpen (ConstString name) { static replicantSource *sourceOpen (ConstString name) {
/* allocate */ /* allocate */
XmdReplicantSource *source = XtNew(XmdReplicantSource); replicantSource *source = XtNew(replicantSource);
if (source == NULL) goto fail; if (source == NULL) goto fail;
memset(source, 0, sizeof(XmdReplicantSource)); memset(source, 0, sizeof(replicantSource));
/* open library */ /* open library */
String path = XmdReplicantResolveName(name); String path = XmdReplicantResolveName(name);
@ -316,13 +317,11 @@ static XmdReplicantSource *XmdReplicantSourceOpen (ConstString name) {
source->symbols.construct = (XmdReplicantFnConstruct) ( source->symbols.construct = (XmdReplicantFnConstruct) (
dlsym(source->handle, symbolName)); dlsym(source->handle, symbolName));
XtFree(symbolName); XtFree(symbolName);
if (source->symbols.construct == NULL) goto fail;
XtAsprintf(&symbolName, "%s_XmdReplicantDestruct", name); XtAsprintf(&symbolName, "%s_XmdReplicantDestruct", name);
source->symbols.destruct = (XmdReplicantFnDestruct) ( source->symbols.destruct = (XmdReplicantFnDestruct) (
dlsym(source->handle, symbolName)); dlsym(source->handle, symbolName));
XtFree(symbolName); XtFree(symbolName);
if (source->symbols.destruct == NULL) goto fail;
XtAsprintf(&symbolName, "%s_XmdReplicantCreate", name); XtAsprintf(&symbolName, "%s_XmdReplicantCreate", name);
source->symbols.create = (XmdReplicantFnCreate) ( source->symbols.create = (XmdReplicantFnCreate) (
@ -333,31 +332,33 @@ static XmdReplicantSource *XmdReplicantSourceOpen (ConstString name) {
/* check if the version matches */ /* check if the version matches */
if (source->symbols.version() != XmdREPLICANT_VERSION) goto fail; if (source->symbols.version() != XmdREPLICANT_VERSION) goto fail;
if (source->symbols.construct != NULL) source->symbols.construct();
return source; return source;
fail: fail:
XmdReplicantSourceClose(source); sourceClose(source);
return NULL; return NULL;
} }
static void XmdReplicantSourceClose (XmdReplicantSource *source) { static void sourceClose (replicantSource *source) {
if (source == NULL) return; if (source == NULL) return;
if (source->symbols.destruct != NULL) source->symbols.destruct();
if (source->handle != NULL) dlclose(source->handle); if (source->handle != NULL) dlclose(source->handle);
XtFree((char *)(source)); XtFree((char *)(source));
} }
static XmdReplicantSource *XmdReplicantSourceGet (ConstString name) { static replicantSource *sourceGet (ConstString name) {
XmdReplicantEnsure(); ensure();
/* check to see if it has already been loaded */ /* check to see if it has already been loaded */
XmdReplicantSource *source = XmdStringMapGet(resident, name); replicantSource *source = XmdStringMapGet(resident, name);
if (source != NULL) return source; if (source != NULL) return source;
/* open the source */ /* open the source */
return XmdReplicantSourceOpen(name); return sourceOpen(name);
} }
static String XmdReplicantScanDir (ConstString path, ConstString name) { static String scanDir (ConstString path, ConstString name) {
DIR *dir = opendir(path); DIR *dir = opendir(path);
if (dir == NULL) return NULL; if (dir == NULL) return NULL;
@ -375,7 +376,7 @@ static String XmdReplicantScanDir (ConstString path, ConstString name) {
return result; return result;
} }
static void XmdReplicantEnsure () { static void ensure () {
if (resident == NULL) { if (resident == NULL) {
resident = XmdStringMapNew(); resident = XmdStringMapNew();
} }

View File

@ -47,7 +47,11 @@ void handleDestroyFreePixmap (
XFreePixmap(XtDisplay(replicant), (Pixmap)(clientData)); XFreePixmap(XtDisplay(replicant), (Pixmap)(clientData));
} }
Widget Launcher_XmdReplicantCreate (Widget parent, XmdReplicantState *state) { Widget Launcher_XmdReplicantCreate (
XtAppContext application,
Widget parent,
XmdReplicantState *state,
) {
String iconName = XmdReplicantStateQuery(state, "Icon"); String iconName = XmdReplicantStateQuery(state, "Icon");
Pixmap icon; Pixmap icon;
#define iconCase(name) if (strcmp(#name, iconName) == 0) {\ #define iconCase(name) if (strcmp(#name, iconName) == 0) {\
@ -61,6 +65,7 @@ Widget Launcher_XmdReplicantCreate (Widget parent, XmdReplicantState *state) {
iconCase(WebBrowser) iconCase(WebBrowser)
iconCase(Music) iconCase(Music)
icon = XmdLoadBitmapIcon(parent, unknown); icon = XmdLoadBitmapIcon(parent, unknown);
#undef iconCase
XtFree(iconName); XtFree(iconName);