]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
show help for the page under mouse when the [?] button is used to request help
[wxWidgets.git] / src / gtk / window.cpp
index c1b8439792c84cddad3254e30bce51ddf7916f51..4079dc814599f862e27e76de2ed43d0354143abf 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        gtk/window.cpp
+// Name:        src/gtk/window.cpp
 // Purpose:
 // Author:      Robert Roebling
 // Id:          $Id$
 #endif
 
 #include "wx/window.h"
-#include "wx/dcclient.h"
-#include "wx/frame.h"
-#include "wx/app.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/intl.h"
+    #include "wx/log.h"
+    #include "wx/app.h"
+    #include "wx/utils.h"
+    #include "wx/frame.h"
+    #include "wx/dcclient.h"
+    #include "wx/menu.h"
+    #include "wx/dialog.h"
+    #include "wx/settings.h"
+    #include "wx/msgdlg.h"
+#endif
+
 #include "wx/layout.h"
-#include "wx/utils.h"
-#include "wx/dialog.h"
-#include "wx/msgdlg.h"
 #include "wx/module.h"
 #include "wx/combobox.h"
 
+#if wxUSE_TOOLBAR_NATIVE
+    #include "wx/toolbar.h"
+#endif
+
 #if wxUSE_DRAG_AND_DROP
     #include "wx/dnd.h"
 #endif
     #include "wx/textctrl.h"
 #endif
 
-#include "wx/menu.h"
 #include "wx/statusbr.h"
-#include "wx/intl.h"
-#include "wx/settings.h"
-#include "wx/log.h"
 #include "wx/fontutil.h"
-#include "wx/stattext.h"
 
 #ifdef __WXDEBUG__
     #include "wx/thread.h"
 #include "wx/math.h"
 #include <ctype.h>
 
+// FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
+#include <gtk/gtkversion.h>
+#if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
+#undef GTK_DISABLE_DEPRECATED
+#endif
+
 #include "wx/gtk/private.h"
 #include <gdk/gdkprivate.h>
 #include <gdk/gdkkeysyms.h>
@@ -261,7 +274,7 @@ gdk_window_warp_pointer (GdkWindow      *window,
                          gint            y)
 {
   if (!window)
-    window = GDK_ROOT_PARENT();
+    window = gdk_get_default_root_window();
 
   if (!GDK_WINDOW_DESTROYED(window))
   {
@@ -273,13 +286,6 @@ gdk_window_warp_pointer (GdkWindow      *window,
   }
 }
 
-//-----------------------------------------------------------------------------
-// idle system
-//-----------------------------------------------------------------------------
-
-extern void wxapp_install_idle_handler();
-extern bool g_isIdle;
-
 //-----------------------------------------------------------------------------
 // local code (see below)
 //-----------------------------------------------------------------------------
@@ -308,6 +314,35 @@ wxWindow *wxFindFocusedChild(wxWindowGTK *win)
     return (wxWindow *)NULL;
 }
 
+static void GetScrollbarWidth(GtkWidget* widget, int& w, int& h)
+{
+    GtkScrolledWindow* scroll_window = GTK_SCROLLED_WINDOW(widget);
+    GtkScrolledWindowClass* scroll_class = GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window));
+    GtkRequisition scroll_req;
+
+    w = 0;
+    if (scroll_window->vscrollbar_visible)
+    {
+        scroll_req.width = 2;
+        scroll_req.height = 2;
+        (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
+            (scroll_window->vscrollbar, &scroll_req );
+        w = scroll_req.width +
+            scroll_class->scrollbar_spacing;
+    }
+
+    h = 0;
+    if (scroll_window->hscrollbar_visible)
+    {
+        scroll_req.width = 2;
+        scroll_req.height = 2;
+        (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
+            (scroll_window->hscrollbar, &scroll_req );
+        h = scroll_req.height +
+            scroll_class->scrollbar_spacing;
+    }
+}
+
 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
 {
     // wxUniversal widgets draw the borders and scrollbars themselves
@@ -320,33 +355,7 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
 
     if (win->m_hasScrolling)
     {
-        GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
-
-        GtkRequisition vscroll_req;
-        vscroll_req.width = 2;
-        vscroll_req.height = 2;
-        (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
-            (scroll_window->vscrollbar, &vscroll_req );
-
-        GtkRequisition hscroll_req;
-        hscroll_req.width = 2;
-        hscroll_req.height = 2;
-        (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
-            (scroll_window->hscrollbar, &hscroll_req );
-
-        GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
-
-        if (scroll_window->vscrollbar_visible)
-        {
-            dw += vscroll_req.width;
-            dw += scroll_class->scrollbar_spacing;
-        }
-
-        if (scroll_window->hscrollbar_visible)
-        {
-            dh += hscroll_req.height;
-            dh += scroll_class->scrollbar_spacing;
-        }
+        GetScrollbarWidth(widget, dw, dh);
     }
 
     int dx = 0;
@@ -389,7 +398,7 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
         gdk_draw_rectangle( widget->window, gc, FALSE,
                          dx, dy,
                          widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
-        gdk_gc_unref( gc );
+        g_object_unref (gc);
         return;
     }
 #endif // __WXUNIVERSAL__
@@ -400,7 +409,10 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
+static gboolean
+gtk_window_own_expose_callback( GtkWidget *widget,
+                                GdkEventExpose *gdk_event,
+                                wxWindowGTK *win )
 {
     if (gdk_event->count > 0) return FALSE;
 
@@ -468,9 +480,10 @@ void wxgtk_combo_size_request_callback(GtkWidget *widget,
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static int gtk_window_expose_callback( GtkWidget *widget,
-                                       GdkEventExpose *gdk_event,
-                                       wxWindow *win )
+static gboolean
+gtk_window_expose_callback( GtkWidget *widget,
+                            GdkEventExpose *gdk_event,
+                            wxWindow *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -646,11 +659,11 @@ static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
             break;
 
         case GDK_Prior:     // == GDK_Page_Up
-            key_code = WXK_PRIOR;
+            key_code = WXK_PAGEUP;
             break;
 
         case GDK_Next:      // == GDK_Page_Down
-            key_code = WXK_NEXT;
+            key_code = WXK_PAGEDOWN;
             break;
 
         case GDK_End:
@@ -729,11 +742,11 @@ static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
             break;
 
         case GDK_KP_Prior: // == GDK_KP_Page_Up
-            key_code = isChar ? WXK_PRIOR : WXK_NUMPAD_PRIOR;
+            key_code = isChar ? WXK_PAGEUP : WXK_NUMPAD_PAGEUP;
             break;
 
         case GDK_KP_Next: // == GDK_KP_Page_Down
-            key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT;
+            key_code = isChar ? WXK_PAGEDOWN : WXK_NUMPAD_PAGEDOWN;
             break;
 
         case GDK_KP_End:
@@ -831,10 +844,6 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event,
     event.m_rawFlags = 0;
 #if wxUSE_UNICODE
     event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
-    if ( gdk_event->type == GDK_KEY_PRESS ||  gdk_event->type == GDK_KEY_RELEASE )
-    {
-        event.m_uniChar = toupper(event.m_uniChar);
-    }
 #endif
     wxGetMousePosition( &x, &y );
     win->ScreenToClient( &x, &y );
@@ -942,6 +951,12 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
     wxFillOtherKeyEventFields(event, win, gdk_event);
 
     event.m_keyCode = key_code;
+#if wxUSE_UNICODE
+    if ( gdk_event->type == GDK_KEY_PRESS ||  gdk_event->type == GDK_KEY_RELEASE )
+    {
+        event.m_uniChar = key_code;
+    }
+#endif
 
     return true;
 }
@@ -959,14 +974,15 @@ struct wxGtkIMData
     }
     ~wxGtkIMData()
     {
-        g_object_unref(context);
+        g_object_unref (context);
     }
 };
 
 extern "C" {
-static gint gtk_window_key_press_callback( GtkWidget *widget,
-                                           GdkEventKey *gdk_event,
-                                           wxWindow *win )
+static gboolean
+gtk_window_key_press_callback( GtkWidget *widget,
+                               GdkEventKey *gdk_event,
+                               wxWindow *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1016,12 +1032,12 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
         if (intercepted_by_IM)
         {
             wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
-            return true;
+            return TRUE;
         }
     }
 
     if (return_after_IM)
-        return false;
+        return FALSE;
 
 #if wxUSE_ACCEL
     if (!ret)
@@ -1079,7 +1095,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
 #if wxUSE_UNICODE
                 event.m_uniChar = event.m_keyCode;
 #endif
-            }               
+            }
 
             // Implement OnCharHook by checking ancestor top level windows
             wxWindow *parent = win;
@@ -1175,9 +1191,10 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
 }
 
 extern "C" {
-static void gtk_wxwindow_commit_cb (GtkIMContext *context,
-                           const gchar  *str,
-                           wxWindow     *window)
+static void
+gtk_wxwindow_commit_cb (GtkIMContext *context,
+                        const gchar  *str,
+                        wxWindow     *window)
 {
     wxKeyEvent event( wxEVT_KEY_DOWN );
 
@@ -1189,13 +1206,8 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context,
                                   window, window->m_imData->lastKeyEvent);
     }
 
-#if wxUSE_UNICODE
-    const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str );
-#else
-    const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str );
-    const wxCharBuffer data = wxConvLocal.cWC2MB( wdata );
-#endif // wxUSE_UNICODE
-    if( !(const wxChar*)data )
+    const wxWxCharBuffer data(wxGTK_CONV_BACK(str));
+    if( !data )
         return;
 
     bool ret = false;
