First replicant yay

This commit is contained in:
Sasha Koshka 2023-11-13 19:05:51 -05:00
parent 55dfca6341
commit a6fa746ef3
18 changed files with 299 additions and 78 deletions

10
libXmd/include/Xmd/Dir.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _XmdDir_h
#define _XmdDir_h
#include <X11/Intrinsic.h>
/* XmdDirGetUser returns the location of the Xmd user directory, which is
located at $HOME/.Xmd */
String XmdDirGetUser ();
#endif

View File

@ -0,0 +1,12 @@
#ifndef _XmdError_h
#define _XmdError_h
typedef enum {
XmdErrorNone,
XmdErrorOutOfMemory,
XmdErrorFileNotFound,
XmdErrorCantOpenFile,
XmdErrorBadSyntax
} XmdError;
#endif

View File

@ -11,8 +11,11 @@
/* XmdReplicantState contains state information for a replicant instance. */
typedef struct _XmdReplicantState XmdReplicantState;
typedef int (*XmdReplicantVersion) ();
typedef Widget (*XmdReplicantCreate) (Widget parent, XmdReplicantState *state);
typedef int (*XmdReplicantFnVersion) ();
typedef void (*XmdReplicantFnConstruct) ();
typedef void (*XmdReplicantFnDestruct) ();
typedef Widget (*XmdReplicantFnCreate) (
Widget parent, XmdReplicantState *state);
/* XmdReplicantOpen opens a replicant from the file located at path. Replicant
files hold state and point to shared object files containing their code.
@ -36,6 +39,12 @@ typedef Widget (*XmdReplicantCreate) (Widget parent, XmdReplicantState *state);
Version must return the value of XmdREPLICANT_VERSION. This is used to detect
the API version that the replicant was compiled with, and applications with a
different API version will refuse to load it.
void NAME_XmdReplicantConstruct ();
Construct is called when the shared object is loaded.
void NAME_XmdReplicantDestruct ();
Descruct is called before the shared object is unloaded.
Widget NAME_XmdReplicantCreate (Widget parent, XmdReplicantState *state);
Create instantiates a new widget representing the replicant given by state.

8
libXmd/src/Dir.c Normal file
View File

@ -0,0 +1,8 @@
#include <Xmd/Dir.h>
#include <stdlib.h>
String XmdDirGetUser () {
String dir = NULL;
XtAsprintf(&dir, "%s/.Xmd", getenv("HOME"));
return dir;
}

View File

@ -2,6 +2,7 @@
#include <Xmd/StringMap.h>
#include <Xmd/Map.h>
#include <Xmd/Buffer.h>
#include <Xmd/Error.h>
#include <stdlib.h>
#include <stdio.h>
@ -15,8 +16,10 @@ typedef struct {
int references;
struct {
XmdReplicantVersion version;
XmdReplicantCreate create;
XmdReplicantFnVersion version;
XmdReplicantFnConstruct construct;
XmdReplicantFnDestruct destruct;
XmdReplicantFnCreate create;
} symbols;
} XmdReplicantSource;
@ -31,8 +34,8 @@ static void XmdReplicantHandleDestroy (
Widget replicant,
XtPointer clientData,
XtPointer callData);
static void XmdReplicantStateSave (XmdReplicantState *state);
static void XmdReplicantStateLoad (XmdReplicantState *state);
static XmdError XmdReplicantStateSave (XmdReplicantState *state);
static XmdError XmdReplicantStateLoad (XmdReplicantState *state);
static XmdReplicantState *XmdReplicantStateNew ();
static void XmdReplicantStateFree (XmdReplicantState *state);
static XmdReplicantSource *XmdReplicantSourceOpen (ConstString name);
@ -41,6 +44,7 @@ static XmdReplicantSource *XmdReplicantSourceGet (ConstString name);
static String XmdReplicantScanDir (
ConstString path,
ConstString name);
static void XmdReplicantEnsure ();
static const String defaultReplicantPath =
"/usr/lib/Xmd/replicants:"
@ -80,6 +84,7 @@ static void XmdReplicantHandleDestroy (
) {
(void)(replicant);
(void)(callData);
XmdReplicantEnsure();
XmdReplicantState *state = clientData;
if (state == NULL) return;
@ -104,12 +109,15 @@ String XmdReplicantResolveName (ConstString rawName) {
char ch = *list;
if (dirBuffer == NULL) dirBuffer = XmdBufferNew(char);
XmdBufferPush(dirBuffer, &ch);
if (ch == ':' || ch == 0) {
char null = 0;
XmdBufferPush(dirBuffer, &null);
String dir = XmdBufferBreak(dirBuffer);
dirBuffer = NULL;
file = XmdReplicantScanDir(dir, name);
XtFree(dir);
} else {
XmdBufferPush(dirBuffer, &ch);
}
list ++;
}
@ -172,12 +180,13 @@ static Bool writeMapValue (
return True;
}
static void XmdReplicantStateSave (XmdReplicantState *state) {
static XmdError XmdReplicantStateSave (XmdReplicantState *state) {
FILE *file = fopen(state->file, "w");
if (file == NULL) return;
if (file == NULL) return XmdErrorCantOpenFile;
fprintf(file, "[%s]\n", state->sourceName);
XmdStringMapIterate(state->map, writeMapValue, file);
fclose(file);
return XmdErrorNone;
}
static String readEscapedMapString (FILE *file, char delimiter) {
@ -208,23 +217,42 @@ static String readEscapedMapString (FILE *file, char delimiter) {
return XmdBufferBreak(string);
}
static void XmdReplicantStateLoad (XmdReplicantState *state) {
FILE *file = fopen(state->file, "w");
if (file == NULL) return;
static XmdError XmdReplicantStateLoad (XmdReplicantState *state) {
if (state->sourceName != NULL) XtFree(state->sourceName);
state->sourceName = NULL;
int ch = 0;
while (isspace((ch == fgetc(file))));
if (ch != '[') return;
FILE *file = fopen(state->file, "r");
if (file == NULL) {
return XmdErrorFileNotFound;
};
int ch = ' ';
while (isspace(ch)) ch = fgetc(file);
if (ch != '[') {
fclose(file);
return XmdErrorBadSyntax;
}
state->sourceName = readEscapedMapString(file, ']');
ch = fgetc(file);
if (ch != '\n') return;
if (ch != '\n') {
fclose(file);
return XmdErrorBadSyntax;
}
while (1) {
String key = readEscapedMapString(file, '=');
String value = readEscapedMapString(file, '\n');
XmdStringMapSet(state->map, key, value);
XtFree(key);
if (value == NULL) break;
if (value == NULL) {
if (key == NULL) {
fclose(file);
return XmdErrorNone;
} else {
fclose(file);
return XmdErrorBadSyntax;
}
}
}
}
@ -276,18 +304,30 @@ static XmdReplicantSource *XmdReplicantSourceOpen (ConstString name) {
XtFree(path);
if (source->handle == NULL) goto fail;
/* find symbols */
String versionName = NULL;
XtAsprintf(&versionName, "%s_XmdReplicantVersion", name);
source->symbols.version = (XmdReplicantVersion) (
dlsym(source->handle, versionName));
XtFree(versionName);
/* find symbols */
String symbolName = NULL;
XtAsprintf(&symbolName, "%s_XmdReplicantVersion", name);
source->symbols.version = (XmdReplicantFnVersion) (
dlsym(source->handle, symbolName));
XtFree(symbolName);
if (source->symbols.version == NULL) goto fail;
String createName = NULL;
XtAsprintf(&createName, "%s_XmdReplicantCreate", name);
source->symbols.create = (XmdReplicantCreate) (
dlsym(source->handle, createName));
XtFree(createName);
XtAsprintf(&symbolName, "%s_XmdReplicantConstruct", name);
source->symbols.construct = (XmdReplicantFnConstruct) (
dlsym(source->handle, symbolName));
XtFree(symbolName);
if (source->symbols.construct == NULL) goto fail;
XtAsprintf(&symbolName, "%s_XmdReplicantDestruct", name);
source->symbols.destruct = (XmdReplicantFnDestruct) (
dlsym(source->handle, symbolName));
XtFree(symbolName);
if (source->symbols.destruct == NULL) goto fail;
XtAsprintf(&symbolName, "%s_XmdReplicantCreate", name);
source->symbols.create = (XmdReplicantFnCreate) (
dlsym(source->handle, symbolName));
XtFree(symbolName);
if (source->symbols.create == NULL) goto fail;
/* check if the version matches */
@ -307,6 +347,8 @@ static void XmdReplicantSourceClose (XmdReplicantSource *source) {
}
static XmdReplicantSource *XmdReplicantSourceGet (ConstString name) {
XmdReplicantEnsure();
/* check to see if it has already been loaded */
XmdReplicantSource *source = XmdStringMapGet(resident, name);
if (source != NULL) return source;
@ -316,7 +358,9 @@ static XmdReplicantSource *XmdReplicantSourceGet (ConstString name) {
}
static String XmdReplicantScanDir (ConstString path, ConstString name) {
DIR *dir = opendir(path);
DIR *dir = opendir(path);
if (dir == NULL) return NULL;
String result = NULL;
while (1) {
struct dirent *entry = readdir(dir);
@ -330,3 +374,9 @@ static String XmdReplicantScanDir (ConstString path, ConstString name) {
closedir(dir);
return result;
}
static void XmdReplicantEnsure () {
if (resident == NULL) {
resident = XmdStringMapNew();
}
}

2
replicants/Launcher/build.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
../../scripts/buildreplicant.sh Launcher "$@"

View File

@ -0,0 +1,27 @@
#define unknown_width 48
#define unknown_height 48
static unsigned char unknown_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00,
0x00, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00,
0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x03, 0x00,
0x00, 0x00, 0x30, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x10, 0xe0, 0x03, 0x00,
0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00,
0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00,
0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00,
0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

View File

@ -0,0 +1,80 @@
#include <Xm/Xm.h>
#include <Xm/PushB.h>
#include <Xmd/Icon.h>
#include <Xmd/Replicant.h>
#include <stdlib.h>
#include "icons/appCalculator.xbm"
#include "icons/appEditor.xbm"
#include "icons/appFiles.xbm"
#include "icons/appMail.xbm"
#include "icons/appMusic.xbm"
#include "icons/appTerminal.xbm"
#include "icons/appWebBrowser.xbm"
#include "icons/unknown.xbm"
void activateLauncher (Widget button, XtPointer clientData, XtPointer callData) {
(void)(button);
(void)(callData);
XmdReplicantState *state = (XmdReplicantState *)(clientData);
String command = XmdReplicantStateQuery(state, "Exec");
String fullCommand = NULL;
XtAsprintf(&fullCommand, "%s &", command);
XtFree(command);
system(fullCommand);
XtFree(fullCommand);
}
int Launcher_XmdReplicantVersion () {
return XmdREPLICANT_VERSION;
}
void Launcher_XmdReplicantConstruct () {
}
void Launcher_XmdReplicantDestruct () {
}
void handleDestroyFreePixmap (
Widget replicant,
XtPointer clientData,
XtPointer callData
) {
(void)(callData);
XFreePixmap(XtDisplay(replicant), (Pixmap)(clientData));
}
Widget Launcher_XmdReplicantCreate (Widget parent, XmdReplicantState *state) {
String iconName = XmdReplicantStateQuery(state, "Icon");
Pixmap icon;
#define iconCase(name) if (strcmp(#name, iconName) == 0) {\
icon = XmdLoadBitmapIcon(parent, app##name);\
} else
iconCase(Calculator)
iconCase(Editor)
iconCase(Files)
iconCase(Mail)
iconCase(Terminal)
iconCase(WebBrowser)
iconCase(Music)
icon = XmdLoadBitmapIcon(parent, unknown);
XtFree(iconName);
Widget button = XtVaCreateManagedWidget (
"launcher", xmPushButtonWidgetClass, parent,
XmNleftAttachment, XmATTACH_FORM,
XmNlabelType, XmPIXMAP,
XmNlabelPixmap, icon,
NULL);
XtAddCallback (
button, XmNactivateCallback,
activateLauncher, (XtPointer)(state));
XtAddCallback (
button, XmNdestroyCallback,
handleDestroyFreePixmap, (XtPointer)(icon));
return button;
}

34
scripts/buildreplicant.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/sh
. `dirname $0`/flags.sh
function build() {
if
mkdir -p lib && \
cc src/*.c -o "lib/$1.so" -shared $CFLAGS
then
echo ".// ok"
return 0
else
echo "XXX FAIL!"
return 1
fi
}
function clean() {
rm -f bin/*
}
case "$2" in
install)
clean; build "$1"
mkdir -p "$PREFIX/lib/Xmd/replicants"
cp "lib/$1.so" "$PREFIX/lib/Xmd/replicants"
clean
;;
clean)
clean
;;
*)
build "$1"
esac

View File

@ -2,4 +2,4 @@
CFLAGS="-std=c99 -Wall -Wextra -Werror -fPIC"
PREFIX="/usr/local"
APP_LIBS="-lXmd -lXm -lXt -lX11"
APP_LIBS="-lXmd -lXm -lXt -lX11 -ldl"

View File

@ -2,32 +2,20 @@
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xmd/Dir.h>
#include <Xmd/Icon.h>
#include <Xmd/Replicant.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "icons/appCalculator.xbm"
#include "icons/appEditor.xbm"
#include "icons/appFiles.xbm"
#include "icons/appMail.xbm"
#include "icons/appTerminal.xbm"
#include "icons/appWebBrowser.xbm"
#include "icons/appMusic.xbm"
#include <dirent.h>
#include "icons/icon.xbm"
typedef struct {
Pixmap icon;
const char * command;
} Launcher;
void createAllLaunchers (Widget);
Widget createLauncher (Widget, Launcher);
void activateLauncher (Widget, XtPointer, XtPointer);
XtAppContext application;
static void loadReplicants (Widget parent);
int main (int argc, char *argv[]) {
Widget window = XtVaAppInitialize (
&application, "Panel",
@ -47,41 +35,42 @@ int main (int argc, char *argv[]) {
"layout", xmRowColumnWidgetClass, window,
XmNorientation, XmHORIZONTAL,
NULL);
createAllLaunchers(layout);
loadReplicants(layout);
XtManageChild(layout);
XtRealizeWidget(window);
XtAppMainLoop(application);
}
void createAllLaunchers (Widget parent) {
#define add(name, cmd) createLauncher(parent, (Launcher){\
.icon = XmdLoadBitmapIcon(parent, app##name),\
.command = cmd " &"\
} );
add(Calculator, "xcalc");
add(Editor, "nedit");
add(Files, "caja");
add(Mail, "nedit");
add(Terminal, "uxterm");
add(WebBrowser, "firefox");
add(Music, "ymuse");
#undef add
}
Widget createLauncher (Widget parent, Launcher launcher) {
Widget button = XtVaCreateManagedWidget (
"launcher", xmPushButtonWidgetClass, parent,
XmNleftAttachment, XmATTACH_FORM,
XmNlabelType, XmPIXMAP,
XmNlabelPixmap, launcher.icon,
NULL);
XtAddCallback(button, XmNactivateCallback, activateLauncher, (XtPointer)(launcher.command));
return button;
}
void activateLauncher (Widget button, XtPointer clientData, XtPointer callData) {
(void)(button);
(void)(callData);
system((char *)(clientData));
static void loadReplicants (Widget parent) {
String userDir = XmdDirGetUser();
String replicantsDir = NULL;
XtAsprintf(&replicantsDir, "%s/panel", userDir);
XtFree(userDir);
struct dirent **entries = NULL;
int entriesCount = scandir(replicantsDir, &entries, NULL, alphasort);
if (entriesCount < 0) {
XtFree(replicantsDir);
/* TODO error message */
return;
}
for (int index = 0; index < entriesCount; index ++) {
struct dirent *entry = entries[index];
String point = NULL;
if ((point = strrchr(entry->d_name,'.')) != NULL) {
if (strcmp(point, ".replicant") == 0) {
String fullName = NULL;
XtAsprintf (
&fullName, "%s/%s",
replicantsDir, entry->d_name);
XmdReplicantOpen(parent, fullName);
XtFree(fullName);
}
}
XtFree((char *)(entry));
}
XtFree((char *)(entries));
XtFree(replicantsDir);
}