]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
update frm Ivan Masar
[wxWidgets.git] / src / gtk / window.cpp
index 2ca9ce464edd47da294df82bc60f6646f38796d0..0cb6276a0dac881f2e7dd8297544fe00c477246b 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
-// Name:        window.cpp
+// Name:        src/gtk/window.cpp
 // Purpose:
 // Author:      Robert Roebling
-// Created:     01/02/97
-// Id:
-// Copyright:   (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
+// Id:          $Id$
+// Copyright:   (c) 1998 Robert Roebling, Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
 
-#ifdef __GNUG__
-#pragma implementation "window.h"
+#ifdef __VMS
+#define XWarpPointer XWARPPOINTER
 #endif
 
-#include "wx/defs.h"
 #include "wx/window.h"
-#include "wx/dc.h"
-#include "wx/frame.h"
-#include "wx/app.h"
-#include "wx/layout.h"
-#include "wx/utils.h"
-#include "wx/dialog.h"
-#include "wx/msgdlg.h"
-#include "wx/dcclient.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/log.h"
+    #include "wx/app.h"
+    #include "wx/frame.h"
+    #include "wx/dcclient.h"
+    #include "wx/menu.h"
+    #include "wx/settings.h"
+    #include "wx/msgdlg.h"
+    #include "wx/textctrl.h"
+    #include "wx/radiobut.h"
+    #include "wx/toolbar.h"
+    #include "wx/combobox.h"
+    #include "wx/layout.h"
+    #include "wx/math.h"
+#endif
+
 #include "wx/dnd.h"
-#include "wx/mdi.h"
-#include "wx/menu.h"
-#include "wx/notebook.h"
-#include "wx/statusbr.h"
-#include <wx/intl.h>
-#include "gdk/gdkkeysyms.h"
-#include <math.h>
+#include "wx/tooltip.h"
+#include "wx/caret.h"
+#include "wx/fontutil.h"
+
+#ifdef __WXDEBUG__
+    #include "wx/thread.h"
+#endif
+
+#include <ctype.h>
+
+// FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
+#include <gtk/gtkversion.h>
+#if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
+    #undef GTK_DISABLE_DEPRECATED
+    #include <gtk/gtkcombo.h>
+    #define GTK_DISABLE_DEPRECATED
+#endif
+
+#include "wx/gtk/private.h"
 #include "wx/gtk/win_gtk.h"
-#include "gdk/gdkprivate.h"
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+
+//-----------------------------------------------------------------------------
+// documentation on internals
+//-----------------------------------------------------------------------------
+
+/*
+   I have been asked several times about writing some documentation about
+   the GTK port of wxWidgets, especially its internal structures. Obviously,
+   you cannot understand wxGTK without knowing a little about the GTK, but
+   some more information about what the wxWindow, which is the base class
+   for all other window classes, does seems required as well.
+
+   I)
+
+   What does wxWindow do? It contains the common interface for the following
+   jobs of its descendants:
+
+   1) Define the rudimentary behaviour common to all window classes, such as
+   resizing, intercepting user input (so as to make it possible to use these
+   events for special purposes in a derived class), window names etc.
+
+   2) Provide the possibility to contain and manage children, if the derived
+   class is allowed to contain children, which holds true for those window
+   classes which do not display a native GTK widget. To name them, these
+   classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
+   work classes are a special case and are handled a bit differently from
+   the rest. The same holds true for the wxNotebook class.
+
+   3) Provide the possibility to draw into a client area of a window. This,
+   too, only holds true for classes that do not display a native GTK widget
+   as above.
+
+   4) Provide the entire mechanism for scrolling widgets. This actual inter-
+   face for this is usually in wxScrolledWindow, but the GTK implementation
+   is in this class.
+
+   5) A multitude of helper or extra methods for special purposes, such as
+   Drag'n'Drop, managing validators etc.
+
+   6) Display a border (sunken, raised, simple or none).
+
+   Normally one might expect, that one wxWidgets window would always correspond
+   to one GTK widget. Under GTK, there is no such all-round widget that has all
+   the functionality. Moreover, the GTK defines a client area as a different
+   widget from the actual widget you are handling. Last but not least some
+   special classes (e.g. wxFrame) handle different categories of widgets and
+   still have the possibility to draw something in the client area.
+   It was therefore required to write a special purpose GTK widget, that would
+   represent a client area in the sense of wxWidgets capable to do the jobs
+   2), 3) and 4). I have written this class and it resides in win_gtk.c of
+   this directory.
+
+   All windows must have a widget, with which they interact with other under-
+   lying GTK widgets. It is this widget, e.g. that has to be resized etc and
+   the wxWindow class has a member variable called m_widget which holds a
+   pointer to this widget. When the window class represents a GTK native widget,
+   this is (in most cases) the only GTK widget the class manages. E.g. the
+   wxStaticText class handles only a GtkLabel widget a pointer to which you
+   can find in m_widget (defined in wxWindow)
+
+   When the class has a client area for drawing into and for containing children
+   it has to handle the client area widget (of the type GtkPizza, defined in
+   win_gtk.c), but there could be any number of widgets, handled by a class
+   The common rule for all windows is only, that the widget that interacts with
+   the rest of GTK must be referenced in m_widget and all other widgets must be
+   children of this widget on the GTK level. The top-most widget, which also
+   represents the client area, must be in the m_wxwindow field and must be of
+   the type GtkPizza.
+
+   As I said, the window classes that display a GTK native widget only have
+   one widget, so in the case of e.g. the wxButton class m_widget holds a
+   pointer to a GtkButton widget. But windows with client areas (for drawing
+   and children) have a m_widget field that is a pointer to a GtkScrolled-
+   Window and a m_wxwindow field that is pointer to a GtkPizza and this
+   one is (in the GTK sense) a child of the GtkScrolledWindow.
+
+   If the m_wxwindow field is set, then all input to this widget is inter-
+   cepted and sent to the wxWidgets class. If not, all input to the widget
+   that gets pointed to by m_widget gets intercepted and sent to the class.
+
+   II)
+
+   The design of scrolling in wxWidgets is markedly different from that offered
+   by the GTK itself and therefore we cannot simply take it as it is. In GTK,
+   clicking on a scrollbar belonging to scrolled window will inevitably move
+   the window. In wxWidgets, the scrollbar will only emit an event, send this
+   to (normally) a wxScrolledWindow and that class will call ScrollWindow()
+   which actually moves the window and its sub-windows. Note that GtkPizza
+   memorizes how much it has been scrolled but that wxWidgets forgets this
+   so that the two coordinates systems have to be kept in synch. This is done
+   in various places using the pizza->xoffset and pizza->yoffset values.
+
+   III)
+
+   Singularly the most broken code in GTK is the code that is supposed to
+   inform subwindows (child windows) about new positions. Very often, duplicate
+   events are sent without changes in size or position, equally often no
+   events are sent at all (All this is due to a bug in the GtkContainer code
+   which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
+   GTK's own system and it simply waits for size events for toplevel windows
+   and then iterates down the respective size events to all window. This has
+   the disadvantage that windows might get size events before the GTK widget
+   actually has the reported size. This doesn't normally pose any problem, but
+   the OpenGL drawing routines rely on correct behaviour. Therefore, I have
+   added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
+   i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
+   window that is used for OpenGL output really has that size (as reported by
+   GTK).
+
+   IV)
+
+   If someone at some point of time feels the immense desire to have a look at,
+   change or attempt to optimise the Refresh() logic, this person will need an
+   intimate understanding of what "draw" and "expose" events are and what
+   they are used for, in particular when used in connection with GTK's
+   own windowless widgets. Beware.
+
+   V)
+
+   Cursors, too, have been a constant source of pleasure. The main difficulty
+   is that a GdkWindow inherits a cursor if the programmer sets a new cursor
+   for the parent. To prevent this from doing too much harm, I use idle time
+   to set the cursor over and over again, starting from the toplevel windows
+   and ending with the youngest generation (speaking of parent and child windows).
+   Also don't forget that cursors (like much else) are connected to GdkWindows,
+   not GtkWidgets and that the "window" field of a GtkWidget might very well
+   point to the GdkWindow of the parent widget (-> "window-less widget") and
+   that the two obviously have very different meanings.
+
+*/
 
 //-----------------------------------------------------------------------------
 // data
 //-----------------------------------------------------------------------------
 
-extern wxList wxPendingDelete;
-extern wxList wxTopLevelWindows;
-extern bool   g_blockEventsOnDrag;
+// Don't allow event propagation during drag
+bool g_blockEventsOnDrag;
+// Don't allow mouse event propagation during scroll
+bool g_blockEventsOnScroll;
+extern wxCursor   g_globalCursor;
+
+// mouse capture state: the window which has it and if the mouse is currently
+// inside it
+static wxWindowGTK  *g_captureWindow = (wxWindowGTK*) NULL;
+static bool g_captureWindowHasMouse = false;
+
+wxWindowGTK  *g_focusWindow = (wxWindowGTK*) NULL;
+
+// the last window which had the focus - this is normally never NULL (except
+// if we never had focus at all) as even when g_focusWindow is NULL it still
+// keeps its previous value
+wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL;
+
+// If a window get the focus set but has not been realized
+// yet, defer setting the focus to idle time.
+wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL;
+
+// global variables because GTK+ DnD want to have the
+// mouse event that caused it
+GdkEvent    *g_lastMouseEvent = (GdkEvent*) NULL;
+int          g_lastButtonNumber = 0;
+
+extern bool g_mainThreadLocked;
 
 //-----------------------------------------------------------------------------
-// "expose_event" (of m_wxwindow, not of m_widget)
+// debug
 //-----------------------------------------------------------------------------
 
-static void gtk_window_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxWindow *win )
-{ 
-  if (!win->HasVMT()) return;
-  if (g_blockEventsOnDrag) return;
-  
-  win->m_updateRegion.Union( gdk_event->area.x,
-                             gdk_event->area.y,
-                            gdk_event->area.width,
-                             gdk_event->area.height );
-           
-  if (gdk_event->count > 0) return;
-
-  wxPaintEvent event( win->GetId() );
-  event.SetEventObject( win );
-  win->GetEventHandler()->ProcessEvent( event );
-  
-  win->m_updateRegion.Clear();
-}
+#ifdef __WXDEBUG__
+
+#if wxUSE_THREADS
+#   define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
+#else
+#   define DEBUG_MAIN_THREAD
+#endif
+#else
+#define DEBUG_MAIN_THREAD
+#endif // Debug
+
+// the trace mask used for the focus debugging messages
+#define TRACE_FOCUS _T("focus")
 
 //-----------------------------------------------------------------------------
-// "draw" (of m_wxwindow, not of m_widget)
+// missing gdk functions
 //-----------------------------------------------------------------------------
 
-static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget), GdkRectangle *rect, wxWindow *win )
-{ 
-  if (!win->HasVMT()) return;
-  if (g_blockEventsOnDrag) return;
-  
-  win->m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
-           
-  wxPaintEvent event( win->GetId() );
-  event.SetEventObject( win );
-  win->GetEventHandler()->ProcessEvent( event );
-  
-  win->m_updateRegion.Clear();
+void
+gdk_window_warp_pointer (GdkWindow      *window,
+                         gint            x,
+                         gint            y)
+{
+  if (!window)
+    window = gdk_get_default_root_window();
+
+  if (!GDK_WINDOW_DESTROYED(window))
+  {
+      XWarpPointer (GDK_WINDOW_XDISPLAY(window),
+                    None,              /* not source window -> move from anywhere */
+                    GDK_WINDOW_XID(window),  /* dest window */
+                    0, 0, 0, 0,        /* not source window -> move from anywhere */
+                    x, y );
+  }
 }
 
 //-----------------------------------------------------------------------------
-// "key_press_event"
+// local code (see below)
 //-----------------------------------------------------------------------------
 
-static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
-{ 
-  if (!win->HasVMT()) return FALSE;
-  if (g_blockEventsOnDrag) return FALSE;
+// returns the child of win which currently has focus or NULL if not found
+//
+// Note: can't be static, needed by textctrl.cpp.
+wxWindow *wxFindFocusedChild(wxWindowGTK *win)
+{
+    wxWindow *winFocus = wxWindowGTK::FindFocus();
+    if ( !winFocus )
+        return (wxWindow *)NULL;
 
-/*
-  printf( "OnKeyPress from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
+    if ( winFocus == win )
+        return (wxWindow *)win;
 
-  long key_code = 0;
-  switch (gdk_event->keyval)
-  {
-    case GDK_BackSpace:     key_code = WXK_BACK;        break;
-    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_Tab:        key_code = WXK_TAB;         break;
-    case GDK_KP_Enter:      key_code = WXK_RETURN;      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_Multiply:   key_code = WXK_MULTIPLY;    break;
-    case GDK_KP_Add:        key_code = WXK_ADD;         break;
-    case GDK_KP_Separator:  key_code = WXK_SEPARATOR;   break;
-    case GDK_KP_Subtract:   key_code = WXK_SUBTRACT;    break;
-    case GDK_KP_Decimal:    key_code = WXK_DECIMAL;     break;
-    case GDK_KP_Divide:     key_code = WXK_DIVIDE;      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_NUMPAD7;     break;
-    case GDK_KP_9:          key_code = WXK_NUMPAD9;     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 ((gdk_event->keyval >= 0x20) && (gdk_event->keyval <= 0xFF)) 
-        key_code = gdk_event->keyval;
+    for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
+          node;
+          node = node->GetNext() )
+    {
+        wxWindow *child = wxFindFocusedChild(node->GetData());
+        if ( child )
+            return child;
     }
-  }
 
-  if (!key_code) return FALSE;
-  
-  wxKeyEvent event( wxEVT_CHAR );
-  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_x = 0;
-  event.m_y = 0;
-  event.SetEventObject( win );
-  
-  bool ret = win->GetEventHandler()->ProcessEvent( event );
-  
-  if (!ret)
-  {
-    wxWindow *ancestor = win;
-    while (ancestor)
-    {    
-      int command = ancestor->GetAcceleratorTable()->GetCommand( event );
-      if (command != -1)
-      {
-        wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
-        ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
-       break;
-      }
-      ancestor = ancestor->GetParent();
-    }
-  }
-  
-  if (ret)
-  {
-    if ((gdk_event->keyval >= 0x20) && (gdk_event->keyval <= 0xFF)) 
-      gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
-  }
-  
-  return ret;
+    return (wxWindow *)NULL;
 }
 
-//-----------------------------------------------------------------------------
-// "button_press_event"
-//-----------------------------------------------------------------------------
+static void GetScrollbarWidth(GtkWidget* widget, int& w, int& h)
+{
+    GtkScrolledWindow* scroll_window = GTK_SCROLLED_WINDOW(widget);
+    GtkScrolledWindowClass* scroll_class = GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window));
+    GtkRequisition scroll_req;
+
+    w = 0;
+    if (scroll_window->vscrollbar_visible)
+    {
+        scroll_req.width = 2;
+        scroll_req.height = 2;
+        (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
+            (scroll_window->vscrollbar, &scroll_req );
+        w = scroll_req.width +
+            scroll_class->scrollbar_spacing;
+    }
 
-static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
+    h = 0;
+    if (scroll_window->hscrollbar_visible)
+    {
+        scroll_req.width = 2;
+        scroll_req.height = 2;
+        (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
+            (scroll_window->hscrollbar, &scroll_req );
+        h = scroll_req.height +
+            scroll_class->scrollbar_spacing;
+    }
+}
+
+static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
 {
-  if (!win->IsOwnGtkWindow( gdk_event->window )) return TRUE;
-  
-  if (g_blockEventsOnDrag) return TRUE;
+    // wxUniversal widgets draw the borders and scrollbars themselves
+#ifndef __WXUNIVERSAL__
+    if (!win->m_hasVMT)
+        return;
 
-  if (win->m_wxwindow)
-  {
-    if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
+    int dx = 0;
+    int dy = 0;
+    if (GTK_WIDGET_NO_WINDOW (widget))
     {
-      gtk_widget_grab_focus (win->m_wxwindow);
-      
-/*
-      printf( "GrabFocus from " );
-      if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-        printf( win->GetClassInfo()->GetClassName() );
-      printf( ".\n" );
-*/
-      
+        dx += widget->allocation.x;
+        dy += widget->allocation.y;
     }
-  }
-    
-  if (!win->HasVMT()) return TRUE;
-    
-/*
-  printf( "OnButtonPress from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
 
-  wxEventType event_type = wxEVT_LEFT_DOWN;
-  
-  if (gdk_event->button == 1)
-  {
-    switch (gdk_event->type)
+    int x = dx;
+    int y = dy;
+
+    int dw = 0;
+    int dh = 0;
+    if (win->m_hasScrolling)
+    {
+        GetScrollbarWidth(widget, dw, dh);
+
+        if (win->GetLayoutDirection() == wxLayout_RightToLeft)
+        {
+            // This is actually wrong for old GTK+ version
+            // which do not display the scrollbar on the
+            // left side in RTL
+            x += dw;
+        }
+    }
+
+    int w = widget->allocation.width-dw;
+    int h = widget->allocation.height-dh;
+
+    if (win->HasFlag(wxRAISED_BORDER))
     {
-      case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
-      case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
-      default:  break;
+        gtk_paint_shadow (widget->style,
+                          widget->window,
+                          GTK_STATE_NORMAL,
+                          GTK_SHADOW_OUT,
+                          NULL, NULL, NULL, // FIXME: No clipping?
+                          x, y, w, h );
+        return;
     }
-  }
-  else if (gdk_event->button == 2)
-  {
-    switch (gdk_event->type)
+
+    if (win->HasFlag(wxSUNKEN_BORDER))
     {
-      case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
-      case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
-      default:  break;
+        gtk_paint_shadow (widget->style,
+                          widget->window,
+                          GTK_STATE_NORMAL,
+                          GTK_SHADOW_IN,
+                          NULL, NULL, NULL, // FIXME: No clipping?
+                          x, y, w, h );
+        return;
     }
-  }
-  else if (gdk_event->button == 3)
-  {
-    switch (gdk_event->type)
+
+    if (win->HasFlag(wxSIMPLE_BORDER))
     {
-      case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
-      case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
-      default:  break;
+        GdkGC *gc;
+        gc = gdk_gc_new( widget->window );
+        gdk_gc_set_foreground( gc, &widget->style->black );
+        gdk_draw_rectangle( widget->window, gc, FALSE, x, y, w-1, h-1 );
+        g_object_unref (gc);
+        return;
     }
-  }
-  
-  wxMouseEvent event( event_type );
-  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 = (long)gdk_event->x;
-  event.m_y = (long)gdk_event->y;
-  
-  // Some control don't have their own X window and thus cannot get
-  // any events. 
-  
-  wxNode *node = win->GetChildren()->First();
-  while (node)
-  {
-    wxWindow *child = (wxWindow*)node->Data();
-    if ((child->m_x <= event.m_x) &&
-        (child->m_y <= event.m_y) &&
-       (child->m_x+child->m_width  >= event.m_x) &&
-       (child->m_y+child->m_height >= event.m_y))
-    {
-      win = child;
-      event.m_x -= child->m_x;
-      event.m_y -= child->m_y;
-      break;
-    }
-    node = node->Next();
-  }
-  
-  event.SetEventObject( win );
-  
-  if (win->GetEventHandler()->ProcessEvent( event ))
-    gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
-  
-  return TRUE;
+#endif // __WXUNIVERSAL__
 }
 
 //-----------------------------------------------------------------------------
-// "button_release"
+// "expose_event" of m_widget
 //-----------------------------------------------------------------------------
 
-static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
-{ 
-  if (!win->IsOwnGtkWindow( gdk_event->window )) return TRUE;
-  if (g_blockEventsOnDrag) return TRUE;
-
-  if (!win->HasVMT()) return TRUE;
-/*
-  printf( "OnButtonRelease from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
-  
-  wxEventType event_type = wxEVT_NULL;
-  
-  switch (gdk_event->button)
-  {
-    case 1: event_type = wxEVT_LEFT_UP; break;
-    case 2: event_type = wxEVT_MIDDLE_UP; break;
-    case 3: event_type = wxEVT_RIGHT_UP; break;
-  }
-
-  wxMouseEvent event( event_type );
-  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 = (long)gdk_event->x;
-  event.m_y = (long)gdk_event->y;
-  
-  // Some control don't have their own X window and thus cannot get
-  // any events. 
-  
-  wxNode *node = win->GetChildren()->First();
-  while (node)
-  {
-    wxWindow *child = (wxWindow*)node->Data();
-    if ((child->m_x <= event.m_x) &&
-        (child->m_y <= event.m_y) &&
-       (child->m_x+child->m_width  >= event.m_x) &&
-       (child->m_y+child->m_height >= event.m_y))
-    {
-      win = child;
-      event.m_x -= child->m_x;
-      event.m_y -= child->m_y;
-      break;
-    }
-    node = node->Next();
-  }
-  
-  event.SetEventObject( win );
-  
-  if (win->GetEventHandler()->ProcessEvent( event ))
-    gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
-  
-  return TRUE;
+extern "C" {
+static gboolean
+gtk_window_own_expose_callback( GtkWidget *widget,
+                                GdkEventExpose *gdk_event,
+                                wxWindowGTK *win )
+{
+    if (gdk_event->count == 0)
+        draw_frame(widget, win);
+    return false;
+}
 }
 
 //-----------------------------------------------------------------------------
-// "motion_notify_event"
+// "size_request" of m_widget
 //-----------------------------------------------------------------------------
 
-static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
-{ 
-  if (!win->IsOwnGtkWindow( gdk_event->window )) return TRUE;
-  if (g_blockEventsOnDrag) return TRUE;
+// make it extern because wxStaticText needs to disconnect this one
+extern "C" {
+void wxgtk_window_size_request_callback(GtkWidget *widget,
+                                        GtkRequisition *requisition,
+                                        wxWindow *win)
+{
+    int w, h;
+    win->GetSize( &w, &h );
+    if (w < 2)
+        w = 2;
+    if (h < 2)
+        h = 2;
 
-  if (!win->HasVMT()) return TRUE;
-  
-/*
-  printf( "OnMotion from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
-  
-  wxMouseEvent event( wxEVT_MOTION );
-  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 = (long)gdk_event->x;
-  event.m_y = (long)gdk_event->y;
-  
-  // Some control don't have their own X window and thus cannot get
-  // any events. 
-  
-  wxNode *node = win->GetChildren()->First();
-  while (node)
-  {
-    wxWindow *child = (wxWindow*)node->Data();
-    if ((child->m_x <= event.m_x) &&
-        (child->m_y <= event.m_y) &&
-       (child->m_x+child->m_width  >= event.m_x) &&
-       (child->m_y+child->m_height >= event.m_y))
-    {
-      win = child;
-      event.m_x -= child->m_x;
-      event.m_y -= child->m_y;
-      break;
-    }
-    node = node->Next();
-  }
-  
-  event.SetEventObject( win );
-  
-  if (win->GetEventHandler()->ProcessEvent( event ))
-    gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
-  
-  return TRUE;
+    requisition->height = h;
+    requisition->width = w;
+}
+}
+
+extern "C" {
+static
+void wxgtk_combo_size_request_callback(GtkWidget *widget,
+                                       GtkRequisition *requisition,
+                                       wxComboBox *win)
+{
+    // This callback is actually hooked into the text entry
+    // of the combo box, not the GtkHBox.
+
+    int w, h;
+    win->GetSize( &w, &h );
+    if (w < 2)
+        w = 2;
+    if (h < 2)
+        h = 2;
+
+    GtkCombo *gcombo = GTK_COMBO(win->m_widget);
+
+    GtkRequisition entry_req;
+    entry_req.width = 2;
+    entry_req.height = 2;
+    (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->entry) )->size_request )
+        (gcombo->entry, &entry_req );
+
+    GtkRequisition button_req;
+    button_req.width = 2;
+    button_req.height = 2;
+    (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request )
+        (gcombo->button, &button_req );
+
+    requisition->width = w - button_req.width;
+    requisition->height = entry_req.height;
+}
 }
 
 //-----------------------------------------------------------------------------
-// "focus_in_event"
+// "expose_event" of m_wxwindow
 //-----------------------------------------------------------------------------
 
-static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
+extern "C" {
+static gboolean
+gtk_window_expose_callback( GtkWidget *widget,
+                            GdkEventExpose *gdk_event,
+                            wxWindow *win )
 {
-  if (g_blockEventsOnDrag) return TRUE;
-  if (win->m_wxwindow)
-  {
-    if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
-    {
-      GTK_WIDGET_SET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
-/*      
-      printf( "SetFocus flag from " );
-      if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-        printf( win->GetClassInfo()->GetClassName() );
-      printf( ".\n" );
-*/
+    DEBUG_MAIN_THREAD
+
+    // This callback gets called in drawing-idle time under
+    // GTK 2.0, so we don't need to defer anything to idle
+    // time anymore.
+
+    GtkPizza *pizza = GTK_PIZZA( widget );
+    if (gdk_event->window != pizza->bin_window)
+    {
+        // block expose events on GTK_WIDGET(pizza)->window,
+        //   all drawing is done on pizza->bin_window
+        return true;
     }
-  }
-  
-  if (!win->HasVMT()) return TRUE;
-  
-/*
-  printf( "OnSetFocus from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( "   " );
-  printf( WXSTRINGCAST win->GetLabel() );
-  printf( ".\n" );
-*/
-  
-  wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
-  event.SetEventObject( win );
-  
-  if (win->GetEventHandler()->ProcessEvent( event ))
-    gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
-  
-  return TRUE;
+
+
+#if 0
+    if (win->GetName())
+    {
+        wxPrintf( wxT("OnExpose from ") );
+        if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
+            wxPrintf( win->GetClassInfo()->GetClassName() );
+        wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
+                                         (int)gdk_event->area.y,
+                                         (int)gdk_event->area.width,
+                                         (int)gdk_event->area.height );
+    }
+
+    gtk_paint_box
+    (
+        win->m_wxwindow->style,
+        pizza->bin_window,
+        GTK_STATE_NORMAL,
+        GTK_SHADOW_OUT,
+        (GdkRectangle*) NULL,
+        win->m_wxwindow,
+        (char *)"button", // const_cast
+        20,20,24,24
+    );
+#endif
+
+    win->GetUpdateRegion() = wxRegion( gdk_event->region );
+
+    win->GtkSendPaintEvents();
+
+    // Let parent window draw window-less widgets
+    return FALSE;
+}
 }
 
 //-----------------------------------------------------------------------------
