]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
Add virtual ~wxAnyScrollHelperBase() to fix compiler warning.
[wxWidgets.git] / src / gtk / window.cpp
index eac2874bea98cec3f6042654be3a3b87fbc2ecc9..e163078b989251a04f9295da18a772df2652b60b 100644 (file)
@@ -2,7 +2,6 @@
 // Name:        src/gtk/window.cpp
 // Purpose:     wxWindowGTK implementation
 // Author:      Robert Roebling
 // Name:        src/gtk/window.cpp
 // Purpose:     wxWindowGTK implementation
 // Author:      Robert Roebling
-// Id:          $Id$
 // Copyright:   (c) 1998 Robert Roebling, Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 // Copyright:   (c) 1998 Robert Roebling, Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 #include "wx/caret.h"
 #include "wx/fontutil.h"
 #include "wx/sysopt.h"
 #include "wx/caret.h"
 #include "wx/fontutil.h"
 #include "wx/sysopt.h"
+#ifdef __WXGTK3__
+    #include "wx/gtk/dc.h"
+#endif
 
 #include <ctype.h>
 
 
 #include <ctype.h>
 
+#include <gtk/gtk.h>
 #include "wx/gtk/private.h"
 #include "wx/gtk/private.h"
+#include "wx/gtk/private/gtk2-compat.h"
+#include "wx/gtk/private/event.h"
 #include "wx/gtk/private/win_gtk.h"
 #include "wx/gtk/private/win_gtk.h"
-#include <gdk/gdkkeysyms.h>
+#include "wx/private/textmeasure.h"
+using namespace wxGTKImpl;
+
+#ifdef GDK_WINDOWING_X11
 #include <gdk/gdkx.h>
 #include <gdk/gdkx.h>
+#include "wx/x11/private/wrapxkb.h"
+#else
+typedef guint KeySym;
+#endif
 
 
-#if !GTK_CHECK_VERSION(2,10,0)
-    // GTK+ can reliably detect Meta key state only since 2.10 when
-    // GDK_META_MASK was introduced -- there wasn't any way to detect it
-    // in older versions. wxGTK used GDK_MOD2_MASK for this purpose, but
-    // GDK_MOD2_MASK is documented as:
-    //
-    //     the fifth modifier key (it depends on the modifier mapping of the X
-    //     server which key is interpreted as this modifier)
-    //
-    // In other words, it isn't guaranteed to map to Meta. This is a real
-    // problem: it is common to map NumLock to it (in fact, it's an exception
-    // if the X server _doesn't_ use it for NumLock).  So the old code caused
-    // wxKeyEvent::MetaDown() to always return true as long as NumLock was on
-    // on many systems, which broke all applications using
-    // wxKeyEvent::GetModifiers() to check modifiers state (see e.g.  here:
-    // http://tinyurl.com/56lsk2).
-    //
-    // Because of this, it's better to not detect Meta key state at all than
-    // to detect it incorrectly. Hence the following #define, which causes
-    // m_metaDown to be always set to false.
-    #define GDK_META_MASK 0
+#include <gdk/gdkkeysyms.h>
+#ifdef __WXGTK3__
+#include <gdk/gdkkeysyms-compat.h>
 #endif
 
 #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
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // documentation on internals
 //-----------------------------------------------------------------------------
 
    Cursors, too, have been a constant source of pleasure. The main difficulty
    is that a GdkWindow inherits a cursor if the programmer sets a new cursor
 
    Cursors, too, have been a constant source of pleasure. The main difficulty
    is that a GdkWindow inherits a cursor if the programmer sets a new cursor
-   for the parent. To prevent this from doing too much harm, I use idle time
-   to set the cursor over and over again, starting from the toplevel windows
-   and ending with the youngest generation (speaking of parent and child windows).
+   for the parent. To prevent this from doing too much harm, SetCursor calls
+   GTKUpdateCursor, which will recursively re-set the cursors of all child windows.
    Also don't forget that cursors (like much else) are connected to GdkWindows,
    not GtkWidgets and that the "window" field of a GtkWidget might very well
    point to the GdkWindow of the parent widget (-> "window-less widget") and
    that the two obviously have very different meanings.
    Also don't forget that cursors (like much else) are connected to GdkWindows,
    not GtkWidgets and that the "window" field of a GtkWidget might very well
    point to the GdkWindow of the parent widget (-> "window-less widget") and
    that the two obviously have very different meanings.
-
 */
 
 //-----------------------------------------------------------------------------
 */
 
 //-----------------------------------------------------------------------------
@@ -228,86 +224,68 @@ int          g_lastButtonNumber = 0;
 //-----------------------------------------------------------------------------
 
 // the trace mask used for the focus debugging messages
 //-----------------------------------------------------------------------------
 
 // the trace mask used for the focus debugging messages
-#define TRACE_FOCUS _T("focus")
-
-//-----------------------------------------------------------------------------
-// missing gdk functions
-//-----------------------------------------------------------------------------
+#define TRACE_FOCUS wxT("focus")
 
 
-void
-gdk_window_warp_pointer (GdkWindow      *window,
-                         gint            x,
-                         gint            y)
+// A handy function to run from under gdb to show information about the given
+// GtkWidget. Right now it only shows its type, we could enhance it to show
+// more information later but this is already pretty useful.
+const char* wxDumpGtkWidget(GtkWidget* w)
 {
 {
-  if (!window)
-    window = gdk_get_default_root_window();
+    static wxString s;
+    s.Printf("GtkWidget %p, type \"%s\"", w, G_OBJECT_TYPE_NAME(w));
 
 
-  if (!GDK_WINDOW_DESTROYED(window))
-  {
-      XWarpPointer (GDK_WINDOW_XDISPLAY(window),
-                    None,              /* not source window -> move from anywhere */
-                    GDK_WINDOW_XID(window),  /* dest window */
-                    0, 0, 0, 0,        /* not source window -> move from anywhere */
-                    x, y );
-  }
+    return s.c_str();
 }
 
 }
 
-
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-// "size_request" of m_widget
+// "expose_event"/"draw" from m_wxwindow
 //-----------------------------------------------------------------------------
 
 extern "C" {
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static void
-wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
-                                   GtkRequisition *requisition,
-                                   wxWindow * win)
+#ifdef __WXGTK3__
+static gboolean draw(GtkWidget*, cairo_t* cr, wxWindow* win)
 {
 {
-    int w, h;
-    win->GetSize( &w, &h );
-    if (w < 2)
-        w = 2;
-    if (h < 2)
-        h = 2;
+    if (gtk_cairo_should_draw_window(cr, win->GTKGetDrawingWindow()))
+        win->GTKSendPaintEvents(cr);
 
 
-    requisition->height = h;
-    requisition->width = w;
-}
+    return false;
 }
 }
-
-//-----------------------------------------------------------------------------
-// "expose_event" of m_wxwindow
-//-----------------------------------------------------------------------------
-
-extern "C" {
-static gboolean
-gtk_window_expose_callback( GtkWidget* widget,
-                            GdkEventExpose *gdk_event,
-                            wxWindow *win )
+#else // !__WXGTK3__
+static gboolean expose_event(GtkWidget*, GdkEventExpose* gdk_event, wxWindow* win)
 {
 {
-    if (gdk_event->window == widget->window)
-    {
-        win->GetUpdateRegion() = wxRegion( gdk_event->region );
-        win->GtkSendPaintEvents();
-    }
-    // Let parent window draw window-less widgets
-    return FALSE;
+    if (gdk_event->window == win->GTKGetDrawingWindow())
+        win->GTKSendPaintEvents(gdk_event->region);
+
+    return false;
 }
 }
+#endif // !__WXGTK3__
 }
 
 #ifndef __WXUNIVERSAL__
 //-----------------------------------------------------------------------------
 }
 
 #ifndef __WXUNIVERSAL__
 //-----------------------------------------------------------------------------
-// "expose_event" from m_wxwindow->parent, for drawing border
+// "expose_event"/"draw" from m_wxwindow->parent, for drawing border
 //-----------------------------------------------------------------------------
 
 extern "C" {
 static gboolean
 //-----------------------------------------------------------------------------
 
 extern "C" {
 static gboolean
-expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
+#ifdef __WXGTK3__
+draw_border(GtkWidget*, cairo_t* cr, wxWindow* win)
+#else
+draw_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
+#endif
 {
 {
-    if (gdk_event->window != widget->window)
+#ifdef __WXGTK3__
+    if (!gtk_cairo_should_draw_window(cr, gtk_widget_get_parent_window(win->m_wxwindow)))
+#else
+    if (gdk_event->window != gtk_widget_get_parent_window(win->m_wxwindow))
+#endif
+        return false;
+
+    if (!win->IsShown())
         return false;
 
         return false;
 
-    const GtkAllocation& alloc = win->m_wxwindow->allocation;
+    GtkAllocation alloc;
+    gtk_widget_get_allocation(win->m_wxwindow, &alloc);
     const int x = alloc.x;
     const int y = alloc.y;
     const int w = alloc.width;
     const int x = alloc.x;
     const int y = alloc.y;
     const int w = alloc.width;
@@ -318,27 +296,55 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
 
     if (win->HasFlag(wxBORDER_SIMPLE))
     {
 
     if (win->HasFlag(wxBORDER_SIMPLE))
     {
+#ifdef __WXGTK3__
+        GtkStyleContext* sc = gtk_widget_get_style_context(win->m_wxwindow);
+        GdkRGBA c;
+        gtk_style_context_get_border_color(sc, GTK_STATE_FLAG_NORMAL, &c);
+        gdk_cairo_set_source_rgba(cr, &c);
+        cairo_set_line_width(cr, 1);
+        cairo_rectangle(cr, x + 0.5, y + 0.5, w - 1, h - 1);
+        cairo_stroke(cr);
+#else
         gdk_draw_rectangle(gdk_event->window,
         gdk_draw_rectangle(gdk_event->window,
-            widget->style->black_gc, false, x, y, w - 1, h - 1);
+            gtk_widget_get_style(widget)->black_gc, false, x, y, w - 1, h - 1);
+#endif
     }
     }
-    else
+    else if (win->HasFlag(wxBORDER_RAISED | wxBORDER_SUNKEN | wxBORDER_THEME))
     {
     {
+#ifdef __WXGTK3__
+        //TODO: wxBORDER_RAISED/wxBORDER_SUNKEN
+        GtkStyleContext* sc;
+        if (win->HasFlag(wxHSCROLL | wxVSCROLL))
+            sc = gtk_widget_get_style_context(wxGTKPrivate::GetTreeWidget());
+        else
+            sc = gtk_widget_get_style_context(wxGTKPrivate::GetEntryWidget());
+
+        gtk_render_frame(sc, cr, x, y, w, h);
+#else // !__WXGTK3__
         GtkShadowType shadow = GTK_SHADOW_IN;
         if (win->HasFlag(wxBORDER_RAISED))
             shadow = GTK_SHADOW_OUT;
 
         GtkShadowType shadow = GTK_SHADOW_IN;
         if (win->HasFlag(wxBORDER_RAISED))
             shadow = GTK_SHADOW_OUT;
 
-        // Style detail to use
+        GtkStyle* style;
         const char* detail;
         const char* detail;
-        if (win->m_widget == win->m_wxwindow)
-            // for non-scrollable wxWindows
-            detail = "entry";
-        else
-            // for scrollable ones
+        if (win->HasFlag(wxHSCROLL | wxVSCROLL))
+        {
+            style = gtk_widget_get_style(wxGTKPrivate::GetTreeWidget());
             detail = "viewport";
             detail = "viewport";
+        }
+        else
+        {
+            style = gtk_widget_get_style(wxGTKPrivate::GetEntryWidget());
+            detail = "entry";
+        }
 
 
+        // clip rect is required to avoid painting background
+        // over upper left (w,h) of parent window
+        GdkRectangle clipRect = { x, y, w, h };
         gtk_paint_shadow(
         gtk_paint_shadow(
-           win->m_wxwindow->style, gdk_event->window, GTK_STATE_NORMAL,
-           shadow, NULL, wxGTKPrivate::GetEntryWidget(), detail, x, y, w, h);
+           style, gdk_event->window, GTK_STATE_NORMAL,
+           shadow, &clipRect, widget, detail, x, y, w, h);
+#endif // !__WXGTK3__
     }
     return false;
 }
     }
     return false;
 }
@@ -350,17 +356,21 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
 
 extern "C" {
 static void
 
 extern "C" {
 static void
-parent_set(GtkWidget* widget, GtkObject* old_parent, wxWindow* win)
+parent_set(GtkWidget* widget, GtkWidget* old_parent, wxWindow* win)
 {
     if (old_parent)
     {
         g_signal_handlers_disconnect_by_func(
 {
     if (old_parent)
     {
         g_signal_handlers_disconnect_by_func(
-            old_parent, (void*)expose_event_border, win);
+            old_parent, (void*)draw_border, win);
     }
     }
-    if (widget->parent)
+    GtkWidget* parent = gtk_widget_get_parent(widget);
+    if (parent)
     {
     {
-        g_signal_connect_after(widget->parent, "expose_event",
-            G_CALLBACK(expose_event_border), win);
+#ifdef __WXGTK3__
+        g_signal_connect_after(parent, "draw", G_CALLBACK(draw_border), win);
+#else
+        g_signal_connect_after(parent, "expose_event", G_CALLBACK(draw_border), win);
+#endif
     }
 }
 }
     }
 }
 }
@@ -370,20 +380,8 @@ parent_set(GtkWidget* widget, GtkObject* old_parent, wxWindow* win)
 // "key_press_event" from any window
 //-----------------------------------------------------------------------------
 
 // "key_press_event" from any window
 //-----------------------------------------------------------------------------
 
-// These are used when transforming Ctrl-alpha to ascii values 1-26
-inline bool wxIsLowerChar(int code)
-{
-    return (code >= 'a' && code <= 'z' );
-}
-
-inline bool wxIsUpperChar(int code)
-{
-    return (code >= 'A' && code <= 'Z' );
-}
-
-
 // set WXTRACE to this to see the key event codes on the console
 // set WXTRACE to this to see the key event codes on the console
-#define TRACE_KEYS  _T("keyevent")
+#define TRACE_KEYS  wxT("keyevent")
 
 // translates an X key symbol to WXK_XXX value
 //
 
 // translates an X key symbol to WXK_XXX value
 //
@@ -671,27 +669,69 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event,
                                       wxWindowGTK *win,
                                       GdkEventKey *gdk_event)
 {
                                       wxWindowGTK *win,
                                       GdkEventKey *gdk_event)
 {
-    int x = 0;
-    int y = 0;
-    GdkModifierType state;
-    if (gdk_event->window)
-        gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
-
     event.SetTimestamp( gdk_event->time );
     event.SetId(win->GetId());
     event.SetTimestamp( gdk_event->time );
     event.SetId(win->GetId());
+
     event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
     event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
     event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
     event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0;
     event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
     event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
     event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
     event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0;
+
+    // At least with current Linux systems, MOD5 corresponds to AltGr key and
+    // we represent it, for consistency with Windows, which really allows to
+    // use Ctrl+Alt as a replacement for AltGr if this key is not present, as a
+    // combination of these two modifiers.
+    if ( gdk_event->state & GDK_MOD5_MASK )
+    {
+        event.m_controlDown =
+        event.m_altDown = true;
+    }
+
+    // Normally we take the state of modifiers directly from the low level GDK
+    // event but unfortunately GDK uses a different convention from MSW for the
+    // key events corresponding to the modifier keys themselves: in it, when
+    // e.g. Shift key is pressed, GDK_SHIFT_MASK is not set while it is set
+    // when Shift is released. Under MSW the situation is exactly reversed and
+    // the modifier corresponding to the key is set when it is pressed and
+    // unset when it is released. To ensure consistent behaviour between
+    // platforms (and because it seems to make slightly more sense, although
+    // arguably both behaviours are reasonable) we follow MSW here.
+    //
+    // Final notice: we set the flags to the desired value instead of just
+    // inverting them because they are not set correctly (i.e. in the same way
+    // as for the real events generated by the user) for wxUIActionSimulator-
+    // produced events and it seems better to keep that class code the same
+    // among all platforms and fix the discrepancy here instead of adding
+    // wxGTK-specific code to wxUIActionSimulator.
+    const bool isPress = gdk_event->type == GDK_KEY_PRESS;
+    switch ( gdk_event->keyval )
+    {
+        case GDK_Shift_L:
+        case GDK_Shift_R:
+            event.m_shiftDown = isPress;
+            break;
+
+        case GDK_Control_L:
+        case GDK_Control_R:
+            event.m_controlDown = isPress;
+            break;
+
+        case GDK_Alt_L:
+        case GDK_Alt_R:
+            event.m_altDown = isPress;
+            break;
+
+        case GDK_Meta_L:
+        case GDK_Meta_R:
+        case GDK_Super_L:
+        case GDK_Super_R:
+            event.m_metaDown = isPress;
+            break;
+    }
+
     event.m_rawCode = (wxUint32) gdk_event->keyval;
     event.m_rawCode = (wxUint32) gdk_event->keyval;
-    event.m_rawFlags = 0;
-#if wxUSE_UNICODE
-    event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
-#endif
-    wxGetMousePosition( &x, &y );
-    win->ScreenToClient( &x, &y );
-    event.m_x = x;
-    event.m_y = y;
+    event.m_rawFlags = gdk_event->hardware_keycode;
+
     event.SetEventObject( win );
 }
 
     event.SetEventObject( win );
 }
 
@@ -714,10 +754,10 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
 
     KeySym keysym = gdk_event->keyval;
 
 
     KeySym keysym = gdk_event->keyval;
 
-    wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
-               event.GetEventType() == wxEVT_KEY_UP ? _T("release")
-                                                    : _T("press"),
-               keysym);
+    wxLogTrace(TRACE_KEYS, wxT("Key %s event: keysym = %lu"),
+               event.GetEventType() == wxEVT_KEY_UP ? wxT("release")
+                                                    : wxT("press"),
+               static_cast<unsigned long>(keysym));
 
     long key_code = wxTranslateKeySymToWXKey(keysym, false /* !isChar */);
 
 
     long key_code = wxTranslateKeySymToWXKey(keysym, false /* !isChar */);
 
@@ -734,6 +774,7 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
                 keysym = (KeySym)gdk_event->string[0];
             }
 
                 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
             // 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
@@ -745,13 +786,20 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
             Display *dpy = (Display *)wxGetDisplay();
             KeyCode keycode = XKeysymToKeycode(dpy, keysym);
 
             Display *dpy = (Display *)wxGetDisplay();
             KeyCode keycode = XKeysymToKeycode(dpy, keysym);
 
-            wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
+            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);
             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;
 
             // 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
 
             // as explained above, we want to have lower register key codes
             // normally but for the letter keys we want to have the upper ones
@@ -784,42 +832,101 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
         }
     }
 
         }
     }
 
-    wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
+    wxLogTrace(TRACE_KEYS, wxT("\t-> wxKeyCode %ld"), key_code);
 
     // sending unknown key events doesn't really make sense
     if ( !key_code )
         return false;
 
 
     // sending unknown key events doesn't really make sense
     if ( !key_code )
         return false;
 
-    // now fill all the other fields
-    wxFillOtherKeyEventFields(event, win, gdk_event);
-
     event.m_keyCode = key_code;
     event.m_keyCode = key_code;
+
 #if wxUSE_UNICODE
 #if wxUSE_UNICODE
-    if ( gdk_event->type == GDK_KEY_PRESS ||  gdk_event->type == GDK_KEY_RELEASE )
+    event.m_uniChar = gdk_keyval_to_unicode(key_code);
+    if ( !event.m_uniChar && event.m_keyCode <= WXK_DELETE )
     {
     {
-        event.m_uniChar = key_code;
+        // Set Unicode key code to the ASCII equivalent for compatibility. E.g.
+        // let RETURN generate the key event with both key and Unicode key
+        // codes of 13.
+        event.m_uniChar = event.m_keyCode;
     }
     }
-#endif
+#endif // wxUSE_UNICODE
+
+    // now fill all the other fields
+    wxFillOtherKeyEventFields(event, win, gdk_event);
 
     return true;
 }
 
 
 
     return true;
 }
 
 
