]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk1/window.cpp
Fixed GetShapeList and similar methods to use OOR.
[wxWidgets.git] / src / gtk1 / window.cpp
index 688d7399cddbd7fdd11bb321777c0acf6a601e0d..c823a1b56f4f10a9625f0f66bd6e8d125ab26a1a 100644 (file)
@@ -25,6 +25,7 @@
 #include "wx/utils.h"
 #include "wx/dialog.h"
 #include "wx/msgdlg.h"
+#include "wx/module.h"
 
 #if wxUSE_DRAG_AND_DROP
     #include "wx/dnd.h"
@@ -39,7 +40,7 @@
 #endif // wxUSE_CARET
 
 #if wxUSE_TEXTCTRL
-#include "wx/textctrl.h"
+    #include "wx/textctrl.h"
 #endif
 
 #include "wx/menu.h"
@@ -54,8 +55,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
+
+#ifdef __WXGTK20__
+extern GtkContainerClass *pizza_parent_class;
+#endif
+
 //-----------------------------------------------------------------------------
 // documentation on internals
 //-----------------------------------------------------------------------------
@@ -204,6 +220,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 +390,6 @@ static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
     return p;
 }
 
-
 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
 {
     // wxUniversal widgets draw the borders and scrollbars themselves
@@ -468,6 +485,11 @@ gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_even
 
     draw_frame( widget, win );
 
+#ifdef __WXGTK20__
+
+    (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
+
+#endif
     return TRUE;
 }
 
@@ -475,264 +497,14 @@ 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 );
 }
 