-// "focus_out_event"
+// "key_press_event" from any window
 //-----------------------------------------------------------------------------
 
-static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
+// These are used when transforming Ctrl-alpha to ascii values 1-26
+inline bool wxIsLowerChar(int code)
+{
+    return (code >= 'a' && code <= 'z' );
+}
+
+inline bool wxIsUpperChar(int code)
+{
+    return (code >= 'A' && code <= 'Z' );
+}
+
+
+// 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_PAGEUP;
+            break;
+
+        case GDK_Next:      // == 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_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_PAGEUP : WXK_NUMPAD_PAGEUP;
+            break;
+
+        case GDK_KP_Next: // == GDK_KP_Page_Down
+            key_code = isChar ? WXK_PAGEDOWN : WXK_NUMPAD_PAGEDOWN;
+            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 void wxFillOtherKeyEventFields(wxKeyEvent& event,
+                                      wxWindowGTK *win,
+                                      GdkEventKey *gdk_event)
+{
+    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.SetId(win->GetId());
+    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_scanCode = gdk_event->keyval;
+    event.m_rawCode = (wxUint32) gdk_event->keyval;
+    event.m_rawFlags = 0;
+#if wxUSE_UNICODE
+    event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
+#endif
+    wxGetMousePosition( &x, &y );
+    win->ScreenToClient( &x, &y );
+    event.m_x = x;
+    event.m_y = y;
+    event.SetEventObject( win );
+}
+
+
+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 = %ld"),
+               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 modifiers, 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 %ld"), key_code);
+
+    // sending unknown key events doesn't really make sense
+    if ( !key_code )
+        return false;
+
+    // now fill all the other fields
+    wxFillOtherKeyEventFields(event, win, gdk_event);
+
+    event.m_keyCode = key_code;
+#if wxUSE_UNICODE
+    if ( gdk_event->type == GDK_KEY_PRESS ||  gdk_event->type == GDK_KEY_RELEASE )
+    {
+        event.m_uniChar = key_code;
+    }
+#endif
+
+    return true;
+}
+
+
+struct wxGtkIMData
+{
+    GtkIMContext *context;
+    GdkEventKey  *lastKeyEvent;
+
+    wxGtkIMData()
+    {
+        context = gtk_im_multicontext_new();
+        lastKeyEvent = NULL;
+    }
+    ~wxGtkIMData()
+    {
+        g_object_unref (context);
+    }
+};
+
+extern "C" {
+static gboolean
+gtk_window_key_press_callback( GtkWidget *widget,
+                               GdkEventKey *gdk_event,
+                               wxWindow *win )
+{
+    DEBUG_MAIN_THREAD
+
+    if (!win->m_hasVMT)
+        return FALSE;
+    if (g_blockEventsOnDrag)
+        return FALSE;
+
+
+    wxKeyEvent event( wxEVT_KEY_DOWN );
+    bool ret = false;
+    bool return_after_IM = false;
+
+    if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+    {
+        // Emit KEY_DOWN event
+        ret = win->GetEventHandler()->ProcessEvent( event );
+    }
+    else
+    {
+        // Return after IM processing as we cannot do
+        // anything with it anyhow.
+        return_after_IM = true;
+    }
+
+    // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
+    // When we get a key_press event here, it could be originate
+    // from the current widget or its child widgets.  However, only the widget
+    // with the INPUT FOCUS can generate the INITIAL key_press event.  That is,
+    // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
+    // originated from its child widgets and shouldn't be passed to IM context.
+    // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
+    // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS.  Besides, when current
+    // widgets has both IM context and input focus, the event should be filtered
+    // by gtk_im_context_filter_keypress().
+    // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
+    if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
+    {
+        // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
+        // docs, if IM filter returns true, no further processing should be done.
+        // we should send the key_down event anyway.
+        bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
+        win->m_imData->lastKeyEvent = NULL;
+        if (intercepted_by_IM)
+        {
+            wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
+            return TRUE;
+        }
+    }
+
+    if (return_after_IM)
+        return FALSE;
+
+#if wxUSE_ACCEL
+    if (!ret)
+    {
+        wxWindowGTK *ancestor = win;
+        while (ancestor)
+        {
+            int command = ancestor->GetAcceleratorTable()->GetCommand( event );
+            if (command != -1)
+            {
+                wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
+                ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
+                break;
+            }
+            if (ancestor->IsTopLevel())
+                break;
+            ancestor = ancestor->GetParent();
+        }
+    }
+#endif // wxUSE_ACCEL
+
+    // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
+    // will only be sent if it is not in an accelerator table.
+    if (!ret)
+    {
+        long key_code;
+        KeySym keysym = gdk_event->keyval;
+        // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
+        key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
+        if ( !key_code )
+        {
+            if ( wxIsAsciiKeysym(keysym) )
+            {
+                // ASCII key
+                key_code = (unsigned char)keysym;
+            }
+            // gdk_event->string is actually deprecated
+            else if ( gdk_event->length == 1 )
+            {
+                key_code = (unsigned char)gdk_event->string[0];
+            }
+        }
+
+        if ( key_code )
+        {
+            wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
+
+            event.m_keyCode = key_code;
+
+            // To conform to the docs we need to translate Ctrl-alpha
+            // characters to values in the range 1-26.
+            if ( event.ControlDown() &&
+                 ( wxIsLowerChar(key_code) || wxIsUpperChar(key_code) ))
+            {
+                if ( wxIsLowerChar(key_code) )
+                    event.m_keyCode = key_code - 'a' + 1;
+                if ( wxIsUpperChar(key_code) )
+                    event.m_keyCode = key_code - 'A' + 1;
+#if wxUSE_UNICODE
+                event.m_uniChar = event.m_keyCode;
+#endif
+            }
+
+            // Implement OnCharHook by checking ancestor top level windows
+            wxWindow *parent = win;
+            while (parent && !parent->IsTopLevel())
+                parent = parent->GetParent();
+            if (parent)
+            {
+                event.SetEventType( wxEVT_CHAR_HOOK );
+                ret = parent->GetEventHandler()->ProcessEvent( event );
+            }
+
+            if (!ret)
+            {
+                event.SetEventType(wxEVT_CHAR);
+                ret = win->GetEventHandler()->ProcessEvent( event );
+            }
+        }
+    }
+
+    return ret;
+}
+}
+
+extern "C" {
+static void
+gtk_wxwindow_commit_cb (GtkIMContext *context,
+                        const gchar  *str,
+                        wxWindow     *window)
+{
+    wxKeyEvent event( wxEVT_KEY_DOWN );
+
+    // take modifiers, cursor position, timestamp etc. from the last
+    // key_press_event that was fed into Input Method:
+    if (window->m_imData->lastKeyEvent)
+    {
+        wxFillOtherKeyEventFields(event,
+                                  window, window->m_imData->lastKeyEvent);
+    }
+
+    const wxWxCharBuffer data(wxGTK_CONV_BACK_SYS(str));
+    if( !data )
+        return;
+
+    bool ret = false;
+
+    // Implement OnCharHook by checking ancestor top level windows
+    wxWindow *parent = window;
+    while (parent && !parent->IsTopLevel())
+        parent = parent->GetParent();
+
+    for( const wxChar* pstr = data; *pstr; pstr++ )
+    {
+#if wxUSE_UNICODE
+        event.m_uniChar = *pstr;
+        // Backward compatible for ISO-8859-1
+        event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
+        wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
+#else
+        event.m_keyCode = *pstr;
+#endif  // wxUSE_UNICODE
+
+        // To conform to the docs we need to translate Ctrl-alpha
+        // characters to values in the range 1-26.
+        if ( event.ControlDown() &&
+             ( wxIsLowerChar(*pstr) || wxIsUpperChar(*pstr) ))
+        {
+            if ( wxIsLowerChar(*pstr) )
+                event.m_keyCode = *pstr - 'a' + 1;
+            if ( wxIsUpperChar(*pstr) )
+                event.m_keyCode = *pstr - 'A' + 1;
+
+            event.m_keyCode = *pstr - 'a' + 1;
+#if wxUSE_UNICODE
+            event.m_uniChar = event.m_keyCode;
+#endif
+        }
+
+        if (parent)
+        {
+            event.SetEventType( wxEVT_CHAR_HOOK );
+            ret = parent->GetEventHandler()->ProcessEvent( event );
+        }
+
+        if (!ret)
+        {
+            event.SetEventType(wxEVT_CHAR);
+            ret = window->GetEventHandler()->ProcessEvent( event );
+        }
+    }
+}
+}
+
+
+//-----------------------------------------------------------------------------
+// "key_release_event" from any window
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static gboolean
+gtk_window_key_release_callback( GtkWidget *widget,
+                                 GdkEventKey *gdk_event,
+                                 wxWindowGTK *win )
+{
+    DEBUG_MAIN_THREAD
+
+    if (!win->m_hasVMT)
+        return FALSE;
+
+    if (g_blockEventsOnDrag)
+        return FALSE;
+
+    wxKeyEvent event( wxEVT_KEY_UP );
+    if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+    {
+        // unknown key pressed, ignore (the event would be useless anyhow)
+        return FALSE;
+    }
+
+    return win->GTKProcessEvent(event);
+}
+}
+
+// ============================================================================
+// the mouse events
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// mouse event processing helpers
+// ----------------------------------------------------------------------------
+
+// init wxMouseEvent with the info from GdkEventXXX struct
+template<typename T> void InitMouseEvent(wxWindowGTK *win,
+                                         wxMouseEvent& event,
+                                         T *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);
+    if (event.GetEventType() == wxEVT_MOUSEWHEEL)
+    {
+       event.m_linesPerAction = 3;
+       event.m_wheelDelta = 120;
+       if (((GdkEventButton*)gdk_event)->button == 4)
+           event.m_wheelRotation = 120;
+       else if (((GdkEventButton*)gdk_event)->button == 5)
+           event.m_wheelRotation = -120;
+    }
+
+    wxPoint pt = win->GetClientAreaOrigin();
+    event.m_x = (wxCoord)gdk_event->x - pt.x;
+    event.m_y = (wxCoord)gdk_event->y - pt.y;
+
+    if ((win->m_wxwindow) && (win->GetLayoutDirection() == wxLayout_RightToLeft))
+    {
+        // origin in the upper right corner
+        int window_width = gtk_pizza_get_rtl_offset( GTK_PIZZA(win->m_wxwindow) );
+        event.m_x = window_width - event.m_x;
+    }
+
+    event.SetEventObject( win );
+    event.SetId( win->GetId() );
+    event.SetTimestamp( gdk_event->time );
+}
+
+static void AdjustEventButtonState(wxMouseEvent& event)
+{
+    // GDK reports the old state of the button for a button press event, but
+    // for compatibility with MSW and common sense we want m_leftDown be TRUE
+    // for a LEFT_DOWN event, not FALSE, so we will invert
+    // left/right/middleDown for the corresponding click events
+
+    if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
+        (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
+        (event.GetEventType() == wxEVT_LEFT_UP))
+    {
+        event.m_leftDown = !event.m_leftDown;
+        return;
+    }
+
+    if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
+        (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
+        (event.GetEventType() == wxEVT_MIDDLE_UP))
+    {
+        event.m_middleDown = !event.m_middleDown;
+        return;
+    }
+
+    if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
+        (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
+        (event.GetEventType() == wxEVT_RIGHT_UP))
+    {
+        event.m_rightDown = !event.m_rightDown;
+        return;
+    }
+}
+
+// find the window to send the mouse event too
+static
+wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
+{
+    wxCoord xx = x;
+    wxCoord yy = y;
+
+    if (win->m_wxwindow)
+    {
+        GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
+        xx += gtk_pizza_get_xoffset( pizza );
+        yy += gtk_pizza_get_yoffset( pizza );
+    }
+
+    wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
+    while (node)
+    {
+        wxWindowGTK *child = node->GetData();
+
+        node = node->GetNext();
+        if (!child->IsShown())
+            continue;
+
+        if (child->IsTransparentForMouse())
+        {
+            // wxStaticBox is transparent in the box itself
+            int xx1 = child->m_x;
+            int yy1 = child->m_y;
+            int xx2 = child->m_x + child->m_width;
+            int yy2 = child->m_y + child->m_height;
+
+            // left
+            if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
+            // right
+                ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
+            // top
+                ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
+            // bottom
+                ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
+            {
+                win = child;
+                x -= child->m_x;
+                y -= child->m_y;
+                break;
+            }
+
+        }
+        else
+        {
+            if ((child->m_wxwindow == (GtkWidget*) NULL) &&
+                (child->m_x <= xx) &&
+                (child->m_y <= yy) &&
+                (child->m_x+child->m_width  >= xx) &&
+                (child->m_y+child->m_height >= yy))
+            {
+                win = child;
+                x -= child->m_x;
+                y -= child->m_y;
+                break;
+            }
+        }
+    }
+
+    return win;
+}
+
+// ----------------------------------------------------------------------------
+// common event handlers helpers
+// ----------------------------------------------------------------------------
+
+bool wxWindowGTK::GTKProcessEvent(wxEvent& event) const
+{
+    // nothing special at this level
+    return GetEventHandler()->ProcessEvent(event);
+}
+
+int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const
+{
+    DEBUG_MAIN_THREAD
+
+    if (!m_hasVMT)
+        return FALSE;
+    if (g_blockEventsOnDrag)
+        return TRUE;
+    if (g_blockEventsOnScroll)
+        return TRUE;
+
+    if (!GTKIsOwnWindow(event->window))
+        return FALSE;
+
+    return -1;
+}
+
+// overloads for all GDK event types we use here: we need to have this as
+// GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
+// derives from it in the sense that the structs have the same layout
+#define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T)                                  \
+    static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win)        \
+    {                                                                         \
+        return win->GTKCallbackCommonPrologue((GdkEventAny *)event);          \
+    }
+
+wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton)
+wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion)
+wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing)
+
+#undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
+
+#define wxCOMMON_CALLBACK_PROLOGUE(event, win)                                \
+    const int rc = wxGtkCallbackCommonPrologue(event, win);                   \
+    if ( rc != -1 )                                                           \
+        return rc
+
+// send the wxChildFocusEvent and wxFocusEvent, common code of
+// gtk_window_focus_in_callback() and SetFocus()
+static bool DoSendFocusEvents(wxWindow *win)
+{
+    // Notify the parent keeping track of focus for the kbd navigation
+    // purposes that we got it.
+    wxChildFocusEvent eventChildFocus(win);
+    (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
+
+    wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
+    eventFocus.SetEventObject(win);
+
+    return win->GetEventHandler()->ProcessEvent(eventFocus);
+}
+
+// all event handlers must have C linkage as they're called from GTK+ C code
+extern "C"
+{
+
+//-----------------------------------------------------------------------------
+// "button_press_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_button_press_callback( GtkWidget *widget,
+                                  GdkEventButton *gdk_event,
+                                  wxWindowGTK *win )
+{
+    wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+    g_lastButtonNumber = gdk_event->button;
+
+    if (win->m_wxwindow && (g_focusWindow != win) && win->CanAcceptFocus())
+    {
+        gtk_widget_grab_focus( win->m_wxwindow );
+    }
+
+    // GDK sends surplus button down events
+    // before a double click event. We
+    // need to filter these out.
+    if ((gdk_event->type == GDK_BUTTON_PRESS) && (win->m_wxwindow))
+    {
+        GdkEvent *peek_event = gdk_event_peek();
+        if (peek_event)
+        {
+            if ((peek_event->type == GDK_2BUTTON_PRESS) ||
+                (peek_event->type == GDK_3BUTTON_PRESS))
+            {
+                gdk_event_free( peek_event );
+                return TRUE;
+            }
+            else
+            {
+                gdk_event_free( peek_event );
+            }
+        }
+    }
+
+    wxEventType event_type = wxEVT_NULL;
+
+    // GdkDisplay is a GTK+ 2.2.0 thing
+#if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
+    if ( gdk_event->type == GDK_2BUTTON_PRESS &&
+            !gtk_check_version(2,2,0) &&
+            gdk_event->button >= 1 && gdk_event->button <= 3 )
+    {
+        // Reset GDK internal timestamp variables in order to disable GDK
+        // triple click events. GDK will then next time believe no button has
+        // been clicked just before, and send a normal button click event.
+        GdkDisplay* display = gtk_widget_get_display (widget);
+        display->button_click_time[1] = 0;
+        display->button_click_time[0] = 0;
+    }
+#endif // GTK 2+
+
+    if (gdk_event->button == 1)
+    {
+        // note that GDK generates triple click events which are not supported
+        // by wxWidgets but still have to be passed to the app as otherwise
+        // clicks would simply go missing
+        switch (gdk_event->type)
+        {
+            // we shouldn't get triple clicks at all for GTK2 because we
+            // suppress them artificially using the code above but we still
+            // should map them to something for GTK1 and not just ignore them
+            // as this would lose clicks
+            case GDK_3BUTTON_PRESS:     // we could also map this to DCLICK...
+            case GDK_BUTTON_PRESS:
+                event_type = wxEVT_LEFT_DOWN;
+                break;
+
+            case GDK_2BUTTON_PRESS:
+                event_type = wxEVT_LEFT_DCLICK;
+                break;
+
+            default:
+                // just to silence gcc warnings
+                ;
+        }
+    }
+    else if (gdk_event->button == 2)
+    {
+        switch (gdk_event->type)
+        {
+            case GDK_3BUTTON_PRESS:
+            case GDK_BUTTON_PRESS:
+                event_type = wxEVT_MIDDLE_DOWN;
+                break;
+
+            case GDK_2BUTTON_PRESS:
+                event_type = wxEVT_MIDDLE_DCLICK;
+                break;
+
+            default:
+                ;
+        }
+    }
+    else if (gdk_event->button == 3)
+    {
+        switch (gdk_event->type)
+        {
+            case GDK_3BUTTON_PRESS:
+            case GDK_BUTTON_PRESS:
+                event_type = wxEVT_RIGHT_DOWN;
+                break;
+
+            case GDK_2BUTTON_PRESS:
+                event_type = wxEVT_RIGHT_DCLICK;
+                break;
+
+            default:
+                ;
+        }
+    }
+    else if (gdk_event->button == 4 || gdk_event->button == 5)
+    {
+        if (gdk_event->type == GDK_BUTTON_PRESS )
+        {
+            event_type = wxEVT_MOUSEWHEEL;
+        }
+    }
+
+    if ( event_type == wxEVT_NULL )
+    {
+        // unknown mouse button or click type
+        return FALSE;
+    }
+
+    g_lastMouseEvent = (GdkEvent*) gdk_event;
+
+    wxMouseEvent event( event_type );
+    InitMouseEvent( win, event, gdk_event );
+
+    AdjustEventButtonState(event);
+
+    // wxListBox actually gets mouse events from the item, so we need to give it
+    // a chance to correct this
+    win->FixUpMouseEvent(widget, event.m_x, event.m_y);
+
+    // find the correct window to send the event to: it may be a different one
+    // from the one which got it at GTK+ level because some controls don't have
+    // their own X window and thus cannot get any events.
+    if ( !g_captureWindow )
+        win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+    // reset the event object and id in case win changed.
+    event.SetEventObject( win );
+    event.SetId( win->GetId() );
+
+    bool ret = win->GTKProcessEvent( event );
+    g_lastMouseEvent = NULL;
+    if ( ret )
+        return TRUE;
+
+    if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() && 
+        (g_focusWindow != win) && win->CanAcceptFocus())
+    {
+        gtk_widget_grab_focus( win->m_wxwindow );
+    }
+
+    if (event_type == wxEVT_RIGHT_DOWN)
+    {
+        // generate a "context menu" event: this is similar to right mouse
+        // click under many GUIs except that it is generated differently
+        // (right up under MSW, ctrl-click under Mac, right down here) and
+        //
+        // (a) it's a command event and so is propagated to the parent
+        // (b) under some ports it can be generated from kbd too
+        // (c) it uses screen coords (because of (a))
+        wxContextMenuEvent evtCtx(
+            wxEVT_CONTEXT_MENU,
+            win->GetId(),
+            win->ClientToScreen(event.GetPosition()));
+        evtCtx.SetEventObject(win);
+        return win->GTKProcessEvent(evtCtx);
+    }
+
+    return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "button_release_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_button_release_callback( GtkWidget *widget,
+                                    GdkEventButton *gdk_event,
+                                    wxWindowGTK *win )
+{
+    wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+    g_lastButtonNumber = 0;
+
+    wxEventType event_type = wxEVT_NULL;
+
+    switch (gdk_event->button)
+    {
+        case 1:
+            event_type = wxEVT_LEFT_UP;
+            break;
+
+        case 2:
+            event_type = wxEVT_MIDDLE_UP;
+            break;
+
+        case 3:
+            event_type = wxEVT_RIGHT_UP;
+            break;
+
+        default:
+            // unknown button, don't process
+            return FALSE;
+    }
+
+    g_lastMouseEvent = (GdkEvent*) gdk_event;
+
+    wxMouseEvent event( event_type );
+    InitMouseEvent( win, event, gdk_event );
+
+    AdjustEventButtonState(event);
+
+    // same wxListBox hack as above
+    win->FixUpMouseEvent(widget, event.m_x, event.m_y);
+
+    if ( !g_captureWindow )
+        win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+    // reset the event object and id in case win changed.
+    event.SetEventObject( win );
+    event.SetId( win->GetId() );
+
+    bool ret = win->GTKProcessEvent(event);
+
+    g_lastMouseEvent = NULL;
+
+    return ret;
+}
+
+//-----------------------------------------------------------------------------
+// "motion_notify_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_motion_notify_callback( GtkWidget *widget,
+                                   GdkEventMotion *gdk_event,
+                                   wxWindowGTK *win )
+{
+    wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+    if (gdk_event->is_hint)
+    {
+        int x = 0;
+        int y = 0;
+        GdkModifierType state;
+        gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+        gdk_event->x = x;
+        gdk_event->y = y;
+    }
+
+    g_lastMouseEvent = (GdkEvent*) gdk_event;
+
+    wxMouseEvent event( wxEVT_MOTION );
+    InitMouseEvent(win, event, gdk_event);
+
+    if ( g_captureWindow )
+    {
+        // synthesise a mouse enter or leave event if needed
+        GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
+        // This seems to be necessary and actually been added to
+        // GDK itself in version 2.0.X
+        gdk_flush();
+
+        bool hasMouse = winUnderMouse == gdk_event->window;
+        if ( hasMouse != g_captureWindowHasMouse )
+        {
+            // the mouse changed window
+            g_captureWindowHasMouse = hasMouse;
+
+            wxMouseEvent eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
+                                                        : wxEVT_LEAVE_WINDOW);
+            InitMouseEvent(win, eventM, gdk_event);
+            eventM.SetEventObject(win);
+            win->GTKProcessEvent(eventM);
+        }
+    }
+    else // no capture
+    {
+        win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+        // reset the event object and id in case win changed.
+        event.SetEventObject( win );
+        event.SetId( win->GetId() );
+    }
+
+    if ( !g_captureWindow )
+    {
+        wxSetCursorEvent cevent( event.m_x, event.m_y );
+        if (win->GTKProcessEvent( cevent ))
+        {
+            win->SetCursor( cevent.GetCursor() );
+        }
+    }
+
+    bool ret = win->GTKProcessEvent(event);
+
+    g_lastMouseEvent = NULL;
+
+    return ret;
+}
+
+//-----------------------------------------------------------------------------
+// "scroll_event", (mouse wheel event)
+//-----------------------------------------------------------------------------
+
+static gboolean
+window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
+{
+    DEBUG_MAIN_THREAD
+
+    if (gdk_event->direction != GDK_SCROLL_UP &&
+        gdk_event->direction != GDK_SCROLL_DOWN)
+    {
+        return false;
+    }
+
+    wxMouseEvent event(wxEVT_MOUSEWHEEL);
+    // Can't use InitMouse macro because scroll events don't have button
+    event.SetTimestamp( gdk_event->time );
+    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
+    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_linesPerAction = 3;
+    event.m_wheelDelta = 120;
+    if (gdk_event->direction == GDK_SCROLL_UP)
+        event.m_wheelRotation = 120;
+    else
+        event.m_wheelRotation = -120;
+
+    wxPoint pt = win->GetClientAreaOrigin();
+    event.m_x = (wxCoord)gdk_event->x - pt.x;
+    event.m_y = (wxCoord)gdk_event->y - pt.y;
+
+    event.SetEventObject( win );
+    event.SetId( win->GetId() );
+    event.SetTimestamp( gdk_event->time );
+
+    return win->GTKProcessEvent(event);
+}
+
+//-----------------------------------------------------------------------------
+// "popup-menu"
+//-----------------------------------------------------------------------------
+
+static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
+{
+    wxContextMenuEvent event(wxEVT_CONTEXT_MENU, win->GetId(), wxPoint(-1, -1));
+    event.SetEventObject(win);
+    return win->GTKProcessEvent(event);
+}
+
+//-----------------------------------------------------------------------------
+// "focus_in_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_focus_in_callback( GtkWidget *widget,
+                              GdkEventFocus *WXUNUSED(event),
+                              wxWindow *win )
+{
+    DEBUG_MAIN_THREAD
+
+    if (win->m_imData)
+        gtk_im_context_focus_in(win->m_imData->context);
+
+    g_focusWindowLast =
+    g_focusWindow = win;
+
+    wxLogTrace(TRACE_FOCUS,
+               _T("%s: focus in"), win->GetName().c_str());
+
+#if wxUSE_CARET
+    // caret needs to be informed about focus change
+    wxCaret *caret = win->GetCaret();
+    if ( caret )
+    {
+        caret->OnSetFocus();
+    }
+#endif // wxUSE_CARET
+
+    gboolean ret = FALSE;
+
+    // does the window itself think that it has the focus?
+    if ( !win->m_hasFocus )
+    {
+        // not yet, notify it
+        win->m_hasFocus = true;
+
+        (void)DoSendFocusEvents(win);
+
+        ret = TRUE;
+    }
+
+    // Disable default focus handling for custom windows
+    // since the default GTK+ handler issues a repaint
+    if (win->m_wxwindow)
+        return ret;
+
+    return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "focus_out_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_focus_out_callback( GtkWidget *widget,
+                               GdkEventFocus *gdk_event,
+                               wxWindowGTK *win )
+{
+    DEBUG_MAIN_THREAD
+
+    if (win->m_imData)
+        gtk_im_context_focus_out(win->m_imData->context);
+
+    wxLogTrace( TRACE_FOCUS,
+                _T("%s: focus out"), win->GetName().c_str() );
+
+
+    wxWindowGTK *winFocus = wxFindFocusedChild(win);
+    if ( winFocus )
+        win = winFocus;
+
+    g_focusWindow = (wxWindowGTK *)NULL;
+
+#if wxUSE_CARET
+    // caret needs to be informed about focus change
+    wxCaret *caret = win->GetCaret();
+    if ( caret )
+    {
+        caret->OnKillFocus();
+    }
+#endif // wxUSE_CARET
+
+    // don't send the window a kill focus event if it thinks that it doesn't
+    // have focus already
+    if ( win->m_hasFocus )
+    {
+        // the event handler might delete the window when it loses focus, so
+        // check whether this is a custom window before calling it
+        const bool has_wxwindow = win->m_wxwindow != NULL;
+
+        win->m_hasFocus = false;
+
+        wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
+        event.SetEventObject( win );
+
+        (void)win->GTKProcessEvent( event );
+
+        // Disable default focus handling for custom windows
+        // since the default GTK+ handler issues a repaint
+        if ( has_wxwindow )
+            return TRUE;
+    }
+
+    // continue with normal processing
+    return FALSE;
+}
+
+static gboolean
+wx_window_focus_callback(GtkWidget *widget,
+                         GtkDirectionType direction,
+                         wxWindowGTK *win)
+{
+    // the default handler for focus signal in GtkPizza (or, rather, in
+    // GtkScrolledWindow from which GtkPizza inherits this behaviour) sets
+    // focus to the window itself even if it doesn't accept focus, i.e. has no
+    // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
+    // the signal from reaching gtk_scrolled_window_focus() if we don't have
+    // any children which might accept focus (we know we don't accept the focus
+    // ourselves as this signal is only connected in this case)
+    if ( win->GetChildren().empty() )
+        g_signal_stop_emission_by_name(widget, "focus");
+
+    // we didn't change the focus
+    return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "enter_notify_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_enter_callback( GtkWidget *widget,
+                           GdkEventCrossing *gdk_event,
+                           wxWindowGTK *win )
+{
+    wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+    // Event was emitted after a grab
+    if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
+    int x = 0;
+    int y = 0;
+    GdkModifierType state = (GdkModifierType)0;
+
+    gdk_window_get_pointer( widget->window, &x, &y, &state );
+
+    wxMouseEvent event( wxEVT_ENTER_WINDOW );
+    InitMouseEvent(win, event, gdk_event);
+    wxPoint pt = win->GetClientAreaOrigin();
+    event.m_x = x + pt.x;
+    event.m_y = y + pt.y;
+
+    if ( !g_captureWindow )
+    {
+        wxSetCursorEvent cevent( event.m_x, event.m_y );
+        if (win->GTKProcessEvent( cevent ))
+        {
+            win->SetCursor( cevent.GetCursor() );
+        }
+    }
+
+    return win->GTKProcessEvent(event);
+}
+
+//-----------------------------------------------------------------------------
+// "leave_notify_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_leave_callback( GtkWidget *widget,
+                           GdkEventCrossing *gdk_event,
+                           wxWindowGTK *win )
+{
+    wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+    // Event was emitted after an ungrab
+    if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
+    wxMouseEvent event( wxEVT_LEAVE_WINDOW );
+    event.SetTimestamp( gdk_event->time );
+    event.SetEventObject( win );
+
+    int x = 0;
+    int y = 0;
+    GdkModifierType state = (GdkModifierType)0;
+
+    gdk_window_get_pointer( widget->window, &x, &y, &state );
+
+    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;
+    event.m_y = y + pt.y;
+
+    return win->GTKProcessEvent(event);
+}
+
+//-----------------------------------------------------------------------------
+// "value_changed" from scrollbar
+//-----------------------------------------------------------------------------
+
+static void
+gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win)
+{
+    wxEventType eventType = win->GetScrollEventType(range);
+    if (eventType != wxEVT_NULL)
+    {
+        // Convert scroll event type to scrollwin event type
+        eventType += wxEVT_SCROLLWIN_TOP - wxEVT_SCROLL_TOP;
+
+        // find the scrollbar which generated the event
+        wxWindowGTK::ScrollDir dir = win->ScrollDirFromRange(range);
+
+        // generate the corresponding wx event
+        const int orient = wxWindow::OrientFromScrollDir(dir);
+        wxScrollWinEvent event(eventType, win->GetScrollPos(orient), orient);
+        event.SetEventObject(win);
+
+        win->m_blockValueChanged[dir] = true;
+        win->GTKProcessEvent(event);
+        win->m_blockValueChanged[dir] = false;
+    }
+}
+
+//-----------------------------------------------------------------------------
+// "button_press_event" from scrollbar
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, wxWindow* win)
+{
+    DEBUG_MAIN_THREAD
+
+    g_blockEventsOnScroll = true;
+    win->m_mouseButtonDown = true;
+
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+// "event_after" from scrollbar
+//-----------------------------------------------------------------------------
+
+static void
+gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win)
+{
+    if (event->type == GDK_BUTTON_RELEASE)
+    {
+        g_signal_handlers_block_by_func(range, (void*)gtk_scrollbar_event_after, win);
+
+        const int orient = wxWindow::OrientFromScrollDir(
+                                        win->ScrollDirFromRange(range));
+        wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBRELEASE, win->GetScrollPos(orient), orient);
+        event.SetEventObject(win);
+        win->GTKProcessEvent(event);
+    }
+}
+
+//-----------------------------------------------------------------------------
+// "button_release_event" from scrollbar
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* win)
+{
+    DEBUG_MAIN_THREAD
+
+    g_blockEventsOnScroll = false;
+    win->m_mouseButtonDown = false;
+    // If thumb tracking
+    if (win->m_isScrolling)
+    {
+        win->m_isScrolling = false;
+        // Hook up handler to send thumb release event after this emission is finished.
+        // To allow setting scroll position from event handler, sending event must
+        // be deferred until after the GtkRange handler for this signal has run
+        g_signal_handlers_unblock_by_func(range, (void*)gtk_scrollbar_event_after, win);
+    }
+
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+// "realize" from m_widget
+//-----------------------------------------------------------------------------
+
+static void
+gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
+{
+    DEBUG_MAIN_THREAD
+
+    if (win->m_imData)
+    {
+        GtkPizza *pizza = GTK_PIZZA( m_widget );
+        gtk_im_context_set_client_window( win->m_imData->context,
+                                          pizza->bin_window );
+    }
+
+    // We cannot set colours and fonts before the widget
+    // been realized, so we do this directly after realization
+    // or otherwise in idle time
+
+    if (win->m_needsStyleChange)
+    {
+        win->SetBackgroundStyle(win->GetBackgroundStyle());
+        win->m_needsStyleChange = false;
+    }
+
+    wxWindowCreateEvent event( win );
+    event.SetEventObject( win );
+    win->GTKProcessEvent( event );
+}
+
+//-----------------------------------------------------------------------------
+// "size_allocate"
+//-----------------------------------------------------------------------------
+
+static
+void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
+                               GtkAllocation *alloc,
+                               wxWindow *win )
+{
+    int client_width = 0;
+    int client_height = 0;
+    win->GetClientSize( &client_width, &client_height );
+    if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
+        return;
+
+    if ( !client_width && !client_height )
+    {
+        // the window is currently unmapped, don't generate size events
+        return;
+    }
+
+    win->m_oldClientWidth = client_width;
+    win->m_oldClientHeight = client_height;
+
+    if (!win->m_nativeSizeEvent)
+    {
+        wxSizeEvent event( win->GetSize(), win->GetId() );
+        event.SetEventObject( win );
+        win->GTKProcessEvent( event );
+    }
+}
+
+} // extern "C"
+
+// ----------------------------------------------------------------------------
+// this wxWindowBase function is implemented here (in platform-specific file)
+// because it is static and so couldn't be made virtual
+// ----------------------------------------------------------------------------
+
+wxWindow *wxWindowBase::DoFindFocus()
+{
+    // the cast is necessary when we compile in wxUniversal mode
+    return (wxWindow *)g_focusWindow;
+}
+
+//-----------------------------------------------------------------------------
+// InsertChild for wxWindowGTK.
+//-----------------------------------------------------------------------------
+
+/* Callback for wxWindowGTK. This very strange beast has to be used because
+ * C++ has no virtual methods in a constructor. We have to emulate a
+ * virtual function here as wxNotebook requires a different way to insert
+ * a child in it. I had opted for creating a wxNotebookPage window class
+ * which would have made this superfluous (such in the MDI window system),
+ * but no-one was listening to me... */
+
+static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
+{
+    /* the window might have been scrolled already, do we
+       have to adapt the position */
+    GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
+    child->m_x += gtk_pizza_get_xoffset( pizza );
+    child->m_y += gtk_pizza_get_yoffset( pizza );
+
+    gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
+                     child->m_widget,
+                     child->m_x,
+                     child->m_y,
+                     child->m_width,
+                     child->m_height );
+}
+
+//-----------------------------------------------------------------------------
+// global functions
+//-----------------------------------------------------------------------------
+
+wxWindow *wxGetActiveWindow()
+{
+    return wxWindow::FindFocus();
+}
+
+
+wxMouseState wxGetMouseState()
+{
+    wxMouseState ms;
+
+    gint x;
+    gint y;
+    GdkModifierType mask;
+
+    gdk_window_get_pointer(NULL, &x, &y, &mask);
+
+    ms.SetX(x);
+    ms.SetY(y);
+    ms.SetLeftDown(mask & GDK_BUTTON1_MASK);
+    ms.SetMiddleDown(mask & GDK_BUTTON2_MASK);
+    ms.SetRightDown(mask & GDK_BUTTON3_MASK);
+
+    ms.SetControlDown(mask & GDK_CONTROL_MASK);
+    ms.SetShiftDown(mask & GDK_SHIFT_MASK);
+    ms.SetAltDown(mask & GDK_MOD1_MASK);
+    ms.SetMetaDown(mask & GDK_MOD2_MASK);
+
+    return ms;
+}
+
+//-----------------------------------------------------------------------------
+// wxWindowGTK
+//-----------------------------------------------------------------------------
+
+// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
+// method
+#ifdef __WXUNIVERSAL__
+    IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
+#else // __WXGTK__
+    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
+#endif // __WXUNIVERSAL__/__WXGTK__
+
+void wxWindowGTK::Init()
+{
+    // GTK specific
+    m_widget = (GtkWidget *) NULL;
+    m_wxwindow = (GtkWidget *) NULL;
+    m_focusWidget = (GtkWidget *) NULL;
+
+    // position/size
+    m_x = 0;
+    m_y = 0;
+    m_width = 0;
+    m_height = 0;
+
+    m_sizeSet = false;
+    m_hasVMT = false;
+    m_isBeingDeleted = false;
+
+    m_showOnIdle= false;
+
+    m_noExpose = false;
+    m_nativeSizeEvent = false;
+
+    m_hasScrolling = false;
+    m_isScrolling = false;
+    m_mouseButtonDown = false;
+    m_blockScrollEvent = false;
+
+    // initialize scrolling stuff
+    for ( int dir = 0; dir < ScrollDir_Max; dir++ )
+    {
+        m_scrollBar[dir] = NULL;
+        m_scrollPos[dir] = 0;
+        m_blockValueChanged[dir] = false;
+    }
+
+    m_oldClientWidth =
+    m_oldClientHeight = 0;
+
+    m_resizing = false;
+
+    m_insertCallback = (wxInsertChildFunction) NULL;
+
+    m_hasFocus = false;
+
+    m_clipPaintRegion = false;
+
+    m_needsStyleChange = false;
+
+    m_cursor = *wxSTANDARD_CURSOR;
+
+    m_imData = NULL;
+    m_dirtyTabOrder = false;
+}
+
+wxWindowGTK::wxWindowGTK()
+{
+    Init();
+}
+
+wxWindowGTK::wxWindowGTK( wxWindow *parent,
+                          wxWindowID id,
+                          const wxPoint &pos,
+                          const wxSize &size,
+                          long style,
+                          const wxString &name  )
+{
+    Init();
+
+    Create( parent, id, pos, size, style, name );
+}
+
+bool wxWindowGTK::Create( wxWindow *parent,
+                          wxWindowID id,
+                          const wxPoint &pos,
+                          const wxSize &size,
+                          long style,
+                          const wxString &name  )
+{
+    if (!PreCreation( parent, pos, size ) ||
+        !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
+    {
+        wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
+        return false;
+    }
+
+    m_insertCallback = wxInsertChildInWindow;
+
+
+    if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
+    {
+        m_wxwindow = gtk_pizza_new_no_scroll();
+
+#ifndef __WXUNIVERSAL__
+        if (HasFlag(wxSIMPLE_BORDER))
+            gtk_container_set_border_width((GtkContainer*)m_wxwindow, 1);
+        else if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
+            gtk_container_set_border_width((GtkContainer*)m_wxwindow, 2);
+#endif // __WXUNIVERSAL__
+
+        m_widget = m_wxwindow;
+    }
+    else
+    {
+        m_wxwindow = gtk_pizza_new();
+
+#ifndef __WXUNIVERSAL__
+        if (HasFlag(wxSIMPLE_BORDER))
+            gtk_container_set_border_width((GtkContainer*)m_wxwindow, 1);
+        else if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
+            gtk_container_set_border_width((GtkContainer*)m_wxwindow, 2);
+#endif // __WXUNIVERSAL__
+
+        m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
+
+        GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
+
+        GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
+        scroll_class->scrollbar_spacing = 0;
+
+        // There is a conflict with default bindings at GTK+
+        // level between scrolled windows and notebooks both of which want to use
+        // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
+        // direction and notebooks for changing pages -- we decide that if we don't
+        // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
+        // means we can get working keyboard navigation in notebooks
+        if ( !HasFlag(wxHSCROLL) )
+        {
+            GtkBindingSet *
+                bindings = gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget));
+            if ( bindings )
+            {
+                gtk_binding_entry_remove(bindings, GDK_Page_Up, GDK_CONTROL_MASK);
+                gtk_binding_entry_remove(bindings, GDK_Page_Down, GDK_CONTROL_MASK);
+            }
+        }
+
+        if (HasFlag(wxALWAYS_SHOW_SB))
+        {
+            gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS );
+
+            scrolledWindow->hscrollbar_visible = TRUE;
+            scrolledWindow->vscrollbar_visible = TRUE;
+        }
+        else
+        {
+            gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+        }
+
+        m_scrollBar[ScrollDir_Horz] = GTK_RANGE(scrolledWindow->hscrollbar);
+        m_scrollBar[ScrollDir_Vert] = GTK_RANGE(scrolledWindow->vscrollbar);
+        if (GetLayoutDirection() == wxLayout_RightToLeft)
+            gtk_range_set_inverted( m_scrollBar[ScrollDir_Horz], TRUE );
+
+        gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
+
+        // connect various scroll-related events
+        for ( int dir = 0; dir < ScrollDir_Max; dir++ )
+        {
+            // these handlers block mouse events to any window during scrolling
+            // such as motion events and prevent GTK and wxWidgets from fighting
+            // over where the slider should be
+            g_signal_connect(m_scrollBar[dir], "button_press_event",
+                         G_CALLBACK(gtk_scrollbar_button_press_event), this);
+            g_signal_connect(m_scrollBar[dir], "button_release_event",
+                         G_CALLBACK(gtk_scrollbar_button_release_event), this);
+
+            gulong handler_id = g_signal_connect(m_scrollBar[dir], "event_after",
+                                G_CALLBACK(gtk_scrollbar_event_after), this);
+            g_signal_handler_block(m_scrollBar[dir], handler_id);
+
+            // these handlers get notified when scrollbar slider moves
+            g_signal_connect(m_scrollBar[dir], "value_changed",
+                         G_CALLBACK(gtk_scrollbar_value_changed), this);
+        }
+
+        gtk_widget_show( m_wxwindow );
+    }
+
+    if (m_parent)
+        m_parent->DoAddChild( this );
+
+    m_focusWidget = m_wxwindow;
+
+    PostCreation();
+
+    return true;
+}
+
+wxWindowGTK::~wxWindowGTK()
+{
+    SendDestroyEvent();
+
+    if (g_focusWindow == this)
+        g_focusWindow = NULL;
+
+    if ( g_delayedFocus == this )
+        g_delayedFocus = NULL;
+
+    m_isBeingDeleted = true;
+    m_hasVMT = false;
+
+    // destroy children before destroying this window itself
+    DestroyChildren();
+
+    // unhook focus handlers to prevent stray events being
+    // propagated to this (soon to be) dead object
+    if (m_focusWidget != NULL)
+    {
+        g_signal_handlers_disconnect_by_func (m_focusWidget,
+                                              (gpointer) gtk_window_focus_in_callback,
+                                              this);
+        g_signal_handlers_disconnect_by_func (m_focusWidget,
+                                              (gpointer) gtk_window_focus_out_callback,
+                                              this);
+    }
+
+    if (m_widget)
+        Show( false );
+
+    // delete before the widgets to avoid a crash on solaris
+    delete m_imData;
+
+    if (m_wxwindow && (m_wxwindow != m_widget))
+    {
+        gtk_widget_destroy( m_wxwindow );
+        m_wxwindow = (GtkWidget*) NULL;
+    }
+
+    if (m_widget)
+    {
+        gtk_widget_destroy( m_widget );
+        m_widget = (GtkWidget*) NULL;
+    }
+}
+
+bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos,  const wxSize &size )
+{
+    if ( GTKNeedsParent() )
+    {
+        wxCHECK_MSG( parent, false, wxT("Must have non-NULL parent") );
+    }
+
+    // Use either the given size, or the default if -1 is given.
+    // See wxWindowBase for these functions.
+    m_width = WidthDefault(size.x) ;
+    m_height = HeightDefault(size.y);
+
+    m_x = (int)pos.x;
+    m_y = (int)pos.y;
+
+    return true;
+}
+
+void wxWindowGTK::PostCreation()
+{
+    wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+
+    if (m_wxwindow)
+    {
+        if (!m_noExpose)
+        {
+            // these get reported to wxWidgets -> wxPaintEvent
+
+            g_signal_connect (m_wxwindow, "expose_event",
+                              G_CALLBACK (gtk_window_expose_callback), this);
+
+            if (GetLayoutDirection() == wxLayout_LeftToRight)
+                gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
+        }
+
+        // Create input method handler
+        m_imData = new wxGtkIMData;
+
+        // Cannot handle drawing preedited text yet
+        gtk_im_context_set_use_preedit( m_imData->context, FALSE );
+
+        g_signal_connect (m_imData->context, "commit",
+                          G_CALLBACK (gtk_wxwindow_commit_cb), this);
+
+        // these are called when the "sunken" or "raised" borders are drawn
+        g_signal_connect (m_widget, "expose_event",
+                          G_CALLBACK (gtk_window_own_expose_callback), this);
+    }
+
+    // focus handling
+
+    if (!GTK_IS_WINDOW(m_widget))
+    {
+        if (m_focusWidget == NULL)
+            m_focusWidget = m_widget;
+
+        if (m_wxwindow)
+        {
+            g_signal_connect (m_focusWidget, "focus_in_event",
+                          G_CALLBACK (gtk_window_focus_in_callback), this);
+            g_signal_connect (m_focusWidget, "focus_out_event",
+                                G_CALLBACK (gtk_window_focus_out_callback), this);
+        }
+        else
+        {
+            g_signal_connect_after (m_focusWidget, "focus_in_event",
+                          G_CALLBACK (gtk_window_focus_in_callback), this);
+            g_signal_connect_after (m_focusWidget, "focus_out_event",
+                                G_CALLBACK (gtk_window_focus_out_callback), this);
+        }
+    }
+
+    if ( !AcceptsFocusFromKeyboard() )
+    {
+        SetCanFocus(false);
+
+        g_signal_connect(m_widget, "focus",
+                            G_CALLBACK(wx_window_focus_callback), this);
+    }
+
+    // connect to the various key and mouse handlers
+
+    GtkWidget *connect_widget = GetConnectWidget();
+
+    ConnectWidget( connect_widget );
+
+    /* We cannot set colours, fonts and cursors before the widget has
+       been realized, so we do this directly after realization */
+    g_signal_connect (connect_widget, "realize",
+                      G_CALLBACK (gtk_window_realized_callback), this);
+
+    if (m_wxwindow)
+    {
+        // Catch native resize events
+        g_signal_connect (m_wxwindow, "size_allocate",
+                          G_CALLBACK (gtk_window_size_callback), this);
+    }
+
+    if (GTK_IS_COMBO(m_widget))
+    {
+        GtkCombo *gcombo = GTK_COMBO(m_widget);
+
+        g_signal_connect (gcombo->entry, "size_request",
+                          G_CALLBACK (wxgtk_combo_size_request_callback),
+                          this);
+    }
+#ifdef GTK_IS_FILE_CHOOSER_BUTTON
+    else if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget))
+    {
+        // If we connect to the "size_request" signal of a GtkFileChooserButton
+        // then that control won't be sized properly when placed inside sizers
+        // (this can be tested removing this elseif and running XRC or WIDGETS samples)
+        // FIXME: what should be done here ?
+    }
+#endif
+    else if ( !IsTopLevel() ) // top level windows use their own callback
+    {
+        // This is needed if we want to add our windows into native
+        // GTK controls, such as the toolbar. With this callback, the
+        // toolbar gets to know the correct size (the one set by the
+        // programmer). Sadly, it misbehaves for wxComboBox.
+        g_signal_connect (m_widget, "size_request",
+                          G_CALLBACK (wxgtk_window_size_request_callback),
+                          this);
+    }
+
+    InheritAttributes();
+
+    m_hasVMT = true;
+
+    SetLayoutDirection(wxLayout_Default);
+
+    // unless the window was created initially hidden (i.e. Hide() had been
+    // called before Create()), we should show it at GTK+ level as well
+    if ( IsShown() )
+        gtk_widget_show( m_widget );
+}
+
+void wxWindowGTK::ConnectWidget( GtkWidget *widget )
+{
+    g_signal_connect (widget, "key_press_event",
+                      G_CALLBACK (gtk_window_key_press_callback), this);
+    g_signal_connect (widget, "key_release_event",
+                      G_CALLBACK (gtk_window_key_release_callback), this);
+    g_signal_connect (widget, "button_press_event",
+                      G_CALLBACK (gtk_window_button_press_callback), this);
+    g_signal_connect (widget, "button_release_event",
+                      G_CALLBACK (gtk_window_button_release_callback), this);
+    g_signal_connect (widget, "motion_notify_event",
+                      G_CALLBACK (gtk_window_motion_notify_callback), this);
+    g_signal_connect (widget, "scroll_event",
+                      G_CALLBACK (window_scroll_event), this);
+    g_signal_connect (widget, "popup_menu",
+                     G_CALLBACK (wxgtk_window_popup_menu_callback), this);
+    g_signal_connect (widget, "enter_notify_event",
+                      G_CALLBACK (gtk_window_enter_callback), this);
+    g_signal_connect (widget, "leave_notify_event",
+                      G_CALLBACK (gtk_window_leave_callback), this);
+}
+
+bool wxWindowGTK::Destroy()
+{
+    wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+
+    m_hasVMT = false;
+
+    return wxWindowBase::Destroy();
+}
+
+void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
+{
+    // inform the parent to perform the move
+    gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
+
+}
+
+void wxWindowGTK::ConstrainSize()
+{
+#ifdef __WXGPE__
+    // GPE's window manager doesn't like size hints at all, esp. when the user
+    // has to use the virtual keyboard, so don't constrain size there
+    if (!IsTopLevel())
+#endif
+    {
+        const wxSize minSize = GetMinSize();
+        const wxSize maxSize = GetMaxSize();
+        if (minSize.x > 0 && m_width  < minSize.x) m_width  = minSize.x;
+        if (minSize.y > 0 && m_height < minSize.y) m_height = minSize.y;
+        if (maxSize.x > 0 && m_width  > maxSize.x) m_width  = maxSize.x;
+        if (maxSize.y > 0 && m_height > maxSize.y) m_height = maxSize.y;
+    }
+}
+
+void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
+{
+    wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+    wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
+
+    if (m_resizing) return; /* I don't like recursions */
+    m_resizing = true;
+
+    int currentX, currentY;
+    GetPosition(&currentX, &currentY);
+    if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+        x = currentX;
+    if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+        y = currentY;
+    AdjustForParentClientOrigin(x, y, sizeFlags);
+
+    // calculate the best size if we should auto size the window
+    if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
+         ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
+    {
+        const wxSize sizeBest = GetBestSize();
+        if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
+            width = sizeBest.x;
+        if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
+            height = sizeBest.y;
+    }
+
+    if (width != -1)
+        m_width = width;
+    if (height != -1)
+        m_height = height;
+
+    ConstrainSize();
+
+#if wxUSE_TOOLBAR_NATIVE
+    if (wxDynamicCast(GetParent(), wxToolBar))
+    {
+       // don't take the x,y values, they're wrong because toolbar sets them
+       GtkWidget  *widget = m_widget;
+       gtk_widget_set_size_request (widget, m_width, m_height);
+    }
+    else
+#endif
+    if (m_parent->m_wxwindow == NULL) // i.e. wxNotebook
+    {
+        // don't set the size for children of wxNotebook, just take the values.
+        m_x = x;
+        m_y = y;
+        m_width = width;
+        m_height = height;
+    }
+    else
+    {
+        GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
+        if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
+        {
+            if (x != -1) m_x = x + gtk_pizza_get_xoffset( pizza );
+            if (y != -1) m_y = y + gtk_pizza_get_yoffset( pizza );
+        }
+        else
+        {
+            m_x = x + gtk_pizza_get_xoffset( pizza );
+            m_y = y + gtk_pizza_get_yoffset( pizza );
+        }
+
+        int left_border = 0;
+        int right_border = 0;
+        int top_border = 0;
+        int bottom_border = 0;
+
+        /* the default button has a border around it */
+        if (GTK_WIDGET_CAN_DEFAULT(m_widget))
+        {
+            GtkBorder *default_border = NULL;
+            gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
+            if (default_border)
+            {
+                left_border += default_border->left;
+                right_border += default_border->right;
+                top_border += default_border->top;
+                bottom_border += default_border->bottom;
+                g_free( default_border );
+            }
+        }
+
+        DoMoveWindow( m_x-top_border,
+                      m_y-left_border,
+                      m_width+left_border+right_border,
+                      m_height+top_border+bottom_border );
+    }
+
+    if (m_hasScrolling)
+    {
+        /* Sometimes the client area changes size without the
+           whole windows's size changing, but if the whole
+           windows's size doesn't change, no wxSizeEvent will
+           normally be sent. Here we add an extra test if
+           the client test has been changed and this will
+           be used then. */
+        GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
+    }
+
+/*
+    wxPrintf( "OnSize sent from " );
+    if (GetClassInfo() && GetClassInfo()->GetClassName())
+        wxPrintf( GetClassInfo()->GetClassName() );
+    wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
+*/
+
+    if (!m_nativeSizeEvent)
+    {
+        wxSizeEvent event( wxSize(m_width,m_height), GetId() );
+        event.SetEventObject( this );
+        GetEventHandler()->ProcessEvent( event );
+    }
+
+    m_resizing = false;
+}
+
+bool wxWindowGTK::GtkShowFromOnIdle()
+{
+    if (IsShown() && m_showOnIdle && !GTK_WIDGET_VISIBLE (m_widget))
+    {
+        GtkAllocation alloc;
+        alloc.x = m_x;
+        alloc.y = m_y;
+        alloc.width = m_width;
+        alloc.height = m_height;
+        gtk_widget_size_allocate( m_widget, &alloc );
+        gtk_widget_show( m_widget );
+        wxShowEvent eventShow(GetId(), true);
+        eventShow.SetEventObject(this);
+        GetEventHandler()->ProcessEvent(eventShow);
+        m_showOnIdle = false;
+        return true;
+    }
+
+    return false;
+}
+
+void wxWindowGTK::OnInternalIdle()
+{
+    // Check if we have to show window now
+    if (GtkShowFromOnIdle()) return;
+
+    if ( m_dirtyTabOrder )
+    {
+        m_dirtyTabOrder = false;
+        RealizeTabOrder();
+    }
+
+    // Update style if the window was not yet realized
+    // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
+    if (m_needsStyleChange)
+    {
+        SetBackgroundStyle(GetBackgroundStyle());
+        m_needsStyleChange = false;
+    }
+
+    wxCursor cursor = m_cursor;
+    if (g_globalCursor.Ok()) cursor = g_globalCursor;
+
+    if (cursor.Ok())
+    {
+        /* I now set the cursor anew in every OnInternalIdle call
+           as setting the cursor in a parent window also effects the
+           windows above so that checking for the current cursor is
+           not possible. */
+
+        if (m_wxwindow && (m_wxwindow != m_widget))
+        {
+            GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
+            if (window)
+                gdk_window_set_cursor( window, cursor.GetCursor() );
+
+            if (!g_globalCursor.Ok())
+                cursor = *wxSTANDARD_CURSOR;
+
+            window = m_widget->window;
+            if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
+                gdk_window_set_cursor( window, cursor.GetCursor() );
+
+        }
+        else if ( m_widget )
+        {
+            GdkWindow *window = m_widget->window;
+            if ( window && !GTK_WIDGET_NO_WINDOW(m_widget) )
+               gdk_window_set_cursor( window, cursor.GetCursor() );
+        }
+    }
+
+    if (wxUpdateUIEvent::CanUpdate(this))
+        UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+}
+
+void wxWindowGTK::DoGetSize( int *width, int *height ) const
+{
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+    if (width) (*width) = m_width;
+    if (height) (*height) = m_height;
+}
+
+void wxWindowGTK::DoSetClientSize( int width, int height )
+{
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+    if (m_wxwindow)
+    {
+        int dw = 0;
+        int dh = 0;
+
+        if (m_hasScrolling)
+        {
+            GetScrollbarWidth(m_widget, dw, dh);
+        }
+
+        const int border = GTK_CONTAINER(m_wxwindow)->border_width;
+        dw += 2 * border;
+        dh += 2 * border;
+
+        width += dw;
+        height += dh;
+    }
+
+    SetSize(width, height);
+}
+
+void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
+{
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+    int w = m_width;
+    int h = m_height;
+
+    if (m_wxwindow)
+    {
+        int dw = 0;
+        int dh = 0;
+
+        if (m_hasScrolling)
+            GetScrollbarWidth(m_widget, dw, dh);
+
+        const int border = GTK_CONTAINER(m_wxwindow)->border_width;
+        dw += 2 * border;
+        dh += 2 * border;
+
+        w -= dw;
+        h -= dh;
+        if (w < 0)
+            w = 0;
+        if (h < 0)
+            h = 0;
+    }
+
+    if (width) *width = w;
+    if (height) *height = h;
+}
+
+void wxWindowGTK::DoGetPosition( int *x, int *y ) const
+{
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+    int dx = 0;
+    int dy = 0;
+    if (m_parent && m_parent->m_wxwindow)
+    {
+        GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
+        dx = gtk_pizza_get_xoffset( pizza );
+        dy = gtk_pizza_get_yoffset( pizza );
+    }
+
+    if (m_x == -1 && m_y == -1)
+    {
+        GdkWindow *source = (GdkWindow *) NULL;
+        if (m_wxwindow)
+            source = GTK_PIZZA(m_wxwindow)->bin_window;
+        else
+            source = m_widget->window;
+
+        if (source)
+        {
+            int org_x = 0;
+            int org_y = 0;
+            gdk_window_get_origin( source, &org_x, &org_y );
+
+            if (m_parent)
+                m_parent->ScreenToClient(&org_x, &org_y);
+
+            wx_const_cast(wxWindowGTK*, this)->m_x = org_x;
+            wx_const_cast(wxWindowGTK*, this)->m_y = org_y;
+        }
+    }
+
+    if (x) (*x) = m_x - dx;
+    if (y) (*y) = m_y - dy;
+}
+
+void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
+{
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+    if (!m_widget->window) return;
+
+    GdkWindow *source = (GdkWindow *) NULL;
+    if (m_wxwindow)
+        source = GTK_PIZZA(m_wxwindow)->bin_window;
+    else
+        source = m_widget->window;
+
+    int org_x = 0;
+    int org_y = 0;
+    gdk_window_get_origin( source, &org_x, &org_y );
+
+    if (!m_wxwindow)
+    {
+        if (GTK_WIDGET_NO_WINDOW (m_widget))
+        {
+            org_x += m_widget->allocation.x;
+            org_y += m_widget->allocation.y;
+        }
+    }
+
+
+    if (x)
+    {
+        if (GetLayoutDirection() == wxLayout_RightToLeft)
+            *x = (GetClientSize().x - *x) + org_x;
+        else
+            *x += org_x;
+    }
+
+    if (y) *y += org_y;
+}
+
+void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
+{
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+    if (!m_widget->window) return;
+
+    GdkWindow *source = (GdkWindow *) NULL;
+    if (m_wxwindow)
+        source = GTK_PIZZA(m_wxwindow)->bin_window;
+    else
+        source = m_widget->window;
+
+    int org_x = 0;
+    int org_y = 0;
+    gdk_window_get_origin( source, &org_x, &org_y );
+
+    if (!m_wxwindow)
+    {
+        if (GTK_WIDGET_NO_WINDOW (m_widget))
+        {
+            org_x += m_widget->allocation.x;
+            org_y += m_widget->allocation.y;
+        }
+    }
+
+    if (x)
+    {
+        if (GetLayoutDirection() == wxLayout_RightToLeft)
+            *x = (GetClientSize().x - *x) - org_x;
+        else
+            *x -= org_x;
+    }
+    if (y) *y -= org_y;
+}
+
+bool wxWindowGTK::Show( bool show )
+{
+    wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
+
+    if (!wxWindowBase::Show(show))
+    {
+        // nothing to do
+        return false;
+    }
+
+    if (show)
+    {
+        if (!m_showOnIdle)
+        {
+            gtk_widget_show( m_widget );
+            wxShowEvent eventShow(GetId(), show);
+            eventShow.SetEventObject(this);
+            GetEventHandler()->ProcessEvent(eventShow);
+        }
+    }
+    else
+    {
+        gtk_widget_hide( m_widget );
+        wxShowEvent eventShow(GetId(), show);
+        eventShow.SetEventObject(this);
+        GetEventHandler()->ProcessEvent(eventShow);
+    }
+
+    return true;
+}
+
+void wxWindowGTK::DoEnable( bool enable )
+{
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+    gtk_widget_set_sensitive( m_widget, enable );
+    if (m_wxwindow && (m_wxwindow != m_widget))
+        gtk_widget_set_sensitive( m_wxwindow, enable );
+}
+
+int wxWindowGTK::GetCharHeight() const
+{
+    wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
+
+    wxFont font = GetFont();
+    wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
+
+    PangoContext *context = NULL;
+    if (m_widget)
+        context = gtk_widget_get_pango_context( m_widget );
+
+    if (!context)
+        return 0;
+
+    PangoFontDescription *desc = font.GetNativeFontInfo()->description;
+    PangoLayout *layout = pango_layout_new(context);
+    pango_layout_set_font_description(layout, desc);
+    pango_layout_set_text(layout, "H", 1);
+    PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
+    PangoRectangle rect;
+    pango_layout_line_get_extents(line, NULL, &rect);
+
+    g_object_unref (layout);
+
+    return (int) PANGO_PIXELS(rect.height);
+}
+
+int wxWindowGTK::GetCharWidth() const
+{
+    wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
+
+    wxFont font = GetFont();
+    wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
+
+    PangoContext *context = NULL;
+    if (m_widget)
+        context = gtk_widget_get_pango_context( m_widget );
+
+    if (!context)
+        return 0;
+
+    PangoFontDescription *desc = font.GetNativeFontInfo()->description;
+    PangoLayout *layout = pango_layout_new(context);
+    pango_layout_set_font_description(layout, desc);
+    pango_layout_set_text(layout, "g", 1);
+    PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
+    PangoRectangle rect;
+    pango_layout_line_get_extents(line, NULL, &rect);
+
+    g_object_unref (layout);
+
+    return (int) PANGO_PIXELS(rect.width);
+}
+
+void wxWindowGTK::GetTextExtent( const wxString& string,
+                                 int *x,
+                                 int *y,
+                                 int *descent,
+                                 int *externalLeading,
+                                 const wxFont *theFont ) const
+{
+    wxFont fontToUse = theFont ? *theFont : GetFont();
+
+    wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
+
+    if (string.empty())
+    {
+        if (x) (*x) = 0;
+        if (y) (*y) = 0;
+        return;
+    }
+
+    PangoContext *context = NULL;
+    if (m_widget)
+        context = gtk_widget_get_pango_context( m_widget );
+
+    if (!context)
+    {
+        if (x) (*x) = 0;
+        if (y) (*y) = 0;
+        return;
+    }
+
+    PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
+    PangoLayout *layout = pango_layout_new(context);
+    pango_layout_set_font_description(layout, desc);
+    {
+        const wxCharBuffer data = wxGTK_CONV( string );
+        if ( data )
+            pango_layout_set_text(layout, data, strlen(data));
+    }
+
+    PangoRectangle rect;
+    pango_layout_get_extents(layout, NULL, &rect);
+
+    if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
+    if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
+    if (descent)
+    {
+        PangoLayoutIter *iter = pango_layout_get_iter(layout);
+        int baseline = pango_layout_iter_get_baseline(iter);
+        pango_layout_iter_free(iter);
+        *descent = *y - PANGO_PIXELS(baseline);
+    }
+    if (externalLeading) (*externalLeading) = 0;  // ??
+
+    g_object_unref (layout);
+}
+
+bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
+{
+    if ( g_delayedFocus == this )
+    {
+        if ( GTK_WIDGET_REALIZED(m_widget) )
+        {
+            gtk_widget_grab_focus(m_widget);
+            g_delayedFocus = NULL;
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void wxWindowGTK::SetFocus()
+{
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+    if ( m_hasFocus )
+    {
+        // don't do anything if we already have focus
+        return;
+    }
+
+    if (m_wxwindow)
+    {
+        if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
+        {
+            gtk_widget_grab_focus (m_wxwindow);
+        }
+    }
+    else if (m_widget)
+    {
+        if (GTK_IS_CONTAINER(m_widget))
+        {
+            if (IsKindOf(CLASSINFO(wxRadioButton)))
+            {
+                gtk_widget_grab_focus (m_widget);
+                return;
+            }
+
+            gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
+        }
+        else
+        if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
+        {
+
+            if (!GTK_WIDGET_REALIZED(m_widget))
+            {
+                // we can't set the focus to the widget now so we remember that
+                // it should be focused and will do it later, during the idle
+                // time, as soon as we can
+                wxLogTrace(TRACE_FOCUS,
+                           _T("Delaying setting focus to %s(%s)"),
+                           GetClassInfo()->GetClassName(), GetLabel().c_str());
+
+                g_delayedFocus = this;
+            }
+            else
+            {
+                wxLogTrace(TRACE_FOCUS,
+                           _T("Setting focus to %s(%s)"),
+                           GetClassInfo()->GetClassName(), GetLabel().c_str());
+
+                gtk_widget_grab_focus (m_widget);
+            }
+        }
+        else
+        {
+           wxLogTrace(TRACE_FOCUS,
+                      _T("Can't set focus to %s(%s)"),
+                      GetClassInfo()->GetClassName(), GetLabel().c_str());
+        }
+    }
+}
+
+void wxWindowGTK::SetCanFocus(bool canFocus)
+{
+    if ( canFocus )
+        GTK_WIDGET_SET_FLAGS(m_widget, GTK_CAN_FOCUS);
+    else
+        GTK_WIDGET_UNSET_FLAGS(m_widget, GTK_CAN_FOCUS);
+
+    if ( m_wxwindow && (m_widget != m_wxwindow) )
+    {
+        if ( canFocus )
+            GTK_WIDGET_SET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
+        else
+            GTK_WIDGET_UNSET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
+    }
+}
+
+bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
 {
-  if (g_blockEventsOnDrag) return TRUE;
-  if (win->m_wxwindow)
-  {
-    if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
-      GTK_WIDGET_UNSET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
-  }
-  
-  if (!win->HasVMT()) return TRUE;
-  
-/*
-  printf( "OnKillFocus from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
-  
-  wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
-  event.SetEventObject( win );
-  
-  if (win->GetEventHandler()->ProcessEvent( event ))
-    gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
+    wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
 
-  return TRUE;
-}
+    wxWindowGTK *oldParent = m_parent,
+             *newParent = (wxWindowGTK *)newParentBase;
 
-//-----------------------------------------------------------------------------
-// "value_changed" from m_vAdjust
-//-----------------------------------------------------------------------------
+    wxASSERT( GTK_IS_WIDGET(m_widget) );
 
-static void gtk_window_vscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
-{
-  if (g_blockEventsOnDrag) return;
+    if ( !wxWindowBase::Reparent(newParent) )
+        return false;
 
-/*
-  printf( "OnVScroll from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
-  
-  if (!win->HasVMT()) return;
-  
-  float diff = win->m_vAdjust->value - win->m_oldVerticalPos;
-  if (fabs(diff) < 0.2) return;
-  
-  wxEventType command = wxEVT_NULL;
-  
-  float line_step = win->m_vAdjust->step_increment;
-  float page_step = win->m_vAdjust->page_increment;
-  
-  if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLL_LINEDOWN;
-  else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLL_LINEUP;
-  else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLL_PAGEDOWN;
-  else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLL_PAGEUP;
-  else command = wxEVT_SCROLL_THUMBTRACK;
-      
-  int value = (int)(win->m_vAdjust->value+0.5);
-
-  wxScrollEvent event( command, win->GetId(), value, wxVERTICAL );
-  event.SetEventObject( win );
-  win->GetEventHandler()->ProcessEvent( event );
-}
+    wxASSERT( GTK_IS_WIDGET(m_widget) );
 
-//-----------------------------------------------------------------------------
-// "value_changed" from m_hAdjust
-//-----------------------------------------------------------------------------
+    /* prevent GTK from deleting the widget arbitrarily */
+    gtk_widget_ref( m_widget );
 
-static void gtk_window_hscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
-{ 
-  if (g_blockEventsOnDrag) return;
-  
-/*
-  printf( "OnHScroll from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
-  
-  if (!win->HasVMT()) return;
-    
-  float diff = win->m_hAdjust->value - win->m_oldHorizontalPos;
-  if (fabs(diff) < 0.2) return;
-  
-  wxEventType command = wxEVT_NULL;
-  
-  float line_step = win->m_hAdjust->step_increment;
-  float page_step = win->m_hAdjust->page_increment;
-  
-  if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLL_LINEDOWN;
-  else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLL_LINEUP;
-  else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLL_PAGEDOWN;
-  else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLL_PAGEUP;
-  else command = wxEVT_SCROLL_THUMBTRACK;
-
-  int value = (int)(win->m_hAdjust->value+0.5);
-      
-  wxScrollEvent event( command, win->GetId(), value, wxHORIZONTAL );
-  event.SetEventObject( win );
-  win->GetEventHandler()->ProcessEvent( event );
-}
+    if (oldParent)
+    {
+        gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
+    }
 
-//-----------------------------------------------------------------------------
-// "changed" from m_vAdjust
-//-----------------------------------------------------------------------------
+    wxASSERT( GTK_IS_WIDGET(m_widget) );
 
-static void gtk_window_vscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
-{
-  if (g_blockEventsOnDrag) return;
+    if (newParent)
+    {
+        if (GTK_WIDGET_VISIBLE (newParent->m_widget))
+        {
+            m_showOnIdle = true;
+            gtk_widget_hide( m_widget );
+        }
 
-/*
-  printf( "OnVScroll change from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
-  
-  if (!win->HasVMT()) return;
-  
-  wxEventType command = wxEVT_SCROLL_THUMBTRACK;
-  int value = (int)(win->m_vAdjust->value+0.5);
+        /* insert GTK representation */
+        (*(newParent->m_insertCallback))(newParent, this);
+    }
 
-  wxScrollEvent event( command, win->GetId(), value, wxVERTICAL );
-  event.SetEventObject( win );
-  win->GetEventHandler()->ProcessEvent( event );
-}
+    /* reverse: prevent GTK from deleting the widget arbitrarily */
+    gtk_widget_unref( m_widget );
 
-//-----------------------------------------------------------------------------
-// "changed" from m_hAdjust
-//-----------------------------------------------------------------------------
+    SetLayoutDirection(wxLayout_Default);
 
-static void gtk_window_hscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
-{ 
-  if (g_blockEventsOnDrag) return;
-  
-/*
-  printf( "OnHScroll change from " );
-  if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-    printf( win->GetClassInfo()->GetClassName() );
-  printf( ".\n" );
-*/
-  
-  if (!win->HasVMT()) return;
-    
-  wxEventType command = wxEVT_SCROLL_THUMBTRACK;
-  int value = (int)(win->m_hAdjust->value+0.5);
-      
-  wxScrollEvent event( command, win->GetId(), value, wxHORIZONTAL );
-  event.SetEventObject( win );
-  win->GetEventHandler()->ProcessEvent( event );
+    return true;
 }
 
-//-----------------------------------------------------------------------------
-// "drop_data_available_event"
-//-----------------------------------------------------------------------------
-
-static void gtk_window_drop_callback( GtkWidget *widget, GdkEvent *event, wxWindow *win )
+void wxWindowGTK::DoAddChild(wxWindowGTK *child)
 {
-  if (!win->HasVMT()) return;
-  
-  if (win->GetDropTarget())
-  {
-    int x = 0;
-    int y = 0;
-    gdk_window_get_pointer( widget->window, &x, &y, (GdkModifierType *) NULL );
-    win->GetDropTarget()->Drop( event, x, y );
-  }
-  
-/*
-  g_free (event->dropdataavailable.data);
-  g_free (event->dropdataavailable.data_type);
-*/
-}
+    wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
 
-//-----------------------------------------------------------------------------
-// "enter_notify_event"
-//-----------------------------------------------------------------------------
+    wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
 
-static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
-{
-  if (widget->window != gdk_event->window) return TRUE;
-  if (g_blockEventsOnDrag) return TRUE;
-  if (!win->HasVMT()) return TRUE;
-  
-  if (widget->window)
-    gdk_window_set_cursor( widget->window, win->m_cursor->GetCursor() );
-    
-  wxMouseEvent event( wxEVT_ENTER_WINDOW );
-  event.SetEventObject( win );
-  return win->GetEventHandler()->ProcessEvent( event );
+    wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
+
+    /* add to list */
+    AddChild( child );
+
+    /* insert GTK representation */
+    (*m_insertCallback)(this, child);
 }
-    
-//-----------------------------------------------------------------------------
-// "leave_notify_event"
-//-----------------------------------------------------------------------------
 
-static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
+void wxWindowGTK::AddChild(wxWindowBase *child)
 {
-  if (widget->window != gdk_event->window) return TRUE;
-  if (!win->HasVMT()) return TRUE;
-  if (g_blockEventsOnDrag) return TRUE;
-  
-  if (widget->window)
-    gdk_window_set_cursor( widget->window, wxSTANDARD_CURSOR->GetCursor() );
-    
-  wxMouseEvent event( wxEVT_LEAVE_WINDOW );
-  event.SetEventObject( win );
-  return win->GetEventHandler()->ProcessEvent( event );
+    wxWindowBase::AddChild(child);
+    m_dirtyTabOrder = true;
+    wxTheApp->WakeUpIdle();
 }
-    
-//-----------------------------------------------------------------------------
-// wxWindow
-//-----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxWindow,wxEvtHandler)
-
-BEGIN_EVENT_TABLE(wxWindow, wxEvtHandler)
-  EVT_SIZE(wxWindow::OnSize)
-  EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged)
-  EVT_INIT_DIALOG(wxWindow::OnInitDialog)
-  EVT_IDLE(wxWindow::OnIdle)
-END_EVENT_TABLE()
-
-wxWindow::wxWindow()
-{
-  m_widget = (GtkWidget *) NULL;
-  m_wxwindow = (GtkWidget *) NULL;
-  m_parent = (wxWindow *) NULL;
-  m_children.DeleteContents( FALSE );
-  m_x = 0;
-  m_y = 0;
-  m_width = 0;
-  m_height = 0;
-  m_minWidth = -1;
-  m_minHeight = -1;
-  m_maxWidth = -1;
-  m_maxHeight = -1;
-  m_retCode = 0;
-  m_eventHandler = this;
-  m_windowValidator = (wxValidator *) NULL;
-  m_windowId = -1;
-  m_cursor = new wxCursor( wxCURSOR_ARROW );
-  m_font = *wxSWISS_FONT;
-  m_windowStyle = 0;
-  m_windowName = "noname";
-  m_constraints = (wxLayoutConstraints *) NULL;
-  m_constraintsInvolvedIn = (wxList *) NULL;
-  m_windowSizer = (wxSizer *) NULL;
-  m_sizerParent = (wxWindow *) NULL;
-  m_autoLayout = FALSE;
-  m_sizeSet = FALSE;
-  m_hasVMT = FALSE;
-  m_needParent = TRUE;
-  m_hasScrolling = FALSE;
-  m_hAdjust = (GtkAdjustment *) NULL;
-  m_vAdjust = (GtkAdjustment *) NULL;
-  m_oldHorizontalPos = 0.0;
-  m_oldVerticalPos = 0.0;
-  m_isShown = FALSE;
-  m_isEnabled = TRUE;
-  m_pDropTarget = (wxDropTarget *) NULL;
-  m_resizing = FALSE;
-}
-
-bool wxWindow::Create( wxWindow *parent, wxWindowID id,
-      const wxPoint &pos, const wxSize &size,
-      long style, const wxString &name  )
-{
-  m_isShown = FALSE;
-  m_isEnabled = TRUE;
-  m_needParent = TRUE;
-  
-  m_cursor = (wxCursor *) NULL;
-  
-  PreCreation( parent, id, pos, size, style, name );
-  
-  m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
-  m_hasScrolling = TRUE;
-  
-  GtkScrolledWindow *s_window;
-  s_window = GTK_SCROLLED_WINDOW(m_widget);
-  
-  GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
-  scroll_class->scrollbar_spacing = 0;
-  
-  gtk_scrolled_window_set_policy( s_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
-    
-  m_oldHorizontalPos = 0.0;
-  m_oldVerticalPos = 0.0;
-  m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(s_window->hscrollbar) );
-  m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(s_window->vscrollbar) );
-  
-  gtk_signal_connect (GTK_OBJECT (m_hAdjust), "value_changed",
-          (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
-  gtk_signal_connect (GTK_OBJECT (m_vAdjust), "value_changed",
-          (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
-          
-  gtk_signal_connect (GTK_OBJECT (m_hAdjust), "changed",
-          (GtkSignalFunc) gtk_window_hscroll_change_callback, (gpointer) this );
-  gtk_signal_connect (GTK_OBJECT (m_vAdjust), "changed",
-          (GtkSignalFunc) gtk_window_vscroll_change_callback, (gpointer) this );
-  
-  GtkViewport *viewport;
-  viewport = GTK_VIEWPORT(s_window->viewport);
-  
-  if (m_windowStyle & wxRAISED_BORDER)
-  {
-    gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
-  }
-  else if (m_windowStyle & wxSUNKEN_BORDER)
-  {
-    gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
-  }
-  else
-  {
-    gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
-  }
-    
-  m_wxwindow = gtk_myfixed_new();
-  
-  if (m_wxwindow) GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
-    
-  if (m_windowStyle & wxTAB_TRAVERSAL == wxTAB_TRAVERSAL)
-    GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
-  else
-    GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
-
-  gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
-
-  // 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) );
-  
-  // I _really_ don't want scrollbars in the beginning    
-  m_vAdjust->lower = 0.0;
-  m_vAdjust->upper = 1.0;
-  m_vAdjust->value = 0.0;
-  m_vAdjust->step_increment = 1.0;
-  m_vAdjust->page_increment = 1.0;
-  m_vAdjust->page_size = 5.0;
-  gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
-  m_hAdjust->lower = 0.0;
-  m_hAdjust->upper = 1.0;
-  m_hAdjust->value = 0.0;
-  m_hAdjust->step_increment = 1.0;
-  m_hAdjust->page_increment = 1.0;
-  m_hAdjust->page_size = 5.0;
-  gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
-  
-  gtk_widget_show( m_wxwindow );
-  
-  PostCreation();
-  
-  Show( TRUE );
-
-  return TRUE;  
-}
-
-wxWindow::~wxWindow(void)
-{
-  m_hasVMT = FALSE;
-  
-  if (m_pDropTarget) delete m_pDropTarget;
-  
-  if (m_parent) m_parent->RemoveChild( this );
-  if (m_widget) Show( FALSE );
-
-  DestroyChildren();
-  
-  if (m_wxwindow) gtk_widget_destroy( m_wxwindow );
-    
-  if (m_widget) gtk_widget_destroy( m_widget );
-  
-  wxDELETE(m_cursor);
-
-  DeleteRelatedConstraints();
-  if (m_constraints)
-  {
-    // This removes any dangling pointers to this window
-    // in other windows' constraintsInvolvedIn lists.
-    UnsetConstraints(m_constraints);
-    delete m_constraints;
-    m_constraints = (wxLayoutConstraints *) NULL;
-  }
-  if (m_windowSizer)
-  {
-    delete m_windowSizer;
-    m_windowSizer = (wxSizer *) NULL;
-  }
-  // If this is a child of a sizer, remove self from parent
-  if (m_sizerParent) m_sizerParent->RemoveChild((wxWindow *)this);
-
-  // Just in case the window has been Closed, but
-  // we're then deleting immediately: don't leave
-  // dangling pointers.
-  wxPendingDelete.DeleteObject(this);
-
-  // Just in case we've loaded a top-level window via
-  // wxWindow::LoadNativeDialog but we weren't a dialog
-  // class
-  wxTopLevelWindows.DeleteObject(this);
-    
-  if (m_windowValidator) delete m_windowValidator;
-}
-
-void wxWindow::PreCreation( wxWindow *parent, wxWindowID id,
-      const wxPoint &pos, const wxSize &size,
-      long style, const wxString &name )
-{
-  if (m_needParent && (parent == NULL))
-    wxFatalError( "Need complete parent.", name );
-
-  m_widget = (GtkWidget *) NULL;
-  m_hasVMT = FALSE;
-  m_parent = parent;
-  m_children.DeleteContents( FALSE );
-  m_x = (int)pos.x;
-  m_y = (int)pos.y;
-  m_width = size.x;
-  if (m_width == -1) m_width = 20;
-  m_height = size.y;
-  if (m_height == -1) m_height = 20;
-  m_minWidth = -1;
-  m_minHeight = -1;
-  m_maxWidth = -1;
-  m_maxHeight = -1;
-  m_retCode = 0;
-  m_eventHandler = this;
-  m_windowId = id;
-  m_sizeSet = FALSE;
-  if (m_cursor == NULL)
-    m_cursor = new wxCursor( wxCURSOR_ARROW );
-  m_font = *wxSWISS_FONT;
-  m_backgroundColour = wxWHITE;
-  m_foregroundColour = wxBLACK;
-  m_windowStyle = style;
-  m_windowName = name;
-  m_constraints = (wxLayoutConstraints *) NULL;
-  m_constraintsInvolvedIn = (wxList *) NULL;
-  m_windowSizer = (wxSizer *) NULL;
-  m_sizerParent = (wxWindow *) NULL;
-  m_autoLayout = FALSE;
-  m_pDropTarget = (wxDropTarget *) NULL;
-  m_resizing = FALSE;
-  m_windowValidator = (wxValidator *) NULL;
-}
-
-void wxWindow::PostCreation(void)
-{
-  if (m_parent) m_parent->AddChild( this );
-  
-//  GtkStyle *style = m_widget->style;
-//  style->font = m_font.GetInternalFont( 1.0 );          // destroy old font ?
-  
-  GtkWidget *connect_widget = GetConnectWidget();
-  if (m_wxwindow)
-  {
-    gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event", 
-      GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
-      
-    gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw", 
-      GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
-  }
-  
-  gtk_signal_connect( GTK_OBJECT(connect_widget), "key_press_event",
-    GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
-
-  gtk_signal_connect( GTK_OBJECT(connect_widget), "button_press_event",
-    GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
-    
-  gtk_signal_connect( GTK_OBJECT(connect_widget), "button_release_event",
-    GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
-    
-  gtk_signal_connect( GTK_OBJECT(connect_widget), "motion_notify_event",
-    GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
-    
-  gtk_signal_connect( GTK_OBJECT(connect_widget), "focus_in_event", 
-    GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
-
-  gtk_signal_connect( GTK_OBJECT(connect_widget), "focus_out_event", 
-    GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
-
-  // Only for cursor handling
-    
-  gtk_signal_connect( GTK_OBJECT(m_widget), "enter_notify_event", 
-    GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
-    
-  gtk_signal_connect( GTK_OBJECT(m_widget), "leave_notify_event", 
-    GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
-    
-  if (m_wxwindow)
-  {
-    gtk_signal_connect( GTK_OBJECT(m_wxwindow), "enter_notify_event", 
-      GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
-      
-    gtk_signal_connect( GTK_OBJECT(m_wxwindow), "leave_notify_event", 
-      GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
-  }
-  
-  if (m_widget && m_parent) gtk_widget_realize( m_widget );
-  
-  if (m_wxwindow)
-  {
-    gtk_widget_realize( m_wxwindow );
-    gdk_gc_set_exposures( m_wxwindow->style->fg_gc[0], TRUE );
-  }
-  
-  SetCursor( wxSTANDARD_CURSOR );
-  
-  m_hasVMT = TRUE;
+void wxWindowGTK::RemoveChild(wxWindowBase *child)
+{
+    wxWindowBase::RemoveChild(child);
+    m_dirtyTabOrder = true;
+    wxTheApp->WakeUpIdle();
 }
 
-bool wxWindow::HasVMT(void)
+/* static */
+wxLayoutDirection wxWindowGTK::GTKGetLayout(GtkWidget *widget)
 {
-  return m_hasVMT;
+    return gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL
+                ? wxLayout_RightToLeft
+                : wxLayout_LeftToRight;
 }
 
-bool wxWindow::Close( bool force )
+/* static */
+void wxWindowGTK::GTKSetLayout(GtkWidget *widget, wxLayoutDirection dir)
 {
-  wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
-  event.SetEventObject(this);
-  event.SetForce(force);
+    wxASSERT_MSG( dir != wxLayout_Default, _T("invalid layout direction") );
 
-  return GetEventHandler()->ProcessEvent(event);
+    gtk_widget_set_direction(widget,
+                             dir == wxLayout_RightToLeft ? GTK_TEXT_DIR_RTL
+                                                         : GTK_TEXT_DIR_LTR);
 }
 
-bool wxWindow::Destroy(void)
+wxLayoutDirection wxWindowGTK::GetLayoutDirection() const
 {
-  m_hasVMT = FALSE;
-  delete this;
-  return TRUE;
+    return GTKGetLayout(m_widget);
 }
 
-bool wxWindow::DestroyChildren(void)
+void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir)
 {
-  if (GetChildren()) 
-  {
-    wxNode *node;
-    while ((node = GetChildren()->First()) != (wxNode *)NULL) 
+    if ( dir == wxLayout_Default )
     {
-      wxWindow *child;
-      if ((child = (wxWindow *)node->Data()) != (wxWindow *)NULL) 
-      {
-        delete child;
-        if (GetChildren()->Member(child)) delete node;
-      }
+        const wxWindow *const parent = GetParent();
+        if ( parent )
+        {
+            // inherit layout from parent.
+            dir = parent->GetLayoutDirection();
+        }
+        else // no parent, use global default layout
+        {
+            dir = wxTheApp->GetLayoutDirection();
+        }
     }
-  }
-  return TRUE;
-}
-
-void wxWindow::PrepareDC( wxDC &WXUNUSED(dc) )
-{
-  // are we to set fonts here ?
-}
 
-void wxWindow::ImplementSetSize(void)
-{ 
-  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_minWidth;
-  if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_minHeight;
-  gtk_widget_set_usize( m_widget, m_width, m_height );
-}
+    if ( dir == wxLayout_Default )
+        return;
 
-void wxWindow::ImplementSetPosition(void)
-{
-  if (IS_KIND_OF(this,wxFrame) || IS_KIND_OF(this,wxDialog))
-  {
-    if ((m_x != -1) || (m_y != -1))
-      gtk_widget_set_uposition( m_widget, m_x, m_y );
-    return;
-  }
-  
-  if (!m_parent)
-  {
-    wxFAIL_MSG( "wxWindow::SetSize error.\n" );
-    return;
-  }
-  
-  if ((m_parent) && (m_parent->m_wxwindow))
-    gtk_myfixed_move( GTK_MYFIXED(m_parent->m_wxwindow), m_widget, m_x, m_y );
-    
-  // Don't do anything for children of wxNotebook and wxMDIChildFrame   
-}
-
-void wxWindow::SetSize( int x, int y, int width, int height, int sizeFlags )
-{
-  if (m_resizing) return; // I don't like recursions
-  m_resizing = TRUE;
-  
-  int newX = x;
-  int newY = y;
-  int newW = width;
-  int newH = height;
-  
-  if ((sizeFlags & wxSIZE_USE_EXISTING) == wxSIZE_USE_EXISTING)
-  {
-    if (newX == -1) newX = m_x;
-    if (newY == -1) newY = m_y;
-    if (newW == -1) newW = m_width;
-    if (newH == -1) newH = m_height;
-  }
-  
-  if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
-  {
-    if (newW == -1) newW = 80;
-  }
-  
-  if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
-  {
-    if (newH == -1) newH = 26;
-  }
-  
-  if ((m_x != newX) || (m_y != newY) || (!m_sizeSet))
-  {
-    m_x = newX;
-    m_y = newY;
-    ImplementSetPosition();
-  }
-  if ((m_width != newW) || (m_height != newH) || (!m_sizeSet))
-  {
-    m_width = newW;
-    m_height = newH;
-    ImplementSetSize();
-  }
-  m_sizeSet = TRUE;
-  
-  wxSizeEvent event( wxSize(m_width,m_height), GetId() );
-  event.SetEventObject( this );
-  ProcessEvent( event );
-  
-  m_resizing = FALSE;
-}
+    GTKSetLayout(m_widget, dir);
 
-void wxWindow::SetSize( int width, int height )
-{
-  SetSize( -1, -1, width, height, wxSIZE_USE_EXISTING );
+    if (m_wxwindow && (m_wxwindow != m_widget))
+        GTKSetLayout(m_wxwindow, dir);
 }
 
-void wxWindow::Move( int x, int y )
+wxCoord
+wxWindowGTK::AdjustForLayoutDirection(wxCoord x,
+                                      wxCoord WXUNUSED(width),
+                                      wxCoord WXUNUSED(widthTotal)) const
 {
-  SetSize( x, y, -1, -1, wxSIZE_USE_EXISTING );
+    // We now mirrors the coordinates of RTL windows in GtkPizza
+    return x;
 }
 
-void wxWindow::GetSize( int *width, int *height ) const
+void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
 {
-  if (width) (*width) = m_width;
-  if (height) (*height) = m_height;
+    wxWindowBase::DoMoveInTabOrder(win, move);
+    m_dirtyTabOrder = true;
+    wxTheApp->WakeUpIdle();
 }
 
-void wxWindow::SetClientSize( int width, int height )
+bool wxWindowGTK::DoNavigateIn(int flags)
 {
-  if (!m_wxwindow)
-  {
-    SetSize( width, height );
-  }
-  else
-  {
-    int dw = 0;
-    int dh = 0;
-    
-    if (!m_hasScrolling)
+    if ( flags & wxNavigationKeyEvent::WinChange )
     {
-/*
-      do we have sunken dialogs ?
-      
-      GtkStyleClass *window_class = m_wxwindow->style->klass;
-    
-      dw += 2 * window_class->xthickness;
-      dh += 2 * window_class->ythickness;
-*/
+        wxFAIL_MSG( _T("not implemented") );
+
+        return false;
     }
-    else
+    else // navigate inside the container
     {
-      GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
-      GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
-    
-      GtkWidget *viewport = scroll_window->viewport;
-      GtkStyleClass *viewport_class = viewport->style->klass;
-    
-      GtkWidget *hscrollbar = scroll_window->hscrollbar;
-      GtkWidget *vscrollbar = scroll_window->vscrollbar;
-    
-      if ((m_windowStyle & wxRAISED_BORDER) ||
-          (m_windowStyle & wxSUNKEN_BORDER))
-      {
-        dw += 2 * viewport_class->xthickness;
-        dh += 2 * viewport_class->ythickness;
-      }
-    
-      if (GTK_WIDGET_VISIBLE(vscrollbar))
-      {
-        dw += vscrollbar->allocation.width;
-        dw += scroll_class->scrollbar_spacing;
-      }
-    
-      if (GTK_WIDGET_VISIBLE(hscrollbar))
-      {
-        dh += hscrollbar->allocation.height;
-        dw += scroll_class->scrollbar_spacing;
-      }
-    }
-    
-    SetSize( width+dw, height+dh );
-  }
-}
+        wxWindow *parent = wxGetTopLevelParent(this);
+        wxCHECK_MSG( parent, false, _T("every window must have a TLW parent") );
 
-void wxWindow::GetClientSize( int *width, int *height ) const
-{
-  if (!m_wxwindow)
-  {
-    if (width) (*width) = m_width;
-    if (height) (*height) = m_height;
-  }
-  else
-  {
-    int dw = 0;
-    int dh = 0;
-    
-    if (!m_hasScrolling)
-    {
-/*
-      do we have sunken dialogs ?
-      
-      GtkStyleClass *window_class = m_wxwindow->style->klass;
-    
-      dw += 2 * window_class->xthickness;
-      dh += 2 * window_class->ythickness;
-*/
+        GtkDirectionType dir;
+        dir = flags & wxNavigationKeyEvent::IsForward ? GTK_DIR_TAB_FORWARD
+                                                      : GTK_DIR_TAB_BACKWARD;
+
+        gboolean rc;
+        g_signal_emit_by_name(parent->m_widget, "focus", dir, &rc);
+
+        return rc == TRUE;
     }
-    else
-    {
-      GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
-      GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
-    
-      GtkWidget *viewport = scroll_window->viewport;
-      GtkStyleClass *viewport_class = viewport->style->klass;
-    
-      GtkWidget *hscrollbar = scroll_window->hscrollbar;
-      GtkWidget *vscrollbar = scroll_window->vscrollbar;
-    
-      if ((m_windowStyle & wxRAISED_BORDER) ||
-          (m_windowStyle & wxSUNKEN_BORDER))
-      {
-        dw += 2 * viewport_class->xthickness;
-        dh += 2 * viewport_class->ythickness;
-      }
-    
-      if (GTK_WIDGET_VISIBLE(vscrollbar))
-      {
-//        dw += vscrollbar->allocation.width;
-        dw += 15;                               // range.slider_width = 11 + 2*2pts edge
-        dw += scroll_class->scrollbar_spacing;
-      }
-    
-      if (GTK_WIDGET_VISIBLE(hscrollbar))
-      {
-//        dh += hscrollbar->allocation.height;
-        dh += 15;
-        dh += scroll_class->scrollbar_spacing;
-      }
-    }
-    
-    if (width) (*width) = m_width - dw;
-    if (height) (*height) = m_height - dh;
-  }
 }
 
-void wxWindow::GetPosition( int *x, int *y ) const
+bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
 {
-  if (x) (*x) = m_x;
-  if (y) (*y) = m_y;
+    // none needed by default
+    return false;
 }
 
-void wxWindow::ClientToScreen( int *x, int *y )
+void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget* WXUNUSED(w))
 {
-  GdkWindow *source = (GdkWindow *) NULL;
-  if (m_wxwindow)
-    source = m_wxwindow->window;
-  else
-    source = m_widget->window;
-    
-  int org_x = 0;
-  int org_y = 0;
-  gdk_window_get_origin( source, &org_x, &org_y );
+    // nothing to do by default since none is needed
+}
 
-  if (!m_wxwindow)
-  {  
-    if (GTK_WIDGET_NO_WINDOW (m_widget))
+void wxWindowGTK::RealizeTabOrder()
+{
+    if (m_wxwindow)
     {
-      org_x += m_widget->allocation.x;
-      org_y += m_widget->allocation.y;
+        if ( !m_children.empty() )
+        {
+            // we don't only construct the correct focus chain but also use
+            // this opportunity to update the mnemonic widgets for the widgets
+            // that need them
+
+            GList *chain = NULL;
+            wxWindowGTK* mnemonicWindow = NULL;
+
+            for ( wxWindowList::const_iterator i = m_children.begin();
+                  i != m_children.end();
+                  ++i )
+            {
+                wxWindowGTK *win = *i;
+
+                if ( mnemonicWindow )
+                {
+                    if ( win->AcceptsFocusFromKeyboard() )
+                    {
+                        // wxComboBox et al. needs to focus on on a different
+                        // widget than m_widget, so if the main widget isn't
+                        // focusable try the connect widget
+                        GtkWidget* w = win->m_widget;
+                        if ( !GTK_WIDGET_CAN_FOCUS(w) )
+                        {
+                            w = win->GetConnectWidget();
+                            if ( !GTK_WIDGET_CAN_FOCUS(w) )
+                                w = NULL;
+                        }
+
+                        if ( w )
+                        {
+                            mnemonicWindow->GTKWidgetDoSetMnemonic(w);
+                            mnemonicWindow = NULL;
+                        }
+                    }
+                }
+                else if ( win->GTKWidgetNeedsMnemonic() )
+                {
+                    mnemonicWindow = win;
+                }
+
+                chain = g_list_prepend(chain, win->m_widget);
+            }
+
+            chain = g_list_reverse(chain);
+
+            gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
+            g_list_free(chain);
+        }
+        else // no children
+        {
+            gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
+        }
     }
-  }
-  
-  if (x) *x += org_x;  
-  if (y) *y += org_y;  
 }
 
-void wxWindow::ScreenToClient( int *x, int *y )
+void wxWindowGTK::Raise()
 {
-  GdkWindow *source = (GdkWindow *) NULL;
-  if (m_wxwindow)
-    source = m_wxwindow->window;
-  else
-    source = m_widget->window;
-    
-  int org_x = 0;
-  int org_y = 0;
-  gdk_window_get_origin( source, &org_x, &org_y );
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-  if (!m_wxwindow)
-  {  
-    if (GTK_WIDGET_NO_WINDOW (m_widget))
+    if (m_wxwindow && m_wxwindow->window)
     {
-      org_x += m_widget->allocation.x;
-      org_y += m_widget->allocation.y;
+        gdk_window_raise( m_wxwindow->window );
+    }
+    else if (m_widget->window)
+    {
+        gdk_window_raise( m_widget->window );
     }
-  }
-  
-  if (x) *x -= org_x;  
-  if (y) *y -= org_y;  
 }
 
-void wxWindow::Centre( int direction )
+void wxWindowGTK::Lower()
 {
-  if (IS_KIND_OF(this,wxDialog) || IS_KIND_OF(this,wxFrame))
-  {
-    if (direction & wxHORIZONTAL == wxHORIZONTAL) m_x = (gdk_screen_width () - m_width) / 2;
-    if (direction & wxVERTICAL == wxVERTICAL) m_y = (gdk_screen_height () - m_height) / 2;
-    ImplementSetPosition();
-  }
-  else
-  {
-    if (m_parent)
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+    if (m_wxwindow && m_wxwindow->window)
     {
-      int p_w = 0;
-      int p_h = 0;
-      m_parent->GetSize( &p_w, &p_h );
-      if (direction & wxHORIZONTAL == wxHORIZONTAL) m_x = (p_w - m_width) / 2;
-      if (direction & wxVERTICAL == wxVERTICAL) m_y = (p_h - m_height) / 2;
-      ImplementSetPosition();
+        gdk_window_lower( m_wxwindow->window );
+    }
+    else if (m_widget->window)
+    {
+        gdk_window_lower( m_widget->window );
     }
-  }
 }
 
-void wxWindow::Fit(void)
+bool wxWindowGTK::SetCursor( const wxCursor &cursor )
 {
-  int maxX = 0;
-  int maxY = 0;
-  wxNode *node = GetChildren()->First();
-  while ( node )
-  {
-    wxWindow *win = (wxWindow *)node->Data();
-    int wx, wy, ww, wh;
-    win->GetPosition(&wx, &wy);
-    win->GetSize(&ww, &wh);
-    if ( wx + ww > maxX )
-      maxX = wx + ww;
-    if ( wy + wh > maxY )
-      maxY = wy + wh;
-
-    node = node->Next();
-  }
-  SetClientSize(maxX + 5, maxY + 10);
-}
+    if ( !wxWindowBase::SetCursor(cursor.Ok() ? cursor : *wxSTANDARD_CURSOR) )
+        return false;
 
-void wxWindow::SetSizeHints( int minW, int minH, int maxW, int maxH, int WXUNUSED(incW), int WXUNUSED(incH) )
-{
-  m_minWidth = minW;
-  m_minHeight = minH;
-  m_maxWidth = maxW;
-  m_maxHeight = maxH;
-}
+    GTKUpdateCursor();
 
-void wxWindow::OnSize( wxSizeEvent &WXUNUSED(event) )
-{
-  //if (GetAutoLayout()) Layout();
+    return true;
 }
 
-bool wxWindow::Show( bool show )
+void wxWindowGTK::GTKUpdateCursor()
 {
-  if (show)
-    gtk_widget_show( m_widget );
-  else
-    gtk_widget_hide( m_widget );
-  m_isShown = show;  
-  return TRUE;
+    wxCursor cursor(g_globalCursor.Ok() ? g_globalCursor : GetCursor());
+    if ( cursor.Ok() )
+    {
+        wxArrayGdkWindows windowsThis;
+        GdkWindow * const winThis = GTKGetWindow(windowsThis);
+        if ( winThis )
+        {
+            gdk_window_set_cursor(winThis, cursor.GetCursor());
+        }
+        else
+        {
+            const size_t count = windowsThis.size();
+            for ( size_t n = 0; n < count; n++ )
+            {
+                GdkWindow *win = windowsThis[n];
+                if ( !win )
+                {
+                    wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
+                    continue;
+                }
+
+                gdk_window_set_cursor(win, cursor.GetCursor());
+            }
+        }
+    }
 }
 
-void wxWindow::Enable( bool enable )
+void wxWindowGTK::WarpPointer( int x, int y )
 {
-  m_isEnabled = enable;
-  gtk_widget_set_sensitive( m_widget, enable );
-  if (m_wxwindow) gtk_widget_set_sensitive( m_wxwindow, enable );
-}
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-int wxWindow::GetCharHeight(void) const
-{
-  GdkFont *font = m_font.GetInternalFont( 1.0 );
-  return font->ascent + font->descent;
-}
+    // We provide this function ourselves as it is
+    // missing in GDK (top of this file).
 
-int wxWindow::GetCharWidth(void) const
-{
-  GdkFont *font = m_font.GetInternalFont( 1.0 );
-  return gdk_string_width( font, "H" );
+    GdkWindow *window = (GdkWindow*) NULL;
+    if (m_wxwindow)
+        window = GTK_PIZZA(m_wxwindow)->bin_window;
+    else
+        window = GetConnectWidget()->window;
+
+    if (window)
+        gdk_window_warp_pointer( window, x, y );
 }
 
-void wxWindow::GetTextExtent( const wxString& string, int *x, int *y,
-  int *descent, int *externalLeading, const wxFont *theFont, bool WXUNUSED(use16) ) const
+wxWindowGTK::ScrollDir wxWindowGTK::ScrollDirFromRange(GtkRange *range) const
 {
-  wxFont fontToUse = m_font;
-  if (theFont) fontToUse = *theFont;
-  
-  GdkFont *font = fontToUse.GetInternalFont( 1.0 );
-  if (x) (*x) = gdk_string_width( font, string );
-  if (y) (*y) = font->ascent + font->descent;
-  if (descent) (*descent) = font->descent;
-  if (externalLeading) (*externalLeading) = 0;  // ??
+    // find the scrollbar which generated the event
+    for ( int dir = 0; dir < ScrollDir_Max; dir++ )
+    {
+        if ( range == m_scrollBar[dir] )
+            return (ScrollDir)dir;
+    }
+
+    wxFAIL_MSG( _T("event from unknown scrollbar received") );
+
+    return ScrollDir_Max;
 }
 
-void wxWindow::MakeModal( bool modal )
+bool wxWindowGTK::DoScrollByUnits(ScrollDir dir, ScrollUnit unit, int units)
 {
-  return;
-  // Disable all other windows
-  if (this->IsKindOf(CLASSINFO(wxDialog)) || this->IsKindOf(CLASSINFO(wxFrame)))
-  {
-    wxNode *node = wxTopLevelWindows.First();
-    while (node)
+    bool changed = false;
+    GtkRange* range = m_scrollBar[dir];
+    if ( range && units )
     {
-      wxWindow *win = (wxWindow *)node->Data();
-      if (win != this)
-        win->Enable(!modal);
+        GtkAdjustment* adj = range->adjustment;
+        gdouble inc = unit == ScrollUnit_Line ? adj->step_increment
+                                              : adj->page_increment;
 
-      node = node->Next();
+        const int posOld = int(adj->value + 0.5);
+        gtk_range_set_value(range, posOld + units*inc);
+
+        changed = int(adj->value + 0.5) != posOld;
     }
-  }
+
+    return changed;
 }
 
-void wxWindow::SetFocus(void)
+bool wxWindowGTK::ScrollLines(int lines)
 {
-  GtkWidget *connect_widget = GetConnectWidget();
-  if (connect_widget)
-  {
-    if (GTK_WIDGET_CAN_FOCUS(connect_widget) && !GTK_WIDGET_HAS_FOCUS (connect_widget) )
-    {
-      gtk_widget_grab_focus (connect_widget);
-    }
-  }
+    return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Line, lines);
 }
 
-bool wxWindow::OnClose(void)
+bool wxWindowGTK::ScrollPages(int pages)
 {
-  return TRUE;
+    return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Page, pages);
 }
 
-void wxWindow::AddChild( wxWindow *child )
+void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
 {
-  // Addchild is (often) called before the program
-  // has left the parents constructor so that no
-  // virtual tables work yet. The approach below
-  // practically imitates virtual tables, i.e. it
-  // implements a different AddChild() behaviour
-  // for wxFrame, wxDialog, wxWindow and 
-  // wxMDIParentFrame.
+    if (!m_widget)
+        return;
+    if (!m_widget->window)
+        return;
 
-  // wxFrame and wxDialog as children aren't placed into the parents
-  
-  if (( IS_KIND_OF(child,wxFrame) || IS_KIND_OF(child,wxDialog) ) &&
-      (!IS_KIND_OF(child,wxMDIChildFrame)))
-  {
-    m_children.Append( child );
-    
-    if ((child->m_x != -1) && (child->m_y != -1))
-      gtk_widget_set_uposition( child->m_widget, child->m_x, child->m_y );
-      
-    return;
-  }
-  
-  // In the case of an wxMDIChildFrame descendant, we use the 
-  // client windows's AddChild()
-  
-  if (IS_KIND_OF(this,wxMDIParentFrame))
-  {
-    if (IS_KIND_OF(child,wxMDIChildFrame))
+    if (m_wxwindow)
     {
-      wxMDIClientWindow *client = ((wxMDIParentFrame*)this)->GetClientWindow();
-      if (client)
-      { 
-        client->AddChild( child );
-        return;
-      }
-    }
-  }
-  
-  // wxNotebook is very special, so it has a private AddChild()
-  
-  if (IS_KIND_OF(this,wxNotebook))
-  {
-    wxNotebook *tab = (wxNotebook*)this;
-    tab->AddChild( child );
-    return;
-  }
-  
-  // wxFrame has a private AddChild
-  
-  if (IS_KIND_OF(this,wxFrame) && !IS_KIND_OF(this,wxMDIChildFrame))
-  {
-    wxFrame *frame = (wxFrame*)this;
-    frame->AddChild( child );
-    return;
-  }
-  
-  // All the rest
-  
-  m_children.Append( child );
-  if (m_wxwindow) gtk_myfixed_put( GTK_MYFIXED(m_wxwindow), child->m_widget, 
-    child->m_x, child->m_y );
-  
-  gtk_widget_set_usize( child->m_widget, child->m_width, child->m_height );
-}
+        if (!GTK_PIZZA(m_wxwindow)->bin_window) return;
 
-wxList *wxWindow::GetChildren(void)
-{
-  return (&m_children);
-}
+        GdkRectangle gdk_rect,
+                    *p;
+        if (rect)
+        {
+            gdk_rect.x = rect->x;
+            gdk_rect.y = rect->y;
+            gdk_rect.width = rect->width;
+            gdk_rect.height = rect->height;
+            if (GetLayoutDirection() == wxLayout_RightToLeft)
+                gdk_rect.x = GetClientSize().x - gdk_rect.x - gdk_rect.width;
+
+            p = &gdk_rect;
+        }
+        else // invalidate everything
+        {
+            p = NULL;
+        }
 
-void wxWindow::RemoveChild( wxWindow *child )
-{
-  if (GetChildren())
- GetChildren()->DeleteObject( child );
-  child->m_parent = (wxWindow *) NULL;
+        gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, p, TRUE );
+    }
 }
 
-void wxWindow::SetReturnCode( int retCode )
+void wxWindowGTK::Update()
 {
-  m_retCode = retCode;
-}
+    GtkUpdate();
 
-int wxWindow::GetReturnCode(void)
-{
-  return m_retCode;
+    // when we call Update() we really want to update the window immediately on
+    // screen, even if it means flushing the entire queue and hence slowing down
+    // everything -- but it should still be done, it's just that Update() should
+    // be called very rarely
+    gdk_flush();
 }
 
-void wxWindow::Raise(void)
+void wxWindowGTK::GtkUpdate()
 {
-  if (m_widget) gdk_window_raise( m_widget->window );
-}
+    if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
+        gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
+    if (m_widget && m_widget->window && (m_wxwindow != m_widget))
+        gdk_window_process_updates( m_widget->window, FALSE );
 
-void wxWindow::Lower(void)
-{
-  if (m_widget) gdk_window_lower( m_widget->window );
+    // for consistency with other platforms (and also because it's convenient
+    // to be able to update an entire TLW by calling Update() only once), we
+    // should also update all our children here
+    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+          node;
+          node = node->GetNext() )
+    {
+        node->GetData()->GtkUpdate();
+    }
 }
 
-wxEvtHandler *wxWindow::GetEventHandler(void)
+bool wxWindowGTK::DoIsExposed( int x, int y ) const
 {
-  return m_eventHandler;
+    return m_updateRegion.Contains(x, y) != wxOutRegion;
 }
 
-void wxWindow::SetEventHandler( wxEvtHandler *handler )
-{
-  m_eventHandler = handler;
-}
 
-void wxWindow::PushEventHandler(wxEvtHandler *handler)
+bool wxWindowGTK::DoIsExposed( int x, int y, int w, int h ) const
 {
-       handler->SetNextHandler(GetEventHandler());
-       SetEventHandler(handler);
+    if (GetLayoutDirection() == wxLayout_RightToLeft)
+        return m_updateRegion.Contains(x-w, y, w, h) != wxOutRegion;
+    else
+        return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
 }
 
-wxEvtHandler *wxWindow::PopEventHandler(bool deleteHandler)
+void wxWindowGTK::GtkSendPaintEvents()
 {
-       if ( GetEventHandler() )
-       {
-               wxEvtHandler *handlerA = GetEventHandler();
-               wxEvtHandler *handlerB = handlerA->GetNextHandler();
-               handlerA->SetNextHandler((wxEvtHandler *) NULL);
-               SetEventHandler(handlerB);
-               if ( deleteHandler )
-               {
-                       delete handlerA;
-                       return (wxEvtHandler *) NULL;
-               }
-               else
-                       return handlerA;
-       }
-       else
-               return (wxEvtHandler *) NULL;
-}
+    if (!m_wxwindow)
+    {
+        m_updateRegion.Clear();
+        return;
+    }
 
-wxValidator *wxWindow::GetValidator(void)
-{
-  return m_windowValidator;
-}
+    // Clip to paint region in wxClientDC
+    m_clipPaintRegion = true;
 
-void wxWindow::SetValidator( const wxValidator& validator )
-{
-  if (m_windowValidator) delete m_windowValidator;
-  m_windowValidator = validator.Clone();
-  if (m_windowValidator) m_windowValidator->SetWindow(this);
-}
+    m_nativeUpdateRegion = m_updateRegion;
 
-bool wxWindow::IsBeingDeleted(void)
-{
-  return FALSE;
-}
+    if (GetLayoutDirection() == wxLayout_RightToLeft)
+    {
+        // Transform m_updateRegion under RTL
+        m_updateRegion.Clear();
 
-void wxWindow::SetId( wxWindowID id )
-{
-  m_windowId = id;
-}
+        gint width;
+        gdk_window_get_geometry( GTK_PIZZA(m_wxwindow)->bin_window,
+                                 NULL, NULL, &width, NULL, NULL );
 
-wxWindowID wxWindow::GetId(void)
-{
-  return m_windowId;
-}
+        wxRegionIterator upd( m_nativeUpdateRegion );
+        while (upd)
+        {
+            wxRect rect;
+            rect.x = upd.GetX();
+            rect.y = upd.GetY();
+            rect.width = upd.GetWidth();
+            rect.height = upd.GetHeight();
 
-void wxWindow::SetCursor( const wxCursor &cursor )
-{
-  wxASSERT(m_cursor != NULL);
+            rect.x = width - rect.x - rect.width;
+            m_updateRegion.Union( rect );
 
-  if (m_cursor != NULL)
-    if (*m_cursor == cursor)
-      return;
-  (*m_cursor) = cursor;
-  if (m_widget->window)
-    gdk_window_set_cursor( m_widget->window, m_cursor->GetCursor() );
-  if (m_wxwindow && m_wxwindow->window)
-    gdk_window_set_cursor( m_wxwindow->window, m_cursor->GetCursor() );
-}
+            ++upd;
+        }
+    }
 
-void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
-{
-  if (eraseBackground && m_wxwindow && m_wxwindow->window)
-  {
-    if (rect)
-      gdk_window_clear_area( m_wxwindow->window, 
-        rect->x, 
-        rect->y, 
-        rect->width, 
-        rect->height );
-    else
-      Clear(); 
-  }
-  if (!rect)
-  {
-    if (m_wxwindow)
+    // widget to draw on
+    GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
+
+    if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
     {
-      int w = 0;
-      int h = 0;
-      GetClientSize( &w, &h );
-      
-      GdkRectangle gdk_rect;
-      gdk_rect.x = 0;
-      gdk_rect.y = 0;
-      gdk_rect.width = w;
-      gdk_rect.height = h;
-      gtk_widget_draw( m_wxwindow, &gdk_rect );
+        // find ancestor from which to steal background
+        wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
+        if (!parent)
+            parent = (wxWindow*)this;
+
+        if (GTK_WIDGET_MAPPED(parent->m_widget))
+        {
+            wxRegionIterator upd( m_nativeUpdateRegion );
+            while (upd)
+            {
+                GdkRectangle rect;
+                rect.x = upd.GetX();
+                rect.y = upd.GetY();
+                rect.width = upd.GetWidth();
+                rect.height = upd.GetHeight();
+
+                gtk_paint_flat_box( parent->m_widget->style,
+                            pizza->bin_window,
+                            (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
+                            GTK_SHADOW_NONE,
+                            &rect,
+                            parent->m_widget,
+                            (char *)"base",
+                            0, 0, -1, -1 );
+
+                ++upd;
+            }
+        }
     }
-  }
-  else
-  {
-    GdkRectangle gdk_rect;
-    gdk_rect.x = rect->x;
-    gdk_rect.y = rect->y;
-    gdk_rect.width = rect->width;
-    gdk_rect.height = rect->height;
-    
-    if (m_wxwindow)
-      gtk_widget_draw( m_wxwindow, &gdk_rect );
-    else
-      gtk_widget_draw( m_widget, &gdk_rect );
-  }
-}
+    else
+    {
+        wxWindowDC dc( (wxWindow*)this );
+        dc.SetClippingRegion( m_updateRegion );
 
-wxRegion wxWindow::GetUpdateRegion() const
-{
-  return m_updateRegion;
-}
+        wxEraseEvent erase_event( GetId(), &dc );
+        erase_event.SetEventObject( this );
 
-bool wxWindow::IsExposed( int x, int y) const
-{
-  return (m_updateRegion.Contains( x, y ) != wxOutRegion );
-}
+        GetEventHandler()->ProcessEvent(erase_event);
+    }
 
-bool wxWindow::IsExposed( int x, int y, int w, int h ) const
-{
-  return (m_updateRegion.Contains( x, y, w, h ) != wxOutRegion );
-}
+    wxNcPaintEvent nc_paint_event( GetId() );
+    nc_paint_event.SetEventObject( this );
+    GetEventHandler()->ProcessEvent( nc_paint_event );
 
-bool wxWindow::IsExposed( const wxPoint& pt ) const
-{
-  return (m_updateRegion.Contains( pt.x, pt.y ) != wxOutRegion );
-}
+    wxPaintEvent paint_event( GetId() );
+    paint_event.SetEventObject( this );
+    GetEventHandler()->ProcessEvent( paint_event );
 
-bool wxWindow::IsExposed( const wxRect& rect ) const
-{
-  return (m_updateRegion.Contains( rect.x, rect.y, rect.width, rect.height ) != wxOutRegion );
-}
+    m_clipPaintRegion = false;
 
-void wxWindow::Clear(void)
-{
-  if (m_wxwindow && m_wxwindow->window) gdk_window_clear( m_wxwindow->window );
+    m_updateRegion.Clear();
+    m_nativeUpdateRegion.Clear();
 }
 
-wxColour wxWindow::GetBackgroundColour(void) const
+void wxWindowGTK::SetDoubleBuffered( bool on )
 {
-  return m_backgroundColour;
-}
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-void wxWindow::SetBackgroundColour( const wxColour &colour )
-{
-  m_backgroundColour = colour;
-  if (m_wxwindow)
-  {
-    m_backgroundColour.CalcPixel( m_wxwindow->style->colormap );
-    gdk_window_set_background( m_wxwindow->window, m_backgroundColour.GetColor() );
-    gdk_window_clear( m_wxwindow->window );
-  }
-  // do something ?
+    if ( m_wxwindow )
+        gtk_widget_set_double_buffered( m_wxwindow, on );
 }
 
-wxColour wxWindow::GetForegroundColour(void) const
+bool wxWindowGTK::IsDoubleBuffered() const
 {
-  return m_foregroundColour;
+    return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow );
 }
 
-void wxWindow::SetForegroundColour( const wxColour &colour )
+void wxWindowGTK::ClearBackground()
 {
-  m_foregroundColour = colour;
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 }
 
-bool wxWindow::Validate(void)
+#if wxUSE_TOOLTIPS
+void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
 {
-  wxNode *node = GetChildren()->First();
-  while (node)
-  {
-    wxWindow *child = (wxWindow *)node->Data();
-    if (child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->Validate(this)) 
-      { return FALSE; }
-    node = node->Next();
-  }
-  return TRUE;
+    wxWindowBase::DoSetToolTip(tip);
+
+    if (m_tooltip)
+        m_tooltip->Apply( (wxWindow *)this );
 }
 
-bool wxWindow::TransferDataToWindow(void)
+void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
 {
-  wxNode *node = GetChildren()->First();
-  while (node)
-  {
-    wxWindow *child = (wxWindow *)node->Data();
-    if (child->GetValidator() && /* child->GetValidator()->Ok() && */
-  !child->GetValidator()->TransferToWindow() )
+    if (tip)
     {
-      wxMessageBox( _("Application Error"), _("Could not transfer data to window"), wxOK|wxICON_EXCLAMATION );
-      return FALSE;
+        wxString tmp( tip );
+        gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
+    }
+    else
+    {
+        gtk_tooltips_set_tip( tips, GetConnectWidget(), NULL, NULL);
     }
-    node = node->Next();
-  }
-  return TRUE;
 }
+#endif // wxUSE_TOOLTIPS
 
-bool wxWindow::TransferDataFromWindow(void)
+bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
 {
-  wxNode *node = GetChildren()->First();
-  while (node)
-  {
-    wxWindow *child = (wxWindow *)node->Data();
-    if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->TransferFromWindow() )
-      { return FALSE; }
-   node = node->Next();
-  }
-  return TRUE;
-}
+    wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
 
-void wxWindow::SetAcceleratorTable( const wxAcceleratorTable& accel )
-{
-  m_acceleratorTable = accel;
-}
+    if (!wxWindowBase::SetBackgroundColour(colour))
+        return false;
 
-void wxWindow::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
-{
-  TransferDataToWindow();
-}
+    if (colour.Ok())
+    {
+        // We need the pixel value e.g. for background clearing.
+        m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
+    }
 
-void wxWindow::InitDialog(void)
-{
-  wxInitDialogEvent event(GetId());
-  event.SetEventObject( this );
-  GetEventHandler()->ProcessEvent(event);
-}
+    // apply style change (forceStyle=true so that new style is applied
+    // even if the bg colour changed from valid to wxNullColour)
+    if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
+        ApplyWidgetStyle(true);
 
-static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
-{
-  menu->SetInvokingWindow( win );
-  wxNode *node = menu->m_items.First();
-  while (node)
-  {
-    wxMenuItem *menuitem = (wxMenuItem*)node->Data();
-    if (menuitem->IsSubMenu())
-      SetInvokingWindow( menuitem->GetSubMenu(), win );
-    node = node->Next();
-  }
+    return true;
 }
 
-bool wxWindow::PopupMenu( wxMenu *menu, int WXUNUSED(x), int WXUNUSED(y) )
+bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
 {
-  SetInvokingWindow( menu, this );
-  gtk_menu_popup( GTK_MENU(menu->m_menu), (GtkWidget *) NULL, (GtkWidget *) NULL, (GtkMenuPositionFunc) NULL, NULL, 0, 0 );
-  return TRUE;
-}
+    wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
 
-void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
-{
-  GtkWidget *dnd_widget = GetConnectWidget();
-  
-  if (m_pDropTarget)
-  {
-    gtk_signal_disconnect_by_func( GTK_OBJECT(dnd_widget),
-      GTK_SIGNAL_FUNC(gtk_window_drop_callback), (gpointer)this );
-  
-    m_pDropTarget->UnregisterWidget( dnd_widget );
-    delete m_pDropTarget;
-  }
-  m_pDropTarget = dropTarget;
-  if (m_pDropTarget)
-  {
-    m_pDropTarget->RegisterWidget( dnd_widget );
-    
-    gtk_signal_connect( GTK_OBJECT(dnd_widget), "drop_data_available_event",
-      GTK_SIGNAL_FUNC(gtk_window_drop_callback), (gpointer)this );
-  }
-}
+    if (!wxWindowBase::SetForegroundColour(colour))
+    {
+        return false;
+    }
 
-wxDropTarget *wxWindow::GetDropTarget() const
-{
-  return m_pDropTarget;
-}
+    if (colour.Ok())
+    {
+        // We need the pixel value e.g. for background clearing.
+        m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
+    }
 
-GtkWidget* wxWindow::GetConnectWidget(void)
-{
-  GtkWidget *connect_widget = m_widget;
-  if (m_wxwindow) connect_widget = m_wxwindow;
-  
-  return connect_widget;
-}
-  
-bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
-{
-  if (m_wxwindow) return (window == m_wxwindow->window);
-  return (window == m_widget->window);
-}
+    // apply style change (forceStyle=true so that new style is applied
+    // even if the bg colour changed from valid to wxNullColour):
+    ApplyWidgetStyle(true);
 
-void wxWindow::SetFont( const wxFont &font )
-{
-  m_font = font;
-/*
-  create new style
-  copy old style values to new one
-  set font in new style
-  -> takes to many resources
-  
-  GtkStyle *style = gtk_style_new();
-  ...
-*/
+    return true;
 }
 
-wxFont *wxWindow::GetFont(void)
+PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
 {
-  return &m_font;
+    return gtk_widget_get_pango_context( m_widget );
 }
 
-void wxWindow::SetWindowStyleFlag( long flag )
+GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
 {
-  m_windowStyle = flag;
-}
+    // do we need to apply any changes at all?
+    if ( !forceStyle &&
+         !m_font.Ok() &&
+         !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
+    {
+        return NULL;
+    }
 
-long wxWindow::GetWindowStyleFlag(void) const
-{
-  return m_windowStyle;
-}
+    GtkRcStyle *style = gtk_rc_style_new();
 
-void wxWindow::CaptureMouse(void)
-{
-  GtkWidget *connect_widget = GetConnectWidget();
-  gtk_grab_add( connect_widget );
-  gdk_pointer_grab ( connect_widget->window, FALSE,
-                    (GdkEventMask)
-        (GDK_BUTTON_PRESS_MASK | 
-        GDK_BUTTON_RELEASE_MASK |
-        GDK_POINTER_MOTION_MASK), 
-        (GdkWindow *) NULL, (GdkCursor *) NULL, GDK_CURRENT_TIME );
-}
+    if ( m_font.Ok() )
+    {
+        style->font_desc =
+            pango_font_description_copy( m_font.GetNativeFontInfo()->description );
+    }
 
-void wxWindow::ReleaseMouse(void)
-{
-  GtkWidget *connect_widget = GetConnectWidget();
-  gtk_grab_remove( connect_widget );
-  gdk_pointer_ungrab ( GDK_CURRENT_TIME );
-}
+    int flagsNormal = 0,
+        flagsPrelight = 0,
+        flagsActive = 0,
+        flagsInsensitive = 0;
 
-void wxWindow::SetTitle( const wxString &WXUNUSED(title) )
-{
-}
+    if ( m_foregroundColour.Ok() )
+    {
+        const GdkColor *fg = m_foregroundColour.GetColor();
 
-wxString wxWindow::GetTitle(void) const
-{
-  return (wxString&)m_windowName;
-}
+        style->fg[GTK_STATE_NORMAL] =
+        style->text[GTK_STATE_NORMAL] = *fg;
+        flagsNormal |= GTK_RC_FG | GTK_RC_TEXT;
 
-wxString wxWindow::GetLabel(void) const
-{
-  return GetTitle();
-}
+        style->fg[GTK_STATE_PRELIGHT] =
+        style->text[GTK_STATE_PRELIGHT] = *fg;
+        flagsPrelight |= GTK_RC_FG | GTK_RC_TEXT;
 
-void wxWindow::SetName( const wxString &name )
-{
-  m_windowName = name;
-}
+        style->fg[GTK_STATE_ACTIVE] =
+        style->text[GTK_STATE_ACTIVE] = *fg;
+        flagsActive |= GTK_RC_FG | GTK_RC_TEXT;
+    }
 
-wxString wxWindow::GetName(void) const
-{
-  return (wxString&)m_windowName;
-}
+    if ( m_backgroundColour.Ok() )
+    {
+        const GdkColor *bg = m_backgroundColour.GetColor();
 
-bool wxWindow::IsShown(void) const
-{
-  return m_isShown;
-}
+        style->bg[GTK_STATE_NORMAL] =
+        style->base[GTK_STATE_NORMAL] = *bg;
+        flagsNormal |= GTK_RC_BG | GTK_RC_BASE;
 
-bool wxWindow::IsRetained(void)
-{
-  return FALSE;
-}
+        style->bg[GTK_STATE_PRELIGHT] =
+        style->base[GTK_STATE_PRELIGHT] = *bg;
+        flagsPrelight |= GTK_RC_BG | GTK_RC_BASE;
 
-wxWindow *wxWindow::FindWindow( long id )
-{
-  if (id == m_windowId) return this;
-  wxNode *node = m_children.First();
-  while (node)
-  {
-    wxWindow *child = (wxWindow*)node->Data();
-    wxWindow *res = child->FindWindow( id );
-    if (res) return res;
-    node = node->Next();
-  }
-  return (wxWindow *) NULL;
+        style->bg[GTK_STATE_ACTIVE] =
+        style->base[GTK_STATE_ACTIVE] = *bg;
+        flagsActive |= GTK_RC_BG | GTK_RC_BASE;
+
+        style->bg[GTK_STATE_INSENSITIVE] =
+        style->base[GTK_STATE_INSENSITIVE] = *bg;
+        flagsInsensitive |= GTK_RC_BG | GTK_RC_BASE;
+    }
+
+    style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)flagsNormal;
+    style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)flagsPrelight;
+    style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)flagsActive;
+    style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)flagsInsensitive;
+
+    return style;
 }
 
-wxWindow *wxWindow::FindWindow( const wxString& name )
+void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
 {
-  if (name == m_windowName) return this;
-  wxNode *node = m_children.First();
-  while (node)
-  {
-    wxWindow *child = (wxWindow*)node->Data();
-    wxWindow *res = child->FindWindow( name );
-    if (res) return res;
-    node = node->Next();
-  }
-  return (wxWindow *) NULL;
+    GtkRcStyle *style = CreateWidgetStyle(forceStyle);
+    if ( style )
+    {
+        DoApplyWidgetStyle(style);
+        gtk_rc_style_unref(style);
+    }
+
+    // Style change may affect GTK+'s size calculation:
+    InvalidateBestSize();
 }
 
-void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
-      int range, bool WXUNUSED(refresh) )
+void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
 {
-  if (!m_wxwindow) return;
-
-  if (orient == wxHORIZONTAL)
-  {
-    float fpos = (float)pos;
-    m_oldHorizontalPos = fpos;
-    float frange = (float)range;
-    float fthumb = (float)thumbVisible;
-    
-    if ((fabs(fpos-m_hAdjust->value) < 0.2) &&
-        (fabs(frange-m_hAdjust->upper) < 0.2) &&
-  (fabs(fthumb-m_hAdjust->page_size) < 0.2))
-      return;
-      
-    m_hAdjust->lower = 0.0;
-    m_hAdjust->upper = frange;
-    m_hAdjust->value = fpos;
-    m_hAdjust->step_increment = 1.0;
-    m_hAdjust->page_increment = (float)(wxMax(fthumb-2,0));
-    m_hAdjust->page_size = fthumb;
-  }
-  else
-  {
-    float fpos = (float)pos;
-    m_oldVerticalPos = fpos;
-    float frange = (float)range;
-    float fthumb = (float)thumbVisible;
-    
-    if ((fabs(fpos-m_vAdjust->value) < 0.2) &&
-        (fabs(frange-m_vAdjust->upper) < 0.2) &&
-  (fabs(fthumb-m_vAdjust->page_size) < 0.2))
-      return;
-      
-    m_vAdjust->lower = 0.0;
-    m_vAdjust->upper = frange;
-    m_vAdjust->value = fpos;
-    m_vAdjust->step_increment = 1.0;
-    m_vAdjust->page_increment = (float)(wxMax(fthumb-2,0));
-    m_vAdjust->page_size = fthumb;
-  }
-  
-  if (m_wxwindow->window)
-  {
-    if (orient == wxHORIZONTAL)
-      gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
+    if (m_wxwindow)
+        gtk_widget_modify_style(m_wxwindow, style);
     else
-      gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
-      
-    gtk_widget_set_usize( m_widget, m_width, m_height );
-  }
+        gtk_widget_modify_style(m_widget, style);
 }
 
-void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
+bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
 {
-  if (!m_wxwindow) return;
-  
-  if (orient == wxHORIZONTAL)
-  {
-    float fpos = (float)pos;
-    m_oldHorizontalPos = fpos;
+    wxWindowBase::SetBackgroundStyle(style);
 
-    if (fabs(fpos-m_hAdjust->value) < 0.2) return;
-    m_hAdjust->value = fpos;
-  }
-  else
-  {
-    float fpos = (float)pos;
-    m_oldVerticalPos = fpos;
-    if (fabs(fpos-m_vAdjust->value) < 0.2) return;
-    m_vAdjust->value = fpos;
-  }
-  
-  if (m_wxwindow->window)
-  {  
-    if (orient == wxHORIZONTAL)
-      gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
-    else  
-      gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
-  }
-}
+    if (style == wxBG_STYLE_CUSTOM)
+    {
+        GdkWindow *window = (GdkWindow*) NULL;
+        if (m_wxwindow)
+            window = GTK_PIZZA(m_wxwindow)->bin_window;
+        else
+            window = GetConnectWidget()->window;
 
-int wxWindow::GetScrollThumb( int orient ) const
-{
-  if (!m_wxwindow) return 0;
+        if (window)
+        {
+            // Make sure GDK/X11 doesn't refresh the window
+            // automatically.
+            gdk_window_set_back_pixmap( window, None, False );
+#ifdef __X__
+            Display* display = GDK_WINDOW_DISPLAY(window);
+            XFlush(display);
+#endif
+            m_needsStyleChange = false;
+        }
+        else
+            // Do in OnIdle, because the window is not yet available
+            m_needsStyleChange = true;
 
-  if (orient == wxHORIZONTAL)
-    return (int)(m_hAdjust->page_size+0.5);
-  else
-    return (int)(m_vAdjust->page_size+0.5);
+        // Don't apply widget style, or we get a grey background
+    }
+    else
+    {
+        // apply style change (forceStyle=true so that new style is applied
+        // even if the bg colour changed from valid to wxNullColour):
+        ApplyWidgetStyle(true);
+    }
+    return true;
 }
 
-int wxWindow::GetScrollPos( int orient ) const
+#if wxUSE_DRAG_AND_DROP
+
+void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
 {
-  if (!m_wxwindow) return 0;
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
-  if (orient == wxHORIZONTAL)
-    return (int)(m_hAdjust->value+0.5);
-  else
-    return (int)(m_vAdjust->value+0.5);
-}
+    GtkWidget *dnd_widget = GetConnectWidget();
 
-int wxWindow::GetScrollRange( int orient ) const
-{
-  if (!m_wxwindow) return 0;
+    if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
 
-  if (orient == wxHORIZONTAL)
-    return (int)(m_hAdjust->upper+0.5);
-  else
-    return (int)(m_vAdjust->upper+0.5);
+    if (m_dropTarget) delete m_dropTarget;
+    m_dropTarget = dropTarget;
+
+    if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
 }
 
-void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
+#endif // wxUSE_DRAG_AND_DROP
+
+GtkWidget* wxWindowGTK::GetConnectWidget()
 {
-  if (!m_wxwindow) return;
-  
-/*
-  bool refresh = FALSE;
-    
-  if ((m_drawingOffsetX == 0) && (m_drawingOffsetY == 0))
-  {
-    m_drawingOffsetX = -16000;
-    m_drawingOffsetY = -16000;
-    refresh = TRUE;
-  }
-  else
-  {
-    m_drawingOffsetX += dx;
-    m_drawingOffsetY += dy;
-  }
-  
-//  printf( "X: %d  Y: %d  \n", (int)m_drawingOffsetX, (int)m_drawingOffsetY );
-  
-  gtk_myfixed_set_offset( GTK_MYFIXED(m_wxwindow), m_drawingOffsetX, m_drawingOffsetY );
-  
-  if (refresh) Refresh();
-  
-    The code here is very nifty, but it doesn't work with
-    overlapping windows...
-*/
+    GtkWidget *connect_widget = m_widget;
+    if (m_wxwindow) connect_widget = m_wxwindow;
 
-    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();
-      return;
-    }
-    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( m_wxwindow->window, m_wxwindow->style->fg_gc[0], d_x, d_y,
-      m_wxwindow->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 );
-}
-
-//-------------------------------------------------------------------------------------
-//          Layout
-//-------------------------------------------------------------------------------------
-
-wxLayoutConstraints *wxWindow::GetConstraints(void) const
-{
-  return m_constraints;
-}
-
-void wxWindow::SetConstraints( wxLayoutConstraints *constraints )
-{
-  if (m_constraints)
-  {
-    UnsetConstraints(m_constraints);
-    delete m_constraints;
-  }
-  m_constraints = constraints;
-  if (m_constraints)
-  {
-    // Make sure other windows know they're part of a 'meaningful relationship'
-    if (m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this))
-      m_constraints->left.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
-    if (m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this))
-      m_constraints->top.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
-    if (m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this))
-      m_constraints->right.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
-    if (m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this))
-      m_constraints->bottom.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
-    if (m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this))
-      m_constraints->width.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
-    if (m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this))
-      m_constraints->height.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
-    if (m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this))
-      m_constraints->centreX.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
-    if (m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this))
-      m_constraints->centreY.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
-  }
-;
+    return connect_widget;
 }
