LINUX.ORG.RU

Перемещение собственного окна программно в X11

 , ,


0

3

Здравствуйте

Имеется окно, у которого нет заголовка и бордера. Всё изображение внутри окна рисуется через OpenGL, включая собственный заголовок и кнопки типа развернуть/свернуть. И всё вроде бы более-менее работает, но есть большая проблема с тем, чтобы поставить окно в нужное место на экране. В первую очередь это необходимо, чтобы тащить окно мышью за собственный заголовок, но не тут-то было. Окно при перетаскивании дребезжит по всему экрану, хотя и перемещается в нужную сторону. Само перемещение делается сейчас так:

// Изменение положения окна на рабочем столе
void GPlatformUnixOGL::SetWindowRect(CMagicRect* rect)
{
    int wi=rect->Width();
    int he=rect->Height();

   XMoveResizeWindow(display, window, rect->left, rect->top, wi, he);

    XFlush(display);
}

Попытки делать что-то типа override_redirect=True; приводят к тому, что окно нельзя свернуть, хотя дребезга и становится меньше.

Что я делаю не так ? Мне всего-то и надо, чтобы окно заняло то положение, которое я ему отправляю.

Само окно создается так:

int glxAttribs[]={
GLX_RGBA,               // Используем режим RGBA
GLX_DOUBLEBUFFER,       // Двойная буферизация
None                    // Завершаем список атрибутов
};

// Выбираем визуальный формат
XVisualInfo* visualInfo=glXChooseVisual(display, screen, glxAttribs);

Window rootWindow=RootWindow(display, screen);
XSetWindowAttributes windowAttributes;
windowAttributes.colormap=XCreateColormap(display, rootWindow, visualInfo->visual, AllocNone);
windowAttributes.background_pixmap=None;  // ОТКЛЮЧАЕМ очистку фона!
windowAttributes.backing_store=Always;    // Просим X11 сохранять буфер окна

window=XCreateWindow(
display,
rootWindow,
wx, wy, view_width, view_height, // Позиция и размер окна
0,                               // Без границы
visualInfo->depth,               // Глубина цвета
InputOutput,                     // Тип окна
visualInfo->visual,              // Визуальный формат
CWColormap | CWEventMask,        // Устанавливаем атрибуты окна
&windowAttributes
);


// Указываем тип окна NORMAL
Atom wmWindowType = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
Atom wmWindowNormal = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
XChangeProperty(display, window, wmWindowType, XA_ATOM, 32, PropModeReplace, (unsigned char *)&wmWindowNormal, 1);

// Отключаем рамки и заголовок
Atom motifHints = XInternAtom(display, "_MOTIF_WM_HINTS", False);
struct {
long flags;
long functions;
long decorations;
long input_mode;
long status;
} hints = { 2, 0, 0, 0, 0 };
XChangeProperty(display, window, motifHints, motifHints, 32, PropModeReplace, (unsigned char *)&hints, 5);

XSizeHints *h = XAllocSizeHints();
h->flags = PPosition | PSize | PResizeInc | PBaseSize;
h->x = 100;          // Координаты X
h->y = 100;          // Координаты Y
h->width = 640;      // Ширина окна
h->height = 480;     // Высота окна
h->base_width = 640; // Базовая ширина
h->base_height = 480; // Базовая высота

XSetWMNormalHints(display, window, h);
XFree(h);

Всё изображение внутри окна рисуется через OpenGL, включая собственный заголовок и кнопки типа развернуть/свернуть.

Тебя вяленый покусал, что-ли?

anonymous
()

Окно при перетаскивании дребезжит по всему экрану, хотя и перемещается в нужную сторону.

Подозреваю что у тебя проблема с расчётом координат.

rect->left, rect->top

Вот эти значения откуда там берутся? Надо в начале перемещения запомнать все нужные числа и потом смотреть только на положение мышки и пересчитывать по ней. Я когда делал перемещение/ресайз в своём WM, сначала пересчитывал всё при каждом движении мышки и тоже дребезжание получалось из-за разных факторов.

И уточни, что именно ты под «дребезжит» имеешь ввиду - меняются координаты начала окна или его размер?

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от Skullnet

Почему антипаттерн, может он хочет индивидуальный дизайн.

Но, автор, если ты хочешь эмулировать таким способом стандартный заголовок в обычном его оформлении - то, да, так делать не надо. Заголовки в разных WM разные, а в каких-то их вообще нет.

firkax ★★★★★
()