@@ -1223,8 +1235,8 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context,
             event.m_keyCode = *pstr - 'a' + 1;
 #if wxUSE_UNICODE
             event.m_uniChar = event.m_keyCode;
-#endif  
-        }               
+#endif
+        }
 
         if (parent)
         {
@@ -1247,9 +1259,10 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context,
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_window_key_release_callback( GtkWidget *widget,
-                                             GdkEventKey *gdk_event,
-                                             wxWindowGTK *win )
+static gboolean
+gtk_window_key_release_callback( GtkWidget *widget,
+                                 GdkEventKey *gdk_event,
+                                 wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1420,9 +1433,10 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_window_button_press_callback( GtkWidget *widget,
-                                              GdkEventButton *gdk_event,
-                                              wxWindowGTK *win )
+static gboolean
+gtk_window_button_press_callback( GtkWidget *widget,
+                                  GdkEventButton *gdk_event,
+                                  wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1578,6 +1592,10 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
     if ( !g_captureWindow )
         win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
 
+    // reset the event object and id in case win changed.
+    event.SetEventObject( win );
+    event.SetId( win->GetId() );
+
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
         g_signal_stop_emission_by_name (widget, "button_press_event");
@@ -1610,9 +1628,10 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_window_button_release_callback( GtkWidget *widget,
-                                                GdkEventButton *gdk_event,
-                                                wxWindowGTK *win )
+static gboolean
+gtk_window_button_release_callback( GtkWidget *widget,
+                                    GdkEventButton *gdk_event,
+                                    wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1657,6 +1676,10 @@ static gint gtk_window_button_release_callback( GtkWidget *widget,
     if ( !g_captureWindow )
         win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
 
+    // reset the event object and id in case win changed.
+    event.SetEventObject( win );
+    event.SetId( win->GetId() );
+
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
         g_signal_stop_emission_by_name (widget, "button_release_event");
@@ -1672,9 +1695,10 @@ static gint gtk_window_button_release_callback( GtkWidget *widget,
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_window_motion_notify_callback( GtkWidget *widget,
-                                               GdkEventMotion *gdk_event,
-                                               wxWindowGTK *win )
+static gboolean
+gtk_window_motion_notify_callback( GtkWidget *widget,
+                                   GdkEventMotion *gdk_event,
+                                   wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1731,6 +1755,19 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
     else // no capture
     {
         win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+        // reset the event object and id in case win changed.
+        event.SetEventObject( win );
+        event.SetId( win->GetId() );
+    }
+
+    if ( !g_captureWindow )
+    {
+        wxSetCursorEvent cevent( event.m_x, event.m_y );
+        if (win->GetEventHandler()->ProcessEvent( cevent ))
+        {
+            // Rewrite cursor handling here (away from idle).
+        }
     }
 
     if (win->GetEventHandler()->ProcessEvent( event ))
@@ -1744,28 +1781,25 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
 }
 
 //-----------------------------------------------------------------------------
-// "mouse_wheel_event"
+// "scroll_event", (mouse wheel event)
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_window_wheel_callback (GtkWidget * widget,
-                                       GdkEventScroll * gdk_event,
-                                       wxWindowGTK * win)
+static gboolean
+window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
 {
     DEBUG_MAIN_THREAD
 
     if (g_isIdle)
         wxapp_install_idle_handler();
 
-    wxEventType event_type = wxEVT_NULL;
-    if (gdk_event->direction == GDK_SCROLL_UP)
-        event_type = wxEVT_MOUSEWHEEL;
-    else if (gdk_event->direction == GDK_SCROLL_DOWN)
-        event_type = wxEVT_MOUSEWHEEL;
-    else
-        return FALSE;
+    if (gdk_event->direction != GDK_SCROLL_UP &&
+        gdk_event->direction != GDK_SCROLL_DOWN)
+    {
+        return false;
+    }
 
-    wxMouseEvent event( event_type );
+    wxMouseEvent event(wxEVT_MOUSEWHEEL);
     // Can't use InitMouse macro because scroll events don't have button
     event.SetTimestamp( gdk_event->time );
     event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
@@ -1790,13 +1824,7 @@ static gint gtk_window_wheel_callback (GtkWidget * widget,
     event.SetId( win->GetId() );
     event.SetTimestamp( gdk_event->time );
 
-    if (win->GetEventHandler()->ProcessEvent( event ))
-    {
-        g_signal_stop_emission_by_name (widget, "scroll_event");
-        return TRUE;
-    }
-
-    return FALSE;
+    return win->GetEventHandler()->ProcessEvent(event);
 }
 }
 
@@ -1835,9 +1863,10 @@ static bool DoSendFocusEvents(wxWindow *win)
 }
 
 extern "C" {
-static gint gtk_window_focus_in_callback( GtkWidget *widget,
-                                          GdkEvent *WXUNUSED(event),
-                                          wxWindow *win )
+static gboolean
+gtk_window_focus_in_callback( GtkWidget *widget,
+                              GdkEventFocus *WXUNUSED(event),
+                              wxWindow *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1867,19 +1896,24 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     }
 #endif // wxUSE_CARET
 
+    gboolean ret = FALSE;
+
     // does the window itself think that it has the focus?
     if ( !win->m_hasFocus )
     {
         // not yet, notify it
         win->m_hasFocus = true;
 
-        if ( DoSendFocusEvents(win) )
-        {
-           g_signal_stop_emission_by_name (widget, "focus_in_event");
-           return TRUE;
-        }
+        (void)DoSendFocusEvents(win);
+
+        ret = TRUE;
     }
 
+    // Disable default focus handling for custom windows
+    // since the default GTK+ handler issues a repaint
+    if (win->m_wxwindow)
+        return ret;
+
     return FALSE;
 }
 }
@@ -1889,7 +1923,10 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
+static gboolean
+gtk_window_focus_out_callback( GtkWidget *widget,
+                               GdkEventFocus *gdk_event,
+                               wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1923,6 +1960,8 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk
     }
 #endif // wxUSE_CARET
 
+    gboolean ret = FALSE;
+
     // don't send the window a kill focus event if it thinks that it doesn't
     // have focus already
     if ( win->m_hasFocus )
@@ -1932,13 +1971,16 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk
         wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
         event.SetEventObject( win );
 
-        // even if we did process the event in wx code, still let GTK itself
-        // process it too as otherwise bad things happen, especially in GTK2
-        // where the text control simply aborts the program if it doesn't get
-        // the matching focus out event
         (void)win->GetEventHandler()->ProcessEvent( event );
+
+        ret = TRUE;
     }
 
+    // Disable default focus handling for custom windows
+    // since the default GTK+ handler issues a repaint
+    if (win->m_wxwindow)
+        return ret;
+
     return FALSE;
 }
 }
@@ -1948,10 +1990,10 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static
-gint gtk_window_enter_callback( GtkWidget *widget,
-                                GdkEventCrossing *gdk_event,
-                                wxWindowGTK *win )
+static gboolean
+gtk_window_enter_callback( GtkWidget *widget,
+                           GdkEventCrossing *gdk_event,
+                           wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1978,6 +2020,15 @@ gint gtk_window_enter_callback( GtkWidget *widget,
     event.m_x = x + pt.x;
     event.m_y = y + pt.y;
 
+    if ( !g_captureWindow )
+    {
+        wxSetCursorEvent cevent( event.m_x, event.m_y );
+        if (win->GetEventHandler()->ProcessEvent( cevent ))
+        {
+            // Rewrite cursor handling here (away from idle).
+        }
+    }
+
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
        g_signal_stop_emission_by_name (widget, "enter_notify_event");
@@ -1993,7 +2044,10 @@ gint gtk_window_enter_callback( GtkWidget *widget,
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
+static gboolean
+gtk_window_leave_callback( GtkWidget *widget,
+                           GdkEventCrossing *gdk_event,
+                           wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -2041,65 +2095,23 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_
 }
 
 //-----------------------------------------------------------------------------
-// "value_changed" from m_vAdjust
-//-----------------------------------------------------------------------------
-
-extern "C" {
-static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
-                                         wxWindowGTK *win )
-{
-    DEBUG_MAIN_THREAD
-
-    if (g_isIdle)
-        wxapp_install_idle_handler();
-
-    if (g_blockEventsOnDrag) return;
-
-    if (!win->m_hasVMT) return;
-
-    float diff = adjust->value - win->m_oldVerticalPos;
-    if (fabs(diff) < 0.2) return;
-
-    win->m_oldVerticalPos = adjust->value;
-
-    wxEventType command = GtkScrollWinTypeToWx(GTK_SCROLL_JUMP);
-
-    int value = (int)(adjust->value+0.5);
-
-    wxScrollWinEvent event( command, value, wxVERTICAL );
-    event.SetEventObject( win );
-    win->GetEventHandler()->ProcessEvent( event );
-}
-}
-
-//-----------------------------------------------------------------------------
-// "value_changed" from m_hAdjust
+// "value_changed" from scrollbar
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
-                                         wxWindowGTK *win )
+static void
+gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win)
 {
-    DEBUG_MAIN_THREAD
-
-    if (g_isIdle)
-        wxapp_install_idle_handler();
-
-    if (g_blockEventsOnDrag) return;
-    if (!win->m_hasVMT) return;
-
-    float diff = adjust->value - win->m_oldHorizontalPos;
-    if (fabs(diff) < 0.2) return;
-
-    wxEventType command = GtkScrollWinTypeToWx(GTK_SCROLL_JUMP);
-
-    win->m_oldHorizontalPos = adjust->value;
-
-    int value = (int)(adjust->value+0.5);
-
-    wxScrollWinEvent event( command, value, wxHORIZONTAL );
-    event.SetEventObject( win );
-    win->GetEventHandler()->ProcessEvent( event );
+    wxEventType eventType = win->GetScrollEventType(range);
+    if (eventType != wxEVT_NULL)
+    {
+        // Convert scroll event type to scrollwin event type
+        eventType += wxEVT_SCROLLWIN_TOP - wxEVT_SCROLL_TOP;
+        const int orient = range == win->m_scrollBar[0] ? wxHORIZONTAL : wxVERTICAL;
+        wxScrollWinEvent event(eventType, win->GetScrollPos(orient), orient);
+        event.SetEventObject(win);
+        win->GetEventHandler()->ProcessEvent(event);
+    }
 }
 }
 
