1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
|
/* vdesk: virtual desktops for any window manager vim:et:ts=4:
* Copyright 2001, 2003 Adam Sampson <azz@us-lot.org>
* Originally based on code from aewm:
* Copyright (c) 1998-2001 Decklin Foster.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS", WITHOUT ANY EXPRESS
* OR IMPLIED WARRANTIES OF ANY KIND. IN NO EVENT SHALL THE AUTHOR BE
* HELD LIABLE FOR ANY DAMAGES CONNECTED WITH THE USE OF THIS PROGRAM.
*
* You are granted permission to copy, publish, distribute, and/or sell
* copies of this program and any modified versions or derived works,
* provided that this copyright and notice are not removed or altered.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
Display *dpy;
Window root;
Atom wm_state, vdesk_desktop, wm_change_state;
/* Start off the current desk at 1 so that we can set the root
window correctly the first time we start up. */
long todesk, curdesk = 1;
void set_window_desk_vis(Window w, long n, long vis) {
long buf[2];
buf[0] = n; buf[1] = vis;
XChangeProperty(dpy, w, vdesk_desktop, vdesk_desktop, 32, PropModeReplace,
(unsigned char *)buf, 2);
}
long get_window_desk_vis(Window w, long *ovis) {
Atom real_type; int real_format;
unsigned long items_read, items_left;
long *data, n = -1, vis = -1;
if (XGetWindowProperty(dpy, w, vdesk_desktop, 0L, 2L, False,
vdesk_desktop, &real_type, &real_format, &items_read, &items_left,
(unsigned char **) &data) == Success && items_read) {
n = data[0];
vis = data[1];
XFree(data);
}
if (n == -1) {
/* If it's not set, make it the current desk and visible. */
set_window_desk_vis(w, curdesk, 1);
*ovis = 1;
return curdesk;
} else {
*ovis = vis;
return n;
}
}
long get_wm_state(Window w)
{
Atom real_type; int real_format;
unsigned long items_read, items_left;
long *data, state = WithdrawnState;
if (XGetWindowProperty(dpy, w, wm_state, 0L, 2L, False,
wm_state, &real_type, &real_format, &items_read, &items_left,
(unsigned char **) &data) == Success && items_read) {
state = *data;
XFree(data);
}
return state;
}
void iconify_window(Window w) {
XEvent ev;
memset(&ev, 0, sizeof ev);
ev.xclient.type = ClientMessage;
ev.xclient.window = w;
ev.xclient.message_type = wm_change_state;
ev.xclient.format = 32;
ev.xclient.data.l[0] = IconicState;
ev.xclient.data.l[1] = CurrentTime;
XSendEvent(dpy, root, False, SubstructureRedirectMask, &ev);
}
void uniconify_window(Window w) {
XMapWindow(dpy, w);
}
void on_clients(Window w) {
Window dummy_w, *wins;
unsigned int i, nwins;
long state = get_wm_state(w);
if (state != WithdrawnState) {
long vis, n;
n = get_window_desk_vis(w, &vis);
if (state == NormalState) {
/* If the window isn't sticky, changing desktops will
always hide it. */
if (n) {
/* Since it was visible, it's been moved behind our back
and should really be on this desktop. */
set_window_desk_vis(w, curdesk, 1);
/* And hide it. */
iconify_window(w);
}
} else {
if (n == curdesk) {
/* Invisible, but on the current desktop -- means
it's been iconified. */
set_window_desk_vis(w, curdesk, 0);
} else if (n == todesk && vis == 1) {
uniconify_window(w);
}
}
} else if (XQueryTree(dpy, w, &dummy_w, &dummy_w, &wins, &nwins)) {
for (i = 0; i < nwins; i++)
on_clients(wins[i]);
XFree(wins);
}
}
void usage() {
printf(PACKAGE_STRING " by Adam Sampson\n"
"Usage: vdesk [OPTION]... [DESKTOP [WINDOW]...]\n\n"
"To print the current desktop number:\n"
" vdesk\n"
"To switch to desktop DESKTOP:\n"
" vdesk DESKTOP\n"
"To move windows to a desktop (desk 0 is sticky):\n"
" vdesk DESKTOP WINDOWID [WINDOWID]...\n"
"DESKTOP can be any positive integer. WINDOWIDs are in hex.\n\n"
"Report bugs to <" PACKAGE_BUGREPORT ">.\n");
exit(20);
}
int main(int argc, char **argv) {
long t;
int change = 0;
opterr = 0;
while (1) {
int c = getopt(argc, argv, "+?");
if (c == -1)
break;
/* No options supported yet; just show the usage message. */
usage();
}
dpy = XOpenDisplay(NULL);
if (!dpy) {
fprintf(stderr, "%s: cannot open display\n", argv[0]);
return 20;
}
wm_state = XInternAtom(dpy, "WM_STATE", False);
vdesk_desktop = XInternAtom(dpy, "VDESK_DESKTOP", False);
wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
root = DefaultRootWindow(dpy);
curdesk = get_window_desk_vis(root, &t);
if (optind == argc) {
/* Print the current desktop number. */
printf("%ld\n", curdesk);
return 0;
}
if ((argc - optind) == 1)
change = 1;
todesk = strtol(argv[optind], NULL, 0);
if (todesk < 0 || (change && todesk == 0)) {
fprintf(stderr, "%s: bad desktop number '%s'\n", argv[0], argv[optind]);
usage();
}
++optind;
if (change) {
/* Switch to the given desktop. */
if (todesk != curdesk) {
on_clients(root);
set_window_desk_vis(root, todesk, 1);
}
} else {
/* Move the given windows to the given desktop. */
Window w;
int i;
for (i = optind; i < argc; i++) {
w = strtol(argv[i], NULL, 0);
if (w) {
int is_visible = get_wm_state(w) == NormalState;
set_window_desk_vis(w, todesk, is_visible);
if (!is_visible && (todesk == curdesk || !todesk)) {
uniconify_window(w);
}
if (is_visible && todesk && todesk != curdesk) {
iconify_window(w);
}
} else {
fprintf(stderr, "%s: bad window id '%s'\n", argv[0], argv[i]);
usage();
}
}
}
XSync(dpy, False);
return 0;
}
|