Что за wm? И как он обрабатывает configurenotify?. Думаю они друг другу мешают при перетаскивании окна мышью, поэтому у тебя окно туда-сюда елозит. Это асинхронно происходит. Выставь для окна wm hints, wm window type(dock или dialog). А wm дальше сам справится.

arrecck ★★★
()
Ответ на: комментарий от firkax

И уточни, что именно ты под «дребезжит» имеешь ввиду - меняются координаты начала окна или его размер?

Окно прыгало с правой части экрана на левую. Но, кстати, вы оказались правы - я нашел у себя проблему с координатами. Теперь прыгать перестало и даже вроде перемещается нормально, но есть ещё проблема.

Odin_KG
() автор топика
Ответ на: комментарий от arrecck

Что за wm?

echo $DESKTOP_SESSION
/usr/share/xsessions/plasma

echo $XDG_CURRENT_DESKTOP
KDE

У меня достаточно неновая Fedora

Выставь для окна wm hints, wm window type(dock или dialog).

Dock вообще лучше не ставить, потому что мой Linux такое окно всегда отображает поверх других окон, а кроме того оно не сворачивается.

Odin_KG
() автор топика
Ответ на: комментарий от Skullnet

Антипаттерн и юзай тогда SDL.

Хотелось бы обойтись без SDL, тем более, что там нет Drag & Drop.

Вообще сейчас ситуация такова, что по крайней мере на моем компьютере всё более-менее заработало. Единственное что всё портит - если приложение стартует с развернутым окном (точнее я его не разворачиваю, а просто указываю положение во весь экран), то потом приложение уже размер окна менять отказывается (просто игнорирует новые размер и положение). Тут надо ещё подумать…

Odin_KG
() автор топика
Ответ на: комментарий от firkax

Я могу нарисовать самостоятельно заголовок с кнопками развернуть, свернуть, закрыть и бордер ? Мне ещё потребуется, чтобы собственные размеры у этих элементов назначить.

Odin_KG
() автор топика
Ответ на: комментарий от MOPKOBKA

В SDL нет полноценного Drag & Drop - там есть очень ограниченный вариант, чтобы текст скопировать. Мне же нужно свой формат данных регистрировать.

Odin_KG
() автор топика
Ответ на: комментарий от Odin_KG

Зачем тебе собственные размеры для них? Смотри, пользователь настроил себе систему так как ему нравится, включая заголовки окон с кнопками (или их отсутствие, как у меня), а ты «нет, глупый юзер, твои кастомные настройки я пошлю нафиг и буду рисовать как мне хочется». Зачем?

firkax ★★★★★
()
Ответ на: комментарий от firkax

Вопрос, «зачем ?» он как бы неверный, потому что если бы мне не надо было, я бы так не делал. Мне нужно, чтобы работало как минимум на Windows, Mac и на Linux, причем уже понятно, что Linux будет всячески сопротивляться из-за того, что по сути там нормально работает только 1 вариант конкретно через WM (ну уж меньше этого реализовать просто невозможно), а всё остальное несмотря на «заявленность», как я понимаю, в общем случае не работает. Сколько сил на эту уходит, а в результате находится какая-то хрень, которая всё блокирует и хоть начинай с начала.

Odin_KG
() автор топика
Ответ на: комментарий от Odin_KG

Что значит неверный? Очень даже верный. Ты на него сам знаешь ответ?

Linux будет всячески сопротивляться из-за того, что по сути там нормально работает только 1 вариант

Нет, не так. Linux тут вообще ни при чём на самом деле, он окнами не занимается. И это не придирки к словам в данном случае, а существенное уточнение: окнами занимается графический сервер и приложения к нему, тебе надо думать именно о них. А уж запущен он на линуксе или ещё где-то, разницы почти не сделает.

Графических серверов сейчас есть два: один нормальный (xorg), впорой школоподелка, распиаренная зачем-то редхатом (вайланд). Так вот, на втором у тебя окно перемещать вообще не получится, потому что он это не поддерживает и наоборот заявляет что это такая защита от злонамеренных прог. Но не будем о грустном (рекомендую просто указать что вайланд не поддерживается и ссылку на инструкции по замене его на xorg).

