]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk1/window.cpp
regenerated project/makefiles with tmake
[wxWidgets.git] / src / gtk1 / window.cpp
index e66e9b1b9ce081f23492906bfc678a332987d8f7..8ef7d9bfcebb64d29e5db08aa622733ac4f383e2 100644 (file)
 
 #include "wx/gtk/win_gtk.h"
 
 
 #include "wx/gtk/win_gtk.h"
 
+#ifdef __WXGTK20__
+#include <pango/pangox.h>
+#endif
+
 #ifdef __WXGTK20__
     #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
 #else
 #ifdef __WXGTK20__
     #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
 #else
@@ -262,7 +266,7 @@ extern bool g_mainThreadLocked;
 //-----------------------------------------------------------------------------
 
 #ifndef __WXGTK20__
 //-----------------------------------------------------------------------------
 
 #ifndef __WXGTK20__
-#define DISABLE_STYLE_IF_BROKEN_THEME 1
+#define DISABLE_STYLE_IF_BROKEN_THEME 0
 #endif
 
 #ifdef __WXDEBUG__
 #endif
 
 #ifdef __WXDEBUG__
@@ -497,6 +501,14 @@ static int gtk_window_expose_callback( GtkWidget *widget,
     if (g_isIdle)
         wxapp_install_idle_handler();
 
     if (g_isIdle)
         wxapp_install_idle_handler();
 
+#ifdef __WXGTK20__
+    // 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) return FALSE;
+
 #if 0
     if (win->GetName())
     {
 #if 0
     if (win->GetName())
     {
@@ -510,22 +522,18 @@ static int gtk_window_expose_callback( GtkWidget *widget,
     }
 #endif
 
     }
 #endif
 
-#ifdef __WXGTK20__
-    // This callback gets called in drawing-idle time under
-    // GTK 2.0, so we don't need to defer anything to idle
-    // time anymore.
-    
     win->GetUpdateRegion() = wxRegion( gdk_event->region );
 
     win->GtkSendPaintEvents();
 
     win->GetUpdateRegion() = wxRegion( gdk_event->region );
 
     win->GtkSendPaintEvents();
 
-    // Draw window less widgets
+
+    // Let parent window draw window less widgets
     (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
 #else
     // This gets called immediately after an expose event
     // under GTK 1.2 so we collect the calls and wait for
     // the idle handler to pick things up.
     (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
 #else
     // This gets called immediately after an expose event
     // under GTK 1.2 so we collect the calls and wait for
     // the idle handler to pick things up.
-    
+
     win->GetUpdateRegion().Union( gdk_event->area.x,
                                   gdk_event->area.y,
                                   gdk_event->area.width,
     win->GetUpdateRegion().Union( gdk_event->area.x,
                                   gdk_event->area.y,
                                   gdk_event->area.width,
@@ -539,8 +547,7 @@ static int gtk_window_expose_callback( GtkWidget *widget,
     // win->GtkUpdate();
 #endif
 
     // win->GtkUpdate();
 #endif
 
-
-    return TRUE;
+    return FALSE;
 }
 
 //-----------------------------------------------------------------------------
 }
 
 //-----------------------------------------------------------------------------
@@ -1058,6 +1065,7 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
     return TRUE;
 }
 
     return TRUE;
 }
 
+
 static gint gtk_window_key_press_callback( GtkWidget *widget,
                                            GdkEventKey *gdk_event,
                                            wxWindow *win )
 static gint gtk_window_key_press_callback( GtkWidget *widget,
                                            GdkEventKey *gdk_event,
                                            wxWindow *win )
@@ -1107,42 +1115,58 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     // will only be sent if it is not in an accelerator table.
     if (!ret)
     {
     // will only be sent if it is not in an accelerator table.
     if (!ret)
     {
-        // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
+        long key_code;
         KeySym keysym = gdk_event->keyval;
         KeySym keysym = gdk_event->keyval;
-        long key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
-        if ( !key_code )
+#ifdef __WXGTK20__
+        // In GTK 2.0, we need to hand over the key event to an input method
+        // and the IM will emit a "commit" event containing the actual utf8
+        // character.  In that case the EVT_CHAR events will be sent from
+        // there.  But only do it this way for non-KeySym keys.
+        key_code = wxTranslateKeySymToWXKey(gdk_event->keyval, FALSE /* isChar */);
+        if ( !key_code && win->m_imContext )
         {
         {
-            if ( gdk_event->length == 1 )
-            {
-                key_code = (unsigned char)gdk_event->string[0];
-            }
-            else if ( wxIsAsciiKeysym(keysym) )
-            {
-                // ASCII key
-                key_code = (unsigned char)keysym;
-            }
+            gtk_im_context_filter_keypress ( (GtkIMContext*) win->m_imContext, gdk_event );
+            ret = TRUE;
         }
         }
-
-        if ( key_code )
+        else
+#endif
         {
         {
-            wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
-
-            event.m_keyCode = key_code;
-            
-            // Implement OnCharHook by checking ancesteror top level windows
-            wxWindow *parent = win;
-            while (parent && !parent->IsTopLevel())
-            parent = parent->GetParent();
-            if (parent)
+            // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
+            key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
+            if ( !key_code )
             {
             {
-                event.SetEventType( wxEVT_CHAR_HOOK );
-                ret = parent->GetEventHandler()->ProcessEvent( event );
+                if ( gdk_event->length == 1 )
+                {
+                    key_code = (unsigned char)gdk_event->string[0];
+                }
+                else if ( wxIsAsciiKeysym(keysym) )
+                {
+                    // ASCII key
+                    key_code = (unsigned char)keysym;
+                }
             }
 
             }
 
-            if (!ret)
+            if ( key_code )
             {
             {
-                event.SetEventType(wxEVT_CHAR);
-                ret = win->GetEventHandler()->ProcessEvent( event );
+                wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
+
+                event.m_keyCode = key_code;
+
+                // Implement OnCharHook by checking ancesteror 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 );
+                }
             }
         }
     }
             }
         }
     }
@@ -1172,50 +1196,95 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     if ( !ret &&
          (gdk_event->keyval == GDK_Escape) )
     {
     if ( !ret &&
          (gdk_event->keyval == GDK_Escape) )
     {
-        wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
-        new_event.SetEventObject( win );
-        ret = win->GetEventHandler()->ProcessEvent( new_event );
-    }
-
-    // Doesn't work.
-#if 0 
-    // Pressing F10 will activate the menu bar of the top frame
-    if ( (!ret) &&
-         (gdk_event->keyval == GDK_F10) )
-    {
-        wxWindowGTK *ancestor = win;
-        while (ancestor)
+        // however only do it if we have a Cancel button in the dialog,
+        // otherwise the user code may get confused by the events from a
+        // non-existing button and, worse, a wxButton might get button event
+        // from another button which is not really expected
+        wxWindow *winForCancel = win,
+                 *btnCancel = NULL;
+        while ( winForCancel )
         {
         {
-            if (wxIsKindOf(ancestor,wxFrame))
+            btnCancel = winForCancel->FindWindow(wxID_CANCEL);
+            if ( btnCancel )
             {
             {
-                wxFrame *frame = (wxFrame*) ancestor;
-                wxMenuBar *menubar = frame->GetMenuBar();
-                if (menubar)
-                {
-                    wxNode *node = menubar->GetMenus().First();
-                    if (node)
-                    {
-                        wxMenu *firstMenu = (wxMenu*) node->Data();
-                        gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
-                        ret = TRUE;
-                        break;
-                    }
-                }
+                // found a cancel button
+                break;
             }
             }
-            ancestor = ancestor->GetParent();
+
+            if ( winForCancel->IsTopLevel() )
+            {
+                // no need to look further
+                break;
+            }
+
+            // maybe our parent has a cancel button?
+            winForCancel = winForCancel->GetParent();
+        }
+
+        if ( btnCancel )
+        {
+            wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
+            event.SetEventObject(btnCancel);
+            ret = btnCancel->GetEventHandler()->ProcessEvent(event);
         }
     }
         }
     }
-#endif // 0
 
     if (ret)
     {
         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
         return TRUE;
     }
 
     if (ret)
     {
         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
         return TRUE;
     }
-    
+
     return FALSE;
 }
 
     return FALSE;
 }
 
