aboutsummaryrefslogtreecommitdiffstats
path: root/xmover.c
diff options
context:
space:
mode:
Diffstat (limited to 'xmover.c')
-rw-r--r--xmover.c777
1 files changed, 777 insertions, 0 deletions
diff --git a/xmover.c b/xmover.c
new file mode 100644
index 0000000..241f0a7
--- /dev/null
+++ b/xmover.c
@@ -0,0 +1,777 @@
+/*
+ * xmover -- X11 frontend for scsi media changers
+ *
+ * (c) 2002 Gerd Knorr <kraxel@bytesex.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xatom.h>
+#include <X11/cursorfont.h>
+#include <Xm/Xm.h>
+#include <Xm/Form.h>
+#include <Xm/Label.h>
+#include <Xm/RowColumn.h>
+#include <Xm/CascadeB.h>
+#include <Xm/PushB.h>
+#include <Xm/DrawingA.h>
+#include <Xm/Protocols.h>
+#include <Xm/Separator.h>
+#include <Xm/Frame.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/MessageB.h>
+#include <Xm/SelectioB.h>
+#include <Xm/TransferP.h>
+#include <Xm/Text.h>
+
+#include "chio.h"
+
+#include "RegEdit.h"
+#include "list.h"
+#include "man.h"
+
+/* --------------------------------------------------------------------- */
+
+XtAppContext app_context;
+
+static String fallback_ressources[] = {
+#include "xmover.h"
+ NULL
+};
+
+struct ARGS {
+ char *device;
+ int help;
+ int debug;
+} args;
+
+XtResource args_desc[] = {
+ /* name, class, type, size, offset, default_type, default_addr */
+ {
+ /* Strings */
+ "device",
+ XtCString, XtRString, sizeof(char*),
+ XtOffset(struct ARGS*,device),
+ XtRString, "/dev/sch0",
+ },{
+ /* Integer */
+ "help",
+ XtCValue, XtRInt, sizeof(int),
+ XtOffset(struct ARGS*,help),
+ XtRString, "0"
+ },{
+ "debug",
+ XtCValue, XtRInt, sizeof(int),
+ XtOffset(struct ARGS*,debug),
+ XtRString, "0"
+ }
+};
+const int args_count = XtNumber(args_desc);
+
+XrmOptionDescRec opt_desc[] = {
+ { "-c", "device", XrmoptionSepArg, NULL },
+ { "-device", "device", XrmoptionSepArg, NULL },
+
+ { "-debug", "debug", XrmoptionNoArg, "1" },
+ { "-h", "help", XrmoptionNoArg, "1" },
+ { "-help", "help", XrmoptionNoArg, "1" },
+ { "--help", "help", XrmoptionNoArg, "1" },
+};
+const int opt_count = (sizeof(opt_desc)/sizeof(XrmOptionDescRec));
+
+/* prototypes */
+static void elem_convert(Widget, XtPointer, XtPointer);
+static void elem_destination(Widget, XtPointer, XtPointer);
+
+/* --------------------------------------------------------------------- */
+/* atoms */
+
+static Atom XA_WM_DELETE_WINDOW;
+
+static Atom XA_TARGETS;
+static Atom _MOTIF_EXPORT_TARGETS;
+
+static Atom _XMOVER_TYPEUNIT;
+static Atom _XMOVER_REFRESH;
+
+static Atom targets[2];
+static Cardinal ntargets;
+
+void init_atoms(Display *dpy)
+{
+ XA_WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+
+ XA_TARGETS = XInternAtom(dpy, "TARGETS", False);
+ _MOTIF_EXPORT_TARGETS = XInternAtom(dpy, "_MOTIF_EXPORT_TARGETS", False);
+
+ _XMOVER_TYPEUNIT = XInternAtom(dpy, "_XMOVER_TYPEUNIT", False);
+ _XMOVER_REFRESH = XInternAtom(dpy, "_XMOVER_REFRESH", False);
+
+ targets[ntargets++] = _XMOVER_TYPEUNIT;
+ targets[ntargets++] = _XMOVER_REFRESH;
+}
+
+/* ---------------------------------------------------------------------- */
+/* redirect stderr to error dialog box */
+
+struct stderr_handler {
+ Widget box;
+ XmString str;
+ int pipe;
+ XtInputId id;
+};
+
+static void
+stderr_input(XtPointer clientdata, int *src, XtInputId *id)
+{
+ struct stderr_handler *h = clientdata;
+ XmString item;
+ Widget label;
+ char buf[1024];
+ int rc;
+
+ rc = read(h->pipe,buf,sizeof(buf)-1);
+ if (rc <= 0) {
+ /* Oops */
+ XtRemoveInput(h->id);
+ close(h->pipe);
+ XtDestroyWidget(h->box);
+ free(h);
+ }
+ buf[rc] = 0;
+ item = XmStringGenerate(buf, NULL, XmMULTIBYTE_TEXT,NULL);
+ h->str = XmStringConcatAndFree(h->str,item);
+ label = XmMessageBoxGetChild(h->box,XmDIALOG_MESSAGE_LABEL);
+ XtVaSetValues(label,XmNlabelString,h->str,NULL);
+ XtManageChild(h->box);
+};
+
+static void
+stderr_ok_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ struct stderr_handler *h = clientdata;
+
+ XmStringFree(h->str);
+ h->str = XmStringGenerate("", NULL, XmMULTIBYTE_TEXT,NULL);
+ XtUnmanageChild(h->box);
+}
+
+static void
+stderr_close_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ struct stderr_handler *h = clientdata;
+
+ XmStringFree(h->str);
+ h->str = XmStringGenerate("", NULL, XmMULTIBYTE_TEXT,NULL);
+}
+
+static void
+stderr_init(Widget parent)
+{
+ struct stderr_handler *h;
+ int p[2];
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+ h->str = XmStringGenerate("", NULL, XmMULTIBYTE_TEXT,NULL);
+ h->box = XmCreateErrorDialog(parent,"errbox",NULL,0);
+ XtUnmanageChild(XmMessageBoxGetChild(h->box,XmDIALOG_HELP_BUTTON));
+ XtUnmanageChild(XmMessageBoxGetChild(h->box,XmDIALOG_CANCEL_BUTTON));
+ XtAddCallback(h->box,XmNokCallback,stderr_ok_cb,h);
+ XtAddCallback(XtParent(h->box),XmNpopdownCallback,stderr_close_cb,h);
+ pipe(p);
+ dup2(p[1],2);
+ close(p[1]);
+ h->pipe = p[0];
+ h->id = XtAppAddInput(app_context,h->pipe,(XtPointer)XtInputReadMask,
+ stderr_input,h);
+}
+
+/* ---------------------------------------------------------------------- */
+/* pointer games */
+
+struct ptr_list {
+ struct list_head list;
+ Widget widget;
+};
+static struct list_head ptr_wins;
+static Cursor ptr_idle;
+static Cursor ptr_busy;
+
+void ptr_register(Widget widget)
+{
+ struct ptr_list *item;
+
+ if (XtWindow(widget))
+ XDefineCursor(XtDisplay(widget), XtWindow(widget),ptr_idle);
+ item = malloc(sizeof(*item));
+ memset(item,0,sizeof(*item));
+ item->widget = widget;
+ list_add_tail(&item->list,&ptr_wins);
+}
+
+void ptr_unregister(Widget widget)
+{
+ struct list_head *item;
+ struct ptr_list *win,*del;
+
+ del = NULL;
+ list_for_each(item,&ptr_wins) {
+ win = list_entry(item, struct ptr_list, list);
+ if (win->widget == widget)
+ del = win;
+ }
+ if (del)
+ list_del(&del->list);
+}
+
+void ptr_set(Cursor ptr)
+{
+ struct list_head *item;
+ struct ptr_list *win;
+ Display *dpy = NULL;
+
+ list_for_each(item,&ptr_wins) {
+ win = list_entry(item, struct ptr_list, list);
+ if (!XtWindow(win->widget))
+ continue;
+ dpy = XtDisplay(win->widget);
+ XDefineCursor(dpy, XtWindow(win->widget),ptr);
+ }
+ if (dpy)
+ XSync(dpy,False);
+}
+
+void ptr_init(Widget shell)
+{
+ XColor white,red,dummy;
+ Colormap cmap = DefaultColormapOfScreen(XtScreen(shell));
+
+ INIT_LIST_HEAD(&ptr_wins);
+ ptr_idle = XCreateFontCursor(XtDisplay(shell),XC_left_ptr);
+ ptr_busy = XCreateFontCursor(XtDisplay(shell),XC_watch);
+ if (XAllocNamedColor(XtDisplay(shell),cmap,"white",&white,&dummy) &&
+ XAllocNamedColor(XtDisplay(shell),cmap,"red",&red,&dummy)) {
+ XRecolorCursor(XtDisplay(shell),ptr_idle,&red,&white);
+ XRecolorCursor(XtDisplay(shell),ptr_busy,&red,&white);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+/* handle changer elements */
+
+struct changer_elem {
+ struct list_head list;
+ int type;
+ int unit;
+ Widget draw,label;
+ Widget menu,mref,mtag,msrc;
+ struct changer_get_element info;
+};
+
+static int fd;
+static struct changer_params params;
+static struct list_head elems;
+
+static struct changer_elem*
+elem_by_typeunit(int type, int unit)
+{
+ struct list_head *item;
+ struct changer_elem *elem;
+
+ list_for_each(item,&elems) {
+ elem = list_entry(item, struct changer_elem, list);
+ if (elem->type == type &&
+ elem->unit == unit)
+ return elem;
+ }
+ return NULL;
+}
+
+static void update_elem(struct changer_elem *elem)
+{
+ XmString item,str = NULL;
+ char buf[64];
+ int err;
+
+ /* query */
+ elem->info.cge_type = elem->type;
+ elem->info.cge_unit = elem->unit;
+ err = ioctl(fd,CHIOGELEM,&elem->info);
+ if (-1 == err) {
+ fprintf(stderr,"CHIOGELEM(%d/%d): %s\n",
+ elem->type,elem->unit,strerror(errno));
+ }
+
+ /* build XmString */
+ sprintf(buf,"#%03d",elem->unit);
+ item = XmStringGenerate(buf,NULL,XmMULTIBYTE_TEXT,NULL);
+ str = XmStringConcatAndFree(str,item);
+ if (elem->info.cge_flags & CGE_PVOLTAG) {
+ sprintf(buf," [%-32.32s]",elem->info.cge_pvoltag);
+ item = XmStringGenerate(buf,NULL,XmMULTIBYTE_TEXT,"voltag");
+ str = XmStringConcatAndFree(str,item);
+ }
+ if (elem->info.cge_status & CESTATUS_FULL) {
+ item = XmStringGenerate(" full",NULL,XmMULTIBYTE_TEXT,"full");
+ str = XmStringConcatAndFree(str,item);
+ }
+ if (elem->info.cge_status & CESTATUS_EXCEPT) {
+ item = XmStringGenerate(" error",NULL,XmMULTIBYTE_TEXT,"error");
+ str = XmStringConcatAndFree(str,item);
+ }
+
+ /* commit */
+ XtVaSetValues(elem->label,XmNlabelString,str,NULL);
+ XmStringFree(str);
+}
+
+static void
+elem_tag_done_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ XmSelectionBoxCallbackStruct *cd = call_data;
+ struct changer_elem *elem = clientdata;
+ Widget text;
+ char *str;
+
+ if (args.debug)
+ fprintf(stderr,"elem_tag_done_cb\n");
+ if (cd->reason == XmCR_OK) {
+ struct changer_set_voltag tag;
+ text = XmSelectionBoxGetChild(widget,XmDIALOG_TEXT);
+ str = XmTextGetString(text);
+ memset(&tag,0,sizeof(tag));
+ tag.csv_type = elem->type;
+ tag.csv_unit = elem->unit;
+ tag.csv_flags = CSV_PVOLTAG;
+ if (strlen(str) > 0)
+ strncpy(tag.csv_voltag,str,32);
+ else
+ tag.csv_flags |= CSV_CLEARTAG;
+ ptr_set(ptr_busy);
+ if (-1 == ioctl(fd,CHIOSVOLTAG,&tag))
+ perror("CHIOSVOLTAG");
+ update_elem(elem);
+ ptr_set(ptr_idle);
+ }
+ XtDestroyWidget(XtParent(widget));
+}
+
+static void
+elem_tag_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ struct changer_elem *elem = clientdata;
+ Widget box,text;
+
+ if (args.debug)
+ fprintf(stderr,"elem_tag_cb\n");
+ box = XmCreatePromptDialog(elem->draw,"tag",NULL,0);
+ text = XmSelectionBoxGetChild(box,XmDIALOG_TEXT);
+ if (elem->info.cge_flags & CGE_PVOLTAG)
+ XmTextSetString(text,elem->info.cge_pvoltag);
+
+ XtAddCallback(box,XmNokCallback,elem_tag_done_cb,elem);
+ XtAddCallback(box,XmNcancelCallback,elem_tag_done_cb,elem);
+ XmdRegisterEditres(XtParent(box));
+ XtManageChild(box);
+}
+
+static void
+elem_src_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ struct changer_elem *elem = clientdata;
+ struct changer_elem *src;
+ struct changer_move move;
+
+ if (args.debug)
+ fprintf(stderr,"elem_src_cb\n");
+ src = elem_by_typeunit(elem->info.cge_srctype,elem->info.cge_srcunit);
+ memset(&move,0,sizeof(move));
+ move.cm_fromtype = elem->type;
+ move.cm_fromunit = elem->unit;
+ move.cm_totype = elem->info.cge_srctype;
+ move.cm_tounit = elem->info.cge_srcunit;
+ ptr_set(ptr_busy);
+ if (-1 == ioctl(fd,CHIOMOVE,&move))
+ perror("CHIOMOVE");
+ update_elem(elem);
+ update_elem(src);
+ ptr_set(ptr_idle);
+}
+
+static void
+elem_refresh_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ struct changer_elem *elem = clientdata;
+
+ ptr_set(ptr_busy);
+ update_elem(elem);
+ ptr_set(ptr_idle);
+}
+
+static void
+elem_menu_eh(Widget widget, XtPointer clientdata, XEvent *event, Boolean *cont)
+{
+ struct changer_elem *elem = clientdata;
+ Boolean tag,src;
+
+ if (args.debug)
+ fprintf(stderr,"elem_menu_eh\n");
+ tag = (elem->info.cge_status & CESTATUS_FULL) ? True : False;
+ XtVaSetValues(elem->mtag,XmNsensitive,tag,NULL);
+ if (elem->msrc) {
+ src = (elem->info.cge_status & CESTATUS_FULL) &&
+ (elem->info.cge_flags & CGE_SRC);
+ XtVaSetValues(elem->msrc,XmNsensitive,src,NULL);
+ }
+ XmMenuPosition(elem->menu,(XButtonPressedEvent*)event);
+ XtManageChild(elem->menu);
+}
+
+static struct changer_elem*
+add_elem(Widget parent, int type, int unit)
+{
+ struct changer_elem *elem;
+ Cardinal n = 0;
+ Arg args[4];
+ char name[32];
+
+ elem = malloc(sizeof(*elem));
+ memset(elem,0,sizeof(*elem));
+ sprintf(name,"%d/%d",type,unit);
+ elem->type = type;
+ elem->unit = unit;
+ elem->draw = XtVaCreateManagedWidget("d",xmDrawingAreaWidgetClass,parent,
+ NULL);
+ elem->label = XtVaCreateManagedWidget(name,xmLabelWidgetClass,elem->draw,
+ NULL);
+ update_elem(elem);
+
+ /* dnd */
+ XtAddCallback(elem->label,XmNconvertCallback,elem_convert,elem);
+ XtAddCallback(elem->draw,XmNdestinationCallback,elem_destination,elem);
+ XtSetArg(args[n], XmNimportTargets, targets); n++;
+ XtSetArg(args[n], XmNnumImportTargets, ntargets); n++;
+ XmeDropSink(elem->draw,args,n);
+
+ /* context menu */
+ elem->menu = XmCreatePopupMenu(elem->draw,"menu",NULL,0);
+ XtAddEventHandler(elem->draw,ButtonPressMask,False,elem_menu_eh,elem);
+ elem->mref = XtVaCreateManagedWidget("ref",xmPushButtonWidgetClass,
+ elem->menu,NULL);
+ XtAddCallback(elem->mref,XmNactivateCallback,elem_refresh_cb,elem);
+ elem->mtag = XtVaCreateManagedWidget("tag",xmPushButtonWidgetClass,
+ elem->menu,NULL);
+ XtAddCallback(elem->mtag,XmNactivateCallback,elem_tag_cb,elem);
+ if (elem->type == CHET_DT) {
+ elem->msrc = XtVaCreateManagedWidget("src",xmPushButtonWidgetClass,
+ elem->menu,NULL);
+ XtAddCallback(elem->msrc,XmNactivateCallback,elem_src_cb,elem);
+ }
+
+ list_add_tail(&elem->list,&elems);
+ return elem;
+}
+
+/* --------------------------------------------------------------------- */
+/* drag'n'drop stuff */
+
+static void
+elem_convert(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ XmConvertCallbackStruct *ccs = call_data;
+ struct changer_elem *elem = clientdata;
+ unsigned long *largs;
+ char *name;
+ Atom *targs;
+ int n;
+
+ if (args.debug) {
+ name = XGetAtomName(XtDisplay(widget),ccs->target);
+ fprintf(stderr,"elem_convert %s\n",name);
+ XFree(name);
+ }
+
+ if ((ccs->target == XA_TARGETS) ||
+ (ccs->target == _MOTIF_EXPORT_TARGETS)) {
+ targs = (Atom*)XtMalloc(sizeof(Atom)*8);
+ n = 0;
+ targs[n++] = _XMOVER_TYPEUNIT;
+ targs[n++] = _XMOVER_REFRESH;
+ ccs->value = targs;
+ ccs->length = n;
+ ccs->type = XA_ATOM;
+ ccs->format = 32;
+ ccs->status = XmCONVERT_MERGE;
+ }
+ if (ccs->target == _XMOVER_TYPEUNIT) {
+ largs = (unsigned long*)XtMalloc(sizeof(*largs));
+ largs[0] = (elem->type << 16) | elem->unit;
+ ccs->value = largs;
+ ccs->length = 1;
+ ccs->type = XA_INTEGER;
+ ccs->format = 32;
+ ccs->status = XmCONVERT_DONE;
+ }
+ if (ccs->target == _XMOVER_REFRESH) {
+ ptr_set(ptr_busy);
+ update_elem(elem);
+ ptr_set(ptr_idle);
+ ccs->value = NULL;
+ ccs->length = 0;
+ ccs->type = XA_INTEGER;
+ ccs->format = 32;
+ ccs->status = XmCONVERT_DONE;
+ }
+}
+
+static void
+elem_transfer(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ XmSelectionCallbackStruct *scs = call_data;
+ struct changer_elem *elem = clientdata;
+ unsigned long *ldata = scs->value;
+ XmTransferStatus status = XmTRANSFER_DONE_SUCCEED;
+ Time time = XtLastTimestampProcessed(XtDisplay(widget));
+ int pending,i;
+ char *name;
+
+ if (args.debug) {
+ name = XGetAtomName(XtDisplay(widget),scs->target);
+ fprintf(stderr,"elem_transfer %s\n",name);
+ XFree(name);
+ }
+
+ pending = scs->remaining;
+ if (scs->target == XA_TARGETS) {
+ for (i = 0; i < scs->length; i++) {
+ if (ldata[i] == _XMOVER_TYPEUNIT) {
+ XmTransferValue(scs->transfer_id, ldata[i], elem_transfer,
+ elem, time);
+ pending++;
+ }
+ }
+ if (pending == scs->remaining) {
+ /* no target found */
+ status = XmTRANSFER_DONE_FAIL;
+ }
+ }
+ if (scs->target == _XMOVER_TYPEUNIT) {
+ struct changer_move move;
+
+ if (args.debug)
+ fprintf(stderr,"move: %ld/%ld => %d/%d\n",
+ ldata[0] >> 16, ldata[0] & 0xffff,
+ elem->type, elem->unit);
+ memset(&move,0,sizeof(move));
+ move.cm_fromtype = ldata[0] >> 16;
+ move.cm_fromunit = ldata[0] & 0xffff;
+ move.cm_totype = elem->type;
+ move.cm_tounit = elem->unit;
+ ptr_set(ptr_busy);
+ if (move.cm_fromtype != move.cm_totype ||
+ move.cm_fromunit != move.cm_tounit)
+ if (-1 == ioctl(fd,CHIOMOVE,&move))
+ perror("CHIOMOVE");
+ update_elem(elem);
+ ptr_set(ptr_idle);
+ XmTransferValue(scs->transfer_id, _XMOVER_REFRESH, elem_transfer,
+ elem, time);
+ pending++;
+ }
+ XFree(scs->value);
+ if (1 == pending)
+ XmTransferDone(scs->transfer_id, status);
+}
+
+static void
+elem_destination(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ XmDestinationCallbackStruct *dcs = call_data;
+ struct changer_elem *elem = clientdata;
+ Time time = XtLastTimestampProcessed(XtDisplay(widget));
+
+ if (args.debug)
+ fprintf(stderr,"elem_destination\n");
+ XmTransferValue(dcs->transfer_id, XA_TARGETS, elem_transfer, elem, time);
+}
+
+/* --------------------------------------------------------------------- */
+/* gui + basic callbacks */
+
+void
+destroy_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ XtDestroyWidget(clientdata);
+}
+
+static void
+about_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ Widget msgbox;
+
+ msgbox = XmCreateInformationDialog(widget,"aboutbox",NULL,0);
+ XtUnmanageChild(XmMessageBoxGetChild(msgbox,XmDIALOG_HELP_BUTTON));
+ XtUnmanageChild(XmMessageBoxGetChild(msgbox,XmDIALOG_CANCEL_BUTTON));
+ XtAddCallback(msgbox,XmNokCallback,destroy_cb,msgbox);
+ XtManageChild(msgbox);
+}
+
+static void
+close_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ Widget shell = clientdata;
+ XtDestroyWidget(shell);
+ exit(0);
+}
+
+static void
+refresh_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ struct list_head *item;
+ struct changer_elem *elem;
+
+ ptr_set(ptr_busy);
+ list_for_each(item,&elems) {
+ elem = list_entry(item, struct changer_elem, list);
+ update_elem(elem);
+ }
+ ptr_set(ptr_idle);
+}
+
+static void create_widgets(Widget shell)
+{
+ Widget form,menubar,menu,push,frame,scroll,rowcol;
+ int i;
+
+ /* shell stuff */
+ XmdRegisterEditres(shell);
+ XmAddWMProtocolCallback(shell,XA_WM_DELETE_WINDOW,close_cb,shell);
+
+ /* form container */
+ form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell,
+ NULL);
+
+ /* menu- & toolbar */
+ menubar = XmCreateMenuBar(form,"bar",NULL,0);
+ XtManageChild(menubar);
+
+ /* menu -- file */
+ menu = XmCreatePulldownMenu(menubar,"fileM",NULL,0);
+ XtVaCreateManagedWidget("file",xmCascadeButtonWidgetClass,menubar,
+ XmNsubMenuId,menu,NULL);
+ push = XtVaCreateManagedWidget("quit",xmPushButtonWidgetClass,menu,NULL);
+ XtAddCallback(push,XmNactivateCallback,close_cb,shell);
+
+ /* menu -- changer */
+ menu = XmCreatePulldownMenu(menubar,"changerM",NULL,0);
+ XtVaCreateManagedWidget("changer",xmCascadeButtonWidgetClass,menubar,
+ XmNsubMenuId,menu,NULL);
+ push = XtVaCreateManagedWidget("refresh",xmPushButtonWidgetClass,menu,NULL);
+ XtAddCallback(push,XmNactivateCallback,refresh_cb,NULL);
+
+ /* menu - help */
+ menu = XmCreatePulldownMenu(menubar,"helpM",NULL,0);
+ push = XtVaCreateManagedWidget("help",xmCascadeButtonWidgetClass,menubar,
+ XmNsubMenuId,menu,NULL);
+ XtVaSetValues(menubar,XmNmenuHelpWidget,push,NULL);
+ push = XtVaCreateManagedWidget("man",xmPushButtonWidgetClass,menu,NULL);
+ XtAddCallback(push,XmNactivateCallback,man_cb,"xmover");
+ XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL);
+ push = XtVaCreateManagedWidget("about",xmPushButtonWidgetClass,menu,NULL);
+ XtAddCallback(push,XmNactivateCallback,about_cb,NULL);
+
+ /* ie elems */
+ frame = XtVaCreateManagedWidget("ie", xmFrameWidgetClass, form, NULL);
+ XtVaCreateManagedWidget("label",xmLabelWidgetClass,frame,NULL);
+ rowcol = XtVaCreateManagedWidget("rc",xmRowColumnWidgetClass,
+ frame,NULL);
+ for (i = 0; i < params.cp_nportals; i++)
+ add_elem(rowcol, CHET_IE, i);
+
+ /* dt elems */
+ frame = XtVaCreateManagedWidget("dt", xmFrameWidgetClass, form, NULL);
+ XtVaCreateManagedWidget("label",xmLabelWidgetClass,frame,NULL);
+ rowcol = XtVaCreateManagedWidget("rc",xmRowColumnWidgetClass,
+ frame,NULL);
+ for (i = 0; i < params.cp_ndrives; i++)
+ add_elem(rowcol, CHET_DT, i);
+
+ /* st elems */
+ frame = XtVaCreateManagedWidget("st", xmFrameWidgetClass, form, NULL);
+ XtVaCreateManagedWidget("label",xmLabelWidgetClass,frame,NULL);
+ scroll = XmCreateScrolledWindow(frame,"scroll",NULL,0);
+ XtManageChild(scroll);
+ rowcol = XtVaCreateManagedWidget("rc",xmRowColumnWidgetClass,
+ scroll,NULL);
+ for (i = 0; i < params.cp_nslots; i++)
+ add_elem(rowcol, CHET_ST, i);
+}
+
+/* --------------------------------------------------------------------- */
+/* main */
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "xmover -- X11 frontend for scsi media changers\n"
+ "options:\n"
+ " -debug enable debug messages\n"
+ " -device <dev> use <dev> instead of /dev/sch0\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ Widget app_shell;
+ int err;
+
+ /* init X11 */
+ XtSetLanguageProc(NULL,NULL,NULL);
+ app_shell = XtVaAppInitialize(&app_context, "xmover",
+ opt_desc, opt_count,
+ &argc, argv,
+ fallback_ressources,
+ NULL);
+ XtGetApplicationResources(app_shell,&args,
+ args_desc,args_count,
+ NULL,0);
+ if (args.help) {
+ usage();
+ exit(1);
+ }
+
+ /* init changer */
+ fd = open(args.device,O_RDONLY);
+ if (-1 == fd) {
+ fprintf(stderr,"open %s: %s\n",args.device,strerror(errno));
+ exit(1);
+ }
+ err = ioctl(fd,CHIOGPARAMS,&params);
+ if (-1 == err) {
+ perror("CHIOGPARAMS");
+ exit(1);
+ }
+ INIT_LIST_HEAD(&elems);
+
+ init_atoms(XtDisplay(app_shell));
+ if (!args.debug)
+ stderr_init(app_shell);
+ ptr_init(app_shell);
+ ptr_register(app_shell);
+ create_widgets(app_shell);
+
+ XtRealizeWidget(app_shell);
+ XtAppMainLoop(app_context);
+ return 0;
+}