/*-
* Copyright (c) 2001 Jordan DeLong
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "plugutil.h"
/* per-screen structure */
static struct gnomescr {
Window wm_check; /* check window, also used as button proxy */
} *gnomescr = NULL;
/* win_state bitmask values */
#define WIN_STATE_STICKY (1L << 0)
#define WIN_STATE_MINIMIZED (1L << 1) /* ignored */
#define WIN_STATE_MAXIMIZED_VERT (1L << 2) /* ignored */
#define WIN_STATE_MAXIMIZED_HORIZ (1L << 3) /* ignored */
#define WIN_STATE_HIDDEN (1L << 4) /* ignored */
#define WIN_STATE_SHADED (1L << 5) /* ignored */
#define WIN_STATE_HID_WORKSPACE (1L << 6) /* ignored */
#define WIN_STATE_HID_TRANSIENT (1L << 7) /* ignored */
#define WIN_STATE_FIXED_POSITION (1L << 8)
#define WIN_STATE_ARRANGE_IGNORE (1L << 9) /* ignored */
/* win_hints bitmask values */
#define WIN_HINTS_SKIP_FOCUS (1L << 0)
#define WIN_HINTS_SKIP_WINLIST (1L << 1) /* ignored */
#define WIN_HINTS_SKIP_TASKBAR (1L << 2) /* ignored */
#define WIN_HINTS_GROUP_TRANSIENT (1L << 3) /* ignored */
#define WIN_HINTS_FOCUS_ON_CLICK (1L << 4) /* ignored */
#define WIN_HINTS_DO_NOT_COVER (1L << 5) /* ignored */
/* win_layer values */
#define WIN_LAYER_DESKTOP 0
#define WIN_LAYER_BELOW 2
#define WIN_LAYER_NORMAL 4
#define WIN_LAYER_ONTOP 6
#define WIN_LAYER_DOCK 8
#define WIN_LAYER_ABOVE_DOCK 10
#define WIN_LAYER_MENU 12
/* atoms */
static Atom win_supporting_wm_check;
static Atom win_state;
static Atom win_hints;
static Atom win_layer;
/* macros to get protocol atoms */
#define NUM_PROTOCOLS 6
#define WIN_CLIENT_LIST win_protocols_list[0]
#define WIN_DESKTOP_BUTTON_PROXY win_protocols_list[1]
#define WIN_WORKSPACE win_protocols_list[2]
#define WIN_WORKSPACE_COUNT win_protocols_list[3]
#define WIN_AREA_COUNT win_protocols_list[4]
#define WIN_AREA win_protocols_list[5]
/* _WIN_PROTOCOLS stuff */
static Atom win_protocols;
static Atom win_protocols_list[NUM_PROTOCOLS];
static char *win_protocols_names[NUM_PROTOCOLS] = {
"_WIN_CLIENT_LIST",
"_WIN_DESKTOP_BUTTON_PROXY",
"_WIN_WORKSPACE",
"_WIN_WORKSPACE_COUNT",
"_WIN_AREA_COUNT",
"_WIN_AREA"
};
/* set the list of clients for screen */
static int set_client_list(screen_t *screen) {
Window *list, *tmp;
client_t *client;
int size, count;
count = 0;
size = 10;
list = malloc(sizeof(Window) * size);
if (!list)
return -1;
/* recreate the list of clients */
LIST_FOREACH(client, &client_list, c_list)
if (!client->flags.internal && client->screen == screen) {
if (++count > size) {
tmp = realloc(list, sizeof(Window) * (size + size));
if (!tmp) {
free(list);
return -1;
}
list = tmp;
size += size;
}
list[count - 1] = client->window;
}
/* put it on the root window */
XChangeProperty(display, screen->root, WIN_CLIENT_LIST, XA_CARDINAL, 32,
PropModeReplace, (u_char *) list, count);
free(list);
return 0;
}
/* handle hints for newly arriving clients */
static int init_hints(int pcall, client_t *client) {
CARD32 *card;
Atom type;
u_long items, bytes;
int fmt;
/* _WIN_STATE hint */
if (XGetWindowProperty(display, client->window, win_state, 0, 1, 0,
XA_CARDINAL, &type, &fmt, &items, &bytes,
(u_char **) &card) == Success && card) {
if (*card & WIN_STATE_STICKY)
client->flags.sticky = 1;
if (*card & WIN_STATE_FIXED_POSITION) {
client->flags.noresize = 1;
client->flags.nomove = 1;
}
XFree(card);
}
/* _WIN_HINTS hint */
if (XGetWindowProperty(display, client->window, win_hints, 0, 1, 0,
XA_CARDINAL, &type, &fmt, &items, &bytes,
(u_char **) &card) == Success && card) {
if (*card & WIN_HINTS_SKIP_FOCUS)
client->flags.nofocus = 1;
XFree(card);
}
/* _WIN_LAYER hint */
if (XGetWindowProperty(display, client->window, win_layer, 0, 1, 0,
XA_CARDINAL, &type, &fmt, &items, &bytes,
(u_char **) &card) == Success && card) {
if (*card >= WIN_LAYER_DESKTOP && *card < WIN_LAYER_BELOW)
client->stacklayer = STACKLAYER_BOTTOM;
else if (*card < WIN_LAYER_NORMAL)
client->stacklayer = STACKLAYER_BELOW;
else if (*card < WIN_LAYER_ONTOP)
client->stacklayer = STACKLAYER_NORMAL;
else if (*card < WIN_LAYER_ABOVE_DOCK)
client->stacklayer = STACKLAYER_ABOVE;
else if (*card <= WIN_LAYER_MENU)
client->stacklayer = STACKLAYER_TIPTOP;
XFree(card);
}
return PLUGIN_OK;
}
/* when new windows arrive or cleave */
static int window_life(int pcall, client_t *client) {
if (set_client_list(client->screen) == -1)
return PLUGIN_UNLOAD;
return PLUGIN_OK;
}
/* workspace changes */
static int workspace_change(int pcall, screen_t *screen, desktop_t *desktop) {
CARD32 val[2];
if (desktop == screen->desktop) {
val[0] = (CARD32) screen->desktop->viewx;
val[1] = (CARD32) screen->desktop->viewy;
XChangeProperty(display, screen->root, WIN_AREA, XA_CARDINAL,
32, PropModeReplace, (u_char *) val, 2);
}
return PLUGIN_OK;
}
/* when the user switches desktops */
static int desktop_change(int pcall, screen_t *screen, desktop_t *olddesk) {
CARD32 val[2];
/* set the workspace area properties */
val[0] = (CARD32) screen->desktop->width;
val[1] = (CARD32) screen->desktop->height;
XChangeProperty(display, screen->root, WIN_AREA_COUNT, XA_CARDINAL,
32, PropModeReplace, (u_char *) val, 2);
/* now set the current desktop */
val[0] = (CARD32) screen->desktop->num;
XChangeProperty(display, screen->root, WIN_WORKSPACE, XA_CARDINAL,
32, PropModeReplace, (u_char *) val, 1);
/* desktop change also changes workspace */
return workspace_change(pcall, screen, screen->desktop);
}
/* button press on the root window */
static int root_button(int pcall, screen_t *screen, XButtonEvent *e) {
if (e->type == ButtonPress)
XUngrabPointer(display, CurrentTime);
XSendEvent(display, gnomescr[screen->num].wm_check, 0,
SubstructureNotifyMask, (XEvent *) e);
return PLUGIN_OK;
}
/* plugin death */
void shutdown() {
screen_t *screen;
/* kill our per-screen structure */
if (!gnomescr)
return;
/* for each managed screen */
TAILQ_FOREACH(screen, &screen_list, s_list) {
XDeleteProperty(display, RootWindow(display, screen->num),
win_supporting_wm_check);
XDeleteProperty(display, RootWindow(display, screen->num),
win_protocols);
XDeleteProperty(display, RootWindow(display, screen->num),
WIN_DESKTOP_BUTTON_PROXY);
XDeleteProperty(display, RootWindow(display, screen->num),
WIN_CLIENT_LIST);
if (gnomescr[screen->num].wm_check)
XDestroyWindow(display, gnomescr[screen->num].wm_check);
}
free(gnomescr);
}
/* alloc stuff; create the gnome window check window */
int start() {
XSetWindowAttributes attr;
screen_t *screen;
CARD32 val[2];
/* register callbacks */
plugin_callback_add(plugin_this, PCALL_INIT_HINTS, init_hints);
plugin_callback_add(plugin_this, PCALL_WINDOW_BIRTH, window_life);
plugin_callback_add(plugin_this, PCALL_WINDOW_DEATH, window_life);
plugin_callback_add(plugin_this, PCALL_WORKSPACE_CHANGE, workspace_change);
plugin_callback_add(plugin_this, PCALL_DESKTOP_CHANGE, desktop_change);
plugin_callback_add(plugin_this, PCALL_ROOT_BUTTON, root_button);
/* get memory for the per-screen structure */
gnomescr = calloc(screen_count, sizeof(struct gnomescr));
if (!gnomescr)
return PLUGIN_UNLOAD;
/* get atoms */
win_supporting_wm_check = XInternAtom(display, "_WIN_SUPPORTING_WM_CHECK", 0);
win_state = XInternAtom(display, "_WIN_STATE", 0);
win_hints = XInternAtom(display, "_WIN_HINTS", 0);
win_layer = XInternAtom(display, "_WIN_LAYER", 0);
/* get win protocols atoms */
win_protocols = XInternAtom(display, "_WIN_PROTOCOLS", 0);
XInternAtoms(display, win_protocols_names, NUM_PROTOCOLS,
0, win_protocols_list);
/* fill in the per-screen structure */
attr.override_redirect = 1;
TAILQ_FOREACH(screen, &screen_list, s_list) {
/* create the gnome-compliance check window */
gnomescr[screen->num].wm_check = XCreateWindow(display, screen->root,
-30, -30, 2, 2, 0, CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect, &attr);
XChangeProperty(display, screen->root, win_supporting_wm_check, XA_CARDINAL,
32, PropModeReplace, (u_char *) &gnomescr[screen->num].wm_check, 1);
XChangeProperty(display, gnomescr[screen->num].wm_check,
win_supporting_wm_check, XA_CARDINAL, 32, PropModeReplace,
(u_char *) &gnomescr[screen->num].wm_check, 1);
/* set the win_protocols list onto the root window */
XChangeProperty(display, screen->root, win_protocols, XA_ATOM,
32, PropModeReplace, (u_char *) win_protocols_list, NUM_PROTOCOLS);
/* reuse the check window as the button proxy window */
XChangeProperty(display, screen->root, WIN_DESKTOP_BUTTON_PROXY, XA_CARDINAL,
32, PropModeReplace, (u_char *) &gnomescr[screen->num].wm_check, 1);
XChangeProperty(display, gnomescr[screen->num].wm_check,
WIN_DESKTOP_BUTTON_PROXY, XA_CARDINAL, 32, PropModeReplace,
(u_char *) &gnomescr[screen->num].wm_check, 1);
/* setup workspace count, current workspace */
val[0] = (CARD32) screen->desktop_count;
XChangeProperty(display, screen->root, WIN_WORKSPACE_COUNT, XA_CARDINAL, 32,
PropModeReplace, (u_char *) val, 1);
val[0] = (CARD32) screen->desktop->num;
XChangeProperty(display, screen->root, WIN_WORKSPACE, XA_CARDINAL,
32, PropModeReplace, (u_char *) val, 1);
/* set the workspace area properties */
val[0] = (CARD32) screen->desktop->width;
val[1] = (CARD32) screen->desktop->height;
XChangeProperty(display, screen->root, WIN_AREA_COUNT, XA_CARDINAL,
32, PropModeReplace, (u_char *) val, 2);
val[0] = (CARD32) screen->desktop->viewx;
val[1] = (CARD32) screen->desktop->viewy;
XChangeProperty(display, screen->root, WIN_AREA, XA_CARDINAL,
32, PropModeReplace, (u_char *) val, 2);
/* setup the CLIENT_LIST on the screen*/
if (set_client_list(screen) == -1)
return PLUGIN_UNLOAD;
}
return PLUGIN_OK;
}
syntax highlighted by Code2HTML, v. 0.9.1