-//-----------------------------------------------------------------------------
-// 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 )
-    {
-        case GDK_Shift_L:
-        case GDK_Shift_R:       key_code = WXK_SHIFT;       break;
-        case GDK_Control_L:
-        case GDK_Control_R:     key_code = WXK_CONTROL;     break;
-        case GDK_Meta_L:
-        case GDK_Meta_R:
-        case GDK_Alt_L:
-        case GDK_Alt_R:
-        case GDK_Super_L:
-        case GDK_Super_R:       key_code = WXK_ALT;         break;
-        case GDK_Menu:          key_code = WXK_MENU;        break;
-        case GDK_Help:          key_code = WXK_HELP;        break;
-        case GDK_BackSpace:     key_code = WXK_BACK;        break;
-        case GDK_ISO_Left_Tab:
-        case GDK_Tab:           key_code = WXK_TAB;         break;
-        case GDK_Linefeed:      key_code = WXK_RETURN;      break;
-        case GDK_Clear:         key_code = WXK_CLEAR;       break;
-        case GDK_Return:        key_code = WXK_RETURN;      break;
-        case GDK_Pause:         key_code = WXK_PAUSE;       break;
-        case GDK_Scroll_Lock:   key_code = WXK_SCROLL;      break;
-        case GDK_Escape:        key_code = WXK_ESCAPE;      break;
-        case GDK_Delete:        key_code = WXK_DELETE;      break;
-        case GDK_Home:          key_code = WXK_HOME;        break;
-        case GDK_Left:          key_code = WXK_LEFT;        break;
-        case GDK_Up:            key_code = WXK_UP;          break;
-        case GDK_Right:         key_code = WXK_RIGHT;       break;
-        case GDK_Down:          key_code = WXK_DOWN;        break;
-        case GDK_Prior:         key_code = WXK_PRIOR;       break;
-//      case GDK_Page_Up:       key_code = WXK_PAGEUP;      break;
-        case GDK_Next:          key_code = WXK_NEXT;        break;
-//      case GDK_Page_Down:     key_code = WXK_PAGEDOWN;    break;
-        case GDK_End:           key_code = WXK_END;         break;
-        case GDK_Begin:         key_code = WXK_HOME;        break;
-        case GDK_Select:        key_code = WXK_SELECT;      break;
-        case GDK_Print:         key_code = WXK_PRINT;       break;
-        case GDK_Execute:       key_code = WXK_EXECUTE;     break;
-        case GDK_Insert:        key_code = WXK_INSERT;      break;
-        case GDK_Num_Lock:      key_code = WXK_NUMLOCK;     break;
-
-        case GDK_KP_0:         key_code = WXK_NUMPAD0;      break;
-        case GDK_KP_1:         key_code = WXK_NUMPAD1;      break;
-        case GDK_KP_2:         key_code = WXK_NUMPAD2;      break;
-        case GDK_KP_3:         key_code = WXK_NUMPAD3;      break;
-        case GDK_KP_4:         key_code = WXK_NUMPAD4;      break;
-        case GDK_KP_5:         key_code = WXK_NUMPAD5;      break;
-        case GDK_KP_6:         key_code = WXK_NUMPAD6;      break;
-        case GDK_KP_7:         key_code = WXK_NUMPAD7;      break;
-        case GDK_KP_8:         key_code = WXK_NUMPAD8;      break;
-        case GDK_KP_9:         key_code = WXK_NUMPAD9;      break;
-        case GDK_KP_Space:     key_code = WXK_NUMPAD_SPACE; break;
-        case GDK_KP_Tab:       key_code = WXK_NUMPAD_TAB;   break;
-        case GDK_KP_Enter:     key_code = WXK_NUMPAD_ENTER; break;
-        case GDK_KP_F1:        key_code = WXK_NUMPAD_F1;    break;
-        case GDK_KP_F2:        key_code = WXK_NUMPAD_F2;    break;
-        case GDK_KP_F3:        key_code = WXK_NUMPAD_F3;    break;
-        case GDK_KP_F4:        key_code = WXK_NUMPAD_F4;    break;
-        case GDK_KP_Home:      key_code = WXK_NUMPAD_HOME;  break;
-        case GDK_KP_Left:      key_code = WXK_NUMPAD_LEFT;  break;
-        case GDK_KP_Up:        key_code = WXK_NUMPAD_UP;    break;
-        case GDK_KP_Right:     key_code = WXK_NUMPAD_RIGHT; break;
-        case GDK_KP_Down:      key_code = WXK_NUMPAD_DOWN;  break;
-        case GDK_KP_Prior:     key_code = WXK_NUMPAD_PRIOR; break;
-//      case GDK_KP_Page_Up:   key_code = WXK_NUMPAD_PAGEUP;   break;
-        case GDK_KP_Next:      key_code = WXK_NUMPAD_NEXT;  break;
-//      case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
-        case GDK_KP_End:       key_code = WXK_NUMPAD_END;   break;
-        case GDK_KP_Begin:     key_code = WXK_NUMPAD_BEGIN; break;
-        case GDK_KP_Insert:    key_code = WXK_NUMPAD_INSERT; break;
-        case GDK_KP_Delete:    key_code = WXK_NUMPAD_DELETE; break;
-        case GDK_KP_Equal:     key_code = WXK_NUMPAD_EQUAL;  break;
-        case GDK_KP_Multiply:  key_code = WXK_NUMPAD_MULTIPLY; break;
-        case GDK_KP_Add:       key_code = WXK_NUMPAD_ADD;    break;
-        case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
-        case GDK_KP_Subtract:  key_code = WXK_NUMPAD_SUBTRACT;  break;
-        case GDK_KP_Decimal:   key_code = WXK_NUMPAD_DECIMAL;   break;
-        case GDK_KP_Divide:    key_code = WXK_NUMPAD_DIVIDE;    break;
-
-        case GDK_F1:            key_code = WXK_F1;          break;
-        case GDK_F2:            key_code = WXK_F2;          break;
-        case GDK_F3:            key_code = WXK_F3;          break;
-        case GDK_F4:            key_code = WXK_F4;          break;
-        case GDK_F5:            key_code = WXK_F5;          break;
-        case GDK_F6:            key_code = WXK_F6;          break;
-        case GDK_F7:            key_code = WXK_F7;          break;
-        case GDK_F8:            key_code = WXK_F8;          break;
-        case GDK_F9:            key_code = WXK_F9;          break;
-        case GDK_F10:           key_code = WXK_F10;         break;
-        case GDK_F11:           key_code = WXK_F11;         break;
-        case GDK_F12:           key_code = WXK_F12;         break;
-        default:
-        {
-            // do we have the translation?
-            if ( event->length == 1 )
-            {
-                keysym = (KeySym)event->string[0];
-            }
-            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 )
-            {
-                // remember it to be reused below later
-                s_lastKeyPress.keysym = keysym;
-                s_lastKeyPress.keycode = key_code;
-            }
-        }
-    }
-
-    return key_code;
-}
-
-static long map_to_wx_keysym( GdkEventKey *event )
-{
-    KeySym keysym = event->keyval;
-    guint key_code = 0;
-
-    switch (keysym)
-    {
-        case GDK_Menu:          key_code = WXK_MENU;        break;
-        case GDK_Help:          key_code = WXK_HELP;        break;
-        case GDK_BackSpace:     key_code = WXK_BACK;        break;
-        case GDK_ISO_Left_Tab:
-        case GDK_Tab:           key_code = WXK_TAB;         break;
-        case GDK_Linefeed:      key_code = WXK_RETURN;      break;
-        case GDK_Clear:         key_code = WXK_CLEAR;       break;
-        case GDK_Return:        key_code = WXK_RETURN;      break;
-        case GDK_Pause:         key_code = WXK_PAUSE;       break;
-        case GDK_Scroll_Lock:   key_code = WXK_SCROLL;      break;
-        case GDK_Escape:        key_code = WXK_ESCAPE;      break;
-        case GDK_Delete:        key_code = WXK_DELETE;      break;
-        case GDK_Home:          key_code = WXK_HOME;        break;
-        case GDK_Left:          key_code = WXK_LEFT;        break;
-        case GDK_Up:            key_code = WXK_UP;          break;
-        case GDK_Right:         key_code = WXK_RIGHT;       break;
-        case GDK_Down:          key_code = WXK_DOWN;        break;
-        case GDK_Prior:         key_code = WXK_PRIOR;       break;
-//      case GDK_Page_Up:       key_code = WXK_PAGEUP;      break;
-        case GDK_Next:          key_code = WXK_NEXT;        break;
-//      case GDK_Page_Down:     key_code = WXK_PAGEDOWN;    break;
-        case GDK_End:           key_code = WXK_END;         break;
-        case GDK_Begin:         key_code = WXK_HOME;        break;
-        case GDK_Select:        key_code = WXK_SELECT;      break;
-        case GDK_Print:         key_code = WXK_PRINT;       break;
-        case GDK_Execute:       key_code = WXK_EXECUTE;     break;
-        case GDK_Insert:        key_code = WXK_INSERT;      break;
-        case GDK_Num_Lock:      key_code = WXK_NUMLOCK;     break;
-
-        case GDK_KP_0:         key_code = '0';      break;
-        case GDK_KP_1:         key_code = '1';      break;
-        case GDK_KP_2:         key_code = '2';      break;
-        case GDK_KP_3:         key_code = '3';      break;
-        case GDK_KP_4:         key_code = '4';      break;
-        case GDK_KP_5:         key_code = '5';      break;
-        case GDK_KP_6:         key_code = '6';      break;
-        case GDK_KP_7:         key_code = '7';      break;
-        case GDK_KP_8:         key_code = '8';      break;
-        case GDK_KP_9:         key_code = '9';      break;
-        case GDK_KP_Space:     key_code = ' ';      break;
-        case GDK_KP_Tab:       key_code = WXK_TAB;    break;        /* or '\t' ??? */
-        case GDK_KP_Enter:     key_code = WXK_RETURN; break;        /* or '\r' ??? */
-        case GDK_KP_F1:        key_code = WXK_NUMPAD_F1;    break;
-        case GDK_KP_F2:        key_code = WXK_NUMPAD_F2;    break;
-        case GDK_KP_F3:        key_code = WXK_NUMPAD_F3;    break;
-        case GDK_KP_F4:        key_code = WXK_NUMPAD_F4;    break;
-        case GDK_KP_Home:      key_code = WXK_HOME;  break;
-        case GDK_KP_Left:      key_code = WXK_LEFT;  break;
-        case GDK_KP_Up:        key_code = WXK_UP;    break;
-        case GDK_KP_Right:     key_code = WXK_RIGHT; break;
-        case GDK_KP_Down:      key_code = WXK_DOWN;  break;
-        case GDK_KP_Prior:     key_code = WXK_PRIOR; break;
-//      case GDK_KP_Page_Up:   key_code = WXK_PAGEUP; break;
-        case GDK_KP_Next:      key_code = WXK_NEXT;  break;
-//      case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
-        case GDK_KP_End:       key_code = WXK_END;    break;
-        case GDK_KP_Begin:     key_code = WXK_HOME;   break;
-        case GDK_KP_Insert:    key_code = WXK_INSERT; break;
-        case GDK_KP_Delete:    key_code = WXK_DELETE; break;
-        case GDK_KP_Equal:     key_code = '=';   break;
-        case GDK_KP_Multiply:  key_code = '*';   break;
-        case GDK_KP_Add:       key_code = '+';   break;
-        case GDK_KP_Separator: key_code = ',';   break;
-        case GDK_KP_Subtract:  key_code = '-';   break;
-        case GDK_KP_Decimal:   key_code = '.';   break;
-        case GDK_KP_Divide:    key_code = '/';   break;
-
-        case GDK_F1:            key_code = WXK_F1;          break;
-        case GDK_F2:            key_code = WXK_F2;          break;
-        case GDK_F3:            key_code = WXK_F3;          break;
-        case GDK_F4:            key_code = WXK_F4;          break;
-        case GDK_F5:            key_code = WXK_F5;          break;
-        case GDK_F6:            key_code = WXK_F6;          break;
-        case GDK_F7:            key_code = WXK_F7;          break;
-        case GDK_F8:            key_code = WXK_F8;          break;
-        case GDK_F9:            key_code = WXK_F9;          break;
-        case GDK_F10:           key_code = WXK_F10;         break;
-        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;
-            }
-            else if ((keysym & 0xFF) == keysym)
-            {
-                key_code = (guint)keysym;
-            }
-    }
-
-    return key_code;
-}
+#endif // GTK+ < 2.0
 
 //-----------------------------------------------------------------------------
 // "size_request" of m_widget
