XmShelf stub
This commit is contained in:
parent
b3b86808ea
commit
58ef75e455
2
xmshelf/build.sh
Executable file
2
xmshelf/build.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
../scripts/buildapp.sh xmshell "$@"
|
27
xmshelf/src/icons/icon.xbm
Normal file
27
xmshelf/src/icons/icon.xbm
Normal file
@ -0,0 +1,27 @@
|
||||
#define icon_width 48
|
||||
#define icon_height 48
|
||||
static unsigned char icon_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0c, 0x1e, 0x00, 0xf0, 0x03, 0x30,
|
||||
0xfc, 0xf3, 0xff, 0x0f, 0xfc, 0x3f, 0x0c, 0x09, 0x00, 0xf2, 0x13, 0x30,
|
||||
0xfc, 0xf9, 0xff, 0x0d, 0xec, 0x3f, 0x0c, 0x09, 0x80, 0x02, 0x50, 0x30,
|
||||
0xfc, 0xf9, 0xff, 0x02, 0xd0, 0x3f, 0x8c, 0x04, 0x40, 0x01, 0xa6, 0x30,
|
||||
0xfc, 0xfc, 0x7f, 0x81, 0xa1, 0x3f, 0x8c, 0xfc, 0x4f, 0xe1, 0xa0, 0x30,
|
||||
0xfc, 0x04, 0x78, 0x41, 0xa0, 0x3f, 0x4c, 0x06, 0x48, 0x41, 0xa0, 0x30,
|
||||
0x7c, 0x06, 0x78, 0x81, 0xa0, 0x3f, 0x4c, 0x06, 0x88, 0x82, 0x50, 0x30,
|
||||
0x7c, 0x06, 0xf8, 0x03, 0xf0, 0x3f, 0x2c, 0x05, 0x28, 0x0c, 0x0c, 0x31,
|
||||
0x3c, 0x07, 0x38, 0xf0, 0x03, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0xac, 0x00, 0x00, 0x00, 0x00, 0x35, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0c, 0x00, 0x00, 0x22, 0x00, 0x30,
|
||||
0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0c, 0x00, 0x00, 0x7f, 0x00, 0x30,
|
||||
0xfc, 0xff, 0xff, 0xc1, 0xff, 0x3f, 0xcc, 0x3f, 0x00, 0x41, 0x3e, 0x31,
|
||||
0x7c, 0xc0, 0xff, 0xe3, 0x23, 0x3f, 0x4c, 0xc0, 0x1f, 0x14, 0x22, 0x31,
|
||||
0x7c, 0x00, 0xf0, 0xf7, 0x23, 0x31, 0x4c, 0x00, 0xf0, 0x94, 0x22, 0x31,
|
||||
0x7c, 0x00, 0xd0, 0xf7, 0x22, 0x31, 0x4c, 0x00, 0xf0, 0x94, 0x22, 0x31,
|
||||
0x7c, 0x00, 0xd0, 0xf7, 0xe2, 0x31, 0x4c, 0x00, 0xf0, 0x94, 0x22, 0x3f,
|
||||
0x7c, 0x00, 0xd0, 0xf7, 0x36, 0x31, 0x4c, 0xff, 0xf7, 0x94, 0x22, 0x31,
|
||||
0x7c, 0x00, 0xd0, 0xf7, 0x22, 0x31, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0xac, 0x00, 0x00, 0x00, 0x00, 0x35, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0xcc, 0xff, 0xff, 0xff, 0xff, 0x33, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
336
xmshelf/src/main.c
Normal file
336
xmshelf/src/main.c
Normal file
@ -0,0 +1,336 @@
|
||||
#define _XOPEN_SOURCE
|
||||
#include <Xm/Xm.h>
|
||||
#include <Xm/Form.h>
|
||||
#include <Xm/PushB.h>
|
||||
#include <Xm/MainW.h>
|
||||
#include <Xm/IconG.h>
|
||||
#include <Xm/Container.h>
|
||||
#include <Xm/ScrolledW.h>
|
||||
|
||||
#include <Xmd/Icon.h>
|
||||
#include <Xmd/Exec.h>
|
||||
#include <Xmd/Buffer.h>
|
||||
#include <Xmd/StringMap.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "icons/icon.xbm"
|
||||
|
||||
XtAppContext application;
|
||||
typedef enum {
|
||||
DeviceKindGeneric,
|
||||
DeviceKindDisk,
|
||||
DeviceKindRom,
|
||||
DeviceKindFilesystem,
|
||||
DeviceKindTTY
|
||||
} DeviceKind;
|
||||
|
||||
typedef struct {
|
||||
Widget widget;
|
||||
DeviceKind kind;
|
||||
Bool orphaned;
|
||||
String name;
|
||||
String mountPoint;
|
||||
String label;
|
||||
} Device;
|
||||
|
||||
void loadIconPixmaps (void);
|
||||
void refreshDevices (void);
|
||||
void refreshDisks (void);
|
||||
Device * DeviceNew (String name, DeviceKind kind);
|
||||
void DeviceDelete (ConstString name);
|
||||
void DeviceFree (Device *this);
|
||||
void DeviceSetKind (Device *this, DeviceKind kind);
|
||||
void DeviceSetMountPoint (Device *this, ConstString mountPoint);
|
||||
void DeviceSetLabel (Device *this, ConstString label);
|
||||
int readBlockDevice (FILE *stream, Device **);
|
||||
int readLsblkPair (FILE *stream, String *key, String *value);
|
||||
void handleRefresh (Widget, XtPointer, XtPointer);
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
devices = XmdStringMapNew();
|
||||
|
||||
Widget window = XtVaAppInitialize (
|
||||
&application, "Shelf",
|
||||
NULL, 0,
|
||||
&argc, argv,
|
||||
NULL,
|
||||
XmNtitle, "Shelf",
|
||||
XmNiconName, "Shelf",
|
||||
XmNwidth, 256,
|
||||
XmNheight, 256,
|
||||
NULL);
|
||||
|
||||
Widget layout = XtVaCreateWidget (
|
||||
"layout", xmFormWidgetClass, window,
|
||||
XmNorientation, XmVERTICAL,
|
||||
NULL);
|
||||
Pixmap iconPixmap = XmdLoadBitmapIcon(layout, icon);
|
||||
XtVaSetValues (
|
||||
window,
|
||||
XmNiconPixmap, iconPixmap,
|
||||
NULL);
|
||||
|
||||
Pixmap refreshPixmap = XmdLoadBitmapIcon(layout, refresh);
|
||||
XmString string = XmStringCreateLocalized("Refresh");
|
||||
Widget refreshButton = XtVaCreateManagedWidget (
|
||||
"refreshButton", xmPushButtonWidgetClass, layout,
|
||||
XmNleftAttachment, XmATTACH_FORM,
|
||||
XmNbottomAttachment, XmATTACH_FORM,
|
||||
XmNlabelType, XmPIXMAP_AND_STRING,
|
||||
XmNlabelPixmap, refreshPixmap,
|
||||
XmNlabelString, string,
|
||||
NULL);
|
||||
XmStringFree(string);
|
||||
XtAddCallback (
|
||||
refreshButton, XmNactivateCallback,
|
||||
handleRefresh, NULL);
|
||||
|
||||
Pixmap mountPixmap = XmdLoadBitmapIcon(layout, mount);
|
||||
string = XmStringCreateLocalized("Mount");
|
||||
Widget mountButton = XtVaCreateManagedWidget (
|
||||
"mountButton", xmPushButtonWidgetClass, layout,
|
||||
XmNleftAttachment, XmATTACH_WIDGET,
|
||||
XmNleftWidget, refreshButton,
|
||||
XmNbottomAttachment, XmATTACH_FORM,
|
||||
XmNlabelType, XmPIXMAP_AND_STRING,
|
||||
XmNlabelPixmap, mountPixmap,
|
||||
XmNlabelString, string,
|
||||
NULL);
|
||||
XmStringFree(string);
|
||||
|
||||
Pixmap unmountPixmap = XmdLoadBitmapIcon(layout, unmount);
|
||||
string = XmStringCreateLocalized("Unmount");
|
||||
/*Widget unmountButton = */XtVaCreateManagedWidget (
|
||||
"unmountButton", xmPushButtonWidgetClass, layout,
|
||||
XmNleftAttachment, XmATTACH_WIDGET,
|
||||
XmNleftWidget, mountButton,
|
||||
XmNbottomAttachment, XmATTACH_FORM,
|
||||
XmNlabelType, XmPIXMAP_AND_STRING,
|
||||
XmNlabelPixmap, unmountPixmap,
|
||||
XmNlabelString, string,
|
||||
NULL);
|
||||
XmStringFree(string);
|
||||
|
||||
Widget scroller = XtVaCreateWidget (
|
||||
"scroll", xmScrolledWindowWidgetClass, layout,
|
||||
XmNscrollingPolicy, XmAUTOMATIC,
|
||||
XmNleftAttachment, XmATTACH_FORM,
|
||||
XmNtopAttachment, XmATTACH_FORM,
|
||||
XmNrightAttachment, XmATTACH_FORM,
|
||||
XmNbottomAttachment, XmATTACH_WIDGET,
|
||||
XmNbottomWidget, refreshButton,
|
||||
NULL);
|
||||
container = XtVaCreateManagedWidget (
|
||||
"container", xmContainerWidgetClass, scroller,
|
||||
XmNlayoutType, XmSPATIAL,
|
||||
XmNspatialStyle, XmGRID,
|
||||
NULL);
|
||||
|
||||
loadIconPixmaps();
|
||||
refreshDevices();
|
||||
|
||||
XtManageChild(scroller);
|
||||
XtManageChild(layout);
|
||||
XtRealizeWidget(window);
|
||||
XtAppMainLoop(application);
|
||||
}
|
||||
|
||||
void loadIconPixmaps (void) {
|
||||
#define dev(kind, name) \
|
||||
iconsLarge[DeviceKind##kind] = XmdLoadBitmapIcon(container, name); \
|
||||
iconsSmall[DeviceKind##kind] = XmdLoadBitmapIcon(container, name##_small)
|
||||
dev(Generic, generic);
|
||||
dev(Disk, disk);
|
||||
dev(Rom, rom);
|
||||
dev(Filesystem, filesystem);
|
||||
dev(TTY, tty);
|
||||
}
|
||||
|
||||
void handleRefresh (Widget button, XtPointer clientData, XtPointer callData) {
|
||||
(void)(button);
|
||||
(void)(clientData);
|
||||
(void)(callData);
|
||||
refreshDevices();
|
||||
}
|
||||
|
||||
Bool markDevice (XmdStringMap *map, ConstString key, void *value, void *data) {
|
||||
(void)(map);
|
||||
(void)(key);
|
||||
(void)(data);
|
||||
Device *this = value;
|
||||
this->orphaned = True;
|
||||
return True;
|
||||
}
|
||||
|
||||
Bool transferDevice (XmdStringMap *map, ConstString key, void *value, void *data) {
|
||||
(void)(map);
|
||||
(void)(key);
|
||||
(void)(data);
|
||||
Device *this = value;
|
||||
if (this->orphaned) {
|
||||
DeviceFree(this);
|
||||
} else {
|
||||
XmdStringMapSet(devices, key, value);
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
void refreshDevices (void) {
|
||||
XtUnmanageChild(container);
|
||||
|
||||
/* pre-mark all devices as orphaned */
|
||||
XmdStringMapIterate(devices, markDevice, NULL);
|
||||
|
||||
/* refresh devices by category */
|
||||
refreshDisks();
|
||||
|
||||
/* create a new map, only moving over extant devices */
|
||||
XmdStringMap *oldMap = devices;
|
||||
devices = XmdStringMapNew();
|
||||
XmdStringMapIterate(oldMap, transferDevice, NULL);
|
||||
XmdStringMapFree(oldMap);
|
||||
|
||||
XtManageChild(container);
|
||||
}
|
||||
|
||||
String diskName (ConstString directory, ConstString name) {
|
||||
char fullpath[PATH_MAX];
|
||||
snprintf(fullpath, XtNumber(fullpath), "%s/%s", directory, name);
|
||||
char resolved[PATH_MAX];
|
||||
return XtNewString(basename(realpath(fullpath, resolved)));
|
||||
}
|
||||
|
||||
void refreshDisks (void) {
|
||||
/* get disks */
|
||||
ConstString disksById = "/dev/disk/by-id";
|
||||
ConstString disksByLabel = "/dev/disk/by-label";
|
||||
ConstString disksByPartuuid = "/dev/disk/by-partuuid";
|
||||
|
||||
struct dirent **entries = NULL;
|
||||
int entriesCount = scandir(disksById, &entries, NULL, alphasort);
|
||||
if (entriesCount < 0) {
|
||||
/* TODO error message */
|
||||
return;
|
||||
}
|
||||
for (int index = 0; index < entriesCount; index ++) {
|
||||
struct dirent *entry = entries[index];
|
||||
if (entry->d_name[0] == '.') {
|
||||
XtFree((char *)(entry));
|
||||
continue;
|
||||
}
|
||||
String deviceName = diskName(disksById, entry->d_name);
|
||||
XtFree((char *)(entry));
|
||||
|
||||
Device *device = XmdStringMapGet(devices, deviceName);
|
||||
if (device == NULL) {
|
||||
device = DeviceNew(deviceName, DeviceKindDisk);
|
||||
} else {
|
||||
device->orphaned = False;
|
||||
DeviceSetKind(device, DeviceKindDisk);
|
||||
}
|
||||
|
||||
XtFree(deviceName);
|
||||
}
|
||||
XtFree((char *)(entries));
|
||||
|
||||
/* determine disk types */
|
||||
DIR *dir = opendir(disksByPartuuid);
|
||||
if (dir == NULL) {
|
||||
/* TODO error message */
|
||||
return;
|
||||
}
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
String deviceName = diskName(disksByPartuuid, entry->d_name);
|
||||
Device *device = XmdStringMapGet(devices, deviceName);
|
||||
if (device != NULL) DeviceSetKind(device, DeviceKindFilesystem);
|
||||
XtFree(deviceName);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
/* determine partition labels */
|
||||
dir = opendir(disksByLabel);
|
||||
if (dir == NULL) {
|
||||
/* TODO error message */
|
||||
return;
|
||||
}
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
String deviceName = diskName(disksByLabel, entry->d_name);
|
||||
Device *device = XmdStringMapGet(devices, deviceName);
|
||||
if (device != NULL) DeviceSetLabel(device, entry->d_name);
|
||||
XtFree(deviceName);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
Device *DeviceNew (String name, DeviceKind kind) {
|
||||
Device *this = XtNew(Device);
|
||||
this->mountPoint = NULL;
|
||||
this->label = NULL;
|
||||
this->name = XtNewString(name);
|
||||
this->orphaned = False;
|
||||
XmString string = XmStringCreateLocalized(name);
|
||||
this->widget = XtVaCreateManagedWidget (
|
||||
"device", xmIconGadgetClass, container,
|
||||
XmNalignment, XmALIGNMENT_BEGINNING,
|
||||
XmNlabelString, string,
|
||||
NULL);
|
||||
XmStringFree(string);
|
||||
DeviceSetKind(this, kind);
|
||||
XmdStringMapSet(devices, name, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
void DeviceDelete (ConstString name) {
|
||||
DeviceFree(XmdStringMapSet(devices, name, NULL));
|
||||
}
|
||||
|
||||
void DeviceFree (Device *this) {
|
||||
if (this == NULL) return;
|
||||
XtDestroyWidget(this->widget);
|
||||
XtFree((char *)(this->name));
|
||||
XtFree((char *)(this->mountPoint));
|
||||
XtFree((char *)(this->label));
|
||||
XtFree((char *)(this));
|
||||
}
|
||||
|
||||
void DeviceSetKind (Device *this, DeviceKind kind) {
|
||||
XtVaSetValues (
|
||||
this->widget,
|
||||
XmNlargeIconPixmap, iconsLarge[kind],
|
||||
XmNsmallIconPixmap, iconsSmall[kind],
|
||||
NULL);
|
||||
this->kind = kind;
|
||||
}
|
||||
|
||||
void DeviceSetMountPoint (Device *this, ConstString mountPoint) {
|
||||
XtFree(this->mountPoint);
|
||||
this->mountPoint = XtNewString(mountPoint);
|
||||
}
|
||||
|
||||
void DeviceSetLabel (Device *this, ConstString label) {
|
||||
XtFree(this->label);
|
||||
this->label = XtNewString(label);
|
||||
|
||||
XmString string = NULL;
|
||||
if (label == NULL) {
|
||||
string = XmStringCreateLocalized(this->name);
|
||||
} else {
|
||||
string = XmStringCreateLocalized(this->label);
|
||||
}
|
||||
XtVaSetValues (
|
||||
this->widget,
|
||||
XmNlabelString, string,
|
||||
NULL);
|
||||
XmStringFree(string);
|
||||
}
|
Loading…
Reference in New Issue
Block a user