设置终端窗口的标题:wmctrl vs xdotool

DK *_*ose 6 command-line xdotool wmctrl

编辑:我不是在寻找其他方法或更好的方法来更改窗口的标题或向终端中的选项卡添加标题。建议副本中 的答案在任何方面无法解决特定问题,即当wmctrl如上所述设置标题时为什么xdotool search … 选择窗口标题。


操作系统:Ubuntu 18.04

当我打开一个gnome-terminal窗口时,标题是dkb@dkb:~

我可以改变它使用

wmctrl -r :ACTIVE: -N "NewName"
Run Code Online (Sandbox Code Playgroud)

但是xdotool search …,没有“看到”这个标题:

dkb@dkb:~$ xdotool search --name NewName
dkb@dkb:~$ 
Run Code Online (Sandbox Code Playgroud)

我只是返回提示而不是提供相应的窗口标识符。

另一方面,我可以使用xdotool本身来设置标题,然后xdotool search …提供窗口标识符:

dkb@dkb:~$ xdotool getactivewindow set_window --name NewName
dkb@dkb:~$ xdotool search --name NewName
39845894
dkb@dkb:~$ 
Run Code Online (Sandbox Code Playgroud)

换句话说,如果标题被设定xdotoolxdotool search工作,它应该:

man xdotool

search [options] pattern 使用正则表达式模式搜索带有标题、名称或类的窗口。输出是以行分隔的 X 窗口标识符列表。

因此,虽然这不是什么大问题,但我想知道xdotool没有“看到” wmctrl设置的窗口标题的原因是什么

Nyk*_*kin 7

我们可以看到它至少xdotool getactivewindow getwindowname按预期工作。

$ wmctrl -r :ACTIVE: -N "Test1"
$ xdotool getactivewindow getwindowname
Test1
$ xdotool getactivewindow set_window --name Test2
$ xdotool getactivewindow getwindowname
Test2
Run Code Online (Sandbox Code Playgroud)

所以让我们更深入。我们可以使用xprop -id <id>命令列出窗口的属性。对于名称设置的窗口,wmctrl它给出:

_NET_WM_OPAQUE_REGION(CARDINAL) = 0, 0, 1920, 995
_NET_STARTUP_ID(UTF8_STRING) = "brisk-menu-2514-mariusz-HP-Pavilion-Notebook-mate-terminal-1_TIME1314631"
WM_WINDOW_ROLE(STRING) = "mate-terminal-window-4442-66103825-1563868224"
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
_NET_WM_SYNC_REQUEST_COUNTER(CARDINAL) = 79691784, 79691785
_NET_WM_USER_TIME_WINDOW(WINDOW): window id # 0x4c00007
WM_CLIENT_LEADER(WINDOW): window id # 0x4c00001
_NET_WM_PID(CARDINAL) = 4442
WM_LOCALE_NAME(STRING) = "en_US.UTF-8"
WM_CLIENT_MACHINE(STRING) = "mariusz-HP-Pavilion-Notebook"
WM_NORMAL_HINTS(WM_SIZE_HINTS):
        program specified minimum size: 345 by 141
        program specified resize increment: 9 by 20
        program specified base size: 16 by 30
        window gravity: NorthWest
WM_PROTOCOLS(ATOM): protocols  WM_DELETE_WINDOW, WM_TAKE_FOCUS, _NET_WM_PING, _NET_WM_SYNC_REQUEST
WM_CLASS(STRING) = "mate-terminal", "Mate-terminal"
_NET_WM_ICON_NAME(UTF8_STRING) = "Terminal"
_NET_WM_NAME(UTF8_STRING) = "Test1"
Run Code Online (Sandbox Code Playgroud)

对于名称设置的窗口,xdotool它给出:

_NET_WM_OPAQUE_REGION(CARDINAL) = 0, 0, 1920, 995
_NET_STARTUP_ID(UTF8_STRING) = "brisk-menu-2514-mariusz-HP-Pavilion-Notebook-mate-terminal-1_TIME1314631"
WM_WINDOW_ROLE(STRING) = "mate-terminal-window-4442-66103825-1563868224"
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
_NET_WM_SYNC_REQUEST_COUNTER(CARDINAL) = 79691784, 79691785
_NET_WM_USER_TIME_WINDOW(WINDOW): window id # 0x4c00007
WM_CLIENT_LEADER(WINDOW): window id # 0x4c00001
_NET_WM_PID(CARDINAL) = 4442
WM_LOCALE_NAME(STRING) = "en_US.UTF-8"
WM_CLIENT_MACHINE(STRING) = "mariusz-HP-Pavilion-Notebook"
WM_NORMAL_HINTS(WM_SIZE_HINTS):
        program specified minimum size: 345 by 141
        program specified resize increment: 9 by 20
        program specified base size: 16 by 30
        window gravity: NorthWest
