]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
oops, fixed typo breaking iconv constness detection in the previous commit
[wxWidgets.git] / src / gtk / window.cpp
index 71c1df2f66e1bb4ec48b033569255c03b6519ed5..a6f5fa3652b3b38889dc684b7b0d69be7e3ef779 100644 (file)
@@ -486,10 +486,21 @@ static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNU
 
 static long map_to_unmodified_wx_keysym( GdkEventKey *event )
 {
+    // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
+    //     but only event->keyval which is quite useless to us, so remember
+    //     the last character from GDK_KEY_PRESS and resue it as last resort
+    //
+    // NB: should be MT-neutral as always called from main thread only
+    static struct
+    {
+        KeySym keysym;
+        long   keycode;
+    } s_lastKeyPress = { 0, 0 };
+
     KeySym keysym = event->keyval;
-    guint key_code = 0;
+    long key_code;
 
-    switch (keysym)
+    switch ( keysym )
     {
         case GDK_Shift_L:
         case GDK_Shift_R:       key_code = WXK_SHIFT;       break;
@@ -582,20 +593,45 @@ static long map_to_unmodified_wx_keysym( GdkEventKey *event )
         case GDK_F12:           key_code = WXK_F12;         break;
         default:
         {
-        if (event->length == 1)
-        {
-            key_code = toupper( (unsigned char)*event->string );
-        }
-        else if ((keysym & 0xFF) == keysym)
+            // do we have the translation?
+            if ( event->length == 1 )
             {
-                guint upper = gdk_keyval_to_upper( (guint)keysym );
-                keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */
-                key_code = (guint)keysym;
+                keysym = (KeySym)event->string[0];
+            }
+            else if ( (keysym & 0xFF) != keysym )
+            {
+                // non ASCII key, what to do?
+
+                if ( event->type == GDK_KEY_RELEASE )
+                {
+                    // reuse the one from the last keypress if any
+                    if ( keysym == s_lastKeyPress.keysym )
+                    {
+                        key_code = s_lastKeyPress.keycode;
+
+                        // skip "return 0"
+                        break;
+                    }
+                }
+
+                // ignore this one, we don't know it
+                return 0;
+            }
+            //else: ASCII key, ok
+
+            guint upper = gdk_keyval_to_upper( (guint)keysym );
+            key_code = upper ? upper : keysym;
+
+            if ( event->type == GDK_KEY_PRESS )
+            {
+                // remember it to be reused below later
+                s_lastKeyPress.keysym = keysym;
+                s_lastKeyPress.keycode = key_code;
             }
         }
     }
 
-    return (key_code);
+    return key_code;
 }
 
 static long map_to_wx_keysym( GdkEventKey *event )
@@ -685,19 +721,17 @@ static long map_to_wx_keysym( GdkEventKey *event )
         case GDK_F11:           key_code = WXK_F11;         break;
         case GDK_F12:           key_code = WXK_F12;         break;
         default:
-        {
-        if (event->length == 1)
-        {
-            key_code = (unsigned char)*event->string;
-        }
-        else if ((keysym & 0xFF) == keysym)
+            if (event->length == 1)
+            {
+                key_code = (unsigned char)*event->string;
+            }
+            else if ((keysym & 0xFF) == keysym)
             {
                 key_code = (guint)keysym;
             }
-        }
     }
 
-    return (key_code);
+    return key_code;
 }
 
 //-----------------------------------------------------------------------------
