#c #x11 #transparent #alpha #xlib
#c #x11 #прозрачный #альфа #xlib
Вопрос:
Я хотел бы создать полупрозрачное белое окно в XLib, но окно не полупрозрачное, оно остается полностью непрозрачным. Я использую compton compositor, и в системе есть прозрачные окна, поэтому проблема в коде:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
Display* display = XOpenDisplay(NULL);
XVisualInfo vinfo;
XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, amp;vinfo);
XSetWindowAttributes attr;
attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0x80ffffff;
Window win = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 300, 200, 0, vinfo.depth, InputOutput, vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, amp;attr);
XSelectInput(display, win, StructureNotifyMask);
GC gc = XCreateGC(display, win, 0, 0);
Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
XSetWMProtocols(display, win, amp;wm_delete_window, 1);
XMapWindow(display, win);
int keep_running = 1;
XEvent event;
while (keep_running) {
XNextEvent(display, amp;event);
switch(event.type) {
case ClientMessage:
if (event.xclient.message_type == XInternAtom(display, "WM_PROTOCOLS", 1) amp;amp; (Atom)event.xclient.data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", 1))
keep_running = 0;
break;
default:
break;
}
}
XDestroyWindow(display, win);
XCloseDisplay(display);
return 0;
}
Комментарии:
1. Обратите внимание, поскольку в OP упоминается, что для того, чтобы все это работало, в вашей системе необходимо иметь программу-компилятор, запущенную в вашей системе. В Lubuntu этого нет, нужен xcompmgr или аналогичный.
Ответ №1:
X11 ожидает предварительно умноженные цвета, т. Е. Реальные непрозрачные цвета необходимо умножить на альфа-значение (и соответственно масштабировать, т. Е. Разделить на 256, когда ширина канала равна 8 битам). С этим форматом легче работать, когда вам нужно объединить много уровней. Смотрите формулы здесь. Когда все предварительно умножено, требуется меньше вычислений.
Итак, вам нужно умножить каждый из ваших каналов R, G и B на альфа-значение (0x80) и разделить на 256.
Установка фона на 0x80808080 дает желаемый результат:
Обратите внимание, что результат отличается от того, что предлагает @patthoyts: здесь только само окно полупрозрачно, оформление WM остается непрозрачным; там и само окно, и оформление становятся прозрачными с помощью WM (и WM выполняет необходимое смешивание цветов).
Комментарии:
1. Нет, дело не в этом. Проверьте это изображение: oscomp.hu/depot/white_transparency_qt5_vs_xlib.png Цвет фона эквивалентен в обоих окнах: 0x80ffffff; Qt5 нравится, как мне это нужно, а XLib — нет. Должно быть, что-то в коде, я делаю неправильно, но что?
2. @jsr Вы пытались это сделать? Посмотрите на изображение. Как вы думаете, я отредактировал его в gimp или что?
3. Qt не является XLib. Это портативный инструментарий, который работает с X11, Windows GDI, raw фреймбуферами Linux и другими. Я понятия не имею, что Qt делает внутренне, чтобы угодить пользователю и поддерживать согласованный API. X11 делает именно то, что вы можете видеть на изображении, которое я опубликовал.
4. Qt использует расширение XRender. И это моя настоящая проблема, а не прозрачное окно: Qt правильно смешивает альфа-изображения с окнами X11 с помощью XRenderComposite, в то время как если я использую XRenderComposite, то происходит тот же эффект: чем ближе один пиксель к белому, тем меньше работает прозрачность пикселя. Если пиксель полностью белый, то XRenderComposite рисует там белый пиксель, независимо от того, какая альфа была у этого пикселя. Я уверен, что это не предполагаемое поведение смешивания XRender… Если бы вы могли показать мне, как правильно использовать XRenderComposite, тогда это было бы хорошо для меня.
5. И, конечно, я попытался изменить яркость цвета: чем ближе цвет к белому, тем меньше работает альфа, чем ближе цвет к черному, тем больше работает альфа, но это ошибочно! Если я установлю альфа-значение равным нулю, то цвет должен быть полностью прозрачным, независимо от цвета. Проверьте примеры фотографий в моей теме compton: github.com/chjj/compton/issues/382
Ответ №2:
Вам нужно установить _NET_WM_WINDOW_OPACITY. Вот фрагмент, который нужно добавить перед отображением окна:
double alpha = 0.8;
unsigned long opacity = (unsigned long)(0xFFFFFFFFul * alpha);
Atom XA_NET_WM_WINDOW_OPACITY = XInternAtom(display, "_NET_WM_WINDOW_OPACITY", False);
XChangeProperty(display, win, XA_NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)amp;opacity, 1L);
Примечание, которое вы должны добавить #include <X11/Xatom.h>
, чтобы получить объявление XA_CARDINAL .
Я не совсем уверен, насколько стабилен этот интерфейс. Похоже, это предлагаемое расширение спецификации расширенных подсказок диспетчера окон, но, насколько я вижу, оно не вошло ни в какую окончательную редакцию. Я знаю, что именно так Tk реализует поддержку прозрачности в unix.
Результат выглядит так:
Комментарии:
1. К сожалению, это не сработало. Я пробовал это в Xfce, TDE и MotifWM с compton, и оно по-прежнему полностью белое во всех средах. У меня есть код Qt5, который может установить прозрачность фона, просто установив верхний 8 бит цвета фона. Единственное, что он делает раньше, это установка атрибута «WA_TranslucentBackground» окна. Я все еще пытаюсь выяснить, что он делает, просматривая исходные коды Qt5, но безуспешно.
2. @jsr работает с последним KDE. Я думаю, вы можете изменить оконный менеджер в Xfce и TDE на что-то, что поддерживает этот atom.
3. Мне нужно универсальное решение, а не зависящее от WM. Кроме того, Qt5 может создавать полупрозрачное белое окно: oscomp.hu/depot/white_transparency_qt5_vs_xlib.png Цвет фона эквивалентен в двух программах: 0x80ffffff, и все же чистый XLib показывает полностью непрозрачное окно.