-;
 
-void wxWindow::SetAutoLayout( bool autoLayout )
+bool wxWindowGTK::GTKIsOwnWindow(GdkWindow *window) const
 {
-  m_autoLayout = autoLayout;
-}
+    wxArrayGdkWindows windowsThis;
+    GdkWindow * const winThis = GTKGetWindow(windowsThis);
 
-bool wxWindow::GetAutoLayout(void) const
-{
-  return m_autoLayout;
+    return winThis ? window == winThis
+                   : windowsThis.Index(window) != wxNOT_FOUND;
 }
 
-wxSizer *wxWindow::GetSizer(void) const
+GdkWindow *wxWindowGTK::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
 {
-  return m_windowSizer;
+    return m_wxwindow ? GTK_PIZZA(m_wxwindow)->bin_window : m_widget->window;
 }
 
-void wxWindow::SetSizerParent( wxWindow *win )
+bool wxWindowGTK::SetFont( const wxFont &font )
 {
-  m_sizerParent = win;
-}
+    wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
 
-wxWindow *wxWindow::GetSizerParent(void) const
-{
-  return m_sizerParent;
-}
+    if (!wxWindowBase::SetFont(font))
+        return false;
 
-// This removes any dangling pointers to this window
-// in other windows' constraintsInvolvedIn lists.
-void wxWindow::UnsetConstraints(wxLayoutConstraints *c)
-{
-  if (c)
-  {
-    if (c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this))
-      c->left.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
-    if (c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this))
-      c->top.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
-    if (c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this))
-      c->right.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
-    if (c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this))
-      c->bottom.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
-    if (c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this))
-      c->width.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
-    if (c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this))
-      c->height.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
-    if (c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this))
-      c->centreX.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
-    if (c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this))
-      c->centreY.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
-  }
-}
+    // apply style change (forceStyle=true so that new style is applied
+    // even if the font changed from valid to wxNullFont):
+    ApplyWidgetStyle(true);
 