@@ -775,6 +547,7 @@ static int gtk_window_expose_callback( GtkWidget *widget,
     }
 */
 
+#ifndef __WXUNIVERSAL__
     GtkPizza *pizza = GTK_PIZZA (widget);
 
     if (win->GetThemeEnabled())
@@ -794,40 +567,21 @@ static int gtk_window_expose_callback( GtkWidget *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 );
 
-    // Actually send the various events based on the
-    // current update region.
-    if (gdk_event->count == 0)
-        win->GtkSendPaintEvents();
+    // Actual redrawing takes place in idle time.
+    win->Update();
 
-    // 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;
+#ifdef __WXGTK20__
 
-        GdkEventExpose child_event = *gdk_event;
+    (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
 
-        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);
-        }
-    }
+#endif
 
     return TRUE;
 }
@@ -859,8 +613,10 @@ gint gtk_window_event_event_callback( GtkWidget *widget,
 // "draw" of m_wxwindow
 //-----------------------------------------------------------------------------
 
+#ifndef __WXGTK20__
+
 // This callback is a complete replacement of the gtk_pizza_draw() function,
-// which disabled.
+// which is disabled.
 
 static void gtk_window_draw_callback( GtkWidget *widget,
                                       GdkRectangle *rect,
@@ -892,6 +648,7 @@ static void gtk_window_draw_callback( GtkWidget *widget,
     }
 */
 
+#ifndef __WXUNIVERSAL__
     GtkPizza *pizza = GTK_PIZZA (widget);
 
     if (win->GetThemeEnabled())
@@ -919,13 +676,15 @@ static void gtk_window_draw_callback( GtkWidget *widget,
         gdk_window_clear_area( pizza->bin_window,
                                rect->x, rect->y, rect->width, rect->height);
     }
+#endif
 
     win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
 
-    // Actually send the various events based on the
-    // current update region.
-    win->GtkSendPaintEvents();
+    // Actual redrawing takes place in idle time.
 
+    win->Update();
+
+#ifndef __WXUNIVERSAL__
     // Redraw child widgets
     GList *children = pizza->children;
     while (children)
@@ -939,14 +698,416 @@ static void gtk_window_draw_callback( GtkWidget *widget,
             gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
         }
     }
+#endif
 }
 
