x11 XChangeProperty 因 BadValue 而失败

x11 XChangeProperty fails with BadValue

我正在尝试使用 X11 创建全屏 window。我设法获得了基本的 window 和事件处理。根据 this I have to use the property name "_MOTIF_WM_HINTS" in order to hide window decorations, along with the custom type Hints (wherever that may reside or is user created). Nevertheless I found a list of property names here,但是当我尝试使用像“_WM_NAME”或“_NET_WM_NAME”这样的简单代码时,我得到一个 BadValue 错误。

我目前在 Wayland,但我确实安装了 xorg-xwayland

具体来说,我收到了这条错误消息:

X Error of failed request:  BadValue (integer parameter out of range for operation)
  Major opcode of failed request:  18 (X_ChangeProperty)
  Value in failed request:  0x8
  Serial number of failed request:  16
  Current serial number in output stream:  17

有问题的代码如下:

void fgd_window_toggle_fullscreen(fgd_window_t* win) 
{
    Display* display        = win->dsp; 
    Window   window         = win->window;
    int      screen_id      = win->screen_id;   
    fgd_window_info_t* info = &win->info; 
    
    info->is_fullscreen = (info->is_fullscreen == 1) ? 0 : 1;
    
    if (info->is_fullscreen) 
    {   
        Atom name_property = XInternAtom(display, "_NET_WM_NAME", False); 
        
        if (name_property == None) 
        {
            printf("Failed to create property.\n");
            return;
        }
        
        unsigned char some_text[21] = "My fullscreen window.";
        
        XChangeProperty(display, 
                        window, 
                        name_property, 
                        name_property,
                        PropModeReplace,
                        8,
                        some_text, 
                        10);
        
        int video_modes_count = 0; 
        XF86VidModeModeInfo** infos = NULL;
        
        XF86VidModeGetAllModeLines(display, 
                                                   screen_id, 
                                                   &video_modes_count,
                                                   &infos);
        printf("Number of video modes: %d\n", video_modes_count);
        for (int idx = 0; idx < video_modes_count; idx++) 
        {
            XF86VidModeModeInfo* current_info = infos[idx];
            
            printf("ModeInfo[%d] = (%d, %d)\n", idx, current_info->hdisplay,
                   current_info->vdisplay);
        }
        // Switch to another video mode so we can fullscreen the window.
        XF86VidModeModeInfo* video_mode = *infos;
        XF86VidModeSwitchToMode(display, screen_id, video_mode);
        // Move the window to top left corner.
        XF86VidModeSetViewPort(display, screen_id, 0, 0);
        // Resize the window to the coresponding dimensions.
        XResizeWindow(display, window,info->max_width, info->max_heigth);
        
        XFree(infos);
    }
    else
    {
        int width_center  = (info->max_width  >> 1) - (info->width  >> 1);
        int heigth_center = (info->max_heigth >> 1) - (info->heigth >> 1);
        
        XResizeWindow(display, window, info->width, info->heigth);
        XMoveWindow(display, window, width_center, heigth_center);
    }
    
}

这是与代码相关的问题还是我的显示管理器在干扰?

如果你想最大化 window,我可以提供另一种方法。

int MaximizeWindow(Window window)
{
    Display *display = XOpenDisplay(NULL);
    XClientMessageEvent ev = {};
    Atom wmState = XInternAtom(display, "_NET_WM_STATE", False);
    Atom maxH = XInternAtom(display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
    Atom maxV = XInternAtom(display, "_NET_WM_STATE_MAXIMIZED_VERT", False);

    if (wmState == None)
        return 0;

    ev.type = ClientMessage;
    ev.format = 32;
    ev.window = window;
    ev.message_type = wmState;
    ev.data.l[0] = 1;
    ev.data.l[1] = maxH;
    ev.data.l[2] = maxV;
    ev.data.l[3] = 1;

    int rv =  XSendEvent(display, DefaultRootWindow(display), False,
                      SubstructureNotifyMask,
                      (XEvent *)&ev);
    XFlush(display);
    XCloseDisplay(display);
    return rv;
}

Window 句柄作为参数提供给此函数。

我用这个和另一个示例创建了一个 git repo

我找到了解决办法!好像客户端需要调用XSendEvent,通过XChangeProperty.

是不行的

根据this data 并集的前 4 个字节可以是:

_NET_WM_STATE_REMOVE        0    /* remove/unset property */
_NET_WM_STATE_ADD           1    /* add/set property */
_NET_WM_STATE_TOGGLE        2    /* toggle property  */
void toggle_fullscreen(Display* dpy, Window win, b32* fullscreen)
{
    
    XClientMessageEvent msg = {
        .type = ClientMessage,
        .display = dpy,
        .window = win,
        .message_type = XInternAtom(dpy, "_NET_WM_STATE", True),
        .format = 32,
        .data = { .l = {
                *fullscreen,
                XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", True),
                None,
                0,
                1
            }}
    };
    
    XSendEvent(dpy, XRootWindow(dpy, XDefaultScreen(dpy)), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*) &msg);
    
    *fullscreen = !(*fullscreen);
}