-// Back-pointer to other windows we're involved with, so if we delete
-// this window, we must delete any constraints we're involved with.
-void wxWindow::AddConstraintReference(wxWindow *otherWin)
-{
-  if (!m_constraintsInvolvedIn)
-    m_constraintsInvolvedIn = new wxList;
-  if (!m_constraintsInvolvedIn->Member(otherWin))
-    m_constraintsInvolvedIn->Append(otherWin);
+    return true;
 }
 
-// REMOVE back-pointer to other windows we're involved with.
-void wxWindow::RemoveConstraintReference(wxWindow *otherWin)
+void wxWindowGTK::DoCaptureMouse()
 {
-  if (m_constraintsInvolvedIn)
-    m_constraintsInvolvedIn->DeleteObject(otherWin);
-}
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
-// Reset any constraints that mention this window
-void wxWindow::DeleteRelatedConstraints(void)
-{
-  if (m_constraintsInvolvedIn)
-  {
-    wxNode *node = m_constraintsInvolvedIn->First();
-    while (node)
-    {
-      wxWindow *win = (wxWindow *)node->Data();
-      wxNode *next = node->Next();
-      wxLayoutConstraints *constr = win->GetConstraints();
-
-      // Reset any constraints involving this window
-      if (constr)
-      {
-        constr->left.ResetIfWin((wxWindow *)this);
-        constr->top.ResetIfWin((wxWindow *)this);
-        constr->right.ResetIfWin((wxWindow *)this);
-        constr->bottom.ResetIfWin((wxWindow *)this);
-        constr->width.ResetIfWin((wxWindow *)this);
-        constr->height.ResetIfWin((wxWindow *)this);
-        constr->centreX.ResetIfWin((wxWindow *)this);
-        constr->centreY.ResetIfWin((wxWindow *)this);
-      }
-      delete node;
-      node = next;
-    }
-    delete m_constraintsInvolvedIn;
-    m_constraintsInvolvedIn = (wxList *) NULL;
-  }
+    GdkWindow *window = (GdkWindow*) NULL;
+    if (m_wxwindow)
+        window = GTK_PIZZA(m_wxwindow)->bin_window;
+    else
+        window = GetConnectWidget()->window;
+
+    wxCHECK_RET( window, _T("CaptureMouse() failed") );
+
+    const wxCursor* cursor = &m_cursor;
+    if (!cursor->Ok())
+        cursor = wxSTANDARD_CURSOR;
+
+    gdk_pointer_grab( window, FALSE,
+                      (GdkEventMask)
+                         (GDK_BUTTON_PRESS_MASK |
+                          GDK_BUTTON_RELEASE_MASK |
+                          GDK_POINTER_MOTION_HINT_MASK |
+                          GDK_POINTER_MOTION_MASK),
+                      (GdkWindow *) NULL,
+                      cursor->GetCursor(),
+                      (guint32)GDK_CURRENT_TIME );
+    g_captureWindow = this;
+    g_captureWindowHasMouse = true;
 }
 