+#endif
+
 //-----------------------------------------------------------------------------
 // "key_press_event" from any window
 //-----------------------------------------------------------------------------
 
-// turn on to see the key event codes on the console
-#undef DEBUG_KEY_EVENTS
+// set WXTRACE to this to see the key event codes on the console
+#define TRACE_KEYS  _T("keyevent")
+
+// translates an X key symbol to WXK_XXX value
+//
+// if isChar is true it means that the value returned will be used for EVT_CHAR
+// event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
+// for example, while if it is false it means that the value is going to be
+// used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
+// WXK_NUMPAD_DIVIDE
+static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
+{
+    long key_code;
+
+    switch ( keysym )
+    {
+        // Shift, Control and Alt don't generate the CHAR events at all
+        case GDK_Shift_L:
+        case GDK_Shift_R:
+            key_code = isChar ? 0 : WXK_SHIFT;
+            break;
+        case GDK_Control_L:
+        case GDK_Control_R:
+            key_code = isChar ? 0 : WXK_CONTROL;
+            break;
+        case GDK_Meta_L:
+        case GDK_Meta_R:
+        case GDK_Alt_L:
+        case GDK_Alt_R:
+        case GDK_Super_L:
+        case GDK_Super_R:
+            key_code = isChar ? 0 : WXK_ALT;
+            break;
+
+        // neither do the toggle modifies
+        case GDK_Scroll_Lock:
+            key_code = isChar ? 0 : WXK_SCROLL;
+            break;
+
+        case GDK_Caps_Lock:
+            key_code = isChar ? 0 : WXK_CAPITAL;
+            break;
+
+        case GDK_Num_Lock:
+            key_code = isChar ? 0 : WXK_NUMLOCK;
+            break;
+
+
+        // various other special keys
+        case GDK_Menu:
+            key_code = WXK_MENU;
+            break;
+
+        case GDK_Help:
+            key_code = WXK_HELP;
+            break;
+
+        case GDK_BackSpace:
+            key_code = WXK_BACK;
+            break;
+
+        case GDK_ISO_Left_Tab:
+        case GDK_Tab:
+            key_code = WXK_TAB;
+            break;
+
+        case GDK_Linefeed:
+        case GDK_Return:
+            key_code = WXK_RETURN;
+            break;
+
+        case GDK_Clear:
+            key_code = WXK_CLEAR;
+            break;
+
+        case GDK_Pause:
+            key_code = WXK_PAUSE;
+            break;
+
+        case GDK_Select:
+            key_code = WXK_SELECT;
+            break;
+
+        case GDK_Print:
+            key_code = WXK_PRINT;
+            break;
+
+        case GDK_Execute:
+            key_code = WXK_EXECUTE;
+            break;
+
+        case GDK_Escape:
+            key_code = WXK_ESCAPE;
+            break;
+
+        // cursor and other extended keyboard keys
+        case GDK_Delete:
+            key_code = WXK_DELETE;
+            break;
+
+        case GDK_Home:
+            key_code = WXK_HOME;
+            break;
+
+        case GDK_Left:
+            key_code = WXK_LEFT;
+            break;
+
+        case GDK_Up:
+            key_code = WXK_UP;
+            break;
+
+        case GDK_Right:
+            key_code = WXK_RIGHT;
+            break;
+
+        case GDK_Down:
+            key_code = WXK_DOWN;
+            break;
+
+        case GDK_Prior:     // == GDK_Page_Up
+            key_code = WXK_PRIOR;
+            break;
+
+        case GDK_Next:      // == GDK_Page_Down
+            key_code = WXK_NEXT;
+            break;
+
+        case GDK_End:
+            key_code = WXK_END;
+            break;
+
+        case GDK_Begin:
+            key_code = WXK_HOME;
+            break;
+
+        case GDK_Insert:
+            key_code = WXK_INSERT;
+            break;
+
+
+        // numpad keys
+        case GDK_KP_0:
+        case GDK_KP_1:
+        case GDK_KP_2:
+        case GDK_KP_3:
+        case GDK_KP_4:
+        case GDK_KP_5:
+        case GDK_KP_6:
+        case GDK_KP_7:
+        case GDK_KP_8:
+        case GDK_KP_9:
+            key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0;
+            break;
+
+        case GDK_KP_Space:
+            key_code = isChar ? ' ' : WXK_NUMPAD_SPACE;
+            break;
+
+        case GDK_KP_Tab:
+            key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB;
+            break;
+
+        case GDK_KP_Enter:
+            key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER;
+            break;
+
+        case GDK_KP_F1:
+            key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1;
+            break;
+
+        case GDK_KP_F2:
+            key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2;
+            break;
+
+        case GDK_KP_F3:
+            key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3;
+            break;
+
+        case GDK_KP_F4:
+            key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4;
+            break;
+
+        case GDK_KP_Home:
+            key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME;
+            break;
+
+        case GDK_KP_Left:
+            key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT;
+            break;
+
+        case GDK_KP_Up:
+            key_code = isChar ? WXK_UP : WXK_NUMPAD_UP;
+            break;
+
+        case GDK_KP_Right:
+            key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT;
+            break;
+
+        case GDK_KP_Down:
+            key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN;
+            break;
+
+        case GDK_KP_Prior: // == GDK_KP_Page_Up
+            key_code = isChar ? WXK_PRIOR : WXK_NUMPAD_PRIOR;
+            break;
+
+        case GDK_KP_Next: // == GDK_KP_Page_Down
+            key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT;
+            break;
+
+        case GDK_KP_End:
+            key_code = isChar ? WXK_END : WXK_NUMPAD_END;
+            break;
+
+        case GDK_KP_Begin:
+            key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN;
+            break;
+
+        case GDK_KP_Insert:
+            key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT;
+            break;
+
+        case GDK_KP_Delete:
+            key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE;
+            break;
+
+        case GDK_KP_Equal:
+            key_code = isChar ? '=' : WXK_NUMPAD_EQUAL;
+            break;
+
+        case GDK_KP_Multiply:
+            key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY;
+            break;
+
+        case GDK_KP_Add:
+            key_code = isChar ? '+' : WXK_NUMPAD_ADD;
+            break;
+
+        case GDK_KP_Separator:
+            // FIXME: what is this?
+            key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR;
+            break;
+
+        case GDK_KP_Subtract:
+            key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT;
+            break;
+
+        case GDK_KP_Decimal:
+            key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL;
+            break;
+
+        case GDK_KP_Divide:
+            key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE;
+            break;
+
+
+        // function keys
+        case GDK_F1:
+        case GDK_F2:
+        case GDK_F3:
+        case GDK_F4:
+        case GDK_F5:
+        case GDK_F6:
+        case GDK_F7:
+        case GDK_F8:
+        case GDK_F9:
+        case GDK_F10:
+        case GDK_F11:
+        case GDK_F12:
+            key_code = WXK_F1 + keysym - GDK_F1;
+            break;
+
+        default:
+            key_code = 0;
+    }
+
+    return key_code;
+}
+
+static inline bool wxIsAsciiKeysym(KeySym ks)
+{
+    return ks < 256;
+}
+
+static bool
+wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
+                           wxWindowGTK *win,
+                           GdkEventKey *gdk_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 reuse it as last resort
+    //
+    // NB: should be MT-safe as we're always called from the main thread only
+    static struct
+    {
+        KeySym keysym;
+        long   keycode;
+    } s_lastKeyPress = { 0, 0 };
+
+    KeySym keysym = gdk_event->keyval;
+
+    wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %d"),
+               event.GetEventType() == wxEVT_KEY_UP ? _T("release")
+                                                    : _T("press"),
+               keysym);
+
+    long key_code = wxTranslateKeySymToWXKey(keysym, FALSE /* !isChar */);
+
+    if ( !key_code )
+    {
+        // do we have the translation or is it a plain ASCII character?
+        if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
+        {
+            // we should use keysym if it is ASCII as X does some translations
+            // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
+            // which we don't want here (but which we do use for OnChar())
+            if ( !wxIsAsciiKeysym(keysym) )
+            {
+                keysym = (KeySym)gdk_event->string[0];
+            }
+
+            // we want to always get the same key code when the same key is
+            // pressed regardless of the state of the modifies, i.e. on a
+            // standard US keyboard pressing '5' or '%' ('5' key with
+            // Shift) should result in the same key code in OnKeyDown():
+            // '5' (although OnChar() will get either '5' or '%').
+            //
+            // to do it we first translate keysym to keycode (== scan code)
+            // and then back but always using the lower register
+            Display *dpy = (Display *)wxGetDisplay();
+            KeyCode keycode = XKeysymToKeycode(dpy, keysym);
+
+            wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
+
+            KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
+
+            // use the normalized, i.e. lower register, keysym if we've
+            // got one
+            key_code = keysymNormalized ? keysymNormalized : keysym;
+
+            // as explained above, we want to have lower register key codes
+            // normally but for the letter keys we want to have the upper ones
+            //
+            // NB: don't use XConvertCase() here, we want to do it for letters
+            // only
+            key_code = toupper(key_code);
+        }
+        else // non ASCII key, what to do?
+        {
+            // by default, ignore it
+            key_code = 0;
+
+            // but if we have cached information from the last KEY_PRESS
+            if ( gdk_event->type == GDK_KEY_RELEASE )
+            {
+                // then reuse it
+                if ( keysym == s_lastKeyPress.keysym )
+                {
+                    key_code = s_lastKeyPress.keycode;
+                }
+            }
+        }
+
+        if ( gdk_event->type == GDK_KEY_PRESS )
+        {
+            // remember it to be reused for KEY_UP event later
+            s_lastKeyPress.keysym = keysym;
+            s_lastKeyPress.keycode = key_code;
+        }
+    }
+
+    wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %d"), key_code);
+
+    // sending unknown key events doesn't really make sense
+    if ( !key_code )
+        return FALSE;
+
+    // now fill all the other fields
+    int x = 0;
+    int y = 0;
+    GdkModifierType state;
+    if (gdk_event->window)
+        gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+
+    event.SetTimestamp( gdk_event->time );
+    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
+    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
+    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
+    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
+    event.m_keyCode = key_code;
+    event.m_scanCode = gdk_event->keyval;
+    event.m_rawCode = (wxUint32) gdk_event->keyval;
+    event.m_rawFlags = 0;
+    event.m_x = x;
+    event.m_y = y;
+    event.SetEventObject( win );
+
+    return TRUE;
+}
 
 static gint gtk_window_key_press_callback( GtkWidget *widget,
                                            GdkEventKey *gdk_event,
@@ -957,40 +1118,19 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     if (g_isIdle)
         wxapp_install_idle_handler();
 
-    if (!win->m_hasVMT) return FALSE;
-    if (g_blockEventsOnDrag) return FALSE;
-
-
-    int x = 0;
-    int y = 0;
-    GdkModifierType state;
-    if (gdk_event->window)
-        gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
-
-    bool ret = FALSE;
-
-    long key_code = map_to_unmodified_wx_keysym( gdk_event );
-
-#ifdef DEBUG_KEY_EVENTS
-    wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code);
-#endif // DEBUG_KEY_EVENTS
-
-    /* sending unknown key events doesn't really make sense */
-    if (key_code == 0)
+    if (!win->m_hasVMT)
+        return FALSE;
+    if (g_blockEventsOnDrag)
         return FALSE;
 
     wxKeyEvent event( wxEVT_KEY_DOWN );