WM_PROTOCOLS(ATOM): protocols  WM_DELETE_WINDOW, WM_TAKE_FOCUS, _NET_WM_PING, _NET_WM_SYNC_REQUEST
WM_CLASS(STRING) = "mate-terminal", "Mate-terminal"
_NET_WM_ICON_NAME(UTF8_STRING) = "Terminal"
_NET_WM_NAME(STRING) = "Test2"
Run Code Online (Sandbox Code Playgroud)

我们可以看到,在这两种情况下_NET_WM_NAME都设置正确。什么是_NET_WM_NAME?它是 x11 的扩展(链接链接

_NET_WM_NAME

_NET_WM_NAME、UTF8_STRING

客户端应该将其设置为 UTF-8 编码的窗口标题。如果设置,窗口管理器应该优先于 WM_NAME 使用它。

所以 x11 应用程序应该更喜欢这个属性而不是WM_NAME. 让我们显示这两个属性。我从这里拿了 C 代码:

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>

#define MAXSTR 1000

Display *display;
unsigned long window;
unsigned char *prop;

void check_status(int status, unsigned long window)
{
    if (status == BadWindow) {
        printf("window id # 0x%lx does not exists!", window);
        exit(1);
    }

    if (status != Success) {
        printf("XGetWindowProperty failed!");
        exit(2);
    }
}

unsigned char* get_string_property(char* property_name)
{
    Atom actual_type, filter_atom;
    int actual_format, status;
    unsigned long nitems, bytes_after;

    filter_atom = XInternAtom(display, property_name, True);
    status = XGetWindowProperty(display, window, filter_atom, 0, MAXSTR, False, AnyPropertyType,
                                &actual_type, &actual_format, &nitems, &bytes_after, &prop);
    check_status(status, window);
    return prop;
}

unsigned long get_long_property(char* property_name)
{
    get_string_property(property_name);
    unsigned long long_property = prop[0] + (prop[1]<<8) + (prop[2]<<16) + (prop[3]<<24);
    return long_property;
}

int main(int argc, char** argv)
{
    char *display_name = NULL;  // could be the value of $DISPLAY

    display = XOpenDisplay(display_name);
    if (display == NULL) {
        fprintf (stderr, "%s:  unable to open display '%s'\n", argv[0], XDisplayName (display_name));
    }
    int screen = XDefaultScreen(display);
    window = RootWindow(display, screen);

    window = get_long_property("_NET_ACTIVE_WINDOW");

    printf("_NET_WM_PID: %lu\n", get_long_property("_NET_WM_PID"));
    printf("WM_CLASS: %s\n", get_string_property("WM_CLASS"));
    printf("_NET_WM_NAME: %s\n", get_string_property("_NET_WM_NAME"));
    printf("WM_NAME: %s\n", get_string_property("WM_NAME"));

    XCloseDisplay(display);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

只加了printf("WM_NAME: %s\n", get_string_property("WM_NAME"));一行。跑步:

$ gcc test.c -o test -lX11
$ wmctrl -r :ACTIVE: -N "Test1"
$ ./test 
_NET_WM_PID: 4442
WM_CLASS: mate-terminal
_NET_WM_NAME: Test1
WM_NAME: (null)
$ xdotool getactivewindow set_window --name Test2
$ ./test 
_NET_WM_PID: 4442
WM_CLASS: mate-terminal
_NET_WM_NAME: Test2
WM_NAME: Test2
Run Code Online (Sandbox Code Playgroud)

所以结论是:xdotoolset both _NET_WM_NAMEand WN_NAMEbut only search by WM_NAMEand wmctrlset only _NET_WM_NAME

  • 实际上不需要C,我可以只用`xprop -id &lt;id&gt; WM_NAME`来显示属性 (2认同)