Unsolved Window Transparency in Linux
-
Hi all,
I'm trying to achieve window transparency in a simple QMainWindow on Linux (XCB Qt5.3 for Raspberry Pi).
I've tried the following, resulting in a black window:
setAttribute(Qt::WA_TranslucentBackground, True);
setStyleSheet("background:transparent;");
setAttribute(Qt::WA_PaintOnScreen);I also realized I had no compositing manager running so I tried xcompmgr and Compton.
Both make my windows invisible and xcompmgr gives the following errors:
error 8: BadMatch (invalid parameter attributes) request 142 minor 6 serial 14338
error 9: BadDrawable (invalid Pixmap or Window parameter) request 139 minor 4 serial 14339
error 4: BadPixmap (invalid Pixmap parameter) request 54 minor 0 serial 14430Googling for these errors doesn't give clear solutions, but one involves setting the pixel depth on framebuffer. Not sure what I should try setting that to in Qt.
Has anyone else run into this problem before?
Thanks,
Greg -
what is distro ?
-
Raspbian based on Debian Jessie 4.4
-
The first thing you want to do is narrow down the problem by testing out the most primitive and foolproof form of window transparency Qt supports.
Instantiate a
QWidget
, callsetWindowOpacity(0.4)
on it, andshow()
it.I'm generally paranoid about crashes and focused on I/O-bound tasks, so I'm only set up to develop with PyQt at the moment, but this Python3+PyQt5 code displays an empty window on my Kubuntu 14.04 machine which will be entirely transparent (background and foreground, including frame) if compositing is enabled or opaque if it's disabled. (KWin lets you toggle compositing with Alt+Shift+F12)
from PyQt5 import QtGui, QtWidgets app = QtWidgets.QApplication([]) test_widget = QtWidgets.QWidget() test_widget.setWindowOpacity(0.4) test_widget.show() app.exec_()
Give me a bit of time to experiment and I'll try to come up with some proven code for getting a transparent background. (I did use transparency in one of my old PyGTK projects and, under the GTK+ 2.x API, one of the steps is requesting an ARGB visual from the X server because, by default, you're drawing into a plain RGB one. That may be what they meant by "setting the pixel depth on the framebuffer".)
EDIT: Ok, I just installed Qt Creator and here's what I've determined:
-
Adding
setAttribute(Qt::WA_TranslucentBackground);
to the constructor of a bog-standard, wizard-generatedQWidget
will give you what basically looks like a window frame with nothing in it. (In other words, a transparent background, ready to draw on.) -
Your code worked for me once I lowercased
True
and removedsetAttribute(Qt::WA_PaintOnScreen);
. (Without it, I get proper transparency. With it, the window captures a snapshot of whatever is under it at the time it appears.) -
I tried again with one of my non-trivial PyQt GUIs and, on Linux,
window.setAttribute(Qt.WA_TranslucentBackground)
was all I needed to get the kind of behaviour you probably expect. (Translucency everywhere that you'd normally see the window background color but things with their own backgrounds likeQListView
unaffected.)
I also found this StackOverflow thread, which should clarify things a bit if you read both answers.
TL;DR:
- Use
setAttribute(Qt::WA_TranslucentBackground);
- Don't use
setAttribute(Qt::WA_PaintOnScreen);
- It won't work on Windows unless you
setWindowFlags(Qt::FramelessWindowHint);
, but that'll make your window completely invisible unless you draw on it. - Don't add
setStyleSheet("background:transparent;");
until you actually need it. You want to stay as close to default behaviour as possible so unexpected behaviours are simpler to diagnose.
-