如何在Gnome桌面上编程​​一个窗口(带有长宽比提示)以正确调整大小?

时间:2019-05-10 00:32:14

标签: x11 gnome-3

使用Gnome不能正确调整带有宽高比提示的简单Xlib程序的窗口大小。当调整大小导致窗口顶部超过Gnome桌面顶部(或高于桌面顶部Gnome Classic面板栏底部)时,该窗口将显示奇怪的行为。发生这种情况时,窗口将执行以下两项操作之一-切换到最小宽度或消失。

主要在使用左或右调整大小手柄调整大小时出现问题。代码中是否有解决此问题的方法?这是Gnome的错误吗(我在CentOS 7.6上使用Gnome 3.28.2)?

发生这种情况时,我尝试了以下解决方法:

  1. 以编程方式调整窗口大小,然后忽略下一个 ConfigureNotify事件。
  2. 设置窗口的最小尺寸提示。保持窗户 从缩小到一个宽度,但仍然有问题。
  3. 设置最小和最大尺寸提示 窗口具有相同的值,因此无法调整窗口大小。然后 撤消移动窗口时的最大大小,以便可以调整大小 再次。
  4. 设置窗口的y位置,使其不会超出桌面。
  5. 以上各项的组合。

代码示例显示了3和4组合的一种解决方案尝试。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>  // XSetWMNormalHints

char *g_title = "Hello World X Example + Gnome workaround";

float aspect_ratio = 0.75;

void
configure_aspect (Display *display, Window window, float ratio)
{
    XSizeHints hints;
    unsigned char *prop = NULL;

    hints.min_width    = 100;
    hints.min_height   = 100 * ratio;
    hints.min_aspect.x = 1000;
    hints.min_aspect.y = 1000 * ratio;
    hints.max_aspect.x = 1000;
    hints.max_aspect.y = 1000 * ratio;
    hints.flags = PMinSize | PAspect;

    XSetWMNormalHints(display, window, &hints);
}

void
configure_noresize(Display *display, Window window, int w, int h)
{
    XSizeHints hints;

    hints.min_width    = w;
    hints.min_height   = h;
    hints.max_width    = w;
    hints.max_height   = h;
    hints.flags = PMinSize | PMaxSize;
    printf("***************set fixed size***************\n");

    XSetWMNormalHints(display, window, &hints);
}

configure_resize(Display *display, Window window, float ratio)
{
    XSizeHints hints;

    hints.min_width    = 100;
    hints.min_height   = 100 * ratio;
    hints.max_width    = INT_MAX;
    hints.max_height   = INT_MAX;
    hints.min_aspect.x = 1000;
    hints.min_aspect.y = 1000 * ratio;
    hints.max_aspect.x = 1000;
    hints.max_aspect.y = 1000 * ratio;
    hints.flags = PMinSize | PMaxSize | PAspect;
    printf("***************enable resize***************\n");

    XSetWMNormalHints(display, window, &hints);
}

void
Redraw(Display *display, Window window, GC gc, XFontStruct *fontinfo, int w, int h)
{
    static char     hello_string[] = "Hello World";
    static int      hello_string_length = sizeof(hello_string) - 1;
    XWindowAttributes   window_attributes;
    int         text_x;
    int         text_y;
    int         width, height;
    int         font_direction, font_ascent, font_descent;
    XCharStruct     text_structure;

    // get font info and calculate position of text
    XTextExtents(fontinfo, hello_string, hello_string_length,
        &font_direction, &font_ascent, &font_descent,
        &text_structure);
    XGetWindowAttributes(display, window, &window_attributes);
    text_x = (window_attributes.width - text_structure.width)/2;
    text_y = (window_attributes.height -
            (text_structure.ascent+text_structure.descent))/2;

    // draw the text
    XDrawString(display, window, gc,
        text_x, text_y, hello_string, hello_string_length);
}

