The following piece of code initiates substructure redirection on the root window and attempts to resize any new children:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
#define TERMINAL "urxvt"
void start(char* what)
{
if(!fork())
{
char* const args[] = {"/bin/sh", "-c", what, NULL};
execvp("/bin/sh", args);
exit(1);
}
}
int main()
{
Display* dpy;
Window root;
XSetWindowAttributes setAttribs;
XEvent ev;
if(!(dpy = XOpenDisplay(NULL)))
exit(1);
root = XDefaultRootWindow(dpy);
XSelectInput(dpy, root, SubstructureNotifyMask | SubstructureRedirectMask);
XGrabKey(dpy, XKeysymToKeycode(dpy, XK_T), Mod4Mask, root, True, GrabModeAsync, GrabModeAsync);
while(1)
{
XNextEvent(dpy, &ev);
switch(ev.type)
{
case MapRequest:
XMapWindow(dpy, ev.xmaprequest.window);
XMoveResizeWindow(dpy, ev.xmaprequest.window, 0, 0, 800, 600);
XSync(dpy, False);
break;
case KeyPress:
start(TERMINAL);
break;
default:
break;
}
}
XUngrabKey(dpy, AnyKey, AnyModifier, root);
XSync(dpy, False);
return 0;
}
This seems to work fine for simple terminals (you can launch the one defined by the TERMINAL constant with Mod4+t ), but messes up various parts in more complex GUIs. For instance, emacs shows up without a toolbar, and the menu bar doesn't redraw itself when necessary. Firefox looks fine, but pressing the 'open menu' button has no visible effect. Changing the code to respect configuration requests fixes some of the problems ('open menu' button still won't work), but that, of course, defeats the entire purpose. All I want at this point is to be able to resize and reposition windows without breaking them. What am I missing?
[UPDATE]
As per Ingo's suggestion, here's an updated version that doesn't touch windows with override_redirect set:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
#define TERMINAL "urxvt"
void start(char* what)
{
if(!fork())
{
char* const args[] = {"/bin/sh", "-c", what, NULL};
execvp("/bin/sh", args);
exit(1);
}
}
int hasOverrideRedirect(Display* dpy, Window win)
{
XWindowAttributes wa;
if(!XGetWindowAttributes(dpy, win, &wa))
return 0;
return wa.override_redirect;
}
int main()
{
Display* dpy;
Window root;
XSetWindowAttributes setAttribs;
XEvent ev;
if(!(dpy = XOpenDisplay(NULL)))
exit(1);
root = XDefaultRootWindow(dpy);
XSelectInput(dpy, root, SubstructureNotifyMask | SubstructureRedirectMask);
XGrabKey(dpy, XKeysymToKeycode(dpy, XK_T), Mod4Mask, root, True, GrabModeAsync, GrabModeAsync);
while(1)
{
XNextEvent(dpy, &ev);
switch(ev.type)
{
case MapRequest:
XMapWindow(dpy, ev.xmaprequest.window);
if(!hasOverrideRedirect(dpy, ev.xmaprequest.window))
{
XMoveResizeWindow(dpy, ev.xmaprequest.window, 0, 0, 800, 600);
XSync(dpy, False);
}
break;
case KeyPress:
start(TERMINAL);
break;
case ConfigureRequest:
if(hasOverrideRedirect(dpy, ev.xconfigurerequest.window))
{
XConfigureRequestEvent *e2 = &ev.xconfigurerequest;
XWindowChanges wc;
wc.x = e2->x;
wc.y = e2->y;
wc.width = e2->width;
wc.height = e2->height;
wc.border_width = e2->border_width;
wc.sibling = e2->above;
wc.stack_mode = e2->detail;
XConfigureWindow(dpy, e2->window, e2->value_mask, &wc);
}
default:
break;
}
}
XUngrabKey(dpy, AnyKey, AnyModifier, root);
XSync(dpy, False);
return 0;
}
No noticeable difference, as far as the original problem is concerned.
Well, I'm not entirely sure, but there are 3 things to consider:
Window Manager: normally it's the responsibility of the window manager to position and decorate windows. You're trying to subvert this now by resizing the window on the fly.
Complex GUIs: you're resizing every window, but what if programs create subwindows? Say, the toolbar is one subwindow, the browser panel is one, the scrollbar another. You are resizing them as well.
Unexpected behaviour: so, I have an X program and I create a fixed window of 50x50 pixels. Now suddenly someone else decides to make that window 800x600. What is my programma supposed to do?? Surely it gets confused...
You may be able to 'fix' point 2 by checking if the window is a direct descendent of the root window (e.g. it is the application's top level window), and only resize those.