@@ -751,8 +785,14 @@ static int gtk_window_expose_callback( GtkWidget *widget,
         if (!parent)
             parent = win;
 
-        gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
-            GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
+        gtk_paint_flat_box (parent->m_widget->style,
+                            pizza->bin_window,
+                            GTK_STATE_NORMAL,
+                            GTK_SHADOW_NONE,
+                            &gdk_event->area,
+                            parent->m_widget,
+                            (char *)"base",
+                            0, 0, -1, -1);
     }
 
     win->GetUpdateRegion().Union( gdk_event->area.x,
@@ -894,8 +934,14 @@ static void gtk_window_draw_callback( GtkWidget *widget,
         if (!parent)
             parent = win;
 
-        gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
-            GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
+        gtk_paint_flat_box (parent->m_widget->style,
+                            pizza->bin_window,
+                            GTK_STATE_NORMAL,
+                            GTK_SHADOW_NONE,
+                            rect,
+                            parent->m_widget,
+                            (char *)"base",
+                            0, 0, -1, -1);
     }
 
 
@@ -967,6 +1013,9 @@ static void gtk_window_draw_callback( GtkWidget *widget,
 // "key_press_event" from any window
 //-----------------------------------------------------------------------------
 
+// turn on to see the key event codes on the console
+#undef DEBUG_KEY_EVENTS
+
 static gint gtk_window_key_press_callback( GtkWidget *widget,
                                            GdkEventKey *gdk_event,
                                            wxWindow *win )
@@ -980,23 +1029,23 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     if (g_blockEventsOnDrag) return FALSE;
 
 
-/*
-    wxString tmp;
-    tmp += (char)gdk_event->keyval;
-    printf( "KeyDown-Code is: %s.\n", tmp.c_str() );
-    printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
-*/
-
     int x = 0;
     int y = 0;
     GdkModifierType state;
-    if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+    if (gdk_event->window)
+        gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
 
     bool ret = FALSE;
 
     long key_code = map_to_unmodified_wx_keysym( gdk_event );
+
+#ifdef DEBUG_KEY_EVENTS
+    wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code);
+#endif // DEBUG_KEY_EVENTS
+
     /* sending unknown key events doesn't really make sense */
-    if (key_code == 0) return FALSE;
+    if (key_code == 0)
+        return FALSE;
 
     wxKeyEvent event( wxEVT_KEY_DOWN );
     event.SetTimestamp( gdk_event->time );
@@ -1031,39 +1080,37 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     }
 #endif // wxUSE_ACCEL
 
-    /* wxMSW doesn't send char events with Alt pressed */
     /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
        will only be sent if it is not in an accelerator table. */
-    key_code = map_to_wx_keysym( gdk_event );
-
-    if ( (!ret) &&
-         (key_code != 0))
+    if ( !ret )
     {
-        wxKeyEvent event2( wxEVT_CHAR );
-        event2.SetTimestamp( gdk_event->time );
-        event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
-        event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
-        event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
-        event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
-        event2.m_keyCode = key_code;
-        event2.m_scanCode = gdk_event->keyval;
-        event2.m_x = x;
-        event2.m_y = y;
-        event2.SetEventObject( win );
-        ret = win->GetEventHandler()->ProcessEvent( event2 );
+        key_code = map_to_wx_keysym( gdk_event );
+
+        if ( key_code )
+        {
+#ifdef DEBUG_KEY_EVENTS
+            wxPrintf(_T("Char event: %ld\n"), key_code);
+#endif // DEBUG_KEY_EVENTS
+
+            // reuse the ame event object, just change its type and use the
+            // translated keycode instead of the raw one
+            event.SetEventType(wxEVT_CHAR);
+            event.m_keyCode = key_code;
+
+            ret = win->GetEventHandler()->ProcessEvent( event );
+        }
     }
 
     /* win is a control: tab can be propagated up */
