Как нарисовать заголовок с помощью XCB

Я работаю над простым оконным менеджером на c с libxcb и пытаюсь украсить окно заголовком, значком и кнопками min/max/close.

Я тестирую свой wm в Xephyr. Я могу создать новое окно xterm, перемещать его и изменять его размер. Но теперь я хотел бы украсить новое окно xterm (или любое другое приложение в этом отношении), чтобы оно имело заголовок, значок и кнопки min/max/close.

На моем компьютере с Linux я только что установил тему Gtk, и если я, например, запущу Firefox, окно будет украшено после того, как я задаю эту тему в своих настройках. Так что в этом случае я думаю, что это Gtk, который применяет оформление окна. Как это работает?

Я читал, что свойство окна EWMH, _NET_WM_WINDOW_TYPE, можно использовать для определения того, как обрабатывать украшение вашего окна. Поэтому я думаю, что мог бы проверить, является ли тип окна _NET_WM_WINDOW_TYPE_NORMAL, получить WM_NAME из приложения, а затем вручную нарисовать заголовок поверх него.

Это то, как вы обычно должны рисовать свои оконные украшения? Или я могу использовать Gtk (или что-то еще) для этого?


person Carlito    schedule 28.05.2016    source источник


Ответы (1)


Так что в этом случае я думаю, что это Gtk, который применяет оформление окна. Как это работает?

Правильный. Приложения GTK говорят оконному менеджеру не украшать их, устанавливая ширину границы на 0. На данный момент я предлагаю реализовать только это: если окно устанавливает ширину границы на 0, игнорируйте для него украшения. Я бы не стал заморачиваться ни с чем другим в начале. На самом деле вы можете даже игнорировать этот намек на данный момент.

Я читал, что свойство окна EWMH […]

Не заморачивайтесь пока с EWMH. Просто декорируйте все управляемые окна, для которых граница не равна 0. Кроме того, я не вижу веской причины, по которой другие типы окон, такие как диалоги, не должны быть декорированы; Я не думаю, что оконные менеджеры действительно используют это свойство, чтобы определить это, но я могу сказать наверняка только о паре.

Это то, как вы обычно должны рисовать свои оконные украшения? Или я могу использовать Gtk (или что-то еще) для этого?

Хотя вы явно не просили об этом, последнее предложение в этой цитате говорит мне, что вы, возможно, не полностью понимаете, как работают украшения. Самый распространенный способ, и я настоятельно рекомендую вам использовать его, называется перевоспитание.

Переназначение означает, что когда вы управляете окном, вы создаете новое окно (которым, конечно же, вы не должны не управлять как обычным окном клиента), называемое окном frame, а затем переназначаете родителем окно. окно клиента в окно фрейма. Таким образом, фактическим окном верхнего уровня является окно фрейма, принадлежащее оконному менеджеру; клиентское окно (окно, с которым взаимодействует пользователь) является его прямым потомком.

Теперь вы просто делаете окно фрейма немного больше, чем окно клиента, и правильно размещаете окно клиента внутри него. Конечно, вам нужно отслеживать изменения размеров окна клиента и действовать в соответствии с ними.

Итак, почему мы создали это рамочное окно? Простой! Потому что вы можете создать растровое изображение, которое вы используете для этого и на котором вы рисуете свой заголовок. Это лучше, чем рисовать непосредственно в дочернем окне, потому что вы не будете возиться с окном, которым на самом деле не владеете.

Рисование можно выполнить с помощью «сырых» и простых вызовов, таких как xcb_poly_fill_rectangle, или вы можете использовать более сложный подход, например, с помощью библиотеки, такой как cairo (которую я бы рекомендовал). Оконный менеджер i3, например, использует простую абстракцию, которая поддерживает обе функции через флаг компиляции (libi3/draw_util.c).

Этот подход к переназначению является причиной того, что такие инструменты, как xwininfo или xprop, имеют параметр -frame. По умолчанию эти инструменты фактически игнорируют окно фрейма и спускаются в окно клиента, в значительной степени скрывая тот факт, что окно фрейма существует. Просто попробуйте xprop и xprop -frame в одном и том же окне, и вы увидите, что к окну фрейма прикреплено гораздо меньше информации.

После того, как у вас есть переподготовка и рисование, вы можете больше думать о случаях, когда вам не нужно / не хочется украшать окно. Учитывая, что здесь нужно отслеживать довольно много, я думаю, что реализация этого сначала займет вас на некоторое время. Настоятельно рекомендую изучить код других простых оконных менеджеров, которые перестраиваются.

person Ingo Bürk    schedule 28.05.2016
comment
Ах, я не знал о перевоспитании, спасибо. Я буду использовать это, чтобы нарисовать свой собственный заголовок. Но я не понимаю, как я могу заставить тему GTK отображаться для приложений GTK. Нужно ли мне что-то делать (помимо того, что я не рисую собственные украшения), если приложение устанавливает ширину границы равной 0? - person Carlito; 29.05.2016
comment
Нет, GTK — это просто библиотека, которую использует клиент. Оконный менеджер не участвует в рендеринге самого окна клиента, это зависит от клиента, который в этом случае использует GTK, чтобы упростить задачу. Вам не о чем беспокоиться. - person Ingo Bürk; 29.05.2016
comment
Самый распространенный способ сделать это — повторить. Какие еще есть способы нарисовать заголовок? - person oel_runs_the_world; 22.06.2016
comment
@oel_runs_the_world Технически оконный менеджер может отображать окно, которое находится рядом с клиентскими окнами (или даже корневым окном). Для этого клиентские вдовы не нуждаются в переподготовке. Однако это не имело бы большого смысла, а вместо этого вызвало бы много проблем. - person Ingo Bürk; 31.12.2016