Generic_Window_Manager/screen.c

645 lines
18 KiB
C

/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
* Copyright 1989 Massachusetts Institute of Technology
*/
/************************************************\
* *
* BULL WINDOW MANAGER for X11 . *
* *
* MODULE defining the Screen Wob Class. *
* *
\************************************************/
/* include */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "EXTERN.h"
#include "wool.h"
#include "wl_atom.h"
#include "wl_list.h"
#include "wl_number.h"
#include "wl_string.h"
#include "gwm.h"
#include "wl_fsm.h"
#include "wl_pixmap.h"
#include "wl_cursor.h"
#include "wl_client.h"
/* local constants */
/* external */
extern Wob NewWob();
extern ClientWindow LookUpClient(), DecorateWindow();
extern ScreenOpen(), ScreenClose(), ScreenEventHandler(), ReconfigureScreen();
WOB_METHOD ScreenClass[] = {
0, /* METHODS_ARRAY */
WobEval,
WobPrint,
WobRelease,
WobExecute,
WobSet,
WobGetCValue,
ScreenOpen,
ScreenClose,
ScreenEventHandler,
(WOB_METHOD) wool_undefined_method_1,
WobGetDimensions,
(WOB_METHOD) wool_undefined_method_2,
(WOB_METHOD) wool_undefined_method_2,
(WOB_METHOD) ReconfigureScreen,
(WOB_METHOD) wool_undefined_method_2,
(WOB_METHOD) wool_undefined_method_1,
(WOB_METHOD) wool_undefined_method_1,
(WOB_METHOD) wool_undefined_method_1,
(WOB_METHOD) wool_undefined_method_1,
(WOB_METHOD) wool_undefined_method_1
};
/*
* Set up Screen Wob. Usually called from SetUpWob.
*/
ScreenOpen(screen)
ClientWindow screen;
{
screen -> curstate = (int)
WOOL_send(WOOL_open, screen -> fsm, (screen -> fsm));
if (screen -> cursor != NIL)
XDefineCursor(dpy, screen -> hook,
((WOOL_Cursor) screen -> cursor) -> cursor);
if (screen -> tile != NIL)
wool_set_screen_background(screen -> tile);
screen -> input_mask = RootMask | ((WOOL_Fsm) screen -> fsm) -> mask;
XSelectInput(dpy, screen -> hook, screen -> input_mask);
SetTarget(screen);
}
/* Initialize screen data in the list of managed screens
* This function is called BEFORE user profile
*/
GWMScreenContext
RegisterScreen(screen_number)
int screen_number;
{
XSetWindowAttributes wa;
Context = (GWMScreenContext) Malloc(sizeof(struct _GWMScreenContext));
bzero(Context, sizeof(struct _GWMScreenContext));
Context -> screen = screen_number;
Context -> x_screen = ScreenOfDisplay(dpy, screen_number);
Context -> width = DisplayWidth(dpy, screen_number);
Context -> height = DisplayHeight(dpy, screen_number);
Context -> depth = DisplayPlanes(dpy, screen_number);
Context -> widthMM = DisplayWidthMM(dpy, screen_number);
Context -> heightMM = DisplayHeightMM(dpy, screen_number);
Context -> root = RootWindow(dpy, screen_number);
Context -> rootWob = (ClientWindow) NewWob(sizeof(struct _ClientWindow));
Context -> rootWob -> parent = (Wob) NULL; /* to stop recursion */
Context -> rootWob -> type = ScreenClass;
Context -> rootWob -> hook = Context -> root;
Context -> rootWob -> client = Context -> root;
Context -> rootWob -> status = RootStatus;
Context -> rootWob -> window = Context -> rootWob;
Context -> rootWob -> icon = Context -> rootWob;
Context -> rootWob -> box.width = Context -> width;
Context -> rootWob -> box.height = Context -> height;
Context -> rootWob -> screen = Context;
/* init root window colormap */
wa.colormap = Context -> rootWob -> colormap =
DefaultColormap(dpy, Context -> screen);
XChangeWindowAttributes(dpy, Context -> root, CWColormap, &wa);
XInstallColormap(dpy, wa.colormap);
Context -> InstalledColormapCW = Context -> rootWob;
WobRecordHook(Context -> rootWob);
return Context;
}
/* initialize screen AFTER user profile & root window
*/
SetUpScreen(screen, wl_client)
ClientWindow screen;
WOOL_Client wl_client;
{
if (wl_client -> type != WLClient) {
wool_puts("\007GWM: screen not described! -- check your .gwmrc!\n");
exit(1);
}
screen -> box.x = 0;
screen -> box.y = 0;
screen -> box.borderwidth = 0;
screen -> box.width = Context -> width;
screen -> box.height = Context -> height;
screen -> box.background = wl_client -> background;
increase_reference(screen -> cursor = wl_client -> cursor);
increase_reference(screen -> fsm = wl_client -> fsm);
increase_reference(screen -> menu = wl_client -> menu);
increase_reference(screen -> property =
(WOOL_OBJECT) wl_client -> property);
/* bordertile is used to store the background */
increase_reference(screen -> tile = wl_client -> tile);
increase_reference(screen -> opening = wl_client -> opening);
increase_reference(screen -> closing = wl_client -> closing);
increase_reference(screen -> grabs = (WOOL_OBJECT) wl_client -> grabs);
increase_reference(screen -> icon_plug =
(WOOL_OBJECT) wl_client -> icon_plug);
fix_fsm(&(screen -> fsm));
screen -> cached_props = (CWCachedProperties)
Malloc(sizeof(struct _CWCachedProperties));
bzero(screen -> cached_props, sizeof(struct _CWCachedProperties));
#define update_cached_field(name, val) \
increase_reference(screen -> cached_props -> name = (WOOL_OBJECT) val)
update_cached_field(clientclass, NIL_STRING);
update_cached_field(clientname, NIL_STRING);
update_cached_field(machinename, NIL_STRING);
update_cached_field(windowname, NIL_STRING);
update_cached_field(iconname, NIL_STRING);
CreateGwmLabelWindow();
}
/* Called when an event is reported to rootWindow.
* There we detect and decorate newly created windows on first map
*/
ScreenEventHandler(screen, evt)
ClientWindow screen;
Event evt;
{
ClientWindow wob;
switch (evt->type) {
case MapRequest: /* look if this window is not yet
* managed to decorate it */
SetTarget(screen);
if (evt->xmaprequest.parent == Context->root)
if (wob = (ClientWindow) LookUpWob(evt->xmaprequest.window)) {
if (!(wob->opening)) /* has already been mapped */
XMapWindow(dpy, evt->xmaprequest.window);
} else {
if (wob = LookUpClient(evt->xmaprequest.window)) {
if (wob->opening) {
ClientWindowExecuteOpening(wob);
ClientWindowInitialMap(wob);
}
} else {
wob = DecorateWindow(evt->xmaprequest.window,
screen, 1, 1);
ClientWindowInitialMap(wob);
}
}
break;
case ColormapNotify: /* the screen colormap has changed:
* reflect it if the current wob has
* no defined colormap */
if (evt->xcolormap.new) { /* colormap has changed */
SetTarget(screen);
screen->colormap = (evt->xcolormap.colormap == None ?
DefaultColormap(dpy, Context->screen) :
evt->xcolormap.colormap);
if (Context->InstalledColormapCW == screen ||
!Context->InstalledColormapCW ||
Context->InstalledColormapCW->colormap == None)
XInstallColormap(dpy, screen->colormap);
}
break;
case UnmapNotify:{ /* iccc: to withdraw a window */
ClientWindow cw;
if (evt->xunmap.send_event
&& evt->xunmap.from_configure == False
&& (cw = LookUpClient(evt->xunmap.window))) {
if (cw->icon)
ClientWindowUnmap(cw->icon);
ClientWindowUnmap(cw);
cw->cached_props->user_icon = 0;
UnDecorateWindow(cw, 1, 0);
}
}
break;
case ConfigureRequest:{ /* unmapped window */
ClientWindow cw;
/* warning: window may have been redecorated meanwhile */
if (cw = (ClientWindow)
LookUpClient(evt->xconfigurerequest.window)) {
ConfigureRequestEventHandler(cw, evt); /* was remapped */
} else if (evt->xconfigurerequest.window != Context->root) {
ConfigureUnmappedWindow(evt); /* not yet known, obey */
}
}
break;
case PropertyNotify: /* GWM_EXECUTE */
SetTarget(screen);
if (evt->xproperty.atom == XA_GWM_EXECUTE) {
WlExecGWM_EXECUTE();
} else {
WLFsm_action(screen->fsm, screen, evt);
}
break;
default:
WLFsm_action(screen->fsm, screen, evt);
}
}
/* Here we clean up everything for the next WM
*/
int
ScreenClose(screen)
ClientWindow screen;
{
ClientWindow cw;
if (screen -> closing)
WOOL_send(WOOL_eval, screen -> closing, (screen -> closing));
if (Context -> WindowCount) {
cw = Context -> rootWob -> next;
while (cw) {
if (cw -> status & ClientWindowStatus) {
SetTarget(cw);
UnDecorateWindow(cw, 1, 1);
}
cw = cw -> next;
}
}
decrease_reference(screen -> opening);
decrease_reference(screen -> closing);
decrease_reference(screen -> grabs);
decrease_reference(screen -> icon_plug);
WobRelease(screen);
return OK;
}
/* the "current screen" functions
*/
WOOL_OBJECT
wool_current_screen_get()
{
return (WOOL_OBJECT) WLNumber_make(Context -> screen);
}
WOOL_OBJECT
wool_current_screen_set(number)
WOOL_Number number;
{
must_be_number(number, 0);
if(GWMManagedScreens[number -> number]) {
SetTarget(GWMManagedScreens[number -> number] -> rootWob);
return (WOOL_OBJECT) number;
}else{
return NIL;
}
}
/* same with "current root-window" */
WOOL_OBJECT
wool_get_root_window()
{
return (WOOL_OBJECT) WLNumber_make(Context -> rootWob);
}
WOOL_OBJECT
wool_set_root_window(number)
WOOL_Number number;
{
must_be_number(number, 0);
SetTarget(number -> number);
return (WOOL_OBJECT) WLNumber_make(Context -> rootWob);
}
/* sets Context to DefaultScreen, or first one... */
SetDefaultScreen()
{
if (GWMManagedScreens[DefaultScreen(dpy)]) {
SetTarget(GWMManagedScreens[DefaultScreen(dpy)] -> rootWob);
GWM_DefaultScreen = DefaultScreen(dpy);
} else {
for (ContextPtr = GWMManagedScreens;; ContextPtr++)
if (*ContextPtr) {
SetTarget((*ContextPtr) -> rootWob);
GWM_DefaultScreen = (*ContextPtr) -> screen;
return;
}
}
}
int
ScreenOfRoot(window)
Window window;
{
int screen;
for (screen = 0; screen < ScreenCount(dpy); screen++)
if (RootWindow(dpy, screen) == window)
return screen;
return -1;
}
/* does nothing
*/
ReconfigureScreen(screen, culprit)
Wob screen, culprit;
{}
/********************************************\
* *
* "Meter" gestion (window to display infos) *
* *
\********************************************/
/* create the X window for the meter. called at screen initialization
*/
MeterCreate()
{
XGCValues gcv;
XSetWindowAttributes wa;
Context -> meter.x = 0;
Context -> meter.y = 0;
Context -> meter.width = 1;
Context -> meter.height = 1;
Context -> meter.anchor_x = Context -> meter.anchor_y = 0;
Context -> meter.gravity = 1;
Context -> meter.borderwidth = 0;
Context -> meter.font = DefaultFont;
Context -> meter.foreground = Context -> pixel.Back;
Context -> meter.background = Context -> pixel.Fore;
Context -> meter.borderpixel = Context -> pixel.Back;
Context -> meter.horizontal_margin = 2;
Context -> meter.vertical_margin = 2;
Context -> meter.string_length = 60;
Context -> meter.string = (char *) Malloc(60);
Context -> meter.window = XCreateSimpleWindow(dpy, Context -> root,
Context -> meter.x, Context -> meter.y,
Context -> meter.width, Context -> meter.height,
0, 0, Context -> meter.background);
gcv.foreground = Context -> meter.foreground;
gcv.background = Context -> meter.background;
gcv.function = GXcopy;
gcv.graphics_exposures = False;
Context -> meter.gc = XCreateGC(dpy, Context -> root,
GCForeground | GCBackground | GCFunction | GCGraphicsExposures, &gcv);
XSelectInput(dpy, Context -> meter.window, MeterMask);
wa.override_redirect = 1;
XChangeWindowAttributes(dpy, Context -> meter.window,
CWOverrideRedirect, &wa);
XSetFont(dpy, Context -> meter.gc, Context -> meter.font);
XSetForeground(dpy, Context -> meter.gc, Context -> meter.foreground);
XSetBackground(dpy, Context -> meter.gc, Context -> meter.background);
}
/* pop up the meter with room for string
*/
MeterOpen(string)
char *string;
{
MeterUpdate(string);
XMapRaised(dpy, Context -> meter.window);
}
/* unmaps the meter
*/
WOOL_OBJECT
MeterClose()
{
XClearWindow(dpy, Context -> meter.window);
XUnmapWindow(dpy, Context -> meter.window);
return NIL;
}
/* displays another string in the meter, updates size.
*/
MeterUpdate(string)
char *string;
{
int up, down, dir, width, height, l;
XCharStruct extent;
XQueryTextExtents(dpy, Context -> meter.font,
string, strlen(string),
&dir, &up, &down, &extent);
Context->meter.string_x = Context -> meter.horizontal_margin
- extent.lbearing;
Context->meter.string_y = Context -> meter.vertical_margin + up;
width = extent.width + 2 * Context -> meter.horizontal_margin;
height = up + down + 2 * Context -> meter.vertical_margin;
if (width != Context -> meter.width || height != Context -> meter.height)
XResizeWindow(dpy, Context -> meter.window,
Context -> meter.width = width,
Context -> meter.height = height);
if ((l = strlen(string)) >= Context -> meter.string_length) {
Context -> meter.string_length = Max(
2 * Context -> meter.string_length + 4, l + 1);
Context -> meter.string = (char *) Realloc(Context -> meter.string,
Context -> meter.string_length);
}
strcpy(Context -> meter.string, string);
PlaceWinWithGravity(Context -> meter.window,
Context -> meter.gravity,
Context -> meter.anchor_x,
Context -> meter.anchor_y,
&(Context -> meter.x),
&(Context -> meter.y),
Context -> meter.width,
Context -> meter.height,
Context -> meter.borderwidth);
MeterRefresh();
}
MeterRefresh()
{
XClearWindow(dpy, Context -> meter.window);
XDrawString(dpy, Context -> meter.window, Context -> meter.gc,
Context->meter.string_x, Context->meter.string_y,
Context->meter.string, strlen(Context->meter.string));
}
/* pops menu from wool
*/
WOOL_OBJECT
wool_meter_open(argc, argv)
int argc;
WOOL_Number argv[];
{
switch(argc){
case 3:
Context -> meter.anchor_x = argv[0] -> number;
Context -> meter.anchor_y = argv[1] -> number;
MeterOpen(((WOOL_String) argv[2]) -> string);
break;
case 1:
MeterOpen(((WOOL_String) argv[0]) -> string);
break;
default:
return wool_error(BAD_NUMBER_OF_ARGS, argc);
}
return NIL;
}
/* displays a string in the meter
*/
WOOL_OBJECT
wool_meter_update(string)
WOOL_String string;
{
MeterUpdate(string -> string);
return (WOOL_OBJECT) string;
}
/* change graphics of meter
* usage: (meter <key value>...)
* where key can be:
* font
* background
* foreground
* horizontal-margin
* vertical-margin
* x
* y
* gravity
* borderpixel
* borderwidth
*/
WOOL_OBJECT
wool_meter_modify(argc, argv)
int argc;
WOOL_Atom argv[];
{
WOOL_Atom *key = argv, *last_key = argv + argc;
WOOL_List result;
WOOL_OBJECT *result_index;
if (argc % 2)
if (argc == 1) {
must_be_or_nil(WLList, argv[0], 0);
if (argv[0] == (WOOL_Atom) NIL) {
return NIL;
} else {
key = (WOOL_Atom *) ((WOOL_List) argv[0]) -> list;
last_key = (WOOL_Atom *) key +
((WOOL_List) argv[0]) -> size;
}
} else
wool_error(BAD_NUMBER_OF_ARGS, argc);
result = wool_list_make(last_key - key);
result_index = &(result -> list[0]);
for (; key < last_key; key += 2) {
WOOL_Atom old_key = *key;
int old_value;
if (*key == WA_font) {
old_value = Context -> meter.font;
Context -> meter.font = get_C_from_object(key[1]);
XSetFont(dpy, Context -> meter.gc, Context -> meter.font);
} else if (*key == WA_background) {
old_value = Context -> meter.background;
Context -> meter.background = get_C_from_object(key[1]);
XSetBackground(dpy, Context -> meter.gc,
Context -> meter.background);
XSetWindowBackground(dpy, Context -> meter.window,
Context -> meter.background);
} else if (*key == WA_foreground) {
old_value = Context -> meter.foreground;
Context -> meter.foreground = get_C_from_object(key[1]);
XSetForeground(dpy, Context -> meter.gc,
Context -> meter.foreground);
} else if (*key == WA_horizontal_margin) {
old_value = Context -> meter.horizontal_margin;
Context -> meter.horizontal_margin = get_C_from_object(key[1]);
} else if (*key == WA_vertical_margin) {
old_value = Context -> meter.vertical_margin;
Context -> meter.vertical_margin = get_C_from_object(key[1]);
} else if (*key == WA_x) {
old_value = Context -> meter.anchor_x;
Context -> meter.anchor_x = get_C_from_object(key[1]);
} else if (*key == WA_y) {
old_value = Context -> meter.anchor_y;
Context -> meter.anchor_y = get_C_from_object(key[1]);
} else if (*key == WA_gravity) {
old_value = Context -> meter.gravity;
Context -> meter.gravity = get_C_from_object(key[1]);
} else if (*key == WA_borderwidth) {
old_value = Context -> meter.borderwidth;
XSetWindowBorderWidth(dpy, Context -> meter.window,
Context -> meter.borderwidth
= get_C_from_object(key[1]));
} else if (*key == WA_borderpixel) {
old_value = Context -> meter.borderpixel;
XSetWindowBorder(dpy, Context -> meter.window,
Context -> meter.borderpixel
= get_C_from_object(key[1]));
} else {
if (wool_warning("GWM WARNING: ")) {
wool_print(*key);
wool_puts(" is not a key\n");
}
old_key = NULL;
}
if (old_key) {
increase_reference(*result_index++ = (WOOL_OBJECT) old_key);
increase_reference(*result_index++ =
(WOOL_OBJECT) WLNumber_make(old_value));
}
}
if (result -> size = result_index - &(result -> list[0]))
return (WOOL_OBJECT) result;
else
return NIL;
}
/* handles event.
* returns 1 if was for a meter, 0 otherwise
*/
int
MeterEventHandler(evt)
Event evt;
{
ClientWindow wob;
if(GWM_is_ending)
return 1;
FOR_ALL_SCREENS {
if (evt -> xany.window == Context -> meter.window) {
switch (evt -> type) {
case Expose:
MeterRefresh();
break;
}
return 1;
}
}END_OF_ALL_SCREENS;
return 0;
}