]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
guard XTI
[wxWidgets.git] / src / gtk / window.cpp
index 1a3f1065b08be29f2cee5a115802df9c3d02d80b..4178eddb5729d9c1612df273c082c4667cc8caa4 100644 (file)
@@ -31,7 +31,6 @@
 #include "wx/tooltip.h"
 #include "wx/caret.h"
 #include "wx/fontutil.h"
-#include "wx/scopeguard.h"
 #include "wx/sysopt.h"
 
 #include <ctype.h>
 #include "wx/gtk/private/event.h"
 using namespace wxGTKImpl;
 
+#ifdef GDK_WINDOWING_X11
 #include <gdk/gdkx.h>
+#include "wx/x11/private/wrapxkb.h"
+#else
+typedef guint KeySym;
+#endif
 
 #include <gdk/gdkkeysyms.h>
 #if GTK_CHECK_VERSION(3,0,0)
 #include <gdk/gdkkeysyms-compat.h>
 #endif
 
+// 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
 //-----------------------------------------------------------------------------
@@ -213,28 +221,6 @@ int          g_lastButtonNumber = 0;
 // the trace mask used for the focus debugging messages
 #define TRACE_FOCUS wxT("focus")
 
-//-----------------------------------------------------------------------------
-// "size_request" of m_widget
-//-----------------------------------------------------------------------------
-
-extern "C" {
-static void
-wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
-                                   GtkRequisition *requisition,
-                                   wxWindow * win)
-{
-    int w, h;
-    win->GetSize( &w, &h );
-    if (w < 2)
-        w = 2;
-    if (h < 2)
-        h = 2;
-
-    requisition->height = h;
-    requisition->width = w;
-}
-}
-
 //-----------------------------------------------------------------------------
 // "expose_event" of m_wxwindow
 //-----------------------------------------------------------------------------
@@ -724,6 +710,7 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
                 keysym = (KeySym)gdk_event->string[0];
             }
 
+#ifdef GDK_WINDOWING_X11
             // we want to always get the same key code when the same key is
             // pressed regardless of the state of the modifiers, i.e. on a
             // standard US keyboard pressing '5' or '%' ('5' key with
@@ -737,11 +724,18 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
 
             wxLogTrace(TRACE_KEYS, wxT("\t-> keycode %d"), keycode);
 
+#ifdef HAVE_X11_XKBLIB_H
+            KeySym keysymNormalized = XkbKeycodeToKeysym(dpy, keycode, 0, 0);
+#else
             KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
+#endif
 
             // use the normalized, i.e. lower register, keysym if we've
             // got one
             key_code = keysymNormalized ? keysymNormalized : keysym;
+#else
+            key_code = keysym;
+#endif
 
             // as explained above, we want to have lower register key codes
             // normally but for the letter keys we want to have the upper ones
@@ -875,6 +869,17 @@ void AdjustCharEventKeyCodes(wxKeyEvent& event)
 
 } // anonymous namespace
 
+// If a widget does not handle a key or mouse event, GTK+ sends it up the
+// parent chain until it is handled. These events are not supposed to propagate
+// in wxWidgets, so this code avoids handling them in any parent wxWindow,
+// while still allowing the event to propagate so things like native keyboard
+// navigation will work.
+#define wxPROCESS_EVENT_ONCE(EventType, event) \
+    static EventType eventPrev; \
+    if (memcmp(&eventPrev, event, sizeof(EventType)) == 0) \
+        return false; \
+    eventPrev = *event
+
 extern "C" {
 static gboolean
 gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
@@ -886,6 +891,8 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
     if (g_blockEventsOnDrag)
         return FALSE;
 
+    wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event);
+
     wxKeyEvent event( wxEVT_KEY_DOWN );
     bool ret = false;
     bool return_after_IM = false;
@@ -916,7 +923,8 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
         // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
         // docs, if IM filter returns true, no further processing should be done.
         // we should send the key_down event anyway.
-        bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
+        bool intercepted_by_IM =
+            gtk_im_context_filter_keypress(win->m_imData->context, gdk_event) != 0;
         win->m_imData->lastKeyEvent = NULL;
         if (intercepted_by_IM)
         {
@@ -1057,6 +1065,8 @@ gtk_window_key_release_callback( GtkWidget * WXUNUSED(widget),
     if (g_blockEventsOnDrag)
         return FALSE;
 
+    wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event);
+
     wxKeyEvent event( wxEVT_KEY_UP );
     if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
     {
@@ -1122,7 +1132,7 @@ static void AdjustEventButtonState(wxMouseEvent& event)
     }
 }
 
