使用Gnome不能正确调整带有宽高比提示的简单Xlib程序的窗口大小。当调整大小导致窗口顶部超过Gnome桌面顶部(或高于桌面顶部Gnome Classic面板栏底部)时,该窗口将显示奇怪的行为。发生这种情况时,窗口将执行以下两项操作之一-切换到最小宽度或消失。
主要在使用左或右调整大小手柄调整大小时出现问题。代码中是否有解决此问题的方法?这是Gnome的错误吗(我在CentOS 7.6上使用Gnome 3.28.2)?
发生这种情况时,我尝试了以下解决方法:
代码示例显示了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;
}
理想情况下,窗口的顶部将停在桌面顶部,并向下和向两侧调整大小(保持宽高比)。没有窗口消失,无视外观或表现出其他不良行为的情况的任何其他解决方案都是可以接受的。