-struct wxGtkIMData
+namespace
 {
 {
-    GtkIMContext *context;
-    GdkEventKey  *lastKeyEvent;
 
 
-    wxGtkIMData()
+// Send wxEVT_CHAR_HOOK event to the parent of the window and return true only
+// if it was processed (and not skipped).
+bool SendCharHookEvent(const wxKeyEvent& event, wxWindow *win)
+{
+    // wxEVT_CHAR_HOOK must be sent to allow the parent windows (e.g. a dialog
+    // which typically closes when Esc key is pressed in any of its controls)
+    // to handle key events in all of its children unless the mouse is captured
+    // in which case we consider that the keyboard should be "captured" too.
+    if ( !g_captureWindow )
     {
     {
-        context = gtk_im_multicontext_new();
-        lastKeyEvent = NULL;
+        wxKeyEvent eventCharHook(wxEVT_CHAR_HOOK, event);
+        if ( win->HandleWindowEvent(eventCharHook)
+                && !event.IsNextEventAllowed() )
+            return true;
     }
     }
-    ~wxGtkIMData()
+
+    return false;
+}
+
+// Adjust wxEVT_CHAR event key code fields. This function takes care of two
+// conventions:
+// (a) Ctrl-letter key presses generate key codes in range 1..26
+// (b) Unicode key codes are same as key codes for the codes in 1..255 range
+void AdjustCharEventKeyCodes(wxKeyEvent& event)
+{
+    const int code = event.m_keyCode;
+
+    // Check for (a) above.
+    if ( event.ControlDown() )
     {
     {
-        g_object_unref (context);
+        // We intentionally don't use isupper/lower() here, we really need
+        // ASCII letters only as it doesn't make sense to translate any other
+        // ones into this range which has only 26 slots.
+        if ( code >= 'a' && code <= 'z' )
+            event.m_keyCode = code - 'a' + 1;
+        else if ( code >= 'A' && code <= 'Z' )
+            event.m_keyCode = code - 'A' + 1;
+
+#if wxUSE_UNICODE
+        // Adjust the Unicode equivalent in the same way too.
+        if ( event.m_keyCode != code )
+            event.m_uniChar = event.m_keyCode;
+#endif // wxUSE_UNICODE
     }
     }
-};
+
+#if wxUSE_UNICODE
+    // Check for (b) from above.
+    //
+    // FIXME: Should we do it for key codes up to 255?
+    if ( !event.m_uniChar && code < WXK_DELETE )
+        event.m_uniChar = code;
+#endif // wxUSE_UNICODE
+}
+
+} // 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
 
 extern "C" {
 static gboolean
@@ -827,54 +934,33 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
                                GdkEventKey *gdk_event,
                                wxWindow *win )
 {
                                GdkEventKey *gdk_event,
                                wxWindow *win )
 {
-    if (!win->m_hasVMT)
-        return FALSE;
     if (g_blockEventsOnDrag)
         return FALSE;
 
     if (g_blockEventsOnDrag)
         return FALSE;
 
+    wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event);
+
     wxKeyEvent event( wxEVT_KEY_DOWN );
     bool ret = false;
     bool return_after_IM = false;
 
     if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
     {
     wxKeyEvent event( wxEVT_KEY_DOWN );
     bool ret = false;
     bool return_after_IM = false;
 
     if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
     {
-        // Emit KEY_DOWN event
-        ret = win->HandleWindowEvent( event );
-    }
-    else
-    {
-        // Return after IM processing as we cannot do
-        // anything with it anyhow.
-        return_after_IM = true;
-    }
-
-    if ((!ret) && (win->m_imData != NULL))
-    {
-        // 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);
-        win->m_imData->lastKeyEvent = NULL;
-        if (intercepted_by_IM)
+        // Send the CHAR_HOOK event first
+        if ( SendCharHookEvent(event, win) )
         {
         {
-            wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
+            // Don't do anything at all with this event any more.
             return TRUE;
         }
             return TRUE;
         }
-    }
-
-    if (return_after_IM)
-        return FALSE;
 
 
+        // Next check for accelerators.
 #if wxUSE_ACCEL
 #if wxUSE_ACCEL
-    if (!ret)
-    {
         wxWindowGTK *ancestor = win;
         while (ancestor)
         {
             int command = ancestor->GetAcceleratorTable()->GetCommand( event );
             if (command != -1)
             {
         wxWindowGTK *ancestor = win;
         while (ancestor)
         {
             int command = ancestor->GetAcceleratorTable()->GetCommand( event );
             if (command != -1)
             {
-                wxCommandEvent menu_event( wxEVT_COMMAND_MENU_SELECTED, command );
+                wxCommandEvent menu_event( wxEVT_MENU, command );
                 ret = ancestor->HandleWindowEvent( menu_event );
 
                 if ( !ret )
                 ret = ancestor->HandleWindowEvent( menu_event );
 
                 if ( !ret )
@@ -882,7 +968,7 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
                     // if the accelerator wasn't handled as menu event, try
                     // it as button click (for compatibility with other
                     // platforms):
                     // if the accelerator wasn't handled as menu event, try
                     // it as button click (for compatibility with other
                     // platforms):
-                    wxCommandEvent button_event( wxEVT_COMMAND_BUTTON_CLICKED, command );
+                    wxCommandEvent button_event( wxEVT_BUTTON, command );
                     ret = ancestor->HandleWindowEvent( button_event );
                 }
 
                     ret = ancestor->HandleWindowEvent( button_event );
                 }
 
@@ -892,17 +978,50 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
                 break;
             ancestor = ancestor->GetParent();
         }
                 break;
             ancestor = ancestor->GetParent();
         }
-    }
 #endif // wxUSE_ACCEL
 
 #endif // wxUSE_ACCEL
 
+        // If not an accelerator, then emit KEY_DOWN event
+        if ( !ret )
+            ret = win->HandleWindowEvent( event );
+    }
+    else
+    {
+        // Return after IM processing as we cannot do
+        // anything with it anyhow.
+        return_after_IM = true;
+    }
+
+    if ( !ret )
+    {
+        // Indicate that IM handling is in process by setting this pointer
+        // (which will remain valid for all the code called during IM key
+        // handling).
+        win->m_imKeyEvent = gdk_event;
+
+        // 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.
+        const int intercepted_by_IM = win->GTKIMFilterKeypress(gdk_event);
+
+        win->m_imKeyEvent = NULL;
+
+        if ( intercepted_by_IM )
+        {
+            wxLogTrace(TRACE_KEYS, wxT("Key event intercepted by IM"));
+            return TRUE;
+        }
+    }
+
+    if (return_after_IM)
+        return FALSE;
+
     // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
     // will only be sent if it is not in an accelerator table.
     if (!ret)
     {
     // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
     // will only be sent if it is not in an accelerator table.
     if (!ret)
     {
-        long key_code;
         KeySym keysym = gdk_event->keyval;
         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
         KeySym keysym = gdk_event->keyval;
         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
-        key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
+        long key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
         if ( !key_code )
         {
             if ( wxIsAsciiKeysym(keysym) )
         if ( !key_code )
         {
             if ( wxIsAsciiKeysym(keysym) )
@@ -919,39 +1038,18 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
 
         if ( key_code )
         {
 
         if ( key_code )
         {
-            wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
+            wxKeyEvent eventChar(wxEVT_CHAR, event);
 
 
-            event.m_keyCode = key_code;
+            wxLogTrace(TRACE_KEYS, wxT("Char event: %ld"), key_code);
 
 
-            // To conform to the docs we need to translate Ctrl-alpha
-            // characters to values in the range 1-26.
-            if ( event.ControlDown() &&
-                 ( wxIsLowerChar(key_code) || wxIsUpperChar(key_code) ))
-            {
-                if ( wxIsLowerChar(key_code) )
-                    event.m_keyCode = key_code - 'a' + 1;
-                if ( wxIsUpperChar(key_code) )
-                    event.m_keyCode = key_code - 'A' + 1;
+            eventChar.m_keyCode = key_code;
 #if wxUSE_UNICODE
 #if wxUSE_UNICODE
-                event.m_uniChar = event.m_keyCode;
-#endif
-            }
+            eventChar.m_uniChar = gdk_keyval_to_unicode(key_code);
+#endif // wxUSE_UNICODE
 
 
-            // Implement OnCharHook by checking ancestor top level windows
-            wxWindow *parent = win;
-            while (parent && !parent->IsTopLevel())
-                parent = parent->GetParent();
-            if (parent)
-            {
-                event.SetEventType( wxEVT_CHAR_HOOK );
-                ret = parent->HandleWindowEvent( event );
-            }
+            AdjustCharEventKeyCodes(eventChar);
 
 
-            if (!ret)
-            {
-                event.SetEventType(wxEVT_CHAR);
-                ret = win->HandleWindowEvent( event );
-            }
+            ret = win->HandleWindowEvent(eventChar);
         }
     }
 
         }
     }
 
@@ -959,77 +1057,72 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
 }
 }
 
 }
 }
 
+int wxWindowGTK::GTKIMFilterKeypress(GdkEventKey* event) const
+{
+    return m_imContext ? gtk_im_context_filter_keypress(m_imContext, event)
+                       : FALSE;
+}
+
 extern "C" {
 static void
 gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context),
                         const gchar  *str,
                         wxWindow     *window)
 {
 extern "C" {
 static void
 gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context),
                         const gchar  *str,
                         wxWindow     *window)
 {
-    wxKeyEvent event( wxEVT_KEY_DOWN );
+    // Ignore the return value here, it doesn't matter for the "commit" signal.
+    window->GTKDoInsertTextFromIM(str);
+}
+}
+
+bool wxWindowGTK::GTKDoInsertTextFromIM(const char* str)
+{
+    wxKeyEvent event( wxEVT_CHAR );
 
     // take modifiers, cursor position, timestamp etc. from the last
     // key_press_event that was fed into Input Method:
 
     // take modifiers, cursor position, timestamp etc. from the last
     // key_press_event that was fed into Input Method:
-    if (window->m_imData->lastKeyEvent)
+    if ( m_imKeyEvent )
     {
     {
-        wxFillOtherKeyEventFields(event,
-                                  window, window->m_imData->lastKeyEvent);
+        wxFillOtherKeyEventFields(event, this, m_imKeyEvent);
     }
     else
     {
     }
     else
     {
-        event.SetEventObject( window );
+        event.SetEventObject(this);
     }
 
     const wxString data(wxGTK_CONV_BACK_SYS(str));
     if( data.empty() )
     }
 
     const wxString data(wxGTK_CONV_BACK_SYS(str));
     if( data.empty() )
-        return;
-
-    bool ret = false;
-
-    // Implement OnCharHook by checking ancestor top level windows
-    wxWindow *parent = window;
-    while (parent && !parent->IsTopLevel())
-        parent = parent->GetParent();
+        return false;
 
 
+    bool processed = false;
     for( wxString::const_iterator pstr = data.begin(); pstr != data.end(); ++pstr )
     {
 #if wxUSE_UNICODE
         event.m_uniChar = *pstr;
         // Backward compatible for ISO-8859-1
         event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
     for( wxString::const_iterator pstr = data.begin(); pstr != data.end(); ++pstr )
     {
 #if wxUSE_UNICODE
         event.m_uniChar = *pstr;
         // Backward compatible for ISO-8859-1
         event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
-        wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
+        wxLogTrace(TRACE_KEYS, wxT("IM sent character '%c'"), event.m_uniChar);
 #else
         event.m_keyCode = (char)*pstr;
 #endif  // wxUSE_UNICODE
 
 #else
         event.m_keyCode = (char)*pstr;
 #endif  // wxUSE_UNICODE
 
-        // To conform to the docs we need to translate Ctrl-alpha
-        // characters to values in the range 1-26.
-        if ( event.ControlDown() &&
-             ( wxIsLowerChar(*pstr) || wxIsUpperChar(*pstr) ))
-        {
-            if ( wxIsLowerChar(*pstr) )
-                event.m_keyCode = *pstr - 'a' + 1;
-            if ( wxIsUpperChar(*pstr) )
-                event.m_keyCode = *pstr - 'A' + 1;
+        AdjustCharEventKeyCodes(event);
 
 
-            event.m_keyCode = *pstr - 'a' + 1;
-#if wxUSE_UNICODE
-            event.m_uniChar = event.m_keyCode;
-#endif
-        }
+        if ( HandleWindowEvent(event) )
+            processed = true;
+    }
 
 
-        if (parent)
-        {
-            event.SetEventType( wxEVT_CHAR_HOOK );
-            ret = parent->HandleWindowEvent( event );
-        }
+    return processed;
+}
 
 
-        if (!ret)
-        {
-            event.SetEventType(wxEVT_CHAR);
-            ret = window->HandleWindowEvent( event );
-        }
+bool wxWindowGTK::GTKOnInsertText(const char* text)
+{
+    if ( !m_imKeyEvent )
+    {
+        // We're not inside IM key handling at all.
+        return false;
     }
     }
-}
+
+    return GTKDoInsertTextFromIM(text);
 }
 
 
 }
 
 
@@ -1043,12 +1136,11 @@ gtk_window_key_release_callback( GtkWidget * WXUNUSED(widget),
                                  GdkEventKey *gdk_event,
                                  wxWindowGTK *win )
 {
                                  GdkEventKey *gdk_event,
                                  wxWindowGTK *win )
 {
-    if (!win->m_hasVMT)
-        return FALSE;
-
     if (g_blockEventsOnDrag)
         return FALSE;
 
     if (g_blockEventsOnDrag)
         return FALSE;
 
+    wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event);
+
     wxKeyEvent event( wxEVT_KEY_UP );
     if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
     {
     wxKeyEvent event( wxEVT_KEY_UP );
     if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
     {
@@ -1068,38 +1160,6 @@ gtk_window_key_release_callback( GtkWidget * WXUNUSED(widget),
 // mouse event processing helpers
 // ----------------------------------------------------------------------------
 
 // mouse event processing helpers
 // ----------------------------------------------------------------------------
 
-// init wxMouseEvent with the info from GdkEventXXX struct
-template<typename T> void InitMouseEvent(wxWindowGTK *win,
-                                         wxMouseEvent& event,
-                                         T *gdk_event)
-{
-    event.SetTimestamp( gdk_event->time );
-    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
-    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
-    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
-    event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0;
-    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK) != 0;
-    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK) != 0;
-    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK) != 0;
-    event.m_aux1Down = (gdk_event->state & GDK_BUTTON4_MASK) != 0;
-    event.m_aux2Down = (gdk_event->state & GDK_BUTTON5_MASK) != 0;
-
-    wxPoint pt = win->GetClientAreaOrigin();
-    event.m_x = (wxCoord)gdk_event->x - pt.x;
-    event.m_y = (wxCoord)gdk_event->y - pt.y;
-
-    if ((win->m_wxwindow) && (win->GetLayoutDirection() == wxLayout_RightToLeft))
-    {
-        // origin in the upper right corner
-        int window_width = win->m_wxwindow->allocation.width;
-        event.m_x = window_width - event.m_x;
-    }
-
-    event.SetEventObject( win );
-    event.SetId( win->GetId() );
-    event.SetTimestamp( gdk_event->time );
-}
-
 static void AdjustEventButtonState(wxMouseEvent& event)
 {
     // GDK reports the old state of the button for a button press event, but
 static void AdjustEventButtonState(wxMouseEvent& event)
 {
     // GDK reports the old state of the button for a button press event, but
@@ -1130,9 +1190,23 @@ static void AdjustEventButtonState(wxMouseEvent& event)
         event.m_rightDown = !event.m_rightDown;
         return;
     }
         event.m_rightDown = !event.m_rightDown;
         return;
     }
+
+    if ((event.GetEventType() == wxEVT_AUX1_DOWN) ||
+        (event.GetEventType() == wxEVT_AUX1_DCLICK))
+    {
+        event.m_aux1Down = true;
+        return;
+    }
+
+    if ((event.GetEventType() == wxEVT_AUX2_DOWN) ||
+        (event.GetEventType() == wxEVT_AUX2_DCLICK))
+    {
+        event.m_aux2Down = true;
+        return;
+    }
 }
 
 }
 
