Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
xdu/xwin.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
707 lines (628 sloc)
17.3 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* XDU - X Window System Interface. | |
* | |
* We hide all of the X hieroglyphics inside of this module. | |
* | |
* Phillip C. Dykstra | |
* <phil@arl.mil> | |
* 4 Sep 1991. | |
* | |
* Copyright (c) Phillip C. Dykstra 1991, 1993, 1994 | |
* The X Consortium, and any party obtaining a copy of these files from | |
* the X Consortium, directly or indirectly, is granted, free of charge, a | |
* full and unrestricted irrevocable, world-wide, paid up, royalty-free, | |
* nonexclusive right and license to deal in this software and | |
* documentation files (the "Software"), including without limitation the | |
* rights to use, copy, modify, merge, publish, distribute, sublicense, | |
* and/or sell copies of the Software, and to permit persons who receive | |
* copies from any such party to do so. This license includes without | |
* limitation a license to do the foregoing actions under any patents of | |
* the party supplying this software to the X Consortium. | |
*/ | |
#include <X11/Intrinsic.h> | |
#include <X11/Shell.h> | |
#include <X11/StringDefs.h> | |
#include <X11/Xaw/AsciiSrc.h> | |
#include <X11/Xaw/AsciiText.h> | |
#include <X11/Xaw/Form.h> | |
#include <X11/Xaw/Label.h> | |
#include <stdio.h> | |
#include <unistd.h> /* for access() */ | |
#ifndef X_NOT_STDC_ENV | |
#include <stdlib.h> /* for exit() */ | |
#endif | |
/* | |
* IMPORTS: routines that this module vectors out to | |
*/ | |
extern int press(); | |
extern int printpath(); | |
extern int reset(); | |
extern int uponechild(); | |
extern int downonechild(); | |
extern int repaint(); | |
extern int reorder(); | |
extern int setorder(); | |
extern int nodeinfo(); | |
extern int helpinfo(); | |
extern int ncols; | |
extern void savetops(char*, int); | |
extern void savetosvg(char*, int, int, int); | |
/* | |
* EXPORTS: routines that this module exports outside | |
*/ | |
extern int xsetup(); | |
extern int xmainloop(); | |
extern void xclear(); | |
extern void xrepaint(); | |
extern void xdrawrect(); | |
/* | |
* internal routines | |
*/ | |
static void help_popup(); | |
static void help_popdown(); | |
static String fallback_resources[] = { | |
"*window.width: 600", | |
"*window.height: 480", | |
"*help.width: 500", | |
"*help.height: 330", | |
"*order: first", | |
"*psfile: xdu_out.ps", | |
"*svgfile: xdu_out", | |
NULL | |
}; | |
/* | |
* Application Resources | |
*/ | |
typedef struct { | |
Pixel foreground; | |
Pixel background; | |
XFontStruct* font; | |
int ncol; | |
int showsize; | |
char* order; | |
char* psfilename; | |
char* svgfilename; | |
} res_data, *res_data_ptr; | |
static res_data res; | |
static XtResource application_resources[] = { | |
{ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), | |
XtOffset(res_data_ptr, foreground), XtRString, XtDefaultForeground }, | |
{ XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), | |
XtOffset(res_data_ptr, background), XtRString, XtDefaultBackground }, | |
{ XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct*), | |
XtOffset(res_data_ptr, font), XtRString, XtDefaultFont }, | |
{ "ncol", "Ncol", XtRInt, sizeof(int), | |
XtOffset(res_data_ptr, ncol), XtRString, "5" }, | |
{ "showsize", "ShowSize", XtRInt, sizeof(int), | |
XtOffset(res_data_ptr, showsize), XtRString, "1" }, | |
{ "order", "Order", XtRString, sizeof(String), | |
XtOffset(res_data_ptr, order), XtRString, "first" }, | |
{ "psfile", "PSFile", XtRString, sizeof(String), | |
XtOffset(res_data_ptr, psfilename), XtRString, "xdu_out.ps" }, | |
{ "svgfile", "SVGFile", XtRString, sizeof(String), | |
XtOffset(res_data_ptr, svgfilename), XtRString, "xdu_out" } | |
}; | |
/* | |
* Command Line Options | |
*/ | |
static XrmOptionDescRec options[] = { | |
{ "-c", "*ncol", XrmoptionSepArg, NULL }, | |
{ "-f", "*psfile", XrmoptionSepArg, NULL }, | |
{ "+s", "*showsize", XrmoptionNoArg, "1" }, | |
{ "-s", "*showsize", XrmoptionNoArg, "0" }, | |
{ "-n", "*order", XrmoptionNoArg, "size" }, | |
{ "-rn", "*order", XrmoptionNoArg, "rsize" }, | |
{ "-a", "*order", XrmoptionNoArg, "alpha" }, | |
{ "-ra", "*order", XrmoptionNoArg, "ralpha" } | |
}; | |
/* | |
* action routines | |
*/ | |
static void a_goto(); | |
static void a_printpath(); | |
static void a_reset(); | |
static void a_quit(); | |
static void a_reorder(); | |
static void a_size(); | |
static void a_saveps(); | |
static void a_savesvg(); | |
static void a_up(); | |
static void a_down(); | |
static void a_ncol(); | |
static void a_info(); | |
static void a_help(); | |
static void a_removehelp(); | |
static XtActionsRec actionsTable[] = { | |
{ "reset", a_reset }, | |
{ "printpath", a_printpath }, | |
{ "goto", a_goto }, | |
{ "quit", a_quit }, | |
{ "reorder", a_reorder }, | |
{ "size", a_size }, | |
{ "ncol", a_ncol }, | |
{ "saveps", a_saveps }, | |
{ "savesvg", a_savesvg }, | |
{ "uponechild", a_up }, | |
{ "downonechild", a_down }, | |
{ "info", a_info }, | |
{ "help", a_help }, | |
{ "RemoveHelp", a_removehelp } | |
}; | |
static char defaultTranslations[] = "\ | |
<Key>Q: quit()\n\ | |
<Key>Escape: quit()\n\ | |
:<Key>/: reset()\n\ | |
<Key>S: size()\n\ | |
<Key>P: saveps()\n\ | |
<Key>V: savesvg()\n\ | |
<Key>I: info()\n\ | |
<Key>H: help()\n\ | |
<Key>Help: help()\n\ | |
:<Key>?: help()\n\ | |
<Key>A: reorder(alpha)\n\ | |
<Key>N: reorder(size)\n\ | |
<Key>F: reorder(first)\n\ | |
<Key>L: reorder(last)\n\ | |
<Key>R: reorder(reverse)\n\ | |
<Key>U: uponechild()\n\ | |
<Key>D: downonechild()\n\ | |
<Key>1: ncol(1)\n\ | |
<Key>2: ncol(2)\n\ | |
<Key>3: ncol(3)\n\ | |
<Key>4: ncol(4)\n\ | |
<Key>5: ncol(5)\n\ | |
<Key>6: ncol(6)\n\ | |
<Key>7: ncol(7)\n\ | |
<Key>8: ncol(8)\n\ | |
<Key>9: ncol(9)\n\ | |
<Key>0: ncol(10)\n\ | |
<Btn1Down>: goto()\n\ | |
<Btn2Down>: printpath()\n\ | |
<Btn3Down>: reset()\n\ | |
<Btn3Down>(2):quit()\n\ | |
"; | |
#define UNUSED1(x) (void)(x) | |
#define UNUSED2(x, y) (void)(x), (void)(y) | |
#define UNUSED3(x, y, z) (void)(x), (void)(y), (void)(z) | |
#define UNUSED4(a, x, y, z) (void)(a), (void)(x), (void)(y), (void)(z) | |
#define UNUSED5(a, b, x, y, z) (void)(a), (void)(b), (void)(x), (void)(y), (void)(z) | |
#define VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N | |
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1) | |
#define ALL_UNUSED_IMPL_(nargs) UNUSED##nargs | |
#define ALL_UNUSED_IMPL(nargs) ALL_UNUSED_IMPL_(nargs) | |
#define UNUSED(...) \ | |
ALL_UNUSED_IMPL(VA_NUM_ARGS(__VA_ARGS__)) \ | |
(__VA_ARGS__) | |
/* | |
* action routines | |
*/ | |
static void | |
a_quit(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(event, params, num_params); | |
XtAppSetExitFlag(XtWidgetToApplicationContext(w)); | |
return; | |
} | |
static void | |
a_goto(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, params, num_params); | |
press(event->xbutton.x, event->xbutton.y); | |
} | |
static void | |
a_printpath(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, params, num_params); | |
printpath(event->xbutton.x, event->xbutton.y); | |
} | |
static void | |
a_reset(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, event, params, num_params); | |
reset(); | |
} | |
static void | |
a_reorder(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, event); | |
if (*num_params != 1) { | |
fprintf(stderr, "xdu: bad number of params to reorder action\n"); | |
} else { | |
reorder(*params); | |
} | |
} | |
static void | |
a_size(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, event, params, num_params); | |
res.showsize++; | |
if (res.showsize >= 5) | |
res.showsize = 0; | |
xrepaint(); | |
} | |
static void | |
a_saveps(Widget w, XEvent* e, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, e, params, num_params); | |
fprintf(stderr, "saving as postscript to file: %s ..", res.psfilename); | |
savetops(res.psfilename, res.showsize); | |
fprintf(stderr, "saved !\n"); | |
} | |
static void | |
a_up(Widget w, XEvent* e, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, e, params, num_params); | |
uponechild(); | |
} | |
static void | |
a_down(Widget w, XEvent* e, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, e, params, num_params); | |
downonechild(); | |
} | |
static void | |
a_ncol(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, event); | |
int n; | |
if (*num_params != 1) { | |
fprintf(stderr, "xdu: bad number of params to ncol action\n"); | |
return; | |
} | |
n = atoi(*params); | |
if (n < 1 || n > 1000) { | |
fprintf(stderr, "xdu: bad value to ncol action\n"); | |
return; | |
} | |
ncols = res.ncol = n; | |
xrepaint(); | |
} | |
static void | |
a_info(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, event, params, num_params); | |
nodeinfo(); | |
} | |
static void | |
a_help(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, event, params, num_params); | |
/* | |
* helpinfo(); | |
*/ | |
help_popup(); | |
} | |
static void | |
a_removehelp(Widget w, XEvent* event, String* params, Cardinal* num_params) | |
{ | |
UNUSED(w, event, params, num_params); | |
help_popdown(); | |
} | |
/* | |
* callback routines | |
*/ | |
static void setRepaintWhenIdle(); | |
static void | |
c_repaint(Widget w, XtPointer data, XEvent* event, Boolean* continue_to_dispatch) | |
{ | |
UNUSED(w, data, event, continue_to_dispatch); | |
/* | |
* printf("Expose\n"); | |
*/ | |
setRepaintWhenIdle(); | |
} | |
/* | |
* X Window related variables | |
*/ | |
static Display* dpy; | |
static int screen; | |
static Visual* vis; | |
static Window win; | |
static GC gc; | |
static XtAppContext app_con; | |
static int workerRegistered=0; | |
static int last_repaint_width=-1; | |
static int last_repaint_height=-1; | |
Boolean doIdleRepaint(XtPointer data) { | |
(void)data; | |
XWindowAttributes xwa; | |
XGetWindowAttributes(dpy, win, &xwa); | |
if (xwa.width != last_repaint_width || xwa.height != last_repaint_height) { | |
XClearWindow(dpy, win); | |
} | |
repaint(xwa.width, xwa.height); | |
last_repaint_width=xwa.width; | |
last_repaint_height=xwa.height; | |
workerRegistered=0; | |
return True; | |
} | |
static void setRepaintWhenIdle() { | |
if (!workerRegistered) { | |
(void)XtAppAddWorkProc(app_con,doIdleRepaint,NULL); | |
workerRegistered=1; | |
} | |
} | |
static void | |
a_savesvg(Widget w, XEvent* e, String* params, Cardinal* num_params) | |
{ | |
char* extension = ".svg"; | |
int len = strlen(res.svgfilename) + 3 + strlen(extension) + 1; | |
char tmp[len]; | |
char* fname; | |
int i; | |
XWindowAttributes xwa; | |
XGetWindowAttributes(dpy, win, &xwa); | |
UNUSED(w, e, params, num_params); | |
for (i = 0; i > -1; ++i) { | |
snprintf(tmp, len, "%s-%02d%s", res.svgfilename, i, extension); | |
if (access(tmp, F_OK) == -1) { | |
fname = tmp; | |
break; | |
} | |
} | |
if (i < 0) { | |
fprintf(stderr, "ERROR: there are too many xdu_output files!!!\n"); | |
exit(1); | |
} | |
fprintf(stderr, "saving as scalable vector graphic to file: %s ..", | |
fname); | |
savetosvg(fname, res.showsize, xwa.width, xwa.height); | |
fprintf(stderr, "saved !\n"); | |
} | |
Widget toplevel; | |
/* | |
* External Functions | |
*/ | |
int xsetup(int* argcp, char** argv) | |
{ | |
XtTranslations trans_table; | |
Widget w; | |
XGCValues gcv; | |
int n; | |
Arg args[5]; | |
/* | |
* Create the top level Widget | |
*/ | |
n = 0; | |
XtSetArg(args[n], XtNtitle, "XDU Disk Usage Display ('h' for help)"); | |
n++; | |
toplevel = XtAppInitialize(&app_con, "XDu", options, XtNumber(options), argcp, | |
argv, fallback_resources, args, n); | |
XtGetApplicationResources(toplevel, (XtPointer)&res, | |
application_resources, | |
XtNumber(application_resources), NULL, 0); | |
XtAppAddActions(app_con, actionsTable, XtNumber(actionsTable)); | |
trans_table = XtParseTranslationTable(defaultTranslations); | |
/* | |
* Create a simple Label class widget to draw in | |
*/ | |
n = 0; | |
XtSetArg(args[n], XtNlabel, ""); | |
n++; | |
w = XtCreateManagedWidget("window", labelWidgetClass, toplevel, args, | |
n); | |
/* | |
* events | |
*/ | |
XtAddEventHandler(w, ExposureMask, False, c_repaint, NULL); | |
XtAugmentTranslations(w, trans_table); | |
XtRealizeWidget(toplevel); | |
/* | |
* We need these for the raw Xlib calls | |
*/ | |
win = XtWindow(w); | |
dpy = XtDisplay(w); | |
screen = DefaultScreen(dpy); | |
vis = DefaultVisual(dpy, screen); | |
gcv.foreground = res.foreground; | |
gcv.background = res.background; | |
gcv.font = res.font->fid; | |
gc = XCreateGC(dpy, win, (GCFont | GCForeground | GCBackground), &gcv); | |
setorder(res.order); | |
ncols = res.ncol; | |
return (1); | |
} | |
int xmainloop() | |
{ | |
XtAppMainLoop(app_con); | |
return (0); | |
} | |
void xclear() | |
{ | |
XClearWindow(dpy, win); | |
} | |
void xrepaint() | |
{ | |
XWindowAttributes xwa; | |
XClearWindow(dpy, win); | |
XGetWindowAttributes(dpy, win, &xwa); | |
repaint(xwa.width, xwa.height); | |
} | |
void readable_float(float number, char* number_label) | |
{ | |
char number_string[1024]; | |
int i, j, length; | |
sprintf(number_string, "%.2f", number); | |
length = (strlen(number_string) - 4) / 3 + strlen(number_string); | |
for (i = 0, j = 0; i < length; ++i) { | |
if ((length - 3 - i) % 4 == 0 && i < length - 3) { | |
number_label[i] = ','; | |
continue; | |
} | |
number_label[i] = number_string[j++]; | |
} | |
number_label[length] = 0; | |
} | |
void readable_long_long(long long number, char* number_label) | |
{ | |
char number_string[1024]; | |
int i, j, length; | |
sprintf(number_string, "%lld", number); | |
length = (strlen(number_string) - 1) / 3 + strlen(number_string); | |
for (i = 0, j = 0; i < length; ++i) { | |
if ((length - i) % 4 == 0 && i != 0) { | |
number_label[i] = ','; | |
continue; | |
} | |
number_label[i] = number_string[j++]; | |
} | |
number_label[length] = 0; | |
} | |
void xdrawrect(char* name, long long size, int x, int y, int width, int height) | |
{ | |
int textx, | |
texty; | |
char label[1024]; | |
char number_label[1024]; | |
XCharStruct overall; | |
int ascent, | |
descent, | |
direction; | |
int cheight; | |
/* | |
* printf("draw(%d,%d,%d,%d)\n", x, y, width, height ); | |
*/ | |
XDrawRectangle(dpy, win, gc, x, y, width, height); | |
switch (res.showsize) { | |
case 1: | |
readable_long_long(size, number_label); | |
sprintf(label, "%s (%sk)", name, number_label); | |
name = label; | |
break; | |
case 2: | |
readable_float((double)size / (double)1024, number_label); | |
sprintf(label, "%s (%sM)", name, number_label); | |
name = label; | |
break; | |
case 3: | |
readable_float((double)size / (double)(1024 * 1024), number_label); | |
sprintf(label, "%s (%sG)", name, number_label); | |
name = label; | |
break; | |
case 4: | |
readable_float((double)size / (double)(1024 * 1024 * 1024), number_label); | |
sprintf(label, "%s (%sT)", name, number_label); | |
name = label; | |
break; | |
default: | |
break; | |
} | |
XTextExtents(res.font, name, strlen(name), &direction, &ascent, | |
&descent, &overall); | |
cheight = overall.ascent + overall.descent; | |
if (height < (cheight + 2)) | |
return; | |
/* | |
* print label | |
*/ | |
textx = x + 4; | |
texty = y + height / 2.0 + (overall.ascent - overall.descent) / 2.0 + 1.5; | |
XDrawString(dpy, win, gc, textx, texty, name, strlen(name)); | |
} | |
static Widget popup; | |
static void | |
help_popup() | |
{ | |
Widget form, | |
text, | |
src; | |
Arg args[15]; | |
int n; | |
Atom wm_delete_window; | |
XtTranslations trans_table; | |
if (popup != NULL) { | |
XtPopup(popup, XtGrabNone); | |
return; | |
} | |
/* | |
* popup shell | |
*/ | |
n = 0; | |
XtSetArg(args[n], XtNtitle, "XDU Help"); | |
n++; | |
popup = XtCreatePopupShell("helpPopup", transientShellWidgetClass, | |
toplevel, args, n); | |
/* | |
* form container | |
*/ | |
n = 0; | |
XtSetArg(args[n], XtNborderWidth, 0); | |
n++; | |
XtSetArg(args[n], XtNdefaultDistance, 0); | |
n++; | |
form = XtCreateManagedWidget("form", formWidgetClass, popup, args, n); | |
/* | |
* text widget in form | |
*/ | |
n = 0; | |
XtSetArg(args[n], XtNborderWidth, 0); | |
n++; | |
XtSetArg(args[n], XtNresize, XawtextResizeBoth); | |
n++; | |
/* | |
* fallback resources weren't working here on the Sun | |
*/ | |
XtSetArg(args[n], XtNwidth, 500); | |
n++; | |
XtSetArg(args[n], XtNheight, 360); | |
n++; | |
text = XtCreateManagedWidget("help", asciiTextWidgetClass, form, args, n); | |
/* | |
* create text source | |
*/ | |
n = 0; | |
XtSetArg(args[n], XtNtype, XawAsciiString); | |
n++; | |
XtSetArg(args[n], XtNeditType, XawtextRead); | |
n++; | |
XtSetArg(args[n], XtNstring, "\ | |
XDU Version 3.0 - Phil Dykstra <phil@arl.mil>\n\ | |
\n\ | |
Keyboard Commands\n\ | |
a sort alphabetically\n\ | |
n sort numerically (largest first)\n\ | |
f sort first-in-first-out\n\ | |
l sort last-in-first-out\n\ | |
r reverse sort\n\ | |
s toggle size display\n\ | |
/ goto the root\n\ | |
i node info to standard out\n\ | |
h this help message\n\ | |
q quit (also Escape)\n\ | |
0-9 set number of columns (0=10)\n\ | |
\n\ | |
p print to ps-file\n\ | |
v print to svg-file\n\ | |
u go up one child\n\ | |
p go down one child\n\ | |
\n\ | |
Mouse Commands\n\ | |
Left Goto node (goto parent if leftmost box)\n\ | |
Middle Print path of clicked node\n\ | |
Right Back to root\n\ | |
DblRight Quit\n\ | |
"); | |
n++; | |
src = XtCreateWidget("textSource", asciiSrcObjectClass, text, args, n); | |
/* | |
* set text source | |
*/ | |
XawTextSetSource(text, src, 0); | |
XtRealizeWidget(popup); | |
XtPopup(popup, XtGrabNone); | |
trans_table = XtParseTranslationTable("<Key>Q: RemoveHelp()"); | |
XtAugmentTranslations(form, trans_table); | |
/* | |
* Set up ICCCM delete window | |
*/ | |
wm_delete_window = XInternAtom(XtDisplay(popup), "WM_DELETE_WINDOW", False); | |
XtOverrideTranslations(popup, | |
XtParseTranslationTable("<Message>WM_PROTOCOLS: RemoveHelp()")); | |
XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, | |
1); | |
} | |
static void | |
help_popdown() | |
{ | |
XtPopdown(popup); | |
} |