+#ifdef __WXGTK20__
+static void gtk_wxwindow_commit_cb (GtkIMContext *context,
+                                                  const gchar  *str,
+                                                  wxWindow     *window)
+{
+    bool ret = FALSE;
+
+    wxKeyEvent event( wxEVT_KEY_DOWN );
+
+#if wxUSE_UNICODE
+    event.m_uniChar = g_utf8_get_char( str );
+
+    // Backward compatible for ISO-8859
+    if (event.m_uniChar < 256)
+        event.m_keyCode = event.m_uniChar;
+#else
+    gunichar uniChar = g_utf8_get_char( str );
+    // We cannot handle Unicode in non-Unicode mode
+    if (uniChar > 255) return;
+
+    event.m_keyCode = uniChar;
+#endif
+
+
+    // TODO:  We still need to set all the extra attributes of the
+    //        event, modifiers and such...
+
+
+    // Implement OnCharHook by checking ancestor top level windows
+    wxWindow *parent = window;
+    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 = window->GetEventHandler()->ProcessEvent( event );
+    }
+}
+#endif
+
+
 //-----------------------------------------------------------------------------
 // "key_release_event" from any window
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // "key_release_event" from any window
 //-----------------------------------------------------------------------------
@@ -1273,6 +1342,13 @@ static gint gtk_window_key_release_callback( GtkWidget *widget,
     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_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)                               \