@@ -2108,24 +2120,18 @@ static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
-                                                 GdkEventButton *gdk_event,
-                                                 wxWindowGTK *win)
+static gboolean
+gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, wxWindow* win)
 {
     DEBUG_MAIN_THREAD
 
     if (g_isIdle)
         wxapp_install_idle_handler();
 
-
     g_blockEventsOnScroll = true;
+    win->m_mouseButtonDown = true;
 
-// FIXME: there is no 'slider' field in GTK+ 2.0 any more
-#if 0
-    win->m_isScrolling = (gdk_event->window == widget->slider);
-#endif
-
-    return FALSE;
+    return false;
 }
 }
 
@@ -2134,45 +2140,24 @@ static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
-                                                   GdkEventButton *WXUNUSED(gdk_event),
-                                                   wxWindowGTK *win)
+static gboolean
+gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* win)
 {
     DEBUG_MAIN_THREAD
 
-//  don't test here as we can release the mouse while being over
-//  a different window than the slider
-//
-//    if (gdk_event->window != widget->slider) return FALSE;
-
     g_blockEventsOnScroll = false;
-
+    win->m_mouseButtonDown = false;
+    // If thumb tracking
     if (win->m_isScrolling)
     {
-        wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
-        int value = -1;
-        int dir = -1;
-
-        GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
-        if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
-        {
-            value = (int)(win->m_hAdjust->value+0.5);
-            dir = wxHORIZONTAL;
-        }
-        if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
-        {
-            value = (int)(win->m_vAdjust->value+0.5);
-            dir = wxVERTICAL;
-        }
-
-        wxScrollWinEvent event( command, value, dir );
-        event.SetEventObject( win );
-        win->GetEventHandler()->ProcessEvent( event );
+        win->m_isScrolling = false;
+        const int orient = range == win->m_scrollBar[0] ? wxHORIZONTAL : wxVERTICAL;
+        wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBRELEASE, win->GetScrollPos(orient), orient);
+        event.SetEventObject(win);
+        win->GetEventHandler()->ProcessEvent(event);
     }
 