-    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_keyCode = key_code;
-    event.m_scanCode = gdk_event->keyval;
-    event.m_x = x;
-    event.m_y = y;
-    event.SetEventObject( win );
-    ret = win->GetEventHandler()->ProcessEvent( event );
+    if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+    {
+        // unknown key pressed, ignore (the event would be useless anyhow)
+        return FALSE;
+    }
+
+    bool ret = win->GetEventHandler()->ProcessEvent( event );
 
 #if wxUSE_ACCEL
     if (!ret)
@@ -1016,15 +1156,26 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
        will only be sent if it is not in an accelerator table. */
     if ( !ret )
     {
-        key_code = map_to_wx_keysym( gdk_event );
+        KeySym keysym = gdk_event->keyval;
+        long key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
+        if ( !key_code )
+        {
+            if ( gdk_event->length == 1 )
+            {
+                key_code = (unsigned char)gdk_event->string[0];
+            }
+            else if ( wxIsAsciiKeysym(keysym) )
+            {
+                // ASCII key
+                key_code = (unsigned char)keysym;
+            }
+        }
 
         if ( key_code )
         {
-#ifdef DEBUG_KEY_EVENTS
-            wxPrintf(_T("Char event: %ld\n"), key_code);
-#endif // DEBUG_KEY_EVENTS
+            wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
 
-            // reuse the ame event object, just change its type and use the
+            // reuse the same event object, just change its type and use the
             // translated keycode instead of the raw one
             event.SetEventType(wxEVT_CHAR);
             event.m_keyCode = key_code;
@@ -1106,50 +1257,33 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
 // "key_release_event" from any window
 //-----------------------------------------------------------------------------
 
-static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win )
+static gint gtk_window_key_release_callback( GtkWidget *widget,
+                                             GdkEventKey *gdk_event,
+                                             wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
     if (g_isIdle)
         wxapp_install_idle_handler();
 
-    if (!win->m_hasVMT) return FALSE;
-    if (g_blockEventsOnDrag) return FALSE;
-
-    long key_code = map_to_unmodified_wx_keysym( gdk_event );
-
-#ifdef DEBUG_KEY_EVENTS
-    wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code);
-#endif // DEBUG_KEY_EVENTS
-
-    /* sending unknown key events doesn't really make sense */
-    if (key_code == 0) return FALSE;
+    if (!win->m_hasVMT)
+        return FALSE;
 
-    int x = 0;
-    int y = 0;
-    GdkModifierType state;
-    if (gdk_event->window)
-        gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+    if (g_blockEventsOnDrag)
+        return FALSE;
 
     wxKeyEvent event( wxEVT_KEY_UP );
-    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_keyCode = key_code;
-    event.m_scanCode = gdk_event->keyval;
-    event.m_x = x;
-    event.m_y = y;
-    event.SetEventObject( win );
-
-    if (win->GetEventHandler()->ProcessEvent( event ))
+    if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
     {
-        gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
-        return TRUE;
+        // unknown key pressed, ignore (the event would be useless anyhow
+        return FALSE;
     }
 
-    return FALSE;
+    if ( !win->GetEventHandler()->ProcessEvent( event ) )
+        return FALSE;
+
+    gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
+    return TRUE;
 }
 
 // ============================================================================