+    {                                                                         \
+       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;                                 \
                                                                               \
     wxPoint pt = win->GetClientAreaOrigin();                                  \
     event.m_x = (wxCoord)gdk_event->x - pt.x;                                 \
@@ -1329,12 +1405,12 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
         yy += pizza->yoffset;
     }
 
         yy += pizza->yoffset;
     }
 
-    wxNode *node = win->GetChildren().First();
+    wxWindowList::Node  *node = win->GetChildren().GetFirst();
     while (node)
     {
     while (node)
     {
-        wxWindowGTK *child = (wxWindowGTK*)node->Data();
+        wxWindowGTK *child = node->GetData();
 
 
-        node = node->Next();
+        node = node->GetNext();
         if (!child->IsShown())
             continue;
 
         if (!child->IsShown())
             continue;
 
@@ -1344,7 +1420,7 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
             int xx1 = child->m_x;
             int yy1 = child->m_y;
             int xx2 = child->m_x + child->m_width;
             int xx1 = child->m_x;
             int yy1 = child->m_y;
             int xx2 = child->m_x + child->m_width;
-            int yy2 = child->m_x + child->m_height;
+            int yy2 = child->m_y + child->m_height;
 
             // left
             if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
 
             // left
             if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
@@ -1417,6 +1493,26 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
 */
     }
 
 */
     }
 
+    // GDK sends surplus button down event
+    // before a double click event. We
+    // need to filter these out.
+    if (gdk_event->type == GDK_BUTTON_PRESS)
+    {
+        GdkEvent *peek_event = gdk_event_peek();
+        if (peek_event)
+        {
+            if (peek_event->type == GDK_2BUTTON_PRESS)
+            {
+                gdk_event_free( peek_event );
+                return TRUE;
+            }
+            else
+            {
+                gdk_event_free( peek_event );
+            }
+        }
+    }
+
     wxEventType event_type = wxEVT_NULL;
 
     if (gdk_event->button == 1)
     wxEventType event_type = wxEVT_NULL;
 
     if (gdk_event->button == 1)
@@ -1446,6 +1542,22 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
             default:  break;
         }
     }
             default:  break;
         }
     }
