/* Skippy - Seduces Kids Into Perversion * * Copyright (C) 2004 Hyriand * * 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; }