-    if ( (!ret) &&
+    if ( !ret &&
          ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
 //     have this style, yet choose not to process this particular TAB in which
 //     case TAB must still work as a navigational character
 #if 0
-         (!win->HasFlag(wxTE_PROCESS_TAB)) &&
+         !win->HasFlag(wxTE_PROCESS_TAB) &&
 #endif // 0
-         (win->GetParent()) &&
-         (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
+         win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
     {
         wxNavigationKeyEvent new_event;
         new_event.SetEventObject( win->GetParent() );
@@ -1076,7 +1123,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     }
 
     /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
-    if ( (!ret) &&
+    if ( !ret &&
          (gdk_event->keyval == GDK_Escape) )
     {
         wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
@@ -1084,10 +1131,9 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
         ret = win->GetEventHandler()->ProcessEvent( new_event );
     }
 
-#if (GTK_MINOR_VERSION > 0)
-    /* Pressing F10 will activate the menu bar of the top frame. */
     /* Doesn't work. */
-/*
+#if 0 // (GTK_MINOR_VERSION > 0)
+    /* Pressing F10 will activate the menu bar of the top frame. */
     if ( (!ret) &&
          (gdk_event->keyval == GDK_F10) )
     {
@@ -1113,8 +1159,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
             ancestor = ancestor->GetParent();
         }
     }
-*/
-#endif
+#endif // 0
 
     if (ret)
     {
@@ -1139,28 +1184,20 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
-/*
-    printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
-    if (gdk_event->state & GDK_SHIFT_MASK)
-      printf( "ShiftDown.\n" );
-    else
-      printf( "ShiftUp.\n" );
-    if (gdk_event->state & GDK_CONTROL_MASK)
-      printf( "ControlDown.\n" );
-    else
-      printf( "ControlUp.\n" );
-    printf( "\n" );
-*/
-
     long key_code = map_to_unmodified_wx_keysym( gdk_event );
 
+#ifdef DEBUG_KEY_EVENTS
+    wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code);
+#endif // DEBUG_KEY_EVENTS
+
     /* sending unknown key events doesn't really make sense */
     if (key_code == 0) return FALSE;
 
     int x = 0;
     int y = 0;
     GdkModifierType state;
-    if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+    if (gdk_event->window)
+        gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
 
     wxKeyEvent event( wxEVT_KEY_UP );
     event.SetTimestamp( gdk_event->time );
@@ -1183,6 +1220,27 @@ static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk
     return FALSE;
 }
 
+// ============================================================================
+// the mouse events
+// ============================================================================
+
+// init wxMouseEvent with the info from gdk_event
+#define InitMouseEvent(win, event, gdk_event) \
+    { \
+    event.SetTimestamp( gdk_event->time ); \
+    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
+    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
+    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
+    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
+    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
+    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
+    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
+\
+    wxPoint pt = win->GetClientAreaOrigin(); \
+    event.m_x = (wxCoord)gdk_event->x - pt.x; \
+    event.m_y = (wxCoord)gdk_event->y - pt.y; \
+    }
+
 // ----------------------------------------------------------------------------
 // mouse event processing helper
 // ----------------------------------------------------------------------------
@@ -1295,20 +1353,18 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton
     }
 
     wxMouseEvent event( event_type );
-    event.SetTimestamp( gdk_event->time );
-    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
-    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
-    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
-    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
-    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
-    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
-    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
-
-    event.m_x = (wxCoord)gdk_event->x;
-    event.m_y = (wxCoord)gdk_event->y;
+    InitMouseEvent( win, event, gdk_event );
 
     AdjustEventButtonState(event);
 
+    // wxListBox actually get mouse events from the item
+
+    if (win->m_isListBox)
+    {
+        event.m_x += widget->allocation.x;
+        event.m_y += widget->allocation.y;
+    }
+
     // Some control don't have their own X window and thus cannot get
     // any events.
 
@@ -1428,19 +1484,18 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
     }
 
     wxMouseEvent event( event_type );
-    event.SetTimestamp( gdk_event->time );
-    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
-    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
-    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
-    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
-    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
-    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
-    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
-    event.m_x = (wxCoord)gdk_event->x;
-    event.m_y = (wxCoord)gdk_event->y;
+    InitMouseEvent( win, event, gdk_event );
 
     AdjustEventButtonState(event);
 
+    // wxListBox actually get mouse events from the item
+
+    if (win->m_isListBox)
+    {
+        event.m_x += widget->allocation.x;
+        event.m_y += widget->allocation.y;
+    }
+
     // Some control don't have their own X window and thus cannot get
     // any events.
 
@@ -1516,24 +1571,6 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
     return FALSE;
 }
 
-// ============================================================================
-// the mouse events
-// ============================================================================
-
-// init wxMouseEvent with the info from gdk_event
-#define InitMouseEvent(event, gdk_event) \
-    event.SetTimestamp( gdk_event->time ); \
-    event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
-    event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
-    event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
-    event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
-    event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
-    event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
-    event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
-\
-    event.m_x = (wxCoord)gdk_event->x; \
-    event.m_y = (wxCoord)gdk_event->y \
-
 //-----------------------------------------------------------------------------
 // "motion_notify_event"
 //-----------------------------------------------------------------------------
@@ -1571,7 +1608,7 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
 */
 
     wxMouseEvent event( wxEVT_MOTION );
-    InitMouseEvent(event, gdk_event);
+    InitMouseEvent(win, event, gdk_event);
 
     if ( g_captureWindow )
     {
@@ -1585,7 +1622,7 @@ static gint gtk_window_motion_notify_callback( GtkWidget *widget,
 
             wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
                                                        : wxEVT_LEAVE_WINDOW);
-            InitMouseEvent(event, gdk_event);
+            InitMouseEvent(win, event, gdk_event);
             event.SetEventObject(win);
             win->GetEventHandler()->ProcessEvent(event);
         }
@@ -1724,17 +1761,18 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     }
 #endif // wxUSE_CARET
 
-    
     wxWindowGTK *active = wxGetTopLevelParent(win);
     if ( active != g_activeFrame )
     {
         if ( g_activeFrame )
         {
+            wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame);
             wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
             event.SetEventObject(g_activeFrame);
             g_activeFrame->GetEventHandler()->ProcessEvent(event);
         }
 
