]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
check for m_parentMenu being NULL in IsChecked/Checked/Enable() too (closes #10460)
[wxWidgets.git] / src / gtk / window.cpp
index f7c7bf4e249a7b60448a8eeba610c18cedc0e401..6f2da8ab52bfe45e198d0946e20f3c597a552be4 100644 (file)
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkx.h>
 
+#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
+#endif
+
 //-----------------------------------------------------------------------------
 // documentation on internals
 //-----------------------------------------------------------------------------
@@ -182,7 +205,7 @@ extern wxCursor   g_globalCursor;
 
 // mouse capture state: the window which has it and if the mouse is currently
 // inside it
-static wxWindowGTK  *g_captureWindow = (wxWindowGTK*) NULL;
+static wxWindowGTK  *g_captureWindow = NULL;
 static bool g_captureWindowHasMouse = false;
 
 // The window that currently has focus:
@@ -197,7 +220,7 @@ static wxWindowGTK *gs_deferredFocusOut = NULL;
 
 // global variables because GTK+ DnD want to have the
 // mouse event that caused it
-GdkEvent    *g_lastMouseEvent = (GdkEvent*) NULL;
+GdkEvent    *g_lastMouseEvent = NULL;
 int          g_lastButtonNumber = 0;
 
 //-----------------------------------------------------------------------------
@@ -234,11 +257,11 @@ gdk_window_warp_pointer (GdkWindow      *window,
 // "size_request" of m_widget
 //-----------------------------------------------------------------------------
 
-// make it extern because wxStaticText needs to disconnect this one
 extern "C" {
-void wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
-                                        GtkRequisition *requisition,
-                                        wxWindow * win)
+static void
+wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
+                                   GtkRequisition *requisition,
+                                   wxWindow * win)
 {
     int w, h;
     win->GetSize( &w, &h );
@@ -272,38 +295,31 @@ gtk_window_expose_callback( GtkWidget* widget,
 }
 }
 
+#ifndef __WXUNIVERSAL__
 //-----------------------------------------------------------------------------
-// "expose_event" from m_widget, for drawing border
+// "expose_event" from m_wxwindow->parent, for drawing border
 //-----------------------------------------------------------------------------
 
-#ifndef __WXUNIVERSAL__
-
-GtkWidget* GetEntryWidget();
-
 extern "C" {
 static gboolean
 expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
 {
-    // if this event is not for the GdkWindow the border is drawn on
-    if (win->m_wxwindow == win->m_widget && gdk_event->window == widget->window)
+    if (gdk_event->window != widget->window)
+        return false;
+
+    const GtkAllocation& alloc = win->m_wxwindow->allocation;
+    const int x = alloc.x;
+    const int y = alloc.y;
+    const int w = alloc.width;
+    const int h = alloc.height;
+
+    if (w <= 0 || h <= 0)
         return false;
 
-    int x = 0;
-    int y = 0;
-    // GtkScrolledWindow is GTK_NO_WINDOW
-    if (GTK_WIDGET_NO_WINDOW(widget))
-    {
-        x = widget->allocation.x;
-        y = widget->allocation.y;
-    }
-    int w = win->m_wxwindow->allocation.width;
-    int h = win->m_wxwindow->allocation.height;
     if (win->HasFlag(wxBORDER_SIMPLE))
     {
-        GdkGC* gc = gdk_gc_new(gdk_event->window);
-        gdk_gc_set_foreground(gc, &widget->style->black);
-        gdk_draw_rectangle(gdk_event->window, gc, false, x, y, w - 1, h - 1);
-        g_object_unref(gc);
+        gdk_draw_rectangle(gdk_event->window,
+            widget->style->black_gc, false, x, y, w - 1, h - 1);
     }
     else
     {
@@ -313,21 +329,39 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
 
         // Style detail to use
         const char* detail;
-        if (widget == win->m_wxwindow)
+        if (win->m_widget == win->m_wxwindow)
             // for non-scrollable wxWindows
             detail = "entry";
         else
             // for scrollable ones
             detail = "viewport";
 
-        GtkWidget* styleWidget = GetEntryWidget();
         gtk_paint_shadow(
-           styleWidget->style, gdk_event->window, GTK_STATE_NORMAL,
-           shadow, NULL, styleWidget, detail, x, y, w, h);
+           win->m_wxwindow->style, gdk_event->window, GTK_STATE_NORMAL,
+           shadow, NULL, wxGTKPrivate::GetEntryWidget(), detail, x, y, w, h);
     }
+    return false;
+}
+}
+
+//-----------------------------------------------------------------------------
+// "parent_set" from m_wxwindow
+//-----------------------------------------------------------------------------
 