-void wxWindow::SetSizer(wxSizer *sizer)
+void wxWindowGTK::DoReleaseMouse()
 {
-  m_windowSizer = sizer;
-  if (sizer)
-    sizer->SetSizerParent((wxWindow *)this);
-}
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
-/*
- * New version
- */
+    wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
 
-bool wxWindow::Layout(void)
-{
-  if (GetConstraints())
-  {
-    int w, h;
-    GetClientSize(&w, &h);
-    GetConstraints()->width.SetValue(w);
-    GetConstraints()->height.SetValue(h);
-  }
-  
-  // If top level (one sizer), evaluate the sizer's constraints.
-  if (GetSizer())
-  {
-    int noChanges;
-    GetSizer()->ResetConstraints();   // Mark all constraints as unevaluated
-    GetSizer()->LayoutPhase1(&noChanges);
-    GetSizer()->LayoutPhase2(&noChanges);
-    GetSizer()->SetConstraintSizes(); // Recursively set the real window sizes
-    return TRUE;
-  }
-  else
-  {
-    // Otherwise, evaluate child constraints
-    ResetConstraints();   // Mark all constraints as unevaluated
-    DoPhase(1);           // Just one phase need if no sizers involved
-    DoPhase(2);
-    SetConstraintSizes(); // Recursively set the real window sizes
-  }
-  return TRUE;
-}
+    g_captureWindow = (wxWindowGTK*) NULL;
+
+    GdkWindow *window = (GdkWindow*) NULL;
+    if (m_wxwindow)
+        window = GTK_PIZZA(m_wxwindow)->bin_window;
+    else
+        window = GetConnectWidget()->window;
+
+    if (!window)
+        return;
 