Xorg, хоть сам по себе это и один проект, но управление окнами он делегирует оконному менеджеру. Разных оконных менеджеров - сотни, часть их них похожа друг на друга, часть не похожа. Так вот, часть их них использует оформление окон с заголовками, кнопками на них и самодельными рамками, за заголовки можно перемещать, кнопками ещё что-то делать. Другие ничего этого не рисуют, окно это просто прямоугольник это экране, целиком заполненный той картинкой, которую там сделало приложение. Управление при этом делается либо через хоткеи клавиатуры, либо через таскбар. Перемещение окон, хотя по умолчанию в Xorg разрешено, но оконный менеджер запросто может его заблокировать (как и ресайз), и разрешать делать только через интерфейс, нарисованный оконным менеджером. Всякие кнопки сворачивания и прочего - это вообще не дефолт никаким боком, это целиком «творение» оконного менеджера, и работают они так, как выбрал его автор. Послать команду «свернуть окно» мимо них не всегда можно.

а всё остальное несмотря на «заявленность»,

Я не знаю где ты нашёл заявленность. Заявлено было только то, что пользователь может, выбирая разные штуки, переделать поведение окон и прочего до неузнаваемости.

Всё равно, без указания цели всех этих действий сложно что-то посоветовать.

Думаю что вариант «где можно - работает, где нельзя - кнопки/перемещение/ресайз тупо ничего не делают» тебя устроит, потому что другого всё равно нет. Если юзер настроил себе систему так, что прога не может сама сворачивать своё окно - то ты ничего с этим не поделаешь, юзер сильнее. А если ты юзера начнёшь пытаться перехитрить, то это уже будет поведение, подобное всяким вирусам, и твою прогу просто снесут.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Благодарю за подробные объяснения!

Я не знаю где ты нашёл заявленность.

Заявленность состоит в том, что есть функции которые устанавливают положение окна, а также, например, окно можно свернуть программно. Но… если ничего это не работает в общем случае, то таких функций вообще быть не должно - просто не надо дурачить людей, раз это всё в реальности неприменимо.

Odin_KG
() автор топика
Ответ на: комментарий от Odin_KG

У этих функций в документации указано, что их может перехватывать оконный менеджер и подменять их поведение. Если ты пишешь оконный менеджер - то они будут работать точно так, как там описано. Если ты используешь оконный менеджер, которых их не перехватывает - то тоже.

Причём перехват не всегда чтобы заблокировать. Вот пример: допустим, у проги есть окно 100х100 пикселей, и она хочешь его поставить (левый верхний угол) на x=10, y=10. Но оконный менеджер вокруг этого окна рисует рамку и заголовок. Рамка, допустим, занимает 3 пикселя, заголовок 20 пикселей. И так вот, программа шлёт команду «переместить окно на 10,10», оконный менеджер её перехватывает и заменяет на:

1) переместить рамку на 10,10

2) переместить заголовок на 13,13

3) переместить основное окно (то самое) на 13,33

В итоге окно расположено немного не так, где хотела прога, потому что прога не учитывает что над окном есть ещё 23 пикселя служебным элементов. Аналогично и с ресайзом - прога хочет размер 100х100, а оконный менеджер должен думать как всё сделать чтобы ещё и заголовок с рамкой влезли - то ли уменьшить настоящий размер окна, то ли увеличить размер окна+заголовка+рамки.

Есть, конечно, и другой вариант - окно переместить на 10,10, как прога и хотела, а заголовок пририсовать выше (он на y=-10 окажется и уползёт за границу экрана).

Но и для блокировки перемещения этот перехват тоже, конечно, может использоваться.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Благодарю за пояснения ещё раз!

У этих функций в документации указано, что их может перехватывать оконный менеджер и подменять их поведение.

Хм… может я что-то неправильно понимаю, но я бы такие функции просто повыбрасывал, чтобы не создавать путаницу.

И так вот, программа шлёт команду «переместить окно на 10,10», оконный менеджер её перехватывает и заменяет на:

Т.е. X11 воспринимает координаты окна как координаты клиентской части, а не самого окна ??? Подозреваю, что это же и размера касается.

Вы мне сказали главное, что делать на Linux-е так, как я хотел нельзя. Т.е. я вероятно должен выбросить свой заголовок и бордер, и использовать здесь возможности WM. Вроде бы понятно, что делать, но не знаю, сколько там в сумме мелких проблем будет, так как на такой вариант у меня приложение изначально не рассчитано.

Но я теперь вообще не понимаю, могу ли я хоть как-то самостоятельно указать положение окна (хотя бы размер) ? Просто у меня запоминается положение окна в момент закрытия и при следующем запуске окно должно появится в том же месте.

Далее, как я понимаю, я не могу никак убрать с заголовка кнопки типа «свернуть» и «закрыть». Хотя нажатие «закрыть» по-крайней мере можно отловить и сделать свою реакцию А все остальные кнопки на заголовке вообще получаются никак мною не управляемы ?

Odin_KG
() автор топика