Переадресация подструктуры X портит панель инструментов / меню
Следующий фрагмент кода инициирует перенаправление подструктуры в корневом окне и пытается изменить размеры любых новых дочерних элементов:
#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;
}
Кажется, это работает нормально для простых терминалов (вы можете запустить тот, который определен константой TERMINAL с Mod4+t), но путает различные части в более сложных графических интерфейсах. Например, 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;
}
Нет заметной разницы, насколько это касается первоначальной проблемы.
1 ответ
Ну, я не совсем уверен, но есть три вещи, которые следует учитывать:
Диспетчер окон: обычно менеджер окон отвечает за расположение и оформление окон. Вы пытаетесь подорвать это сейчас, изменяя размеры окна на лету.
Сложные графические интерфейсы: вы изменяете размеры каждого окна, но что если программы создают подокна? Скажем, панель инструментов - это одно подокно, панель браузера - одно, а полоса прокрутки - другое. Вы также изменяете их размеры.
Неожиданное поведение: у меня есть программа X, и я создаю фиксированное окно размером 50x50 пикселей. Теперь вдруг кто-то другой решает сделать это окно 800х600. Что должна делать моя программа?? Конечно, это запутывается...
Вы можете быть в состоянии "исправить" пункт 2, проверив, является ли окно прямым потомком корневого окна (например, это окно верхнего уровня приложения), и измените его размер.