-    win->m_isScrolling = false;
-
-    return FALSE;
+    return false;
 }
 }
 
@@ -2195,7 +2180,7 @@ wxWindow *wxWindowBase::DoFindFocus()
    been realized, so we do this directly after realization. */
 
 extern "C" {
-static gint
+static void
 gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
 {
     DEBUG_MAIN_THREAD
@@ -2213,8 +2198,6 @@ gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
     wxWindowCreateEvent event( win );
     event.SetEventObject( win );
     win->GetEventHandler()->ProcessEvent( event );
-
-    return FALSE;
 }
 }
 
@@ -2231,8 +2214,6 @@ void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
     if (g_isIdle)
         wxapp_install_idle_handler();
 
-    if (!win->m_hasScrolling) return;
-
     int client_width = 0;
     int client_height = 0;
     win->GetClientSize( &client_width, &client_height );
@@ -2277,7 +2258,7 @@ void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
     {
         gint width, height;
 
-        gdk_window_get_size (widget->window, &width, &height);
+        gdk_drawable_get_size (widget->window, &width, &height);
         win->m_icattr->preedit_area.width = width;
         win->m_icattr->preedit_area.height = height;
         gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
@@ -2293,7 +2274,7 @@ void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
 /* Initialize XIM support */
 
 extern "C" {
-static gint
+static void
 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
                                 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
 {
@@ -2301,12 +2282,12 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
         wxapp_install_idle_handler();
 
 #ifdef HAVE_XIM
-    if (win->m_ic) return FALSE;
-    if (!widget) return FALSE;
-    if (!gdk_im_ready()) return FALSE;
+    if (win->m_ic) return;
+    if (!widget) return;
+    if (!gdk_im_ready()) return;
 
     win->m_icattr = gdk_ic_attr_new();
-    if (!win->m_icattr) return FALSE;
+    if (!win->m_icattr) return;
 
     gint width, height;
     GdkEventMask mask;
@@ -2348,7 +2329,7 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
                 break;
             }
 
-            gdk_window_get_size (widget->window, &width, &height);
+            gdk_drawable_get_size (widget->window, &width, &height);
 
             attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
             attr->spot_location.x = 0;
@@ -2376,8 +2357,6 @@ gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
               gdk_im_begin (win->m_ic, widget->window);
       }
 #endif // HAVE_XIM
-
-    return FALSE;
 }
 }
 
@@ -2477,11 +2456,14 @@ void wxWindowGTK::Init()
 
     m_hasScrolling = false;
     m_isScrolling = false;
+    m_mouseButtonDown = false;
+    m_blockScrollEvent = false;
+
+    m_scrollBar[0] =
+    m_scrollBar[1] = NULL;
+    m_scrollPos[0] =
+    m_scrollPos[1] = 0;
 
-    m_hAdjust = (GtkAdjustment*) NULL;
-    m_vAdjust = (GtkAdjustment*) NULL;
-    m_oldHorizontalPos =
-    m_oldVerticalPos = 0.0;
     m_oldClientWidth =
     m_oldClientHeight = 0;
 
@@ -2545,8 +2527,8 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
     gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
 
-    m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
-    m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
+    m_scrollBar[0] = GTK_RANGE(scrolledWindow->hscrollbar);
+    m_scrollBar[1] = GTK_RANGE(scrolledWindow->vscrollbar);
 
     m_wxwindow = gtk_pizza_new();
 