-// 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)
 {
 static
 wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
 {
@@ -1149,7 +1223,7 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
     wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
     while (node)
     {
     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())
 
         node = node->GetNext();
         if (!child->IsShown())
@@ -1182,6 +1256,7 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
         else
         {
             if ((child->m_wxwindow == NULL) &&
         else
         {
             if ((child->m_wxwindow == NULL) &&
+                win->IsClientAreaChild(child) &&
                 (child->m_x <= xx) &&
                 (child->m_y <= yy) &&
                 (child->m_x+child->m_width  >= xx) &&
                 (child->m_x <= xx) &&
                 (child->m_y <= yy) &&
                 (child->m_x+child->m_width  >= xx) &&
@@ -1208,10 +1283,13 @@ bool wxWindowGTK::GTKProcessEvent(wxEvent& event) const
     return HandleWindowEvent(event);
 }
 
     return HandleWindowEvent(event);
 }
 
+bool wxWindowGTK::GTKShouldIgnoreEvent() const
+{
+    return g_blockEventsOnDrag;
+}
+
 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const
 {
 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const
 {
-    if (!m_hasVMT)
-        return FALSE;
     if (g_blockEventsOnDrag)
         return TRUE;
     if (g_blockEventsOnScroll)
     if (g_blockEventsOnDrag)
         return TRUE;
     if (g_blockEventsOnScroll)
@@ -1252,118 +1330,95 @@ extern "C"
 //-----------------------------------------------------------------------------
 
 static gboolean
 //-----------------------------------------------------------------------------
 
 static gboolean
-gtk_window_button_press_callback( GtkWidget *widget,
+gtk_window_button_press_callback( GtkWidget* WXUNUSED_IN_GTK3(widget),
                                   GdkEventButton *gdk_event,
                                   wxWindowGTK *win )
 {
                                   GdkEventButton *gdk_event,
                                   wxWindowGTK *win )
 {
+    wxPROCESS_EVENT_ONCE(GdkEventButton, gdk_event);
+
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     g_lastButtonNumber = gdk_event->button;
 
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     g_lastButtonNumber = gdk_event->button;
 
-    // GDK sends surplus button down events
-    // before a double click event. We
-    // need to filter these out.
-    if ((gdk_event->type == GDK_BUTTON_PRESS) && (win->m_wxwindow))
+    wxEventType event_type;
+    wxEventType down;
+    wxEventType dclick;
+    switch (gdk_event->button)
     {
     {
-        GdkEvent *peek_event = gdk_event_peek();
-        if (peek_event)
-        {
-            if ((peek_event->type == GDK_2BUTTON_PRESS) ||
-                (peek_event->type == GDK_3BUTTON_PRESS))
+        case 1:
+            down = wxEVT_LEFT_DOWN;
+            dclick = wxEVT_LEFT_DCLICK;
+            break;
+        case 2:
+            down = wxEVT_MIDDLE_DOWN;
+            dclick = wxEVT_MIDDLE_DCLICK;
+            break;
+        case 3:
+            down = wxEVT_RIGHT_DOWN;
+            dclick = wxEVT_RIGHT_DCLICK;
+            break;
+        case 8:
+            down = wxEVT_AUX1_DOWN;
+            dclick = wxEVT_AUX1_DCLICK;
+            break;
+        case 9:
+            down = wxEVT_AUX2_DOWN;
+            dclick = wxEVT_AUX2_DCLICK;
+            break;
+        default:
+            return false;
+    }
+    switch (gdk_event->type)
+    {
+        case GDK_BUTTON_PRESS:
+            event_type = down;
+            // GDK sends surplus button down events
+            // before a double click event. We
+            // need to filter these out.
+            if (win->m_wxwindow)
             {
             {
-                gdk_event_free( peek_event );
-                return TRUE;
+                GdkEvent* peek_event = gdk_event_peek();
+                if (peek_event)
+                {
+                    const GdkEventType peek_event_type = peek_event->type;
+                    gdk_event_free(peek_event);
+                    if (peek_event_type == GDK_2BUTTON_PRESS ||
+                        peek_event_type == GDK_3BUTTON_PRESS)
+                    {
+                        return true;
+                    }
+                }
             }
             }
-            else
+            break;
+        case GDK_2BUTTON_PRESS:
+            event_type = dclick;
+#ifndef __WXGTK3__
+            if (gdk_event->button >= 1 && gdk_event->button <= 3)
             {
             {
-                gdk_event_free( peek_event );
+                // Reset GDK internal timestamp variables in order to disable GDK
+                // triple click events. GDK will then next time believe no button has
+                // been clicked just before, and send a normal button click event.
+                GdkDisplay* display = gtk_widget_get_display(widget);
+                display->button_click_time[1] = 0;
+                display->button_click_time[0] = 0;
             }
             }
-        }
+#endif // !__WXGTK3__
+            break;
+        // we shouldn't get triple clicks at all for GTK2 because we
+        // suppress them artificially using the code above but we still
+        // should map them to something for GTK3 and not just ignore them
+        // as this would lose clicks
+        case GDK_3BUTTON_PRESS:
+            event_type = down;
+            break;
+        default:
+            return false;
     }
 
     }
 
-    wxEventType event_type = wxEVT_NULL;
+    g_lastMouseEvent = (GdkEvent*) gdk_event;
 
 
-    if ( gdk_event->type == GDK_2BUTTON_PRESS &&
-            gdk_event->button >= 1 && gdk_event->button <= 3 )
-    {
-        // Reset GDK internal timestamp variables in order to disable GDK
-        // triple click events. GDK will then next time believe no button has
-        // been clicked just before, and send a normal button click event.
-        GdkDisplay* display = gtk_widget_get_display (widget);
-        display->button_click_time[1] = 0;
-        display->button_click_time[0] = 0;
-    }
-
-    if (gdk_event->button == 1)
-    {
-        // note that GDK generates triple click events which are not supported
-        // by wxWidgets but still have to be passed to the app as otherwise
-        // clicks would simply go missing
-        switch (gdk_event->type)
-        {
-            // we shouldn't get triple clicks at all for GTK2 because we
-            // suppress them artificially using the code above but we still
-            // should map them to something for GTK1 and not just ignore them
-            // as this would lose clicks
-            case GDK_3BUTTON_PRESS:     // we could also map this to DCLICK...
-            case GDK_BUTTON_PRESS:
-                event_type = wxEVT_LEFT_DOWN;
-                break;
-
-            case GDK_2BUTTON_PRESS:
-                event_type = wxEVT_LEFT_DCLICK;
-                break;
-
-            default:
-                // just to silence gcc warnings
-                ;
-        }
-    }
-    else if (gdk_event->button == 2)
-    {
-        switch (gdk_event->type)
-        {
-            case GDK_3BUTTON_PRESS:
-            case GDK_BUTTON_PRESS:
-                event_type = wxEVT_MIDDLE_DOWN;
-                break;
-
-            case GDK_2BUTTON_PRESS:
-                event_type = wxEVT_MIDDLE_DCLICK;
-                break;
-
-            default:
-                ;
-        }
-    }
-    else if (gdk_event->button == 3)
-    {
-        switch (gdk_event->type)
-        {
-            case GDK_3BUTTON_PRESS:
-            case GDK_BUTTON_PRESS:
-                event_type = wxEVT_RIGHT_DOWN;
-                break;
-
-            case GDK_2BUTTON_PRESS:
-                event_type = wxEVT_RIGHT_DCLICK;
-                break;
-
-            default:
-                ;
-        }
-    }
-
-    if ( event_type == wxEVT_NULL )
-    {
-        // unknown mouse button or click type
-        return FALSE;
-    }
-
-    g_lastMouseEvent = (GdkEvent*) gdk_event;
-
-    wxMouseEvent event( event_type );
-    InitMouseEvent( win, event, gdk_event );
+    wxMouseEvent event( event_type );
+    InitMouseEvent( win, event, gdk_event );
 
     AdjustEventButtonState(event);
 
 
     AdjustEventButtonState(event);
 
@@ -1417,6 +1472,8 @@ gtk_window_button_release_callback( GtkWidget *WXUNUSED(widget),
                                     GdkEventButton *gdk_event,
                                     wxWindowGTK *win )
 {
                                     GdkEventButton *gdk_event,
                                     wxWindowGTK *win )
 {
+    wxPROCESS_EVENT_ONCE(GdkEventButton, gdk_event);
+
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     g_lastButtonNumber = 0;
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     g_lastButtonNumber = 0;
@@ -1437,6 +1494,14 @@ gtk_window_button_release_callback( GtkWidget *WXUNUSED(widget),
             event_type = wxEVT_RIGHT_UP;
             break;
 
             event_type = wxEVT_RIGHT_UP;
             break;
 
+        case 8:
+            event_type = wxEVT_AUX1_UP;
+            break;
+
+        case 9:
+            event_type = wxEVT_AUX2_UP;
+            break;
+
         default:
             // unknown button, don't process
             return FALSE;
         default:
             // unknown button, don't process
             return FALSE;
@@ -1472,14 +1537,19 @@ gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
                                    GdkEventMotion *gdk_event,
                                    wxWindowGTK *win )
 {
                                    GdkEventMotion *gdk_event,
                                    wxWindowGTK *win )
 {
+    wxPROCESS_EVENT_ONCE(GdkEventMotion, gdk_event);
+
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     if (gdk_event->is_hint)
     {
         int x = 0;
         int y = 0;
     wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
 
     if (gdk_event->is_hint)
     {
         int x = 0;
         int y = 0;
-        GdkModifierType state;
-        gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+#ifdef __WXGTK3__
+        gdk_window_get_device_position(gdk_event->window, gdk_event->device, &x, &y, NULL);
+#else
+        gdk_window_get_pointer(gdk_event->window, &x, &y, NULL);
+#endif
         gdk_event->x = x;
         gdk_event->y = y;
     }
         gdk_event->x = x;
         gdk_event->y = y;
     }
@@ -1492,7 +1562,12 @@ gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
     if ( g_captureWindow )
     {
         // synthesise a mouse enter or leave event if needed
     if ( g_captureWindow )
     {
         // synthesise a mouse enter or leave event if needed
-        GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
+        GdkWindow* winUnderMouse =
+#ifdef __WXGTK3__
+            gdk_device_get_window_at_position(gdk_event->device, NULL, NULL);
+#else
+            gdk_window_at_pointer(NULL, NULL);
+#endif
         // This seems to be necessary and actually been added to
         // GDK itself in version 2.0.X
         gdk_flush();
         // This seems to be necessary and actually been added to
         // GDK itself in version 2.0.X
         gdk_flush();
@@ -1539,80 +1614,112 @@ gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
 // "scroll_event" (mouse wheel event)
 //-----------------------------------------------------------------------------
 
 // "scroll_event" (mouse wheel event)
 //-----------------------------------------------------------------------------
 
-static gboolean
-window_scroll_event_hscrollbar(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
+// Compute lines/columns per action the same way as private GTK+ function
+// _gtk_range_get_wheel_delta()
+static inline int GetWheelScrollActionDelta(GtkRange* range)
 {
 {
-    if (gdk_event->direction != GDK_SCROLL_LEFT &&
-        gdk_event->direction != GDK_SCROLL_RIGHT)
+    int delta = 3;
+    if (range)
     {
     {
-        return false;
+        GtkAdjustment* adj = gtk_range_get_adjustment(range);
+        const double page_size = gtk_adjustment_get_page_size(adj);
+        delta = wxRound(pow(page_size, 2.0 / 3.0));
     }
     }
+    return delta;
+}
 
 
+static gboolean
+window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
+{
     wxMouseEvent event(wxEVT_MOUSEWHEEL);
     InitMouseEvent(win, event, gdk_event);
 
     wxMouseEvent event(wxEVT_MOUSEWHEEL);
     InitMouseEvent(win, event, gdk_event);
 
-    GtkRange *range = win->m_scrollBar[wxWindow::ScrollDir_Horz];
-    if (!range) return FALSE;
+    event.m_wheelDelta = 120;
 
 
-    if (range && GTK_WIDGET_VISIBLE (range))
+#if GTK_CHECK_VERSION(3,4,0)
+    if (gdk_event->direction == GDK_SCROLL_SMOOTH)
     {
     {
-        GtkAdjustment *adj = range->adjustment;
-        gdouble delta = adj->step_increment * 3;
-        if (gdk_event->direction == GDK_SCROLL_LEFT)
-            delta = -delta;
-
-        gdouble new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
-
-        gtk_adjustment_set_value (adj, new_value);
+        bool processed_x = false;
+        if (gdk_event->delta_x)
+        {
+            event.m_wheelAxis = wxMOUSE_WHEEL_HORIZONTAL;
+            event.m_wheelRotation = int(event.m_wheelDelta * gdk_event->delta_x);
+            GtkRange* range = win->m_scrollBar[wxWindow::ScrollDir_Horz];
+            event.m_linesPerAction = GetWheelScrollActionDelta(range);
+            event.m_columnsPerAction = event.m_linesPerAction;
+            processed_x = win->GTKProcessEvent(event);
+        }
+        bool processed_y = false;
+        if (gdk_event->delta_y)
+        {
+            event.m_wheelAxis = wxMOUSE_WHEEL_VERTICAL;
+            event.m_wheelRotation = int(event.m_wheelDelta * -gdk_event->delta_y);
+            GtkRange* range = win->m_scrollBar[wxWindow::ScrollDir_Vert];
+            event.m_linesPerAction = GetWheelScrollActionDelta(range);
+            event.m_columnsPerAction = event.m_linesPerAction;
+            processed_y = win->GTKProcessEvent(event);
+        }
+        return processed_x || processed_y;
+    }
+#endif // GTK_CHECK_VERSION(3,4,0)
+    GtkRange *range;
+    switch (gdk_event->direction)
+    {
+        case GDK_SCROLL_UP:
+        case GDK_SCROLL_DOWN:
+            range = win->m_scrollBar[wxWindow::ScrollDir_Vert];
+            event.m_wheelAxis = wxMOUSE_WHEEL_VERTICAL;
+            break;
+        case GDK_SCROLL_LEFT:
+        case GDK_SCROLL_RIGHT:
+            range = win->m_scrollBar[wxWindow::ScrollDir_Horz];
+            event.m_wheelAxis = wxMOUSE_WHEEL_HORIZONTAL;
+            break;
+        default:
+            return false;
+    }
 
 
-        return TRUE;
+    event.m_wheelRotation = event.m_wheelDelta;
+    if (gdk_event->direction == GDK_SCROLL_DOWN ||
+        gdk_event->direction == GDK_SCROLL_LEFT)
+    {
+        event.m_wheelRotation = -event.m_wheelRotation;
     }
     }
+    event.m_linesPerAction = GetWheelScrollActionDelta(range);
+    event.m_columnsPerAction = event.m_linesPerAction;
 
 
-    return FALSE;
+    return win->GTKProcessEvent(event);
 }
 
 }
 
+#if GTK_CHECK_VERSION(3,4,0)
 static gboolean
 static gboolean
-window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
+hscrollbar_scroll_event(GtkWidget* widget, GdkEventScroll* gdk_event, wxWindow* win)
 {
 {
-    if (gdk_event->direction != GDK_SCROLL_UP &&
-        gdk_event->direction != GDK_SCROLL_DOWN)
+    GdkEventScroll event2;
+    if (gdk_event->direction == GDK_SCROLL_SMOOTH && gdk_event->delta_x == 0)
     {
     {
-        return false;
+        memcpy(&event2, gdk_event, sizeof(event2));
+        event2.delta_x = event2.delta_y;
+        event2.delta_y = 0;
+        gdk_event = &event2;
     }
     }
+    return window_scroll_event(widget, gdk_event, win);
+}
 
 
-    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;
-
-    if (win->GTKProcessEvent(event))
-      return TRUE;
-
-    GtkRange *range = win->m_scrollBar[wxWindow::ScrollDir_Vert];
-    if (!range) return FALSE;
-
-    if (range && GTK_WIDGET_VISIBLE (range))
+static gboolean
+vscrollbar_scroll_event(GtkWidget* widget, GdkEventScroll* gdk_event, wxWindow* win)
+{
+    GdkEventScroll event2;
+    if (gdk_event->direction == GDK_SCROLL_SMOOTH && gdk_event->delta_y == 0)
     {
     {
-        GtkAdjustment *adj = range->adjustment;
-        gdouble delta = adj->step_increment * 3;
-        if (gdk_event->direction == GDK_SCROLL_UP)
-          delta = -delta;
-
-        gdouble new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
-
-        gtk_adjustment_set_value (adj, new_value);
-
-        return TRUE;
+        memcpy(&event2, gdk_event, sizeof(event2));
+        event2.delta_y = event2.delta_x;
+        event2.delta_x = 0;
+        gdk_event = &event2;
     }
     }
-
-    return FALSE;
+    return window_scroll_event(widget, gdk_event, win);
 }
 }
+#endif // GTK_CHECK_VERSION(3,4,0)
 
 //-----------------------------------------------------------------------------
 // "popup-menu"
 
 //-----------------------------------------------------------------------------
 // "popup-menu"
@@ -1676,7 +1783,7 @@ wx_window_focus_callback(GtkWidget *widget,
 //-----------------------------------------------------------------------------
 
 static gboolean
 //-----------------------------------------------------------------------------
 
 static gboolean
-gtk_window_enter_callback( GtkWidget *widget,
+gtk_window_enter_callback( GtkWidget*,
                            GdkEventCrossing *gdk_event,
                            wxWindowGTK *win )
 {
                            GdkEventCrossing *gdk_event,
                            wxWindowGTK *win )
 {
@@ -1685,17 +1792,8 @@ gtk_window_enter_callback( GtkWidget *widget,
     // Event was emitted after a grab
     if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
 
     // Event was emitted after a grab
     if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
 
-    int x = 0;
-    int y = 0;
-    GdkModifierType state = (GdkModifierType)0;
-
-    gdk_window_get_pointer( widget->window, &x, &y, &state );
-
     wxMouseEvent event( wxEVT_ENTER_WINDOW );
     InitMouseEvent(win, event, gdk_event);
     wxMouseEvent event( wxEVT_ENTER_WINDOW );
     InitMouseEvent(win, event, gdk_event);
-    wxPoint pt = win->GetClientAreaOrigin();
-    event.m_x = x + pt.x;
-    event.m_y = y + pt.y;
 
     if ( !g_captureWindow )
     {
 
     if ( !g_captureWindow )
     {
@@ -1714,7 +1812,7 @@ gtk_window_enter_callback( GtkWidget *widget,
 //-----------------------------------------------------------------------------
 
 static gboolean
 //-----------------------------------------------------------------------------
 
 static gboolean
-gtk_window_leave_callback( GtkWidget *widget,
+gtk_window_leave_callback( GtkWidget*,
                            GdkEventCrossing *gdk_event,
                            wxWindowGTK *win )
 {
                            GdkEventCrossing *gdk_event,
                            wxWindowGTK *win )
 {
@@ -1724,13 +1822,6 @@ gtk_window_leave_callback( GtkWidget *widget,
     if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
 
     wxMouseEvent event( wxEVT_LEAVE_WINDOW );
     if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
 
     wxMouseEvent event( wxEVT_LEAVE_WINDOW );
-
-    int x = 0;
-    int y = 0;
-    GdkModifierType state = (GdkModifierType)0;
-
-    gdk_window_get_pointer( widget->window, &x, &y, &state );
-
     InitMouseEvent(win, event, gdk_event);
 
     return win->GTKProcessEvent(event);
     InitMouseEvent(win, event, gdk_event);
 
     return win->GTKProcessEvent(event);
@@ -1821,27 +1912,9 @@ gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* w
 //-----------------------------------------------------------------------------
 
 static void
 //-----------------------------------------------------------------------------
 
 static void
-gtk_window_realized_callback(GtkWidget* widget, wxWindow* win)
+gtk_window_realized_callback(GtkWidget* WXUNUSED(widget), wxWindowGTK* win)
 {
 {
-    if (win->m_imData)
-    {
-        gtk_im_context_set_client_window( win->m_imData->context,
-                                          widget->window);
-    }
-    
-    // We cannot set colours and fonts before the widget
-    // been realized, so we do this directly after realization
-    // or otherwise in idle time
-
-    if (win->m_needsStyleChange)
-    {
-        win->SetBackgroundStyle(win->GetBackgroundStyle());
-        win->m_needsStyleChange = false;
-    }
-
-    wxWindowCreateEvent event( win );
-    event.SetEventObject( win );
-    win->GTKProcessEvent( event );
+    win->GTKHandleRealized();
 }
 
 //-----------------------------------------------------------------------------
 }
 
 //-----------------------------------------------------------------------------
@@ -1855,21 +1928,30 @@ size_allocate(GtkWidget*, GtkAllocation* alloc, wxWindow* win)
     int h = alloc->height;
     if (win->m_wxwindow)
     {
     int h = alloc->height;
     if (win->m_wxwindow)
     {
-        int border_x, border_y;
-        WX_PIZZA(win->m_wxwindow)->get_border_widths(border_x, border_y);
-        w -= 2 * border_x;
-        h -= 2 * border_y;
+        GtkBorder border;
+        WX_PIZZA(win->m_wxwindow)->get_border(border);
+        w -= border.left + border.right;
+        h -= border.top + border.bottom;
         if (w < 0) w = 0;
         if (h < 0) h = 0;
     }
         if (w < 0) w = 0;
         if (h < 0) h = 0;
     }
-    if (win->m_oldClientWidth != w || win->m_oldClientHeight != h)
+    GtkAllocation a;
+    gtk_widget_get_allocation(win->m_widget, &a);
+    // update position for widgets in native containers, such as wxToolBar
+    if (!WX_IS_PIZZA(gtk_widget_get_parent(win->m_widget)))
+    {
+        win->m_x = a.x;
+        win->m_y = a.y;
+    }
+    win->m_useCachedClientSize = true;
+    if (win->m_clientWidth != w || win->m_clientHeight != h)
     {
     {
-        win->m_oldClientWidth  = w;
-        win->m_oldClientHeight = h;
+        win->m_clientWidth  = w;
+        win->m_clientHeight = h;
         // this callback can be connected to m_wxwindow,
         // so always get size from m_widget->allocation
         // this callback can be connected to m_wxwindow,
         // so always get size from m_widget->allocation
-        win->m_width  = win->m_widget->allocation.width;
-        win->m_height = win->m_widget->allocation.height;
+        win->m_width  = a.width;
+        win->m_height = a.height;
         if (!win->m_nativeSizeEvent)
         {
             wxSizeEvent event(win->GetSize(), win->GetId());
         if (!win->m_nativeSizeEvent)
         {
             wxSizeEvent event(win->GetSize(), win->GetId());
@@ -1901,48 +1983,115 @@ gtk_window_grab_broken( GtkWidget*,
 #endif
 
 //-----------------------------------------------------------------------------
 #endif
 
 //-----------------------------------------------------------------------------
-// "style_set"
+// "style_set"/"style_updated"
 //-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
 
-static
-void gtk_window_style_set_callback( GtkWidget *WXUNUSED(widget),
-                               GtkStyle *previous_style,
-                               wxWindow* win )
+#ifdef __WXGTK3__
+static void style_updated(GtkWidget*, wxWindow* win)
+#else
+static void style_updated(GtkWidget*, GtkStyle*, wxWindow* win)
+#endif
 {
 {
-    if (win && previous_style)
-    {
-        wxSysColourChangedEvent event;
-        event.SetEventObject(win);
+    wxSysColourChangedEvent event;
+    event.SetEventObject(win);
+    win->GTKProcessEvent(event);
+}
 
 
-        win->GTKProcessEvent( event );
-    }
+//-----------------------------------------------------------------------------
+// "unrealize"
+//-----------------------------------------------------------------------------
+
+static void unrealize(GtkWidget*, wxWindow* win)
+{
+    win->GTKHandleUnrealize();
 }
 
 } // extern "C"
 
 }
 
 } // extern "C"
 
-// Helper to suspend colour change event event processing while we change a widget's style
-class wxSuspendStyleEvents
+void wxWindowGTK::GTKHandleRealized()
 {
 {
-public:
-    wxSuspendStyleEvents(wxWindow* win)
+    if (IsFrozen())
+        DoFreeze();
+
+    GdkWindow* const window = GTKGetDrawingWindow();
+
+    if (m_imContext)
     {
     {
-        m_win = NULL;
-        if (win->m_wxwindow && win->IsTopLevel())
+        gtk_im_context_set_client_window
+        (
+            m_imContext,
+            window ? window
+                       : gtk_widget_get_window(m_widget)
+        );
+    }
+
+    // Use composited window if background is transparent, if supported.
+    if (m_backgroundStyle == wxBG_STYLE_TRANSPARENT)
+    {
+#if wxGTK_HAS_COMPOSITING_SUPPORT
+        if (IsTransparentBackgroundSupported())
+        {
+            if (window)
+                gdk_window_set_composited(window, true);
+        }
+        else
+#endif // wxGTK_HAS_COMPOSITING_SUPPORT
         {
         {
-            m_win = win;
-            g_signal_handlers_block_by_func(
-                m_win->m_wxwindow, (void*)gtk_window_style_set_callback, m_win);
+            // We revert to erase mode if transparency is not supported
+            m_backgroundStyle = wxBG_STYLE_ERASE;
         }
     }
         }
     }
-    ~wxSuspendStyleEvents()
+
+#ifndef __WXGTK3__
+    if (window && (
+        m_backgroundStyle == wxBG_STYLE_PAINT ||
+        m_backgroundStyle == wxBG_STYLE_TRANSPARENT))
+    {
+        gdk_window_set_back_pixmap(window, NULL, false);
+    }
+#endif
+
+    wxWindowCreateEvent event(static_cast<wxWindow*>(this));
+    event.SetEventObject( this );
+    GTKProcessEvent( event );
+
+    GTKUpdateCursor(true, false);
+
+    if (m_wxwindow && IsTopLevel())
     {
     {
-        if (m_win)
-            g_signal_handlers_unblock_by_func(
-                m_win->m_wxwindow, (void*)gtk_window_style_set_callback, m_win);
+        // attaching to style changed signal after realization avoids initial
+        // changes we don't care about
+        const gchar *detailed_signal =
+#ifdef __WXGTK3__
+            "style_updated";
+#else
+            "style_set";
+#endif
+        g_signal_connect(m_wxwindow,
+            detailed_signal,
+            G_CALLBACK(style_updated), this);
     }
     }
+}
+
+void wxWindowGTK::GTKHandleUnrealize()
+{
+    // unrealizing a frozen window seems to have some lingering effect
+    // preventing updates to the affected area
+    if (IsFrozen())
+        DoThaw();
+
+    if (m_wxwindow)
+    {
+        if (m_imContext)
+            gtk_im_context_set_client_window(m_imContext, NULL);
 
 
-    wxWindow* m_win;
-};
+        if (IsTopLevel())
+        {
+            g_signal_handlers_disconnect_by_func(
+                m_wxwindow, (void*)style_updated, this);
+        }
+    }
+}
 
 // ----------------------------------------------------------------------------
 // this wxWindowBase function is implemented here (in platform-specific file)
 
 // ----------------------------------------------------------------------------
 // this wxWindowBase function is implemented here (in platform-specific file)
@@ -1951,6 +2100,15 @@ public:
 
 wxWindow *wxWindowBase::DoFindFocus()
 {
 
 wxWindow *wxWindowBase::DoFindFocus()
 {
+#if wxUSE_MENUS
+    // 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();
+#endif // wxUSE_MENUS
+
     wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus;
     // the cast is necessary when we compile in wxUniversal mode
     return static_cast<wxWindow*>(focus);
     wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus;
     // the cast is necessary when we compile in wxUniversal mode
     return static_cast<wxWindow*>(focus);
@@ -1959,17 +2117,15 @@ wxWindow *wxWindowBase::DoFindFocus()
 void wxWindowGTK::AddChildGTK(wxWindowGTK* child)
 {
     wxASSERT_MSG(m_wxwindow, "Cannot add a child to a window without a client area");
 void wxWindowGTK::AddChildGTK(wxWindowGTK* child)
 {
     wxASSERT_MSG(m_wxwindow, "Cannot add a child to a window without a client area");
-    
+
     // the window might have been scrolled already, we
     // have to adapt the position
     wxPizza* pizza = WX_PIZZA(m_wxwindow);
     child->m_x += pizza->m_scroll_x;
     child->m_y += pizza->m_scroll_y;
 
     // the window might have been scrolled already, we
     // have to adapt the position
     wxPizza* pizza = WX_PIZZA(m_wxwindow);
     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);
-    gtk_fixed_put(
-        GTK_FIXED(m_wxwindow), 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);
 }
 
 //-----------------------------------------------------------------------------
 }
 
 //-----------------------------------------------------------------------------
@@ -1982,6 +2138,29 @@ wxWindow *wxGetActiveWindow()
 }
 
 
 }
 
 
+// Under Unix this is implemented using X11 functions in utilsx11.cpp but we
+// need to have this function under Windows too, so provide at least a stub.
+#ifndef GDK_WINDOWING_X11
+bool wxGetKeyState(wxKeyCode WXUNUSED(key))
+{
+    wxFAIL_MSG(wxS("Not implemented under Windows"));
+    return false;
+}
+#endif // __WINDOWS__
+
+static GdkDisplay* GetDisplay()
+{
+    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();
+    return display;
+}
+
 wxMouseState wxGetMouseState()
 {
     wxMouseState ms;
 wxMouseState wxGetMouseState()
 {
     wxMouseState ms;
@@ -1990,13 +2169,24 @@ wxMouseState wxGetMouseState()
     gint y;
     GdkModifierType mask;
 
     gint y;
     GdkModifierType mask;
 
-    gdk_window_get_pointer(NULL, &x, &y, &mask);
+    GdkDisplay* display = GetDisplay();
+#ifdef __WXGTK3__
+    GdkDeviceManager* manager = gdk_display_get_device_manager(display);
+    GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
+    GdkScreen* screen;
+    gdk_device_get_position(device, &screen, &x, &y);
+    GdkWindow* window = gdk_screen_get_root_window(screen);
+    gdk_device_get_state(device, window, NULL, &mask);
+#else
+    gdk_display_get_pointer(display, NULL, &x, &y, &mask);
+#endif
 
     ms.SetX(x);
     ms.SetY(y);
     ms.SetLeftDown((mask & GDK_BUTTON1_MASK) != 0);
     ms.SetMiddleDown((mask & GDK_BUTTON2_MASK) != 0);
     ms.SetRightDown((mask & GDK_BUTTON3_MASK) != 0);
 
     ms.SetX(x);
     ms.SetY(y);
     ms.SetLeftDown((mask & GDK_BUTTON1_MASK) != 0);
     ms.SetMiddleDown((mask & GDK_BUTTON2_MASK) != 0);
     ms.SetRightDown((mask & GDK_BUTTON3_MASK) != 0);
+    // see the comment in InitMouseEvent()
     ms.SetAux1Down((mask & GDK_BUTTON4_MASK) != 0);
     ms.SetAux2Down((mask & GDK_BUTTON5_MASK) != 0);
 
     ms.SetAux1Down((mask & GDK_BUTTON4_MASK) != 0);
     ms.SetAux2Down((mask & GDK_BUTTON5_MASK) != 0);
 
@@ -2016,9 +2206,7 @@ wxMouseState wxGetMouseState()
 // method
 #ifdef __WXUNIVERSAL__
     IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
 // method
 #ifdef __WXUNIVERSAL__
     IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
-#else // __WXGTK__
-    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
-#endif // __WXUNIVERSAL__/__WXGTK__
+#endif // __WXUNIVERSAL__
 
 void wxWindowGTK::Init()
 {
 
 void wxWindowGTK::Init()
 {
@@ -2033,12 +2221,14 @@ void wxWindowGTK::Init()
     m_width = 0;
     m_height = 0;
 
     m_width = 0;
     m_height = 0;
 
-    m_hasVMT = false;
-
     m_showOnIdle = false;
 
     m_noExpose = false;
     m_nativeSizeEvent = false;
     m_showOnIdle = false;
 
     m_noExpose = false;
     m_nativeSizeEvent = false;
+#ifdef __WXGTK3__
+    m_paintContext = NULL;
+    m_styleProvider = NULL;
+#endif
 
     m_isScrolling = false;
     m_mouseButtonDown = false;
 
     m_isScrolling = false;
     m_mouseButtonDown = false;
@@ -2050,16 +2240,17 @@ void wxWindowGTK::Init()
         m_scrollPos[dir] = 0;
     }
 
         m_scrollPos[dir] = 0;
     }
 
-    m_oldClientWidth =
-    m_oldClientHeight = 0;
+    m_clientWidth =
+    m_clientHeight = 0;
+    m_useCachedClientSize = false;
 
     m_clipPaintRegion = false;
 
 
     m_clipPaintRegion = false;
 
-    m_needsStyleChange = false;
-
     m_cursor = *wxSTANDARD_CURSOR;
 
     m_cursor = *wxSTANDARD_CURSOR;
 
-    m_imData = NULL;
+    m_imContext = NULL;
+    m_imKeyEvent = NULL;
+
     m_dirtyTabOrder = false;
 }
 
     m_dirtyTabOrder = false;
 }
 
@@ -2080,6 +2271,77 @@ wxWindowGTK::wxWindowGTK( wxWindow *parent,
     Create( parent, id, pos, size, style, name );
 }
 
     Create( parent, id, pos, size, style, name );
 }
 
+void wxWindowGTK::GTKCreateScrolledWindowWith(GtkWidget* view)
+{
+    wxASSERT_MSG( HasFlag(wxHSCROLL) || HasFlag(wxVSCROLL),
+                  wxS("Must not be called if scrolling is not needed.") );
+
+    m_widget = gtk_scrolled_window_new( NULL, NULL );
+
+    GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
+
+    // There is a conflict with default bindings at GTK+
+    // level between scrolled windows and notebooks both of which want to use
+    // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
+    // direction and notebooks for changing pages -- we decide that if we don't
+    // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
+    // means we can get working keyboard navigation in notebooks
+    if ( !HasFlag(wxHSCROLL) )
+    {
+        GtkBindingSet *
+            bindings = gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget));
+        if ( bindings )
+        {
+            gtk_binding_entry_remove(bindings, GDK_Page_Up, GDK_CONTROL_MASK);
+            gtk_binding_entry_remove(bindings, GDK_Page_Down, GDK_CONTROL_MASK);
+        }
+    }
+
+    // If wx[HV]SCROLL is not given, the corresponding scrollbar is not shown
+    // at all. Otherwise it may be shown only on demand (default) or always, if
+    // the wxALWAYS_SHOW_SB is specified.
+    GtkPolicyType horzPolicy = HasFlag(wxHSCROLL)
+                                ? HasFlag(wxALWAYS_SHOW_SB)
+                                    ? GTK_POLICY_ALWAYS
+                                    : GTK_POLICY_AUTOMATIC
+                                : GTK_POLICY_NEVER;
+    GtkPolicyType vertPolicy = HasFlag(wxVSCROLL)
+                                ? HasFlag(wxALWAYS_SHOW_SB)
+                                    ? GTK_POLICY_ALWAYS
+                                    : GTK_POLICY_AUTOMATIC
+                                : GTK_POLICY_NEVER;
+    gtk_scrolled_window_set_policy( scrolledWindow, horzPolicy, vertPolicy );
+
+    m_scrollBar[ScrollDir_Horz] = GTK_RANGE(gtk_scrolled_window_get_hscrollbar(scrolledWindow));
+    m_scrollBar[ScrollDir_Vert] = GTK_RANGE(gtk_scrolled_window_get_vscrollbar(scrolledWindow));
+    if (GetLayoutDirection() == wxLayout_RightToLeft)
+        gtk_range_set_inverted( m_scrollBar[ScrollDir_Horz], TRUE );
+
+    gtk_container_add( GTK_CONTAINER(m_widget), view );
+
+    // connect various scroll-related events
+    for ( int dir = 0; dir < ScrollDir_Max; dir++ )
+    {
+        // these handlers block mouse events to any window during scrolling
+        // such as motion events and prevent GTK and wxWidgets from fighting
+        // over where the slider should be
+        g_signal_connect(m_scrollBar[dir], "button_press_event",
+                     G_CALLBACK(gtk_scrollbar_button_press_event), this);
+        g_signal_connect(m_scrollBar[dir], "button_release_event",
+                     G_CALLBACK(gtk_scrollbar_button_release_event), this);
+
+        gulong handler_id = g_signal_connect(m_scrollBar[dir], "event_after",
+                            G_CALLBACK(gtk_scrollbar_event_after), this);
+        g_signal_handler_block(m_scrollBar[dir], handler_id);
+
+        // these handlers get notified when scrollbar slider moves
+        g_signal_connect_after(m_scrollBar[dir], "value_changed",
+                     G_CALLBACK(gtk_scrollbar_value_changed), this);
+    }
+
+    gtk_widget_show( view );
+}
+
 bool wxWindowGTK::Create( wxWindow *parent,
                           wxWindowID id,
                           const wxPoint &pos,
 bool wxWindowGTK::Create( wxWindow *parent,
                           wxWindowID id,
                           const wxPoint &pos,
@@ -2107,7 +2369,7 @@ bool wxWindowGTK::Create( wxWindow *parent,
 #endif
 
 
 #endif
 
 
-    m_wxwindow = wxPizza::New(m_windowStyle,this);
+    m_wxwindow = wxPizza::New(m_windowStyle);
 #ifndef __WXUNIVERSAL__
     if (HasFlag(wxPizza::BORDER_STYLES))
     {
 #ifndef __WXUNIVERSAL__
     if (HasFlag(wxPizza::BORDER_STYLES))
     {
@@ -2118,69 +2380,7 @@ bool wxWindowGTK::Create( wxWindow *parent,
     if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
         m_widget = m_wxwindow;
     else
     if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
         m_widget = m_wxwindow;
     else
-    {
-        m_widget = gtk_scrolled_window_new( NULL, NULL );
-
-        GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
-
-        // There is a conflict with default bindings at GTK+
-        // level between scrolled windows and notebooks both of which want to use
-        // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
-        // direction and notebooks for changing pages -- we decide that if we don't
-        // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
-        // means we can get working keyboard navigation in notebooks
-        if ( !HasFlag(wxHSCROLL) )
-        {
-            GtkBindingSet *
-                bindings = gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget));
-            if ( bindings )
-            {
-                gtk_binding_entry_remove(bindings, GDK_Page_Up, GDK_CONTROL_MASK);
-                gtk_binding_entry_remove(bindings, GDK_Page_Down, GDK_CONTROL_MASK);
-            }
-        }
-
-        if (HasFlag(wxALWAYS_SHOW_SB))
-        {
-            gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS );
-
-            scrolledWindow->hscrollbar_visible = TRUE;
-            scrolledWindow->vscrollbar_visible = TRUE;
-        }
-        else
-        {
-            gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
-        }
-
-        m_scrollBar[ScrollDir_Horz] = GTK_RANGE(scrolledWindow->hscrollbar);
-        m_scrollBar[ScrollDir_Vert] = GTK_RANGE(scrolledWindow->vscrollbar);
-        if (GetLayoutDirection() == wxLayout_RightToLeft)
-            gtk_range_set_inverted( m_scrollBar[ScrollDir_Horz], TRUE );
-
-        gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
-
-        // connect various scroll-related events
-        for ( int dir = 0; dir < ScrollDir_Max; dir++ )
-        {
-            // these handlers block mouse events to any window during scrolling
-            // such as motion events and prevent GTK and wxWidgets from fighting
-            // over where the slider should be
-            g_signal_connect(m_scrollBar[dir], "button_press_event",
-                         G_CALLBACK(gtk_scrollbar_button_press_event), this);
-            g_signal_connect(m_scrollBar[dir], "button_release_event",
-                         G_CALLBACK(gtk_scrollbar_button_release_event), this);
-
-            gulong handler_id = g_signal_connect(m_scrollBar[dir], "event_after",
-                                G_CALLBACK(gtk_scrollbar_event_after), this);
-            g_signal_handler_block(m_scrollBar[dir], handler_id);
-
-            // these handlers get notified when scrollbar slider moves
-            g_signal_connect_after(m_scrollBar[dir], "value_changed",
-                         G_CALLBACK(gtk_scrollbar_value_changed), this);
-        }
-
-        gtk_widget_show( m_wxwindow );
-    }
+        GTKCreateScrolledWindowWith(m_wxwindow);
     g_object_ref(m_widget);
 
     if (m_parent)
     g_object_ref(m_widget);
 
     if (m_parent)
@@ -2195,6 +2395,12 @@ bool wxWindowGTK::Create( wxWindow *parent,
     return true;
 }
 
     return true;
 }
 
+void wxWindowGTK::GTKDisconnect(void* instance)
+{
+    g_signal_handlers_disconnect_matched(instance,
+        GSignalMatchType(G_SIGNAL_MATCH_DATA), 0, 0, NULL, NULL, this);
+}
+
 wxWindowGTK::~wxWindowGTK()
 {
     SendDestroyEvent();
 wxWindowGTK::~wxWindowGTK()
 {
     SendDestroyEvent();
@@ -2207,28 +2413,46 @@ wxWindowGTK::~wxWindowGTK()
     if ( gs_deferredFocusOut == this )
         gs_deferredFocusOut = NULL;
 
     if ( gs_deferredFocusOut == this )
         gs_deferredFocusOut = NULL;
 
-    m_hasVMT = false;
+    // Unlike the above cases, which can happen in normal circumstances, a
+    // window shouldn't be destroyed while it still has capture, so even though
+    // we still reset the global pointer to avoid leaving it dangling and
+    // crashing afterwards, also complain about it.
+    if ( g_captureWindow == this )
+    {
+        wxFAIL_MSG( wxS("Destroying window with mouse capture") );
+        g_captureWindow = NULL;
+    }
+
+    if (m_wxwindow)
+    {
+        GTKDisconnect(m_wxwindow);
+        GtkWidget* parent = gtk_widget_get_parent(m_wxwindow);
+        if (parent)
+            GTKDisconnect(parent);
+    }
+    if (m_widget && m_widget != m_wxwindow)
+        GTKDisconnect(m_widget);
 
     // destroy children before destroying this window itself
     DestroyChildren();
 
 
     // destroy children before destroying this window itself
     DestroyChildren();
 
-    // unhook focus handlers to prevent stray events being
-    // propagated to this (soon to be) dead object
-    if (m_focusWidget != NULL)
+    // delete before the widgets to avoid a crash on solaris
+    if ( m_imContext )
     {
     {
-        g_signal_handlers_disconnect_by_func (m_focusWidget,
-                                              (gpointer) gtk_window_focus_in_callback,
-                                              this);
-        g_signal_handlers_disconnect_by_func (m_focusWidget,
-                                              (gpointer) gtk_window_focus_out_callback,
-                                              this);
+        g_object_unref(m_imContext);
+        m_imContext = NULL;
     }
 
     }
 
-    if (m_widget)
-        Show( false );
+    // avoid problem with GTK+ 2.18 where a frozen window causes the whole
+    // TLW to be frozen, and if the window is then destroyed, nothing ever
+    // gets painted again
+    while (IsFrozen())
+        Thaw();
 
 
-    // delete before the widgets to avoid a crash on solaris
-    delete m_imData;
+#ifdef __WXGTK3__
+    if (m_styleProvider)
+        g_object_unref(m_styleProvider);
+#endif
 
     if (m_widget)
     {
 
     if (m_widget)
     {
@@ -2255,8 +2479,11 @@ bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos,  const w
     m_width = WidthDefault(size.x) ;
     m_height = HeightDefault(size.y);
 
     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;
 }
 
     return true;
 }
@@ -2265,26 +2492,46 @@ void wxWindowGTK::PostCreation()
 {
     wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
 
 {
     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);
+#ifdef __WXGTK3__
+        gtk_widget_set_visual(m_widget, gdk_screen_get_rgba_visual(screen));
+#else
+        GdkColormap *rgba_colormap = gdk_screen_get_rgba_colormap (screen);
+
+        if (rgba_colormap)
+            gtk_widget_set_colormap(m_widget, rgba_colormap);
+#endif
+    }
+#endif // wxGTK_HAS_COMPOSITING_SUPPORT
+
     if (m_wxwindow)
     {
         if (!m_noExpose)
         {
             // these get reported to wxWidgets -> wxPaintEvent
     if (m_wxwindow)
     {
         if (!m_noExpose)
         {
             // these get reported to wxWidgets -> wxPaintEvent
-
-            g_signal_connect (m_wxwindow, "expose_event",
-                              G_CALLBACK (gtk_window_expose_callback), this);
+#ifdef __WXGTK3__
+            g_signal_connect(m_wxwindow, "draw", G_CALLBACK(draw), this);
+#else
+            g_signal_connect(m_wxwindow, "expose_event", G_CALLBACK(expose_event), this);
+#endif
 
             if (GetLayoutDirection() == wxLayout_LeftToRight)
                 gtk_widget_set_redraw_on_allocate(m_wxwindow, HasFlag(wxFULL_REPAINT_ON_RESIZE));
         }
 
         // Create input method handler
 
             if (GetLayoutDirection() == wxLayout_LeftToRight)
                 gtk_widget_set_redraw_on_allocate(m_wxwindow, HasFlag(wxFULL_REPAINT_ON_RESIZE));
         }
 
         // Create input method handler
-        m_imData = new wxGtkIMData;
+        m_imContext = gtk_im_multicontext_new();
 
         // Cannot handle drawing preedited text yet
 
         // Cannot handle drawing preedited text yet
-        gtk_im_context_set_use_preedit( m_imData->context, FALSE );
+        gtk_im_context_set_use_preedit( m_imContext, FALSE );
 
 
-        g_signal_connect (m_imData->context, "commit",
+        g_signal_connect (m_imContext, "commit",
                           G_CALLBACK (gtk_wxwindow_commit_cb), this);
     }
 
                           G_CALLBACK (gtk_wxwindow_commit_cb), this);
     }
 
@@ -2325,10 +2572,19 @@ void wxWindowGTK::PostCreation()
 
     ConnectWidget( connect_widget );
 
 
     ConnectWidget( connect_widget );
 
-    /* We cannot set colours, fonts and cursors before the widget has
-       been realized, so we do this directly after realization */
-    g_signal_connect (connect_widget, "realize",
-                      G_CALLBACK (gtk_window_realized_callback), this);
+    // We cannot set colours, fonts and cursors before the widget has been
+    // realized, so we do this directly after realization -- unless the widget
+    // was in fact realized already.
+    if ( gtk_widget_get_realized(connect_widget) )
+    {
+        GTKHandleRealized();
+    }
+    else
+    {
+        g_signal_connect (connect_widget, "realize",
+                          G_CALLBACK (gtk_window_realized_callback), this);
+    }
+    g_signal_connect(connect_widget, "unrealize", G_CALLBACK(unrealize), this);
 
     if (!IsTopLevel())
     {
 
     if (!IsTopLevel())
     {
@@ -2336,53 +2592,33 @@ void wxWindowGTK::PostCreation()
             G_CALLBACK(size_allocate), this);
     }
 
             G_CALLBACK(size_allocate), this);
     }
 
-    if (m_wxwindow)
-    {
 #if GTK_CHECK_VERSION(2, 8, 0)
 #if GTK_CHECK_VERSION(2, 8, 0)
-        if (!gtk_check_version(2,8,0))
+#ifndef __WXGTK3__
+    if ( gtk_check_version(2,8,0) == NULL )
+#endif
+    {
+        // Make sure we can notify the app when mouse capture is lost
+        if ( m_wxwindow )
         {
         {
-            // Make sure we can notify the app when mouse capture is lost
             g_signal_connect (m_wxwindow, "grab_broken_event",
                           G_CALLBACK (gtk_window_grab_broken), this);
         }
             g_signal_connect (m_wxwindow, "grab_broken_event",
                           G_CALLBACK (gtk_window_grab_broken), this);
         }
-#endif
-    }
 
 
-    if ( connect_widget != m_wxwindow )
-    {
-#if GTK_CHECK_VERSION(2, 8, 0)
-        if (!gtk_check_version(2,8,0))
+        if ( connect_widget != m_wxwindow )
         {
         {
-            // Make sure we can notify app code when mouse capture is lost
             g_signal_connect (connect_widget, "grab_broken_event",
                         G_CALLBACK (gtk_window_grab_broken), this);
         }
             g_signal_connect (connect_widget, "grab_broken_event",
                         G_CALLBACK (gtk_window_grab_broken), this);
         }
-#endif
     }
     }
+#endif // GTK+ >= 2.8
 
 
-#ifdef GTK_IS_FILE_CHOOSER_BUTTON
-    if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget))
-    {
-        // If we connect to the "size_request" signal of a GtkFileChooserButton
-        // then that control won't be sized properly when placed inside sizers
-        // (this can be tested removing this elseif and running XRC or WIDGETS samples)
-        // FIXME: what should be done here ?
-    } else
-#endif
-    if ( !IsTopLevel() ) // top level windows use their own callback
-    {
-        // 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();
+    // apply any font or color changes made before creation
+    GTKApplyWidgetStyle();
 
 
-    m_hasVMT = true;
+    InheritAttributes();
 
     SetLayoutDirection(wxLayout_Default);
 
 
     SetLayoutDirection(wxLayout_Default);
 
@@ -2392,6 +2628,12 @@ void wxWindowGTK::PostCreation()
         gtk_widget_show( m_widget );
 }
 
         gtk_widget_show( m_widget );
 }
 
+unsigned long
+wxWindowGTK::GTKConnectWidget(const char *signal, wxGTKCallback callback)
+{
+    return g_signal_connect(m_widget, signal, callback, this);
+}
+
 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
 {
     g_signal_connect (widget, "key_press_event",
 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
 {
     g_signal_connect (widget, "key_press_event",
@@ -2407,12 +2649,21 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
 
     g_signal_connect (widget, "scroll_event",
                       G_CALLBACK (window_scroll_event), this);
 
     g_signal_connect (widget, "scroll_event",
                       G_CALLBACK (window_scroll_event), this);
-    if (m_scrollBar[ScrollDir_Horz])
-        g_signal_connect (m_scrollBar[ScrollDir_Horz], "scroll_event",
-                      G_CALLBACK (window_scroll_event_hscrollbar), this);
-    if (m_scrollBar[ScrollDir_Vert])
-        g_signal_connect (m_scrollBar[ScrollDir_Vert], "scroll_event",
-                      G_CALLBACK (window_scroll_event), this);
+    for (int i = 0; i < 2; i++)
+    {
+        GtkRange* range = m_scrollBar[i];
+        if (range)
+        {
+#if GTK_CHECK_VERSION(3,4,0)
+            GCallback cb = GCallback(i == ScrollDir_Horz
+                ? hscrollbar_scroll_event
+                : vscrollbar_scroll_event);
+#else
+            GCallback cb = GCallback(window_scroll_event);
+#endif
+            g_signal_connect(range, "scroll_event", cb, this);
+        }
+    }
 
     g_signal_connect (widget, "popup_menu",
                      G_CALLBACK (wxgtk_window_popup_menu_callback), this);
 
     g_signal_connect (widget, "popup_menu",
                      G_CALLBACK (wxgtk_window_popup_menu_callback), this);
@@ -2420,29 +2671,48 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
                       G_CALLBACK (gtk_window_enter_callback), this);
     g_signal_connect (widget, "leave_notify_event",
                       G_CALLBACK (gtk_window_leave_callback), this);
                       G_CALLBACK (gtk_window_enter_callback), this);
     g_signal_connect (widget, "leave_notify_event",
                       G_CALLBACK (gtk_window_leave_callback), this);
-
-    if (IsTopLevel() && m_wxwindow)
-        g_signal_connect (m_wxwindow, "style_set",
-                              G_CALLBACK (gtk_window_style_set_callback), this);
 }
 
 }
 
-bool wxWindowGTK::Destroy()
-{
-    wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
-
-    m_hasVMT = false;
+static GSList* gs_queueResizeList;
 
 
-    return wxWindowBase::Destroy();
+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);
 }
 
 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
 {
     gtk_widget_set_size_request(m_widget, 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);
+    GtkWidget* parent = gtk_widget_get_parent(m_widget);
+    if (WX_IS_PIZZA(parent))
+        WX_PIZZA(parent)->move(m_widget, x, y, width, height);
+
+    // 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()
 }
 
 void wxWindowGTK::ConstrainSize()
@@ -2464,16 +2734,24 @@ void wxWindowGTK::ConstrainSize()
 
 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
 {
 
 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");
 
 
-    int currentX, currentY;
-    GetPosition(&currentX, &currentY);
-    if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
-        x = currentX;
-    if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
-        y = currentY;
-    AdjustForParentClientOrigin(x, y, sizeFlags);
+    int scrollX = 0, scrollY = 0;
+    GtkWidget* parent = gtk_widget_get_parent(m_widget);
+    if (WX_IS_PIZZA(parent))
+    {
+        wxPizza* pizza = WX_PIZZA(parent);
+        scrollX = pizza->m_scroll_x;
+        scrollY = pizza->m_scroll_y;
+    }
+    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) ||
 
     // calculate the best size if we should auto size the window
     if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
@@ -2486,60 +2764,47 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
             height = sizeBest.y;
     }
 
             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)
-    {
-        wxPizza* pizza = WX_PIZZA(m_parent->m_wxwindow);
-        m_x = x + pizza->m_scroll_x;
-        m_y = y + pizza->m_scroll_y;
+    const bool sizeChange = m_width != width || m_height != height;
 
 
-        int left_border = 0;
-        int right_border = 0;
-        int top_border = 0;
-        int bottom_border = 0;
+    if (sizeChange)
+        m_useCachedClientSize = false;
+
+    if (sizeChange || m_x != x || m_y != y)
+    {
+        m_x = x;
+        m_y = y;
+        m_width = width;
+        m_height = height;
 
         /* the default button has a border around it */
 
         /* the default button has a border around it */
-        if (GTK_WIDGET_CAN_DEFAULT(m_widget))
+        if (gtk_widget_get_can_default(m_widget))
         {
             GtkBorder *default_border = NULL;
             gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
             if (default_border)
             {
         {
             GtkBorder *default_border = NULL;
             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 );
             }
         }
 
                 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
     {
         // update these variables to keep size_allocate handler
         // from sending another size event for this change
-        GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
+        DoGetClientSize(&m_clientWidth, &m_clientHeight);
 
 
-        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 );
         wxSizeEvent event( wxSize(m_width,m_height), GetId() );
         event.SetEventObject( this );
         HandleWindowEvent( event );
@@ -2548,7 +2813,7 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
 
 bool wxWindowGTK::GTKShowFromOnIdle()
 {
 
 bool wxWindowGTK::GTKShowFromOnIdle()
 {
-    if (IsShown() && m_showOnIdle && !GTK_WIDGET_VISIBLE (m_widget))
+    if (IsShown() && m_showOnIdle && !gtk_widget_get_visible (m_widget))
     {
         GtkAllocation alloc;
         alloc.x = m_x;
     {
         GtkAllocation alloc;
         alloc.x = m_x;
@@ -2581,54 +2846,11 @@ void wxWindowGTK::OnInternalIdle()
         RealizeTabOrder();
     }
 
         RealizeTabOrder();
     }
 
-    // Update style if the window was not yet realized
-    // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
-    if (m_needsStyleChange)
-    {
-        SetBackgroundStyle(GetBackgroundStyle());
-        m_needsStyleChange = false;
-    }
-
-    wxCursor cursor = m_cursor;
-    if (g_globalCursor.Ok()) cursor = g_globalCursor;
-
-    if (cursor.Ok())
-    {
-        /* I now set the cursor anew in every OnInternalIdle call
-           as setting the cursor in a parent window also effects the
-           windows above so that checking for the current cursor is
-           not possible. */
-
-        if (m_wxwindow && (m_wxwindow != m_widget))
-        {
-            GdkWindow *window = m_wxwindow->window;
-            if (window)
-                gdk_window_set_cursor( window, cursor.GetCursor() );
-
-            if (!g_globalCursor.Ok())
-                cursor = *wxSTANDARD_CURSOR;
-
-            window = m_widget->window;
-            if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
-                gdk_window_set_cursor( window, cursor.GetCursor() );
-
-        }
-        else if ( m_widget )
-        {
-            GdkWindow *window = m_widget->window;
-            if ( window && !GTK_WIDGET_NO_WINDOW(m_widget) )
-               gdk_window_set_cursor( window, cursor.GetCursor() );
-        }
-    }
-
-    if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
-        UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+    wxWindowBase::OnInternalIdle();
 }
 
 void wxWindowGTK::DoGetSize( int *width, int *height ) const
 {
 }
 
 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;
 }
     if (width) (*width) = m_width;
     if (height) (*height) = m_height;
 }
@@ -2646,6 +2868,13 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
+    if (m_useCachedClientSize)
+    {
+        if (width)  *width  = m_clientWidth;
+        if (height) *height = m_clientHeight;
+        return;
+    }
+
     int w = m_width;
     int h = m_height;
 
     int w = m_width;
     int h = m_height;
 
@@ -2659,6 +2888,16 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
                                            &policy[ScrollDir_Horz],
                                            &policy[ScrollDir_Vert]);
 
                                            &policy[ScrollDir_Horz],
                                            &policy[ScrollDir_Vert]);
 
+            // get scrollbar spacing the same way the GTK-private function
+            // _gtk_scrolled_window_get_scrollbar_spacing() does it
+            int scrollbar_spacing =
+                GTK_SCROLLED_WINDOW_GET_CLASS(m_widget)->scrollbar_spacing;
+            if (scrollbar_spacing < 0)
+            {
+                gtk_widget_style_get(
+                    m_widget, "scrollbar-spacing", &scrollbar_spacing, NULL);
+            }
+
             for ( int i = 0; i < ScrollDir_Max; i++ )
             {
                 // don't account for the scrollbars we don't have
             for ( int i = 0; i < ScrollDir_Max; i++ )
             {
                 // don't account for the scrollbars we don't have
@@ -2680,26 +2919,42 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
                     case GTK_POLICY_AUTOMATIC:
                         // may be shown or not, check
                         GtkAdjustment *adj = gtk_range_get_adjustment(range);
                     case GTK_POLICY_AUTOMATIC:
                         // may be shown or not, check
                         GtkAdjustment *adj = gtk_range_get_adjustment(range);
-                        if ( adj->upper <= adj->page_size )
+                        if (gtk_adjustment_get_upper(adj) <= gtk_adjustment_get_page_size(adj))
                             continue;
                 }
 
                             continue;
                 }
 
-                GtkScrolledWindowClass *scroll_class =
-                    GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
-
                 GtkRequisition req;
                 GtkRequisition req;
+#ifdef __WXGTK3__
+                GtkWidget* widget = GTK_WIDGET(range);
+                if (i == ScrollDir_Horz)
+                {
+                    if (height)
+                    {
+                        gtk_widget_get_preferred_height(widget, NULL, &req.height);
+                        h -= req.height + scrollbar_spacing;
+                    }
+                }
+                else
+                {
+                    if (width)
+                    {
+                        gtk_widget_get_preferred_width(widget, NULL, &req.width);
+                        w -= req.width + scrollbar_spacing;
+                    }
+                }
+#else // !__WXGTK3__
                 gtk_widget_size_request(GTK_WIDGET(range), &req);
                 if (i == ScrollDir_Horz)
                 gtk_widget_size_request(GTK_WIDGET(range), &req);
                 if (i == ScrollDir_Horz)
-                    h -= req.height + scroll_class->scrollbar_spacing;
+                    h -= req.height + scrollbar_spacing;
                 else
                 else
-                    w -= req.width + scroll_class->scrollbar_spacing;
+                    w -= req.width + scrollbar_spacing;
+#endif // !__WXGTK3__
             }
         }
 
             }
         }
 
-        int border_x, border_y;
-        WX_PIZZA(m_wxwindow)->get_border_widths(border_x, border_y);
-        w -= 2 * border_x;
-        h -= 2 * border_y;
+        const wxSize sizeBorders = DoGetBorderSize();
+        w -= sizeBorders.x;
+        h -= sizeBorders.y;
 
         if (w < 0)
             w = 0;
 
         if (w < 0)
             w = 0;
@@ -2711,41 +2966,29 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
     if (height) *height = h;
 }
 
     if (height) *height = h;
 }
 
-void wxWindowGTK::DoGetPosition( int *x, int *y ) const
+wxSize wxWindowGTK::DoGetBorderSize() const
 {
 {
-    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+    if ( !m_wxwindow )
+        return wxWindowBase::DoGetBorderSize();
 
 
+    GtkBorder border;
+    WX_PIZZA(m_wxwindow)->get_border(border);
+    return wxSize(border.left + border.right, border.top + border.bottom);
+}
+
+void wxWindowGTK::DoGetPosition( int *x, int *y ) const
+{
     int dx = 0;
     int dy = 0;
     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;
     }
         dx = pizza->m_scroll_x;
         dy = pizza->m_scroll_y;
     }
-
-    if (m_x == -1 && m_y == -1)
-    {
-        GdkWindow *source = NULL;
-        if (m_wxwindow)
-            source = m_wxwindow->window;
-        else
-            source = m_widget->window;
-
-        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;
 }
     if (x) (*x) = m_x - dx;
     if (y) (*y) = m_y - dy;
 }
@@ -2754,13 +2997,13 @@ void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (!m_widget->window) return;
+    if (gtk_widget_get_window(m_widget) == NULL) return;
 
     GdkWindow *source = NULL;
     if (m_wxwindow)
 
     GdkWindow *source = NULL;
     if (m_wxwindow)
-        source = m_wxwindow->window;
+        source = gtk_widget_get_window(m_wxwindow);
     else
     else
-        source = m_widget->window;
+        source = gtk_widget_get_window(m_widget);
 
     int org_x = 0;
     int org_y = 0;
 
     int org_x = 0;
     int org_y = 0;
@@ -2768,10 +3011,12 @@ void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
 
     if (!m_wxwindow)
     {
 
     if (!m_wxwindow)
     {
-        if (GTK_WIDGET_NO_WINDOW (m_widget))
+        if (!gtk_widget_get_has_window(m_widget))
         {
         {
-            org_x += m_widget->allocation.x;
-            org_y += m_widget->allocation.y;
+            GtkAllocation a;
+            gtk_widget_get_allocation(m_widget, &a);
+            org_x += a.x;
+            org_y += a.y;
         }
     }
 
         }
     }
 
@@ -2791,13 +3036,13 @@ void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (!m_widget->window) return;
+    if (!gtk_widget_get_realized(m_widget)) return;
 
     GdkWindow *source = NULL;
     if (m_wxwindow)
 
     GdkWindow *source = NULL;
     if (m_wxwindow)
-        source = m_wxwindow->window;
+        source = gtk_widget_get_window(m_wxwindow);
     else
     else
-        source = m_widget->window;
+        source = gtk_widget_get_window(m_widget);
 
     int org_x = 0;
     int org_y = 0;
 
     int org_x = 0;
     int org_y = 0;
@@ -2805,10 +3050,12 @@ void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
 
     if (!m_wxwindow)
     {
 
     if (!m_wxwindow)
     {
-        if (GTK_WIDGET_NO_WINDOW (m_widget))
+        if (!gtk_widget_get_has_window(m_widget))
         {
         {
-            org_x += m_widget->allocation.x;
-            org_y += m_widget->allocation.y;
+            GtkAllocation a;
+            gtk_widget_get_allocation(m_widget, &a);
+            org_x += a.x;
+            org_y += a.y;
         }
     }
 
         }
     }
 
@@ -2824,29 +3071,40 @@ void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
 
 bool wxWindowGTK::Show( bool show )
 {
 
 bool wxWindowGTK::Show( bool show )
 {
-    wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
-
-    if (!wxWindowBase::Show(show))
+    if ( !wxWindowBase::Show(show) )
     {
         // nothing to do
         return false;
     }
 
     {
         // nothing to do
         return false;
     }
 
-    if (show && m_showOnIdle)
+    // notice that we may call Hide() before the window is created and this is
+    // actually useful to create it hidden initially -- but we can't call
+    // Show() before it is created
+    if ( !m_widget )
     {
     {
-        // deferred
+        wxASSERT_MSG( !show, "can't show invalid window" );
+        return true;
     }
     }
-    else
+
+    if ( show )
     {
     {
-        if (show)
-            gtk_widget_show(m_widget);
-        else
-            gtk_widget_hide(m_widget);
-        wxShowEvent eventShow(GetId(), show);
-        eventShow.SetEventObject(this);
-        HandleWindowEvent(eventShow);
+        if ( m_showOnIdle )
+        {
+            // defer until later
+            return true;
+        }
+
+        gtk_widget_show(m_widget);
+    }
+    else // hide
+    {
+        gtk_widget_hide(m_widget);
     }
 
     }
 
+    wxShowEvent eventShow(GetId(), show);
+    eventShow.SetEventObject(this);
+    HandleWindowEvent(eventShow);
+
     return true;
 }
 
     return true;
 }
 
@@ -2864,7 +3122,7 @@ int wxWindowGTK::GetCharHeight() const
     wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
 
     wxFont font = GetFont();
     wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
 
     wxFont font = GetFont();
-    wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
+    wxCHECK_MSG( font.IsOk(), 12, wxT("invalid font") );
 
     PangoContext* context = gtk_widget_get_pango_context(m_widget);
 
 
     PangoContext* context = gtk_widget_get_pango_context(m_widget);
 
@@ -2890,7 +3148,7 @@ int wxWindowGTK::GetCharWidth() const
     wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
 
     wxFont font = GetFont();
     wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
 
     wxFont font = GetFont();
-    wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
+    wxCHECK_MSG( font.IsOk(), 8, wxT("invalid font") );
 
     PangoContext* context = gtk_widget_get_pango_context(m_widget);
 
 
     PangoContext* context = gtk_widget_get_pango_context(m_widget);
 
@@ -2908,62 +3166,28 @@ int wxWindowGTK::GetCharWidth() const
 
     g_object_unref (layout);
 
 
     g_object_unref (layout);
 
-    return (int) PANGO_PIXELS(rect.width);
-}
-
-void wxWindowGTK::GetTextExtent( const wxString& string,
-                                 int *x,
-                                 int *y,
-                                 int *descent,
-                                 int *externalLeading,
-                                 const wxFont *theFont ) const
-{
-    wxFont fontToUse = theFont ? *theFont : GetFont();
-
-    wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
-
-    if (string.empty())
-    {
-        if (x) (*x) = 0;
-        if (y) (*y) = 0;
-        return;
-    }
-
-    PangoContext *context = NULL;
-    if (m_widget)
-        context = gtk_widget_get_pango_context( m_widget );
-
-    if (!context)
-    {
-        if (x) (*x) = 0;
-        if (y) (*y) = 0;
-        return;
-    }
-
-    PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
-    PangoLayout *layout = pango_layout_new(context);
-    pango_layout_set_font_description(layout, desc);
-    {
-        const wxCharBuffer data = wxGTK_CONV( string );
-        if ( data )
-            pango_layout_set_text(layout, data, strlen(data));
-    }
-
-    PangoRectangle rect;
-    pango_layout_get_extents(layout, NULL, &rect);
+    return (int) PANGO_PIXELS(rect.width);
+}
 
 
-    if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
-    if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
-    if (descent)
-    {
-        PangoLayoutIter *iter = pango_layout_get_iter(layout);
-        int baseline = pango_layout_iter_get_baseline(iter);
-        pango_layout_iter_free(iter);
-        *descent = *y - PANGO_PIXELS(baseline);
-    }
-    if (externalLeading) (*externalLeading) = 0;  // ??
+void wxWindowGTK::DoGetTextExtent( const wxString& string,
+                                   int *x,
+                                   int *y,
+                                   int *descent,
+                                   int *externalLeading,
+                                   const wxFont *theFont ) const
+{
+    // ensure we work with a valid font
+    wxFont fontToUse;
+    if ( !theFont || !theFont->IsOk() )
+        fontToUse = GetFont();
+    else
+        fontToUse = *theFont;
 
 
-    g_object_unref (layout);
+    wxCHECK_RET( fontToUse.IsOk(), wxT("invalid font") );
+
+    const wxWindow* win = static_cast<const wxWindow*>(this);
+    wxTextMeasure txm(win, &fontToUse);
+    txm.GetTextExtent(string, x, y, descent, externalLeading);
 }
 
 void wxWindowGTK::GTKDisableFocusOutEvent()
 }
 
 void wxWindowGTK::GTKDisableFocusOutEvent()
@@ -3014,8 +3238,8 @@ bool wxWindowGTK::GTKHandleFocusIn()
                "handling focus_in event for %s(%p, %s)",
                GetClassInfo()->GetClassName(), this, GetLabel());
 
                "handling focus_in event for %s(%p, %s)",
                GetClassInfo()->GetClassName(), this, GetLabel());
 
-    if (m_imData)
-        gtk_im_context_focus_in(m_imData->context);
+    if (m_imContext)
+        gtk_im_context_focus_in(m_imContext);
 
     gs_currentFocus = this;
     gs_pendingFocus = NULL;
 
     gs_currentFocus = this;
     gs_pendingFocus = NULL;
@@ -3077,8 +3301,8 @@ void wxWindowGTK::GTKHandleFocusOutNoDeferring()
                "handling focus_out event for %s(%p, %s)",
                GetClassInfo()->GetClassName(), this, GetLabel());
 
                "handling focus_out event for %s(%p, %s)",
                GetClassInfo()->GetClassName(), this, GetLabel());
 
-    if (m_imData)
-        gtk_im_context_focus_out(m_imData->context);
+    if (m_imContext)
+        gtk_im_context_focus_out(m_imContext);
 
     if ( gs_currentFocus != this )
     {
 
     if ( gs_currentFocus != this )
     {
@@ -3108,6 +3332,7 @@ void wxWindowGTK::GTKHandleFocusOutNoDeferring()
 
     wxFocusEvent event( wxEVT_KILL_FOCUS, GetId() );
     event.SetEventObject( this );
 
     wxFocusEvent event( wxEVT_KILL_FOCUS, GetId() );
     event.SetEventObject( this );
+    event.SetWindow( FindFocus() );
     GTKProcessEvent( event );
 }
 
     GTKProcessEvent( event );
 }
 
@@ -3139,7 +3364,7 @@ void wxWindowGTK::SetFocus()
     // within its toplevel", i.e. returns true for one widget per TLW, not
     // globally) returns true immediately after grabbing focus,
     // GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
     // within its toplevel", i.e. returns true for one widget per TLW, not
     // globally) returns true immediately after grabbing focus,
     // GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
-    // has focus at the moment) takes affect only after the window is shown
+    // has focus at the moment) takes effect only after the window is shown
     // (if it was hidden at the moment of the call) or at the next event loop
     // iteration.
     //
     // (if it was hidden at the moment of the call) or at the next event loop
     // iteration.
     //
@@ -3151,17 +3376,17 @@ void wxWindowGTK::SetFocus()
     GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget;
 
     if ( GTK_IS_CONTAINER(widget) &&
     GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget;
 
     if ( GTK_IS_CONTAINER(widget) &&
-         !GTK_WIDGET_CAN_FOCUS(widget) )
+         !gtk_widget_get_can_focus(widget) )
     {
         wxLogTrace(TRACE_FOCUS,
     {
         wxLogTrace(TRACE_FOCUS,
-                   _T("Setting focus to a child of %s(%p, %s)"),
+                   wxT("Setting focus to a child of %s(%p, %s)"),
                    GetClassInfo()->GetClassName(), this, GetLabel().c_str());
         gtk_widget_child_focus(widget, GTK_DIR_TAB_FORWARD);
     }
     else
     {
         wxLogTrace(TRACE_FOCUS,
                    GetClassInfo()->GetClassName(), this, GetLabel().c_str());
         gtk_widget_child_focus(widget, GTK_DIR_TAB_FORWARD);
     }
     else
     {
         wxLogTrace(TRACE_FOCUS,
-                   _T("Setting focus to %s(%p, %s)"),
+                   wxT("Setting focus to %s(%p, %s)"),
                    GetClassInfo()->GetClassName(), this, GetLabel().c_str());
         gtk_widget_grab_focus(widget);
     }
                    GetClassInfo()->GetClassName(), this, GetLabel().c_str());
         gtk_widget_grab_focus(widget);
     }
@@ -3169,17 +3394,13 @@ void wxWindowGTK::SetFocus()
 
 void wxWindowGTK::SetCanFocus(bool canFocus)
 {
 
 void wxWindowGTK::SetCanFocus(bool canFocus)
 {
-    if ( canFocus )
-        GTK_WIDGET_SET_FLAGS(m_widget, GTK_CAN_FOCUS);
-    else
-        GTK_WIDGET_UNSET_FLAGS(m_widget, GTK_CAN_FOCUS);
+    wxCHECK_RET(m_widget, "invalid window");
+
+    gtk_widget_set_can_focus(m_widget, canFocus);
 
     if ( m_wxwindow && (m_widget != m_wxwindow) )
     {
 
     if ( m_wxwindow && (m_widget != m_wxwindow) )
     {
-        if ( canFocus )
-            GTK_WIDGET_SET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
-        else
-            GTK_WIDGET_UNSET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
+        gtk_widget_set_can_focus(m_wxwindow, canFocus);
     }
 }
 
     }
 }
 
@@ -3187,8 +3408,7 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
 {
     wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
 
 {
     wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
 
-    wxWindowGTK *oldParent = m_parent,
-             *newParent = (wxWindowGTK *)newParentBase;
+    wxWindowGTK * const newParent = (wxWindowGTK *)newParentBase;
 
     wxASSERT( GTK_IS_WIDGET(m_widget) );
 
 
     wxASSERT( GTK_IS_WIDGET(m_widget) );
 
@@ -3197,14 +3417,17 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
 
     wxASSERT( GTK_IS_WIDGET(m_widget) );
 
 
     wxASSERT( GTK_IS_WIDGET(m_widget) );
 
-    if (oldParent)
-        gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
+    // Notice that old m_parent pointer might be non-NULL here but the widget
+    // still not have any parent at GTK level if it's a notebook page that had
+    // been removed from the notebook so test this at GTK level and not wx one.
+    if ( GtkWidget *parentGTK = gtk_widget_get_parent(m_widget) )
+        gtk_container_remove(GTK_CONTAINER(parentGTK), m_widget);
 
     wxASSERT( GTK_IS_WIDGET(m_widget) );
 
     if (newParent)
     {
 
     wxASSERT( GTK_IS_WIDGET(m_widget) );
 
     if (newParent)
     {
-        if (GTK_WIDGET_VISIBLE (newParent->m_widget))
+        if (gtk_widget_get_visible (newParent->m_widget))
         {
             m_showOnIdle = true;
             gtk_widget_hide( m_widget );
         {
             m_showOnIdle = true;
             gtk_widget_hide( m_widget );
@@ -3255,7 +3478,7 @@ wxLayoutDirection wxWindowGTK::GTKGetLayout(GtkWidget *widget)
 /* static */
 void wxWindowGTK::GTKSetLayout(GtkWidget *widget, wxLayoutDirection dir)
 {
 /* static */
 void wxWindowGTK::GTKSetLayout(GtkWidget *widget, wxLayoutDirection dir)
 {
-    wxASSERT_MSG( dir != wxLayout_Default, _T("invalid layout direction") );
+    wxASSERT_MSG( dir != wxLayout_Default, wxT("invalid layout direction") );
 
     gtk_widget_set_direction(widget,
                              dir == wxLayout_RightToLeft ? GTK_TEXT_DIR_RTL
 
     gtk_widget_set_direction(widget,
                              dir == wxLayout_RightToLeft ? GTK_TEXT_DIR_RTL
@@ -3312,14 +3535,14 @@ bool wxWindowGTK::DoNavigateIn(int flags)
 {
     if ( flags & wxNavigationKeyEvent::WinChange )
     {
 {
     if ( flags & wxNavigationKeyEvent::WinChange )
     {
-        wxFAIL_MSG( _T("not implemented") );
+        wxFAIL_MSG( wxT("not implemented") );
 
         return false;
     }
     else // navigate inside the container
     {
         wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
 
         return false;
     }
     else // navigate inside the container
     {
         wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
-        wxCHECK_MSG( parent, false, _T("every window must have a TLW parent") );
+        wxCHECK_MSG( parent, false, wxT("every window must have a TLW parent") );
 
         GtkDirectionType dir;
         dir = flags & wxNavigationKeyEvent::IsForward ? GTK_DIR_TAB_FORWARD
 
         GtkDirectionType dir;
         dir = flags & wxNavigationKeyEvent::IsForward ? GTK_DIR_TAB_FORWARD
@@ -3328,7 +3551,7 @@ bool wxWindowGTK::DoNavigateIn(int flags)
         gboolean rc;
         g_signal_emit_by_name(parent->m_widget, "focus", dir, &rc);
 
         gboolean rc;
         g_signal_emit_by_name(parent->m_widget, "focus", dir, &rc);
 
-        return rc == TRUE;
+        return rc != 0;
     }
 }
 
     }
 }
 
@@ -3362,18 +3585,20 @@ void wxWindowGTK::RealizeTabOrder()
             {
                 wxWindowGTK *win = *i;
 
             {
                 wxWindowGTK *win = *i;
 
+                bool focusableFromKeyboard = win->AcceptsFocusFromKeyboard();
+
                 if ( mnemonicWindow )
                 {
                 if ( mnemonicWindow )
                 {
-                    if ( win->AcceptsFocusFromKeyboard() )
+                    if ( focusableFromKeyboard )
                     {
                         // wxComboBox et al. needs to focus on on a different
                         // widget than m_widget, so if the main widget isn't
                         // focusable try the connect widget
                         GtkWidget* w = win->m_widget;
                     {
                         // wxComboBox et al. needs to focus on on a different
                         // widget than m_widget, so if the main widget isn't
                         // focusable try the connect widget
                         GtkWidget* w = win->m_widget;
-                        if ( !GTK_WIDGET_CAN_FOCUS(w) )
+                        if ( !gtk_widget_get_can_focus(w) )
                         {
                             w = win->GetConnectWidget();
                         {
                             w = win->GetConnectWidget();
-                            if ( !GTK_WIDGET_CAN_FOCUS(w) )
+                            if ( !gtk_widget_get_can_focus(w) )
                                 w = NULL;
                         }
 
                                 w = NULL;
                         }
 
@@ -3389,7 +3614,8 @@ void wxWindowGTK::RealizeTabOrder()
                     mnemonicWindow = win;
                 }
 
                     mnemonicWindow = win;
                 }
 
-                chain = g_list_prepend(chain, win->m_widget);
+                if ( focusableFromKeyboard )
+                    chain = g_list_prepend(chain, win->m_widget);
             }
 
             chain = g_list_reverse(chain);
             }
 
             chain = g_list_reverse(chain);
@@ -3408,13 +3634,13 @@ void wxWindowGTK::Raise()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (m_wxwindow && m_wxwindow->window)
+    if (m_wxwindow && gtk_widget_get_window(m_wxwindow))
     {
     {
-        gdk_window_raise( m_wxwindow->window );
+        gdk_window_raise(gtk_widget_get_window(m_wxwindow));
     }
     }
-    else if (m_widget->window)
+    else if (gtk_widget_get_window(m_widget))
     {
     {
-        gdk_window_raise( m_widget->window );
+        gdk_window_raise(gtk_widget_get_window(m_widget));
     }
 }
 
     }
 }
 
@@ -3422,19 +3648,19 @@ void wxWindowGTK::Lower()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (m_wxwindow && m_wxwindow->window)
+    if (m_wxwindow && gtk_widget_get_window(m_wxwindow))
     {
     {
-        gdk_window_lower( m_wxwindow->window );
+        gdk_window_lower(gtk_widget_get_window(m_wxwindow));
     }
     }
-    else if (m_widget->window)
+    else if (gtk_widget_get_window(m_widget))
     {
     {
-        gdk_window_lower( m_widget->window );
+        gdk_window_lower(gtk_widget_get_window(m_widget));
     }
 }
 
 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
 {
     }
 }
 
 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
 {
-    if ( !wxWindowBase::SetCursor(cursor.Ok() ? cursor : *wxSTANDARD_CURSOR) )
+    if ( !wxWindowBase::SetCursor(cursor.IsOk() ? cursor : *wxSTANDARD_CURSOR) )
         return false;
 
     GTKUpdateCursor();
         return false;
 
     GTKUpdateCursor();
@@ -3442,50 +3668,60 @@ bool wxWindowGTK::SetCursor( const wxCursor &cursor )
     return true;
 }
 
     return true;
 }
 
-void wxWindowGTK::GTKUpdateCursor()
+void wxWindowGTK::GTKUpdateCursor(bool update_self /*=true*/, bool recurse /*=true*/)
 {
 {
-    wxCursor cursor(g_globalCursor.Ok() ? g_globalCursor : GetCursor());
-    if ( cursor.Ok() )
+    if (update_self)
     {
     {
-        wxArrayGdkWindows windowsThis;
-        GdkWindow * const winThis = GTKGetWindow(windowsThis);
-        if ( winThis )
-        {
-            gdk_window_set_cursor(winThis, cursor.GetCursor());
-        }
-        else
+        wxCursor cursor(g_globalCursor.IsOk() ? g_globalCursor : GetCursor());
+        if ( cursor.IsOk() )
         {
         {
-            const size_t count = windowsThis.size();
-            for ( size_t n = 0; n < count; n++ )
+            wxArrayGdkWindows windowsThis;
+            GdkWindow* window = GTKGetWindow(windowsThis);
+            if (window)
+                gdk_window_set_cursor( window, cursor.GetCursor() );
+            else
             {
             {
-                GdkWindow *win = windowsThis[n];
-                if ( !win )
+                const size_t count = windowsThis.size();
+                for ( size_t n = 0; n < count; n++ )
                 {
                 {
-                    wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
-                    continue;
+                    GdkWindow *win = windowsThis[n];
+                    // It can be zero if the window has not been realized yet.
+                    if ( win )
+                    {
+                        gdk_window_set_cursor(win, cursor.GetCursor());
+                    }
                 }
                 }
-
-                gdk_window_set_cursor(win, cursor.GetCursor());
             }
         }
     }
             }
         }
     }
+
+    if (recurse)
+    {
+        for (wxWindowList::iterator it = GetChildren().begin(); it != GetChildren().end(); ++it)
+        {
+            (*it)->GTKUpdateCursor( true );
+        }
+    }
 }
 
 void wxWindowGTK::WarpPointer( int x, int y )
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
 }
 
 void wxWindowGTK::WarpPointer( int x, int y )
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    // We provide this function ourselves as it is
-    // missing in GDK (top of this file).
-
-    GdkWindow *window = NULL;
-    if (m_wxwindow)
-        window = m_wxwindow->window;
-    else
-        window = GetConnectWidget()->window;
-
-    if (window)
-        gdk_window_warp_pointer( window, x, y );
+    ClientToScreen(&x, &y);
+    GdkDisplay* display = gtk_widget_get_display(m_widget);
+    GdkScreen* screen = gtk_widget_get_screen(m_widget);
+#ifdef __WXGTK3__
+    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
 }
 
 wxWindowGTK::ScrollDir wxWindowGTK::ScrollDirFromRange(GtkRange *range) const
@@ -3497,7 +3733,7 @@ wxWindowGTK::ScrollDir wxWindowGTK::ScrollDirFromRange(GtkRange *range) const
             return (ScrollDir)dir;
     }
 
             return (ScrollDir)dir;
     }
 
-    wxFAIL_MSG( _T("event from unknown scrollbar received") );
+    wxFAIL_MSG( wxT("event from unknown scrollbar received") );
 
     return ScrollDir_Max;
 }
 
     return ScrollDir_Max;
 }
@@ -3508,14 +3744,14 @@ bool wxWindowGTK::DoScrollByUnits(ScrollDir dir, ScrollUnit unit, int units)
     GtkRange* range = m_scrollBar[dir];
     if ( range && units )
     {
     GtkRange* range = m_scrollBar[dir];
     if ( range && units )
     {
-        GtkAdjustment* adj = range->adjustment;
-        gdouble inc = unit == ScrollUnit_Line ? adj->step_increment
-                                              : adj->page_increment;
+        GtkAdjustment* adj = gtk_range_get_adjustment(range);
+        double inc = unit == ScrollUnit_Line ? gtk_adjustment_get_step_increment(adj)
+                                             : gtk_adjustment_get_page_increment(adj);
 
 
-        const int posOld = int(adj->value + 0.5);
+        const int posOld = wxRound(gtk_adjustment_get_value(adj));
         gtk_range_set_value(range, posOld + units*inc);
 
         gtk_range_set_value(range, posOld + units*inc);
 
-        changed = int(adj->value + 0.5) != posOld;
+        changed = wxRound(gtk_adjustment_get_value(adj)) != posOld;
     }
 
     return changed;
     }
 
     return changed;
@@ -3534,56 +3770,48 @@ bool wxWindowGTK::ScrollPages(int pages)
 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground),
                           const wxRect *rect)
 {
 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground),
                           const wxRect *rect)
 {
-    if ( !m_widget )
-    {
-        // it is valid to call Refresh() for a window which hasn't been created
-        // yet, it simply doesn't do anything in this case
-        return;
-    }
-
-    if (!m_wxwindow)
+    if (m_wxwindow)
     {
     {
-        if (rect)
-            gtk_widget_queue_draw_area( m_widget, rect->x, rect->y, rect->width, rect->height );
-        else
-            gtk_widget_queue_draw( m_widget );
+        if (gtk_widget_get_mapped(m_wxwindow))
+        {
+            GdkWindow* window = gtk_widget_get_window(m_wxwindow);
+            if (rect)
+            {
+                GdkRectangle r = { rect->x, rect->y, rect->width, rect->height };
+                if (GetLayoutDirection() == wxLayout_RightToLeft)
+                    r.x = gdk_window_get_width(window) - r.x - rect->width;
+                gdk_window_invalidate_rect(window, &r, true);
+            }
+            else
+                gdk_window_invalidate_rect(window, NULL, true);
+        }
     }
     }
-    else
+    else if (m_widget)
     {
     {
-        // Just return if the widget or one of its ancestors isn't mapped
-        GtkWidget *w;
-        for (w = m_wxwindow; w != NULL; w = w->parent)
-            if (!GTK_WIDGET_MAPPED (w))
-                return;
-
-        if (rect)
+        if (gtk_widget_get_mapped(m_widget))
         {
         {
-            int x = rect->x;
-            if (GetLayoutDirection() == wxLayout_RightToLeft)
-                x = GetClientSize().x - x - rect->width;
-            GdkRectangle r;
-            r.x = rect->x;
-            r.y = rect->y;
-            r.width = rect->width;
-            r.height = rect->height;
-            gdk_window_invalidate_rect( m_wxwindow->window, &r, TRUE );
+            if (rect)
+                gtk_widget_queue_draw_area(m_widget, rect->x, rect->y, rect->width, rect->height);
+            else
+                gtk_widget_queue_draw(m_widget);
         }
         }
-        else
-            gdk_window_invalidate_rect( m_wxwindow->window, NULL, TRUE );
     }
 }
 
 void wxWindowGTK::Update()
 {
     }
 }
 
 void wxWindowGTK::Update()
 {
-    if (m_widget && m_widget->window)
+    if (m_widget && gtk_widget_get_mapped(m_widget))
     {
         GdkDisplay* display = gtk_widget_get_display(m_widget);
         // Flush everything out to the server, and wait for it to finish.
         // This ensures nothing will overwrite the drawing we are about to do.
         gdk_display_sync(display);
 
     {
         GdkDisplay* display = gtk_widget_get_display(m_widget);
         // Flush everything out to the server, and wait for it to finish.
         // This ensures nothing will overwrite the drawing we are about to do.
         gdk_display_sync(display);
 
-        gdk_window_process_updates(m_widget->window, TRUE);
-        
+        GdkWindow* window = GTKGetDrawingWindow();
+        if (window == NULL)
+            window = gtk_widget_get_window(m_widget);
+        gdk_window_process_updates(window, true);
+
         // Flush again, but no need to wait for it to finish
         gdk_display_flush(display);
     }
         // Flush again, but no need to wait for it to finish
         gdk_display_flush(display);
     }
@@ -3602,14 +3830,23 @@ bool wxWindowGTK::DoIsExposed( int x, int y, int w, int h ) const
         return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
 }
 
         return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
 }
 
-void wxWindowGTK::GtkSendPaintEvents()
+#ifdef __WXGTK3__
+void wxWindowGTK::GTKSendPaintEvents(cairo_t* cr)
+#else
+void wxWindowGTK::GTKSendPaintEvents(const GdkRegion* region)
+#endif
 {
 {
-    if (!m_wxwindow)
-    {
-        m_updateRegion.Clear();
-        return;
-    }
-
+#ifdef __WXGTK3__
+    m_paintContext = cr;
+    double x1, y1, x2, y2;
+    cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+    m_updateRegion = wxRegion(int(x1), int(y1), int(x2 - x1), int(y2 - y1));
+#else // !__WXGTK3__
+    m_updateRegion = wxRegion(region);
+#if wxGTK_HAS_COMPOSITING_SUPPORT
+    cairo_t* cr = NULL;
+#endif
+#endif // !__WXGTK3__
     // Clip to paint region in wxClientDC
     m_clipPaintRegion = true;
 
     // Clip to paint region in wxClientDC
     m_clipPaintRegion = true;
 
@@ -3620,8 +3857,7 @@ void wxWindowGTK::GtkSendPaintEvents()
         // Transform m_updateRegion under RTL
         m_updateRegion.Clear();
 
         // Transform m_updateRegion under RTL
         m_updateRegion.Clear();
 
-        gint width;
-        gdk_drawable_get_size(m_wxwindow->window, &width, NULL);
+        const int width = gdk_window_get_width(GTKGetDrawingWindow());
 
         wxRegionIterator upd( m_nativeUpdateRegion );
         while (upd)
 
         wxRegionIterator upd( m_nativeUpdateRegion );
         while (upd)
@@ -3639,54 +3875,95 @@ void wxWindowGTK::GtkSendPaintEvents()
         }
     }
 
         }
     }
 
-    if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
+    switch ( GetBackgroundStyle() )
     {
     {
-        // find ancestor from which to steal background
-        wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
-        if (!parent)
-            parent = (wxWindow*)this;
+        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)
+#ifndef __WXGTK3__
+                cr = gdk_cairo_create(m_wxwindow->window);
+                gdk_cairo_region(cr, m_nativeUpdateRegion.GetRegion());
+                cairo_clip(cr);
+#endif
+                cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+                cairo_paint(cr);
+                cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+#ifndef __WXGTK3__
+                cairo_surface_flush(cairo_get_target(cr));
+#endif
+            }
+#endif // wxGTK_HAS_COMPOSITING_SUPPORT
+            break;
 
 
-        if (GTK_WIDGET_MAPPED(parent->m_widget))
-        {
-            wxRegionIterator upd( m_nativeUpdateRegion );
-            while (upd)
+        case wxBG_STYLE_ERASE:
             {
             {
-                GdkRectangle rect;
-                rect.x = upd.GetX();
-                rect.y = upd.GetY();
-                rect.width = upd.GetWidth();
-                rect.height = upd.GetHeight();
-
-                gtk_paint_flat_box( parent->m_widget->style,
-                            m_wxwindow->window,
-                            (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
-                            GTK_SHADOW_NONE,
-                            &rect,
-                            parent->m_widget,
-                            (char *)"base",
-                            0, 0, -1, -1 );
-
-                ++upd;
+#ifdef __WXGTK3__
+                wxGTKCairoDC dc(cr);
+#else
+                wxWindowDC dc( (wxWindow*)this );
+                dc.SetDeviceClippingRegion( m_updateRegion );
+
+                // Work around gtk-qt <= 0.60 bug whereby the window colour
+                // remains grey
+                if ( UseBgCol() &&
+                        wxSystemOptions::
+                            GetOptionInt("gtk.window.force-background-colour") )
+                {
+                    dc.SetBackground(GetBackgroundColour());
+                    dc.Clear();
+                }
+#endif // !__WXGTK3__
+                wxEraseEvent erase_event( GetId(), &dc );
+                erase_event.SetEventObject( this );
+
+                if ( HandleWindowEvent(erase_event) )
+                {
+                    // background erased, don't do it again
+                    break;
+                }
             }
             }
-        }
-    }
-    else
-    {
-        wxWindowDC dc( (wxWindow*)this );
-        dc.SetDeviceClippingRegion( m_updateRegion );
+            // fall through
 
 
-        // Work around gtk-qt <= 0.60 bug whereby the window colour
-        // remains grey
-        if (GetBackgroundStyle() == wxBG_STYLE_COLOUR && GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
-        {
-            dc.SetBackground(wxBrush(GetBackgroundColour()));
-            dc.Clear();
-        }
+        case wxBG_STYLE_SYSTEM:
+            if ( GetThemeEnabled() )
+            {
+                GdkWindow* gdkWindow = GTKGetDrawingWindow();
+                const int w = gdk_window_get_width(gdkWindow);
+                const int h = gdk_window_get_height(gdkWindow);
+#ifdef __WXGTK3__
+                GtkStyleContext* sc = gtk_widget_get_style_context(m_wxwindow);
+                gtk_render_background(sc, cr, 0, 0, w, h);
+#else
+                // find ancestor from which to steal background
+                wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
+                if (!parent)
+                    parent = (wxWindow*)this;
+                GdkRectangle rect;
+                m_nativeUpdateRegion.GetBox(rect.x, rect.y, rect.width, rect.height);
+                gtk_paint_flat_box(gtk_widget_get_style(parent->m_widget),
+                                    gdkWindow,
+                                    gtk_widget_get_state(m_wxwindow),
+                                    GTK_SHADOW_NONE,
+                                    &rect,
+                                    parent->m_widget,
+                                    (char *)"base",
+                                    0, 0, w, h);
+#endif // !__WXGTK3__
+            }
+            break;
 
 
-        wxEraseEvent erase_event( GetId(), &dc );
-        erase_event.SetEventObject( this );
+        case wxBG_STYLE_PAINT:
+            // nothing to do: window will be painted over in EVT_PAINT
+            break;
 
 
-        HandleWindowEvent(erase_event);
+        default:
+            wxFAIL_MSG( "unsupported background style" );
     }
 
     wxNcPaintEvent nc_paint_event( GetId() );
     }
 
     wxNcPaintEvent nc_paint_event( GetId() );
@@ -3697,8 +3974,46 @@ void wxWindowGTK::GtkSendPaintEvents()
     paint_event.SetEventObject( this );
     HandleWindowEvent( paint_event );
 
     paint_event.SetEventObject( this );
     HandleWindowEvent( paint_event );
 
-    m_clipPaintRegion = false;
+#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)
+            {
+#ifndef __WXGTK3__
+                if (cr == NULL)
+                {
+                    cr = gdk_cairo_create(m_wxwindow->window);
+                    gdk_cairo_region(cr, m_nativeUpdateRegion.GetRegion());
+                    cairo_clip(cr);
+                }
+#endif // !__WXGTK3__
+                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);
+            }
+        }
+#ifndef __WXGTK3__
+        if (cr)
+            cairo_destroy(cr);
+#endif
+    }
+#endif // wxGTK_HAS_COMPOSITING_SUPPORT
+
+    m_clipPaintRegion = false;
+#ifdef __WXGTK3__
+    m_paintContext = NULL;
+#endif
     m_updateRegion.Clear();
     m_nativeUpdateRegion.Clear();
 }
     m_updateRegion.Clear();
     m_nativeUpdateRegion.Clear();
 }
