]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
marked dbkeyg.h as a wxBase file (fixes 685857)
[wxWidgets.git] / src / gtk / window.cpp
index 76c5596cc050a22b41bd7c5db462a053ce9442b8..acc7d12ca243f3efa74f6415124d6da12341e490 100644 (file)
 
 #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
@@ -262,7 +266,7 @@ extern bool g_mainThreadLocked;
 //-----------------------------------------------------------------------------
 
 #ifndef __WXGTK20__
-#define DISABLE_STYLE_IF_BROKEN_THEME 1
+#define DISABLE_STYLE_IF_BROKEN_THEME 0
 #endif
 
 #ifdef __WXDEBUG__
@@ -501,10 +505,10 @@ static int gtk_window_expose_callback( GtkWidget *widget,
     // 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())
     {
@@ -522,13 +526,14 @@ static int gtk_window_expose_callback( GtkWidget *widget,
 
     win->GtkSendPaintEvents();
 
+
     // 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.
-    
+
     win->GetUpdateRegion().Union( gdk_event->area.x,
                                   gdk_event->area.y,
                                   gdk_event->area.width,
@@ -1060,6 +1065,7 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
     return TRUE;
 }
 
+#ifndef __WXGTK20__
 static gint gtk_window_key_press_callback( GtkWidget *widget,
                                            GdkEventKey *gdk_event,
                                            wxWindow *win )
@@ -1130,7 +1136,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
             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())
@@ -1174,50 +1180,217 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     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 );
+        // 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 )
+        {
+            btnCancel = winForCancel->FindWindow(wxID_CANCEL);
+            if ( btnCancel )
+            {
+                // found a cancel button
+                break;
+            }
+
+            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);
+        }
     }
 
-    // Doesn't work.
-#if 0 
-    // Pressing F10 will activate the menu bar of the top frame
-    if ( (!ret) &&
-         (gdk_event->keyval == GDK_F10) )
+    if (ret)
     {
-        wxWindowGTK *ancestor = win;
-        while (ancestor)
+        gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
+        return TRUE;
+    }
+
+    return FALSE;
+}
+#endif
+
+#ifdef __WXGTK20__
+static gint gtk_window_key_press_callback( GtkWidget *widget,
+                                           GdkEventKey *gdk_event,
+                                           wxWindow *win )
+{
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+
+    if (!win->m_hasVMT)
+        return FALSE;
+    if (g_blockEventsOnDrag)
+        return FALSE;
+
+    bool ret = FALSE;
+    bool dont_use_IM = FALSE;
+
+    wxKeyEvent event( wxEVT_KEY_DOWN );
+    long keycode = wxTranslateKeySymToWXKey( gdk_event->keyval, FALSE );
+    if (keycode)
+    {
+        // We were able to decode the key press without
+        // any input method, so don't use it.
+        dont_use_IM = TRUE;
+
+        // now fill all the other fields
+        int x = 0;
+        int y = 0;
+        GdkModifierType state;
+        if (gdk_event->window)
+            gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+
+        event.SetTimestamp( gdk_event->time );
+        event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
+        event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
+        event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
+        event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
+        event.m_keyCode = keycode;
+        event.m_scanCode = gdk_event->keyval;
+        event.m_rawCode = (wxUint32) gdk_event->keyval;
+        event.m_rawFlags = 0;
+        event.m_x = x;
+        event.m_y = y;
+        event.SetEventObject( win );
+
+        // send key down event
+        ret = win->GetEventHandler()->ProcessEvent( event );
+
+        if (!ret)
         {
-            if (wxIsKindOf(ancestor,wxFrame))
+            // Implement OnCharHook by checking ancesteror top level windows
+            wxWindow *parent = win;
+            while (parent && !parent->IsTopLevel())
+            parent = parent->GetParent();
+            if (parent)
             {
-                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;
-                    }
-                }
+                event.SetEventType( wxEVT_CHAR_HOOK );
+                ret = parent->GetEventHandler()->ProcessEvent( event );
+            }
+
+            if (!ret)
+            {
+                event.SetEventType(wxEVT_CHAR);
+                ret = win->GetEventHandler()->ProcessEvent( event );
+            }
+        }
+
+        // win is a control: tab can be propagated up
+        if ( !ret &&
+             ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
+            win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
+        {
+            wxNavigationKeyEvent new_event;
+            new_event.SetEventObject( win->GetParent() );
+            // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
+            new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
+            // CTRL-TAB changes the (parent) window, i.e. switch notebook page
+            new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
+            new_event.SetCurrentFocus( win );
+            ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
+        }
+
+        if ( !ret &&
+             (gdk_event->keyval == GDK_Escape) )
+        {
+            wxWindow *winForCancel = win, *btnCancel = NULL;
+            while ( winForCancel )
+            {
+                btnCancel = winForCancel->FindWindow(wxID_CANCEL);
+                if ( btnCancel ) break;
+
+                if ( winForCancel->IsTopLevel() ) break;
+
+                winForCancel = winForCancel->GetParent();
+            }
+
+            if ( btnCancel )
+            {
+                wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
+                event.SetEventObject(btnCancel);
+                ret = btnCancel->GetEventHandler()->ProcessEvent(event);
             }
-            ancestor = ancestor->GetParent();
         }
     }
