即使在 X11 中取消映射后也无法重新设置父级
Cannot Reparent even after Unmapping in X11
我正在使用 X11 并想执行重新父级。我从 Rosetta Code 在 C 中得到了一个示例 hello world 应用程序。我做了一些修改使其成为 2 windows.
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void) {
Display *d;
Window w, w2;
XEvent e;
const char *msg = "Hello, World!";
int s;
d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Cannot open display\n");
exit(1);
}
s = DefaultScreen(d);
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 1000, 1000, 1,
BlackPixel(d, s), WhitePixel(d, s));
w2 = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
BlackPixel(d, s), WhitePixel(d, s));
XSelectInput(d, w, ExposureMask | KeyPressMask);
XMapWindow(d, w); //map the bigger window
XSelectInput(d, w2, ExposureMask | KeyPressMask);
XMapWindow(d, w2); //map the smaller window
XFlush(d);
XUnmapWindow(d, w2); //unmap the smaller window to reparent it
XFlush(d);
XReparentWindow(d, w2, w, 500, 500);
XMapWindow(d, w2); //remap the smaller window
while (1) {
XNextEvent(d, &e);
if (e.type == Expose) {
XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
XDrawString(d, w, DefaultGC(d, s), 10, 50, msg, strlen(msg));
XFillRectangle(d, w2, DefaultGC(d, s), 20, 20, 10, 10);
XDrawString(d, w2, DefaultGC(d, s), 10, 50, msg, strlen(msg));
}
if (e.type == KeyPress)
break;
}
XCloseDisplay(d);
return 0;
}
但是这段代码不起作用;它显示两个单独的 windows:
但是当我删除标记为 map the smaller window
和 unmap the smaller window to reparent it
的行时,我得到了正确的结果:
两者不应该产生相同的正确结果。我原来做的就是映射,然后立即取消映射。
我刚刚在我的 Linux 机器上重现了该行为。
问题似乎是您的程序与“Window 管理器”之间的时间问题。
“Window 管理器”是负责在 windows 处绘制标题栏和边框的程序。 “Window 经理”是这样工作的:
每当 window 映射到根 window 时,X11 就会通知“Window 管理器”。 “Window 管理器”创建一个包含标题栏和边框的“外部 window”。然后重新设置 window 的父级,因此 window 成为“外部 window”的 child window。
示例:
如果“Window管理器”映射后处理一些window,则成为“外层window”的childwindow;出于这个原因,任何不是“外部 window”的 child window 的 window 显然不会被“Window 管理器”处理,如果它已映射。
...至少在“正常情况下”。
因此,“Window 管理器”不关心根 window 上 un-mapped 的 windows(但只关心 windows 来自“外部 window”)的 un-mapped。
通常情况下,“Window 经理”的行为如下:
Your program Window manager
------------ --------------
XMapWindow(d, w2);
XFlush(d);
wm_w2 = XCreateWindow(...);
XUnmapWindow(..., w2);
XReparentWindow(..., w2, wm_w2, ...);
XMapWindow(..., w2);
XUnmapWindow(d, w2);
XFlush(d);
XReparentWindow(..., w2, root, ...);
XDestroyWindow(... wm_w2);
XReparentWindow(d, w2, w, 500, 500);
XMapWindow(d, w2);
... ...
但是,您的程序执行 XMapWindow()
和 XUnmapWindow()
时没有足够的时间让“Window 经理”做出反应。
因此,这两个程序有可能(并且很可能)按以下顺序工作:
Your program Window manager
------------ --------------
XMapWindow(d, w2);
XFlush(d); // Here the window manager
// is notified about window w2
XUnmapWindow(d, w2);
XFlush(d); // The window manager will ignore
// w2 being un-mapped because
// it is not the child of an
// "outer window", yet!
XReparentWindow(d, w2, w, 500, 500);
XMapWindow(d, w2);
... ...
// The window manager received the
// notification using XNextEvent()
wm_w2 = XCreateWindow(...);
XUnmapWindow(..., w2);
XReparentWindow(..., w2, wm_w2, ...);
XMapWindow(..., w2);
您必须在 XMapWindow()
和 XUnmapWindow()
之间等待一段时间,让“Window 经理”re-parent window 挡路它是由“Window 经理”完成的。
否则,“Window 经理”将在您完成后执行 re-parenting!
顺便说一句:在我的电脑上,问题可以通过更简单的方式重现:
创建一个 window,映射它并在此之后立即 un-map 它...
将显示 window,尽管最后调用的函数是 XUnmapWindow()
。
我正在使用 X11 并想执行重新父级。我从 Rosetta Code 在 C 中得到了一个示例 hello world 应用程序。我做了一些修改使其成为 2 windows.
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void) {
Display *d;
Window w, w2;
XEvent e;
const char *msg = "Hello, World!";
int s;
d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Cannot open display\n");
exit(1);
}
s = DefaultScreen(d);
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 1000, 1000, 1,
BlackPixel(d, s), WhitePixel(d, s));
w2 = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
BlackPixel(d, s), WhitePixel(d, s));
XSelectInput(d, w, ExposureMask | KeyPressMask);
XMapWindow(d, w); //map the bigger window
XSelectInput(d, w2, ExposureMask | KeyPressMask);
XMapWindow(d, w2); //map the smaller window
XFlush(d);
XUnmapWindow(d, w2); //unmap the smaller window to reparent it
XFlush(d);
XReparentWindow(d, w2, w, 500, 500);
XMapWindow(d, w2); //remap the smaller window
while (1) {
XNextEvent(d, &e);
if (e.type == Expose) {
XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
XDrawString(d, w, DefaultGC(d, s), 10, 50, msg, strlen(msg));
XFillRectangle(d, w2, DefaultGC(d, s), 20, 20, 10, 10);
XDrawString(d, w2, DefaultGC(d, s), 10, 50, msg, strlen(msg));
}
if (e.type == KeyPress)
break;
}
XCloseDisplay(d);
return 0;
}
但是这段代码不起作用;它显示两个单独的 windows:
但是当我删除标记为 map the smaller window
和 unmap the smaller window to reparent it
的行时,我得到了正确的结果:
两者不应该产生相同的正确结果。我原来做的就是映射,然后立即取消映射。
我刚刚在我的 Linux 机器上重现了该行为。
问题似乎是您的程序与“Window 管理器”之间的时间问题。
“Window 管理器”是负责在 windows 处绘制标题栏和边框的程序。 “Window 经理”是这样工作的:
每当 window 映射到根 window 时,X11 就会通知“Window 管理器”。 “Window 管理器”创建一个包含标题栏和边框的“外部 window”。然后重新设置 window 的父级,因此 window 成为“外部 window”的 child window。
示例:
如果“Window管理器”映射后处理一些window,则成为“外层window”的childwindow;出于这个原因,任何不是“外部 window”的 child window 的 window 显然不会被“Window 管理器”处理,如果它已映射。
...至少在“正常情况下”。
因此,“Window 管理器”不关心根 window 上 un-mapped 的 windows(但只关心 windows 来自“外部 window”)的 un-mapped。
通常情况下,“Window 经理”的行为如下:
Your program Window manager
------------ --------------
XMapWindow(d, w2);
XFlush(d);
wm_w2 = XCreateWindow(...);
XUnmapWindow(..., w2);
XReparentWindow(..., w2, wm_w2, ...);
XMapWindow(..., w2);
XUnmapWindow(d, w2);
XFlush(d);
XReparentWindow(..., w2, root, ...);
XDestroyWindow(... wm_w2);
XReparentWindow(d, w2, w, 500, 500);
XMapWindow(d, w2);
... ...
但是,您的程序执行 XMapWindow()
和 XUnmapWindow()
时没有足够的时间让“Window 经理”做出反应。
因此,这两个程序有可能(并且很可能)按以下顺序工作:
Your program Window manager
------------ --------------
XMapWindow(d, w2);
XFlush(d); // Here the window manager
// is notified about window w2
XUnmapWindow(d, w2);
XFlush(d); // The window manager will ignore
// w2 being un-mapped because
// it is not the child of an
// "outer window", yet!
XReparentWindow(d, w2, w, 500, 500);
XMapWindow(d, w2);
... ...
// The window manager received the
// notification using XNextEvent()
wm_w2 = XCreateWindow(...);
XUnmapWindow(..., w2);
XReparentWindow(..., w2, wm_w2, ...);
XMapWindow(..., w2);
您必须在 XMapWindow()
和 XUnmapWindow()
之间等待一段时间,让“Window 经理”re-parent window 挡路它是由“Window 经理”完成的。
否则,“Window 经理”将在您完成后执行 re-parenting!
顺便说一句:在我的电脑上,问题可以通过更简单的方式重现:
创建一个 window,映射它并在此之后立即 un-map 它...
将显示 window,尽管最后调用的函数是 XUnmapWindow()
。