@@ -3713,7 +4028,7 @@ void wxWindowGTK::SetDoubleBuffered( bool on )
 
 bool wxWindowGTK::IsDoubleBuffered() const
 {
 
 bool wxWindowGTK::IsDoubleBuffered() const
 {
-    return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow );
+    return gtk_widget_get_double_buffered( m_wxwindow ) != 0;
 }
 
 void wxWindowGTK::ClearBackground()
 }
 
 void wxWindowGTK::ClearBackground()
@@ -3724,57 +4039,65 @@ void wxWindowGTK::ClearBackground()
 #if wxUSE_TOOLTIPS
 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
 {
 #if wxUSE_TOOLTIPS
 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
 {
-    wxWindowBase::DoSetToolTip(tip);
+    if (m_tooltip != tip)
+    {
+        wxWindowBase::DoSetToolTip(tip);
 
 
-    if (m_tooltip)
-        m_tooltip->GTKApply( (wxWindow *)this );
+        if (m_tooltip)
+            m_tooltip->GTKSetWindow(static_cast<wxWindow*>(this));
+        else
+            GTKApplyToolTip(NULL);
+    }
 }
 
 }
 
-void wxWindowGTK::GTKApplyToolTip( GtkTooltips *tips, const gchar *tip )
+void wxWindowGTK::GTKApplyToolTip(const char* tip)
 {
 {
-    gtk_tooltips_set_tip(tips, GetConnectWidget(), tip, NULL);
+    wxToolTip::GTKApply(GetConnectWidget(), tip);
 }
 #endif // wxUSE_TOOLTIPS
 
 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
 {
 }
 #endif // wxUSE_TOOLTIPS
 
 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
 {
-    wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
-
     if (!wxWindowBase::SetBackgroundColour(colour))
         return false;
 
     if (!wxWindowBase::SetBackgroundColour(colour))
         return false;
 
-    if (colour.Ok())
+    if (m_widget)
     {
     {
-        // We need the pixel value e.g. for background clearing.
-        m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
-    }
+#ifndef __WXGTK3__
+        if (colour.IsOk())
+        {
+            // We need the pixel value e.g. for background clearing.
+            m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
+        }
+#endif
 
 
-    // apply style change (forceStyle=true so that new style is applied
-    // even if the bg colour changed from valid to wxNullColour)
-    if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
+        // apply style change (forceStyle=true so that new style is applied
+        // even if the bg colour changed from valid to wxNullColour)
         GTKApplyWidgetStyle(true);
         GTKApplyWidgetStyle(true);
+    }
 
     return true;
 }
 
 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
 {
 
     return true;
 }
 
 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
 {
-    wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
-
     if (!wxWindowBase::SetForegroundColour(colour))
     if (!wxWindowBase::SetForegroundColour(colour))
-    {
         return false;
         return false;
-    }
 
 
-    if (colour.Ok())
+    if (m_widget)
     {
     {
-        // We need the pixel value e.g. for background clearing.
-        m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
-    }
+#ifndef __WXGTK3__
+        if (colour.IsOk())
+        {
+            // We need the pixel value e.g. for background clearing.
+            m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
+        }
+#endif
 
 
-    // apply style change (forceStyle=true so that new style is applied
-    // even if the bg colour changed from valid to wxNullColour):
-    GTKApplyWidgetStyle(true);
+        // apply style change (forceStyle=true so that new style is applied
+        // even if the bg colour changed from valid to wxNullColour):
+        GTKApplyWidgetStyle(true);
+    }
 
     return true;
 }
 
     return true;
 }
