]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
Disabled masked bitmaps under GTK 2.0 until I know
[wxWidgets.git] / src / gtk / window.cpp
index 16d1c5820006d30e84b2f9000c2274d6922f6db1..d3fc1c023d09ade04e4a44011ee649b63a22bf88 100644 (file)
@@ -54,8 +54,7 @@
 
 #include <math.h>
 
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
+#include "wx/gtk/private.h"
 #include <gdk/gdkprivate.h>
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkx.h>
 
 #include "wx/gtk/win_gtk.h"
 
+#ifdef __WXGTK20__
+    #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
+#else
+    #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
+#endif
+
+#ifdef __WXGTK20__
+    #ifdef HAVE_XIM
+        #undef HAVE_XIM
+    #endif
+#endif
+
 //-----------------------------------------------------------------------------
 // documentation on internals
 //-----------------------------------------------------------------------------
@@ -204,6 +215,8 @@ extern bool       g_blockEventsOnDrag;
 extern bool       g_blockEventsOnScroll;
 extern wxCursor   g_globalCursor;
 
+static GdkGC *g_eraseGC = NULL;
+
 // mouse capture state: the window which has it and if the mouse is currently
 // inside it
 static wxWindowGTK  *g_captureWindow = (wxWindowGTK*) NULL;
@@ -372,7 +385,6 @@ static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
     return p;
 }
 
-
 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
 {
     // wxUniversal widgets draw the borders and scrollbars themselves
@@ -385,34 +397,34 @@ static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
 
     if (win->m_hasScrolling)
     {
-            GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
+        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 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 );
+        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) );
+        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->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 (scroll_window->hscrollbar_visible)
+        {
+            dh += hscroll_req.height;
+            dh += scroll_class->scrollbar_spacing;
+        }
+}
 
     int dx = 0;
     int dy = 0;
@@ -475,21 +487,36 @@ gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_even
 // "draw" of m_widget
 //-----------------------------------------------------------------------------
 
+#ifndef __WXGTK20__
+
 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
 {
     draw_frame( widget, win );
 }
 