-// find the window to send the mouse event too
+// find the window to send the mouse event to
 static
 wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
 {
@@ -1139,7 +1149,7 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
     wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
     while (node)
     {
-        wxWindowGTK *child = node->GetData();
+        wxWindow* child = static_cast<wxWindow*>(node->GetData());
 
         node = node->GetNext();
         if (!child->IsShown())
@@ -1172,6 +1182,7 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
         else
         {
             if ((child->m_wxwindow == NULL) &&
+                win->IsClientAreaChild(child) &&
                 (child->m_x <= xx) &&
                 (child->m_y <= yy) &&
                 (child->m_x+child->m_width  >= xx) &&
@@ -1251,6 +1262,8 @@ gtk_window_button_press_callback( GtkWidget *widget,
                                   GdkEventButton *gdk_event,
                                   wxWindowGTK *win )
 {
+    wxPROCESS_EVENT_ONCE(GdkEventButton, gdk_event);
+
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     g_lastButtonNumber = gdk_event->button;
@@ -1448,6 +1461,8 @@ gtk_window_button_release_callback( GtkWidget *WXUNUSED(widget),
                                     GdkEventButton *gdk_event,
                                     wxWindowGTK *win )
 {
+    wxPROCESS_EVENT_ONCE(GdkEventButton, gdk_event);
+
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     g_lastButtonNumber = 0;
@@ -1511,6 +1526,8 @@ gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
                                    GdkEventMotion *gdk_event,
                                    wxWindowGTK *win )
 {
+    wxPROCESS_EVENT_ONCE(GdkEventMotion, gdk_event);
+
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     if (gdk_event->is_hint)
@@ -1607,22 +1624,43 @@ window_scroll_event_hscrollbar(GtkWidget*, GdkEventScroll* gdk_event, wxWindow*
 static gboolean
 window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
 {
-    if (gdk_event->direction != GDK_SCROLL_UP &&
-        gdk_event->direction != GDK_SCROLL_DOWN)
-    {
-        return false;
-    }
-
     wxMouseEvent event(wxEVT_MOUSEWHEEL);
     InitMouseEvent(win, event, gdk_event);
 
     // FIXME: Get these values from GTK or GDK
     event.m_linesPerAction = 3;
     event.m_wheelDelta = 120;
-    if (gdk_event->direction == GDK_SCROLL_UP)
-        event.m_wheelRotation = 120;
-    else
-        event.m_wheelRotation = -120;
+
+    // Determine the scroll direction.
+    switch (gdk_event->direction)
+    {
+        case GDK_SCROLL_UP:
+        case GDK_SCROLL_RIGHT:
+            event.m_wheelRotation = 120;
+            break;
+
+        case GDK_SCROLL_DOWN:
+        case GDK_SCROLL_LEFT:
+            event.m_wheelRotation = -120;
+            break;
+
+        default:
+            return false;  // Unknown/unhandled direction
+    }
+
+    // And the scroll axis.
+    switch (gdk_event->direction)
+    {
+        case GDK_SCROLL_UP:
+        case GDK_SCROLL_DOWN:
+            event.m_wheelAxis = wxMOUSE_WHEEL_VERTICAL;
+            break;
+
+        case GDK_SCROLL_LEFT:
+        case GDK_SCROLL_RIGHT:
+            event.m_wheelAxis = wxMOUSE_WHEEL_HORIZONTAL;
+            break;
+    }
 
     if (win->GTKProcessEvent(event))
       return TRUE;
@@ -1935,10 +1973,18 @@ void gtk_window_style_set_callback( GtkWidget *WXUNUSED(widget),
 {
     if (win && previous_style)
     {
-        wxSysColourChangedEvent event;
-        event.SetEventObject(win);
-
-        win->GTKProcessEvent( event );
+        if (win->IsTopLevel())
+        {
+            wxSysColourChangedEvent event;
+            event.SetEventObject(win);
+            win->GTKProcessEvent(event);
+        }
+        else
+        {
+            // Border width could change, which will change client size.
+            // Make sure size event occurs for this
+            win->m_oldClientWidth = 0;
+        }
     }
 }
 
@@ -1956,6 +2002,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
@@ -1980,6 +2045,13 @@ void wxWindowGTK::GTKHandleRealized()
 
 wxWindow *wxWindowBase::DoFindFocus()
 {
+    // For compatibility with wxMSW, pretend that showing a popup menu doesn't
+    // change the focus and that it remains on the window showing it, even
+    // though the real focus does change in GTK.
+    extern wxMenu *wxCurrentPopupMenu;
+    if ( wxCurrentPopupMenu )
+        return wxCurrentPopupMenu->GetInvokingWindow();
+
     wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus;
     // the cast is necessary when we compile in wxUniversal mode
     return static_cast<wxWindow*>(focus);
@@ -1995,9 +2067,8 @@ void wxWindowGTK::AddChildGTK(wxWindowGTK* child)
     child->m_x += pizza->m_scroll_x;
     child->m_y += pizza->m_scroll_y;
 
-    gtk_widget_set_size_request(
-        child->m_widget, child->m_width, child->m_height);
-    pizza->put(child->m_widget, child->m_x, child->m_y);
+    pizza->put(child->m_widget,
+        child->m_x, child->m_y, child->m_width, child->m_height);
 }
 
 //-----------------------------------------------------------------------------
@@ -2286,8 +2357,11 @@ bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos,  const w
     m_width = WidthDefault(size.x) ;
     m_height = HeightDefault(size.y);
 
-    m_x = (int)pos.x;
-    m_y = (int)pos.y;
+    if (pos != wxDefaultPosition)
+    {
+        m_x = pos.x;
+        m_y = pos.y;
+    }
 
     return true;
 }
@@ -2296,6 +2370,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)
@@ -2394,16 +2483,8 @@ void wxWindowGTK::PostCreation()
     }
 #endif // GTK+ >= 2.8
 
-    if ( GTKShouldConnectSizeRequest() )
-    {
-        // This is needed if we want to add our windows into native
-        // GTK controls, such as the toolbar. With this callback, the
-        // toolbar gets to know the correct size (the one set by the
-        // programmer). Sadly, it misbehaves for wxComboBox.
-        g_signal_connect (m_widget, "size_request",
-                          G_CALLBACK (wxgtk_window_size_request_callback),
-                          this);
-    }
+    if (!WX_IS_PIZZA(gtk_widget_get_parent(m_widget)) && !GTK_IS_WINDOW(m_widget))
+        gtk_widget_set_size_request(m_widget, m_width, m_height);
 
     InheritAttributes();
 
@@ -2452,7 +2533,7 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
     g_signal_connect (widget, "leave_notify_event",
                       G_CALLBACK (gtk_window_leave_callback), this);
 
-    if (IsTopLevel() && m_wxwindow)
+    if (m_wxwindow && (IsTopLevel() || HasFlag(wxBORDER_RAISED | wxBORDER_SUNKEN | wxBORDER_THEME)))
         g_signal_connect (m_wxwindow, "style_set",
                               G_CALLBACK (gtk_window_style_set_callback), this);
 }
@@ -2464,14 +2545,46 @@ bool wxWindowGTK::Destroy()
     return wxWindowBase::Destroy();
 }
 
+static GSList* gs_queueResizeList;
+
+extern "C" {
+static gboolean queue_resize(void*)
+{
+    gdk_threads_enter();
+    for (GSList* p = gs_queueResizeList; p; p = p->next)
+    {
+        if (p->data)
+        {
+            gtk_widget_queue_resize(GTK_WIDGET(p->data));
+            g_object_remove_weak_pointer(G_OBJECT(p->data), &p->data);
+        }
+    }
+    g_slist_free(gs_queueResizeList);
+    gs_queueResizeList = NULL;
+    gdk_threads_leave();
+    return false;
+}
+}
+
 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
 {
     gtk_widget_set_size_request(m_widget, width, height);
+    GtkWidget* parent = gtk_widget_get_parent(m_widget);
+    if (WX_IS_PIZZA(parent))
+        WX_PIZZA(parent)->move(m_widget, x, y, width, height);
 
-    // inform the parent to perform the move
-    wxASSERT_MSG(m_parent && m_parent->m_wxwindow,
-                 "the parent window has no client area?");
-    WX_PIZZA(m_parent->m_wxwindow)->move(m_widget, x, y);
+    // With GTK3, gtk_widget_queue_resize() is ignored while a size-allocate
+    // is in progress. This situation is common in wxWidgets, since
+    // size-allocate can generate wxSizeEvent and size event handlers often
+    // call SetSize(), directly or indirectly. Work around this by deferring
+    // the queue-resize until after size-allocate processing is finished.
+    if (g_slist_find(gs_queueResizeList, m_widget) == NULL)
+    {
+        if (gs_queueResizeList == NULL)
+            g_idle_add_full(GTK_PRIORITY_RESIZE, queue_resize, NULL, NULL);
+        gs_queueResizeList = g_slist_prepend(gs_queueResizeList, m_widget);
+        g_object_add_weak_pointer(G_OBJECT(m_widget), &gs_queueResizeList->data);
+    }
 }
 
 void wxWindowGTK::ConstrainSize()
@@ -2493,19 +2606,24 @@ void wxWindowGTK::ConstrainSize()
 
 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
 {
-    wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
-    wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
+    wxCHECK_RET(m_widget, "invalid window");
 
-    if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0 && (x == -1 || y == -1))
+    int scrollX = 0, scrollY = 0;
+    GtkWidget* parent = gtk_widget_get_parent(m_widget);
+    if (WX_IS_PIZZA(parent))
     {
-        int currentX, currentY;
-        GetPosition(&currentX, &currentY);
-        if (x == -1)
-            x = currentX;
-        if (y == -1)
-            y = currentY;
+        wxPizza* pizza = WX_PIZZA(parent);
+        scrollX = pizza->m_scroll_x;
+        scrollY = pizza->m_scroll_y;
     }
-    AdjustForParentClientOrigin(x, y, sizeFlags);
+    if (x != -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+        x += scrollX;
+    else
+        x = m_x;
+    if (y != -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+        y += scrollY;
+    else
+        y = m_y;
 
     // calculate the best size if we should auto size the window
     if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
@@ -2518,22 +2636,18 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
             height = sizeBest.y;
     }
 
-    const wxSize oldSize(m_width, m_height);
-    if (width != -1)
-        m_width = width;
-    if (height != -1)
-        m_height = height;
+    if (width == -1)
+        width = m_width;
+    if (height == -1)
+        height = m_height;
 
-    if (m_parent->m_wxwindow)
+    const bool sizeChange = m_width != width || m_height != height;
+    if (sizeChange || m_x != x || m_y != y)
     {
-        wxPizza* pizza = WX_PIZZA(m_parent->m_wxwindow);
-        m_x = x + pizza->m_scroll_x;
-        m_y = y + pizza->m_scroll_y;
-
-        int left_border = 0;
-        int right_border = 0;
-        int top_border = 0;
-        int bottom_border = 0;
+        m_x = x;
+        m_y = y;
+        m_width = width;
+        m_height = height;
 
         /* the default button has a border around it */
         if (gtk_widget_get_can_default(m_widget))
@@ -2542,36 +2656,23 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
             gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
             if (default_border)
             {
-                left_border += default_border->left;
-                right_border += default_border->right;
-                top_border += default_border->top;
-                bottom_border += default_border->bottom;
+                x -= default_border->left;
+                y -= default_border->top;
+                width += default_border->left + default_border->right;
+                height += default_border->top + default_border->bottom;
                 gtk_border_free( default_border );
             }
         }
 
-        DoMoveWindow( m_x - left_border,
-                      m_y - top_border,
-                      m_width+left_border+right_border,
-                      m_height+top_border+bottom_border );
+        DoMoveWindow(x, y, width, height);
     }
 
-    if (m_width != oldSize.x || m_height != oldSize.y)
+    if ((sizeChange && !m_nativeSizeEvent) || (sizeFlags & wxSIZE_FORCE_EVENT))
     {
         // update these variables to keep size_allocate handler
         // from sending another size event for this change
         GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
 
-        gtk_widget_queue_resize(m_widget);
-        if (!m_nativeSizeEvent)
-        {
-            wxSizeEvent event( wxSize(m_width,m_height), GetId() );
-            event.SetEventObject( this );
-            HandleWindowEvent( event );
-        }
-    } else
-    if (sizeFlags & wxSIZE_FORCE_EVENT)
-    {
         wxSizeEvent event( wxSize(m_width,m_height), GetId() );
         event.SetEventObject( this );
         HandleWindowEvent( event );
@@ -2618,8 +2719,6 @@ void wxWindowGTK::OnInternalIdle()
 
 void wxWindowGTK::DoGetSize( int *width, int *height ) const
 {
-    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
-
     if (width) (*width) = m_width;
     if (height) (*height) = m_height;
 }
@@ -2714,39 +2813,17 @@ wxSize wxWindowGTK::DoGetBorderSize() const
 
 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
 {
-    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
-
     int dx = 0;
     int dy = 0;
-    if (!IsTopLevel() && m_parent && m_parent->m_wxwindow)
+    GtkWidget* parent = NULL;
+    if (m_widget)
+        parent = gtk_widget_get_parent(m_widget);
+    if (WX_IS_PIZZA(parent))
     {
-        wxPizza* pizza = WX_PIZZA(m_parent->m_wxwindow);
+        wxPizza* pizza = WX_PIZZA(parent);
         dx = pizza->m_scroll_x;
         dy = pizza->m_scroll_y;
     }
-
-    if (m_x == -1 && m_y == -1)
-    {
-        GdkWindow *source = NULL;
-        if (m_wxwindow)
-            source = gtk_widget_get_window(m_wxwindow);
-        else
-            source = gtk_widget_get_window(m_widget);
-
-        if (source)
-        {
-            int org_x = 0;
-            int org_y = 0;
-            gdk_window_get_origin( source, &org_x, &org_y );
-
-            if (m_parent)
-                m_parent->ScreenToClient(&org_x, &org_y);
-
-            const_cast<wxWindowGTK*>(this)->m_x = org_x;
-            const_cast<wxWindowGTK*>(this)->m_y = org_y;
-        }
-    }
-
     if (x) (*x) = m_x - dx;
     if (y) (*y) = m_y - dy;
 }
@@ -3341,7 +3418,7 @@ bool wxWindowGTK::DoNavigateIn(int flags)
         gboolean rc;
         g_signal_emit_by_name(parent->m_widget, "focus", dir, &rc);
 
-        return rc == TRUE;
+        return rc != 0;
     }
 }
 
@@ -3505,11 +3582,13 @@ void wxWindowGTK::WarpPointer( int x, int y )
     GdkDeviceManager* manager = gdk_display_get_device_manager(display);
     gdk_device_warp(gdk_device_manager_get_client_pointer(manager), screen, x, y);
 #else
+#ifdef GDK_WINDOWING_X11
     XWarpPointer(GDK_DISPLAY_XDISPLAY(display),
         None,
         GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
         0, 0, 0, 0, x, y);
 #endif
+#endif
 }
 
 wxWindowGTK::ScrollDir wxWindowGTK::ScrollDirFromRange(GtkRange *range) const
@@ -3625,7 +3704,9 @@ void wxWindowGTK::GtkSendPaintEvents()
         m_updateRegion.Clear();
         return;
     }
-
+#if wxGTK_HAS_COMPOSITING_SUPPORT
+    cairo_t* cr = NULL;
+#endif
     // Clip to paint region in wxClientDC
     m_clipPaintRegion = true;
 
@@ -3657,6 +3738,27 @@ void wxWindowGTK::GtkSendPaintEvents()
 
     switch ( GetBackgroundStyle() )
     {
+        case wxBG_STYLE_TRANSPARENT:
+#if wxGTK_HAS_COMPOSITING_SUPPORT
+            if (IsTransparentBackgroundSupported())
+            {
+                // 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)
+                cr = gdk_cairo_create(m_wxwindow->window);
+                gdk_cairo_region(cr, m_nativeUpdateRegion.GetRegion());
+                cairo_clip(cr);
+
+                cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+                cairo_paint(cr);
+                cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+                cairo_surface_flush(cairo_get_target(cr));
+            }
+#endif // wxGTK_HAS_COMPOSITING_SUPPORT
+            break;
+
         case wxBG_STYLE_ERASE:
             {
                 wxWindowDC dc( (wxWindow*)this );
@@ -3733,6 +3835,39 @@ void wxWindowGTK::GtkSendPaintEvents()
     paint_event.SetEventObject( this );
     HandleWindowEvent( paint_event );
 
+#if wxGTK_HAS_COMPOSITING_SUPPORT
+    if (IsTransparentBackgroundSupported())
+    { // now composite children which need it
+        // 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)
+            {
+                if (cr == NULL)
+                {
+                    cr = gdk_cairo_create(m_wxwindow->window);
+                    gdk_cairo_region(cr, m_nativeUpdateRegion.GetRegion());
+                    cairo_clip(cr);
+                }
+
+                GtkWidget *child = compositeChild->m_wxwindow;
+                GtkAllocation alloc;
+                gtk_widget_get_allocation(child, &alloc);
+
+                // The source data is the (composited) child
+                gdk_cairo_set_source_window(
+                    cr, gtk_widget_get_window(child), alloc.x, alloc.y);
+
+                cairo_paint(cr);
+            }
+        }
+        if (cr)
+            cairo_destroy(cr);
+    }
+#endif // wxGTK_HAS_COMPOSITING_SUPPORT
+
     m_clipPaintRegion = false;
 
     m_updateRegion.Clear();
@@ -3749,7 +3884,7 @@ void wxWindowGTK::SetDoubleBuffered( bool on )
 
 bool wxWindowGTK::IsDoubleBuffered() const
 {
-    return gtk_widget_get_double_buffered( m_wxwindow );
+    return gtk_widget_get_double_buffered( m_wxwindow ) != 0;
 }
 
 void wxWindowGTK::ClearBackground()
@@ -3936,30 +4071,29 @@ 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 )
     {
-        GdkWindow *window;
-        if ( m_wxwindow )
-        {
-            window = GTKGetDrawingWindow();
-        }
-        else
-        {
-            GtkWidget * const w = GetConnectWidget();
-            window = w ? gtk_widget_get_window(w) : NULL;
-        }
+        window = GTKGetDrawingWindow();
+    }
+    else
+    {
+        GtkWidget * const w = GetConnectWidget();
+        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
             // automatically.
-            gdk_window_set_back_pixmap( window, None, False );
-#ifdef __X__
-            Display* display = GDK_WINDOW_DISPLAY(window);
-            XFlush(display);
-#endif
+            gdk_window_set_back_pixmap( window, NULL, FALSE );
             m_needsStyleChange = false;
         }
         else // window not realized yet
@@ -3980,6 +4114,49 @@ bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
     return true;
 }
 