@@ -2576,42 +2558,24 @@ bool wxWindowGTK::Create( wxWindow *parent,
     GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
     m_acceptsFocus = true;
 
-    // I _really_ don't want scrollbars in the beginning
-    m_vAdjust->lower = 0.0;
-    m_vAdjust->upper = 1.0;
-    m_vAdjust->value = 0.0;
-    m_vAdjust->step_increment = 1.0;
-    m_vAdjust->page_increment = 1.0;
-    m_vAdjust->page_size = 5.0;
-    g_signal_emit_by_name (m_vAdjust, "changed");
-    m_hAdjust->lower = 0.0;
-    m_hAdjust->upper = 1.0;
-    m_hAdjust->value = 0.0;
-    m_hAdjust->step_increment = 1.0;
-    m_hAdjust->page_increment = 1.0;
-    m_hAdjust->page_size = 5.0;
-    g_signal_emit_by_name (m_hAdjust, "changed");
-
     // 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 (scrolledWindow->vscrollbar, "button_press_event",
-                      G_CALLBACK (gtk_scrollbar_button_press_callback), this);
-    g_signal_connect (scrolledWindow->hscrollbar, "button_press_event",
-                      G_CALLBACK (gtk_scrollbar_button_press_callback), this);
-    g_signal_connect (scrolledWindow->vscrollbar, "button_release_event",
-                      G_CALLBACK (gtk_scrollbar_button_release_callback), this);
-    g_signal_connect (scrolledWindow->hscrollbar, "button_release_event",
-                      G_CALLBACK (gtk_scrollbar_button_release_callback), this);
-
-    // these handlers get notified when screen updates are required either when
-    // scrolling or when the window size (and therefore scrollbar configuration)
-    // has changed
-
-    g_signal_connect (m_hAdjust, "value_changed",
-                      G_CALLBACK (gtk_window_hscroll_callback), this);
-    g_signal_connect (m_vAdjust, "value_changed",
-                      G_CALLBACK (gtk_window_vscroll_callback), this);
+    g_signal_connect(m_scrollBar[0], "button_press_event",
+                     G_CALLBACK(gtk_scrollbar_button_press_event), this);
+    g_signal_connect(m_scrollBar[1], "button_press_event",
+                     G_CALLBACK(gtk_scrollbar_button_press_event), this);
+    g_signal_connect(m_scrollBar[0], "button_release_event",
+                     G_CALLBACK(gtk_scrollbar_button_release_event), this);
+    g_signal_connect(m_scrollBar[1], "button_release_event",
+                     G_CALLBACK(gtk_scrollbar_button_release_event), this);
+
+    // these handlers get notified when scrollbar slider moves
+
+    g_signal_connect(m_scrollBar[0], "value_changed",
+                     G_CALLBACK(gtk_scrollbar_value_changed), this);
+    g_signal_connect(m_scrollBar[1], "value_changed",
+                     G_CALLBACK(gtk_scrollbar_value_changed), this);
 
     gtk_widget_show( m_wxwindow );
 
@@ -2733,10 +2697,20 @@ void wxWindowGTK::PostCreation()
         if (m_focusWidget == NULL)
             m_focusWidget = m_widget;
 