+    else if (gdk_event->button == 4)
+    {
+        switch (gdk_event->type)
+        {
+            case GDK_BUTTON_PRESS: event_type = wxEVT_MOUSEWHEEL; break;
+            default:  break;
+        }
+    }
+    else if (gdk_event->button == 5)
+    {
+        switch (gdk_event->type)
+        {
+            case GDK_BUTTON_PRESS: event_type = wxEVT_MOUSEWHEEL; break;
+            default:  break;
+        }
+    }
 
     if ( event_type == wxEVT_NULL )
     {
 
     if ( event_type == wxEVT_NULL )
     {
@@ -1477,6 +1589,20 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
     wxPrintf( wxT(".\n") );
 */
 
     wxPrintf( wxT(".\n") );
 */
 
+#ifndef __WXGTK20__
+    if (event_type == wxEVT_LEFT_DCLICK)
+    {
+        // GTK 1.2 crashes when intercepting double
+        // click events from both wxSpinButton and
+        // wxSpinCtrl
+        if (GTK_IS_SPIN_BUTTON(win->m_widget))
+        {
+            // Just disable this event for now.
+            return FALSE;
+        }
+    }
+#endif
+
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
@@ -1490,7 +1616,9 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
 // "button_release_event"
 //-----------------------------------------------------------------------------
 
 // "button_release_event"
 //-----------------------------------------------------------------------------
 
-static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
+static gint gtk_window_button_release_callback( GtkWidget *widget,
+                                                GdkEventButton *gdk_event,
+                                                wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
 
 {
     DEBUG_MAIN_THREAD
 
@@ -1503,21 +1631,25 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
 
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
 
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
-/*
-    printf( "OnButtonRelease from " );
-    if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-        printf( win->GetClassInfo()->GetClassName() );
-    printf( ".\n" );
-*/
-
     wxEventType event_type = wxEVT_NULL;
 
     switch (gdk_event->button)
     {
     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: return FALSE;
+        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:
+            // unknwon button, don't process
+            return FALSE;
     }
 
     wxMouseEvent event( event_type );
     }
 
     wxMouseEvent event( event_type );
@@ -1528,6 +1660,20 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
     // same wxListBox hack as above
     win->FixUpMouseEvent(widget, event.m_x, event.m_y);
 
     // same wxListBox hack as above
     win->FixUpMouseEvent(widget, event.m_x, event.m_y);
 
+    if ( event_type == wxEVT_RIGHT_UP )
+    {
+        // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
+        // except that:
+        //
+        // (a) it's a command event and so is propagated to the parent
+        // (b) under MSW 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()));
+        (void)win->GetEventHandler()->ProcessEvent(evtCtx);
+    }
+
     if ( !g_captureWindow )
         win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
 
     if ( !g_captureWindow )
         win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
 
@@ -1583,6 +1729,10 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
     {
         // synthetize a mouse enter or leave event if needed
         GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
     {
         // synthetize 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 )
         {
         bool hasMouse = winUnderMouse == gdk_event->window;
         if ( hasMouse != g_captureWindowHasMouse )
         {
@@ -1676,7 +1826,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
 #endif // wxUSE_CARET
 
     g_activeFrameLostFocus = FALSE;
 #endif // wxUSE_CARET
 
     g_activeFrameLostFocus = FALSE;
-    
+
     wxWindowGTK *active = wxGetTopLevelParent(win);
     if ( active != g_activeFrame )
     {
     wxWindowGTK *active = wxGetTopLevelParent(win);
     if ( active != g_activeFrame )
     {
@@ -1693,7 +1843,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
         wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
         event.SetEventObject(g_activeFrame);
         g_activeFrame->GetEventHandler()->ProcessEvent(event);
         wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
         event.SetEventObject(g_activeFrame);
         g_activeFrame->GetEventHandler()->ProcessEvent(event);
-        
+
         // Don't send focus events in addition to activate
         // if (win == g_activeFrame)
         //    return TRUE;
         // Don't send focus events in addition to activate
         // if (win == g_activeFrame)
         //    return TRUE;
@@ -1806,6 +1956,9 @@ gint gtk_window_enter_callback( GtkWidget *widget,
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
+    // Event was emitted after a grab
+    if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
     int x = 0;
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
     int x = 0;
@@ -1843,6 +1996,9 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
+    // Event was emitted after an ungrab
+    if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
     wxMouseEvent event( wxEVT_LEAVE_WINDOW );
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
     wxMouseEvent event( wxEVT_LEAVE_WINDOW );
@@ -1898,7 +2054,9 @@ static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
 
     win->m_oldVerticalPos = adjust->value;
 
 
     win->m_oldVerticalPos = adjust->value;
 
+#ifndef __WXGTK20__
     GtkScrolledWindow   *sw = GTK_SCROLLED_WINDOW(win->m_widget);
     GtkScrolledWindow   *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
     wxEventType         command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
 
     int value = (int)(adjust->value+0.5);
     wxEventType         command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
 
     int value = (int)(adjust->value+0.5);
@@ -1927,7 +2085,9 @@ static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
     float diff = adjust->value - win->m_oldHorizontalPos;
     if (fabs(diff) < 0.2) return;
 
     float diff = adjust->value - win->m_oldHorizontalPos;
     if (fabs(diff) < 0.2) return;
 
+#ifndef __WXGTK20__
     GtkScrolledWindow   *sw = GTK_SCROLLED_WINDOW(win->m_widget);
     GtkScrolledWindow   *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
     wxEventType         command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
 
     win->m_oldHorizontalPos = adjust->value;
     wxEventType         command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
 
     win->m_oldHorizontalPos = adjust->value;
@@ -2019,21 +2179,6 @@ wxWindow *wxWindowBase::FindFocus()
     return (wxWindow *)g_focusWindow;
 }
 
     return (wxWindow *)g_focusWindow;
 }
 
-//-----------------------------------------------------------------------------
-// "destroy" event
-//-----------------------------------------------------------------------------
-
-// VZ: Robert commented the code using out so it generates warnings: should
-//     be either fixed or removed completely
-#if 0
-
-static void gtk_window_destroy_callback( GtkWidget* widget, wxWindow *win )
-{
-    wxWindowDestroyEvent event(win);
-    win->GetEventHandler()->ProcessEvent(event);
-}
-
-#endif // 0
 
 //-----------------------------------------------------------------------------
 // "realize" from m_widget
 
 //-----------------------------------------------------------------------------
 // "realize" from m_widget
@@ -2043,7 +2188,7 @@ static void gtk_window_destroy_callback( GtkWidget* widget, wxWindow *win )
    been realized, so we do this directly after realization. */
 
 static gint
    been realized, so we do this directly after realization. */
 
 static gint
-gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
+gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
 {
     DEBUG_MAIN_THREAD
 
 {
     DEBUG_MAIN_THREAD
 
@@ -2056,6 +2201,14 @@ gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
     if (win->m_delayedForegroundColour)
         win->GtkSetForegroundColour( win->GetForegroundColour() );
 
     if (win->m_delayedForegroundColour)
         win->GtkSetForegroundColour( win->GetForegroundColour() );
 
+#ifdef __WXGTK20__
+    if (win->m_imContext)
+    {
+        GtkPizza *pizza = GTK_PIZZA( m_widget );
+        gtk_im_context_set_client_window( (GtkIMContext*) win->m_imContext, pizza->bin_window );
+    }
+#endif
+
     wxWindowCreateEvent event( win );
     event.SetEventObject( win );
     win->GetEventHandler()->ProcessEvent( event );
     wxWindowCreateEvent event( win );
     event.SetEventObject( win );
     win->GetEventHandler()->ProcessEvent( event );
@@ -2315,10 +2468,15 @@ void wxWindowGTK::Init()
     m_delayedForegroundColour = FALSE;
     m_delayedBackgroundColour = FALSE;
 
     m_delayedForegroundColour = FALSE;
     m_delayedBackgroundColour = FALSE;
 
+#ifdef __WXGTK20__
+    m_imContext = NULL;
+    m_x11Context = NULL;
+#else
 #ifdef HAVE_XIM
     m_ic = (GdkIC*) NULL;
     m_icattr = (GdkICAttr*) NULL;
 #endif
 #ifdef HAVE_XIM
     m_ic = (GdkIC*) NULL;
     m_icattr = (GdkICAttr*) NULL;
 #endif
+#endif
 }
 
 wxWindowGTK::wxWindowGTK()
 }
 
 wxWindowGTK::wxWindowGTK()
@@ -2353,9 +2511,9 @@ bool wxWindowGTK::Create( wxWindow *parent,
     }
 
     m_insertCallback = wxInsertChildInWindow;
     }
 
     m_insertCallback = wxInsertChildInWindow;
-    
+
     // always needed for background clearing
     // always needed for background clearing
-    m_delayedBackgroundColour = TRUE; 
+    m_delayedBackgroundColour = TRUE;
 
     m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
     GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
 
     m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
     GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
@@ -2439,6 +2597,17 @@ bool wxWindowGTK::Create( wxWindow *parent,
     gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
           (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
 
     gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
           (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
 
+#ifdef __WXGTK20__
+    // Create input method handler
+    m_imContext = (GtkIMMulticontext*) gtk_im_multicontext_new ();
+
+    // Cannot handle drawing preedited text yet
+    gtk_im_context_set_use_preedit( (GtkIMContext*) m_imContext, FALSE );
+
+    g_signal_connect (G_OBJECT (m_imContext), "commit",
+        G_CALLBACK (gtk_wxwindow_commit_cb), this);
+#endif
+
     gtk_widget_show( m_wxwindow );
 
     if (m_parent)
     gtk_widget_show( m_wxwindow );
 
     if (m_parent)
@@ -2455,6 +2624,8 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
 wxWindowGTK::~wxWindowGTK()
 {
 
 wxWindowGTK::~wxWindowGTK()
 {
+    SendDestroyEvent();
+
     if (g_focusWindow == this)
         g_focusWindow = NULL;
 
     if (g_focusWindow == this)
         g_focusWindow = NULL;
 
@@ -2562,7 +2733,18 @@ void wxWindowGTK::PostCreation()
                     GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
             }
 #else
                     GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
             }
 #else
-            gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
+            // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
+#endif
+
+#ifdef __WXGTK20__
+        // Create input method handler
+        m_imContext = (GtkIMMulticontext*) gtk_im_multicontext_new ();
+
+        // Cannot handle drawing preedited text yet
+        gtk_im_context_set_use_preedit( (GtkIMContext*) m_imContext, FALSE );
+
+        g_signal_connect (G_OBJECT (m_imContext), "commit",
+            G_CALLBACK (gtk_wxwindow_commit_cb), this);
 #endif
         }
 
 #endif
         }
 
@@ -2649,11 +2831,6 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
 
     gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
       GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
 
     gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
       GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
-      
-    // This keeps crashing on me. RR.
-    //
-    // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
-    //  GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
 }
 
 bool wxWindowGTK::Destroy()
 }
 
 bool wxWindowGTK::Destroy()
@@ -2808,7 +2985,7 @@ void wxWindowGTK::OnInternalIdle()
         }
         g_activeFrameLostFocus = FALSE;
     }
         }
         g_activeFrameLostFocus = FALSE;
     }
-    
+
     wxCursor cursor = m_cursor;
     if (g_globalCursor.Ok()) cursor = g_globalCursor;
 
     wxCursor cursor = m_cursor;
     if (g_globalCursor.Ok()) cursor = g_globalCursor;
 
@@ -3079,6 +3256,11 @@ bool wxWindowGTK::Show( bool show )
     else
         gtk_widget_hide( m_widget );
 
     else
         gtk_widget_hide( m_widget );
 
+    wxShowEvent eventShow(GetId(), show);
+    eventShow.m_eventObject = this;
+
+    GetEventHandler()->ProcessEvent(eventShow);
+
     return TRUE;
 }
 
     return TRUE;
 }
 
