以下代码段在根窗口上启动子结构重定向,并尝试调整任何新子级的大小:
#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;
}
这似乎适用于简单的终端(您可以使用 Mod4+t 启动由终端常量定义的终端(,但在更复杂的 GUI 中会弄乱各个部分。例如,emacs 在没有工具栏的情况下显示,并且菜单栏在必要时不会重绘。Firefox看起来不错,但按下"打开菜单"按钮没有明显效果。更改代码以尊重配置请求可以解决一些问题("打开菜单"按钮仍然不起作用(,但这当然会破坏整个目的。此时我想要的只是能够在不破坏窗口的情况下调整窗口大小和重新定位窗口。我错过了什么?
[更新]
根据Ingo的建议,这是一个更新的版本,它不接触override_redirect设置的窗口:
#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;
}
就原始问题而言,没有明显的区别。
好吧,我不完全确定,但有 3 件事需要考虑:
- 窗口管理器
:通常由窗口管理器负责定位和装饰窗口。您现在正试图通过动态调整窗口大小来颠覆这一点。
复杂的 GUI:您正在调整每个窗口的大小,但如果程序创建子窗口怎么办?比如说,工具栏是一个子窗口,浏览器面板是一个,滚动条是另一个。您也在调整它们的大小。
意外行为:因此,我有一个 X 程序,并创建了一个 50x50 像素的固定窗口。现在突然有人决定让那个窗口变成800x600。我的程序应该做什么??肯定会感到困惑...
您可以通过检查窗口是否是根窗口的直接后代(例如,它是应用程序的顶级窗口(来"修复"第 2 点,并且只调整它们的大小。