+#endif
+
 //-----------------------------------------------------------------------------
 // key code mapping routines
 //-----------------------------------------------------------------------------
 
 static long map_to_unmodified_wx_keysym( GdkEventKey *event )
 {
+    // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
+    //     but only event->keyval which is quite useless to us, so remember
+    //     the last character from GDK_KEY_PRESS and resue it as last resort
+    //
+    // NB: should be MT-neutral as always called from main thread only
+    static struct
+    {
+        KeySym keysym;
+        long   keycode;
+    } s_lastKeyPress = { 0, 0 };
+
     KeySym keysym = event->keyval;
     long key_code;
 
-    switch (keysym)
+    switch ( keysym )
     {
         case GDK_Shift_L:
         case GDK_Shift_R:       key_code = WXK_SHIFT;       break;
@@ -581,16 +608,43 @@ static long map_to_unmodified_wx_keysym( GdkEventKey *event )
         case GDK_F11:           key_code = WXK_F11;         break;
         case GDK_F12:           key_code = WXK_F12;         break;
         default:
-            if ( (keysym & 0xFF) == keysym )
+        {
+            // do we have the translation?
+            if ( event->length == 1 )
             {
-                guint upper = gdk_keyval_to_upper( (guint)keysym );
-                key_code = upper ? upper : keysym;
+                keysym = (KeySym)event->string[0];
             }
-            else
+            else if ( (keysym & 0xFF) != keysym )
+            {
+                // non ASCII key, what to do?
+
+                if ( event->type == GDK_KEY_RELEASE )
+                {
+                    // reuse the one from the last keypress if any
+                    if ( keysym == s_lastKeyPress.keysym )
+                    {
+                        key_code = s_lastKeyPress.keycode;
+
+                        // skip "return 0"
+                        break;
+                    }
+                }
+
+                // ignore this one, we don't know it
+                return 0;
+            }
+            //else: ASCII key, ok
+
+            guint upper = gdk_keyval_to_upper( (guint)keysym );
+            key_code = upper ? upper : keysym;
+
+            if ( event->type == GDK_KEY_PRESS )
             {
-                // unknown key code
-                key_code = 0;
+                // remember it to be reused below later
+                s_lastKeyPress.keysym = keysym;
+                s_lastKeyPress.keycode = key_code;
             }
+        }
     }
 
     return key_code;
@@ -683,7 +737,6 @@ static long map_to_wx_keysym( GdkEventKey *event )
         case GDK_F11:           key_code = WXK_F11;         break;
         case GDK_F12:           key_code = WXK_F12;         break;
         default:
-        {
             if (event->length == 1)
             {
                 key_code = (unsigned char)*event->string;
@@ -692,7 +745,6 @@ static long map_to_wx_keysym( GdkEventKey *event )
             {
                 key_code = (guint)keysym;
             }
-        }
     }
 
     return key_code;
@@ -717,6 +769,10 @@ static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition
 // "expose_event" of m_wxwindow
 //-----------------------------------------------------------------------------
 
+#ifdef __WXGTK20__
+extern GtkContainerClass *pizza_parent_class;
+#endif
+
 static int gtk_window_expose_callback( GtkWidget *widget,
                                        GdkEventExpose *gdk_event,
                                        wxWindow *win )
@@ -739,6 +795,7 @@ static int gtk_window_expose_callback( GtkWidget *widget,
     }
 */
 
+#ifndef __WXUNIVERSAL__
     GtkPizza *pizza = GTK_PIZZA (widget);
 
     if (win->GetThemeEnabled())
@@ -749,77 +806,30 @@ static int gtk_window_expose_callback( GtkWidget *widget,
         if (!parent)
             parent = win;
 
-        gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
-            GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
+        gtk_paint_flat_box (parent->m_widget->style,
+                            pizza->bin_window,
+                            GTK_STATE_NORMAL,
+                            GTK_SHADOW_NONE,
+                            &gdk_event->area,
+                            parent->m_widget,
+                            (char *)"base",
+                            0, 0, -1, -1);
     }
+#endif
 
     win->GetUpdateRegion().Union( gdk_event->area.x,
                                   gdk_event->area.y,
                                   gdk_event->area.width,
                                   gdk_event->area.height );
 
-    if (gdk_event->count == 0)
-    {
-        win->m_clipPaintRegion = TRUE;
-
-        wxWindowDC dc(win);
-        dc.SetClippingRegion(win->GetUpdateRegion());
-        wxEraseEvent eevent( win->GetId(), &dc );
-        eevent.SetEventObject( win );
-#if 1
-        (void)win->GetEventHandler()->ProcessEvent(eevent);
-#else // 0
-        if (!win->GetEventHandler()->ProcessEvent(eevent))
-        {
-            wxClientDC dc( win );
-            dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
-            dc.SetPen( *wxTRANSPARENT_PEN );
-
-            wxRegionIterator upd( win->GetUpdateRegion() );
-            while (upd)
-            {
-                dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
-                upd ++;
-            }
-        }
-#endif // 1/0
-
-        wxNcPaintEvent eventNc( win->GetId() );
-        eventNc.SetEventObject( win );
-        win->GetEventHandler()->ProcessEvent( eventNc );
-
-        wxPaintEvent event( win->GetId() );
-        event.SetEventObject( win );
-        win->GetEventHandler()->ProcessEvent( event );
-
-        win->GetUpdateRegion().Clear();
-
-        win->m_clipPaintRegion = FALSE;
-    }
-
-    /* The following code will result in all window-less widgets
-       being redrawn if the wxWindows class is given a chance to
-       paint *anything* because it will then be allowed to paint
-       over the window-less widgets */
-    GList *children = pizza->children;
-    while (children)
-    {
-        GtkPizzaChild *child = (GtkPizzaChild*) children->data;
-        children = children->next;
-
-        GdkEventExpose child_event = *gdk_event;
+    // Actual redrawing takes place in idle time.
+    win->Update();
+    
+#ifdef __WXGTK20__
 
-        if (GTK_WIDGET_NO_WINDOW (child->widget) &&
-            GTK_WIDGET_DRAWABLE (child->widget) /* &&
-            gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ )
-        {
-            child_event.area.x = child->widget->allocation.x;
-            child_event.area.y = child->widget->allocation.y;
-            child_event.area.width = child->widget->allocation.width;
-            child_event.area.height = child->widget->allocation.height;
-            gtk_widget_event (child->widget, (GdkEvent*) &child_event);
-        }
-    }
+    (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
+    
+#endif    
 
     return TRUE;
 }
@@ -828,11 +838,11 @@ static int gtk_window_expose_callback( GtkWidget *widget,
 // "event" of m_wxwindow
 //-----------------------------------------------------------------------------
 
-/* GTK thinks it is clever and filters out a certain amount of "unneeded"
-   expose events. We need them, of course, so we override the main event
-   procedure in GtkWidget by giving our own handler for all system events.
-   There, we look for expose events ourselves whereas all other events are
-   handled normally. */
+// GTK thinks it is clever and filters out a certain amount of "unneeded"
+// expose events. We need them, of course, so we override the main event
+// procedure in GtkWidget by giving our own handler for all system events.
+// There, we look for expose events ourselves whereas all other events are
+// handled normally.
 
 gint gtk_window_event_event_callback( GtkWidget *widget,
                                       GdkEventExpose *event,
@@ -851,8 +861,10 @@ gint gtk_window_event_event_callback( GtkWidget *widget,
 // "draw" of m_wxwindow
 //-----------------------------------------------------------------------------
 
-/* This callback is a complete replacement of the gtk_pizza_draw() function,
-   which disabled. */
+#ifndef __WXGTK20__
+
+// This callback is a complete replacement of the gtk_pizza_draw() function,
+// which is disabled.
 
 static void gtk_window_draw_callback( GtkWidget *widget,
                                       GdkRectangle *rect,
@@ -863,6 +875,8 @@ static void gtk_window_draw_callback( GtkWidget *widget,
     if (g_isIdle)
         wxapp_install_idle_handler();
 
+    // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
+    // there are no child windows.
     if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
         (win->GetChildren().GetCount() == 0))
     {
@@ -882,6 +896,7 @@ static void gtk_window_draw_callback( GtkWidget *widget,
     }
 */
 
+#ifndef __WXUNIVERSAL__
     GtkPizza *pizza = GTK_PIZZA (widget);
 
     if (win->GetThemeEnabled())
@@ -892,8 +907,14 @@ static void gtk_window_draw_callback( GtkWidget *widget,
         if (!parent)
             parent = win;
 
-        gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
-            GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
+        gtk_paint_flat_box (parent->m_widget->style,
+                            pizza->bin_window,
+                            GTK_STATE_NORMAL,
+                            GTK_SHADOW_NONE,
+                            rect,
+                            parent->m_widget,
+                            (char *)"base",
+                            0, 0, -1, -1);
     }
 
 
@@ -903,64 +924,33 @@ static void gtk_window_draw_callback( GtkWidget *widget,
         gdk_window_clear_area( pizza->bin_window,
                                rect->x, rect->y, rect->width, rect->height);
     }
-
-    win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
-
-    win->m_clipPaintRegion = TRUE;
-
-    wxWindowDC dc(win);
-    dc.SetClippingRegion(win->GetUpdateRegion());
-    wxEraseEvent eevent( win->GetId(), &dc );
-    eevent.SetEventObject( win );
-
-#if 1
-    (void)win->GetEventHandler()->ProcessEvent(eevent);
-#else
-    if (!win->GetEventHandler()->ProcessEvent(eevent))
-    {
-        if (!win->GetEventHandler()->ProcessEvent(eevent))
-        {
-            wxClientDC dc( win );
-            dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
-            dc.SetPen( *wxTRANSPARENT_PEN );
-
-            wxRegionIterator upd( win->GetUpdateRegion() );
-            while (upd)
-            {
-                dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
-                upd ++;
-            }
-        }
-    }
 #endif
 
-    wxNcPaintEvent eventNc( win->GetId() );
-    eventNc.SetEventObject( win );
-    win->GetEventHandler()->ProcessEvent( eventNc );
-
-    wxPaintEvent event( win->GetId() );
-    event.SetEventObject( win );
-    win->GetEventHandler()->ProcessEvent( event );
-
-    win->GetUpdateRegion().Clear();
-
-    win->m_clipPaintRegion = FALSE;
+    win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
 
+    // Actual redrawing takes place in idle time.
+    
+    win->Update();
 
+#ifndef __WXUNIVERSAL__
+    // Redraw child widgets
     GList *children = pizza->children;
     while (children)
     {
-            GtkPizzaChild *child = (GtkPizzaChild*) children->data;
-            children = children->next;
+        GtkPizzaChild *child = (GtkPizzaChild*) children->data;
+        children = children->next;
 
-            GdkRectangle child_area;
-            if (gtk_widget_intersect (child->widget, rect, &child_area))
-            {
-                gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
-            }
+        GdkRectangle child_area;
+        if (gtk_widget_intersect (child->widget, rect, &child_area))
+        {
+            gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
+        }
     }
+#endif
 }
 
+#endif
+
 //-----------------------------------------------------------------------------
 // "key_press_event" from any window
 //-----------------------------------------------------------------------------
@@ -1172,6 +1162,27 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk
     return FALSE;
 }
 
+// ============================================================================
+// the mouse events
+// ============================================================================
+
+// init wxMouseEvent with the info from gdk_event
+#define InitMouseEvent(win, event, gdk_event) \
+    { \
+    event.SetTimestamp( gdk_event->time ); \
+    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
+    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
+    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
+    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
+    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
+    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
+    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
+\
+    wxPoint pt = win->GetClientAreaOrigin(); \
+    event.m_x = (wxCoord)gdk_event->x - pt.x; \
+    event.m_y = (wxCoord)gdk_event->y - pt.y; \
+    }
+
 // ----------------------------------------------------------------------------
 // mouse event processing helper
 // ----------------------------------------------------------------------------
@@ -1231,20 +1242,15 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton
 
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
-    if (win->m_wxwindow)
+    if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus())
     {
-        if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
-        {
-            gtk_widget_grab_focus (win->m_wxwindow);
-
+        gtk_widget_grab_focus( win->m_wxwindow );
 /*
-            wxPrintf( wxT("GrabFocus from ") );
-            if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-                wxPrintf( win->GetClassInfo()->GetClassName() );
-            wxPrintf( wxT(".\n") );
+        wxPrintf( wxT("GrabFocus from ") );
+        if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
+            wxPrintf( win->GetClassInfo()->GetClassName() );
+        wxPrintf( wxT(".\n") );
 */
-
-        }
     }
 
     wxEventType event_type = wxEVT_NULL;
@@ -1284,20 +1290,18 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton
     }
 
     wxMouseEvent event( event_type );
-    event.SetTimestamp( gdk_event->time );
-    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
-    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
-    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
-    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
-    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
-    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
-    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
-
-    event.m_x = (wxCoord)gdk_event->x;
-    event.m_y = (wxCoord)gdk_event->y;
+    InitMouseEvent( win, event, gdk_event );
 
     AdjustEventButtonState(event);
 
+    // wxListBox actually get mouse events from the item
+
+    if (win->m_isListBox)
+    {
+        event.m_x += widget->allocation.x;
+        event.m_y += widget->allocation.y;
+    }
+
     // Some control don't have their own X window and thus cannot get
     // any events.
 
@@ -1417,19 +1421,18 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
     }
 
     wxMouseEvent event( event_type );
-    event.SetTimestamp( gdk_event->time );
-    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
-    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
-    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
-    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
-    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
-    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
-    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
-    event.m_x = (wxCoord)gdk_event->x;
-    event.m_y = (wxCoord)gdk_event->y;
+    InitMouseEvent( win, event, gdk_event );
 
     AdjustEventButtonState(event);
 
+    // wxListBox actually get mouse events from the item
+
+    if (win->m_isListBox)
+    {
+        event.m_x += widget->allocation.x;
+        event.m_y += widget->allocation.y;
+    }
+
     // Some control don't have their own X window and thus cannot get
     // any events.
 
@@ -1505,24 +1508,6 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
     return FALSE;
 }
 
-// ============================================================================
-// the mouse events
-// ============================================================================
-
-// init wxMouseEvent with the info from gdk_event
-#define InitMouseEvent(event, gdk_event) \
-    event.SetTimestamp( gdk_event->time ); \
-    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
-    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
-    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
-    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
-    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
-    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
-    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
-\
-    event.m_x = (wxCoord)gdk_event->x; \
-    event.m_y = (wxCoord)gdk_event->y \
-
 //-----------------------------------------------------------------------------
 // "motion_notify_event"
 //-----------------------------------------------------------------------------
@@ -1560,7 +1545,7 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
 */
 
     wxMouseEvent event( wxEVT_MOTION );
-    InitMouseEvent(event, gdk_event);
+    InitMouseEvent(win, event, gdk_event);
 
     if ( g_captureWindow )
     {
@@ -1574,7 +1559,7 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
 
             wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
                                                        : wxEVT_LEAVE_WINDOW);
-            InitMouseEvent(event, gdk_event);
+            InitMouseEvent(win, event, gdk_event);
             event.SetEventObject(win);
             win->GetEventHandler()->ProcessEvent(event);
         }