-#endif // 0
 
     if (ret)
     {
         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
         return TRUE;
     }
-    
+
+    if (!dont_use_IM && win->m_imContext)
+    {
+        // 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.
+        gtk_im_context_filter_keypress ( (GtkIMContext*) win->m_imContext, gdk_event );
+
+        return TRUE;
+    }
+
     return FALSE;
 }
 
+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
+
+    if (!ret)
+    {
+        // Implement OnCharHook by checking ancesteror 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
 //-----------------------------------------------------------------------------
@@ -1275,6 +1448,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);                \
+    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;                                 \
@@ -1331,12 +1511,12 @@ wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
         yy += pizza->yoffset;
     }
 
-    wxNode *node = win->GetChildren().First();
+    wxWindowList::Node  *node = win->GetChildren().GetFirst();
     while (node)
     {
-        wxWindowGTK *child = (wxWindowGTK*)node->Data();
+        wxWindowGTK *child = node->GetData();
 
-        node = node->Next();
+        node = node->GetNext();
         if (!child->IsShown())
             continue;
 
@@ -1419,6 +1599,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)
@@ -1448,6 +1648,22 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
             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 )
     {
@@ -1479,6 +1695,20 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
     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" );
@@ -1492,7 +1722,9 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
 // "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
 
@@ -1505,21 +1737,25 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
 
     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)
     {
-        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 );
@@ -1530,6 +1766,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);
 
+    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);
 
@@ -1662,7 +1912,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
 
     wxLogTrace(TRACE_FOCUS,
                _T("%s: focus in"), win->GetName().c_str());
-
+    
 #ifdef HAVE_XIM
     if (win->m_ic)
         gdk_im_begin(win->m_ic, win->m_wxwindow->window);
@@ -1678,7 +1928,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
 #endif // wxUSE_CARET
 
     g_activeFrameLostFocus = FALSE;
-    
+
     wxWindowGTK *active = wxGetTopLevelParent(win);
     if ( active != g_activeFrame )
     {
@@ -1695,7 +1945,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);
-        
+
         // Don't send focus events in addition to activate
         // if (win == g_activeFrame)
         //    return TRUE;
@@ -1900,7 +2150,9 @@ static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
 
     win->m_oldVerticalPos = adjust->value;
 
+#ifndef __WXGTK20__
     GtkScrolledWindow   *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
     wxEventType         command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
 
     int value = (int)(adjust->value+0.5);
@@ -1929,7 +2181,9 @@ static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
     float diff = adjust->value - win->m_oldHorizontalPos;
     if (fabs(diff) < 0.2) return;
 
+#ifndef __WXGTK20__
     GtkScrolledWindow   *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
     wxEventType         command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
 
     win->m_oldHorizontalPos = adjust->value;
@@ -2045,7 +2299,7 @@ static void gtk_window_destroy_callback( GtkWidget* widget, wxWindow *win )
    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
 
@@ -2058,6 +2312,14 @@ gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
     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 );
@@ -2317,10 +2579,15 @@ void wxWindowGTK::Init()
     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
+#endif
 }
 
 wxWindowGTK::wxWindowGTK()
@@ -2355,9 +2622,9 @@ bool wxWindowGTK::Create( wxWindow *parent,
     }
 
     m_insertCallback = wxInsertChildInWindow;
-    
+
     // 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 );
@@ -2441,6 +2708,17 @@ bool wxWindowGTK::Create( wxWindow *parent,
     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)
@@ -2564,7 +2842,18 @@ void wxWindowGTK::PostCreation()
                     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
         }
 
@@ -2651,7 +2940,7 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
 
     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",
@@ -2810,7 +3099,7 @@ void wxWindowGTK::OnInternalIdle()
         }
         g_activeFrameLostFocus = FALSE;
     }