@@ -1232,20 +1366,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;
@@ -1668,10 +1797,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
@@ -1730,9 +1856,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
 
@@ -1742,17 +1866,9 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
-    // 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 )
-    {
-        gs_widgetLastFocus = NULL;
-
-        return FALSE;
-    }
+#if 0
+    wxLogDebug( wxT("OnKillFocus from %s"), win->GetName().c_str() );
+#endif
 
     if ( !g_activeFrameLostFocus && g_activeFrame )
     {
@@ -1778,13 +1894,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();
@@ -1877,13 +1986,13 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_
 
     gdk_window_get_pointer( widget->window, &x, &y, &state );
 
-    event.m_shiftDown = (state & GDK_SHIFT_MASK);
-    event.m_controlDown = (state & GDK_CONTROL_MASK);
-    event.m_altDown = (state & GDK_MOD1_MASK);
-    event.m_metaDown = (state & GDK_MOD2_MASK);
-    event.m_leftDown = (state & GDK_BUTTON1_MASK);
-    event.m_middleDown = (state & GDK_BUTTON2_MASK);
-    event.m_rightDown = (state & GDK_BUTTON3_MASK);
+    event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
+    event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
+    event.m_altDown = (state & GDK_MOD1_MASK) != 0;
+    event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
+    event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
+    event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
+    event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
 
     wxPoint pt = win->GetClientAreaOrigin();
     event.m_x = x + pt.x;
@@ -1902,7 +2011,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
 
@@ -1918,14 +2029,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);
 