@@ -1688,10 +1673,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     g_focusWindow = win;
 
 #if 0
-    wxPrintf( "OnSetFocus from " );
-    if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-        wxPrintf( win->GetClassInfo()->GetClassName() );
-    wxPrintf( ".\n" );
+    wxLogDebug( wxT("OnSetFocus from %s\n"), win->GetName().c_str() );
 #endif
 
     // notify the parent keeping track of focus for the kbd navigation
@@ -1713,17 +1695,18 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     }
 #endif // wxUSE_CARET
 
-    
     wxWindowGTK *active = wxGetTopLevelParent(win);
     if ( active != g_activeFrame )
     {
         if ( g_activeFrame )
         {
+            wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame);
             wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
             event.SetEventObject(g_activeFrame);
             g_activeFrame->GetEventHandler()->ProcessEvent(event);
         }
 
+        wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active);
         g_activeFrame = active;
         wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
         event.SetEventObject(g_activeFrame);
@@ -1749,9 +1732,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
 // "focus_out_event"
 //-----------------------------------------------------------------------------
 
-static GtkWidget *gs_widgetLastFocus = NULL;
-
-static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
+static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1761,19 +1742,21 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
-    //wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") )
-    g_activeFrameLostFocus = TRUE;
+#if 0
+    wxLogDebug( wxT("OnKillFocus from %s"), win->GetName().c_str() );
+#endif
 