+bool wxWindowGTK::IsTransparentBackgroundSupported(wxString* reason) const
+{
+#if wxGTK_HAS_COMPOSITING_SUPPORT
+    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;
+#else
+    if (reason)
+    {
+        *reason = _("This program was compiled with a too old version of GTK+, "
+                    "please rebuild with GTK+ 2.12 or newer.");
+    }
+
+    return false;
+#endif // wxGTK_HAS_COMPOSITING_SUPPORT/!wxGTK_HAS_COMPOSITING_SUPPORT
+}
+
 // ----------------------------------------------------------------------------
 // Pop-up menu stuff
 // ----------------------------------------------------------------------------
@@ -4012,14 +4189,6 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
 {
     wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
 
-    // For compatibility with other ports, pretend that the window showing the
-    // menu has focus while the menu is shown. This is needed because the popup
-    // menu actually steals the focus from the window it's associated it in
-    // wxGTK unlike, say, wxMSW.
-    wxWindowGTK* const oldPendingFocus = gs_pendingFocus;
-    gs_pendingFocus = this;
-    wxON_BLOCK_EXIT_SET( gs_pendingFocus, oldPendingFocus );
-
     menu->UpdateUI();
 
     wxPoint pos;
@@ -4372,12 +4541,6 @@ void wxWindowGTK::GTKScrolledWindowSetBorder(GtkWidget* w, int wxstyle)
     }
 }
 