-        g_signal_connect (m_focusWidget, "focus_in_event",
+        if (m_wxwindow)
+        {
+            g_signal_connect (m_focusWidget, "focus_in_event",
+                          G_CALLBACK (gtk_window_focus_in_callback), this);
+            g_signal_connect (m_focusWidget, "focus_out_event",
+                                G_CALLBACK (gtk_window_focus_out_callback), this);
+        }
+        else
+        {
+            g_signal_connect_after (m_focusWidget, "focus_in_event",
                           G_CALLBACK (gtk_window_focus_in_callback), this);
-        g_signal_connect_after (m_focusWidget, "focus_out_event",
+            g_signal_connect_after (m_focusWidget, "focus_out_event",
                                 G_CALLBACK (gtk_window_focus_out_callback), this);
+        }
     }
 
     // connect to the various key and mouse handlers
@@ -2807,7 +2781,7 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
     g_signal_connect (widget, "motion_notify_event",
                       G_CALLBACK (gtk_window_motion_notify_callback), this);
     g_signal_connect (widget, "scroll_event",
-                      G_CALLBACK (gtk_window_wheel_callback), this);
+                      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",
@@ -2850,9 +2824,46 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
         y = currentY;
     AdjustForParentClientOrigin(x, y, sizeFlags);
 
-    if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
+    // calculate the best size if we should auto size the window
+    if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
+         ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
+    {
+        const wxSize sizeBest = GetBestSize();
+        if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
+            width = sizeBest.x;
+        if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
+            height = sizeBest.y;
+    }
+
+    if (width != -1)
+        m_width = width;
+    if (height != -1)
+        m_height = height;
+
+    int minWidth  = GetMinWidth(),
+        minHeight = GetMinHeight(),
+        maxWidth  = GetMaxWidth(),
+        maxHeight = GetMaxHeight();
+
+    if ((minWidth  != -1) && (m_width  < minWidth )) m_width  = minWidth;
+    if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
+    if ((maxWidth  != -1) && (m_width  > maxWidth )) m_width  = maxWidth;
+    if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
+
+#if wxUSE_TOOLBAR_NATIVE
+    if (wxDynamicCast(GetParent(), wxToolBar))
+    {
+       // don't take the x,y values, they're wrong because toolbar sets them
+       GtkWidget  *widget = GTK_WIDGET(m_widget);
+       gtk_widget_set_size_request (widget, m_width, m_height);
+       if (GTK_WIDGET_VISIBLE (widget))
+            gtk_widget_queue_resize (widget);
+    }
+    else
+#endif
+    if (m_parent->m_wxwindow == NULL) // i.e. wxNotebook
     {
-        /* don't set the size for children of wxNotebook, just take the values. */
+        // don't set the size for children of wxNotebook, just take the values.
         m_x = x;
         m_y = y;
         m_width = width;
@@ -2872,32 +2883,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
             m_y = y + pizza->yoffset;
         }
 
-        // calculate the best size if we should auto size the window
-        if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
-                ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
-        {
-            const wxSize sizeBest = GetBestSize();
-            if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
-                width = sizeBest.x;
-            if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
-                height = sizeBest.y;
-        }
-
-        if (width != -1)
-            m_width = width;
-        if (height != -1)
-            m_height = height;
-
-        int minWidth = GetMinWidth(),
-            minHeight = GetMinHeight(),
-            maxWidth = GetMaxWidth(),
-            maxHeight = GetMaxHeight();
-
-        if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
-        if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
-        if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
-        if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
-
         int left_border = 0;
         int right_border = 0;
         int top_border = 0;
@@ -3021,135 +3006,76 @@ void wxWindowGTK::DoSetClientSize( int width, int height )
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (!m_wxwindow)
-    {
-        SetSize( width, height );
-    }
-    else
+    if (m_wxwindow)
     {
         int dw = 0;
         int dh = 0;
 
+        if (m_hasScrolling)
+        {
+            GetScrollbarWidth(m_widget, dw, dh);
+        }
+
 #ifndef __WXUNIVERSAL__
         if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
         {
-            /* when using GTK 1.2 we set the shadow border size to 2 */
+            // shadow border size is 2
             dw += 2 * 2;
             dh += 2 * 2;
         }
         if (HasFlag(wxSIMPLE_BORDER))
         {
-            /* when using GTK 1.2 we set the simple border size to 1 */
+            // simple border size is 1
             dw += 1 * 2;
             dh += 1 * 2;
         }
 #endif // __WXUNIVERSAL__
 
-        if (m_hasScrolling)
-        {
-            GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
-
-            GtkRequisition vscroll_req;
-            vscroll_req.width = 2;
-            vscroll_req.height = 2;
-            (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
-                (scroll_window->vscrollbar, &vscroll_req );
-
-            GtkRequisition hscroll_req;
-            hscroll_req.width = 2;
-            hscroll_req.height = 2;
-            (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
-                (scroll_window->hscrollbar, &hscroll_req );
-
-            GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
-
-            if (scroll_window->vscrollbar_visible)
-            {
-                dw += vscroll_req.width;
-                dw += scroll_class->scrollbar_spacing;
-            }
-
-            if (scroll_window->hscrollbar_visible)
-            {
-                dh += hscroll_req.height;
-                dh += scroll_class->scrollbar_spacing;
-            }
-        }
-
-       SetSize( width+dw, height+dh );
+        width += dw;
+        height += dh;
     }
+
+    SetSize(width, height);
 }
 
 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (!m_wxwindow)
-    {
-        if (width) (*width) = m_width;
-        if (height) (*height) = m_height;
-    }
-    else
+    int w = m_width;
+    int h = m_height;
+
+    if (m_wxwindow)
     {
         int dw = 0;
         int dh = 0;
 
+        if (m_hasScrolling)
+        {
+            GetScrollbarWidth(m_widget, dw, dh);
+        }
+
 #ifndef __WXUNIVERSAL__
         if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
         {
-            /* when using GTK 1.2 we set the shadow border size to 2 */
+            // shadow border size is 2
             dw += 2 * 2;
             dh += 2 * 2;
         }
         if (HasFlag(wxSIMPLE_BORDER))
         {
-            /* when using GTK 1.2 we set the simple border size to 1 */
+            // simple border size is 1
             dw += 1 * 2;
             dh += 1 * 2;
         }
 #endif // __WXUNIVERSAL__
 
-        if (m_hasScrolling)
-        {
-            GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
-
-            GtkRequisition vscroll_req;
-            vscroll_req.width = 2;
-            vscroll_req.height = 2;
-            (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
-                (scroll_window->vscrollbar, &vscroll_req );
-
-            GtkRequisition hscroll_req;
-            hscroll_req.width = 2;
-            hscroll_req.height = 2;
-            (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
-                (scroll_window->hscrollbar, &hscroll_req );
-
-            GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
-
-            if (scroll_window->vscrollbar_visible)
-            {
-                dw += vscroll_req.width;
-                dw += scroll_class->scrollbar_spacing;
-            }
-
-            if (scroll_window->hscrollbar_visible)
-            {
-                dh += hscroll_req.height;
-                dh += scroll_class->scrollbar_spacing;
-            }
-        }
-
-        if (width) (*width) = m_width - dw;
-        if (height) (*height) = m_height - dh;
+        w -= dw;
+        h -= dh;
     }
 
-/*
-    printf( "GetClientSize, name %s ", GetName().c_str() );
-    if (width) printf( " width = %d", (*width) );
-    if (height) printf( " height = %d", (*height) );
-    printf( "\n" );
-*/
+    if (width) *width = w;
+    if (height) *height = h;
 }
 
 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
@@ -3309,7 +3235,7 @@ int wxWindowGTK::GetCharHeight() const
     PangoRectangle rect;
     pango_layout_line_get_extents(line, NULL, &rect);
 
-    g_object_unref( G_OBJECT( layout ) );
+    g_object_unref (layout);
 
     return (int) PANGO_PIXELS(rect.height);
 }
@@ -3337,7 +3263,7 @@ int wxWindowGTK::GetCharWidth() const
     PangoRectangle rect;
     pango_layout_line_get_extents(line, NULL, &rect);
 
-    g_object_unref( G_OBJECT( layout ) );
+    g_object_unref (layout);
 
     return (int) PANGO_PIXELS(rect.width);
 }
@@ -3375,14 +3301,9 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
     PangoLayout *layout = pango_layout_new(context);
     pango_layout_set_font_description(layout, desc);
     {
-#if wxUSE_UNICODE
-        const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
-        pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
-#else
-        const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
-        const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
-        pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
-#endif
+        const wxCharBuffer data = wxGTK_CONV( string );
+        if ( data )
+            pango_layout_set_text(layout, data, strlen(data));
     }
 
     PangoRectangle rect;
@@ -3399,7 +3320,7 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
     }
     if (externalLeading) (*externalLeading) = 0;  // ??
 
-    g_object_unref( G_OBJECT( layout ) );
+    g_object_unref (layout);
 }
 
 void wxWindowGTK::SetFocus()
@@ -3537,44 +3458,62 @@ void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
         wxapp_install_idle_handler();
 }
 
+bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
+{
+    // none needed by default
+    return false;
+}
+
+void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget* WXUNUSED(w))
+{
+    // nothing to do by default since none is needed
+}
+
 void wxWindowGTK::RealizeTabOrder()
 {
     if (m_wxwindow)
     {
         if ( !m_children.empty() )
         {
-#if wxUSE_STATTEXT
             // we don't only construct the correct focus chain but also use
-            // this opportunity to update the mnemonic widgets for all labels
-            //
-            // it would be nice to extract this code from here and put it in
-            // stattext.cpp to reduce dependencies but there is no really easy
-            // way to do it unfortunately
-            wxStaticText *lastLabel = NULL;
-#endif // wxUSE_STATTEXT
+            // this opportunity to update the mnemonic widgets for the widgets
+            // that need them
 
             GList *chain = NULL;
+            wxWindowGTK* mnemonicWindow = NULL;
 
             for ( wxWindowList::const_iterator i = m_children.begin();
                   i != m_children.end();
                   ++i )
             {
                 wxWindowGTK *win = *i;
-#if wxUSE_STATTEXT
-                if ( lastLabel )
+
+                if ( mnemonicWindow )
                 {
                     if ( win->AcceptsFocusFromKeyboard() )
                     {
-                        GtkLabel *l = GTK_LABEL(lastLabel->m_widget);
-                        gtk_label_set_mnemonic_widget(l, win->m_widget);
-                        lastLabel = NULL;
+                        // 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) )
+                        {
+                            w = win->GetConnectWidget();
+                            if ( !GTK_WIDGET_CAN_FOCUS(w) )
+                                w = NULL;
+                        }
+
+                        if ( w )
+                        {
+                            mnemonicWindow->GTKWidgetDoSetMnemonic(w);
+                            mnemonicWindow = NULL;
+                        }
                     }
                 }
-                else // check if this one is a label
+                else if ( win->GTKWidgetNeedsMnemonic() )
                 {
-                    lastLabel = wxDynamicCast(win, wxStaticText);
+                    mnemonicWindow = win;
                 }
-#endif // wxUSE_STATTEXT
 
                 chain = g_list_prepend(chain, win->m_widget);
             }
@@ -3652,38 +3591,32 @@ void wxWindowGTK::WarpPointer( int x, int y )
         gdk_window_warp_pointer( window, x, y );
 }
 
-static bool wxScrollAdjust(GtkAdjustment* adj, double change)
+bool wxWindowGTK::ScrollLines(int lines)
 {
-    double value_start = adj->value;
-    double value = value_start + change;
-    double upper = adj->upper - adj->page_size;
-    if (value > upper)
+    bool changed = false;
+    GtkRange* range = m_scrollBar[1];
+    if (range != NULL)
     {
-        value = upper;
+        GtkAdjustment* adj = range->adjustment;
+        const int pos = int(adj->value + 0.5);
+        gtk_range_set_value(range, pos + lines);
+        changed = pos != int(adj->value + 0.5);
     }
-    // Lower bound will be checked by gtk_adjustment_set_value
-    gtk_adjustment_set_value(adj, value);
-    return adj->value != value_start;
-}
-
-bool wxWindowGTK::ScrollLines(int lines)
-{
-    return
-        m_vAdjust != NULL &&
-        wxScrollAdjust(m_vAdjust, lines * m_vAdjust->step_increment);
+    return changed;
 }
 
 bool wxWindowGTK::ScrollPages(int pages)
 {
-    return
-        m_vAdjust != NULL &&
-        wxScrollAdjust(m_vAdjust, pages * m_vAdjust->page_increment);
-}
-
-void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment* adj)
-{
-    wxASSERT(m_vAdjust == NULL);
-    m_vAdjust = adj;
+    bool changed = false;
+    GtkRange* range = m_scrollBar[1];
+    if (range != NULL)
+    {
+        GtkAdjustment* adj = range->adjustment;
+        const int pos = int(adj->value + 0.5);
+        gtk_range_set_value(range, pos + pages * adj->page_size);
+        changed = pos != int(adj->value + 0.5);
+    }
+    return changed;
 }
 
 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
@@ -4059,7 +3992,7 @@ void wxWindowGTK::DoCaptureMouse()
 
     wxCHECK_RET( window, _T("CaptureMouse() failed") );
 
-    wxCursor* cursor = & m_cursor;
+    const wxCursor* cursor = &m_cursor;
     if (!cursor->Ok())
         cursor = wxSTANDARD_CURSOR;
 
@@ -4107,80 +4040,47 @@ bool wxWindowGTK::IsRetained() const
     return false;
 }
 
+void wxWindowGTK::BlockScrollEvent()
+{
+    wxASSERT(!m_blockScrollEvent);
+    m_blockScrollEvent = true;
+}
+
+void wxWindowGTK::UnblockScrollEvent()
+{
+    wxASSERT(m_blockScrollEvent);
+    m_blockScrollEvent = false;
+}
+
 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
-      int range, bool refresh )
+      int range, bool )
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
-
     wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
 
-    m_hasScrolling = true;
-
-    if (orient == wxHORIZONTAL)
+    if (range > 0)
     {
-        float fpos = (float)pos;
-        float frange = (float)range;
-        float fthumb = (float)thumbVisible;
-        if (fpos > frange-fthumb) fpos = frange-fthumb;
-        if (fpos < 0.0) fpos = 0.0;
-
-        if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
-            (fabs(fthumb-m_hAdjust->page_size) < 0.2))
-        {
-            SetScrollPos( orient, pos, refresh );
-            return;
-        }
-
-        m_oldHorizontalPos = fpos;
-
-        m_hAdjust->lower = 0.0;
-        m_hAdjust->upper = frange;
-        m_hAdjust->value = fpos;
-        m_hAdjust->step_increment = 1.0;
-        m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
-        m_hAdjust->page_size = fthumb;
+        m_hasScrolling = true;
     }
     else
     {
-        float fpos = (float)pos;
-        float frange = (float)range;
-        float fthumb = (float)thumbVisible;
-        if (fpos > frange-fthumb) fpos = frange-fthumb;
-        if (fpos < 0.0) fpos = 0.0;
-
-        if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
-            (fabs(fthumb-m_vAdjust->page_size) < 0.2))
-        {
-            SetScrollPos( orient, pos, refresh );
-            return;
-        }
-
-        m_oldVerticalPos = fpos;
-
-        m_vAdjust->lower = 0.0;
-        m_vAdjust->upper = frange;
-        m_vAdjust->value = fpos;
-        m_vAdjust->step_increment = 1.0;
-        m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
-        m_vAdjust->page_size = fthumb;
+        // GtkRange requires upper > lower
+        range =
+        thumbVisible = 1;
     }
 