-    // no further painting is needed for border-only GdkWindow
-    return win->m_wxwindow == win->m_widget;
+extern "C" {
+static void
+parent_set(GtkWidget* widget, GtkObject* old_parent, wxWindow* win)
+{
+    if (old_parent)
+    {
+        g_signal_handlers_disconnect_by_func(
+            old_parent, (void*)expose_event_border, win);
+    }
+    if (widget->parent)
+    {
+        g_signal_connect_after(widget->parent, "expose_event",
+            G_CALLBACK(expose_event_border), win);
+    }
 }
 }
 #endif // !__WXUNIVERSAL__
@@ -648,7 +682,7 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event,
     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_MOD2_MASK) != 0;
+    event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0;
     event.m_scanCode = gdk_event->keyval;
     event.m_rawCode = (wxUint32) gdk_event->keyval;
     event.m_rawFlags = 0;
@@ -790,7 +824,7 @@ struct wxGtkIMData
 
 extern "C" {
 static gboolean
-gtk_window_key_press_callback( GtkWidget *widget,
+gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
                                GdkEventKey *gdk_event,
                                wxWindow *win )
 {
@@ -799,12 +833,6 @@ gtk_window_key_press_callback( GtkWidget *widget,
     if (g_blockEventsOnDrag)
         return FALSE;
 
-    // GTK+ sends keypress events to the focus widget and then
-    // to all its parent and grandparent widget. We only want
-    // the key events from the focus widget.
-    if (!GTK_WIDGET_HAS_FOCUS(widget))
-        return FALSE;
-
     wxKeyEvent event( wxEVT_KEY_DOWN );
     bool ret = false;
     bool return_after_IM = false;
@@ -1050,7 +1078,7 @@ template<typename T> void InitMouseEvent(wxWindowGTK *win,
     event.m_shiftDown = gdk_event->state & GDK_SHIFT_MASK;
     event.m_controlDown = gdk_event->state & GDK_CONTROL_MASK;
     event.m_altDown = gdk_event->state & GDK_MOD1_MASK;
-    event.m_metaDown = gdk_event->state & GDK_MOD2_MASK;
+    event.m_metaDown = gdk_event->state & GDK_META_MASK;
     event.m_leftDown = gdk_event->state & GDK_BUTTON1_MASK;
     event.m_middleDown = gdk_event->state & GDK_BUTTON2_MASK;
     event.m_rightDown = gdk_event->state & GDK_BUTTON3_MASK;
@@ -1154,7 +1182,7 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
         }
         else
         {
-            if ((child->m_wxwindow == (GtkWidget*) NULL) &&
+            if ((child->m_wxwindow == NULL) &&
                 (child->m_x <= xx) &&
                 (child->m_y <= yy) &&
                 (child->m_x+child->m_width  >= xx) &&
@@ -1519,6 +1547,38 @@ gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
 // "scroll_event" (mouse wheel event)
 //-----------------------------------------------------------------------------
 
+static gboolean
+window_scroll_event_hscrollbar(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
+{
+    if (gdk_event->direction != GDK_SCROLL_LEFT &&
+        gdk_event->direction != GDK_SCROLL_RIGHT)
+    {
+        return false;
+    }
+
+    wxMouseEvent event(wxEVT_MOUSEWHEEL);
+    InitMouseEvent(win, event, gdk_event);
+
+    GtkRange *range = win->m_scrollBar[wxWindow::ScrollDir_Horz];
+    if (!range) return FALSE;
+
+    if (range && GTK_WIDGET_VISIBLE (range))
+    {
+        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);
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
 static gboolean
 window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
 {
@@ -1539,7 +1599,27 @@ window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
     else
         event.m_wheelRotation = -120;
 
-    return win->GTKProcessEvent(event);
+    if (win->GTKProcessEvent(event))
+      return TRUE;
+
+    GtkRange *range = win->m_scrollBar[wxWindow::ScrollDir_Vert];
+    if (!range) return FALSE;
+
+    if (range && GTK_WIDGET_VISIBLE (range))
+    {
+        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;
+    }
+
+    return FALSE;
 }
 
 //-----------------------------------------------------------------------------
@@ -1881,32 +1961,21 @@ wxWindow *wxWindowBase::DoFindFocus()
 {
     wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus;
     // the cast is necessary when we compile in wxUniversal mode
-    return wx_static_cast(wxWindow*, focus);
+    return static_cast<wxWindow*>(focus);
 }
 
-//-----------------------------------------------------------------------------
-// InsertChild for wxWindowGTK.
-//-----------------------------------------------------------------------------
-
-/* Callback for wxWindowGTK. This very strange beast has to be used because
- * C++ has no virtual methods in a constructor. We have to emulate a
- * virtual function here as wxNotebook requires a different way to insert
- * a child in it. I had opted for creating a wxNotebookPage window class
- * which would have made this superfluous (such in the MDI window system),
- * but no-one was listening to me... */
-
-static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
+void wxWindowGTK::AddChildGTK(wxWindowGTK* child)
 {
     /* the window might have been scrolled already, do we
        have to adapt the position */
-    wxPizza* pizza = WX_PIZZA(parent->m_wxwindow);
+    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(parent->m_wxwindow), child->m_widget, child->m_x, child->m_y);
+        GTK_FIXED(m_wxwindow), child->m_widget, child->m_x, child->m_y);
 }
 
 //-----------------------------------------------------------------------------
@@ -1940,7 +2009,7 @@ wxMouseState wxGetMouseState()
     ms.SetControlDown(mask & GDK_CONTROL_MASK);
     ms.SetShiftDown(mask & GDK_SHIFT_MASK);
     ms.SetAltDown(mask & GDK_MOD1_MASK);
-    ms.SetMetaDown(mask & GDK_MOD2_MASK);
+    ms.SetMetaDown(mask & GDK_META_MASK);
 
     return ms;
 }
@@ -1960,9 +2029,9 @@ wxMouseState wxGetMouseState()
 void wxWindowGTK::Init()
 {
     // GTK specific
-    m_widget = (GtkWidget *) NULL;
-    m_wxwindow = (GtkWidget *) NULL;
-    m_focusWidget = (GtkWidget *) NULL;
+    m_widget = NULL;
+    m_wxwindow = NULL;
+    m_focusWidget = NULL;
 
     // position/size
     m_x = 0;
@@ -1971,9 +2040,8 @@ void wxWindowGTK::Init()
     m_height = 0;
 
     m_hasVMT = false;
-    m_isBeingDeleted = false;
 
-    m_showOnIdle= false;
+    m_showOnIdle = false;
 
     m_noExpose = false;
     m_nativeSizeEvent = false;
@@ -1991,8 +2059,6 @@ void wxWindowGTK::Init()
     m_oldClientWidth =
     m_oldClientHeight = 0;
 
-    m_insertCallback = wxInsertChildInWindow;
-
     m_clipPaintRegion = false;
 
     m_needsStyleChange = false;
@@ -2029,6 +2095,7 @@ bool wxWindowGTK::Create( wxWindow *parent,
 {
     // Get default border
     wxBorder border = GetBorder(style);
+
     style &= ~wxBORDER_MASK;
     style |= border;
 
@@ -2039,19 +2106,29 @@ bool wxWindowGTK::Create( wxWindow *parent,
         return false;
     }
 
+        // We should accept the native look
+#if 0
+        GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
+        scroll_class->scrollbar_spacing = 0;
+#endif
 
-    m_wxwindow = wxPizza::New(m_windowStyle);
+
+    m_wxwindow = wxPizza::New(m_windowStyle,this);
+#ifndef __WXUNIVERSAL__
+    if (HasFlag(wxPizza::BORDER_STYLES))
+    {
+        g_signal_connect(m_wxwindow, "parent_set",
+            G_CALLBACK(parent_set), this);
+    }
+#endif
     if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
         m_widget = m_wxwindow;
     else
     {
-        m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
+        m_widget = gtk_scrolled_window_new( NULL, NULL );
 
         GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
 
-        GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
-        scroll_class->scrollbar_spacing = 0;
-
         // 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
@@ -2110,6 +2187,7 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
         gtk_widget_show( m_wxwindow );
     }
+    g_object_ref(m_widget);
 
     if (m_parent)
         m_parent->DoAddChild( this );
@@ -2135,7 +2213,6 @@ wxWindowGTK::~wxWindowGTK()
     if ( gs_deferredFocusOut == this )
         gs_deferredFocusOut = NULL;
 
-    m_isBeingDeleted = true;
     m_hasVMT = false;
 
     // destroy children before destroying this window itself
@@ -2159,17 +2236,17 @@ wxWindowGTK::~wxWindowGTK()
     // delete before the widgets to avoid a crash on solaris
     delete m_imData;
 
-    if (m_wxwindow && (m_wxwindow != m_widget))
-    {
-        gtk_widget_destroy( m_wxwindow );
-        m_wxwindow = (GtkWidget*) NULL;
-    }
-
     if (m_widget)
     {
-        gtk_widget_destroy( m_widget );
-        m_widget = (GtkWidget*) NULL;
+        // Note that gtk_widget_destroy() does not destroy the widget, it just
+        // emits the "destroy" signal. The widget is not actually destroyed
+        // until its reference count drops to zero.
+        gtk_widget_destroy(m_widget);
+        // Release our reference, should be the last one
+        g_object_unref(m_widget);
+        m_widget = NULL;
     }
+    m_wxwindow = NULL;
 }
 
 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos,  const wxSize &size )
@@ -2215,15 +2292,6 @@ void wxWindowGTK::PostCreation()
 
         g_signal_connect (m_imData->context, "commit",
                           G_CALLBACK (gtk_wxwindow_commit_cb), this);
-
-        // border drawing
-#ifndef __WXUNIVERSAL__
-        if (HasFlag(wxPizza::BORDER_STYLES))
-        {
-            g_signal_connect(m_widget, "expose_event",
-                G_CALLBACK(expose_event_border), this);
-        }
-#endif
     }
 
     // focus handling
@@ -2342,8 +2410,16 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
                       G_CALLBACK (gtk_window_button_release_callback), this);
     g_signal_connect (widget, "motion_notify_event",
                       G_CALLBACK (gtk_window_motion_notify_callback), 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);
+
     g_signal_connect (widget, "popup_menu",
                      G_CALLBACK (wxgtk_window_popup_menu_callback), this);
     g_signal_connect (widget, "enter_notify_event",
@@ -2419,8 +2495,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
     if (height != -1)
         m_height = height;
 
-    ConstrainSize();
-
     if (m_parent->m_wxwindow)
     {
         wxPizza* pizza = WX_PIZZA(m_parent->m_wxwindow);
@@ -2466,6 +2540,12 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
             event.SetEventObject( this );
             HandleWindowEvent( event );
         }
+    } else 
+    if (sizeFlags & wxSIZE_FORCE_EVENT)
+    {
+        wxSizeEvent event( wxSize(m_width,m_height), GetId() );
+        event.SetEventObject( this );
+        HandleWindowEvent( event );
     }
 }
 
@@ -2572,21 +2652,50 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
     int w = m_width;
     int h = m_height;
 
-    if (m_wxwindow)
+    if ( m_wxwindow )
     {
         // if window is scrollable, account for scrollbars
-        for (int i = 0; i < 2 && m_scrollBar[i]; i++)
+        if ( GTK_IS_SCROLLED_WINDOW(m_widget) )
         {
-            GtkRequisition req;
-            GtkAdjustment* adj = gtk_range_get_adjustment(m_scrollBar[i]);
-            // if scrollbar enabled
-            if (adj->upper > adj->page_size)
+            GtkPolicyType policy[ScrollDir_Max];
+            gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(m_widget),
+                                           &policy[ScrollDir_Horz],
+                                           &policy[ScrollDir_Vert]);
+
+            for ( int i = 0; i < ScrollDir_Max; i++ )
             {
-                gtk_widget_size_request(GTK_WIDGET(m_scrollBar[i]), &req);
+                // don't account for the scrollbars we don't have
+                GtkRange * const range = m_scrollBar[i];
+                if ( !range )
+                    continue;
+
+                // nor for the ones we have but don't current show
+                switch ( policy[i] )
+                {
+                    case GTK_POLICY_NEVER:
+                        // never shown so doesn't take any place
+                        continue;
+
+                    case GTK_POLICY_ALWAYS:
+                        // no checks necessary
+                        break;
+
+                    case GTK_POLICY_AUTOMATIC:
+                        // may be shown or not, check
+                        GtkAdjustment *adj = gtk_range_get_adjustment(range);
+                        if ( adj->upper <= adj->page_size )
+                            continue;
+                }
+
+                GtkScrolledWindowClass *scroll_class =
+                    GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
+
+                GtkRequisition req;
+                gtk_widget_size_request(GTK_WIDGET(range), &req);
                 if (i == ScrollDir_Horz)
-                    h -= req.height;
+                    h -= req.height + scroll_class->scrollbar_spacing;
                 else
-                    w -= req.width;
+                    w -= req.width + scroll_class->scrollbar_spacing;
             }
         }
 
@@ -2620,7 +2729,7 @@ void wxWindowGTK::DoGetPosition( int *x, int *y ) const
 
     if (m_x == -1 && m_y == -1)
     {
-        GdkWindow *source = (GdkWindow *) NULL;
+        GdkWindow *source = NULL;
         if (m_wxwindow)
             source = m_wxwindow->window;
         else
@@ -2635,8 +2744,8 @@ void wxWindowGTK::DoGetPosition( int *x, int *y ) const
             if (m_parent)
                 m_parent->ScreenToClient(&org_x, &org_y);
 
-            wx_const_cast(wxWindowGTK*, this)->m_x = org_x;
-            wx_const_cast(wxWindowGTK*, this)->m_y = org_y;
+            const_cast<wxWindowGTK*>(this)->m_x = org_x;
+            const_cast<wxWindowGTK*>(this)->m_y = org_y;
         }
     }
 
@@ -2650,7 +2759,7 @@ void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
 
     if (!m_widget->window) return;
 
-    GdkWindow *source = (GdkWindow *) NULL;
+    GdkWindow *source = NULL;
     if (m_wxwindow)
         source = m_wxwindow->window;
     else
@@ -2687,7 +2796,7 @@ void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
 
     if (!m_widget->window) return;
 
-    GdkWindow *source = (GdkWindow *) NULL;
+    GdkWindow *source = NULL;
     if (m_wxwindow)
         source = m_wxwindow->window;
     else
@@ -2860,6 +2969,17 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
     g_object_unref (layout);
 }
 
+void wxWindowGTK::GTKDisableFocusOutEvent()
+{
+    g_signal_handlers_block_by_func( m_focusWidget,
+                                (gpointer) gtk_window_focus_out_callback, this);
+}
+
+void wxWindowGTK::GTKEnableFocusOutEvent()
+{
+    g_signal_handlers_unblock_by_func( m_focusWidget,
+                                (gpointer) gtk_window_focus_out_callback, this);
+}
 
 bool wxWindowGTK::GTKHandleFocusIn()
 {
@@ -2914,7 +3034,7 @@ bool wxWindowGTK::GTKHandleFocusIn()
 
     // Notify the parent keeping track of focus for the kbd navigation
     // purposes that we got it.
-    wxChildFocusEvent eventChildFocus(this);
+    wxChildFocusEvent eventChildFocus(static_cast<wxWindow*>(this));
     GTKProcessEvent(eventChildFocus);
 
     wxFocusEvent eventFocus(wxEVT_SET_FOCUS, GetId());
@@ -3080,13 +3200,8 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
 
     wxASSERT( GTK_IS_WIDGET(m_widget) );
 
-    /* prevent GTK from deleting the widget arbitrarily */
-    gtk_widget_ref( m_widget );
-
     if (oldParent)
-    {
         gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
-    }
 
     wxASSERT( GTK_IS_WIDGET(m_widget) );
 
@@ -3097,14 +3212,10 @@ bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
             m_showOnIdle = true;
             gtk_widget_hide( m_widget );
         }
-
         /* insert GTK representation */
-        (*(newParent->m_insertCallback))(newParent, this);
+        newParent->AddChildGTK(this);
     }
 
