Переадресация подструктуры 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, проверив, является ли окно прямым потомком корневого окна (например, это окно верхнего уровня приложения), и измените его размер.

Другие вопросы по тегам