-    // VZ: this is really weird but GTK+ seems to call us from inside
-    //     gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
-    //     this widget and then "focus_in". This is totally unexpected and
-    //     completely breaks wxUniv code so ignore this dummy event (we can't
-    //     be losing focus if we're about to acquire it!)
-    if ( widget == gs_widgetLastFocus )
+    if ( !g_activeFrameLostFocus && g_activeFrame )
     {
-        gs_widgetLastFocus = NULL;
+        // VZ: commenting this out because it does happen (although not easy
+        //     to reproduce, I only see it when using wxMiniFrame and not
+        //     always) and makes using Mahogany quite annoying
+#if 0
+        wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
+                        wxT("unfocusing window that hasn't gained focus properly") )
+#endif // 0
 
-        return FALSE;
+        g_activeFrameLostFocus = TRUE;
     }
 
     // if the focus goes out of our app alltogether, OnIdle() will send
@@ -1787,13 +1770,6 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
 
     g_focusWindow = (wxWindowGTK *)NULL;
 
-#if 0
-    wxPrintf( "OnKillFocus from " );
-    if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-        wxPrintf( win->GetClassInfo()->GetClassName() );
-    wxPrintf( ".\n" );
-#endif
-
 #ifdef HAVE_XIM
     if (win->m_ic)
         gdk_im_end();
@@ -1846,10 +1822,10 @@ static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_
 
     gdk_window_get_pointer( widget->window, &x, &y, &state );
 
-    InitMouseEvent(event, gdk_event);
-
-    event.m_x = x;
-    event.m_y = y;
+    InitMouseEvent(win, event, gdk_event);
+    wxPoint pt = win->GetClientAreaOrigin();
+    event.m_x = x + pt.x;
+    event.m_y = y + pt.y;
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
@@ -1894,8 +1870,9 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_
     event.m_middleDown = (state & GDK_BUTTON2_MASK);
     event.m_rightDown = (state & GDK_BUTTON3_MASK);
 
-    event.m_x = x;
-    event.m_y = y;
+    wxPoint pt = win->GetClientAreaOrigin();
+    event.m_x = x + pt.x;
+    event.m_y = y + pt.y;
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
@@ -1910,7 +1887,9 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_
 // "value_changed" from m_vAdjust
 //-----------------------------------------------------------------------------
 
-static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
+static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
+                                         SCROLLBAR_CBACK_ARG
+                                         wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1926,14 +1905,7 @@ static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win
 
     win->m_oldVerticalPos = adjust->value;
 
-    GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
-    GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
-
-    wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
-    if      (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
-    else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD)  command = wxEVT_SCROLLWIN_LINEDOWN;
-    else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
-    else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD)  command = wxEVT_SCROLLWIN_PAGEDOWN;
+    wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win->m_widget));
 
     int value = (int)(adjust->value+0.5);
 
@@ -1946,7 +1918,9 @@ static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win
 // "value_changed" from m_hAdjust
 //-----------------------------------------------------------------------------
 
-static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
+static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
+                                         SCROLLBAR_CBACK_ARG
+                                         wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
@@ -1959,16 +1933,9 @@ static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win
     float diff = adjust->value - win->m_oldHorizontalPos;
     if (fabs(diff) < 0.2) return;
 
-    win->m_oldHorizontalPos = adjust->value;
-
-    GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
-    GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
+    wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win->m_widget));
 
-    wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
-    if      (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
-    else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD)  command = wxEVT_SCROLLWIN_LINEDOWN;
-    else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
-    else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD)  command = wxEVT_SCROLLWIN_PAGEDOWN;
+    win->m_oldHorizontalPos = adjust->value;
 
     int value = (int)(adjust->value+0.5);
 