@@ -1938,7 +2042,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
 
@@ -1951,16 +2057,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);
 
@@ -1984,7 +2083,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;
 }
@@ -2367,6 +2470,9 @@ bool wxWindowGTK::Create( wxWindow *parent,
     }
 
     m_insertCallback = wxInsertChildInWindow;
+    
+    // always needed for background clearing
+    m_delayedBackgroundColour = TRUE; 
 
     m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
     GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
@@ -2383,10 +2489,7 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
     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))
@@ -2405,33 +2508,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;
@@ -2583,6 +2666,7 @@ 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 );
 
@@ -2591,14 +2675,19 @@ void wxWindowGTK::PostCreation()
                 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
@@ -2606,12 +2695,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 );
 
@@ -2727,7 +2810,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;
@@ -2753,20 +2835,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,
@@ -2806,7 +2895,7 @@ void wxWindowGTK::OnInternalIdle()
 {
     // Update invalidated regions.
     Update();
-    
+
     // Synthetize activate events.
     if ( g_sendActivateEvent != -1 )
     {
@@ -3196,8 +3285,6 @@ void wxWindowGTK::SetFocus()
     {
         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);
         }
     }
@@ -3209,21 +3296,13 @@ 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
         {
            // ?
         }
     }
-
-#if 0
-    wxPrintf( "SetFocus finished in " );
-    if (GetClassInfo() && GetClassInfo()->GetClassName())
-        wxPrintf( GetClassInfo()->GetClassName() );
-    wxPrintf( ".\n" );
-#endif
-
 }
 
 bool wxWindowGTK::AcceptsFocus() const