+    gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
+}
 
-// Do a phase of evaluating constraints:
-// the default behaviour. wxSizers may do a similar
-// thing, but also impose their own 'constraints'
-// and order the evaluation differently.
-bool wxWindow::LayoutPhase1(int *noChanges)
+/* static */
+wxWindow *wxWindowBase::GetCapture()
 {
-  wxLayoutConstraints *constr = GetConstraints();
-  if (constr)
-  {
-    return constr->SatisfyConstraints((wxWindow *)this, noChanges);
-  }
-  else
-    return TRUE;
+    return (wxWindow *)g_captureWindow;
 }
 
-bool wxWindow::LayoutPhase2(int *noChanges)
+bool wxWindowGTK::IsRetained() const
 {
-  *noChanges = 0;
-  
-  // Layout children
-  DoPhase(1);
-  DoPhase(2);
-  return TRUE;
+    return false;
 }
 
-// Do a phase of evaluating child constraints
-bool wxWindow::DoPhase(int phase)
+void wxWindowGTK::BlockScrollEvent()
 {
-  int noIterations = 0;
-  int maxIterations = 500;
-  int noChanges = 1;
-  int noFailures = 0;
-  wxList succeeded;
-  while ((noChanges > 0) && (noIterations < maxIterations))
-  {
-    noChanges = 0;
-    noFailures = 0;
-    wxNode *node = GetChildren()->First();
-    while (node)
-    {
-      wxWindow *child = (wxWindow *)node->Data();
-      if (!child->IsKindOf(CLASSINFO(wxFrame)) && !child->IsKindOf(CLASSINFO(wxDialog)))
-      {
-        wxLayoutConstraints *constr = child->GetConstraints();
-        if (constr)
-        {
-          if (succeeded.Member(child))
-          {
-          }
-          else
-          {
-            int tempNoChanges = 0;
-            bool success = ( (phase == 1) ? child->LayoutPhase1(&tempNoChanges) : child->LayoutPhase2(&tempNoChanges) ) ;
-            noChanges += tempNoChanges;
-            if (success)
-            {
-              succeeded.Append(child);
-            }
-          }
-        }
-      }
-      node = node->Next();
-    }
-    noIterations ++;
-  }
-  return TRUE;
+    wxASSERT(!m_blockScrollEvent);
+    m_blockScrollEvent = true;
 }
 
