Gtkmm-3.0 and Cairomm, transparent window not working - c++

I've been trying for the last hour to make this work.
The idea es Dock is a class whose base is Gtk::Window, and upon the signal_draw() being emited, the given context should be painted by CairoMM to be transparent.. Instead I see a black window.
Here goes the code:
Dock::Dock() : Gtk::Window()
{
set_decorated(false);
set_default_size(200,200);
set_app_paintable(true);
signal_draw().connect(sigc::mem_fun(*this,&Dock::dibujar));
}
bool Dock::dibujar(const Cairo::RefPtr<Cairo::Context>& contexto)
{
contexto->set_source_rgba(1.0,1.0,1.0,0.0);
contexto->set_operator(Cairo::OPERATOR_SOURCE);
contexto->paint();
return false;
}
Shouldn't it be enough to make the window transparent?

Your draw handler doesn't have access to the information about what else should be painted on the window, so your paint() call paints a transparent layer above what is, I guess by default, a black background.
Luckily there is a method to achieve what you want: Gtk::Widget::set_opacity()

Related

QOpenGLWidget fullscreen toggle

I am using Qt 5.6 on Windows (built with the opengl desktop flag, no ANGLE) and I have a widget inheriting QOpenGLWidget as follows:
class SomeWidget: public QOpenGLWidget, protected QOpenGLFunctions
{
...
}
This widget is added in a layout in the main window and has the main window as a parent. The OpenGL stuff displays fine. I want to maximize or make fullscreen that widget and then restore it back to its position / size in the main window. The code looks like that:
onFullscreen()
{
// remove widget from layout
// set widget's parent to NULL
// create a new dialog / layout and add widget to it
// call dialog->showFullScreen
}
onRestore()
{
// set parent to main window
// insert in main window layout
// restore original size
// close dialog
}
I also added in main():
app.setAttribute(Qt::AA_ShareOpenGLContexts); // onFullscreen() crashes if this line is not present
I get a black screen when I go to fullscreen and don't see the red clear color. There is no error message.
Interestingly if I replace dialog->showFullScreen() by dialog->showMaximized() the original rendering disappears and I don't see another dialog.
I have the same approach to display another widget fullscreen that does not derive QOpenGLWidget and it works fine.
Any idea on what is going on and how I could achieve to display the QOpenGLWidget in fullscreen and restore it back in its place in the main window ?
Many thanks !

Drop shadow on masked window

In my project, I have a window that has been masked with setMask(QRect()). It works fine, but the shadow that the Window Manager leaves is gone. I definitely want that drop shadow effect on my program.
At first, I moved all of my objects into a single widget and had that widget cast a box shadow onto the MainWindow. Then I made the MainWindow transparent with setAttribute(Qt::WA_TranslucentBackground, true) and setWindowFlags(Qt::FramelessWindowHint). This did the job, however, having a frameless window caused many issue that I can't seem to fix. Namely, this: https://stackoverflow.com/questions/31418494/qtframelesswindowhint-window-cant-be-recorded-with-obs
If I just do setAttribute(Qt::WA_TranslucentBackground, true) or set the style sheet, the background becomes black, not transparent.
So my question is, how do I make the MainWindow transparent without removing the frame? Or how do I cast a shadow when using setMask?
Thanks for your time.

Clear Transparent Background for QWidget

I have a widget as on overlay for another widget. The transparency works fine, as long as I don't clear the background of the overlay.
But I have to clear the widget to acutalize the displayed "effects". I tried to solve the inital problem (the background getting the default color) like described in 20848594, but except changing the color to black it had no effect...
Has anyone an idea why the widget which should be transparent does not display the underlaying widget(s)?
Here the code:
SudokuMarkerOverlayWidget::SudokuMarkerOverlayWidget(QWidget* parent, uint const fieldSize) : QWidget(parent)
{
// Translucent should be the correct one
setAttribute(Qt::WA_TranslucentBackground);
//setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TransparentForMouseEvents);
...
}
void SudokuMarkerOverlayWidget::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.setRenderHint( QPainter::Antialiasing );
// Tried this too, no difference
// painter.setCompositionMode(QPainter::CompositionMode_Source);
// painter.fillRect( this->rect(), Qt::transparent );
painter.setCompositionMode(QPainter::CompositionMode_Clear);
painter.eraseRect( this->rect() );
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
...
}
EDIT:
Just noticed, using CompositionMode Source instead of SourceOver for my semi-transparent painting (gradient seen in first image) also causes them to be a red-to-black-gradient instead of red-to-transparent.
That means every transparency except the inital by WA_TranslucentBackground or WA_NoSystemBackground isn't working.
Widgets in Qt can be either a 'native' or 'alien' type. In one case they're a separate operating system window. In some operating systems a transparent window isn't supported.
You might want to consider using QML if you're after fancy visual effects. That's what it was designed for.

Qt - avoid white background when resizing (set immediately a background color)