@@ -1992,7 +1959,11 @@ static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
 
 
     g_blockEventsOnScroll = TRUE;
+
+    // FIXME: there is no 'slider' field in GTK+ 2.0 any more
+#ifndef __WXGTK20__
     win->m_isScrolling = (gdk_event->window == widget->slider);
+#endif
 
     return FALSE;
 }
@@ -2310,7 +2281,7 @@ void wxWindowGTK::Init()
 
     m_noExpose = FALSE;
     m_nativeSizeEvent = FALSE;
-    
+
     m_hasScrolling = FALSE;
     m_isScrolling = FALSE;
 
@@ -2326,6 +2297,7 @@ void wxWindowGTK::Init()
 
     m_isStaticBox = FALSE;
     m_isRadioButton = FALSE;
+    m_isListBox = FALSE;
     m_isFrame = FALSE;
     m_acceptsFocus = FALSE;
 
@@ -2389,11 +2361,8 @@ bool wxWindowGTK::Create( wxWindow *parent,
     m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
 
     m_wxwindow = gtk_pizza_new();
-
-    gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
-
+    
 #ifndef __WXUNIVERSAL__
-#if (GTK_MINOR_VERSION > 0)
     GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
 
     if (HasFlag(wxRAISED_BORDER))
@@ -2412,33 +2381,13 @@ bool wxWindowGTK::Create( wxWindow *parent,
     {
         gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
     }
-#else // GTK_MINOR_VERSION == 0
-    GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
-
-    if (HasFlag(wxRAISED_BORDER))
-    {
-        gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
-    }
-    else if (HasFlag(wxSUNKEN_BORDER))
-    {
-        gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
-    }
-    else
-    {
-        gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
-    }
-#endif // GTK_MINOR_VERSION
 #endif // __WXUNIVERSAL__
 
+    gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
+
     GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
     m_acceptsFocus = TRUE;
 
-#if (GTK_MINOR_VERSION == 0)
-    // shut the viewport up
-    gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
-    gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
-#endif // GTK_MINOR_VERSION == 0
-
     // I _really_ don't want scrollbars in the beginning
     m_vAdjust->lower = 0.0;
     m_vAdjust->upper = 1.0;
@@ -2484,7 +2433,7 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
     if (m_parent)
         m_parent->DoAddChild( this );
-        
+
     m_focusWidget = m_wxwindow;
 
     PostCreation();
@@ -2578,7 +2527,7 @@ bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos,  const w
 void wxWindowGTK::PostCreation()
 {
     wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
-    
+
     if (m_wxwindow)
     {
         if (!m_noExpose)
@@ -2590,22 +2539,28 @@ void wxWindowGTK::PostCreation()
             gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
                 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
 
+#ifndef __WXGTK20__
             gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
                 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
-
+                
             if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
             {
                 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
                     GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
             }
+#else
+            gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
+#endif
         }
 
-        // these are called when the "sunken" or "raised" borders are drawn */
+        // these are called when the "sunken" or "raised" borders are drawn
         gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
           GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
 
+#ifndef __WXGTK20__
         gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
           GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
+#endif
     }
 
     // focus handling
@@ -2613,12 +2568,6 @@ void wxWindowGTK::PostCreation()
     if (m_focusWidget == NULL)
         m_focusWidget = m_widget;
 
-#if 0
-    if (GetClassInfo() && GetClassInfo()->GetClassName())
-        wxPrintf( GetClassInfo()->GetClassName() );
-    wxPrintf( ".\n" );
-#endif
-
     gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
         GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
 
@@ -2734,7 +2683,6 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
     else
     {
         GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
-
         if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
         {
             if (x != -1) m_x = x + pizza->xoffset;
@@ -2760,20 +2708,27 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
              if (height == -1) m_height = 26;
         }
 
-        if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
-        if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
-        if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
-        if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
+        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 border = 0;
         int bottom_border = 0;
 
+#ifndef __WXGTK20__
         if (GTK_WIDGET_CAN_DEFAULT(m_widget))
         {
             /* the default button has a border around it */
             border = 6;
             bottom_border = 5;
         }
+#endif
 
         DoMoveWindow( m_x-border,
                       m_y-border,
@@ -2811,6 +2766,10 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
 
 void wxWindowGTK::OnInternalIdle()
 {
+    // Update invalidated regions.
+    Update();
+    
+    // Synthetize activate events.
     if ( g_sendActivateEvent != -1 )
     {
         bool activate = g_sendActivateEvent != 0;
@@ -2825,6 +2784,7 @@ void wxWindowGTK::OnInternalIdle()
     {
         if ( g_activeFrame )
         {
+            wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
             wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
             event.SetEventObject(g_activeFrame);
             g_activeFrame->GetEventHandler()->ProcessEvent(event);
@@ -3025,7 +2985,7 @@ void wxWindowGTK::DoGetPosition( int *x, int *y ) const
         dx = pizza->xoffset;
         dy = pizza->yoffset;
     }
-    
+
     if (x) (*x) = m_x - dx;
     if (y) (*y) = m_y - dy;
 }
@@ -3187,12 +3147,17 @@ void wxWindowGTK::SetFocus()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
+#if 0
+    wxPrintf( "SetFocus from " );
+    if (GetClassInfo() && GetClassInfo()->GetClassName())
+        wxPrintf( GetClassInfo()->GetClassName() );
+    wxPrintf( ".\n" );
+#endif
+
     if (m_wxwindow)
     {
         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
         {
-            // see comment in gtk_window_focus_out_callback()
-            gs_widgetLastFocus = m_wxwindow;
             gtk_widget_grab_focus (m_wxwindow);
         }
     }
@@ -3204,7 +3169,7 @@ void wxWindowGTK::SetFocus()
         }
         else if (GTK_IS_CONTAINER(m_widget))
         {
-            gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
+            SET_CONTAINER_FOCUS( m_widget, GTK_DIR_TAB_FORWARD );
         }
         else
         {
@@ -3307,8 +3272,8 @@ void wxWindowGTK::WarpPointer( int x, int y )
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    /* we provide this function ourselves as it is
-       missing in GDK (top of this file)  */
+    // We provide this function ourselves as it is
+    // missing in GDK (top of this file).
 
     GdkWindow *window = (GdkWindow*) NULL;
     if (m_wxwindow)
@@ -3325,96 +3290,174 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
     if (!m_widget) return;
     if (!m_widget->window) return;
 
-    // temporarily hide the caret to avoid nasty interactions between caret
-    // drawing and the window contents redraw
-#if 0 // def wxUSE_CARET -- doesn't seem to help :-(
-    wxCaretSuspend cs((wxWindow *)this);
-#endif // wxUSE_CARET
-
+#ifndef __WXGTK20__
     if (eraseBackground && m_wxwindow && m_wxwindow->window)
     {
         if (rect)
         {
-            gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
-                                   rect->x, rect->y,
-                                   rect->width, rect->height );
+            // Schedule for later Updating in ::Update() or ::OnInternalIdle().
+            m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
         }
         else
         {
-            gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
+            // Schedule for later Updating in ::Update() or ::OnInternalIdle().
+            m_clearRegion.Clear();
+            m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
         }
     }
 
-    /* there is no GTK equivalent of "draw only, don't clear" so we
-       invent our own in the GtkPizza widget */
-
-    if (!rect)
+    if (rect)
     {
         if (m_wxwindow)
         {
-
-/*
-            GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
-            gboolean old_clear = pizza->clear_on_draw;
-            gtk_pizza_set_clear( pizza, FALSE );
-            gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
-            gtk_pizza_set_clear( pizza, old_clear );
-*/
-            GdkEventExpose gdk_event;
-            gdk_event.type = GDK_EXPOSE;
-            gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
-            gdk_event.count = 0;
-            gdk_event.area.x = 0;
-            gdk_event.area.y = 0;
-            gdk_event.area.width = m_wxwindow->allocation.width;
-            gdk_event.area.height = m_wxwindow->allocation.height;
-            gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
+            // Schedule for later Updating in ::Update() or ::OnInternalIdle().
+            m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
         }
         else
         {
-            gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
+            GdkRectangle gdk_rect;
+            gdk_rect.x = rect->x;
+            gdk_rect.y = rect->y;
+            gdk_rect.width = rect->width;
+            gdk_rect.height = rect->height;
+            gtk_widget_draw( m_widget, &gdk_rect );
         }
     }
     else
     {
-
         if (m_wxwindow)
         {
-/*
-            GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
-            gboolean old_clear = pizza->clear_on_draw;
-            gtk_pizza_set_clear( pizza, FALSE );
-
+            // Schedule for later Updating in ::Update() or ::OnInternalIdle().
+            m_updateRegion.Clear();
+            m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
+        }
+        else
+        {
+            gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
+        }
+    }
+#else
+    if (m_wxwindow)
+    {
+        if (rect)
+        {
             GdkRectangle gdk_rect;
             gdk_rect.x = rect->x;
             gdk_rect.y = rect->y;
             gdk_rect.width = rect->width;
             gdk_rect.height = rect->height;
-            gtk_widget_draw( m_wxwindow, &gdk_rect );
-            gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
+            gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, &gdk_rect, TRUE );
+        }
+        else
+        {
+            gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, NULL, TRUE );
+        }
+    }
+#endif
+}
 
-            gtk_pizza_set_clear( pizza, old_clear );
-*/
+void wxWindowGTK::Update()
+{
+#ifdef __WXGTK20__
+    if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
+        gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
+#endif
+
+    if (!m_updateRegion.IsEmpty())
+        GtkSendPaintEvents();
+}
+
+void wxWindowGTK::GtkSendPaintEvents()
+{
+    if (!m_wxwindow)
+    {
+        m_clearRegion.Clear();
+        m_updateRegion.Clear();
+        return;
+    }
+
+    m_clipPaintRegion = TRUE;
+
+    // if (!m_clearRegion.IsEmpty())   // always send an erase event
+    {
+        wxWindowDC dc( (wxWindow*)this );
+        dc.SetClippingRegion( m_clearRegion );
+        
+        wxEraseEvent erase_event( GetId(), &dc );
+        erase_event.SetEventObject( this );
+    
+        if (!GetEventHandler()->ProcessEvent(erase_event))
+        {
+            gdk_gc_set_foreground( g_eraseGC, m_backgroundColour.GetColor() );
+        
+            wxRegionIterator upd( m_clearRegion );
+            while (upd)
+            {
+                gdk_draw_rectangle( GTK_PIZZA(m_wxwindow)->bin_window, g_eraseGC, 0,
+                                       upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
+                upd ++;
+            }
+        }
+        m_clearRegion.Clear();
+    }
+
+    wxNcPaintEvent nc_paint_event( GetId() );
+    nc_paint_event.SetEventObject( this );
+    GetEventHandler()->ProcessEvent( nc_paint_event );
+
+    wxPaintEvent paint_event( GetId() );
+    paint_event.SetEventObject( this );
+    GetEventHandler()->ProcessEvent( paint_event );
+
+    m_clipPaintRegion = FALSE;
+
+#ifndef __WXUNIVERSAL__
+#ifndef __WXGTK20__
+    // The following code will result in all window-less widgets
+    // being redrawn because the wxWindows class is allowed to
+    // paint over the window-less widgets.
+    
+    GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
+    
+    GList *children = pizza->children;
+    while (children)
+    {
+        GtkPizzaChild *child = (GtkPizzaChild*) children->data;
+        children = children->next;
+
+        if (GTK_WIDGET_NO_WINDOW (child->widget) &&
+            GTK_WIDGET_DRAWABLE (child->widget))
+        {
+            // Get intersection of widget area and update region
+            wxRegion region( m_updateRegion );
+            
             GdkEventExpose gdk_event;
             gdk_event.type = GDK_EXPOSE;
-            gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
+            gdk_event.window = pizza->bin_window;
             gdk_event.count = 0;
-            gdk_event.area.x = rect->x;
-            gdk_event.area.y = rect->y;
-            gdk_event.area.width = rect->width;
-            gdk_event.area.height = rect->height;
-            gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
-        }
-        else
-        {
-            GdkRectangle gdk_rect;
-            gdk_rect.x = rect->x;
-            gdk_rect.y = rect->y;
-            gdk_rect.width = rect->width;
-            gdk_rect.height = rect->height;
-            gtk_widget_draw( m_widget, &gdk_rect );
+            
+            wxRegionIterator upd( m_updateRegion );
+            while (upd)
+            {
+                GdkRectangle rect;
+                rect.x = upd.GetX();
+                rect.y = upd.GetY();
+                rect.width = upd.GetWidth();
+                rect.height = upd.GetHeight();
+                
+                if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
+                {
+                    gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
+                }
+                
+                upd ++;
+            }
         }
     }
+#endif
+#endif
+
+    m_updateRegion.Clear();
 }
 
 void wxWindowGTK::Clear()
@@ -3471,7 +3514,7 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
 
     if ((m_wxwindow) &&
         (m_wxwindow->window) &&
-        (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
+        (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)))
     {
         /* wxMSW doesn't clear the window here. I don't do that either to
           provide compatibility. call Clear() to do the job. */
@@ -3520,10 +3563,9 @@ GtkStyle *wxWindowGTK::GetWidgetStyle()
     if (m_widgetStyle)
     {
         GtkStyle *remake = gtk_style_copy( m_widgetStyle );
-#ifdef __WXGTK20__
-        /* FIXME: is this necessary? */
-        _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
-#else
+
+        // FIXME: no more klass in 2.0
+#ifndef __WXGTK20__
         remake->klass = m_widgetStyle->klass;
 #endif
 
@@ -3538,10 +3580,9 @@ GtkStyle *wxWindowGTK::GetWidgetStyle()
             def = gtk_widget_get_default_style();
 
         m_widgetStyle = gtk_style_copy( def );
-#ifdef __WXGTK20__
-        /* FIXME: is this necessary? */
-        _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
-#else
+
+        // FIXME: no more klass in 2.0
+#ifndef __WXGTK20__
         m_widgetStyle->klass = def->klass;
 #endif
     }
@@ -3551,7 +3592,7 @@ GtkStyle *wxWindowGTK::GetWidgetStyle()
 
 void wxWindowGTK::SetWidgetStyle()
 {
-#if DISABLE_STYLE_IF_BROKEN_THEM
+#if DISABLE_STYLE_IF_BROKEN_THEME
     if (m_widget->style->engine_data)
     {
         static bool s_warningPrinted = FALSE;
@@ -3567,16 +3608,15 @@ void wxWindowGTK::SetWidgetStyle()
 
     GtkStyle *style = GetWidgetStyle();
 
-    if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
+    if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
     {
-        gdk_font_unref( style->font );
-        style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
+        SET_STYLE_FONT(style, m_font.GetInternalFont( 1.0 ));
     }
 
     if (m_foregroundColour.Ok())
     {
         m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
-        if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
+        if (m_foregroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT))
         {
             style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
             style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
@@ -3602,7 +3642,7 @@ void wxWindowGTK::SetWidgetStyle()
     if (m_backgroundColour.Ok())
     {
         m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
-        if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
+        if (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))
         {
             style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
             style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
@@ -3648,7 +3688,8 @@ void wxWindowGTK::ApplyWidgetStyle()
 
 #if wxUSE_MENUS_NATIVE
 
-static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
+extern "C"
+void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
 {
     *is_waiting = FALSE;
 }
@@ -3669,16 +3710,32 @@ static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
     }
 }
 
+// used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
+// wxPopupMenuPositionCallback()
+//
+// should be safe even in the MT case as the user can hardly popup 2 menus
+// simultaneously, can he?
 static gint gs_pop_x = 0;
 static gint gs_pop_y = 0;
 
-static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
-                              gint *x, gint *y,
-                              wxWindowGTK *win )
+extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
+                                             gint *x, gint *y,
+#ifdef __WXGTK20__
+                                             gboolean * WXUNUSED(whatever),
+#endif
+                                             gpointer WXUNUSED(user_data) )
 {
-    win->ClientToScreen( &gs_pop_x, &gs_pop_y );
-    *x = gs_pop_x;
-    *y = gs_pop_y;
+    // ensure that the menu appears entirely on screen
+    GtkRequisition req;
+    gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
+
+    wxSize sizeScreen = wxGetDisplaySize();
+
+    gint xmax = sizeScreen.x - req.width,
+         ymax = sizeScreen.y - req.height;
+
+    *x = gs_pop_x < xmax ? gs_pop_x : xmax;
+    *y = gs_pop_y < ymax ? gs_pop_y : ymax;
 }
 
 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
@@ -3693,20 +3750,23 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
 
     gs_pop_x = x;
     gs_pop_y = y;
+    ClientToScreen( &gs_pop_x, &gs_pop_y );
 
     bool is_waiting = TRUE;
 
-    gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
-      GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
+    gtk_signal_connect( GTK_OBJECT(menu->m_menu),
+                        "hide",
+                        GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
+                        (gpointer)&is_waiting );
 
     gtk_menu_popup(
                   GTK_MENU(menu->m_menu),
-                  (GtkWidget *) NULL,          // parent menu shell
-                  (GtkWidget *) NULL,          // parent menu item
-                  (GtkMenuPositionFunc) pop_pos_callback,
-                  (gpointer) this,             // client data
-                  0,                           // button used to activate it
-                  gs_timeLastClick             // the time of activation
+                  (GtkWidget *) NULL,           // parent menu shell
+                  (GtkWidget *) NULL,           // parent menu item
+                  wxPopupMenuPositionCallback,  // function to position it
+                  NULL,                         // client data
+                  0,                            // button used to activate it
+                  gs_timeLastClick              // the time of activation
                 );
 
     while (is_waiting)
@@ -3763,7 +3823,7 @@ bool wxWindowGTK::SetFont( const wxFont &font )
         return FALSE;
     }
 
-    wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
+    wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
     if ( sysbg == m_backgroundColour )
     {
         m_backgroundColour = wxNullColour;
@@ -3778,7 +3838,7 @@ bool wxWindowGTK::SetFont( const wxFont &font )
     return TRUE;
 }
 
-void wxWindowGTK::CaptureMouse()
+void wxWindowGTK::DoCaptureMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
@@ -3807,12 +3867,14 @@ void wxWindowGTK::CaptureMouse()
     g_captureWindowHasMouse = TRUE;
 }
 
-void wxWindowGTK::ReleaseMouse()
+void wxWindowGTK::DoReleaseMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
     wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
 
+    g_captureWindow = (wxWindowGTK*) NULL;
+
     GdkWindow *window = (GdkWindow*) NULL;
     if (m_wxwindow)
         window = GTK_PIZZA(m_wxwindow)->bin_window;
@@ -3823,7 +3885,6 @@ void wxWindowGTK::ReleaseMouse()
         return;
 
     gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
-    g_captureWindow = (wxWindowGTK*) NULL;
 }
 
 /* static */
@@ -3995,65 +4056,47 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
 
     wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
 
+    // No scrolling requested.
     if ((dx == 0) && (dy == 0)) return;
-
-    m_clipPaintRegion = TRUE;
-    gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
-    m_clipPaintRegion = FALSE;
-
-/*
-    if (m_children.GetCount() > 0)
+    
+#ifndef __WXGTK20__
+    if (!m_updateRegion.IsEmpty())
     {
-        gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
+        m_updateRegion.Offset( dx, dy );
+        
+        int cw = 0;
+        int ch = 0;
+        GetClientSize( &cw, &ch );
+        m_updateRegion.Intersect( 0, 0, cw, ch );
     }
-    else
+    
+    if (!m_clearRegion.IsEmpty())
     {
-        GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
-
-        pizza->xoffset -= dx;
-        pizza->yoffset -= dy;
-
-        GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
-        gdk_gc_set_exposures( m_scrollGC, TRUE );
-
+        m_clearRegion.Offset( dx, dy );
+        
         int cw = 0;
         int ch = 0;
         GetClientSize( &cw, &ch );
-        int w = cw - abs(dx);
-        int h = ch - abs(dy);
-
-        if ((h < 0) || (w < 0))
-        {
-            Refresh();
-        }
-        else
-        {
-            int s_x = 0;
-            int s_y = 0;
-            if (dx < 0) s_x = -dx;
-            if (dy < 0) s_y = -dy;
-            int d_x = 0;
-            int d_y = 0;
-            if (dx > 0) d_x = dx;
-            if (dy > 0) d_y = dy;
-
-            gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
-                pizza->bin_window, s_x, s_y, w, h );
-
-            wxRect rect;
-            if (dx < 0) rect.x = cw+dx; else rect.x = 0;
-            if (dy < 0) rect.y = ch+dy; else rect.y = 0;
-            if (dy != 0) rect.width = cw; else rect.width = abs(dx);
-            if (dx != 0) rect.height = ch; else rect.height = abs(dy);
-
-            Refresh( TRUE, &rect );
-        }
-
-        gdk_gc_unref( m_scrollGC );
+        m_clearRegion.Intersect( 0, 0, cw, ch );
     }
-*/
+    
+    m_clipPaintRegion = TRUE;
+    
+    gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
+    
+    m_clipPaintRegion = FALSE;
+#else
+
+    gdk_window_scroll( GTK_PIZZA(m_wxwindow)->bin_window, -dx, -dy );
+    
+    GTK_PIZZA(m_wxwindow)->xoffset -= dx;
+    GTK_PIZZA(m_wxwindow)->yoffset -= dy;
+    
+#endif    
+   
 }
 
+
 // Find the wxWindow at the current mouse position, also returning the mouse
 // position.
 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
@@ -4095,3 +4138,32 @@ wxPoint wxGetMousePosition()
 
 }
 
+// ----------------------------------------------------------------------------
+// wxDCModule
+// ----------------------------------------------------------------------------
+
+class wxWinModule : public wxModule
+{
+public:
+    bool OnInit();
+    void OnExit();
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxWinModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
+
+bool wxWinModule::OnInit()
+{
+    g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
+    gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
+    
+    return TRUE;
+}
+
+void wxWinModule::OnExit()
+{
+    gdk_gc_unref( g_eraseGC );
+}
+