x11 XChangeProperty 因 BadValue 而失败

问题描述

我正在尝试使用 X11 创建一个全屏窗口。我设法获得了一个基本的窗口和事件处理。根据 this,我必须使用属性名称“_MOTIF_WM_HINTS”来隐藏窗口装饰以及自定义类型 Hints(无论它位于何处或由用户创建)。尽管如此,我还是找到了一个属性名称列表 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,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,video_mode);
        // Move the window to top left corner.
        XF86VidModeSetViewPort(display,0);
        // Resize the window to the coresponding dimensions.
        XResizeWindow(display,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,info->width,info->heigth);
        XMoveWindow(display,width_center,heigth_center);
    }
    
}

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

解决方法

如果你想最大化窗口,我可以提供另一种方法来做到这一点。

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;
}

窗口句柄作为参数提供给这个函数。

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

,

我找到了解决方案!好像客户端需要调用XSendEvent,不能通过XChangeProperty实现。

根据thisdata联合的前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,True),.format = 32,.data = { .l = {
                *fullscreen,XInternAtom(dpy,"_NET_WM_STATE_FULLSCREEN",None,1
            }}
    };
    
    XSendEvent(dpy,XRootWindow(dpy,XDefaultScreen(dpy)),SubstructureRedirectMask | SubstructureNotifyMask,(XEvent*) &msg);
    
    *fullscreen = !(*fullscreen);
}