Implement wxBG_STYLE_TRANSPARENT support for wxGTK.
Use composited windows if supported by GTK+ for wxWindows with this background style. Also add wxWindow::IsTransparentBackgroundSupported() and show how to use it in the sample. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@70569 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -488,6 +488,7 @@ All (GUI):
|
||||
|
||||
GTK:
|
||||
|
||||
- Implement support for wxBG_STYLE_TRANSPARENT (Armel Asselin).
|
||||
- Fix wxNotebook best size calculation.
|
||||
|
||||
MSW:
|
||||
|
@@ -81,6 +81,7 @@ public:
|
||||
virtual bool SetFont( const wxFont &font );
|
||||
|
||||
virtual bool SetBackgroundStyle(wxBackgroundStyle style) ;
|
||||
virtual bool IsTransparentBackgroundSupported(wxString* reason = NULL) const;
|
||||
|
||||
virtual int GetCharHeight() const;
|
||||
virtual int GetCharWidth() const;
|
||||
@@ -399,7 +400,6 @@ private:
|
||||
bool DoScrollByUnits(ScrollDir dir, ScrollUnit unit, int units);
|
||||
virtual void AddChildGTK(wxWindowGTK* child);
|
||||
|
||||
|
||||
DECLARE_DYNAMIC_CLASS(wxWindowGTK)
|
||||
wxDECLARE_NO_COPY_CLASS(wxWindowGTK);
|
||||
};
|
||||
|
@@ -1029,8 +1029,7 @@ public:
|
||||
wxColour GetForegroundColour() const;
|
||||
|
||||
// Set/get the background style.
|
||||
virtual bool SetBackgroundStyle(wxBackgroundStyle style)
|
||||
{ m_backgroundStyle = style; return true; }
|
||||
virtual bool SetBackgroundStyle(wxBackgroundStyle style);
|
||||
wxBackgroundStyle GetBackgroundStyle() const
|
||||
{ return m_backgroundStyle; }
|
||||
|
||||
@@ -1039,6 +1038,13 @@ public:
|
||||
// from a parent window
|
||||
virtual bool HasTransparentBackground() { return false; }
|
||||
|
||||
// Returns true if background transparency is supported for this
|
||||
// window, i.e. if calling SetBackgroundStyle(wxBG_STYLE_TRANSPARENT)
|
||||
// has a chance of succeeding. If reason argument is non-NULL, returns a
|
||||
// user-readable explanation of why it isn't supported if the return
|
||||
// value is false.
|
||||
virtual bool IsTransparentBackgroundSupported(wxString* reason = NULL) const;
|
||||
|
||||
// set/retrieve the font for the window (SetFont() returns true if the
|
||||
// font really changed)
|
||||
virtual bool SetFont(const wxFont& font) = 0;
|
||||
|
@@ -546,9 +546,14 @@ enum wxBackgroundStyle
|
||||
/* this style is deprecated and doesn't do anything, don't use */
|
||||
wxBG_STYLE_COLOUR,
|
||||
|
||||
/* this is a Mac-only style, don't use in portable code */
|
||||
wxBG_STYLE_TRANSPARENT,
|
||||
/**
|
||||
Indicates that the window background is not erased, letting the parent
|
||||
window show through.
|
||||
|
||||
Currently this style is only supported in wxOSX and wxGTK with
|
||||
compositing available, see wxWindow::IsTransparentBackgroundSupported().
|
||||
*/
|
||||
wxBG_STYLE_TRANSPARENT,
|
||||
};
|
||||
|
||||
|
||||
|
@@ -1755,11 +1755,57 @@ public:
|
||||
@c wxBG_STYLE_PAINT is a simpler and more efficient solution to the same
|
||||
problem.
|
||||
|
||||
|
||||
Under wxGTK and wxOSX, you can use ::wxBG_STYLE_TRANSPARENT to obtain
|
||||
full transparency of the window background. Note that wxGTK supports
|
||||
this only since GTK 2.12 with a compositing manager enabled, call
|
||||
IsTransparentBackgroundSupported() to check whether this is the case.
|
||||
|
||||
Also, on order for @c SetBackgroundStyle(wxBG_STYLE_TRANSPARENT) to
|
||||
work, it must be called before Create(). If you're using your own
|
||||
wxWindow-derived class you should write your code in the following way:
|
||||
@code
|
||||
class MyWidget : public wxWindow
|
||||
{
|
||||
public:
|
||||
MyWidget(wxWindow* parent, ...)
|
||||
: wxWindow() // Use default ctor here!
|
||||
{
|
||||
// Do this first:
|
||||
SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
|
||||
|
||||
// And really create the window afterwards:
|
||||
Create(parent, ...);
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
@see SetBackgroundColour(), GetForegroundColour(),
|
||||
SetTransparent()
|
||||
SetTransparent(), IsTransparentBackgroundSupported()
|
||||
*/
|
||||
virtual bool SetBackgroundStyle(wxBackgroundStyle style);
|
||||
|
||||
/**
|
||||
Checks whether using transparent background might work.
|
||||
|
||||
If this function returns @false, calling SetBackgroundStyle() with
|
||||
::wxBG_STYLE_TRANSPARENT is not going to work. If it returns @true,
|
||||
setting transparent style should normally succeed.
|
||||
|
||||
Notice that this function would typically be called on the parent of a
|
||||
window you want to set transparent background style for as the window
|
||||
for which this method is called must be fully created.
|
||||
|
||||
@param reason
|
||||
If not @NULL, a reason message is provided if transparency is not
|
||||
supported.
|
||||
|
||||
@return @true if background transparency is supported.
|
||||
|
||||
@since 2.9.4
|
||||
*/
|
||||
virtual bool IsTransparentBackgroundSupported(wxString *reason = NULL) const;
|
||||
|
||||
/**
|
||||
Sets the font for this window. This function should not be called for the
|
||||
parent window if you don't want its font to be inherited by its children,
|
||||
|
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "wx/custombgwin.h"
|
||||
#include "wx/dcbuffer.h"
|
||||
#include "wx/artprov.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// resources
|
||||
@@ -146,13 +147,28 @@ public:
|
||||
ControlWithTransparency(wxWindow *parent,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size)
|
||||
: wxWindow(parent, wxID_ANY, pos, size, wxBORDER_NONE)
|
||||
{
|
||||
Connect(wxEVT_PAINT,
|
||||
wxPaintEventHandler(ControlWithTransparency::OnPaint));
|
||||
wxString reason;
|
||||
if ( parent->IsTransparentBackgroundSupported(&reason) )
|
||||
{
|
||||
SetBackgroundStyle (wxBG_STYLE_TRANSPARENT);
|
||||
m_message = "This is custom control with transparency";
|
||||
}
|
||||
else
|
||||
{
|
||||
m_message = "Transparency not supported, check tooltip.";
|
||||
}
|
||||
|
||||
virtual bool HasTransparentBackground() { return true; }
|
||||
Create (parent, wxID_ANY, pos, size, wxBORDER_NONE);
|
||||
Connect(wxEVT_PAINT,
|
||||
wxPaintEventHandler(ControlWithTransparency::OnPaint));
|
||||
|
||||
if ( !reason.empty() )
|
||||
{
|
||||
// This can be only done now, after creating the window.
|
||||
SetToolTip(reason);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void OnPaint( wxPaintEvent& WXUNUSED(event) )
|
||||
@@ -165,8 +181,17 @@ private:
|
||||
|
||||
dc.SetTextForeground(*wxBLUE);
|
||||
dc.SetBackgroundMode(wxTRANSPARENT);
|
||||
dc.DrawText("This is custom control with transparency", 0, 2);
|
||||
dc.DrawText(m_message, 0, 2);
|
||||
|
||||
// Draw some bitmap/icon to ensure transparent bitmaps are indeed
|
||||
// transparent on transparent windows
|
||||
wxBitmap bmp(wxArtProvider::GetBitmap(wxART_WARNING, wxART_MENU));
|
||||
wxIcon icon(wxArtProvider::GetIcon(wxART_GOTO_LAST, wxART_MENU));
|
||||
dc.DrawBitmap (bmp, GetSize().x - 1 - bmp.GetWidth(), 2);
|
||||
dc.DrawIcon(icon, GetSize().x - 1 - bmp.GetWidth()-icon.GetWidth(), 2);
|
||||
}
|
||||
|
||||
wxString m_message;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -329,7 +354,7 @@ MyCanvas::MyCanvas(wxFrame *parent)
|
||||
"right one drawn directly",
|
||||
wxPoint(150, 20));
|
||||
|
||||
new ControlWithTransparency(this, wxPoint(65, 125), wxSize(300, 22));
|
||||
new ControlWithTransparency(this, wxPoint(65, 125), wxSize(350, 22));
|
||||
|
||||
SetFocusIgnoringChildren();
|
||||
SetBackgroundColour(*wxCYAN);
|
||||
|
@@ -1553,6 +1553,39 @@ wxColour wxWindowBase::GetForegroundColour() const
|
||||
return m_foregroundColour;
|
||||
}
|
||||
|
||||
bool wxWindowBase::SetBackgroundStyle(wxBackgroundStyle style)
|
||||
{
|
||||
// The checks below shouldn't be triggered if we're not really changing the
|
||||
// style.
|
||||
if ( style == m_backgroundStyle )
|
||||
return true;
|
||||
|
||||
// Transparent background style can be only set before creation because of
|
||||
// wxGTK limitation.
|
||||
wxCHECK_MSG( (style != wxBG_STYLE_TRANSPARENT) || !GetHandle(),
|
||||
false,
|
||||
"wxBG_STYLE_TRANSPARENT style can only be set before "
|
||||
"Create()-ing the window." );
|
||||
|
||||
// And once it is set, wxBG_STYLE_TRANSPARENT can't be unset.
|
||||
wxCHECK_MSG( (m_backgroundStyle != wxBG_STYLE_TRANSPARENT) ||
|
||||
(style == wxBG_STYLE_TRANSPARENT),
|
||||
false,
|
||||
"wxBG_STYLE_TRANSPARENT can't be unset once it was set." );
|
||||
|
||||
m_backgroundStyle = style;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxWindowBase::IsTransparentBackgroundSupported(wxString *reason) const
|
||||
{
|
||||
if ( reason )
|
||||
*reason = _("This platform does not support background transparency.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
|
||||
{
|
||||
if ( colour == m_backgroundColour )
|
||||
|
@@ -129,7 +129,11 @@ enum wxPoolGCType
|
||||
wxTEXT_SCREEN,
|
||||
wxBG_SCREEN,
|
||||
wxPEN_SCREEN,
|
||||
wxBRUSH_SCREEN
|
||||
wxBRUSH_SCREEN,
|
||||
wxTEXT_COLOUR_ALPHA,
|
||||
wxBG_COLOUR_ALPHA,
|
||||
wxPEN_COLOUR_ALPHA,
|
||||
wxBRUSH_COLOUR_ALPHA
|
||||
};
|
||||
|
||||
struct wxGC
|
||||
@@ -375,6 +379,13 @@ void wxWindowDCImpl::SetUpDC( bool isMemDC )
|
||||
m_textGC = wxGetPoolGC( m_gdkwindow, wxTEXT_SCREEN );
|
||||
m_bgGC = wxGetPoolGC( m_gdkwindow, wxBG_SCREEN );
|
||||
}
|
||||
else if (m_cmap == gdk_screen_get_rgba_colormap(gdk_colormap_get_screen(m_cmap)))
|
||||
{
|
||||
m_penGC = wxGetPoolGC( m_gdkwindow, wxPEN_COLOUR_ALPHA );
|
||||
m_brushGC = wxGetPoolGC( m_gdkwindow, wxBRUSH_COLOUR_ALPHA );
|
||||
m_textGC = wxGetPoolGC( m_gdkwindow, wxTEXT_COLOUR_ALPHA );
|
||||
m_bgGC = wxGetPoolGC( m_gdkwindow, wxBG_COLOUR_ALPHA );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_penGC = wxGetPoolGC( m_gdkwindow, wxPEN_COLOUR );
|
||||
|
@@ -48,6 +48,15 @@ using namespace wxGTKImpl;
|
||||
#include <gdk/gdkkeysyms-compat.h>
|
||||
#endif
|
||||
|
||||
#if wxUSE_GRAPHICS_CONTEXT
|
||||
#include "wx/graphics.h"
|
||||
#include "wx/scopedptr.h"
|
||||
#endif // wxUSE_GRAPHICS_CONTEXT
|
||||
|
||||
// gdk_window_set_composited() is only supported since 2.12
|
||||
#define wxGTK_VERSION_REQUIRED_FOR_COMPOSITING 2,12,0
|
||||
#define wxGTK_HAS_COMPOSITING_SUPPORT GTK_CHECK_VERSION(2,12,0)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// documentation on internals
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1979,6 +1988,25 @@ void wxWindowGTK::GTKHandleRealized()
|
||||
);
|
||||
}
|
||||
|
||||
// Use composited window if background is transparent, if supported.
|
||||
if (m_backgroundStyle == wxBG_STYLE_TRANSPARENT)
|
||||
{
|
||||
#if wxGTK_HAS_COMPOSITING_SUPPORT
|
||||
if (IsTransparentBackgroundSupported())
|
||||
{
|
||||
GdkWindow* const window = GTKGetDrawingWindow();
|
||||
if (window)
|
||||
gdk_window_set_composited(window, true);
|
||||
}
|
||||
else
|
||||
#endif // wxGTK_HAS_COMPOSITING_SUPPORT
|
||||
{
|
||||
// We revert to erase mode if transparency is not supported
|
||||
m_backgroundStyle = wxBG_STYLE_ERASE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// We cannot set colours and fonts before the widget
|
||||
// been realized, so we do this directly after realization
|
||||
// or otherwise in idle time
|
||||
@@ -2319,6 +2347,21 @@ void wxWindowGTK::PostCreation()
|
||||
{
|
||||
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
|
||||
|
||||
#if wxGTK_HAS_COMPOSITING_SUPPORT
|
||||
// Set RGBA visual as soon as possible to minimize the possibility that
|
||||
// somebody uses the wrong one.
|
||||
if ( m_backgroundStyle == wxBG_STYLE_TRANSPARENT &&
|
||||
IsTransparentBackgroundSupported() )
|
||||
{
|
||||
GdkScreen *screen = gtk_widget_get_screen (m_widget);
|
||||
|
||||
GdkColormap *rgba_colormap = gdk_screen_get_rgba_colormap (screen);
|
||||
|
||||
if (rgba_colormap)
|
||||
gtk_widget_set_colormap(m_widget, rgba_colormap);
|
||||
}
|
||||
#endif // wxGTK_HAS_COMPOSITING_SUPPORT
|
||||
|
||||
if (m_wxwindow)
|
||||
{
|
||||
if (!m_noExpose)
|
||||
@@ -3692,6 +3735,24 @@ void wxWindowGTK::GtkSendPaintEvents()
|
||||
|
||||
switch ( GetBackgroundStyle() )
|
||||
{
|
||||
#if wxUSE_GRAPHICS_CONTEXT
|
||||
case wxBG_STYLE_TRANSPARENT:
|
||||
{
|
||||
// Set a transparent background, so that overlaying in parent
|
||||
// might indeed let see through where this child did not
|
||||
// explicitly paint.
|
||||
// NB: it works also for top level windows (but this is the
|
||||
// windows manager which then does the compositing job)
|
||||
wxScopedPtr<wxGraphicsContext> gc (wxGraphicsContext::Create( this ));
|
||||
cairo_t *cairo_context = (cairo_t *)gc->GetNativeContext();
|
||||
|
||||
gc->Clip (m_nativeUpdateRegion);
|
||||
cairo_set_operator (cairo_context, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint (cairo_context);
|
||||
break;
|
||||
}
|
||||
#endif // wxUSE_GRAPHICS_CONTEXT
|
||||
|
||||
case wxBG_STYLE_ERASE:
|
||||
{
|
||||
wxWindowDC dc( (wxWindow*)this );
|
||||
@@ -3768,6 +3829,39 @@ void wxWindowGTK::GtkSendPaintEvents()
|
||||
paint_event.SetEventObject( this );
|
||||
HandleWindowEvent( paint_event );
|
||||
|
||||
#if wxUSE_GRAPHICS_CONTEXT
|
||||
{ // now composite children which need it
|
||||
wxScopedPtr<wxGraphicsContext> gc (wxGraphicsContext::Create( this ));
|
||||
cairo_t *cairo_context = (cairo_t *)gc->GetNativeContext();
|
||||
|
||||
// Overlay all our composite children on top of the painted area
|
||||
wxWindowList::compatibility_iterator node;
|
||||
for ( node = m_children.GetFirst(); node ; node = node->GetNext() )
|
||||
{
|
||||
wxWindow *compositeChild = node->GetData();
|
||||
if (compositeChild->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT)
|
||||
{
|
||||
GtkWidget *child = compositeChild->m_wxwindow;
|
||||
|
||||
// The source data is the (composited) child
|
||||
gdk_cairo_set_source_pixmap (cairo_context, child->window,
|
||||
child->allocation.x,
|
||||
child->allocation.y);
|
||||
|
||||
// Draw no more than our expose event intersects our child
|
||||
gc->Clip (m_nativeUpdateRegion);
|
||||
gc->Clip (child->allocation.x, child->allocation.y,
|
||||
child->allocation.width, child->allocation.height);
|
||||
|
||||
cairo_set_operator (cairo_context, CAIRO_OPERATOR_OVER);
|
||||
cairo_paint (cairo_context);
|
||||
|
||||
gc->ResetClip ();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // wxUSE_GRAPHICS_CONTEXT
|
||||
|
||||
m_clipPaintRegion = false;
|
||||
|
||||
m_updateRegion.Clear();
|
||||
@@ -3971,10 +4065,9 @@ void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
|
||||
|
||||
bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
|
||||
{
|
||||
wxWindowBase::SetBackgroundStyle(style);
|
||||
if (!wxWindowBase::SetBackgroundStyle(style))
|
||||
return false;
|
||||
|
||||
if ( style == wxBG_STYLE_PAINT )
|
||||
{
|
||||
GdkWindow *window;
|
||||
if ( m_wxwindow )
|
||||
{
|
||||
@@ -3986,6 +4079,10 @@ bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
|
||||
window = w ? gtk_widget_get_window(w) : NULL;
|
||||
}
|
||||
|
||||
bool wantNoBackPixmap = style == wxBG_STYLE_PAINT || style == wxBG_STYLE_TRANSPARENT;
|
||||
|
||||
if ( wantNoBackPixmap )
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
// Make sure GDK/X11 doesn't refresh the window
|
||||
@@ -4011,6 +4108,55 @@ bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxWindowGTK::IsTransparentBackgroundSupported(wxString* reason) const
|
||||
{
|
||||
#if wxGTK_HAS_COMPOSITING_SUPPORT && wxUSE_GRAPHICS_CONTEXT
|
||||
if (gtk_check_version(wxGTK_VERSION_REQUIRED_FOR_COMPOSITING) != NULL)
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
*reason = _("GTK+ installed on this machine is too old to "
|
||||
"support screen compositing, please install "
|
||||
"GTK+ 2.12 or later.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// NB: We don't check here if the particular kind of widget supports
|
||||
// transparency, we check only if it would be possible for a generic window
|
||||
|
||||
wxCHECK_MSG ( m_widget, false, "Window must be created first" );
|
||||
|
||||
if (!gdk_screen_is_composited(gtk_widget_get_screen(m_widget)))
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
*reason = _("Compositing not supported by this system, "
|
||||
"please enable it in your Window Manager.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif !wxGTK_HAS_COMPOSITING_SUPPORT
|
||||
if (reason)
|
||||
{
|
||||
*reason = _("This program was compiled with a too old version of GTK+, "
|
||||
"please rebuild with GTK+ 2.12 or newer.");
|
||||
}
|
||||
#elif !wxUSE_GRAPHICS_CONTEXT
|
||||
if (reason)
|
||||
{
|
||||
*reason = _("wxUSE_GRAPHICS_CONTEXT required for compositing window, "
|
||||
"please rebuild wxWidgets with support for it.");
|
||||
}
|
||||
#endif // wxGTK_HAS_COMPOSITING_SUPPORT/!wxGTK_HAS_COMPOSITING_SUPPORT
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Pop-up menu stuff
|
||||
// ----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user