The question is in bold at the end so please read this as a whole.
I have a QAbstractScrollArea widget that I manually and completely render in the OnPaint() event.
In its constructor I set
setAttribute( Qt::WA_OpaquePaintEvent, true );
setAttribute( Qt::WA_NoSystemBackground, true );
setStyleSheet( "QWidget { background-color: rgb(0,0,77); }" );
and the paint event looks like this:
void MyArea::paintEvent (QPaintEvent *event) {
QPainter view(viewport());
view.fillRect(rect(), backgroundBrush);
renderedPixmap = heavyAndSlowRenderingOnAPixmap();
view.drawPixmap(viewRect, renderedPixmap, pixmapRect);
}
as you can see there's a "slow" function involved to render stuff into a pixmap.
The problem is: when I resize the window, I can see for a moment a white flickering in the area not yet redrawn
I know I can't avoid the white region until the viewport has been redrawn, but I'd like to draw that white region with the background color immediately.
So here's the question: can I display a background color immediately before the heavy-pixmap rendering?
I can't seem to find a way to achieve this.. it seems all graphics operations are buffered and then immediately bit-blitted to the screen together. I'm using Windows 8.1 x64 and Qt5. Any way to immediately draw the background color and then proceed with the rest of the rendering?
The best solution would be to move the expensive rendering out of the paintEvent(), potentially into another thread. You'll want to cache the rendered pixmap anyway. Update that pixmap when really needed and then call update() to trigger a repaint.

Transparent child control

I'm writing a control that may have some of its parts transparent or semitransparent. Basically this control shows a png image (with alpha channel). The control's parent window has some graphics on it. Therefore, to make the png control render correctly it needs to get image of what the parent window would draw beneath it. Parent dialog might have WS_CLIPCHILDREN flag set, that means that the the parent window won't draw anything under the the png control and in this case png control won't work properly.
This control has to work on Windows Mobile also, so it can't have WS_EX_TRANSPARENT
Funny you should ask. I just wrote code to do this yesterday. It's in the code base for Project Resistance. Look at how ResistorView (which has a PNG with transparency) interacts with MainForm (which has the background image).
I'm not doing c#, so I don't think that could be helpful. I tried to look into your code and I don't see anything that can solve my problem even though you accomplish the same task as me.
To give more details, my control also supports gif animation and I also used the same IImage load from stream as you do in your project. From my experience, that IImage load from stream is unbelievable junk code, it's extremely slow. I have no idea how that possibly could be so slow. Loading 32x32 gif with 31 frames takes like 1.5secods using that junk IImage stuff. I wrote my own loader (using some opensource gif library) and without any optimization entire decoding/loading of the gif frames takes less than 100ms. I'm using TouchPro2... I can't imagine how badly this code would perform on a low end device.
As a quick alternative here's a possible solution to my question:
in the WM_PAINT handler of the child control that draws images (gif or png) I do the following:
first, I call SetRedraw(false) on self and on parent window.
then I hide the child control, and send WM_PAINT to parent window with optional HDC (as wParam). The parent window renders everything to the offscreen bitmap (passed via hdc to WM_PAINT) and after WM_PAINT successfully returns I take relevant part of the offscreen bitmap.
Then I enable show the child window and call SetRedraw(true) on both child and the parent window. That trick works but has some disadvantages obviously (I need to createa huge offscreen bitmap to capture entire screen area even though I need 32x32 pixel from the middle of parent window).
the code is below:
bool pic_control::get_parent_bg(MyBitmap & bg)
{
CWindow parent = GetParent();
CClientDC dc(parent);
bool is_visible = IsWindowVisible() && parent.IsWindowVisible();
if(!is_visible){
return false;
}
parent.SetRedraw(false);
SetRedraw(false);
CRect rect;
parent.GetClientRect(rect);
MyBitmap bmp;
bmp.create(rect.Width(), rect.Height());
ShowWindow(SW_HIDE);
parent.SendMessage(WM_PAINT, (WPARAM)(HDC)bmp.dc());
ShowWindow(SW_SHOW);
GetWindowRect(rect);
parent.ScreenToClient(rect);
bg.create(rect.Width(), rect.Height());
bg.dc().BitBlt(0, 0, rect.Width(), rect.Height(), bmp.dc(), rect.left, rect.top, SRCCOPY);
IF_DEBUG SAL::saveHBITMAPToJpeg(bg.GetBitmap(), "frames/BG.jpg", 100);
SetRedraw(true);
parent.SetRedraw(true);
return true;
}
WS_CLIPCHILDREN is forced on in WinCe, you cannot toggle it. I dont know why, maybe it is done for performance reasons.
From my experience what i did in this situation.
1) If the parent window bacgkround is dynamic (for instance window that contains map, which can be moved), then it is painted to memory canvas first, then to the screen, and memory canvas is saved and used for painting transparent childs. Memory canvas would not contain holes in place of child windows, so it can be used for futher pixel merge. The disadvantage here is memory consumption to hold canvas in memory.
2) If parent window background is static (dialog box, menu, etc) then you can make non-window childs.
class CImageButton
{
public:
bool IsPointInside(POINT pt);
void OnPaint(HDC canvas);
void OnClick();
void SetRect(RECT& rc);
private:
RECT m_rc;
};
Your parent window will contain an array of such objects and redirect WM_PAINT and
mouse clicks to them.
The disavantage is additional code needed to be added to parent window, but you can make a base class for all your parent windows, which would handle issues with non-windowed controls.