X子结构重定向消化工具/菜单栏

时间:2016-02-01 10:55:17

标签: c x11 xlib window-management

以下代码启动根窗口上的子结构重定向,并尝试调整任何新子项的大小:

#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启动由TERMINAL常量定义的终端),但会在更复杂的GUI中混淆各个部分。例如,emacs在没有工具栏的情况下显示,并且菜单栏在必要时不会重绘。 Firefox看起来很好,但按下“打开菜单”按钮没有明显的效果。更改代码以尊重配置请求修复了一些问题(“打开菜单”按钮仍然不起作用),但这当然会破坏整个目的。此时我想要的是能够在不破坏窗口的情况下调整窗口大小和重新定位窗口。我错过了什么?

[UPDATE]

根据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 个答案:

答案 0 :(得分:-1)

嗯,我不完全确定,但有三件事需要考虑:

  • 窗口管理器:通常窗口管理器负责定位和装饰窗口。你现在试图通过动态调整窗口大小来破坏它。

  • 复杂的GUI:您正在调整每个窗口的大小,但是如果程序创建子窗口会怎么样?比如,工具栏是一个子窗口,浏览器面板是一个,滚动条是另一个。你也正在调整它们的大小。

  • 意外行为:所以,我有一个X程序,我创建了一个50x50像素的固定窗口。现在突然有人决定将该窗口设为800x600。我的程序应该做什么?肯定会感到困惑......

您可以通过检查窗口是否是根窗口的直接后代(例如,它是应用程序的顶级窗口)来“修复”第2点,并且只调整那些。