/* Skippy - Seduces Kids Into Perversion
*
* Copyright (C) 2004 Hyriand <hyriand@thegraveyard.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "skippy.h"
#define WM_PERSONALITY_NETWM 0
#define WM_PERSONALITY_GNOME 1
/* From WindowMaker's gnome.c */
#define WIN_HINTS_SKIP_FOCUS (1<<0) /*"alt-tab" skips this win*/
#define WIN_HINTS_SKIP_WINLIST (1<<1) /*do not show in window list*/
#define WIN_HINTS_SKIP_TASKBAR (1<<2) /*do not show on taskbar*/
#define WIN_HINTS_GROUP_TRANSIENT (1<<3) /*Reserved - definition is unclear*/
#define WIN_HINTS_FOCUS_ON_CLICK (1<<4) /*app only accepts focus if clicked*/
#define WIN_HINTS_DO_NOT_COVER (1<<5) /* attempt to not cover this window */
#define WIN_STATE_STICKY (1<<0) /*everyone knows sticky*/
#define WIN_STATE_MINIMIZED (1<<1) /*Reserved - definition is unclear*/
#define WIN_STATE_MAXIMIZED_VERT (1<<2) /*window in maximized V state*/
#define WIN_STATE_MAXIMIZED_HORIZ (1<<3) /*window in maximized H state*/
#define WIN_STATE_HIDDEN (1<<4) /*not on taskbar but window visible*/
#define WIN_STATE_SHADED (1<<5) /*shaded (MacOS / Afterstep style)*/
/* these are bogus states defined in "the spec" */
#define WIN_STATE_HID_WORKSPACE (1<<6) /*not on current desktop*/
#define WIN_STATE_HID_TRANSIENT (1<<7) /*owner of transient is hidden*/
#define WIN_STATE_FIXED_POSITION (1<<8) /*window is fixed in position even*/
#define WIN_STATE_ARRANGE_IGNORE (1<<9) /*ignore for auto arranging*/
static int WM_PERSONALITY = WM_PERSONALITY_NETWM,
NETWM_HAS_FULLSCREEN = 0,
IGNORE_SKIP_TASKBAR = 0;
void
wm_get_atoms(Display *dpy)
{
XA_WM_STATE = XInternAtom(dpy, "WM_STATE", 0);
WM_CLIENT_LEADER = XInternAtom(dpy, "WM_CLIENT_LEADER", 0);
XA_UTF8_STRING = XInternAtom(dpy, "UTF8_STRING", 0);
_XROOTPMAP_ID = XInternAtom(dpy, "_XROOTPMAP_ID", 0);
ESETROOT_PMAP_ID = XInternAtom(dpy, "ESETROOT_PMAP_ID", 0);
_NET_SUPPORTING_WM_CHECK = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", 0);
_NET_SUPPORTED = XInternAtom(dpy, "_NET_SUPPORTED", 0);
_NET_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", 0);
_NET_CLIENT_LIST = XInternAtom(dpy, "_NET_CLIENT_LIST", 0);
_NET_CLIENT_LIST_STACKING = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", 0);
_NET_CURRENT_DESKTOP = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", 0);
_NET_WM_DESKTOP = XInternAtom(dpy, "_NET_WM_DESKTOP", 0);
_NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", 0);
_NET_WM_STATE_HIDDEN = XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", 0);
_NET_WM_STATE_SKIP_TASKBAR = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", 0);
_NET_WM_STATE_SKIP_PAGER = XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", 0);
_NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", 0);
_NET_WM_STATE_SHADED = XInternAtom(dpy, "_NET_WM_STATE_SHADED", 0);
_NET_WM_STATE_ABOVE = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", 0);
_NET_WM_STATE_STICKY = XInternAtom(dpy, "_NET_WM_STATE_STICKY", 0);
_NET_WM_WINDOW_TYPE = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", 0);
_NET_WM_WINDOW_TYPE_DESKTOP = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", 0);
_NET_WM_WINDOW_TYPE_DOCK = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0);
_NET_WM_VISIBLE_NAME = XInternAtom(dpy, "_NET_WM_VISIBLE_NAME", 0);
_NET_WM_NAME = XInternAtom(dpy, "_NET_WM_VISIBLE_NAME", 0);
_WIN_SUPPORTING_WM_CHECK = XInternAtom(dpy, "_WIN_SUPPORTING_WM_CHECK", 0);
_WIN_WORKSPACE = XInternAtom(dpy, "_WIN_WORKSPACE", 0);
_WIN_WORKSPACE_COUNT = XInternAtom(dpy, "_WIN_WORKSPACE_COUNT", 0);
_WIN_PROTOCOLS = XInternAtom(dpy, "_WIN_PROTOCOLS", 0);
_WIN_CLIENT_LIST = XInternAtom(dpy, "_WIN_CLIENT_LIST", 0);
_WIN_STATE = XInternAtom(dpy, "_WIN_STATE", 0);
_WIN_HINTS = XInternAtom(dpy, "_WIN_HINTS", 0);
}
char
wm_check_netwm(Display *dpy)
{
Window wm_check;
unsigned char *data, *data2;
int status, real_format;
Atom real_type;
unsigned long items_read, items_left, i;
char req = 0;
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _NET_SUPPORTING_WM_CHECK,
0L, 1L, False, XA_WINDOW, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success || ! items_read) {
if(status == Success)
XFree(data);
return 0;
}
wm_check = ((Window*)data)[0];
XFree(data);
status = XGetWindowProperty(dpy, wm_check, _NET_SUPPORTING_WM_CHECK,
0L, 1L, False, XA_WINDOW, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success && ! items_read) {
if(status == Success)
XFree(data);
return 0;
}
if(wm_check != ((Window*)data)[0]) {
XFree(data);
return 0;
}
XFree(data);
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _NET_SUPPORTED,
0L, 8192L, False, XA_ATOM, &real_type, &real_format,
&items_read, &items_left, &data2);
if(status != Success || ! items_read) {
if(status == Success)
XFree(data2);
return 0;
}
for(i = 0; i < items_read; i++) {
if(((Atom*)data2)[i] == _NET_NUMBER_OF_DESKTOPS)
req |= 1;
else if(((Atom*)data2)[i] == _NET_CURRENT_DESKTOP)
req |= 2;
else if(((Atom*)data2)[i] == _NET_WM_STATE)
req |= 4;
else if(((Atom*)data2)[i] == _NET_CLIENT_LIST)
req |= 8;
else if(((Atom*)data2)[i] == _NET_CLIENT_LIST_STACKING)
req |= 16;
else if(((Atom*)data2)[i] == _NET_WM_STATE_FULLSCREEN)
NETWM_HAS_FULLSCREEN = 1;
}
XFree(data2);
if(req & 16) {
req |= 8;
_NET_CLIENT_LIST = _NET_CLIENT_LIST_STACKING;
}
return ((req & 15) == 15);
}
char
wm_check_gnome(Display *dpy)
{
Window wm_check;
unsigned char *data, *data2;
int status, real_format;
Atom real_type;
unsigned long items_read, items_left, i;
char req = 0;
WM_PERSONALITY = WM_PERSONALITY_GNOME;
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _WIN_SUPPORTING_WM_CHECK,
0L, 1L, False, XA_CARDINAL, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success || ! items_read) {
if(status == Success)
XFree(data);
return 0;
}
wm_check = ((Window*)data)[0];
XFree(data);
status = XGetWindowProperty(dpy, wm_check, _WIN_SUPPORTING_WM_CHECK,
0L, 1L, False, XA_CARDINAL, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success && ! items_read) {
if(status == Success)
XFree(data);
return 0;
}
if(wm_check != ((Window*)data)[0]) {
XFree(data);
return 0;
}
XFree(data);
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _WIN_PROTOCOLS,
0L, 8192L, False, XA_ATOM, &real_type, &real_format,
&items_read, &items_left, &data2);
if(status != Success || ! items_read) {
if(status == Success)
XFree(data2);
return 0;
}
for(i = 0; i < items_read; i++) {
if(((Atom*)data2)[i] == _WIN_WORKSPACE)
req |= 1;
else if(((Atom*)data2)[i] == _WIN_WORKSPACE_COUNT)
req |= 2;
else if(((Atom*)data2)[i] == _WIN_STATE)
req |= 4;
else if(((Atom*)data2)[i] == _WIN_CLIENT_LIST)
req |= 8;
}
XFree(data2);
return ((req & 15) == 15);
}
char
wm_check(Display *dpy)
{
return wm_check_netwm(dpy) || wm_check_gnome(dpy);
}
dlist *
wm_get_stack(Display *dpy)
{
dlist *l = 0;
unsigned char *data;
int status, real_format;
Atom real_type;
unsigned long items_read, items_left, i;
if(WM_PERSONALITY == WM_PERSONALITY_NETWM)
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _NET_CLIENT_LIST,
0L, 8192L, False, XA_WINDOW, &real_type, &real_format,
&items_read, &items_left, &data);
else
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _WIN_CLIENT_LIST,
0L, 8192L, False, XA_CARDINAL, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success)
return 0;
for(i = 0; i < items_read; i++)
l = dlist_add(l, (void*)((CARD32*)data)[i]);
XFree(data);
return l;
}
Pixmap
wm_get_root_pmap(Display *dpy)
{
Pixmap rootpmap = None;
unsigned char *data;
int status, real_format;
Atom real_type;
unsigned long items_read, items_left;
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _XROOTPMAP_ID,
0L, 1L, False, XA_PIXMAP, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success) {
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy), ESETROOT_PMAP_ID,
0L, 1L, False, XA_PIXMAP, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success)
return None;
}
if(items_read)
rootpmap = ((Pixmap*)data)[0];
XFree(data);
return rootpmap;
}
CARD32
wm_get_current_desktop(Display *dpy)
{
CARD32 desktop = 0;
unsigned char *data;
int status, real_format;
Atom real_type;
unsigned long items_read, items_left;
status = XGetWindowProperty(dpy, DefaultRootWindow(dpy),
(WM_PERSONALITY == WM_PERSONALITY_NETWM) ? _NET_CURRENT_DESKTOP : _WIN_WORKSPACE,
0L, 1L, False, XA_CARDINAL, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success)
return 0;
if(items_read)
desktop = ((CARD32*)data)[0];
XFree(data);
return desktop;
}
FcChar8 *
wm_get_window_title(Display *dpy, Window window, int *length_return)
{
unsigned char *data;
FcChar8 *ret = 0;
int status, real_format;
Atom real_type;
unsigned long items_read, items_left;
*length_return = 0;
status = XGetWindowProperty(dpy, window, _NET_WM_VISIBLE_NAME,
0, 8192, False, XA_UTF8_STRING, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success || items_read == 0)
{
if(status == Success)
XFree(data);
status = XGetWindowProperty(dpy, window, _NET_WM_NAME,
0, 8192, False, XA_UTF8_STRING, &real_type, &real_format,
&items_read, &items_left, &data);
}
if(status != Success || items_read == 0)
{
if(status == Success)
XFree(data);
status = XGetWindowProperty(dpy, window, XA_WM_NAME,
0, 8192, False, XA_STRING, &real_type, &real_format,
&items_read, &items_left, &data);
}
if(status != Success)
return 0;
if(items_read)
{
ret = (FcChar8 *)malloc(items_read);
memcpy(ret, data, items_read);
*length_return = items_read;
}
XFree(data);
return ret;
}
Window
wm_get_group_leader(Display *dpy, Window window)
{
unsigned char *data;
int status, real_format;
Atom real_type;
unsigned long items_read, items_left;
Window leader = None;
status = XGetWindowProperty(dpy, window, WM_CLIENT_LEADER,
0, 1, False, XA_WINDOW, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success)
{
XWMHints *hints = XGetWMHints(dpy, window);
if(! hints)
return None;
if(hints->flags & WindowGroupHint)
leader = hints->window_group;
return leader;
}
if(items_read)
leader = ((Window*)data)[0];
XFree(data);
return leader;
}
void
wm_use_netwm_fullscreen(Bool b)
{
NETWM_HAS_FULLSCREEN = b ? NETWM_HAS_FULLSCREEN : False;
}
void
wm_ignore_skip_taskbar(Bool b)
{
IGNORE_SKIP_TASKBAR = b;
}
void
wm_set_fullscreen(Display *dpy, Window window, int x, int y, unsigned int width, unsigned int height)
{
if(WM_PERSONALITY == WM_PERSONALITY_NETWM && NETWM_HAS_FULLSCREEN)
{
Atom props[6];
props[0] = _NET_WM_STATE_FULLSCREEN;
props[1] = _NET_WM_STATE_SKIP_TASKBAR;
props[2] = _NET_WM_STATE_SKIP_PAGER;
props[3] = _NET_WM_STATE_ABOVE;
props[4] = _NET_WM_STATE_STICKY;
props[5] = 0;
XChangeProperty(dpy, window, _NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char*)props, 5);
}
else
{
XSetWindowAttributes wattr;
wattr.override_redirect = True;
XChangeWindowAttributes(dpy, window, CWOverrideRedirect, &wattr);
XMoveResizeWindow(dpy, window, x, y, width, height);
}
}
int
wm_validate_window(Display *dpy, Window win)
{
unsigned char *data;
Atom *atoms;
int status, real_format;
Atom real_type;
unsigned long items_read, items_left, i;
int result = 1;
if(WM_PERSONALITY == WM_PERSONALITY_NETWM)
{
status = XGetWindowProperty(dpy, win, _NET_WM_STATE,
0L, 8192L, False, XA_ATOM, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success)
return 0;
atoms = (Atom *)data;
for(i = 0; result && i < items_read; i++) {
if(atoms[i] == _NET_WM_STATE_HIDDEN)
result = 0;
else if(! IGNORE_SKIP_TASKBAR && atoms[i] == _NET_WM_STATE_SKIP_TASKBAR)
result = 0;
else if(atoms[i] == _NET_WM_STATE_SHADED)
result = 0;
if(! result)
break;
}
XFree(data);
if(! result)
return 0;
status = XGetWindowProperty(dpy, win, _NET_WM_WINDOW_TYPE,
0L, 1L, False, XA_ATOM, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success)
return 1;
atoms = (Atom *)data;
if(items_read && (atoms[0] == _NET_WM_WINDOW_TYPE_DESKTOP || atoms[0] == _NET_WM_WINDOW_TYPE_DOCK))
result = 0;
XFree(data);
return result;
} else {
CARD32 attr;
status = XGetWindowProperty(dpy, win, _WIN_STATE,
0L, 1L, False, XA_CARDINAL, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success || ! items_read)
{
if(status == Success)
XFree(data);
return 0;
}
attr = (((CARD32*)data)[0]) & (WIN_STATE_MINIMIZED |
WIN_STATE_SHADED |
WIN_STATE_HIDDEN);
if(attr)
result = 0;
XFree(data);
if(! result)
return 0;
if(! IGNORE_SKIP_TASKBAR)
{
status = XGetWindowProperty(dpy, win, _WIN_HINTS,
0L, 1L, False, XA_CARDINAL, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success || ! items_read)
{
if(status == Success)
XFree(data);
return 1; /* If there's no _WIN_HINTS, assume it's 0, thus valid */
}
attr = ((CARD32*)data)[0];
if(attr & WIN_HINTS_SKIP_TASKBAR)
result = 0;
XFree(data);
}
return result;
}
}
CARD32
wm_get_window_desktop(Display *dpy, Window win)
{
int status, real_format;
Atom real_type;
unsigned long items_read, items_left;
unsigned char *data;
CARD32 desktop = 0;
if(WM_PERSONALITY == WM_PERSONALITY_GNOME)
{
status = XGetWindowProperty(dpy, win, _WIN_STATE,
0L, 1L, False, XA_CARDINAL, &real_type, &real_format,
&items_read, &items_left, &data);
if(status == Success)
{
if(items_read)
desktop = (((CARD32*)data)[0] & WIN_STATE_STICKY) ? (CARD32)-1 : 0;
XFree(data);
if(desktop)
return desktop;
}
}
status = XGetWindowProperty(dpy, win,
(WM_PERSONALITY == WM_PERSONALITY_NETWM) ? _NET_WM_DESKTOP : _WIN_WORKSPACE,
0L, 1L, False, XA_CARDINAL, &real_type, &real_format,
&items_read, &items_left, &data);
if(status != Success)
return wm_get_current_desktop(dpy);
if(items_read)
desktop = ((CARD32*)data)[0];
else
desktop = wm_get_current_desktop(dpy);
XFree(data);
return desktop;
}
/* Get focused window and traverse towards the root window until a window with WM_STATE is found */
Window
wm_get_focused(Display *dpy)
{
Window focused = None, root = None, *children;
unsigned int tmp_u;
int revert_to, status, real_format;
Atom real_type;
unsigned long items_read, items_left;
unsigned char *data;
XGetInputFocus(dpy, &focused, &revert_to);
while(focused != None && focused != root)
{
status = XGetWindowProperty(dpy, focused, XA_WM_STATE,
0L, 1L, False, XA_WM_STATE, &real_type, &real_format,
&items_read, &items_left, &data);
if(status == Success)
{
XFree(data);
if(items_read)
break;
}
XQueryTree(dpy, focused, &root, &focused, &children, &tmp_u);
if(children)
XFree(children);
}
return focused;
}
syntax highlighted by Code2HTML, v. 0.9.1