-    /* reverse: prevent GTK from deleting the widget arbitrarily */
-    gtk_widget_unref( m_widget );
-
     SetLayoutDirection(wxLayout_Default);
 
     return true;
@@ -3119,7 +3230,7 @@ void wxWindowGTK::DoAddChild(wxWindowGTK *child)
     AddChild( child );
 
     /* insert GTK representation */
-    (*m_insertCallback)(this, child);
+    AddChildGTK(child);
 }
 
 void wxWindowGTK::AddChild(wxWindowBase *child)
@@ -3370,7 +3481,7 @@ void wxWindowGTK::WarpPointer( int x, int y )
     // We provide this function ourselves as it is
     // missing in GDK (top of this file).
 
-    GdkWindow *window = (GdkWindow*) NULL;
+    GdkWindow *window = NULL;
     if (m_wxwindow)
         window = m_wxwindow->window;
     else
@@ -3426,63 +3537,39 @@ bool wxWindowGTK::ScrollPages(int pages)
 void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground),
                           const wxRect *rect)
 {
-    if (!m_widget)
-        return;
-    if (!m_widget->window)
+    GtkWidget* widget;
+    if (m_wxwindow)
+        widget = m_wxwindow;
+    else if (m_widget)
+        widget = m_widget;
+    else
         return;
 
-    if (m_wxwindow)
+    if (rect == NULL)
+        gtk_widget_queue_draw(widget);
+    else
     {
-        if (m_wxwindow->window == NULL) return;
-
-        GdkRectangle gdk_rect,
-                    *p;
-        if (rect)
-        {
-            gdk_rect.x = rect->x;
-            gdk_rect.y = rect->y;
-            gdk_rect.width = rect->width;
-            gdk_rect.height = rect->height;
-            if (GetLayoutDirection() == wxLayout_RightToLeft)
-                gdk_rect.x = GetClientSize().x - gdk_rect.x - gdk_rect.width;
-
-            p = &gdk_rect;
-        }
-        else // invalidate everything
-        {
-            p = NULL;
-        }
+        int x = rect->x;
+        if (GetLayoutDirection() == wxLayout_RightToLeft)
+            x = GetClientSize().x - x - rect->width;
 
-        gdk_window_invalidate_rect(m_wxwindow->window, p, true);
+        gtk_widget_queue_draw_area(widget, x, rect->y, rect->width, rect->height);
     }
 }
 
 void wxWindowGTK::Update()
 {
-    GtkUpdate();
-
-    // when we call Update() we really want to update the window immediately on
-    // screen, even if it means flushing the entire queue and hence slowing down
-    // everything -- but it should still be done, it's just that Update() should
-    // be called very rarely
-    gdk_flush();
-}
+    if (m_widget && m_widget->window)
+    {
+        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);
 
