]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
restore previous encoding, changed for error to UTF8
[wxWidgets.git] / src / gtk / window.cpp
index 5b8290f3c88372e4065743214ac4a1ba7c6a3898..b65a255afc355aa00e68e85888d7e86ef4dac8aa 100644 (file)
 #include "wx/fontutil.h"
 #include "wx/sysopt.h"
 
-#ifdef __WXDEBUG__
-    #include "wx/thread.h"
-#endif
-
 #include <ctype.h>
 
 #include "wx/gtk/private.h"
-#include "wx/gtk/win_gtk.h"
+#include "wx/gtk/private/win_gtk.h"
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkx.h>
 
@@ -189,39 +185,23 @@ extern wxCursor   g_globalCursor;
 static wxWindowGTK  *g_captureWindow = (wxWindowGTK*) NULL;
 static bool g_captureWindowHasMouse = false;
 
-wxWindowGTK  *g_focusWindow = (wxWindowGTK*) NULL;
+// The window that currently has focus or is scheduled to get it in the next
+// event loop iteration
+static wxWindowGTK *gs_focusWindow = NULL;
 
-// the last window which had the focus - this is normally never NULL (except
-// if we never had focus at all) as even when g_focusWindow is NULL it still
-// keeps its previous value
-wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL;
-
-// If a window get the focus set but has not been realized
-// yet, defer setting the focus to idle time.
-wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL;
+// the window that has deferred focus-out event pending, if any (see
+// GTKAddDeferredFocusOut() for details)
+static wxWindowGTK *gs_deferredFocusOut = NULL;
 
 // global variables because GTK+ DnD want to have the
 // mouse event that caused it
 GdkEvent    *g_lastMouseEvent = (GdkEvent*) NULL;
 int          g_lastButtonNumber = 0;
 
-extern bool g_mainThreadLocked;
-
 //-----------------------------------------------------------------------------
 // debug
 //-----------------------------------------------------------------------------
 
-#ifdef __WXDEBUG__
-
-#if wxUSE_THREADS
-#   define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
-#else
-#   define DEBUG_MAIN_THREAD
-#endif
-#else
-#define DEBUG_MAIN_THREAD
-#endif // Debug
-
 // the trace mask used for the focus debugging messages
 #define TRACE_FOCUS _T("focus")
 
@@ -247,62 +227,6 @@ gdk_window_warp_pointer (GdkWindow      *window,
   }
 }
 
-//-----------------------------------------------------------------------------
-// local code (see below)
-//-----------------------------------------------------------------------------
-
-// returns the child of win which currently has focus or NULL if not found
-//
-// Note: can't be static, needed by textctrl.cpp.
-wxWindow *wxFindFocusedChild(wxWindowGTK *win)
-{
-    wxWindow *winFocus = wxWindowGTK::FindFocus();
-    if ( !winFocus )
-        return (wxWindow *)NULL;
-
-    if ( winFocus == win )
-        return (wxWindow *)win;
-
-    for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
-          node;
-          node = node->GetNext() )
-    {
-        wxWindow *child = wxFindFocusedChild(node->GetData());
-        if ( child )
-            return child;
-    }
-
-    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;
-    }
-}
 
 //-----------------------------------------------------------------------------
 // "size_request" of m_widget