-    
+
     wxCursor cursor = m_cursor;
     if (g_globalCursor.Ok()) cursor = g_globalCursor;
 
@@ -3081,6 +3370,11 @@ bool wxWindowGTK::Show( bool show )
     else
         gtk_widget_hide( m_widget );
 
+    wxShowEvent eventShow(GetId(), show);
+    eventShow.m_eventObject = this;
+
+    GetEventHandler()->ProcessEvent(eventShow);
+
     return TRUE;
 }
 
@@ -3126,9 +3420,31 @@ int wxWindowGTK::GetCharHeight() const
 
     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;
+#endif
 }
 
 int wxWindowGTK::GetCharWidth() const
@@ -3137,9 +3453,31 @@ int wxWindowGTK::GetCharWidth() const
 
     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" );
+#endif
 }
 
 void wxWindowGTK::GetTextExtent( const wxString& string,
@@ -3153,26 +3491,26 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
     if (theFont) fontToUse = *theFont;
 
     wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
-    
+
     if (string.IsEmpty())
     {
         if (x) (*x) = 0;
         if (y) (*y) = 0;
         return;
     }
-#ifdef __WXGTK20__
 
+#ifdef __WXGTK20__
     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;
     }
-    
+
     PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
     PangoLayout *layout = pango_layout_new(context);
     pango_layout_set_font_description(layout, desc);
@@ -3187,10 +3525,10 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
 #endif
     }
     PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
     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)
@@ -3199,7 +3537,7 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
         (*descent) = 0;
     }
     if (externalLeading) (*externalLeading) = 0;  // ??
-    
+
     g_object_unref( G_OBJECT( layout ) );
 #else
     GdkFont *font = fontToUse.GetInternalFont( 1.0 );
@@ -3376,11 +3714,11 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
 {
     if (!m_widget) return;
     if (!m_widget->window) return;
-    
+
 #ifndef __WXGTK20__
     if (g_isIdle)
         wxapp_install_idle_handler();
-        
+
     if (eraseBackground && m_wxwindow && m_wxwindow->window)
     {
         if (rect)
@@ -3466,7 +3804,7 @@ void wxWindowGTK::GtkSendPaintEvents()
 {
     if (!m_wxwindow)
     {
-#ifndef __WXGTK20__    
+#ifndef __WXGTK20__
         m_clearRegion.Clear();
 #endif
         m_updateRegion.Clear();
@@ -3479,7 +3817,7 @@ void wxWindowGTK::GtkSendPaintEvents()
 #ifndef __WXGTK20__
     // widget to draw on
     GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
-            
+
     // later for GTK 2.0, too.
     if (GetThemeEnabled())
     {
@@ -3489,7 +3827,7 @@ void wxWindowGTK::GtkSendPaintEvents()
             parent = parent->GetParent();
         if (!parent)
             parent = (wxWindow*)this;
-    
+
         wxRegionIterator upd( m_updateRegion );
         while (upd)
         {
@@ -3498,7 +3836,7 @@ void wxWindowGTK::GtkSendPaintEvents()
             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,
@@ -3507,7 +3845,7 @@ void wxWindowGTK::GtkSendPaintEvents()
                         parent->m_widget,
                         (char *)"base",
                         0, 0, -1, -1 );
-                        
+
             upd ++;
         }
     }
@@ -3578,7 +3916,7 @@ void wxWindowGTK::GtkSendPaintEvents()
     {
         GtkPizzaChild *child = (GtkPizzaChild*) children->data;
         children = children->next;
-        
+
         if (GTK_WIDGET_NO_WINDOW (child->widget) &&
             GTK_WIDGET_DRAWABLE (child->widget))
         {
@@ -3624,7 +3962,7 @@ void wxWindowGTK::Clear()
         m_clearRegion.Clear();
         wxSize size( GetClientSize() );
         m_clearRegion.Union( 0,0,size.x,size.y );
-        
+
         // Better do this in idle?
         GtkUpdate();
     }
@@ -3655,10 +3993,10 @@ void wxWindowGTK::GtkSetBackgroundColour( const wxColour &colour )
         window = GetConnectWidget()->window;
 
     wxASSERT( 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.
@@ -3742,6 +4080,21 @@ bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
     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)
@@ -3794,7 +4147,13 @@ void wxWindowGTK::SetWidgetStyle()
 
     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 );
+        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())
@@ -4239,7 +4598,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") );
-    
+
     // No scrolling requested.
     if ((dx == 0) && (dy == 0)) return;
 
@@ -4296,10 +4655,8 @@ wxPoint wxGetMousePosition()
 
     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;