+        wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active);
         g_activeFrame = active;
         wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
         event.SetEventObject(g_activeFrame);
@@ -1772,9 +1810,6 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
-    wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") )
-    g_activeFrameLostFocus = TRUE;
-
     // VZ: this is really weird but GTK+ seems to call us from inside
     //     gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
     //     this widget and then "focus_in". This is totally unexpected and
@@ -1787,6 +1822,19 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
         return FALSE;
     }
 
+    if ( !g_activeFrameLostFocus && g_activeFrame )
+    {
+        // VZ: commenting this out because it does happen (although not easy
+        //     to reproduce, I only see it when using wxMiniFrame and not
+        //     always) and makes using Mahogany quite annoying
+#if 0
+        wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
+                        wxT("unfocusing window that hasn't gained focus properly") )
+#endif // 0
+
+        g_activeFrameLostFocus = TRUE;
+    }
+
     // if the focus goes out of our app alltogether, OnIdle() will send
     // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
     // g_sendActivateEvent to -1
@@ -1857,10 +1905,10 @@ static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_
 
     gdk_window_get_pointer( widget->window, &x, &y, &state );
 
-    InitMouseEvent(event, gdk_event);
-
-    event.m_x = x;
-    event.m_y = y;
+    InitMouseEvent(win, event, gdk_event);
+    wxPoint pt = win->GetClientAreaOrigin();
+    event.m_x = x + pt.x;
+    event.m_y = y + pt.y;
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
@@ -1905,8 +1953,9 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_
     event.m_middleDown = (state & GDK_BUTTON2_MASK);
     event.m_rightDown = (state & GDK_BUTTON3_MASK);
 
