Окно простой программы Xlib с подсказкой соотношения сторон не изменяется должным образом с Gnome.Когда изменение размера приводит к тому, что верхняя часть окна становится выше верхней части рабочего стола Gnome (или выше нижней части панели панели Gnome Classic в верхней части рабочего стола), в окне отображается странное поведение.Когда это происходит, окно выполняет одно из двух действий - переключается на минимальную ширину или исчезает.
Проблемы в основном возникают при изменении размера с помощью левого или правого маркеров изменения размера.Есть ли способ обойти это в коде?Является ли это ошибкой в Gnome (я использую Gnome 3.28.2 в CentOS 7.6)?
Я пробовал следующие обходные пути, когда это происходит:
- Программно изменяя размеры окна изатем игнорируем следующее событие ConfigureNotify.
- Установка подсказки о минимальном размере окна.Это предотвращает сокращение окна до ширины, равной единице, но по-прежнему имеет проблемы.
- Установка минимальных и максимальных размеров окна одинаковыми значениями, поэтому размер окна не может быть изменен.Затем отмените максимальный размер при перемещении окна, чтобы можно было снова изменить его размер.
- Установка положения y окна, чтобы оно не выходило за рабочий стол.
- Комбинации вышеперечисленного.
В примере кода показана одна попытка решения с комбинацией 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;
}
В идеале верхняя часть окна должна останавливаться в верхней части рабочего стола и изменять размервниз и в стороны (сохраняя аспект).Приемлемо любое другое решение, которое не имеет условия, при котором окно исчезает, игнорирует аспект или проявляет другое плохое поведение.