@@ -3338,12 +3417,7 @@ 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)
@@ -3389,14 +3463,35 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
             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;
+            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
 }
 
 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()
@@ -3410,20 +3505,27 @@ void wxWindowGTK::GtkSendPaintEvents()
 
     m_clipPaintRegion = TRUE;
 
-    if (!m_clearRegion.IsEmpty())
+    // 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))
         {
+            if (!g_eraseGC)
+            {
+                g_eraseGC = gdk_gc_new( GTK_PIZZA(m_wxwindow)->bin_window );
+                gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
+            }
+            gdk_gc_set_foreground( g_eraseGC, m_backgroundColour.GetColor() );
+
             wxRegionIterator upd( m_clearRegion );
             while (upd)
             {
-                gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
+                gdk_draw_rectangle( GTK_PIZZA(m_wxwindow)->bin_window, g_eraseGC, 1,
                                        upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
                 upd ++;
             }
@@ -3439,9 +3541,55 @@ void wxWindowGTK::GtkSendPaintEvents()
     paint_event.SetEventObject( this );
     GetEventHandler()->ProcessEvent( paint_event );
 
-    m_updateRegion.Clear();
-
     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 = pizza->bin_window;
+            gdk_event.count = 0;
+
+            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()
@@ -3452,7 +3600,7 @@ void wxWindowGTK::Clear()
 
     if (m_wxwindow && m_wxwindow->window)
     {
-//        gdk_window_clear( m_wxwindow->window );
+        gdk_window_clear( m_wxwindow->window );
     }
 }
 
@@ -3496,6 +3644,12 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
         m_delayedBackgroundColour = TRUE;
     }
 
+    if (window)
+    {
+        // We need the pixel value e.g. for background clearing.
+        m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
+    }
+    
     if ((m_wxwindow) &&
         (m_wxwindow->window) &&
         (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)))
@@ -3503,7 +3657,6 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
         /* wxMSW doesn't clear the window here. I don't do that either to
           provide compatibility. call Clear() to do the job. */
 
-        m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
         gdk_window_set_background( window, m_backgroundColour.GetColor() );
     }
 
@@ -3547,10 +3700,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
 
@@ -3565,10 +3717,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
     }
@@ -3578,7 +3729,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;
@@ -3596,8 +3747,7 @@ void wxWindowGTK::SetWidgetStyle()
 
     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())
@@ -3707,6 +3857,9 @@ static gint gs_pop_y = 0;
 
 extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
                                              gint *x, gint *y,
+#ifdef __WXGTK20__
+                                             gboolean * WXUNUSED(whatever),
+#endif
                                              gpointer WXUNUSED(user_data) )
 {
     // ensure that the menu appears entirely on screen
@@ -4042,89 +4195,45 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
 
     // No scrolling requested.
     if ((dx == 0) && (dy == 0)) return;
-    
+
+#ifndef __WXGTK20__
     if (!m_updateRegion.IsEmpty())
     {
         m_updateRegion.Offset( dx, dy );
-        
+
         int cw = 0;
         int ch = 0;
         GetClientSize( &cw, &ch );
         m_updateRegion.Intersect( 0, 0, cw, ch );
     }
-    
+
     if (!m_clearRegion.IsEmpty())
     {
         m_clearRegion.Offset( dx, dy );
-        
+
         int cw = 0;
         int ch = 0;
         GetClientSize( &cw, &ch );
         m_clearRegion.Intersect( 0, 0, cw, ch );
     }
-    
-#if 1
 
     m_clipPaintRegion = TRUE;
-    
+
     gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
-    
-    m_clipPaintRegion = FALSE;
 
+    m_clipPaintRegion = FALSE;
 #else
 
-    if (m_children.GetCount() > 0)
-    {
-        gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
-    }
-    else
-    {
-        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 );
-
-        int cw = 0;
-        int ch = 0;
-        GetClientSize( &cw, &ch );
-        int w = cw - abs(dx);
-        int h = ch - abs(dy);
+    gdk_window_scroll( GTK_PIZZA(m_wxwindow)->bin_window, dx, 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 );
-        }
+    GTK_PIZZA(m_wxwindow)->xoffset += dx;
+    GTK_PIZZA(m_wxwindow)->yoffset += dy;
 
-        gdk_gc_unref( m_scrollGC );
-    }
 #endif
+
 }
 
+
 // Find the wxWindow at the current mouse position, also returning the mouse
 // position.
 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
@@ -4166,3 +4275,33 @@ 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()
+{
+    if (g_eraseGC)
+        gdk_gc_unref( g_eraseGC );
+}
+