-    event.m_x = x;
-    event.m_y = y;
+    wxPoint pt = win->GetClientAreaOrigin();
+    event.m_x = x + pt.x;
+    event.m_y = y + pt.y;
 
     if (win->GetEventHandler()->ProcessEvent( event ))
     {
@@ -2321,7 +2370,7 @@ void wxWindowGTK::Init()
 
     m_noExpose = FALSE;
     m_nativeSizeEvent = FALSE;
-    
+
     m_hasScrolling = FALSE;
     m_isScrolling = FALSE;
 
@@ -2337,6 +2386,7 @@ void wxWindowGTK::Init()
 
     m_isStaticBox = FALSE;
     m_isRadioButton = FALSE;
+    m_isListBox = FALSE;
     m_isFrame = FALSE;
     m_acceptsFocus = FALSE;
 
@@ -2495,7 +2545,7 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
     if (m_parent)
         m_parent->DoAddChild( this );
-        
+
     m_focusWidget = m_wxwindow;
 
     PostCreation();
@@ -2589,7 +2639,7 @@ bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos,  const w
 void wxWindowGTK::PostCreation()
 {
     wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
-    
+
     if (m_wxwindow)
     {
         if (!m_noExpose)
@@ -2836,6 +2886,7 @@ void wxWindowGTK::OnInternalIdle()
     {
         if ( g_activeFrame )
         {
+            wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
             wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
             event.SetEventObject(g_activeFrame);
             g_activeFrame->GetEventHandler()->ProcessEvent(event);
@@ -3036,7 +3087,7 @@ void wxWindowGTK::DoGetPosition( int *x, int *y ) const
         dx = pizza->xoffset;
         dy = pizza->yoffset;
     }
-    
+
     if (x) (*x) = m_x - dx;
     if (y) (*y) = m_y - dy;
 }
@@ -3198,6 +3249,13 @@ void wxWindowGTK::SetFocus()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
+#if 0
+    wxPrintf( "SetFocus from " );
+    if (GetClassInfo() && GetClassInfo()->GetClassName())
+        wxPrintf( GetClassInfo()->GetClassName() );
+    wxPrintf( ".\n" );
+#endif
+
     if (m_wxwindow)
     {
         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
@@ -3222,6 +3280,14 @@ void wxWindowGTK::SetFocus()
            // ?
         }
     }
+
+#if 0
+    wxPrintf( "SetFocus finished in " );
+    if (GetClassInfo() && GetClassInfo()->GetClassName())
+        wxPrintf( GetClassInfo()->GetClassName() );
+    wxPrintf( ".\n" );
+#endif
+
 }
 
 bool wxWindowGTK::AcceptsFocus() const
@@ -3482,7 +3548,7 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
 
     if ((m_wxwindow) &&
         (m_wxwindow->window) &&
-        (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
+        (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)))
     {
         /* wxMSW doesn't clear the window here. I don't do that either to
           provide compatibility. call Clear() to do the job. */
@@ -3578,7 +3644,7 @@ void wxWindowGTK::SetWidgetStyle()
 
     GtkStyle *style = GetWidgetStyle();
 
-    if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
+    if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
     {
         gdk_font_unref( style->font );
         style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
@@ -3587,7 +3653,7 @@ void wxWindowGTK::SetWidgetStyle()
     if (m_foregroundColour.Ok())
     {
         m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
-        if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
+        if (m_foregroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT))
         {
             style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
             style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
@@ -3613,7 +3679,7 @@ void wxWindowGTK::SetWidgetStyle()
     if (m_backgroundColour.Ok())
     {
         m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
-        if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
+        if (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))
         {
             style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
             style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
@@ -3659,7 +3725,8 @@ void wxWindowGTK::ApplyWidgetStyle()
 
 #if wxUSE_MENUS_NATIVE
 
-static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
+extern "C"
+void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
 {
     *is_waiting = FALSE;
 }
@@ -3680,16 +3747,29 @@ static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
     }
 }
 
+// used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
+// wxPopupMenuPositionCallback()
+//
+// should be safe even in the MT case as the user can hardly popup 2 menus
+// simultaneously, can he?
 static gint gs_pop_x = 0;
 static gint gs_pop_y = 0;
 
-static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
-                              gint *x, gint *y,
-                              wxWindowGTK *win )
+extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
+                                             gint *x, gint *y,
+                                             gpointer WXUNUSED(user_data) )
 {
-    win->ClientToScreen( &gs_pop_x, &gs_pop_y );
-    *x = gs_pop_x;
-    *y = gs_pop_y;
+    // ensure that the menu appears entirely on screen
+    GtkRequisition req;
+    gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
+
+    wxSize sizeScreen = wxGetDisplaySize();
+
+    gint xmax = sizeScreen.x - req.width,
+         ymax = sizeScreen.y - req.height;
+
+    *x = gs_pop_x < xmax ? gs_pop_x : xmax;
+    *y = gs_pop_y < ymax ? gs_pop_y : ymax;
 }
 
 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
@@ -3704,20 +3784,23 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
 
     gs_pop_x = x;
     gs_pop_y = y;
+    ClientToScreen( &gs_pop_x, &gs_pop_y );
 
     bool is_waiting = TRUE;
 
-    gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
-      GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
+    gtk_signal_connect( GTK_OBJECT(menu->m_menu),
+                        "hide",
+                        GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
+                        (gpointer)&is_waiting );
 
     gtk_menu_popup(
                   GTK_MENU(menu->m_menu),
-                  (GtkWidget *) NULL,          // parent menu shell
-                  (GtkWidget *) NULL,          // parent menu item
-                  (GtkMenuPositionFunc) pop_pos_callback,
-                  (gpointer) this,             // client data
-                  0,                           // button used to activate it
-                  gs_timeLastClick             // the time of activation
+                  (GtkWidget *) NULL,           // parent menu shell
+                  (GtkWidget *) NULL,           // parent menu item
+                  wxPopupMenuPositionCallback,  // function to position it
+                  NULL,                         // client data
+                  0,                            // button used to activate it
+                  gs_timeLastClick              // the time of activation
                 );
 
     while (is_waiting)
@@ -3774,7 +3857,7 @@ bool wxWindowGTK::SetFont( const wxFont &font )
         return FALSE;
     }
 
-    wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
+    wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
     if ( sysbg == m_backgroundColour )
     {
         m_backgroundColour = wxNullColour;
@@ -3789,7 +3872,7 @@ bool wxWindowGTK::SetFont( const wxFont &font )
     return TRUE;
 }
 
-void wxWindowGTK::CaptureMouse()
+void wxWindowGTK::DoCaptureMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
@@ -3818,12 +3901,14 @@ void wxWindowGTK::CaptureMouse()
     g_captureWindowHasMouse = TRUE;
 }
 
-void wxWindowGTK::ReleaseMouse()
+void wxWindowGTK::DoReleaseMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
     wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
 
+    g_captureWindow = (wxWindowGTK*) NULL;
+
     GdkWindow *window = (GdkWindow*) NULL;
     if (m_wxwindow)
         window = GTK_PIZZA(m_wxwindow)->bin_window;
@@ -3834,7 +3919,6 @@ void wxWindowGTK::ReleaseMouse()
         return;
 
     gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
-    g_captureWindow = (wxWindowGTK*) NULL;
 }
 
 /* static */