-    if (orient == wxHORIZONTAL)
-        g_signal_emit_by_name (m_hAdjust, "changed");
-    else
-        g_signal_emit_by_name (m_vAdjust, "changed");
-}
-
-void wxWindowGTK::GtkUpdateScrollbar(int orient)
-{
-    GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
-    gpointer fn = orient == wxHORIZONTAL
-            ? (gpointer) gtk_window_hscroll_callback
-            : (gpointer) gtk_window_vscroll_callback;
+    const int i = orient == wxVERTICAL;
+    GtkAdjustment* adj = m_scrollBar[i]->adjustment;
+    adj->value = pos;
+    adj->step_increment = 1;
+    adj->page_increment =
+    adj->page_size = thumbVisible;
 
-    g_signal_handlers_disconnect_by_func (adj, fn, this);
-    g_signal_emit_by_name (adj, "value_changed");
-    g_signal_connect (adj, "value_changed", G_CALLBACK (fn), this);
+    BlockScrollEvent();
+    // automatically clamps value to [0,range-page_size], and emits change events
+    gtk_range_set_range(m_scrollBar[i], 0, range);
+    UnblockScrollEvent();
+    m_scrollPos[i] = adj->value;
 }
 
 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
@@ -4188,58 +4088,98 @@ void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
     wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
 
-    GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
-
-    float fpos = (float)pos;
-    if (fpos > adj->upper - adj->page_size)
-        fpos = adj->upper - adj->page_size;
-    if (fpos < 0.0)
-        fpos = 0.0;
-    *(orient == wxHORIZONTAL ? &m_oldHorizontalPos : &m_oldVerticalPos) = fpos;
-
-    if (fabs(fpos-adj->value) < 0.2)
-        return;
-    adj->value = fpos;
-
-    if ( m_wxwindow->window )
+    // This check is more than an optimization. Without it, the slider
+    //   will not move smoothly while tracking when using wxScrollHelper.
+    if (GetScrollPos(orient) != pos)
     {
+        const int i = orient == wxVERTICAL;
+        BlockScrollEvent();
+        gtk_range_set_value(m_scrollBar[i], pos);
+        UnblockScrollEvent();
+        m_scrollPos[i] = m_scrollBar[i]->adjustment->value;
     }
 }
 
 int wxWindowGTK::GetScrollThumb( int orient ) const
 {
     wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
-
     wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
 
-    if (orient == wxHORIZONTAL)
-        return (int)(m_hAdjust->page_size+0.5);
-    else
-        return (int)(m_vAdjust->page_size+0.5);
+    const int i = orient == wxVERTICAL;
+    return int(m_scrollBar[i]->adjustment->page_size);
 }
 
 int wxWindowGTK::GetScrollPos( int orient ) const
 {
     wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
-
     wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
 
-    if (orient == wxHORIZONTAL)
-        return (int)(m_hAdjust->value+0.5);
-    else
-        return (int)(m_vAdjust->value+0.5);
+    const int i = orient == wxVERTICAL;
+    return int(m_scrollBar[i]->adjustment->value + 0.5);
 }
 
 int wxWindowGTK::GetScrollRange( int orient ) const
 {
     wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
-
     wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
 
-    if (orient == wxHORIZONTAL)
-        return (int)(m_hAdjust->upper+0.5);
-    else
-        return (int)(m_vAdjust->upper+0.5);
+    const int i = orient == wxVERTICAL;
+    return int(m_scrollBar[i]->adjustment->upper);
+}
+
+// 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);
+    const double tolerance = 1.0 / 1024;
+    return fabs(increment - fabs(x)) < tolerance;
+}
+
+wxEventType wxWindowGTK::GetScrollEventType(GtkRange* range)
+{
+    DEBUG_MAIN_THREAD
+
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+
+    wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]);
+
+    const int barIndex = range == m_scrollBar[1];
+    GtkAdjustment* adj = range->adjustment;
+    const int value = int(adj->value + 0.5);
+    // save previous position
+    const double oldPos = m_scrollPos[barIndex];
+    // update current position
+    m_scrollPos[barIndex] = adj->value;
+    // If event should be ignored, or integral position has not changed
+    if (!m_hasVMT || g_blockEventsOnDrag || m_blockScrollEvent || value == int(oldPos + 0.5))
+    {
+        return wxEVT_NULL;
+    }
+
+    wxEventType eventType = wxEVT_SCROLL_THUMBTRACK;
+    if (!m_isScrolling)
+    {
+        // Difference from last change event
+        const double diff = adj->value - oldPos;
+        const bool isDown = diff > 0;
+
+        if (IsScrollIncrement(adj->step_increment, diff))
+        {
+            eventType = isDown ? wxEVT_SCROLL_LINEDOWN : wxEVT_SCROLL_LINEUP;
+        }
+        else if (IsScrollIncrement(adj->page_increment, diff))
+        {
+            eventType = isDown ? wxEVT_SCROLL_PAGEDOWN : wxEVT_SCROLL_PAGEUP;
+        }
+        else if (m_mouseButtonDown)
+        {
+            // Assume track event
+            m_isScrolling = true;
+        }
+    }
+    return eventType;
 }
 
 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
@@ -4258,6 +4198,29 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
     m_clipPaintRegion = false;
 }
 
+void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget* w, int wxstyle)
+{
+    //RN: Note that static controls usually have no border on gtk, so maybe
+    //it makes sense to treat that as simply no border at the wx level
+    //as well...
+    if (!(wxstyle & wxNO_BORDER) && !(wxstyle & wxBORDER_STATIC))
+    {
+        GtkShadowType gtkstyle;
+
+        if(wxstyle & wxBORDER_RAISED)
+            gtkstyle = GTK_SHADOW_OUT;
+        else if (wxstyle & wxBORDER_SUNKEN)
+            gtkstyle = GTK_SHADOW_IN;
+        else if (wxstyle & wxBORDER_DOUBLE)
+            gtkstyle = GTK_SHADOW_ETCHED_IN;
+        else //default
+            gtkstyle = GTK_SHADOW_IN;
+
+        gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w),
+                                             gtkstyle );
+    }
+}
+
 void wxWindowGTK::SetWindowStyleFlag( long style )
 {
     // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
@@ -4332,7 +4295,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
 
 bool wxWinModule::OnInit()
 {
-    // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
+    // g_eraseGC = gdk_gc_new( gdk_get_default_root_window() );
     // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
 
     return true;
@@ -4341,6 +4304,5 @@ bool wxWinModule::OnInit()
 void wxWinModule::OnExit()
 {
     if (g_eraseGC)
-        gdk_gc_unref( g_eraseGC );
+        g_object_unref (g_eraseGC);
 }
-