@@ -3784,19 +4107,12 @@ PangoContext *wxWindowGTK::GTKGetPangoDefaultContext()
     return gtk_widget_get_pango_context( m_widget );
 }
 
     return gtk_widget_get_pango_context( m_widget );
 }
 
-GtkRcStyle *wxWindowGTK::GTKCreateWidgetStyle(bool forceStyle)
+#ifndef __WXGTK3__
+GtkRcStyle* wxWindowGTK::GTKCreateWidgetStyle()
 {
 {
-    // do we need to apply any changes at all?
-    if ( !forceStyle &&
-         !m_font.Ok() &&
-         !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
-    {
-        return NULL;
-    }
-
     GtkRcStyle *style = gtk_rc_style_new();
 
     GtkRcStyle *style = gtk_rc_style_new();
 
-    if ( m_font.Ok() )
+    if ( m_font.IsOk() )
     {
         style->font_desc =
             pango_font_description_copy( m_font.GetNativeFontInfo()->description );
     {
         style->font_desc =
             pango_font_description_copy( m_font.GetNativeFontInfo()->description );
@@ -3807,7 +4123,7 @@ GtkRcStyle *wxWindowGTK::GTKCreateWidgetStyle(bool forceStyle)
         flagsActive = 0,
         flagsInsensitive = 0;
 
         flagsActive = 0,
         flagsInsensitive = 0;
 
-    if ( m_foregroundColour.Ok() )
+    if ( m_foregroundColour.IsOk() )
     {
         const GdkColor *fg = m_foregroundColour.GetColor();
 
     {
         const GdkColor *fg = m_foregroundColour.GetColor();
 
@@ -3824,7 +4140,7 @@ GtkRcStyle *wxWindowGTK::GTKCreateWidgetStyle(bool forceStyle)
         flagsActive |= GTK_RC_FG | GTK_RC_TEXT;
     }
 
         flagsActive |= GTK_RC_FG | GTK_RC_TEXT;
     }
 
-    if ( m_backgroundColour.Ok() )
+    if ( m_backgroundColour.IsOk() )
     {
         const GdkColor *bg = m_backgroundColour.GetColor();
 
     {
         const GdkColor *bg = m_backgroundColour.GetColor();
 
@@ -3852,14 +4168,36 @@ GtkRcStyle *wxWindowGTK::GTKCreateWidgetStyle(bool forceStyle)
 
     return style;
 }
 
     return style;
 }
+#endif // !__WXGTK3__
 
 void wxWindowGTK::GTKApplyWidgetStyle(bool forceStyle)
 {
 
 void wxWindowGTK::GTKApplyWidgetStyle(bool forceStyle)
 {
-    GtkRcStyle *style = GTKCreateWidgetStyle(forceStyle);
-    if ( style )
+    if (forceStyle || m_font.IsOk() ||
+        m_foregroundColour.IsOk() || m_backgroundColour.IsOk())
     {
     {
+#ifdef __WXGTK3__
+        if (m_backgroundColour.IsOk())
+        {
+            // create a GtkStyleProvider to override "background-image"
+            if (m_styleProvider == NULL)
+                m_styleProvider = GTK_STYLE_PROVIDER(gtk_css_provider_new());
+            const char css[] =
+                "*{background-image:-gtk-gradient(linear,0 0,0 1,"
+                "from(rgba(%u,%u,%u,%g)),to(rgba(%u,%u,%u,%g)))}";
+            char buf[sizeof(css) + 20];
+            const unsigned r = m_backgroundColour.Red();
+            const unsigned g = m_backgroundColour.Green();
+            const unsigned b = m_backgroundColour.Blue();
+            const double a = m_backgroundColour.Alpha() / 255.0;
+            g_snprintf(buf, sizeof(buf), css, r, g, b, a, r, g, b, a);
+            gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(m_styleProvider), buf, -1, NULL);
+        }
+        DoApplyWidgetStyle(NULL);
+#else
+        GtkRcStyle* style = GTKCreateWidgetStyle();
         DoApplyWidgetStyle(style);
         DoApplyWidgetStyle(style);
-        gtk_rc_style_unref(style);
+        g_object_unref(style);
+#endif
     }
 
     // Style change may affect GTK+'s size calculation:
     }
 
     // Style change may affect GTK+'s size calculation:
@@ -3868,57 +4206,120 @@ void wxWindowGTK::GTKApplyWidgetStyle(bool forceStyle)
 
 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
 {
 
 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
 {
-    wxSuspendStyleEvents s(static_cast<wxWindow*>(this));
+    GtkWidget* widget = m_wxwindow ? m_wxwindow : m_widget;
 
 
-    if (m_wxwindow)
-        gtk_widget_modify_style(m_wxwindow, style);
-    else
-        gtk_widget_modify_style(m_widget, style);
+    // block the signal temporarily to avoid sending
+    // wxSysColourChangedEvents when we change the colours ourselves
+    bool unblock = false;
+    if (m_wxwindow && IsTopLevel())
+    {
+        unblock = true;
+        g_signal_handlers_block_by_func(
+            m_wxwindow, (void*)style_updated, this);
+    }
+
+    GTKApplyStyle(widget, style);
+
+    if (unblock)
+    {
+        g_signal_handlers_unblock_by_func(
+            m_wxwindow, (void*)style_updated, this);
+    }
+}
+
+void wxWindowGTK::GTKApplyStyle(GtkWidget* widget, GtkRcStyle* WXUNUSED_IN_GTK3(style))
+{
+#ifdef __WXGTK3__
+    const PangoFontDescription* pfd = NULL;
+    if (m_font.IsOk())
+        pfd = pango_font_description_copy(m_font.GetNativeFontInfo()->description);
+    gtk_widget_override_font(widget, pfd);
+    gtk_widget_override_color(widget, GTK_STATE_FLAG_NORMAL, m_foregroundColour);
+    gtk_widget_override_background_color(widget, GTK_STATE_FLAG_NORMAL, m_backgroundColour);
+
+    // setting background color has no effect with some themes when the widget style
+    // has a "background-image" property, so we need to override that as well
+
+    GtkStyleContext* context = gtk_widget_get_style_context(widget);
+    if (m_styleProvider)
+        gtk_style_context_remove_provider(context, m_styleProvider);
+    cairo_pattern_t* pattern = NULL;
+    if (m_backgroundColour.IsOk())
+    {
+        gtk_style_context_get(context,
+            GTK_STATE_FLAG_NORMAL, "background-image", &pattern, NULL);
+    }
+    if (pattern)
+    {
+        cairo_pattern_destroy(pattern);
+        gtk_style_context_add_provider(context,
+            m_styleProvider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+    }
+#else
+    gtk_widget_modify_style(widget, style);
+#endif
 }
 
 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
 {
 }
 
 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
 {
-    wxWindowBase::SetBackgroundStyle(style);
+    if (!wxWindowBase::SetBackgroundStyle(style))
+        return false;
 
 
-    if (style == wxBG_STYLE_CUSTOM)
+#ifndef __WXGTK3__
+    GdkWindow *window;
+    if ((style == wxBG_STYLE_PAINT || style == wxBG_STYLE_TRANSPARENT) &&
+        (window = GTKGetDrawingWindow()))
     {
     {
-        GdkWindow *window;
-        if ( m_wxwindow )
-        {
-            window = m_wxwindow->window;
-        }
-        else
-        {
-            GtkWidget * const w = GetConnectWidget();
-            window = w ? w->window : NULL;
-        }
+        gdk_window_set_back_pixmap(window, NULL, false);
+    }
+#endif // !__WXGTK3__
 
 
-        if (window)
+    return true;
+}
+
+bool wxWindowGTK::IsTransparentBackgroundSupported(wxString* reason) const
+{
+#if wxGTK_HAS_COMPOSITING_SUPPORT
+#ifndef __WXGTK3__
+    if (gtk_check_version(wxGTK_VERSION_REQUIRED_FOR_COMPOSITING) != NULL)
+    {
+        if (reason)
         {
         {
-            // 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
-            m_needsStyleChange = false;
+            *reason = _("GTK+ installed on this machine is too old to "
+                        "support screen compositing, please install "
+                        "GTK+ 2.12 or later.");
         }
         }
-        else // window not realized yet
+
+        return false;
+    }
+#endif // !__WXGTK3__
+
+    // 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)
         {
         {
-            // Do in OnIdle, because the window is not yet available
-            m_needsStyleChange = true;
+            *reason = _("Compositing not supported by this system, "
+                        "please enable it in your Window Manager.");
         }
 
         }
 
-        // Don't apply widget style, or we get a grey background
+        return false;
     }
     }
-    else
+
+    return true;
+#else
+    if (reason)
     {
     {
-        // apply style change (forceStyle=true so that new style is applied
-        // even if the bg colour changed from valid to wxNullColour):
-        GTKApplyWidgetStyle(true);
+        *reason = _("This program was compiled with a too old version of GTK+, "
+                    "please rebuild with GTK+ 2.12 or newer.");
     }
     }
-    return true;
+
+    return false;
+#endif // wxGTK_HAS_COMPOSITING_SUPPORT/!wxGTK_HAS_COMPOSITING_SUPPORT
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -3927,23 +4328,6 @@ bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
 
 #if wxUSE_MENUS_NATIVE
 
 
 #if wxUSE_MENUS_NATIVE
 
-static void SetInvokingWindow( wxMenu *menu, wxWindow* win )
-{
-    menu->SetInvokingWindow( win );
-
-    wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
-    while (node)
-    {
-        wxMenuItem *menuitem = node->GetData();
-        if (menuitem->IsSubMenu())
-        {
-            SetInvokingWindow( menuitem->GetSubMenu(), win );
-        }
-
-        node = node->GetNext();
-    }
-}
-
 extern "C" {
 static
 void wxPopupMenuPositionCallback( GtkMenu *menu,
 extern "C" {
 static
 void wxPopupMenuPositionCallback( GtkMenu *menu,
@@ -3953,7 +4337,11 @@ void wxPopupMenuPositionCallback( GtkMenu *menu,
 {
     // ensure that the menu appears entirely on screen
     GtkRequisition req;
 {
     // ensure that the menu appears entirely on screen
     GtkRequisition req;
+#ifdef __WXGTK3__
+    gtk_widget_get_preferred_size(GTK_WIDGET(menu), &req, NULL);
+#else
     gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
     gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
+#endif
 
     wxSize sizeScreen = wxGetDisplaySize();
     wxPoint *pos = (wxPoint*)user_data;
 
     wxSize sizeScreen = wxGetDisplaySize();
     wxPoint *pos = (wxPoint*)user_data;
@@ -3970,10 +4358,6 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
 {
     wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
 
 {
     wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
 
-    wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
-
-    SetInvokingWindow( menu, this );
-
     menu->UpdateUI();
 
     wxPoint pos;
     menu->UpdateUI();
 
     wxPoint pos;
@@ -4003,6 +4387,13 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
                   gtk_get_current_event_time()
                 );
 
                   gtk_get_current_event_time()
                 );
 
+    // it is possible for gtk_menu_popup() to fail
+    if (!gtk_widget_get_visible(GTK_WIDGET(menu->m_menu)))
+    {
+        menu->m_popupShown = false;
+        return false;
+    }
+
     while (menu->m_popupShown)
     {
         gtk_main_iteration();
     while (menu->m_popupShown)
     {
         gtk_main_iteration();
@@ -4050,19 +4441,20 @@ bool wxWindowGTK::GTKIsOwnWindow(GdkWindow *window) const
 
 GdkWindow *wxWindowGTK::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
 {
 
 GdkWindow *wxWindowGTK::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
 {
-    return m_wxwindow ? m_wxwindow->window : m_widget->window;
+    return m_wxwindow ? GTKGetDrawingWindow() : gtk_widget_get_window(m_widget);
 }
 
 bool wxWindowGTK::SetFont( const wxFont &font )
 {
 }
 
 bool wxWindowGTK::SetFont( const wxFont &font )
 {
-    wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
-
     if (!wxWindowBase::SetFont(font))
         return false;
 
     if (!wxWindowBase::SetFont(font))
         return false;
 
-    // apply style change (forceStyle=true so that new style is applied
-    // even if the font changed from valid to wxNullFont):
-    GTKApplyWidgetStyle(true);
+    if (m_widget)
+    {
+        // apply style change (forceStyle=true so that new style is applied
+        // even if the font changed from valid to wxNullFont):
+        GTKApplyWidgetStyle(true);
+    }
 
     return true;
 }
 
     return true;
 }
@@ -4073,25 +4465,35 @@ void wxWindowGTK::DoCaptureMouse()
 
     GdkWindow *window = NULL;
     if (m_wxwindow)
 
     GdkWindow *window = NULL;
     if (m_wxwindow)
-        window = m_wxwindow->window;
+        window = GTKGetDrawingWindow();
     else
     else
-        window = GetConnectWidget()->window;
+        window = gtk_widget_get_window(GetConnectWidget());
 
 
-    wxCHECK_RET( window, _T("CaptureMouse() failed") );
+    wxCHECK_RET( window, wxT("CaptureMouse() failed") );
 
     const wxCursor* cursor = &m_cursor;
 
     const wxCursor* cursor = &m_cursor;
-    if (!cursor->Ok())
+    if (!cursor->IsOk())
         cursor = wxSTANDARD_CURSOR;
 
         cursor = wxSTANDARD_CURSOR;
 
+    const GdkEventMask mask = GdkEventMask(
+        GDK_BUTTON_PRESS_MASK |
+        GDK_BUTTON_RELEASE_MASK |
+        GDK_POINTER_MOTION_HINT_MASK |
+        GDK_POINTER_MOTION_MASK);
+#ifdef __WXGTK3__
+    GdkDisplay* display = gdk_window_get_display(window);
+    GdkDeviceManager* manager = gdk_display_get_device_manager(display);
+    GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
+    gdk_device_grab(
+        device, window, GDK_OWNERSHIP_NONE, false, mask,
+        cursor->GetCursor(), unsigned(GDK_CURRENT_TIME));
+#else
     gdk_pointer_grab( window, FALSE,
     gdk_pointer_grab( window, FALSE,
-                      (GdkEventMask)
-                         (GDK_BUTTON_PRESS_MASK |
-                          GDK_BUTTON_RELEASE_MASK |
-                          GDK_POINTER_MOTION_HINT_MASK |
-                          GDK_POINTER_MOTION_MASK),
+                      mask,
                       NULL,
                       cursor->GetCursor(),
                       (guint32)GDK_CURRENT_TIME );
                       NULL,
                       cursor->GetCursor(),
                       (guint32)GDK_CURRENT_TIME );
+#endif
     g_captureWindow = this;
     g_captureWindowHasMouse = true;
 }
     g_captureWindow = this;
     g_captureWindowHasMouse = true;
 }
@@ -4106,14 +4508,21 @@ void wxWindowGTK::DoReleaseMouse()
 
     GdkWindow *window = NULL;
     if (m_wxwindow)
 
     GdkWindow *window = NULL;
     if (m_wxwindow)
-        window = m_wxwindow->window;
+        window = GTKGetDrawingWindow();
     else
     else
-        window = GetConnectWidget()->window;
+        window = gtk_widget_get_window(GetConnectWidget());
 
     if (!window)
         return;
 
 
     if (!window)
         return;
 
+#ifdef __WXGTK3__
+    GdkDisplay* display = gdk_window_get_display(window);
+    GdkDeviceManager* manager = gdk_display_get_device_manager(display);
+    GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
+    gdk_device_ungrab(device, unsigned(GDK_CURRENT_TIME));
+#else
     gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
     gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
+#endif
 }
 
 void wxWindowGTK::GTKReleaseMouseAndNotify()
 }
 
 void wxWindowGTK::GTKReleaseMouseAndNotify()
@@ -4143,7 +4552,7 @@ void wxWindowGTK::SetScrollbar(int orient,
 {
     const int dir = ScrollDirFromOrient(orient);
     GtkRange* const sb = m_scrollBar[dir];
 {
     const int dir = ScrollDirFromOrient(orient);
     GtkRange* const sb = m_scrollBar[dir];
-    wxCHECK_RET( sb, _T("this window is not scrollable") );
+    wxCHECK_RET( sb, wxT("this window is not scrollable") );
 
     if (range <= 0)
     {
 
     if (range <= 0)
     {
@@ -4152,17 +4561,14 @@ void wxWindowGTK::SetScrollbar(int orient,
         thumbVisible = 1;
     }
 
         thumbVisible = 1;
     }
 
-    GtkAdjustment * const adj = sb->adjustment;
-    adj->step_increment = 1;
-    adj->page_increment =
-    adj->page_size = thumbVisible;
-    adj->value = pos;
-
     g_signal_handlers_block_by_func(
         sb, (void*)gtk_scrollbar_value_changed, this);
 
     g_signal_handlers_block_by_func(
         sb, (void*)gtk_scrollbar_value_changed, this);
 
+    gtk_range_set_increments(sb, 1, thumbVisible);
+    gtk_adjustment_set_page_size(gtk_range_get_adjustment(sb), thumbVisible);
     gtk_range_set_range(sb, 0, range);
     gtk_range_set_range(sb, 0, range);
-    m_scrollPos[dir] = sb->adjustment->value;
+    gtk_range_set_value(sb, pos);
+    m_scrollPos[dir] = gtk_range_get_value(sb);
 
     g_signal_handlers_unblock_by_func(
         sb, (void*)gtk_scrollbar_value_changed, this);
 
     g_signal_handlers_unblock_by_func(
         sb, (void*)gtk_scrollbar_value_changed, this);
@@ -4172,7 +4578,7 @@ void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
 {
     const int dir = ScrollDirFromOrient(orient);
     GtkRange * const sb = m_scrollBar[dir];
 {
     const int dir = ScrollDirFromOrient(orient);
     GtkRange * const sb = m_scrollBar[dir];
-    wxCHECK_RET( sb, _T("this window is not scrollable") );
+    wxCHECK_RET( sb, wxT("this window is not scrollable") );
 
     // This check is more than an optimization. Without it, the slider
     //   will not move smoothly while tracking when using wxScrollHelper.
 
     // This check is more than an optimization. Without it, the slider
     //   will not move smoothly while tracking when using wxScrollHelper.
@@ -4182,7 +4588,7 @@ void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
             sb, (void*)gtk_scrollbar_value_changed, this);
 
         gtk_range_set_value(sb, pos);
             sb, (void*)gtk_scrollbar_value_changed, this);
 
         gtk_range_set_value(sb, pos);
-        m_scrollPos[dir] = sb->adjustment->value;
+        m_scrollPos[dir] = gtk_range_get_value(sb);
 
         g_signal_handlers_unblock_by_func(
             sb, (void*)gtk_scrollbar_value_changed, this);
 
         g_signal_handlers_unblock_by_func(
             sb, (void*)gtk_scrollbar_value_changed, this);
@@ -4192,32 +4598,34 @@ void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
 int wxWindowGTK::GetScrollThumb(int orient) const
 {
     GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
 int wxWindowGTK::GetScrollThumb(int orient) const
 {
     GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
-    wxCHECK_MSG( sb, 0, _T("this window is not scrollable") );
+    wxCHECK_MSG( sb, 0, wxT("this window is not scrollable") );
 
 
-    return wxRound(sb->adjustment->page_size);
+    return wxRound(gtk_adjustment_get_page_size(gtk_range_get_adjustment(sb)));
 }
 
 int wxWindowGTK::GetScrollPos( int orient ) const
 {
     GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
 }
 
 int wxWindowGTK::GetScrollPos( int orient ) const
 {
     GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
-    wxCHECK_MSG( sb, 0, _T("this window is not scrollable") );
+    wxCHECK_MSG( sb, 0, wxT("this window is not scrollable") );
 
 
-    return wxRound(sb->adjustment->value);
+    return wxRound(gtk_range_get_value(sb));
 }
 
 int wxWindowGTK::GetScrollRange( int orient ) const
 {
     GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
 }
 
 int wxWindowGTK::GetScrollRange( int orient ) const
 {
     GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
-    wxCHECK_MSG( sb, 0, _T("this window is not scrollable") );
+    wxCHECK_MSG( sb, 0, wxT("this window is not scrollable") );
 
 
-    return wxRound(sb->adjustment->upper);
+    return wxRound(gtk_adjustment_get_upper(gtk_range_get_adjustment(sb)));
 }
 
 // Determine if increment is the same as +/-x, allowing for some small
 //   difference due to possible inexactness in floating point arithmetic
 static inline bool IsScrollIncrement(double increment, double x)
 {
 }
 
 // Determine if increment is the same as +/-x, allowing for some small
 //   difference due to possible inexactness in floating point arithmetic
 static inline bool IsScrollIncrement(double increment, double x)
 {
-    wxASSERT(increment > 0);
+    wxASSERT(increment >= 0);
+    if ( increment == 0. )
+        return false;
     const double tolerance = 1.0 / 1024;
     return fabs(increment - fabs(x)) < tolerance;
 }
     const double tolerance = 1.0 / 1024;
     return fabs(increment - fabs(x)) < tolerance;
 }
@@ -4227,16 +4635,15 @@ wxEventType wxWindowGTK::GTKGetScrollEventType(GtkRange* range)
     wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]);
 
     const int barIndex = range == m_scrollBar[1];
     wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]);
 
     const int barIndex = range == m_scrollBar[1];
-    GtkAdjustment* adj = range->adjustment;
 
 
-    const int value = wxRound(adj->value);
+    const double value = gtk_range_get_value(range);
 
     // save previous position
     const double oldPos = m_scrollPos[barIndex];
     // update current position
 
     // save previous position
     const double oldPos = m_scrollPos[barIndex];
     // update current position
-    m_scrollPos[barIndex] = adj->value;
+    m_scrollPos[barIndex] = value;
     // If event should be ignored, or integral position has not changed
     // If event should be ignored, or integral position has not changed
-    if (!m_hasVMT || g_blockEventsOnDrag || value == wxRound(oldPos))
+    if (g_blockEventsOnDrag || wxRound(value) == wxRound(oldPos))
     {
         return wxEVT_NULL;
     }
     {
         return wxEVT_NULL;
     }
@@ -4245,14 +4652,15 @@ wxEventType wxWindowGTK::GTKGetScrollEventType(GtkRange* range)
     if (!m_isScrolling)
     {
         // Difference from last change event
     if (!m_isScrolling)
     {
         // Difference from last change event
-        const double diff = adj->value - oldPos;
+        const double diff = value - oldPos;
         const bool isDown = diff > 0;
 
         const bool isDown = diff > 0;
 
-        if (IsScrollIncrement(adj->step_increment, diff))
+        GtkAdjustment* adj = gtk_range_get_adjustment(range);
+        if (IsScrollIncrement(gtk_adjustment_get_step_increment(adj), diff))
         {
             eventType = isDown ? wxEVT_SCROLL_LINEDOWN : wxEVT_SCROLL_LINEUP;
         }
         {
             eventType = isDown ? wxEVT_SCROLL_LINEDOWN : wxEVT_SCROLL_LINEUP;
         }
-        else if (IsScrollIncrement(adj->page_increment, diff))
+        else if (IsScrollIncrement(gtk_adjustment_get_page_increment(adj), diff))
         {
             eventType = isDown ? wxEVT_SCROLL_PAGEDOWN : wxEVT_SCROLL_PAGEUP;
         }
         {
             eventType = isDown ? wxEVT_SCROLL_PAGEDOWN : wxEVT_SCROLL_PAGEUP;
         }
@@ -4314,7 +4722,7 @@ void wxWindowGTK::GTKScrolledWindowSetBorder(GtkWidget* w, int wxstyle)
 
         if(wxstyle & wxBORDER_RAISED)
             gtkstyle = GTK_SHADOW_OUT;
 
         if(wxstyle & wxBORDER_RAISED)
             gtkstyle = GTK_SHADOW_OUT;
-        else if (wxstyle & wxBORDER_SUNKEN)
+        else if ((wxstyle & wxBORDER_SUNKEN) || (wxstyle & wxBORDER_THEME))
             gtkstyle = GTK_SHADOW_IN;
 #if 0
         // Now obsolete
             gtkstyle = GTK_SHADOW_IN;
 #if 0
         // Now obsolete
@@ -4329,12 +4737,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)
 // Find the wxWindow at the current mouse position, also returning the mouse
 // position.
 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
@@ -4345,40 +4747,30 @@ wxWindow* wxFindWindowAtPointer(wxPoint& pt)
 }
 
 // Get the current mouse position.
 }
 
 // Get the current mouse position.
-wxPoint wxGetMousePosition()
+void wxGetMousePosition(int* x, int* y)
 {
 {
-  /* 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);
-  */
-
-    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);
+    GdkDisplay* display = GetDisplay();
+#ifdef __WXGTK3__
+    GdkDeviceManager* manager = gdk_display_get_device_manager(display);
+    GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
+    gdk_device_get_position(device, NULL, x, y);
+#else
+    gdk_display_get_pointer(display, NULL, x, y, NULL);
+#endif
+}
 
 
+wxPoint wxGetMousePosition()
+{
+    wxPoint pt;
+    wxGetMousePosition(&pt.x, &pt.y);
+    return pt;
 }
 
 GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
 {
     GdkWindow* window = NULL;
     if (m_wxwindow)
 }
 
 GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
 {
     GdkWindow* window = NULL;
     if (m_wxwindow)
-        window = m_wxwindow->window;
+        window = gtk_widget_get_window(m_wxwindow);
     return window;
 }
 
     return window;
 }
 
@@ -4386,80 +4778,38 @@ GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
 // freeze/thaw
 // ----------------------------------------------------------------------------
 
 // freeze/thaw
 // ----------------------------------------------------------------------------
 
-extern "C"
-{
-
-// this is called if we attempted to freeze unrealized widget when it finally
-// is realized (and so can be frozen):
-static void wx_frozen_widget_realize(GtkWidget* w, void* WXUNUSED(data))
-{
-    wxASSERT( w && !GTK_WIDGET_NO_WINDOW(w) );
-    wxASSERT( GTK_WIDGET_REALIZED(w) );
-
-    g_signal_handlers_disconnect_by_func
-    (
-        w,
-        (void*)wx_frozen_widget_realize,
-        NULL
-    );
-
-    gdk_window_freeze_updates(w->window);
-}
-
-} // extern "C"
-
-void wxWindowGTK::GTKFreezeWidget(GtkWidget *w)
+void wxWindowGTK::GTKFreezeWidget(GtkWidget* widget)
 {
 {
-    if ( !w || GTK_WIDGET_NO_WINDOW(w) )
-        return; // window-less widget, cannot be frozen
-
-    if ( !GTK_WIDGET_REALIZED(w) )
+    if (widget && gtk_widget_get_has_window(widget))
     {
     {
-        // we can't thaw unrealized widgets because they don't have GdkWindow,
-        // so set it up to be done immediately after realization:
-        g_signal_connect_after
-        (
-            w,
-            "realize",
-            G_CALLBACK(wx_frozen_widget_realize),
-            NULL
-        );
-        return;
+        GdkWindow* window = gtk_widget_get_window(widget);
+        if (window)
+            gdk_window_freeze_updates(window);
     }
     }
-
-    gdk_window_freeze_updates(w->window);
 }
 
 }
 
-void wxWindowGTK::GTKThawWidget(GtkWidget *w)
+void wxWindowGTK::GTKThawWidget(GtkWidget* widget)
 {
 {
-    if ( !w || GTK_WIDGET_NO_WINDOW(w) )
-        return; // window-less widget, cannot be frozen
-
-    if ( !GTK_WIDGET_REALIZED(w) )
+    if (widget && gtk_widget_get_has_window(widget))
     {
     {
-        // the widget wasn't realized yet, no need to thaw
-        g_signal_handlers_disconnect_by_func
-        (
-            w,
-            (void*)wx_frozen_widget_realize,
-            NULL
-        );
-        return;
+        GdkWindow* window = gtk_widget_get_window(widget);
+        if (window)
+            gdk_window_thaw_updates(window);
     }
     }
-
-    gdk_window_thaw_updates(w->window);
 }
 
 void wxWindowGTK::DoFreeze()
 {
 }
 
 void wxWindowGTK::DoFreeze()
 {
-    GTKFreezeWidget(m_widget);
-    if ( m_wxwindow && m_widget != m_wxwindow )
-        GTKFreezeWidget(m_wxwindow);
+    GtkWidget* widget = m_wxwindow;
+    if (widget == NULL)
+        widget = m_widget;
+    GTKFreezeWidget(widget);
 }
 
 void wxWindowGTK::DoThaw()
 {
 }
 
 void wxWindowGTK::DoThaw()
 {
-    GTKThawWidget(m_widget);
-    if ( m_wxwindow && m_widget != m_wxwindow )
-        GTKThawWidget(m_wxwindow);
+    GtkWidget* widget = m_wxwindow;
+    if (widget == NULL)
+        widget = m_widget;
+    GTKThawWidget(widget);
 }
 }