@@ -3124,9 +3306,31 @@ int wxWindowGTK::GetCharHeight() const
 
     wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
 
 
     wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
 
+#ifdef __WXGTK20__
+    PangoContext *context = NULL;
+    if (m_widget)
+        context = gtk_widget_get_pango_context( m_widget );
+
+    if (!context)
+        return 0;
+
+    PangoFontDescription *desc = m_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( G_OBJECT( layout ) );
+
+    return (int) (rect.height / PANGO_SCALE);
+#else
     GdkFont *font = m_font.GetInternalFont( 1.0 );
 
     return font->ascent + font->descent;
     GdkFont *font = m_font.GetInternalFont( 1.0 );
 
     return font->ascent + font->descent;
+#endif
 }
 
 int wxWindowGTK::GetCharWidth() const
 }
 
 int wxWindowGTK::GetCharWidth() const
@@ -3135,9 +3339,31 @@ int wxWindowGTK::GetCharWidth() const
 
     wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
 
 
     wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
 
+#ifdef __WXGTK20__
+    PangoContext *context = NULL;
+    if (m_widget)
+        context = gtk_widget_get_pango_context( m_widget );
+
+    if (!context)
+        return 0;
+
+    PangoFontDescription *desc = m_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( G_OBJECT( layout ) );
+
+    return (int) (rect.width / PANGO_SCALE);
+#else
     GdkFont *font = m_font.GetInternalFont( 1.0 );
 
     return gdk_string_width( font, "H" );
     GdkFont *font = m_font.GetInternalFont( 1.0 );
 
     return gdk_string_width( font, "H" );