@@ -332,41 +256,10 @@ void wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
 
 extern "C" {
 static gboolean
-gtk_window_expose_callback( GtkWidget *widget,
+gtk_window_expose_callback( GtkWidget*,
                             GdkEventExpose *gdk_event,
                             wxWindow *win )
 {
-    DEBUG_MAIN_THREAD
-
-    wxPizza *pizza = WX_PIZZA(widget);
-    GdkWindow *backing_window = pizza->m_backing_window;
-
-    int w = widget->allocation.width;
-    int h = widget->allocation.height;
-    
-    // if this event is for the border-only GdkWindow
-    if (backing_window && gdk_event->window == pizza->m_backing_window)
-    {
-        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, 0, 0, w - 1, h - 1);
-            g_object_unref(gc);
-        }
-        else
-        {
-            GtkShadowType shadow = GTK_SHADOW_IN;
-            if (win->HasFlag(wxBORDER_RAISED))
-                shadow = GTK_SHADOW_OUT;
-            gtk_paint_shadow(
-                widget->style, gdk_event->window, GTK_STATE_NORMAL,
-                shadow, NULL, widget, "viewport", 0, 0, w, h);
-        }
-        
-        return TRUE;
-    }
-
 #if 0
     if (win->GetName())
     {
@@ -397,7 +290,7 @@ gtk_window_expose_callback( GtkWidget *widget,
     win->GtkSendPaintEvents();
 
     // Let parent window draw window-less widgets
-    return TRUE;
+    return FALSE;
 }
 }
 
@@ -405,14 +298,16 @@ gtk_window_expose_callback( GtkWidget *widget,
 // "expose_event" from m_widget, for drawing border
 //-----------------------------------------------------------------------------
 
-#if 0
-ndef __WXUNIVERSAL__
+#ifndef __WXUNIVERSAL__
+
+GtkWidget* GetEntryWidget();
+
 extern "C" {
 static gboolean
-expose_event_border(GtkWidget* widget, GdkEventExpose* event, wxWindow* win)
+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 && event->window == widget->window)
+    if (win->m_wxwindow == win->m_widget && gdk_event->window == widget->window)
         return false;
 
     int x = 0;
@@ -427,10 +322,9 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* event, wxWindow* win)
     int h = win->m_wxwindow->allocation.height;
     if (win->HasFlag(wxBORDER_SIMPLE))
     {
-        GdkGC* gc;
-        gc = gdk_gc_new(event->window);
+        GdkGC* gc = gdk_gc_new(gdk_event->window);
         gdk_gc_set_foreground(gc, &widget->style->black);
-        gdk_draw_rectangle(event->window, gc, false, x, y, w - 1, h - 1);
+        gdk_draw_rectangle(gdk_event->window, gc, false, x, y, w - 1, h - 1);
         g_object_unref(gc);
     }
     else
@@ -438,9 +332,20 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* event, wxWindow* win)
         GtkShadowType shadow = GTK_SHADOW_IN;
         if (win->HasFlag(wxBORDER_RAISED))
             shadow = GTK_SHADOW_OUT;
+
+        // Style detail to use
+        const char* detail;
+        if (widget == win->m_wxwindow)
+            // for non-scrollable wxWindows
+            detail = "entry";
+        else
+            // for scrollable ones
+            detail = "viewport";
+
+        GtkWidget* styleWidget = GetEntryWidget();
         gtk_paint_shadow(
-            widget->style, event->window, GTK_STATE_NORMAL,
-            shadow, &event->area, widget, "entry", x, y, w, h);
+           styleWidget->style, gdk_event->window, GTK_STATE_NORMAL,
+           shadow, NULL, styleWidget, detail, x, y, w, h);
     }
 
     // no further painting is needed for border-only GdkWindow
@@ -911,8 +816,6 @@ gtk_window_key_press_callback( GtkWidget *widget,
                                GdkEventKey *gdk_event,
                                wxWindow *win )
 {
-    DEBUG_MAIN_THREAD
-
     if (!win->m_hasVMT)
         return FALSE;
     if (g_blockEventsOnDrag)
@@ -931,7 +834,7 @@ gtk_window_key_press_callback( GtkWidget *widget,
     if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
     {
         // Emit KEY_DOWN event
-        ret = win->GetEventHandler()->ProcessEvent( event );
+        ret = win->HandleWindowEvent( event );
     }
     else
     {
@@ -967,7 +870,7 @@ gtk_window_key_press_callback( GtkWidget *widget,
             if (command != -1)
             {
                 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
-                ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
+                ret = ancestor->HandleWindowEvent( command_event );
                 break;
             }
             if (ancestor->IsTopLevel())
@@ -1026,13 +929,13 @@ gtk_window_key_press_callback( GtkWidget *widget,
             if (parent)
             {
                 event.SetEventType( wxEVT_CHAR_HOOK );
-                ret = parent->GetEventHandler()->ProcessEvent( event );
+                ret = parent->HandleWindowEvent( event );
             }
 
             if (!ret)
             {
                 event.SetEventType(wxEVT_CHAR);
-                ret = win->GetEventHandler()->ProcessEvent( event );
+                ret = win->HandleWindowEvent( event );
             }
         }
     }
@@ -1102,13 +1005,13 @@ gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context),
         if (parent)
         {
             event.SetEventType( wxEVT_CHAR_HOOK );
-            ret = parent->GetEventHandler()->ProcessEvent( event );
+            ret = parent->HandleWindowEvent( event );
         }
 
         if (!ret)
         {
             event.SetEventType(wxEVT_CHAR);
-            ret = window->GetEventHandler()->ProcessEvent( event );
+            ret = window->HandleWindowEvent( event );
         }
     }
 }
