1007 lines
25 KiB
C
1007 lines
25 KiB
C
/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
|
|
* Copyright 1989 Massachusetts Institute of Technology
|
|
*/
|
|
/******************************\
|
|
* *
|
|
* BULL WINDOW MANAGER for X11 *
|
|
* *
|
|
* main body *
|
|
* *
|
|
\******************************/
|
|
|
|
/* include */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "EXTERN.h"
|
|
#include "wool.h"
|
|
#include "wl_atom.h"
|
|
#include "wl_string.h"
|
|
#include "wl_list.h"
|
|
#include "wl_client.h"
|
|
#include "wl_func.h"
|
|
#include "yacc.h"
|
|
#include "wl_number.h"
|
|
#include <X11/Xlib.h>
|
|
#include "wl_pixmap.h"
|
|
#include "INTERN.h"
|
|
#include "gwm.h"
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <sys/time.h>
|
|
#ifdef NEED_SELECT_H
|
|
#include <sys/select.h>
|
|
#endif
|
|
|
|
/* external */
|
|
|
|
#ifdef NOXEHTYPE
|
|
typedef int (*XErrorHandler) ();
|
|
extern XErrorHandler XSetErrorHandler ();
|
|
#endif
|
|
|
|
#ifdef NO_GWM_LOG
|
|
#define GWM_log()
|
|
#endif
|
|
#ifndef GWM_LOG_ID
|
|
#define GWM_LOG_ID 0
|
|
#endif
|
|
|
|
/* a comment string to tell "what" is this binary (precompiled? etc...)
|
|
* e.g, in makefile: C_COMPILER= cc -DGWM_LOG_NAME='\"-D-alpha\"'
|
|
*/
|
|
#ifndef GWM_LOG_NAME
|
|
#define GWM_LOG_NAME ""
|
|
#endif
|
|
|
|
extern int XError();
|
|
extern int InitWool();
|
|
extern Wob LookUpWob();
|
|
extern InitScreens();
|
|
extern Wob NewClientWindow();
|
|
extern void ScreenClose();
|
|
extern void DecorateWindows();
|
|
extern char *wool_fix_path();
|
|
extern NoXError();
|
|
extern GWMScreenContext RegisterScreen();
|
|
extern void GWM_BusErrorSignalHandler();
|
|
extern ClientWindow LookUpClient();
|
|
DECLARE_strchr;
|
|
|
|
/* local */
|
|
|
|
static char err[] = "\007GWM:";
|
|
static int GWM_Decorate_one_window=0;
|
|
static int GWM_Decorate_all_windows=0;
|
|
static int GWM_is_initialized = 0;
|
|
static int GWM_RetryStart = 0;
|
|
|
|
/* routines */
|
|
|
|
int GWM_Initialize();
|
|
|
|
|
|
int gwm_stdin = 0, gwm_prompt = 0;
|
|
|
|
|
|
/*
|
|
* Main body of GWM:
|
|
* - parse arguments
|
|
* - initialize X
|
|
* - initialize Wool
|
|
* - read user profile
|
|
* - decorate all already present windows
|
|
* - enter main loop: GWM_ProcessEvents
|
|
*/
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
malloc_init(); /* FIRST THING TO DO!!! */
|
|
#ifdef MONITOR
|
|
moncontrol(0); /* do not trace profile read */
|
|
#endif /* MONITOR */
|
|
GWM_argc = argc;
|
|
GWM_argv = argv;
|
|
GWM_getopts(argc, argv); /* options & open display */
|
|
if (gwm_stdin && gwm_prompt) {
|
|
printf("> ");
|
|
fflush(stdout);
|
|
}
|
|
RegisterScreens();
|
|
|
|
if (wool_error_occurred(GWM_Initialize)) /* Init wool and display */
|
|
GWM_Abort("cannot initialize");
|
|
|
|
if (wool_error_in_profile && !wool_continue_reading_on_error)
|
|
GWM_Abort("error while reading profile");
|
|
|
|
if (wool_error_occurred(InitScreens)) /* screen and syswd */
|
|
GWM_Abort("cannot set up");
|
|
|
|
if (wool_error_occurred(DecorateWindows) &&
|
|
!wool_continue_reading_on_error)/* existing windows */
|
|
GWM_Abort("cannot decorate windows");
|
|
|
|
FOR_ALL_SCREENS { /* call opening on all screens */
|
|
SetTarget(Context -> rootWob);
|
|
WOOL_send(WOOL_eval, Context -> rootWob -> opening,
|
|
(Context -> rootWob -> opening));
|
|
decrease_reference(Context -> rootWob -> opening);
|
|
Context -> rootWob -> opening = NULL;
|
|
} END_OF_ALL_SCREENS;
|
|
|
|
/* send signal if a process is waiting for gwm to come up */
|
|
if (GWM_kill_pid) {
|
|
kill(GWM_kill_pid, GWM_kill_pid_sig);
|
|
}
|
|
|
|
GWM_is_initialized = 1;
|
|
GWM_log();
|
|
if (set_wool_error_resume_point()) { /* wool_error will jump here */
|
|
if (GWM_is_restarting || GWM_is_ending)
|
|
GWM_BusErrorSignalHandler(0); /* skip wool when error in ending */
|
|
zrt_gc(0);
|
|
if (GWM_window_being_decorated) {
|
|
Window w = GWM_window_being_decorated -> client;
|
|
ClientWindowClose(GWM_window_being_decorated);
|
|
GWM_window_being_decorated = 0;
|
|
XMapWindow(dpy, w);
|
|
}
|
|
}
|
|
|
|
#ifdef MONITOR
|
|
moncontrol(1); /* only trace main loop */
|
|
#endif /* MONITOR */
|
|
GWM_ProcessEvents(1); /* MAIN LOOP (never returns!) */
|
|
return 0;
|
|
}
|
|
|
|
/* fatal init error handler */
|
|
|
|
GWM_Abort(message)
|
|
char * message;
|
|
{
|
|
fprintf(stderr, "%s -- %s, aborting\n", err, message);
|
|
exit(-1);
|
|
}
|
|
|
|
|
|
void read_stdin()
|
|
{
|
|
static int bi, len, pn, is;
|
|
static char *b = NULL;
|
|
char buf[1024], c;
|
|
int n, i;
|
|
|
|
if (!b) {
|
|
b = Malloc(len = 1024);
|
|
pn = is = 0;
|
|
strcpy(b, "(print ");
|
|
bi = 7;
|
|
}
|
|
|
|
if ((n = read(0, buf, 1024)) > 0) {
|
|
for (i = 0; i < n; i++) {
|
|
c = b[bi++] = buf[i];
|
|
if (c == '(' && !is) pn++;
|
|
else if (c == ')' && !is) pn--;
|
|
else if (c == '"') is ^= 1;
|
|
else if (c == '\n' && !pn && !is) {
|
|
b[bi-1] = '\0';
|
|
strcat(b, " \"\\n\")");
|
|
wool_execute_string(b);
|
|
bi = 7;
|
|
}
|
|
if (bi == len - 10)
|
|
b = Realloc(b, len += 1024);
|
|
}
|
|
if (buf[i-1] == '\n' && gwm_prompt) {
|
|
if (pn)
|
|
printf("%d> ", pn);
|
|
else
|
|
printf("> ");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* The main loop of GWM:
|
|
* - wait for an event
|
|
* - look if it is for the hook (X window) of a wob
|
|
* (or the client of a window), then dispatch it to the concerned
|
|
* wob
|
|
* - if it is a new window being mapped, decorate it
|
|
* - the server is grabbed, redirect events to grabbing wob
|
|
*
|
|
* If blocking is 1, the loop never ends, whereas if it is 0, it returns as
|
|
* soons as the queue is empty (via the XPending call)
|
|
*/
|
|
|
|
GWM_ProcessEvents(blocking)
|
|
int blocking;
|
|
{
|
|
EventData evt;
|
|
Wob wob;
|
|
struct timeval to;
|
|
fd_set fds;
|
|
int s = 0;
|
|
int local_zrt_size = zrt_size;
|
|
|
|
#ifdef DEBUG
|
|
wob = 0; /* entry point for dbx */
|
|
#endif /* DEBUG */
|
|
|
|
if (gwm_stdin) {
|
|
FD_ZERO(&fds);
|
|
FD_SET(0, &fds);
|
|
to.tv_sec = to.tv_usec = 0;
|
|
s = select(1, &fds, NULL, NULL, &to);
|
|
}
|
|
while (blocking || XPending(dpy) || s > 0) {
|
|
|
|
if (gwm_stdin && !XPending(dpy)) {
|
|
FD_ZERO(&fds);
|
|
FD_SET(0, &fds);
|
|
FD_SET(ConnectionNumber(dpy), &fds);
|
|
to.tv_sec = to.tv_usec = 0;
|
|
s = select(FD_SETSIZE, &fds, NULL, NULL, blocking ? NULL : &to);
|
|
|
|
if (s > 0 && FD_ISSET(0, &fds))
|
|
read_stdin();
|
|
s = 0;
|
|
goto next_event;
|
|
}
|
|
|
|
XNextEvent(dpy, &evt);
|
|
TraceDo('e',GWM_prettyprint_event("XEV: ", &evt, "\n"));
|
|
|
|
if (EventProperties[evt.xany.type] & EPTime) {
|
|
Time newtime = *((Time *)(((char *)(&evt)) +
|
|
EventTimeFieldOffset[evt.xany.type]));
|
|
if (newtime) { /* sometimes the X Server goofs up */
|
|
GWMTime = newtime;
|
|
}
|
|
}
|
|
|
|
if (wob = LookUpWob(evt.xany.window)) {
|
|
if (GWM_ServerGrabbed) {
|
|
if(event_is_grabbable(evt)) {
|
|
if (GWM_GrabChildEvents
|
|
|| !IsAnAncestor(GWM_ServerGrabbed, wob))
|
|
wob = GWM_ServerGrabbed;
|
|
WOOL_send(WOOL_process_event, wob, (wob, &evt));
|
|
} else if (event_is_redirectable(evt)) {
|
|
if (wob == GWM_ServerGrabbed
|
|
|| (!GWM_GrabChildEvents
|
|
&& IsAnAncestor(GWM_ServerGrabbed, wob))
|
|
|| IsNotGrabDiscarded(&evt)) {
|
|
WOOL_send(WOOL_process_event, wob, (wob, &evt));
|
|
}
|
|
} else {
|
|
WOOL_send(WOOL_process_event, wob, (wob, &evt));
|
|
}
|
|
} else {
|
|
WOOL_send(WOOL_process_event, wob, (wob, &evt));
|
|
}
|
|
} else if (wob = (Wob) LookUpClient(evt.xany.window)) {
|
|
WOOL_send(WOOL_process_event, wob, (wob, &evt));
|
|
} else if (evt.xany.type == MappingNotify) {
|
|
XRefreshKeyboardMapping(&evt.xmapping);
|
|
} else if (evt.xany.type == ColormapNotify) {
|
|
Update_colormap_in_colormap_windows_list(&evt);
|
|
} else if (MeterEventHandler(&evt)) {
|
|
;
|
|
#ifdef DEBUG
|
|
} else {
|
|
wool_printf("Received event %s", eventtype[evt.type]);
|
|
wool_printf(" for unknown window 0x%x\n", evt.xany.window);
|
|
#endif /* DEBUG */
|
|
}
|
|
if (event_is_key_or_button(evt))/* store last button */
|
|
bcopy(&evt, &GWM_LastEvent, sizeof(XEvent));
|
|
|
|
next_event:
|
|
zrt_gc(local_zrt_size);
|
|
if (blocking)
|
|
dft_gc();
|
|
}
|
|
}
|
|
|
|
#ifndef NO_GWM_LOG
|
|
/* sends an UDP packet to keep count of all GWM running, if you want to
|
|
* sends your host name, or GWM_LOG_ID (string) if you dont want to send me
|
|
* this info
|
|
*/
|
|
|
|
GWM_log()
|
|
{
|
|
char buf[256];
|
|
|
|
if (getenv("NO_GWM_LOG"))
|
|
return;
|
|
sprintf(buf, "%s%s STARTED", GWM_version_name, GWM_LOG_NAME);
|
|
#ifndef DEBUG
|
|
#endif /* DEBUG */
|
|
}
|
|
#endif /* !NO_GWM_LOG */
|
|
|
|
/*
|
|
* Initialize GCs used in wool
|
|
*/
|
|
|
|
InitGC()
|
|
{
|
|
XGCValues gc_values;
|
|
|
|
FOR_ALL_SCREENS {
|
|
gc_values.graphics_exposures = False;
|
|
gc_values.function = GXinvert;
|
|
Context -> gc.Invert = XCreateGC(dpy, Context -> root,
|
|
GCGraphicsExposures | GCFunction, &gc_values);
|
|
gc_values.foreground = Context -> pixel.Fore;
|
|
gc_values.background = Context -> pixel.Back;
|
|
gc_values.function = GXcopy;
|
|
Context -> gc.Work = XCreateGC(dpy, Context -> root,
|
|
GCGraphicsExposures | GCForeground | GCBackground | GCFunction,
|
|
&gc_values);
|
|
gc_values.ts_x_origin = 0;
|
|
gc_values.ts_y_origin = 0;
|
|
gc_values.function = GXcopy;
|
|
gc_values.fill_style = FillStippled;
|
|
Context -> gc.Set = XCreateGC(dpy, Context -> root,
|
|
GCFunction | GCTileStipXOrigin | GCGraphicsExposures
|
|
| GCTileStipYOrigin | GCFillStyle, &gc_values);
|
|
gc_values.ts_x_origin = 0;
|
|
gc_values.ts_y_origin = 0;
|
|
gc_values.function = GXcopy;
|
|
gc_values.fill_style = FillTiled;
|
|
Context -> gc.Tile = XCreateGC(dpy, Context -> root,
|
|
GCFunction | GCTileStipXOrigin | GCGraphicsExposures
|
|
| GCTileStipYOrigin | GCFillStyle, &gc_values);
|
|
gc_values.function = GXinvert;
|
|
Context -> gc.Back = XCreateGC(dpy, Context -> root,
|
|
GCGraphicsExposures | GCFunction, &gc_values);
|
|
gc_values.line_width = 0;
|
|
gc_values.foreground = 0xfd;
|
|
gc_values.function = GXxor;
|
|
gc_values.subwindow_mode = IncludeInferiors;
|
|
Context -> gc.Draw = XCreateGC(dpy, Context -> root,
|
|
GCGraphicsExposures | GCLineWidth | GCForeground | GCFunction
|
|
| GCSubwindowMode, &gc_values);
|
|
MakeDefaultBitmap();
|
|
gc_values.function = GXinvert;
|
|
Context -> gc.Bitmap = XCreateGC(dpy, Context -> DefaultBitmap,
|
|
GCGraphicsExposures | GCFunction, &gc_values);
|
|
}END_OF_ALL_SCREENS;
|
|
}
|
|
|
|
/*
|
|
* GWM_Initialize
|
|
* initialize:
|
|
* X
|
|
* Wool
|
|
* internal variables
|
|
*/
|
|
|
|
int
|
|
GWM_Initialize()
|
|
{
|
|
XSetWindowAttributes attributes;
|
|
|
|
GWM_SignalsInit();
|
|
XrmInitialize();
|
|
SetUpDefaults();
|
|
InitGC();
|
|
if (InitWool() != OK)
|
|
return FatalError;
|
|
|
|
/* initialize wool_host_name */
|
|
wool_hostname_get();
|
|
|
|
/* a hack for compilers chocking on wl_event.c initialisations on
|
|
offsets of structures instead of instance
|
|
code provided by:
|
|
Rodney McDuff <mcduff@newton.physics.uq.oz.au>
|
|
*/
|
|
#ifdef NO_STRUCTURE_OFFSETS
|
|
/* assign nonzero values to EventTimeFieldOffset[]
|
|
since apollo compiler complains at determining structure
|
|
sizes at compile time */
|
|
{
|
|
XEvent dummy_evt_ptr;
|
|
#define XEventFieldOffset(evt_type, field) \
|
|
(((char *)(&(dummy_evt_ptr.evt_type.field))) - \
|
|
((char *)(&(dummy_evt_ptr.type))))
|
|
;
|
|
EventTimeFieldOffset[2] = XEventFieldOffset(xkey, time);
|
|
EventTimeFieldOffset[3] = XEventFieldOffset(xkey, time);
|
|
EventTimeFieldOffset[4] = XEventFieldOffset(xbutton, time);
|
|
EventTimeFieldOffset[5] = XEventFieldOffset(xbutton, time);
|
|
EventTimeFieldOffset[6] = XEventFieldOffset(xmotion, time);
|
|
EventTimeFieldOffset[7] = XEventFieldOffset(xcrossing, time);
|
|
EventTimeFieldOffset[8] = XEventFieldOffset(xcrossing, time);
|
|
EventTimeFieldOffset[28] = XEventFieldOffset(xproperty, time);
|
|
EventTimeFieldOffset[29] = XEventFieldOffset(xselectionclear, time);
|
|
EventTimeFieldOffset[30] = XEventFieldOffset(xselectionrequest, time);
|
|
EventTimeFieldOffset[31] = XEventFieldOffset(xselection, time);
|
|
}
|
|
#endif /* NO_STRUCTURE_OFFSETS */
|
|
|
|
/* Manage Windows */
|
|
attributes.event_mask = KeyPressMask | ButtonPressMask | ButtonReleaseMask
|
|
| EnterWindowMask | LeaveWindowMask | FocusChangeMask
|
|
| SubstructureRedirectMask;
|
|
XSetErrorHandler(NoXError);
|
|
XSync(dpy, False);
|
|
FOR_ALL_SCREENS {
|
|
ErrorStatus = 0;
|
|
XChangeWindowAttributes(dpy, Context -> root,
|
|
CWEventMask, &attributes);
|
|
XSync(dpy, False);
|
|
if (ErrorStatus && (!GWM_Decorate_all_windows)) {
|
|
fprintf(stderr,
|
|
"GWM: cannot get control of windows on screen #%d!\n%s\n",
|
|
Context -> screen,
|
|
"Maybe another window manager is running on the display?");
|
|
if (GWM_RetryStart) {
|
|
fprintf(stderr, "Retrying... kill your other window manager!\n");
|
|
do {
|
|
ErrorStatus = 0;
|
|
XChangeWindowAttributes(dpy, Context -> root,
|
|
CWEventMask, &attributes);
|
|
XSync(dpy, False);
|
|
} while(ErrorStatus);
|
|
fprintf(stderr, "OK for screen %d\n", Context -> screen);
|
|
} else {
|
|
exit(1);
|
|
}
|
|
}
|
|
}END_OF_ALL_SCREENS;
|
|
GWM_re_init_PointerRoot();
|
|
XSetErrorHandler(XError);
|
|
return OK;
|
|
}
|
|
|
|
/* re-init pointerroot */
|
|
|
|
GWM_re_init_PointerRoot()
|
|
{
|
|
XSelectInput(dpy, Context -> root, 0);
|
|
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
|
|
}
|
|
|
|
/* CloseEverything
|
|
* n = 0 normal (end)
|
|
* 1 error (we can still print messages)
|
|
* -1 fatal error (connection closed)
|
|
*/
|
|
|
|
#ifdef VOID_SIGNALS
|
|
void
|
|
#endif
|
|
GWM_end(n)
|
|
int n;
|
|
{
|
|
#ifdef MONITOR
|
|
moncontrol(0); /* do not trace ending code */
|
|
#endif /* MONITOR */
|
|
if (n >= 0 && GWM_is_initialized) {
|
|
XSetErrorHandler(NoXError);
|
|
GWM_re_init_PointerRoot();
|
|
XSync(dpy, True);
|
|
if (!GWM_is_ending && Context -> rootWob) {
|
|
GWM_is_ending = 1;
|
|
wool_do_print_errors = 0;
|
|
FOR_ALL_SCREENS {
|
|
SetTarget(Context -> rootWob);
|
|
ScreenClose(Context -> rootWob);
|
|
}END_OF_ALL_SCREENS;
|
|
}
|
|
XCloseDisplay(dpy);
|
|
}
|
|
exit(n);
|
|
}
|
|
|
|
/* wool_end is calling GWM_end */
|
|
wool_end(n)
|
|
int n;
|
|
{
|
|
GWM_end(n);
|
|
}
|
|
|
|
/* signals management
|
|
*/
|
|
|
|
static int GWM_in_fatal_error;
|
|
|
|
/* We try to handle bus errors gracefully, i.e. by trying to trigger a
|
|
* wool_error and going on, but aborting if we get one more
|
|
*/
|
|
|
|
void
|
|
GWM_FatalSignalHandler(sig)
|
|
int sig;
|
|
{
|
|
if (!GWM_in_fatal_error) {
|
|
GWM_in_fatal_error = 1;
|
|
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
|
|
XSync(dpy, True);
|
|
if (wool_is_reading_file)
|
|
fprintf(stderr, "\n\"%s\": line %d:\n", wool_is_reading_file,
|
|
yylineno);
|
|
wool_stack_dump(1);
|
|
fprintf(stderr,
|
|
"\007\nGWM: Fatal error due to UNIX signal # %d -- Aborting\n",
|
|
sig);
|
|
}
|
|
exit(sig);
|
|
}
|
|
|
|
/* Try to handle bus errors as normal errors, execpt that:
|
|
* - if 2 bus errors come within 1 second, abort.
|
|
* - if we were ending, just end, (in case the end code is faulty)
|
|
* - ditto for restarting
|
|
*/
|
|
|
|
void
|
|
GWM_BusErrorSignalHandler(sig)
|
|
int sig;
|
|
{
|
|
int current_time;
|
|
static int aborting;
|
|
|
|
if (GWM_Window_being_opened)
|
|
XMapWindow(dpy, GWM_Window_being_opened -> hook);
|
|
|
|
if (GWM_is_restarting) {
|
|
XCloseDisplay(dpy);
|
|
execvp(GWM_is_restarting[0], GWM_is_restarting);
|
|
}
|
|
if (GWM_is_ending)
|
|
GWM_end(-1);
|
|
current_time = time(0);
|
|
if (current_time == GWM_time_of_last_bus_error) {
|
|
if (aborting) {
|
|
exit(-1);
|
|
} else {
|
|
aborting = 1;
|
|
GWM_is_ending = 1;
|
|
fprintf(stderr,
|
|
"\007\nGWM: Internal error: bus error -- restarting\n");
|
|
XCloseDisplay(dpy);
|
|
execvp(GWM_argv[0], GWM_argv);
|
|
}
|
|
}
|
|
else {
|
|
GWM_time_of_last_bus_error = current_time;
|
|
#ifdef SYSV
|
|
signal(sig, GWM_BusErrorSignalHandler);
|
|
#endif /* SYSV */
|
|
wool_error(INTERNAL_ERROR, "bus error");
|
|
}
|
|
}
|
|
|
|
GWM_SignalsInit()
|
|
{
|
|
signal(SIGHUP, SIG_IGN);
|
|
/* keep signals for dbx debugging */
|
|
#ifndef DEBUG
|
|
signal(SIGINT, GWM_end);
|
|
signal(SIGQUIT, GWM_end);
|
|
signal(SIGTERM, GWM_end);
|
|
signal(SIGFPE, GWM_FatalSignalHandler);
|
|
signal(SIGILL, GWM_BusErrorSignalHandler);
|
|
#ifdef SIGBUS
|
|
signal(SIGBUS, GWM_BusErrorSignalHandler);
|
|
#endif
|
|
signal(SIGSEGV, GWM_BusErrorSignalHandler);
|
|
#ifdef SIGSYS
|
|
signal(SIGSYS, GWM_FatalSignalHandler);
|
|
#endif
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
/*
|
|
* functions to process events in the queue
|
|
*/
|
|
|
|
WOOL_OBJECT
|
|
wool_process_masked_events(mask)
|
|
int mask; /* such as ExposureMask, SubstructureNotifyMask */
|
|
{
|
|
EventData evt;
|
|
Wob wob;
|
|
|
|
SAVE_EVENT_CONTEXT;
|
|
XSync(dpy, 0);
|
|
while (XCheckMaskEvent(dpy, mask, &evt)) {
|
|
if ((wob = LookUpWob(evt.xany.window))
|
|
|| (wob = (Wob) LookUpClient(evt.xany.window))) {
|
|
WOOL_send(WOOL_process_event, wob, (wob, &evt));
|
|
}
|
|
}
|
|
RESTORE_EVENT_CONTEXT;
|
|
return NIL;
|
|
}
|
|
|
|
/* to remove unmapped events
|
|
problem: argument w does not seem to be correctly passed, so use global
|
|
*/
|
|
|
|
static Window WindowUnmapped;
|
|
|
|
int
|
|
GWM_remove_unmap_event(d, evt, arg)
|
|
Display *d;
|
|
XEvent *evt;
|
|
XPointer arg;
|
|
{
|
|
if (evt->xany.type == UnmapNotify
|
|
&& evt->xunmap.window == WindowUnmapped)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
wool_process_unmap_events(w)
|
|
Window w;
|
|
{
|
|
XEvent evt;
|
|
|
|
XSync(dpy, 0);
|
|
WindowUnmapped = w;
|
|
while (XCheckIfEvent(dpy, &evt, GWM_remove_unmap_event, (char *)w))
|
|
;
|
|
}
|
|
|
|
WOOL_OBJECT
|
|
wool_process_exposes()
|
|
{
|
|
return wool_process_masked_events(ExposureMask);
|
|
}
|
|
|
|
/*
|
|
* initialize X and Context
|
|
*/
|
|
|
|
GWM_OpenDisplay(display)
|
|
char *display;
|
|
{
|
|
GWM_Display = (char *) XDisplayName(display);
|
|
if ((dpy = XOpenDisplay(display)) == NULL) {
|
|
fprintf(stderr, "%s Cannot XOpenDisplay on %s\n",
|
|
err, XDisplayName(display));
|
|
exit(1);
|
|
}
|
|
#ifdef SHAPE
|
|
GWM_ShapeExtension = XShapeQueryExtension(dpy, &GWM_ShapeEventBase,
|
|
&GWM_ShapeErrorBase);
|
|
#endif /* SHAPE */
|
|
if (GWM_Synchronize)
|
|
XSynchronize(dpy, 1);
|
|
GWM_ScreenCount = ScreenCount(dpy);
|
|
wob_context = XUniqueContext();
|
|
client_context = XUniqueContext();
|
|
XSetErrorHandler(XError);
|
|
}
|
|
|
|
/* options handling
|
|
*/
|
|
|
|
char *
|
|
path_append(old_path, new_path)
|
|
char *old_path;
|
|
char *new_path;
|
|
{
|
|
char *path;
|
|
static int path_was_malloced;
|
|
|
|
switch(*new_path){
|
|
case '+': case '-': /* append & prepend */
|
|
if(path_was_malloced)
|
|
path = Realloc(old_path, strlen(old_path) + strlen(new_path) + 1);
|
|
else
|
|
path = Malloc(strlen(old_path) + strlen(new_path) + 1);
|
|
path_was_malloced = 1;
|
|
strcpy(path, (*new_path == '+' ? old_path : new_path+1));
|
|
strcat(path, ":");
|
|
strcat(path, (*new_path == '+' ? new_path+1 : old_path));
|
|
break;
|
|
default: /* replace */
|
|
if(path_was_malloced)
|
|
Free(old_path);
|
|
path = new_path;
|
|
path_was_malloced = 0;
|
|
}
|
|
return path;
|
|
}
|
|
|
|
usage()
|
|
{
|
|
fprintf(stderr, "USAGE: gwm OPTIONS [host:display]\n");
|
|
fprintf(stderr, "OPTIONS:\n");
|
|
fprintf(stderr, " -f file use file instead of .gwmrc\n");
|
|
fprintf(stderr, " -p path force GWMPATH\n");
|
|
fprintf(stderr, " -p +path appends to GWMPATH\n");
|
|
fprintf(stderr, " -p -path prepends to GWMPATH\n");
|
|
fprintf(stderr, " -d display manage display\n");
|
|
fprintf(stderr, " -x screens do not manage screens e.g. -x3,2,5\n");
|
|
fprintf(stderr, " -k pid send signal (def. SIGALRM) to pid when init is done\n");
|
|
fprintf(stderr, " -K signal number of signal to send for -k option\n");
|
|
fprintf(stderr, " -1 manages only 1 screen, the default one\n");
|
|
fprintf(stderr, " -r retries till it can manage screens\n");
|
|
fprintf(stderr, " -i input focus remains PointerRoot\n");
|
|
fprintf(stderr, " -F no freeze: never freeze server\n");
|
|
fprintf(stderr, " -t to turn tracing on (as (trace 1))\n");
|
|
fprintf(stderr, " -m to map all windows on startup\n");
|
|
fprintf(stderr, " -s synchronize X calls\n");
|
|
fprintf(stderr, " -q quiet: do not print startup banner\n");
|
|
fprintf(stderr, " -a asynchronously obeys button clicks\n");
|
|
fprintf(stderr, " -D debug: does not abort on error in profile\n");
|
|
fprintf(stderr, " -W decorate over another Window Manager\n");
|
|
fprintf(stderr, " -w window_id decorate ONLY one window\n");
|
|
fprintf(stderr, " -I read WOOL commands from stdin\n");
|
|
fprintf(stderr, " -P together with -I: print prompts\n");
|
|
#ifdef DEBUG
|
|
fprintf(stderr, " -T flags to trace some items:\n");
|
|
fprintf(stderr, " f for fsm events\n");
|
|
fprintf(stderr, " e for all X events\n");
|
|
fprintf(stderr, " l for all file loads\n");
|
|
fprintf(stderr, " m for malloc/frees\n");
|
|
#endif
|
|
fprintf(stderr, "\nGWMPATH is %s\n", wool_path);
|
|
fprintf(stderr, "built-in path was %s\n", DEFAULT_WLPATH);
|
|
}
|
|
|
|
GWM_getopts(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
|
|
{
|
|
extern int optind;
|
|
extern char *optarg;
|
|
char *display_name = 0;
|
|
char *s;
|
|
int c, errflag = 0;
|
|
|
|
wool_user_profile_name = WOOL_USER_PROFILE;
|
|
wool_text_extension = WOOL_TEXT_EXTENSION;
|
|
|
|
/* initialize paths (put .:$HOME before built-ins) */
|
|
wool_path = wool_fix_path(DEFAULT_WLPATH);
|
|
if ((s = (char *) getenv(WLPROFILE_USER_VARIABLE)) && (s[0] != '\0'))
|
|
wool_user_profile_name = s;
|
|
if ((s = (char *) getenv(WLPATH_SHELL_VARIABLE)) && (s[0] != '\0'))
|
|
wool_path = s;
|
|
if ((s = (char *) getenv("GWM_MONOSCREEN")) && (s[0] != '\0'))
|
|
GWM_Monoscreen = 1;
|
|
|
|
while ((c = getopt(argc, argv, "mtsb:p:f:DFT:w:Wd:iax:1qrk:K:IP")) != EOF) {
|
|
switch ((char) c) {
|
|
case 'I':
|
|
gwm_stdin = 1;
|
|
break;
|
|
case 'P':
|
|
gwm_prompt = 1;
|
|
break;
|
|
#ifdef USER_DEBUG
|
|
case 't': /* set trace level */
|
|
wool_tracing_on = 1;
|
|
break;
|
|
#endif /* USER_DEBUG */
|
|
#ifdef DEBUG
|
|
case 'T':
|
|
GWM_Tracelevel = atoi(optarg);
|
|
WlTraceFlags = optarg;
|
|
/* Current traceflags:
|
|
* l load files
|
|
* e All X events received
|
|
* f fsm MATCH/REJECTS
|
|
* m mallocs
|
|
* p pixmap creation
|
|
*/
|
|
break;
|
|
#endif /* DEBUG */
|
|
case 'i':
|
|
GWM_No_set_focus = 1;
|
|
break;
|
|
case 'm': /* map all windows found on startup */
|
|
GWM_Mapall = 1;
|
|
break;
|
|
case 's': /* no synchro in DEBUG mode */
|
|
GWM_Synchronize = 1;
|
|
break;
|
|
case 'r': /* retry on StructureRedirect */
|
|
GWM_RetryStart = 1;
|
|
break;
|
|
case 'f':
|
|
wool_user_profile_name = optarg;
|
|
break;
|
|
case 'p':
|
|
wool_path = path_append(wool_path, optarg);
|
|
break;
|
|
case 'D':
|
|
wool_continue_reading_on_error = 1;
|
|
break;
|
|
case 'F':
|
|
GWM_GrabServer = 0;
|
|
break;
|
|
case 'w':
|
|
GWM_Decorate_one_window = atoi(optarg);
|
|
break;
|
|
case 'W':
|
|
GWM_Decorate_all_windows = 1;
|
|
break;
|
|
case 'd':
|
|
display_name = optarg;
|
|
break;
|
|
case 'x':
|
|
GWM_ScreensNotManaged = optarg;
|
|
break;
|
|
case 'a':
|
|
GWM_UserSynchronous = 0;
|
|
break;
|
|
case '1':
|
|
GWM_Monoscreen = 1;
|
|
break;
|
|
case 'q':
|
|
GWM_quiet = 1;
|
|
break;
|
|
case 'k':
|
|
GWM_kill_pid = atoi(optarg);
|
|
break;
|
|
case 'K':
|
|
GWM_kill_pid_sig = atoi(optarg);
|
|
break;
|
|
case '?': /* usage */
|
|
default:
|
|
errflag++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!GWM_kill_pid_sig)
|
|
GWM_kill_pid_sig = SIGALRM;
|
|
|
|
if(!GWM_quiet || errflag)
|
|
GWM_print_banner();
|
|
|
|
if (errflag) {
|
|
usage();
|
|
exit(1);
|
|
}
|
|
GWM_OpenDisplay(optind < argc ? argv[optind] : display_name);
|
|
}
|
|
|
|
/*
|
|
* executes a function. Returns 1 on first wool_error, and aborts function.
|
|
*/
|
|
|
|
int
|
|
wool_error_occurred(function)
|
|
int (*function)();
|
|
{
|
|
if (set_wool_error_resume_point()) {
|
|
return 1;
|
|
}
|
|
ASSERT(function);
|
|
(*function)();
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
DecorateWindows()
|
|
/*
|
|
* called to make wobs other all pre-existing windows
|
|
*/
|
|
{
|
|
Window dummywin, parent; /* dummy parent */
|
|
Window *children; /* list of root sons */
|
|
unsigned int nchildren; /* number of children */
|
|
ClientWindow wob;
|
|
int i;
|
|
|
|
FOR_ALL_SCREENS {
|
|
if (XQueryTree(dpy, Context -> root, &dummywin, &parent,
|
|
&children, &nchildren)) {
|
|
SetTarget(Context -> rootWob);
|
|
GWM_ProcessingExistingWindows = 1;
|
|
for (i = 0; i < nchildren; i++) {
|
|
if (wob = LookUpClient(children[i]))
|
|
ClientWindowInitialMap(wob);
|
|
else if ((Mapped(children[i]) || GWM_Mapall)
|
|
&& ((!GWM_Decorate_one_window)
|
|
|| (GWM_Decorate_one_window == children[i]))) {
|
|
if (wob = (ClientWindow)
|
|
DecorateWindow(children[i],
|
|
Context -> rootWob, 1, 1)) {
|
|
ClientWindowInitialMap(wob);
|
|
}
|
|
}
|
|
}
|
|
GWM_ProcessingExistingWindows = 0;
|
|
XFreeN(children);
|
|
}
|
|
}END_OF_ALL_SCREENS;
|
|
}
|
|
|
|
/* initialise managed screens */
|
|
|
|
InitScreens()
|
|
{
|
|
FOR_ALL_SCREENS {
|
|
SetTarget(Context -> rootWob);
|
|
SetUpScreen(Context -> rootWob,
|
|
WOOL_send(WOOL_eval, WL_describe_screen_call,
|
|
(WL_describe_screen_call)));
|
|
ScreenOpen(Context -> rootWob);
|
|
}END_OF_ALL_SCREENS;
|
|
}
|
|
|
|
/* set up the list of managed screens: GWMManagedScreens */
|
|
|
|
RegisterScreens()
|
|
{
|
|
int screen_num;
|
|
int number_of_managed_screens = 0;
|
|
|
|
GWMManagedScreens = (GWMScreenContext *)
|
|
Calloc(sizeof(GWMScreenContext), ScreenCount(dpy));
|
|
|
|
/* parse list of non-managed screens and pokes them */
|
|
mark_numbers_in_list(ScreenCount(dpy), GWM_ScreensNotManaged,
|
|
GWMManagedScreens);
|
|
|
|
/* poke 1 in used screens, 0 in unused and count them
|
|
* manage only DefaultScreen if we are in Monoscreen mode
|
|
*/
|
|
for (screen_num = 0; screen_num < ScreenCount(dpy); screen_num++) {
|
|
if (GWMManagedScreens[screen_num]) {
|
|
GWMManagedScreens[screen_num] = NULL;
|
|
} else if ((!GWM_Monoscreen) || screen_num == DefaultScreen(dpy)) {
|
|
GWMManagedScreens[screen_num] = (GWMScreenContext) 1;
|
|
number_of_managed_screens++;
|
|
}
|
|
}
|
|
|
|
/* (abort if none left) */
|
|
if (!number_of_managed_screens)
|
|
GWM_Abort("no screen left to manage");
|
|
|
|
/* allocates and registers the managed screens */
|
|
for (screen_num = 0; screen_num < ScreenCount(dpy); screen_num++) {
|
|
if (GWMManagedScreens[screen_num]) {
|
|
GWMManagedScreens[screen_num] = RegisterScreen(screen_num);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* parses a comma-separated list of numbers (string) and pokes 1 in the list
|
|
* if comprised beetween 0 and max_n
|
|
*/
|
|
|
|
mark_numbers_in_list(max_n, string, list)
|
|
int max_n;
|
|
char *string;
|
|
WOOL_OBJECT *list;
|
|
{
|
|
int n;
|
|
|
|
while (string && *string) {
|
|
n = atoi(string);
|
|
if (*string >= '0' && *string <= '9'
|
|
&& n >= 0 && n < ScreenCount(dpy))
|
|
list[n] = (WOOL_OBJECT) 1;
|
|
if (string = strchr(string, ','))
|
|
string++;
|
|
else
|
|
return;
|
|
}
|
|
}
|
|
|