-void wxWindow::ResetConstraints(void)
+void wxWindowGTK::UnblockScrollEvent()
 {
-  wxLayoutConstraints *constr = GetConstraints();
-  if (constr)
-  {
-    constr->left.SetDone(FALSE);
-    constr->top.SetDone(FALSE);
-    constr->right.SetDone(FALSE);
-    constr->bottom.SetDone(FALSE);
-    constr->width.SetDone(FALSE);
-    constr->height.SetDone(FALSE);
-    constr->centreX.SetDone(FALSE);
-    constr->centreY.SetDone(FALSE);
-  }
-  wxNode *node = GetChildren()->First();
-  while (node)
-  {
-    wxWindow *win = (wxWindow *)node->Data();
-    if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog)))
-      win->ResetConstraints();
-    node = node->Next();
-  }
+    wxASSERT(m_blockScrollEvent);
+    m_blockScrollEvent = false;
 }
 
-// Need to distinguish between setting the 'fake' size for
-// windows and sizers, and setting the real values.
-void wxWindow::SetConstraintSizes(bool recurse)
+void wxWindowGTK::SetScrollbar(int orient,
+                               int pos,
+                               int thumbVisible,
+                               int range,
+                               bool WXUNUSED(update))
 {
-  wxLayoutConstraints *constr = GetConstraints();
-  if (constr && constr->left.GetDone() && constr->right.GetDone() &&
-                constr->width.GetDone() && constr->height.GetDone())
-  {
-    int x = constr->left.GetValue();
-    int y = constr->top.GetValue();
-    int w = constr->width.GetValue();
-    int h = constr->height.GetValue();
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+    wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
+    wxCHECK_RET( m_wxwindow != m_widget, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
 
-    // If we don't want to resize this window, just move it...
-    if ((constr->width.GetRelationship() != wxAsIs) ||
-        (constr->height.GetRelationship() != wxAsIs))
+    if (range > 0)
     {
-      // Calls Layout() recursively. AAAGH. How can we stop that.
-      // Simply take Layout() out of non-top level OnSizes.
-      SizerSetSize(x, y, w, h);
+        m_hasScrolling = true;
     }
     else
     {
-      SizerMove(x, y);
+        // GtkRange requires upper > lower
+        range =
+        thumbVisible = 1;
     }
-  }
-  else if (constr)
-  {
-    char *windowClass = this->GetClassInfo()->GetClassName();
-
-    wxString winName;
-  if (GetName() == "")
-    winName = _("unnamed");
-  else
-    winName = GetName();
-    wxDebugMsg(_("Constraint(s) not satisfied for window of type %s, name %s:\n"), (const char *)windowClass, (const char *)winName);
-    if (!constr->left.GetDone())
-      wxDebugMsg(_("  unsatisfied 'left' constraint.\n"));
-    if (!constr->right.GetDone())
-      wxDebugMsg(_("  unsatisfied 'right' constraint.\n"));
-    if (!constr->width.GetDone())
-      wxDebugMsg(_("  unsatisfied 'width' constraint.\n"));
-    if (!constr->height.GetDone())
-      wxDebugMsg(_("  unsatisfied 'height' constraint.\n"));
-    wxDebugMsg(_("Please check constraints: try adding AsIs() constraints.\n"));
-  }
 
-  if (recurse)
-  {
-    wxNode *node = GetChildren()->First();
-    while (node)
+    if (pos > range - thumbVisible)
+        pos = range - thumbVisible;
+    if (pos < 0)
+        pos = 0;
+    GtkAdjustment* adj = m_scrollBar[ScrollDirFromOrient(orient)]->adjustment;
+    adj->step_increment = 1;
+    adj->page_increment =
+    adj->page_size = thumbVisible;
+    adj->upper = range;
+    SetScrollPos(orient, pos);
+    gtk_adjustment_changed(adj);
+}
+
+void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
+{
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+    wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
+    wxCHECK_RET( m_wxwindow != m_widget, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
+
+    // This check is more than an optimization. Without it, the slider
+    //   will not move smoothly while tracking when using wxScrollHelper.
+    if (GetScrollPos(orient) != pos)
     {
-      wxWindow *win = (wxWindow *)node->Data();
-      if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog)))
-        win->SetConstraintSizes();
-      node = node->Next();
+        const int dir = ScrollDirFromOrient(orient);
+        GtkAdjustment* adj = m_scrollBar[dir]->adjustment;
+        const int max = int(adj->upper - adj->page_size);
+        if (pos > max)
+            pos = max;
+        if (pos < 0)
+            pos = 0;
+        m_scrollPos[dir] = adj->value = pos;
+
+        // If a "value_changed" signal emission is not already in progress
+        if (!m_blockValueChanged[dir])
+        {
+            gtk_adjustment_value_changed(adj);
+        }
     }
-  }
 }
 