-void wxWindowGTK::GtkUpdate()
-{
-    if (m_wxwindow && m_wxwindow->window)
-        gdk_window_process_updates(m_wxwindow->window, false);
-    if (m_widget && m_widget->window && (m_wxwindow != m_widget))
-        gdk_window_process_updates( m_widget->window, FALSE );
+        gdk_window_process_updates(m_widget->window, true);
 
-    // for consistency with other platforms (and also because it's convenient
-    // to be able to update an entire TLW by calling Update() only once), we
-    // should also update all our children here
-    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-          node;
-          node = node->GetNext() )
-    {
-        node->GetData()->GtkUpdate();
+        // Flush again, but no need to wait for it to finish
+        gdk_display_flush(display);
     }
 }
 
@@ -3491,7 +3578,6 @@ bool wxWindowGTK::DoIsExposed( int x, int y ) const
     return m_updateRegion.Contains(x, y) != wxOutRegion;
 }
 
-
 bool wxWindowGTK::DoIsExposed( int x, int y, int w, int h ) const
 {
     if (GetLayoutDirection() == wxLayout_RightToLeft)
@@ -3571,7 +3657,7 @@ void wxWindowGTK::GtkSendPaintEvents()
     else
     {
         wxWindowDC dc( (wxWindow*)this );
-        dc.SetClippingRegion( m_updateRegion );
+        dc.SetDeviceClippingRegion( m_updateRegion );
 
         // Work around gtk-qt <= 0.60 bug whereby the window colour
         // remains grey
@@ -3898,8 +3984,8 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
     menu->m_popupShown = true;
     gtk_menu_popup(
                   GTK_MENU(menu->m_menu),
-                  (GtkWidget *) NULL,           // parent menu shell
-                  (GtkWidget *) NULL,           // parent menu item
+                  NULL,           // parent menu shell
+                  NULL,           // parent menu item
                   posfunc,                      // function to position it
                   userdata,                     // client data
                   0,                            // button used to activate it
@@ -3924,12 +4010,12 @@ void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
 
     GtkWidget *dnd_widget = GetConnectWidget();
 
-    if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
+    if (m_dropTarget) m_dropTarget->GtkUnregisterWidget( dnd_widget );
 
     if (m_dropTarget) delete m_dropTarget;
     m_dropTarget = dropTarget;
 
-    if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
+    if (m_dropTarget) m_dropTarget->GtkRegisterWidget( dnd_widget );
 }
 
 #endif // wxUSE_DRAG_AND_DROP
@@ -3974,7 +4060,7 @@ void wxWindowGTK::DoCaptureMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
-    GdkWindow *window = (GdkWindow*) NULL;
+    GdkWindow *window = NULL;
     if (m_wxwindow)
         window = m_wxwindow->window;
     else
@@ -3992,7 +4078,7 @@ void wxWindowGTK::DoCaptureMouse()
                           GDK_BUTTON_RELEASE_MASK |
                           GDK_POINTER_MOTION_HINT_MASK |
                           GDK_POINTER_MOTION_MASK),
-                      (GdkWindow *) NULL,
+                      NULL,
                       cursor->GetCursor(),
                       (guint32)GDK_CURRENT_TIME );
     g_captureWindow = this;
@@ -4005,9 +4091,9 @@ void wxWindowGTK::DoReleaseMouse()
 
     wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
 
-    g_captureWindow = (wxWindowGTK*) NULL;
+    g_captureWindow = NULL;
 
-    GdkWindow *window = (GdkWindow*) NULL;
+    GdkWindow *window = NULL;
     if (m_wxwindow)
         window = m_wxwindow->window;
     else