-void wxWindowGTK::SetWindowStyleFlag( long style )
-{
-    // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
-    wxWindowBase::SetWindowStyleFlag(style);
-}
-
 // Find the wxWindow at the current mouse position, also returning the mouse
 // position.
 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
@@ -4390,31 +4553,18 @@ wxWindow* wxFindWindowAtPointer(wxPoint& pt)
 // Get the current mouse position.
 wxPoint wxGetMousePosition()
 {
-  /* This crashes when used within wxHelpContext,
-     so we have to use the X-specific implementation below.
-    gint x, y;
-    GdkModifierType *mask;
-    (void) gdk_window_get_pointer(NULL, &x, &y, mask);
-
-    return wxPoint(x, y);
-  */
+    wxWindow* tlw = NULL;
+    if (!wxTopLevelWindows.empty())
+        tlw = wxTopLevelWindows.front();
+    GdkDisplay* display;
+    if (tlw && tlw->m_widget)
+        display = gtk_widget_get_display(tlw->m_widget);
+    else
+        display = gdk_display_get_default();
 
     int x, y;
-    GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
-
-    Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
-    Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
-    Window rootReturn, childReturn;
-    int rootX, rootY, winX, winY;
-    unsigned int maskReturn;
-
-    XQueryPointer (display,
-           rootWindow,
-           &rootReturn,
-                   &childReturn,
-                   &rootX, &rootY, &winX, &winY, &maskReturn);
-    return wxPoint(rootX, rootY);
-
+    gdk_display_get_pointer(display, NULL, &x, &y, NULL);
+    return wxPoint(x, y);
 }
 
 GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const