-// This assumes that all sizers are 'on' the same
-// window, i.e. the parent of this window.
-void wxWindow::TransformSizerToActual(int *x, int *y) const
+int wxWindowGTK::GetScrollThumb(int orient) const
 {
-  if (!m_sizerParent || m_sizerParent->IsKindOf(CLASSINFO(wxDialog)) ||
-         m_sizerParent->IsKindOf(CLASSINFO(wxFrame)) )
-    return;
-    
-  int xp, yp;
-  m_sizerParent->GetPosition(&xp, &yp);
-  m_sizerParent->TransformSizerToActual(&xp, &yp);
-  *x += xp;
-  *y += yp;
+    wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
+    wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
+    wxCHECK_MSG( m_wxwindow != m_widget, 0, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
+
+    return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->page_size);
 }
 
-void wxWindow::SizerSetSize(int x, int y, int w, int h)
+int wxWindowGTK::GetScrollPos( int orient ) const
 {
-  int xx = x;
-  int yy = y;
-  TransformSizerToActual(&xx, &yy);
-  SetSize(xx, yy, w, h);
+    wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
+    wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
+    wxCHECK_MSG( m_wxwindow != m_widget, 0, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
+
+    return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->value + 0.5);
 }
 
-void wxWindow::SizerMove(int x, int y)
+int wxWindowGTK::GetScrollRange( int orient ) const
 {
-  int xx = x;
-  int yy = y;
-  TransformSizerToActual(&xx, &yy);
-  Move(xx, yy);
+    wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
+    wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
+    wxCHECK_MSG( m_wxwindow != m_widget, 0, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
+
+    return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->upper);
 }
 
-// Only set the size/position of the constraint (if any)
-void wxWindow::SetSizeConstraint(int x, int y, int w, int h)
+// Determine if increment is the same as +/-x, allowing for some small
+//   difference due to possible inexactness in floating point arithmetic
+static inline bool IsScrollIncrement(double increment, double x)
 {
-  wxLayoutConstraints *constr = GetConstraints();
-  if (constr)
-  {
-    if (x != -1)
-    {
-      constr->left.SetValue(x);
-      constr->left.SetDone(TRUE);
-    }
-    if (y != -1)
-    {
-      constr->top.SetValue(y);
-      constr->top.SetDone(TRUE);
-    }
-    if (w != -1)
+    wxASSERT(increment > 0);
+    const double tolerance = 1.0 / 1024;
+    return fabs(increment - fabs(x)) < tolerance;
+}
+
+wxEventType wxWindowGTK::GetScrollEventType(GtkRange* range)
+{
+    DEBUG_MAIN_THREAD
+
+    wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]);
+
+    const int barIndex = range == m_scrollBar[1];
+    GtkAdjustment* adj = range->adjustment;
+
+    const int value = int(adj->value + 0.5);
+
+    // save previous position
+    const double oldPos = m_scrollPos[barIndex];
+    // update current position
+    m_scrollPos[barIndex] = adj->value;
+    // If event should be ignored, or integral position has not changed
+    if (!m_hasVMT || g_blockEventsOnDrag || value == int(oldPos + 0.5))
     {
-      constr->width.SetValue(w);
-      constr->width.SetDone(TRUE);
+        return wxEVT_NULL;
     }
-    if (h != -1)
+
+    wxEventType eventType = wxEVT_SCROLL_THUMBTRACK;
+    if (!m_isScrolling)
     {
-      constr->height.SetValue(h);
-      constr->height.SetDone(TRUE);
+        // Difference from last change event
+        const double diff = adj->value - oldPos;
+        const bool isDown = diff > 0;
+
+        if (IsScrollIncrement(adj->step_increment, diff))
+        {
+            eventType = isDown ? wxEVT_SCROLL_LINEDOWN : wxEVT_SCROLL_LINEUP;
+        }
+        else if (IsScrollIncrement(adj->page_increment, diff))
+        {
+            eventType = isDown ? wxEVT_SCROLL_PAGEDOWN : wxEVT_SCROLL_PAGEUP;
+        }
+        else if (m_mouseButtonDown)
+        {
+            // Assume track event
+            m_isScrolling = true;
+        }
     }
-  }
+    return eventType;
 }
 
-void wxWindow::MoveConstraint(int x, int y)
+void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
 {
-  wxLayoutConstraints *constr = GetConstraints();
-  if (constr)
-  {
-    if (x != -1)
+    wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+
+    wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
+
+    // No scrolling requested.
+    if ((dx == 0) && (dy == 0)) return;
+
+    m_clipPaintRegion = true;
+
+    if (GetLayoutDirection() == wxLayout_RightToLeft)
+        gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), dx, -dy );
+    else
+        gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
+
+    m_clipPaintRegion = false;
+
+#if wxUSE_CARET
+    bool restoreCaret = (GetCaret() != NULL && GetCaret()->IsVisible());
+    if (restoreCaret)
     {
-      constr->left.SetValue(x);
-      constr->left.SetDone(TRUE);
+        wxRect caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
+        if (dx > 0)
+            caretRect.width += dx;
+        else
+        {
+            caretRect.x += dx; caretRect.width -= dx;
+        }
+        if (dy > 0)
+            caretRect.height += dy;
+        else
+        {
+            caretRect.y += dy; caretRect.height -= dy;
+        }
+
+        RefreshRect(caretRect);
     }
-    if (y != -1)
+#endif // wxUSE_CARET
+}
+
+void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget* w, int wxstyle)
+{
+    //RN: Note that static controls usually have no border on gtk, so maybe
+    //it makes sense to treat that as simply no border at the wx level
+    //as well...
+    if (!(wxstyle & wxNO_BORDER) && !(wxstyle & wxBORDER_STATIC))
     {
-      constr->top.SetValue(y);
-      constr->top.SetDone(TRUE);
+        GtkShadowType gtkstyle;
+
+        if(wxstyle & wxBORDER_RAISED)
+            gtkstyle = GTK_SHADOW_OUT;
+        else if (wxstyle & wxBORDER_SUNKEN)
+            gtkstyle = GTK_SHADOW_IN;
+        else if (wxstyle & wxBORDER_DOUBLE)
+            gtkstyle = GTK_SHADOW_ETCHED_IN;
+        else //default
+            gtkstyle = GTK_SHADOW_IN;
+
+        gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w),
+                                             gtkstyle );
     }
-  }
 }
 
-void wxWindow::GetSizeConstraint(int *w, int *h) const
+void wxWindowGTK::SetWindowStyleFlag( long style )
 {
-  wxLayoutConstraints *constr = GetConstraints();
-  if (constr)
-  {
-    *w = constr->width.GetValue();
-    *h = constr->height.GetValue();
-  }
-  else
-    GetSize(w, h);
+    // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
+    wxWindowBase::SetWindowStyleFlag(style);
 }
 
-void wxWindow::GetClientSizeConstraint(int *w, int *h) const
+// Find the wxWindow at the current mouse position, also returning the mouse
+// position.
+wxWindow* wxFindWindowAtPointer(wxPoint& pt)
 {
-  wxLayoutConstraints *constr = GetConstraints();
-  if (constr)
-  {
-    *w = constr->width.GetValue();
-    *h = constr->height.GetValue();
-  }
-  else
-    GetClientSize(w, h);
+    pt = wxGetMousePosition();
+    wxWindow* found = wxFindWindowAtPoint(pt);
+    return found;
 }
 
-void wxWindow::GetPositionConstraint(int *x, int *y) const
+// Get the current mouse position.
+wxPoint wxGetMousePosition()
 {
-  wxLayoutConstraints *constr = GetConstraints();
-  if (constr)
-  {
-    *x = constr->left.GetValue();
-    *y = constr->top.GetValue();
-  }
-  else
-    GetPosition(x, y);
+  /* This crashes when used within wxHelpContext,
+     so we have to use the X-specific implementation below.
+    gint x, y;
+    GdkModifierType *mask;
+    (void) gdk_window_get_pointer(NULL, &x, &y, mask);
+
+    return wxPoint(x, y);
+  */
+
+    int x, y;
+    GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
+
+    Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
+    Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
+    Window rootReturn, childReturn;
+    int rootX, rootY, winX, winY;
+    unsigned int maskReturn;
+
+    XQueryPointer (display,
+           rootWindow,
+           &rootReturn,
+                   &childReturn,
+                   &rootX, &rootY, &winX, &winY, &maskReturn);
+    return wxPoint(rootX, rootY);
+
 }
 
-bool wxWindow::AcceptsFocus() const
+// Needed for implementing e.g. combobox on wxGTK within a modal dialog.
+void wxAddGrab(wxWindow* window)
 {
-  return IsEnabled() && IsShown();
+    gtk_grab_add( (GtkWidget*) window->GetHandle() );
 }
 
-void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event) )
+void wxRemoveGrab(wxWindow* window)
 {
-  UpdateWindowUI();
+    gtk_grab_remove( (GtkWidget*) window->GetHandle() );
 }