+#endif
 }
 
 void wxWindowGTK::GetTextExtent( const wxString& string,
 }
 
 void wxWindowGTK::GetTextExtent( const wxString& string,
@@ -3151,26 +3377,26 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
     if (theFont) fontToUse = *theFont;
 
     wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
     if (theFont) fontToUse = *theFont;
 
     wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
-    
+
     if (string.IsEmpty())
     {
         if (x) (*x) = 0;
         if (y) (*y) = 0;
         return;
     }
     if (string.IsEmpty())
     {
         if (x) (*x) = 0;
         if (y) (*y) = 0;
         return;
     }
-#ifdef __WXGTK20__
 
 
+#ifdef __WXGTK20__
     PangoContext *context = NULL;
     if (m_widget)
     PangoContext *context = NULL;
     if (m_widget)
-        gtk_widget_get_pango_context( m_widget );
-        
+        context = gtk_widget_get_pango_context( m_widget );
+
     if (!context)
     {
         if (x) (*x) = 0;
         if (y) (*y) = 0;
         return;
     }
     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);
     PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
     PangoLayout *layout = pango_layout_new(context);
     pango_layout_set_font_description(layout, desc);
@@ -3185,10 +3411,10 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
 #endif
     }
     PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
 #endif
     }
     PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
     PangoRectangle rect;
     pango_layout_line_get_extents(line, NULL, &rect);
     PangoRectangle rect;
     pango_layout_line_get_extents(line, NULL, &rect);