void
configure(Display *display, Window window, XConfigureEvent *e)
{
    static int last_x = 0;
    static int last_y = 0;
    static int last_w = 0;
    static int last_h = 0;
    static int is_size_fixed = 0;
    int x;
    int y;
    int is_resize = 0;

    if (0 == last_w) {
        // initialize last width and height values
        last_w = e->width;
        last_h = e->height;
    }

    if ((e->width != last_w) || (e->height != last_h)) {
        // this is a resize event
        is_resize = 1;
    }

    if (is_resize) {
        // DEVNOTE: coordinates are client (drawing area) coordinates
        // for resize
        Window dummy;

        printf("Configure(resize): location(%d, %d), size(%d, %d)\n",
               e->x, e->y, e->width, e->height);

        XTranslateCoordinates(display, window, DefaultRootWindow(display),
                      e->x, e->y, &x, &y, &dummy);
        x -= e->x + 5;
        y -= e->y + 5;
        printf("configure: xlt_location(%d, %d)\n", x, y);
        if (y < 61) {
            // happens when resizing from left or right side
            int new_h = last_h + (last_y - 60);
            int new_w = new_h / aspect_ratio;
            printf("noresize (w2, h2)=(%d, %d)\n", new_w, new_h);

            // this sets the size to what the size would have been
            // if the top of the window hadn't passed the panel bar
            configure_noresize(display, window, new_w, new_h);

            is_size_fixed = 1;
            XStoreName(display, window, "Move window to re-enable resizing");
        } else {
            last_x = x;
            last_y = y;
        }
    } else {
        // DEVNOTE; coordinates are screen coordinates for move
        printf("Configure(move): location(%d, %d), size(%d, %d)\n",
               e->x, e->y, e->width, e->height);
        if (is_size_fixed) {
            if (e->y > 65) {
                configure_resize(display, window, aspect_ratio);
                XStoreName(display, window, g_title);
                is_size_fixed = 0;
            }
        }

        last_x = x;
        last_y = y;
    }

    last_w = e->width;
    last_h = e->height;

    printf("\n");
}

void
main_event_loop(Display *display, Window window, GC gc, XFontStruct *fontinfo)
{
    XEvent          event;
    int         do_loop = 1;

    do {
        XNextEvent(display, &event);

        switch (event.type) {
        case Expose:
        {
            XExposeEvent *e = (XExposeEvent *)&event;
            int w = e->width;
            int h = e->height;
            Redraw(display, window, gc, fontinfo, w, h);
            break;
        }
        case ClientMessage:
            // window closing, break out of event loop to quit
            do_loop = 0;
            break;
        case ConfigureNotify:
            printf("ConfigureNotify event\n");
            configure(display, window, (XConfigureEvent *)&event);
            break;
        default:
            break;
        }
    } while (do_loop);
}

int
main (int argc, char *argv[])
{
    Display         *display;
    Visual          *visual;
    int         depth;
    XSetWindowAttributes    win_attributes;
    Window          window;
    XFontStruct     *fontinfo;
    XGCValues       gc_values;
    GC          graphics_context;
    long            event_mask;

    display = XOpenDisplay(NULL);
    visual = DefaultVisual(display, 0);
    depth  = DefaultDepth(display, 0);

    win_attributes.background_pixel = XWhitePixel(display, 0);
    window = XCreateWindow(display, XRootWindow(display, 0),
                    0, 0, 400, 300, 5, depth,
                    InputOutput, visual,
                    CWBackPixel,
                    &win_attributes);
    XStoreName(display, window, g_title);

    // setup event mask
    event_mask = ExposureMask | StructureNotifyMask;
    XSelectInput(display, window, event_mask);

    // Tell Window Manager we are interested in window close event
    Atom WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(display, window, &WM_DELETE_WINDOW, 1);

    fontinfo = XLoadQueryFont(display, "10x20");

    gc_values.font = fontinfo->fid;
    gc_values.foreground = XBlackPixel(display, 0);
    graphics_context = XCreateGC(display, window,
                    GCFont+GCForeground, &gc_values);

    XMapWindow(display, window);
    configure_aspect(display, window, aspect_ratio);

    main_event_loop(display, window, graphics_context, fontinfo);

    XDestroyWindow(display, window);
    XCloseDisplay(display);

    return 0;
}

理想情况下,窗口的顶部将停在桌面顶部,并向下和向两侧调整大小(保持宽高比)。没有窗口消失,无视外观或表现出其他不良行为的情况的任何其他解决方案都是可以接受的。

0 个答案:

没有答案