@@ -1125,8 +1028,6 @@ gtk_window_key_release_callback( GtkWidget * WXUNUSED(widget),
                                  GdkEventKey *gdk_event,
                                  wxWindowGTK *win )
 {
-    DEBUG_MAIN_THREAD
-
     if (!win->m_hasVMT)
         return FALSE;
 
@@ -1289,13 +1190,11 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
 bool wxWindowGTK::GTKProcessEvent(wxEvent& event) const
 {
     // nothing special at this level
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const
 {
-    DEBUG_MAIN_THREAD
-
     if (!m_hasVMT)
         return FALSE;
     if (g_blockEventsOnDrag)
@@ -1329,21 +1228,6 @@ wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing)
     if ( rc != -1 )                                                           \
         return rc
 
-// send the wxChildFocusEvent and wxFocusEvent, common code of
-// gtk_window_focus_in_callback() and SetFocus()
-static bool DoSendFocusEvents(wxWindow *win)
-{
-    // Notify the parent keeping track of focus for the kbd navigation
-    // purposes that we got it.
-    wxChildFocusEvent eventChildFocus(win);
-    (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
-
-    wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
-    eventFocus.SetEventObject(win);
-
-    return win->GetEventHandler()->ProcessEvent(eventFocus);
-}
-
 // all event handlers must have C linkage as they're called from GTK+ C code
 extern "C"
 {
@@ -1488,7 +1372,7 @@ gtk_window_button_press_callback( GtkWidget *widget,
         return TRUE;
 
     if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
-        (g_focusWindow != win) /* && win->IsFocusable() */)
+        (gs_focusWindow != win) /* && win->IsFocusable() */)
     {
         win->SetFocus();
     }
@@ -1650,8 +1534,6 @@ gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
 static gboolean
 window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
 {
-    DEBUG_MAIN_THREAD
-
     if (gdk_event->direction != GDK_SCROLL_UP &&
         gdk_event->direction != GDK_SCROLL_DOWN)
     {
@@ -1660,6 +1542,8 @@ window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* 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)
@@ -1688,47 +1572,9 @@ static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
 static gboolean
 gtk_window_focus_in_callback( GtkWidget * WXUNUSED(widget),
                               GdkEventFocus *WXUNUSED(event),
-                              wxWindow *win )
+                              wxWindowGTK *win )
 {
-    DEBUG_MAIN_THREAD
-
-    if (win->m_imData)
-        gtk_im_context_focus_in(win->m_imData->context);
-
-    g_focusWindowLast =
-    g_focusWindow = win;
-
-    wxLogTrace(TRACE_FOCUS,
-               _T("%s: focus in"), win->GetName().c_str());
-
-#if wxUSE_CARET
-    // caret needs to be informed about focus change
-    wxCaret *caret = win->GetCaret();
-    if ( caret )
-    {
-        caret->OnSetFocus();
-    }
-#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;
-
-        (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;
+    return win->GTKHandleFocusIn();
 }
 
 //-----------------------------------------------------------------------------
@@ -1740,55 +1586,13 @@ gtk_window_focus_out_callback( GtkWidget * WXUNUSED(widget),
                                GdkEventFocus * WXUNUSED(gdk_event),
                                wxWindowGTK *win )
 {
-    DEBUG_MAIN_THREAD
-
-    if (win->m_imData)
-        gtk_im_context_focus_out(win->m_imData->context);
-
-    wxLogTrace( TRACE_FOCUS,
-                _T("%s: focus out"), win->GetName().c_str() );
-
-
-    wxWindowGTK *winFocus = wxFindFocusedChild(win);
-    if ( winFocus )
-        win = winFocus;
-
-    g_focusWindow = (wxWindowGTK *)NULL;
-
-#if wxUSE_CARET
-    // caret needs to be informed about focus change
-    wxCaret *caret = win->GetCaret();
-    if ( caret )
-    {
-        caret->OnKillFocus();
-    }
-#endif // wxUSE_CARET
-
-    // don't send the window a kill focus event if it thinks that it doesn't
-    // have focus already
-    if ( win->m_hasFocus )
-    {
-        // the event handler might delete the window when it loses focus, so
-        // check whether this is a custom window before calling it
-        const bool has_wxwindow = win->m_wxwindow != NULL;
-
-        win->m_hasFocus = false;
-
-        wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
-        event.SetEventObject( win );
-
-        (void)win->GTKProcessEvent( event );
-
-        // Disable default focus handling for custom windows
-        // since the default GTK+ handler issues a repaint
-        if ( has_wxwindow )
-            return TRUE;
-    }
-
-    // continue with normal processing
-    return FALSE;
+    return win->GTKHandleFocusOut();
 }
 
+//-----------------------------------------------------------------------------
+// "focus"
+//-----------------------------------------------------------------------------
+
 static gboolean
 wx_window_focus_callback(GtkWidget *widget,
                          GtkDirectionType WXUNUSED(direction),
@@ -1904,8 +1708,6 @@ gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win)
 static gboolean
 gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, wxWindow* win)
 {
-    DEBUG_MAIN_THREAD
-
     g_blockEventsOnScroll = true;
     win->m_mouseButtonDown = true;
 
@@ -1939,8 +1741,6 @@ gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win)
 static gboolean
 gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* win)
 {
-    DEBUG_MAIN_THREAD
-
     g_blockEventsOnScroll = false;
     win->m_mouseButtonDown = false;
     // If thumb tracking
@@ -1963,8 +1763,6 @@ gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* w
 static void
 gtk_window_realized_callback(GtkWidget* widget, wxWindow* win)
 {
-    DEBUG_MAIN_THREAD
-
     if (win->m_imData)
     {
         gtk_im_context_set_client_window( win->m_imData->context,
@@ -2036,7 +1834,7 @@ gtk_window_grab_broken( GtkWidget*,
     {
         wxMouseCaptureLostEvent evt( win->GetId() );
         evt.SetEventObject( win );
-        win->GetEventHandler()->ProcessEvent( evt );
+        win->HandleWindowEvent( evt );
     }
     return false;
 }
@@ -2051,11 +1849,8 @@ void gtk_window_style_set_callback( GtkWidget *WXUNUSED(widget),
                                GtkStyle *previous_style,
                                wxWindow* win )
 {
-    //wxLogDebug(wxT("gtk_window_style_set_callback"));
     if (win && previous_style)
     {
-        wxString name(win->GetName());
-        //wxLogDebug(wxT("gtk_window_style_set_callback %s"), name.c_str());
         wxSysColourChangedEvent event;
         event.SetEventObject(win);
 
@@ -2065,40 +1860,28 @@ void gtk_window_style_set_callback( GtkWidget *WXUNUSED(widget),
 
 } // extern "C"
 
-// Connect/disconnect style-set
-
-void wxConnectStyleSet(wxWindow* win)
-{
-    if (win->m_wxwindow)
-        g_signal_connect (win->m_wxwindow, "style_set",
-                              G_CALLBACK (gtk_window_style_set_callback), win);
-}
-
-void wxDisconnectStyleSet(wxWindow* win)
-{
-  if (win->m_wxwindow)
-      g_signal_handlers_disconnect_by_func (win->m_wxwindow,
-                                          (gpointer) gtk_window_style_set_callback,
-                                              win);
-}
-
 // Helper to suspend colour change event event processing while we change a widget's style
 class wxSuspendStyleEvents
 {
 public:
-  wxSuspendStyleEvents(wxWindow* win)
-  {
-    m_win = win;
-    if (win->IsTopLevel())
-      wxDisconnectStyleSet(win);
-  }
-  ~wxSuspendStyleEvents()
-  {
-    if (m_win->IsTopLevel())
-      wxConnectStyleSet(m_win);
-  }
+    wxSuspendStyleEvents(wxWindow* win)
+    {
+        m_win = NULL;
+        if (win->m_wxwindow && win->IsTopLevel())
+        {
+            m_win = win;
+            g_signal_handlers_block_by_func(
+                m_win->m_wxwindow, (void*)gtk_window_style_set_callback, m_win);
+        }
+    }
+    ~wxSuspendStyleEvents()
+    {
+        if (m_win)
+            g_signal_handlers_unblock_by_func(
+                m_win->m_wxwindow, (void*)gtk_window_style_set_callback, m_win);
+    }
 
-  wxWindow* m_win;
+    wxWindow* m_win;
 };
 
 // ----------------------------------------------------------------------------
@@ -2109,7 +1892,7 @@ public:
 wxWindow *wxWindowBase::DoFindFocus()
 {
     // the cast is necessary when we compile in wxUniversal mode
-    return (wxWindow *)g_focusWindow;
+    return wx_static_cast(wxWindow*, gs_focusWindow);
 }
 
 //-----------------------------------------------------------------------------
@@ -2206,7 +1989,6 @@ void wxWindowGTK::Init()
     m_noExpose = false;
     m_nativeSizeEvent = false;
 
-    m_hasScrolling = false;
     m_isScrolling = false;
     m_mouseButtonDown = false;
 
@@ -2222,8 +2004,6 @@ void wxWindowGTK::Init()
 
     m_insertCallback = wxInsertChildInWindow;
 
-    m_hasFocus = false;
-
     m_clipPaintRegion = false;
 
     m_needsStyleChange = false;
@@ -2258,6 +2038,11 @@ bool wxWindowGTK::Create( wxWindow *parent,
                           long style,
                           const wxString &name  )
 {
+    // Get default border
+    wxBorder border = GetBorder(style);
+    style &= ~wxBORDER_MASK;
+    style |= border;
+
     if (!PreCreation( parent, pos, size ) ||
         !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
     {
@@ -2265,13 +2050,13 @@ bool wxWindowGTK::Create( wxWindow *parent,
         return false;
     }
 
+
     m_wxwindow = wxPizza::New(m_windowStyle);
     if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
         m_widget = m_wxwindow;
     else
     {
         m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
-        gtk_container_set_resize_mode(GTK_CONTAINER(m_widget), GTK_RESIZE_QUEUE);
 
         GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
 
@@ -2351,11 +2136,11 @@ wxWindowGTK::~wxWindowGTK()
 {
     SendDestroyEvent();
 
-    if (g_focusWindow == this)
-        g_focusWindow = NULL;
+    if (gs_focusWindow == this)
+        gs_focusWindow = NULL;
 
-    if ( g_delayedFocus == this )
-        g_delayedFocus = NULL;
+    if ( gs_deferredFocusOut == this )
+        gs_deferredFocusOut = NULL;
 
     m_isBeingDeleted = true;
     m_hasVMT = false;
@@ -2439,9 +2224,8 @@ void wxWindowGTK::PostCreation()
                           G_CALLBACK (gtk_wxwindow_commit_cb), this);
 
         // border drawing
-#if 0
-ndef __WXUNIVERSAL__
-        if (HasFlag(wxBORDER_SIMPLE | wxBORDER_RAISED | wxBORDER_SUNKEN))
+#ifndef __WXUNIVERSAL__
+        if (HasFlag(wxPizza::BORDER_STYLES))
         {
             g_signal_connect(m_widget, "expose_event",
                 G_CALLBACK(expose_event_border), this);
@@ -2687,7 +2471,7 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
         {
             wxSizeEvent event( wxSize(m_width,m_height), GetId() );
             event.SetEventObject( this );
-            GetEventHandler()->ProcessEvent( event );
+            HandleWindowEvent( event );
         }
     }
 }
@@ -2705,7 +2489,7 @@ bool wxWindowGTK::GtkShowFromOnIdle()
         gtk_widget_show( m_widget );
         wxShowEvent eventShow(GetId(), true);
         eventShow.SetEventObject(this);
-        GetEventHandler()->ProcessEvent(eventShow);
+        HandleWindowEvent(eventShow);
         m_showOnIdle = false;
         return true;
     }
@@ -2715,6 +2499,9 @@ bool wxWindowGTK::GtkShowFromOnIdle()
 
 void wxWindowGTK::OnInternalIdle()
 {
+    if ( gs_deferredFocusOut )
+        GTKHandleDeferredFocusOut();
+
     // Check if we have to show window now
     if (GtkShowFromOnIdle()) return;
 
@@ -2764,7 +2551,7 @@ void wxWindowGTK::OnInternalIdle()
         }
     }
 
-    if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
+    if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
         UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
 }
 
@@ -2794,19 +2581,27 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
 
     if (m_wxwindow)
     {
-        int dw = 0;
-        int dh = 0;
-
-        if (m_hasScrolling)
-            GetScrollbarWidth(m_widget, dw, dh);
+        // if window is scrollable, account for scrollbars
+        for (int i = 0; i < 2 && m_scrollBar[i]; i++)
+        {
+            GtkRequisition req;
+            GtkAdjustment* adj = gtk_range_get_adjustment(m_scrollBar[i]);
+            // if scrollbar enabled
+            if (adj->upper > adj->page_size)
+            {
+                gtk_widget_size_request(GTK_WIDGET(m_scrollBar[i]), &req);
+                if (i == ScrollDir_Horz)
+                    h -= req.height;
+                else
+                    w -= req.width;
+            }
+        }
 
         int border_x, border_y;
         WX_PIZZA(m_wxwindow)->get_border_widths(border_x, border_y);
-        dw += 2 * border_x;
-        dh += 2 * border_y;
+        w -= 2 * border_x;
+        h -= 2 * border_y;
 
-        w -= dw;
-        h -= dh;
         if (w < 0)
             w = 0;
         if (h < 0)
@@ -2938,22 +2733,19 @@ bool wxWindowGTK::Show( bool show )
         return false;
     }
 
-    if (show)
+    if (show && m_showOnIdle)
     {
-        if (!m_showOnIdle)
-        {
-            gtk_widget_show( m_widget );
-            wxShowEvent eventShow(GetId(), show);
-            eventShow.SetEventObject(this);
-            GetEventHandler()->ProcessEvent(eventShow);
-        }
+        // deferred
     }
     else
     {
-        gtk_widget_hide( m_widget );
+        if (show)
+            gtk_widget_show(m_widget);
+        else
+            gtk_widget_hide(m_widget);
         wxShowEvent eventShow(GetId(), show);
         eventShow.SetEventObject(this);
-        GetEventHandler()->ProcessEvent(eventShow);
+        HandleWindowEvent(eventShow);
     }
 
     return true;
@@ -3075,90 +2867,194 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
     g_object_unref (layout);
 }
 
-bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
+
+bool wxWindowGTK::GTKHandleFocusIn()
 {
-    if ( g_delayedFocus == this )
+    // Disable default focus handling for custom windows since the default GTK+
+    // handler issues a repaint
+    const bool retval = m_wxwindow ? true : false;
+
+
+    // NB: if there's still unprocessed deferred focus-out event (see
+    //     GTKHandleFocusOut() for explanation), we need to process it first so
+    //     that the order of focus events -- focus-out first, then focus-in
+    //     elsewhere -- is preserved
+    if ( gs_deferredFocusOut )
     {
-        if ( GTK_WIDGET_REALIZED(m_widget) )
+        if ( GTKNeedsToFilterSameWindowFocus() &&
+             gs_deferredFocusOut == this )
         {
-            gtk_widget_grab_focus(m_widget);
-            g_delayedFocus = NULL;
-
-            return true;
+            // GTK+ focus changed from this wxWindow back to itself, so don't
+            // emit any events at all
+            wxLogTrace(TRACE_FOCUS,
+                       "filtered out spurious focus change within %s(%p, %s)",
+                       GetClassInfo()->GetClassName(), this, GetLabel());
+            gs_deferredFocusOut = NULL;
+            return retval;
         }
+
+        // otherwise we need to send focus-out first
+        wxASSERT_MSG ( gs_deferredFocusOut != this,
+                       "GTKHandleFocusIn(GTKFocus_Normal) called even though focus changed back to itself - derived class should handle this" );
+        GTKHandleDeferredFocusOut();
     }
 
-    return false;
+
+    wxLogTrace(TRACE_FOCUS,
+               "handling focus_in event for %s(%p, %s)",
+               GetClassInfo()->GetClassName(), this, GetLabel());
+
+    if (m_imData)
+        gtk_im_context_focus_in(m_imData->context);
+
+    // NB: SetFocus() does this assignment too, but not all focus changes
+    //     originate from SetFocus() call
+    gs_focusWindow = this;
+
+#if wxUSE_CARET
+    // caret needs to be informed about focus change
+    wxCaret *caret = GetCaret();
+    if ( caret )
+    {
+        caret->OnSetFocus();
+    }
+#endif // wxUSE_CARET
+
+    // Notify the parent keeping track of focus for the kbd navigation
+    // purposes that we got it.
+    wxChildFocusEvent eventChildFocus(this);
+    GTKProcessEvent(eventChildFocus);
+
+    wxFocusEvent eventFocus(wxEVT_SET_FOCUS, GetId());
+    eventFocus.SetEventObject(this);
+    GTKProcessEvent(eventFocus);
+
+    return retval;
 }
 
-void wxWindowGTK::SetFocus()
+bool wxWindowGTK::GTKHandleFocusOut()
 {
-    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
-    if ( m_hasFocus )
+    // Disable default focus handling for custom windows since the default GTK+
+    // handler issues a repaint
+    const bool retval = m_wxwindow ? true : false;
+
+
+    // NB: If a control is composed of several GtkWidgets and when focus
+    //     changes from one of them to another within the same wxWindow, we get
+    //     a focus-out event followed by focus-in for another GtkWidget owned
+    //     by the same wx control. We don't want to generate two spurious
+    //     wxEVT_SET_FOCUS events in this case, so we defer sending wx events
+    //     from GTKHandleFocusOut() until we know for sure it's not coming back
+    //     (i.e. in GTKHandleFocusIn() or at idle time).
+    if ( GTKNeedsToFilterSameWindowFocus() )
     {
-        // don't do anything if we already have focus
-        return;
+        wxASSERT_MSG( gs_deferredFocusOut == NULL,
+                      "deferred focus out event already pending" );
+        wxLogTrace(TRACE_FOCUS,
+                   "deferring focus_out event for %s(%p, %s)",
+                   GetClassInfo()->GetClassName(), this, GetLabel());
+        gs_deferredFocusOut = this;
+        return retval;
     }
 
-    if (m_wxwindow)
+    GTKHandleFocusOutNoDeferring();
+
+    return retval;
+}
+
+void wxWindowGTK::GTKHandleFocusOutNoDeferring()
+{
+    wxLogTrace(TRACE_FOCUS,
+               "handling focus_out event for %s(%p, %s)",
+               GetClassInfo()->GetClassName(), this, GetLabel());
+
+    if (m_imData)
+        gtk_im_context_focus_out(m_imData->context);
+
+    if ( gs_focusWindow != this )
     {
-        // wxWindow::SetFocus() should really set the focus to
-        // this control, whatever the flags are
-        if (!GTK_WIDGET_CAN_FOCUS(m_wxwindow))
-            GTK_WIDGET_SET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
+        // Something is terribly wrong, gs_focusWindow is out of sync with the
+        // real focus. We will reset it to NULL anyway, because after this
+        // focus-out event is handled, one of the following with happen:
+        //
+        // * either focus will go out of the app altogether, in which case
+        //   gs_focusWindow _should_ be NULL
+        //
+        // * or it goes to another control, in which case focus-in event will
+        //   follow immediately and it will set gs_focusWindow to the right
+        //   value
+        wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
+                   GetClassInfo()->GetClassName(), this, GetLabel());
+    }
+    gs_focusWindow = NULL;
 
-        if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
-        {
-            gtk_widget_grab_focus (m_wxwindow);
-        }
+#if wxUSE_CARET
+    // caret needs to be informed about focus change
+    wxCaret *caret = GetCaret();
+    if ( caret )
+    {
+        caret->OnKillFocus();
     }
-    else
+#endif // wxUSE_CARET
+
+    wxFocusEvent event( wxEVT_KILL_FOCUS, GetId() );
+    event.SetEventObject( this );
+    GTKProcessEvent( event );
+}
+
+/*static*/
+void wxWindowGTK::GTKHandleDeferredFocusOut()
+{
+    // NB: See GTKHandleFocusOut() for explanation. This function is called
+    //     from either GTKHandleFocusIn() or OnInternalIdle() to process
+    //     deferred event.
+    if ( gs_deferredFocusOut )
     {
-        // wxWindow::SetFocus() should really set the focus to
-        // this control, whatever the flags are
-        if (!GTK_WIDGET_CAN_FOCUS(m_widget))
-            GTK_WIDGET_SET_FLAGS(m_widget, GTK_CAN_FOCUS);
+        wxWindowGTK *win = gs_deferredFocusOut;
+        gs_deferredFocusOut = NULL;
 
-        if (GTK_IS_CONTAINER(m_widget))
-        {
-            if (GTK_IS_RADIO_BUTTON(m_widget))
-            {
-                gtk_widget_grab_focus (m_widget);
-                return;
-            }
+        wxLogTrace(TRACE_FOCUS,
+                   "processing deferred focus_out event for %s(%p, %s)",
+                   win->GetClassInfo()->GetClassName(), win, win->GetLabel());
 
-            gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
-        }
-        else
-        if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
-        {
+        win->GTKHandleFocusOutNoDeferring();
+    }
+}
 
-            if (!GTK_WIDGET_REALIZED(m_widget))
-            {
-                // we can't set the focus to the widget now so we remember that
-                // it should be focused and will do it later, during the idle
-                // time, as soon as we can
-                wxLogTrace(TRACE_FOCUS,
-                           _T("Delaying setting focus to %s(%s)"),
-                           GetClassInfo()->GetClassName(), GetLabel().c_str());
-
-                g_delayedFocus = this;
-            }
-            else
-            {
-                wxLogTrace(TRACE_FOCUS,
-                           _T("Setting focus to %s(%s)"),
-                           GetClassInfo()->GetClassName(), GetLabel().c_str());
+void wxWindowGTK::SetFocus()
+{
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
-                gtk_widget_grab_focus (m_widget);
-            }
-        }
-        else
-        {
-           wxLogTrace(TRACE_FOCUS,
-                      _T("Can't set focus to %s(%s)"),
-                      GetClassInfo()->GetClassName(), GetLabel().c_str());
-        }
+    // Setting "physical" focus is not immediate in GTK+ and while
+    // gtk_widget_is_focus ("determines if the widget is the focus widget
+    // 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
+    // (if it was hidden at the moment of the call) or at the next event loop
+    // iteration.
+    //
+    // Because we want to FindFocus() call immediately following
+    // foo->SetFocus() to return foo, we have to keep track of "pending" focus
+    // ourselves.
+    gs_focusWindow = this;
+
+    GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget;
+
+    if ( GTK_IS_CONTAINER(widget) &&
+         !GTK_WIDGET_CAN_FOCUS(widget) )
+    {
+        wxLogTrace(TRACE_FOCUS,
+                   _T("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,
+                   _T("Setting focus to %s(%p, %s)"),
+                   GetClassInfo()->GetClassName(), this, GetLabel().c_str());
+        gtk_widget_grab_focus(widget);
     }
 }
 
@@ -3305,7 +3201,7 @@ wxWindowGTK::AdjustForLayoutDirection(wxCoord x,
     return x;
 }
 
-void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
+void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
 {
     wxWindowBase::DoMoveInTabOrder(win, move);
     m_dirtyTabOrder = true;
@@ -3649,7 +3545,6 @@ void wxWindowGTK::GtkSendPaintEvents()
         }
     }
 
-#if 0
     if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
     {
         // find ancestor from which to steal background
@@ -3697,20 +3592,16 @@ void wxWindowGTK::GtkSendPaintEvents()
         wxEraseEvent erase_event( GetId(), &dc );
         erase_event.SetEventObject( this );
 
-        GetEventHandler()->ProcessEvent(erase_event);
+        HandleWindowEvent(erase_event);
     }
-    
+
     wxNcPaintEvent nc_paint_event( GetId() );
     nc_paint_event.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( nc_paint_event );
-#endif
-    if (GetName() == "MyMiniControl")
-       wxPrintf( "MyMini paint\n" );
+    HandleWindowEvent( nc_paint_event );
 
     wxPaintEvent paint_event( GetId() );
     paint_event.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( paint_event );
+    HandleWindowEvent( paint_event );
 
     m_clipPaintRegion = false;
 
@@ -4044,7 +3935,7 @@ void wxWindowGTK::GTKReleaseMouseAndNotify()
     DoReleaseMouse();
     wxMouseCaptureLostEvent evt(GetId());
     evt.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( evt );
+    HandleWindowEvent( evt );
 }
 
 /* static */
@@ -4068,11 +3959,7 @@ void wxWindowGTK::SetScrollbar(int orient,
     GtkRange* const sb = m_scrollBar[dir];
     wxCHECK_RET( sb, _T("this window is not scrollable") );
 
-    if (range > 0)
-    {
-        m_hasScrolling = true;
-    }
-    else
+    if (range <= 0)
     {
         // GtkRange requires upper > lower
         range =
@@ -4151,8 +4038,6 @@ static inline bool IsScrollIncrement(double increment, double x)
 
 wxEventType wxWindowGTK::GetScrollEventType(GtkRange* range)
 {
-    DEBUG_MAIN_THREAD
-
     wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]);
 
     const int barIndex = range == m_scrollBar[1];
@@ -4303,21 +4188,40 @@ wxPoint wxGetMousePosition()
 
 }
 
-// Needed for implementing e.g. combobox on wxGTK within a modal dialog.
-void wxAddGrab(wxWindow* window)
+GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
 {
-    gtk_grab_add( (GtkWidget*) window->GetHandle() );
+    GdkWindow* window = NULL;
+    if (m_wxwindow)
+        window = m_wxwindow->window;
+    return window;
 }
 
-void wxRemoveGrab(wxWindow* window)
+// ----------------------------------------------------------------------------
+// freeze/thaw
+// ----------------------------------------------------------------------------
+
+void wxWindowGTK::GTKFreezeWidget(GtkWidget *w)
 {
-    gtk_grab_remove( (GtkWidget*) window->GetHandle() );
+    if ( w && !GTK_WIDGET_NO_WINDOW(w) )
+        gdk_window_freeze_updates(w->window);
 }
 
-GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
+void wxWindowGTK::GTKThawWidget(GtkWidget *w)
 {
-    GdkWindow* window = NULL;
-    if (m_wxwindow)
-        window = m_wxwindow->window;
-    return window;
+    if ( w && !GTK_WIDGET_NO_WINDOW(w) )
+        gdk_window_thaw_updates(w->window);
+}
+
+void wxWindowGTK::DoFreeze()
+{
+    GTKFreezeWidget(m_widget);
+    if ( m_wxwindow && m_widget != m_wxwindow )
+        GTKFreezeWidget(m_wxwindow);
+}
+
+void wxWindowGTK::DoThaw()
+{
+    GTKThawWidget(m_widget);
+    if ( m_wxwindow && m_widget != m_wxwindow )
+        GTKThawWidget(m_wxwindow);
 }