home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
x
/
xlibpr3.zip
/
winman
/
winman.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-01-15
|
27KB
|
808 lines
/*
* Copyright 1989 O'Reilly and Associates, Inc.
* See ../Copyright for complete rights and liability information.
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xos.h>
#include <X11/cursorfont.h>
#include <stdio.h>
#include <signal.h>
#include "bitmaps/focus_frame_bi" /* name must be <= 14 chars for
* sys V compatibility */
/* include file for printing event types */
#include "eventnames.h"
#define MAX_CHOICE 10
#define DRAW 1
#define ERASE 0
#define RAISE 1
#define LOWER 0
#define MOVE 1
#define RESIZE 0
#define NONE 100
#define NOTDEFINED 0
#define BLACK 1
#define WHITE 0
Window focus_window;
Window inverted_pane = NONE;
static char *menu_label[] =
{
"Raise",
"Lower",
"Move",
"Resize",
"CirculateDn",
"CirculateUp",
"(De)Iconify",
"Kybrd Focus",
"New Xterm",
"Exit",
};
Display *display;
int screen_num;
XFontStruct *font_info;
char icon_name[50];
main()
{
Window menuwin;
Window panes[MAX_CHOICE];
int menu_width, menu_height, x = 0, y = 0, border_width = 4;
int winindex;
int cursor_shape;
Cursor cursor, hand_cursor;
char *font_name = "9x15";
int direction, ascent, descent;
int char_count;
char *string;
XCharStruct overall;
Bool owner_events;
int pointer_mode;
int keyboard_mode;
Window confine_to;
GC gc, rgc;
int pane_height;
Window assoc_win;
XEvent event;
unsigned int button;
if ( (display=XOpenDisplay(NULL)) == NULL )
{
(void) fprintf( stderr, "winman: cannot connect to \
X server %s\n", XDisplayName(NULL));
exit( -1 );
}
screen_num = DefaultScreen(display);
/* Access font */
font_info = XLoadQueryFont(display,font_name);
if (font_info == NULL)
{
(void) fprintf( stderr, "winman: Cannot open font %s\n",
font_name);
exit( -1 );
}
string = menu_label[6];
char_count = strlen(string);
/* determine the extent of each menu pane based
* on the font size */
XTextExtents(font_info, string, char_count, &direction, &ascent,
&descent, &overall);
menu_width = overall.width + 4;
pane_height = overall.ascent + overall.descent + 4;
menu_height = pane_height * MAX_CHOICE;
/* place the window in upper right corner*/
x = DisplayWidth(display,screen_num) - menu_width - (2*border_width);
y = 0; /* appears at top */
/* create opaque window */
menuwin = XCreateSimpleWindow(display, RootWindow(display,
screen_num), x, y, menu_width, menu_height,
border_width, BlackPixel(display,screen_num),
WhitePixel(display,screen_num));
/* create the choice windows for the text */
for (winindex = 0; winindex < MAX_CHOICE; winindex++) {
panes[winindex] = XCreateSimpleWindow(display, menuwin, 0,
menu_height/MAX_CHOICE*winindex, menu_width,
pane_height, border_width = 1,
BlackPixel(display,screen_num),
WhitePixel(display,screen_num));
XSelectInput(display, panes[winindex], ButtonPressMask
| ButtonReleaseMask | ExposureMask);
}
XSelectInput(display, RootWindow(display, screen_num),
SubstructureNotifyMask);
/* these don't appear until parent (menuwin) is mapped */
XMapSubwindows(display,menuwin);
/* create the cursor for the menu */
cursor = XCreateFontCursor(display, XC_left_ptr);
hand_cursor = XCreateFontCursor(display, XC_hand2);
XDefineCursor(display, menuwin, cursor);
focus_window = RootWindow(display, screen_num);
/* Create two Graphics Contexts for inverting panes (white on
* black). We invert the panes by changing the background
* pixel, clearing the window, and using the GC with the
* contrasting color to redraw the text. Another way is
* using XCopyArea. The default is to generate GraphicsExpose
* and NoExpose events to indicate whether the source area
* was obscured. Since the logical function is GXinvert
* the destination is also the source. Therefore if other
* windows are obscuring parts of the exposed pane, the
* wrong area will be inverted. Therefore we would need to
* handle GraphicsExpose and NoExpose events. We'll do it the
* easier way. */
gc = XCreateGC(display, RootWindow(display, screen_num) , 0, NULL);
XSetForeground(display, gc, BlackPixel(display, screen_num));
rgc = XCreateGC(display, RootWindow(display, screen_num) , 0, NULL);
XSetForeground(display, rgc, WhitePixel(display, screen_num));
/* map the menu window (and its subwindows) to the screen_num */
XMapWindow(display, menuwin);
/* Force child processes to disinherit the TCP file descriptor.
* This helps the shell command (creating new xterm) forked and
* exec'ed from the menu to work properly. */
if ((fcntl(ConnectionNumber(display), F_SETFD, 1)) == -1)
fprintf(stderr, "winman: child cannot disinherit TCP fd");
/* loop getting events on the menu window and icons */
while (1)
{
/* wait for an event */
XNextEvent(display, &event);
/* if expose, draw text in pane if it is pane */
switch (event.type) {
case Expose:
if (isIcon(event.xexpose.window, event.xexpose.x,
event.xexpose.y, &assoc_win, icon_name, False))
XDrawString(display, event.xexpose.window, gc, 2,
ascent + 2, icon_name, strlen(icon_name));
else /* it's a pane, might be inverted */
{
if (inverted_pane == event.xexpose.window)
paint_pane(event.xexpose.window, panes, gc, rgc, BLACK);
else
paint_pane(event.xexpose.window, panes, gc, rgc, WHITE);
}
break;
case ButtonPress:
paint_pane(event.xbutton.window, panes, gc, rgc, BLACK);
button = event.xbutton.button;
inverted_pane = event.xbutton.window;
/* get the matching ButtonRelease on same button */
while (1) {
/* get rid of other presses */
while (XCheckTypedEvent(display, ButtonPress,
&event))
;
/* wait for release; if on correct button exit */
XMaskEvent(display, ButtonReleaseMask, &event);
if (event.xbutton.button == button) {
/* get rid of other releases */
while (XCheckTypedEvent(display, ButtonRelease,
&event))
;
break;
}
}
/* all events are sent to the grabbing
* window regardless of
* whether this is True or False.
* owner_events only affects the distribution of
* events when the pointer is within this
* application's windows. */
owner_events = True;
/* we don't want pointer or keyboard events
* frozen in the server */
pointer_mode = GrabModeAsync;
keyboard_mode = GrabModeAsync;
/* we don't want to confine the cursor */
confine_to = None;
XGrabPointer(display, menuwin, owner_events,
ButtonPressMask | ButtonReleaseMask,
pointer_mode, keyboard_mode,
confine_to, hand_cursor, CurrentTime);
/* if press and release occured in same window,
* do command, if not, do nothing */
if (inverted_pane == event.xbutton.window)
{
/* convert window ID to
* window array index */
for (winindex = 0; inverted_pane !=
panes[winindex]; winindex++)
;
switch (winindex)
{
case 0:
raise_lower(menuwin, RAISE);
break;
case 1:
raise_lower(menuwin, LOWER);
break;
case 2:
move_resize(menuwin, hand_cursor, MOVE);
break;
case 3:
move_resize(menuwin, hand_cursor, RESIZE);
break;
case 4:
circup(menuwin);
break;
case 5:
circdn(menuwin);
break;
case 6:
iconify(menuwin);
break;
case 7:
focus_window = focus(menuwin);
break;
case 8:
execute("xterm&");
break;
case 9: /* exit */
XSetInputFocus(display,
RootWindow(display,screen_num),
RevertToPointerRoot,
CurrentTime);
/* turn all icons back into windows */
/* must clear focus highlights */
XClearWindow(display, RootWindow(display, screen_num));
/* need to change focus border
* width back here */
XFlush(display);
XCloseDisplay(display);
exit(1);
default:
(void) fprintf(stderr,
"Something went wrong\n");
break;
} /* end switch */
} /* end if */
/* Invert Back Here (logical function is invert) */
paint_pane(event.xexpose.window, panes, gc, rgc, WHITE);
inverted_pane = NONE;
draw_focus_frame();
XUngrabPointer(display, CurrentTime);
XFlush(display);
break;
case DestroyNotify:
/* window we have iconified has died, remove its icon.
* Don't need to remove window from save set
* because that is done automatically */
removeIcon(event.xdestroywindow.window);
break;
case CirculateNotify:
case ConfigureNotify:
case UnmapNotify:
/* all these uncover areas of screen_num */
draw_focus_frame();
break;
case CreateNotify:
case GravityNotify:
case MapNotify:
case ReparentNotify:
/* don't need these but get them anyway
* since we need DestroyNotify and UnmapNotify
*/
break;
case ButtonRelease:
/* throw these way, they are spurious here */
break;
case MotionNotify:
/* throw these way, they are spurious here */
break;
default:
fprintf(stderr, "winman: got unexpected %s event.\n",
event_names[event.type]);
} /* end switch */
} /* end menu loop (while) */
} /* end main */
paint_pane(window, panes, ngc, rgc, mode)
Window window;
Window panes[];
GC ngc, rgc;
int mode;
{
int win;
int x = 2, y;
GC gc;
if (mode == BLACK) {
XSetWindowBackground(display, window, BlackPixel(display,
screen_num));
gc = rgc;
}
else {
XSetWindowBackground(display, window, WhitePixel(display,
screen_num));
gc = ngc;
}
/* clearing repaints the background */
XClearWindow(display, window);
/* find out index of window for label text */
for (win = 0; window != panes[win]; win++)
;
y = font_info->max_bounds.ascent;
/* the string length is necessary because strings for
XDrawString may not be NULL terminated */
XDrawString(display, window, gc, x, y, menu_label[win],
strlen( menu_label[win]));
}
circup(menuwin)
Window menuwin;
{
XCirculateSubwindowsUp(display, RootWindow(display,screen_num));
XRaiseWindow(display, menuwin);
}
circdn(menuwin)
Window menuwin;
{
XCirculateSubwindowsDown(display, RootWindow(display,screen_num));
XRaiseWindow(display, menuwin);
}
raise_lower(menuwin, raise_or_lower)
Window menuwin;
Bool raise_or_lower;
{
XEvent report;
int root_x,root_y;
Window child, root;
int win_x, win_y;
unsigned int mask;
unsigned int button;
/* wait for ButtonPress, find out which subwindow of root */
XMaskEvent(display, ButtonPressMask, &report);
button = report.xbutton.button;
XQueryPointer(display, RootWindow(display,screen_num), &root,
&child, &root_x, &root_y, &win_x, &win_y,
&mask);
/* if not RootWindow, raise */
if (child != NULL)
{
if (raise_or_lower == RAISE)
XRaiseWindow(display, child);
else
XLowerWindow(display, child);
/* make sure window manager can never be obscured */
XRaiseWindow(display, menuwin);
}
/* wait for ButtonRelease before exiting */
/* get the matching ButtonRelease on same button */
while (1) {
XMaskEvent(display, ButtonReleaseMask, &report);
if (report.xbutton.button == button) {
break;
}
}
/* throw out any remaining events so we start fresh */
while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask,
&report))
;
}
iconify(menuwin)
Window menuwin;
{
XEvent report;
extern Window focus_window;
Window assoc_win;
int press_x,press_y;
Window child;
Window root;
int win_x, win_y;
unsigned int mask;
unsigned int button;
/* wait for ButtonPress, any win */
XMaskEvent(display, ButtonPressMask, &report);
button = report.xbutton.button;
/* find out which subwindow the mouse was in */
XQueryPointer(display, RootWindow(display,screen_num), &root,
&child, &press_x, &press_y, &win_x, &win_y, &mask);
/* Can't iconify rootwindow or menu window */
if ((child == NULL) || (child == menuwin))
{
/* wait for ButtonRelease before exiting */
while (1) {
XMaskEvent(display, ButtonReleaseMask, &report);
if (report.xbutton.button == button) break;
}
return;
}
/* returned value of isIcon not used here, but it
* is elsewhere in the code */
isIcon(child, press_x, press_y, &assoc_win, icon_name, True);
/* window selected is unmapped, whether it is icon
* or main window. Associated window is then mapped. */
XUnmapWindow(display, child);
XMapWindow(display, assoc_win);
/* wait for ButtonRelease before exiting */
/* get the matching ButtonRelease on same button */
while (1) {
XMaskEvent(display, ButtonReleaseMask, &report);
if (report.xbutton.button == button) break;
}
/* throw out any remaining events so we start fresh for next op */
while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask,
&report))
;
}
focus(menuwin)
Window menuwin;
{
XEvent report;
int x,y;
Window child;
Window root;
Window assoc_win;
extern Window focus_window;
int win_x, win_y;
unsigned int mask;
unsigned int button;
XWindowAttributes win_attr;
static int old_width;
static Window old_focus;
int status;
/* wait for ButtonPress, any win */
XMaskEvent(display, ButtonPressMask, &report);
button = report.xbutton.button;
/* find out which subwindow the mouse was in */
XQueryPointer(display, RootWindow(display,screen_num), &root,
&child, &x, &y, &win_x, &win_y, &mask);
if ((child == menuwin) || (child == NULL) || (isIcon(child, x, y, &assoc_win,
icon_name, True)))
focus_window = RootWindow(display, screen_num);
else
focus_window = child;
if (focus_window != old_focus) { /* if focus changed */
/* if not first time set, set border back */
if (old_focus != NULL)
XSetWindowBorderWidth(display, old_focus, old_width);
XSetInputFocus(display, focus_window, RevertToPointerRoot,
CurrentTime);
if (focus_window != RootWindow(display, screen_num)) {
/* get current border width and add one */
if (!(status = XGetWindowAttributes(display,
focus_window, &win_attr)))
fprintf(stderr, "winman: can't get attributes for \
focus window\n");
XSetWindowBorderWidth(display, focus_window,
win_attr.border_width + 1);
/* keep record so we can change it back */
old_width = win_attr.border_width;
}
}
/* get the matching ButtonRelease on same button */
while (1) {
XMaskEvent(display, ButtonReleaseMask, &report);
if (report.xbutton.button == button) break;
}
/* throw out any remaining events so we start fresh for next op */
while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask,
&report))
;
old_focus = focus_window;
return(focus_window);
}
draw_focus_frame()
{
XWindowAttributes win_attr;
int frame_width = 4;
Pixmap focus_tile;
GC gc;
int foreground = BlackPixel(display, screen_num);
int background = WhitePixel(display, screen_num);
extern Window focus_window;
Bool first_time = True;
if (first_time) {
/* make Bitmap from bitmap data */
focus_tile = XCreatePixmapFromBitmapData(display,
RootWindow(display,screen_num),
focus_frame_bi_bits, focus_frame_bi_width,
focus_frame_bi_height, foreground,
background, DefaultDepth(display, screen_num));
/* Create Graphics Context */
gc = XCreateGC(display, RootWindow(display,screen_num), 0, NULL);
XSetFillStyle(display, gc, FillTiled);
XSetTile(display, gc, focus_tile);
first_time = False;
}
/* get rid of old frames */
XClearWindow(display, RootWindow(display,screen_num));
/* if focus is RootWindow, no frame drawn */
if (focus_window == RootWindow(display,screen_num)) return;
/* get dimensions and position of focus_window*/
XGetWindowAttributes(display, focus_window, &win_attr);
XFillRectangle(display, RootWindow(display,screen_num), gc,
win_attr.x - frame_width, win_attr.y - frame_width,
win_attr.width + 2 * (win_attr.border_width + frame_width),
win_attr.height + 2 * (win_attr.border_width + frame_width));
}
move_resize(menuwin, hand_cursor, move_or_resize)
Window menuwin;
Cursor hand_cursor;
Bool move_or_resize;
{
XEvent report;
XWindowAttributes win_attr;
int press_x, press_y, release_x, release_y, move_x, move_y;
static int box_drawn = False;
int left, right, top, bottom;
Window root, child;
Window win_to_configure;
int win_x, win_y;
unsigned int mask;
unsigned int pressed_button;
XSizeHints size_hints;
Bool min_size, increment;
unsigned int width, height;
int temp_size;
static GC gc;
static int first_time = True;
if (first_time) {
gc = XCreateGC(display, RootWindow(display,screen_num), 0, NULL);
XSetSubwindowMode(display, gc, IncludeInferiors);
XSetForeground(display, gc, BlackPixel(display, screen_num));
XSetFunction(display, gc, GXxor);
first_time = False;
}
/* wait for ButtonPress choosing window to configure */
XMaskEvent(display, ButtonPressMask, &report);
pressed_button = report.xbutton.button;
/* which child of root was press in? */
XQueryPointer(display, RootWindow(display,screen_num), &root,
&child, &press_x, &press_y, &win_x,
&win_y, &mask);
win_to_configure = child;
if ((win_to_configure == NULL) ||
((win_to_configure == menuwin)
&& (move_or_resize == RESIZE))) {
/* if in RootWindow or resizing menuwin get
* release event and get out */
while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask,
&report))
;
return;
}
/* button press was in a valid subwindow of root */
/* get original position and size of window */
XGetWindowAttributes(display, win_to_configure,
&win_attr);
/* get size hints for the window */
XGetNormalHints(display, win_to_configure, &size_hints);
if (size_hints.flags && PMinSize)
min_size = True;
if (size_hints.flags && PResizeInc)
increment = True;
/* now we need pointer motion events. */
XChangeActivePointerGrab(display, PointerMotionHintMask |
ButtonMotionMask | ButtonReleaseMask |
OwnerGrabButtonMask, hand_cursor, CurrentTime);
/* don't allow other display operations during move,
* because Xor won't work properly otherwise */
XGrabServer(display);
/* move outline of window until button release */
while (1) {
XNextEvent(display, &report);
switch (report.type) {
case ButtonRelease:
if (report.xbutton.button == pressed_button) {
if (box_drawn)
undraw_box(gc, left, top, right, bottom);
XUngrabServer(display);
/* get final window position */
XQueryPointer(display, RootWindow(display,
screen_num), &root, &child, &release_x,
&release_y, &win_x, &win_y, &mask);
/* move or resize window */
if (move_or_resize == MOVE)
XMoveWindow(display, win_to_configure,
win_attr.x + (release_x - press_x),
win_attr.y + (release_y - press_y));
else
XResizeWindow(display, win_to_configure,
right - left, bottom - top);
XRaiseWindow(display, win_to_configure);
XFlush(display);
box_drawn = False;
while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask,
&report))
;
return;
}
break;
case MotionNotify:
if (box_drawn == True)
undraw_box(gc, left, top, right, bottom);
/* can get rid of all MotionNotify events in queue,
* since otherwise the round-trip delays caused by
* XQueryPointer may cause a backlog
* of MotionNotify events, which will cause additional
* wasted XQueryPointer calls. */
while (XCheckTypedEvent(display, MotionNotify,
&report));
/* get current mouse position */
XQueryPointer(display, RootWindow(display,screen_num),
&root, &child, &move_x, &move_y,
&win_x, &win_y, &mask);
if (move_or_resize == MOVE) {
left = move_x - press_x + win_attr.x;
top = move_y - press_y + win_attr.y;
right = left + win_attr.width;
bottom = top + win_attr.height;
}
else
{
if (move_x < win_attr.x) move_x = 0;
if (move_y < win_attr.y ) move_y = 0;
left = win_attr.x;
top = win_attr.y;
right = left + win_attr.width + move_x
- press_x;
bottom = top + win_attr.height + move_y
- press_y;
/* must adjust size according to size hints */
/* enforce minimum dimensions */
width = right - left;
height = bottom - top;
/* make sure dimension are increment of
* width_inc and height_inc and at least
* min_width and min_height */
for (temp_size = size_hints.min_width;
temp_size < width;
temp_size += size_hints.width_inc)
;
for (temp_size = size_hints.min_height;
temp_size < height;
temp_size += size_hints.height_inc)
;
/* most applications (xterm inc.)
* pad their right and bottom
* dimensions by 2 pixels */
right = left + temp_size + 2;
bottom = top + temp_size + 2;
}
draw_box(gc, left, top, right, bottom);
box_drawn = True;
break;
default:
/* StructureNotify events shouldn't appear here,
* because of the ChangeActivePointerGrab
* call, but they do for some reason. */
/* Anyway, it doesn't matter */
/* fprintf(stderr, "unexpected event type %s\n",
report.type); */
;
} /* end switch */
} /* end outer while */
} /* end move */
#ifdef SYSV
#ifndef hpux
#define vfork() fork()
#endif /* hpux */
#endif /* SYSV */
/* the following procedure is a copy of the implementation of
* system, modified to reset the handling of SIGINT, SIGQUIT,
* and SIGHUP before exec-ing */
execute(s)
char *s;
{
int status, pid, w;
register int (*istat)(), (*qstat)();
if ((pid = vfork()) == 0) {
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGHUP, SIG_DFL);
execl("/bin/sh", "sh", "-c", s, 0);
_exit(127);
}
istat = signal(SIGINT, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
while ((w = wait(&status)) != pid && w != -1)
;
if (w == -1)
status = -1;
signal(SIGINT, istat);
signal(SIGQUIT, qstat);
return(status);
}