-       
+
     if (x) (*x) = (wxCoord) (rect.width / PANGO_SCALE);
     if (y) (*y) = (wxCoord) (rect.height / PANGO_SCALE);
     if (descent)
     if (x) (*x) = (wxCoord) (rect.width / PANGO_SCALE);
     if (y) (*y) = (wxCoord) (rect.height / PANGO_SCALE);
     if (descent)
@@ -3197,7 +3423,7 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
         (*descent) = 0;
     }
     if (externalLeading) (*externalLeading) = 0;  // ??
         (*descent) = 0;
     }
     if (externalLeading) (*externalLeading) = 0;  // ??
-    
+
     g_object_unref( G_OBJECT( layout ) );
 #else
     GdkFont *font = fontToUse.GetInternalFont( 1.0 );
     g_object_unref( G_OBJECT( layout ) );
 #else
     GdkFont *font = fontToUse.GetInternalFont( 1.0 );
@@ -3374,11 +3600,23 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
 {
     if (!m_widget) return;
     if (!m_widget->window) return;
 {
     if (!m_widget) return;
     if (!m_widget->window) return;
-    
+
 #ifndef __WXGTK20__
     if (g_isIdle)
         wxapp_install_idle_handler();
 #ifndef __WXGTK20__
     if (g_isIdle)
         wxapp_install_idle_handler();
-        
+
+    wxRect myRect(0,0,0,0);
+    if (m_wxwindow && rect)
+    {
+        myRect.SetSize(wxSize( m_wxwindow->allocation.width,
+                               m_wxwindow->allocation.height));
+        myRect.Intersect(*rect);
+        if (!myRect.width || !myRect.height)
+            // nothing to do, rectangle is empty
+            return;
+        rect = &myRect;
+    }
+
     if (eraseBackground && m_wxwindow && m_wxwindow->window)
     {
         if (rect)
     if (eraseBackground && m_wxwindow && m_wxwindow->window)
     {
         if (rect)
@@ -3464,7 +3702,7 @@ void wxWindowGTK::GtkSendPaintEvents()
 {
     if (!m_wxwindow)
     {
 {
     if (!m_wxwindow)
     {
-#ifndef __WXGTK20__    
+#ifndef __WXGTK20__
         m_clearRegion.Clear();
 #endif
         m_updateRegion.Clear();
         m_clearRegion.Clear();
 #endif
         m_updateRegion.Clear();
@@ -3477,7 +3715,7 @@ void wxWindowGTK::GtkSendPaintEvents()
 #ifndef __WXGTK20__
     // widget to draw on
     GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
 #ifndef __WXGTK20__
     // widget to draw on
     GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
-            
+
     // later for GTK 2.0, too.
     if (GetThemeEnabled())
     {
     // later for GTK 2.0, too.
     if (GetThemeEnabled())
     {
@@ -3487,7 +3725,7 @@ void wxWindowGTK::GtkSendPaintEvents()
             parent = parent->GetParent();
         if (!parent)
             parent = (wxWindow*)this;
             parent = parent->GetParent();
         if (!parent)
             parent = (wxWindow*)this;
-    
+
         wxRegionIterator upd( m_updateRegion );
         while (upd)
         {
         wxRegionIterator upd( m_updateRegion );
         while (upd)
         {
@@ -3496,7 +3734,7 @@ void wxWindowGTK::GtkSendPaintEvents()
             rect.y = upd.GetY();
             rect.width = upd.GetWidth();
             rect.height = upd.GetHeight();
             rect.y = upd.GetY();
             rect.width = upd.GetWidth();
             rect.height = upd.GetHeight();
-                    
+
             gtk_paint_flat_box( parent->m_widget->style,
                         pizza->bin_window,
                         GTK_STATE_NORMAL,
             gtk_paint_flat_box( parent->m_widget->style,
                         pizza->bin_window,
                         GTK_STATE_NORMAL,
@@ -3505,7 +3743,7 @@ void wxWindowGTK::GtkSendPaintEvents()
                         parent->m_widget,
                         (char *)"base",
                         0, 0, -1, -1 );
                         parent->m_widget,
                         (char *)"base",
                         0, 0, -1, -1 );
-                        
+
             upd ++;
         }
     }
             upd ++;
         }
     }
@@ -3576,7 +3814,7 @@ void wxWindowGTK::GtkSendPaintEvents()
     {
         GtkPizzaChild *child = (GtkPizzaChild*) children->data;
         children = children->next;
     {
         GtkPizzaChild *child = (GtkPizzaChild*) children->data;
         children = children->next;
-        
+
         if (GTK_WIDGET_NO_WINDOW (child->widget) &&
             GTK_WIDGET_DRAWABLE (child->widget))
         {
         if (GTK_WIDGET_NO_WINDOW (child->widget) &&
             GTK_WIDGET_DRAWABLE (child->widget))
         {
@@ -3622,7 +3860,7 @@ void wxWindowGTK::Clear()
         m_clearRegion.Clear();
         wxSize size( GetClientSize() );
         m_clearRegion.Union( 0,0,size.x,size.y );
         m_clearRegion.Clear();
         wxSize size( GetClientSize() );
         m_clearRegion.Union( 0,0,size.x,size.y );
-        
+
         // Better do this in idle?
         GtkUpdate();
     }
         // Better do this in idle?
         GtkUpdate();
     }
@@ -3653,10 +3891,10 @@ void wxWindowGTK::GtkSetBackgroundColour( const wxColour &colour )
         window = GetConnectWidget()->window;
 
     wxASSERT( window );
         window = GetConnectWidget()->window;
 
     wxASSERT( window );
-    
+
     // We need the pixel value e.g. for background clearing.
     m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
     // We need the pixel value e.g. for background clearing.
     m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
-    
+
     if (m_wxwindow)
     {
         // wxMSW doesn't clear the window here, either.
     if (m_wxwindow)
     {
         // wxMSW doesn't clear the window here, either.
@@ -3740,6 +3978,21 @@ bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
     return TRUE;
 }
 
     return TRUE;
 }
 
+#ifdef __WXGTK20__
+PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
+{
+    return gtk_widget_get_pango_context( m_widget );
+}
+
+PangoContext *wxWindowGTK::GtkGetPangoX11Context()
+{
+    if (!m_x11Context)
+        m_x11Context = pango_x_get_context( gdk_display );
+
+    return m_x11Context;
+}
+#endif
+
 GtkStyle *wxWindowGTK::GetWidgetStyle()
 {
     if (m_widgetStyle)
 GtkStyle *wxWindowGTK::GetWidgetStyle()
 {
     if (m_widgetStyle)
@@ -3792,7 +4045,13 @@ void wxWindowGTK::SetWidgetStyle()
 
     if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
     {
 
     if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
     {
-        SET_STYLE_FONT(style, m_font.GetInternalFont( 1.0 ));
+#ifdef __WXGTK20__
+        pango_font_description_free( style->font_desc );
+        style->font_desc = pango_font_description_copy( m_font.GetNativeFontInfo()->description );
+#else
+        gdk_font_unref( style->font );
+        style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
+#endif
     }
 
     if (m_foregroundColour.Ok())
     }
 
     if (m_foregroundColour.Ok())
@@ -4237,7 +4496,7 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
     wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
     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;
 
     // No scrolling requested.
     if ((dx == 0) && (dy == 0)) return;
 
@@ -4261,21 +4520,13 @@ void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
         GetClientSize( &cw, &ch );
         m_clearRegion.Intersect( 0, 0, cw, ch );
     }
         GetClientSize( &cw, &ch );
         m_clearRegion.Intersect( 0, 0, cw, ch );
     }
+#endif
+
     m_clipPaintRegion = TRUE;
 
     gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
 
     m_clipPaintRegion = FALSE;
     m_clipPaintRegion = TRUE;
 
     gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
 
     m_clipPaintRegion = FALSE;
-#else
-    wxCHECK_RET( GTK_PIZZA(m_wxwindow)->bin_window != NULL, wxT("window needs client area for scrolling") );
-
-    gdk_window_scroll( GTK_PIZZA(m_wxwindow)->bin_window, dx, dy );
-
-    GTK_PIZZA(m_wxwindow)->xoffset += dx;
-    GTK_PIZZA(m_wxwindow)->yoffset += dy;
-
-#endif
-
 }
 
 
 }
 
 
@@ -4302,10 +4553,8 @@ wxPoint wxGetMousePosition()
 
     int x, y;
     GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
 
     int x, y;
     GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
-    if (!windowAtPtr)
-      return wxPoint(-999, -999);
 
 
-    Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
+    Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
     Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
     Window rootReturn, childReturn;
     int rootX, rootY, winX, winY;
     Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
     Window rootReturn, childReturn;
     int rootX, rootY, winX, winY;