]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
optimized default GUI font loading
[wxWidgets.git] / src / gtk / window.cpp
index ce6e688621d91f43799109ab4b804db0c36a4498..05a2f829cb4e0dfbf11285b61517ddc0c2bf15ea 100644 (file)
     #include "wx/caret.h"
 #endif // wxUSE_CARET
 
+#if wxUSE_TEXTCTRL
+#include "wx/textctrl.h"
+#endif
+
 #include "wx/menu.h"
 #include "wx/statusbr.h"
 #include "wx/intl.h"
@@ -212,6 +216,11 @@ static bool g_captureWindowHasMouse = FALSE;
 // keeps its previous value
 static wxWindowGTK *g_focusWindowLast = (wxWindowGTK *)NULL;
 
+// the frame that is currently active (i.e. its child has focus). It is
+// used to generate wxActivateEvents
+static wxWindowGTK *g_activeFrame = (wxWindowGTK *)NULL;
+static bool g_activeFrameLostFocus = FALSE;
+
 // if we detect that the app has got/lost the focus, we set this variable to
 // either TRUE or FALSE and an activate event will be sent during the next
 // OnIdle() call and it is reset to -1: this value means that we shouldn't
@@ -333,27 +342,37 @@ extern bool g_isIdle;
 // returns the child of win which currently has focus or NULL if not found
 //
 // Note: can't be static, needed by textctrl.cpp.
-wxWindow *FindFocusedChild(wxWindowGTK *win)
+wxWindow *wxFindFocusedChild(wxWindowGTK *win)
 {
-    wxWindowGTK *winFocus = wxWindowGTK::FindFocus();
+    wxWindow *winFocus = wxWindowGTK::FindFocus();
     if ( !winFocus )
-        return (wxWindowGTK *)NULL;
+        return (wxWindow *)NULL;
 
     if ( winFocus == win )
-        return win;
+        return (wxWindow *)win;
 
     for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
           node;
           node = node->GetNext() )
     {
-        wxWindowGTK *child = FindFocusedChild(node->GetData());
+        wxWindow *child = wxFindFocusedChild(node->GetData());
         if ( child )
             return child;
     }
 
-    return (wxWindowGTK *)NULL;
+    return (wxWindow *)NULL;
+}
+
+// Returns toplevel grandparent of given window:
+static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
+{
+    wxWindowGTK *p = win;
+    while (p && !p->IsTopLevel())
+         p = p->GetParent();
+    return p;
 }
 
+
 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
 {
     // wxUniversal widgets draw the borders and scrollbars themselves
@@ -467,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;
@@ -563,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 )
@@ -666,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;
 }
 
 //-----------------------------------------------------------------------------
@@ -948,6 +1001,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 )
@@ -961,23 +1017,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 );
@@ -1012,39 +1068,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 = map_to_wx_keysym( gdk_event );
 
-    if ( (!ret) &&
-         (key_code != 0))
-    {
-        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 );
+        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() );
@@ -1057,7 +1111,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);
@@ -1065,10 +1119,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) )
     {
@@ -1094,8 +1147,7 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
             ancestor = ancestor->GetParent();
         }
     }
-*/
-#endif
+#endif // 0
 
     if (ret)
     {
@@ -1120,28 +1172,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 );
@@ -1289,6 +1333,14 @@ static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton
     event.m_y = (wxCoord)gdk_event->y;
 
     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.
@@ -1422,6 +1474,14 @@ static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButto
 
     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.
 
@@ -1665,7 +1725,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     switch ( g_sendActivateEvent )
     {
         case -1:
-            // we've got focus from outside, synthtize wxActivateEvent
+            // we've got focus from outside, synthetize wxActivateEvent
             g_sendActivateEvent = 1;
             break;
 
@@ -1679,20 +1739,17 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     g_focusWindowLast =
     g_focusWindow = win;
 
-/*
-    printf( "OnSetFocus from " );
+#if 0
+    wxPrintf( "OnSetFocus from " );
     if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-        printf( win->GetClassInfo()->GetClassName() );
-    printf( "   " );
-    printf( WXSTRINGCAST win->GetLabel() );
-    printf( ".\n" );
-*/
+        wxPrintf( win->GetClassInfo()->GetClassName() );
+    wxPrintf( ".\n" );
+#endif
 
-    wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
-    if (panel)
-    {
-        panel->SetLastFocus(win);
-    }
+    // notify the parent keeping track of focus for the kbd navigation
+    // purposes that we got it
+    wxChildFocusEvent eventFocus(win);
+    (void)win->GetEventHandler()->ProcessEvent(eventFocus);
 
 #ifdef HAVE_XIM
     if (win->m_ic)
@@ -1708,14 +1765,25 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     }
 #endif // wxUSE_CARET
 
-    if (win->IsTopLevel())
+    wxWindowGTK *active = wxGetTopLevelParent(win);
+    if ( active != g_activeFrame )
     {
-        wxActivateEvent event( wxEVT_ACTIVATE, TRUE, win->GetId() );
-        event.SetEventObject( win );
+        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);
+        }
 
-        // ignore return value
-        win->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);
+        g_activeFrame->GetEventHandler()->ProcessEvent(event);
     }
+    g_activeFrameLostFocus = FALSE;
+
 
     wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
     event.SetEventObject( win );
@@ -1734,6 +1802,8 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
 // "focus_out_event"
 //-----------------------------------------------------------------------------
 
+static GtkWidget *gs_widgetLastFocus = NULL;
+
 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
 {
     DEBUG_MAIN_THREAD
@@ -1744,23 +1814,48 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
     if (!win->m_hasVMT) return FALSE;
     if (g_blockEventsOnDrag) return FALSE;
 
+    // VZ: this is really weird but GTK+ seems to call us from inside
+    //     gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
+    //     this widget and then "focus_in". This is totally unexpected and
+    //     completely breaks wxUniv code so ignore this dummy event (we can't
+    //     be losing focus if we're about to acquire it!)
+    if ( widget == gs_widgetLastFocus )
+    {
+        gs_widgetLastFocus = NULL;
+
+        return FALSE;
+    }
+
+    if ( !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
     g_sendActivateEvent = 0;
 
-    wxWindowGTK *winFocus = FindFocusedChild(win);
+    wxWindowGTK *winFocus = wxFindFocusedChild(win);
     if ( winFocus )
         win = winFocus;
 
     g_focusWindow = (wxWindowGTK *)NULL;
 
-/*
-    printf( "OnKillFocus from " );
+#if 0
+    wxPrintf( "OnKillFocus from " );
     if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
-        printf( win->GetClassInfo()->GetClassName() );
-    printf( ".\n" );
-*/
+        wxPrintf( win->GetClassInfo()->GetClassName() );
+    wxPrintf( ".\n" );
+#endif
 
 #ifdef HAVE_XIM
     if (win->m_ic)
@@ -1776,15 +1871,6 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED
     }
 #endif // wxUSE_CARET
 
-    if (win->IsTopLevel())
-    {
-        wxActivateEvent event( wxEVT_ACTIVATE, FALSE, win->GetId() );
-        event.SetEventObject( win );
-
-        // ignore return value
-        win->GetEventHandler()->ProcessEvent( event );
-    }
-
     wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
     event.SetEventObject( win );
 
@@ -1814,9 +1900,7 @@ static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
     wxMouseEvent event( wxEVT_ENTER_WINDOW );
-#if (GTK_MINOR_VERSION > 0)
     event.SetTimestamp( gdk_event->time );
-#endif
     event.SetEventObject( win );
 
     int x = 0;
@@ -1856,9 +1940,7 @@ static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_
     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
 
     wxMouseEvent event( wxEVT_LEAVE_WINDOW );
-#if (GTK_MINOR_VERSION > 0)
     event.SetTimestamp( gdk_event->time );
-#endif
     event.SetEventObject( win );
 
     int x = 0;
@@ -2260,11 +2342,13 @@ wxWindow *wxGetActiveWindow()
 // wxWindowGTK
 //-----------------------------------------------------------------------------
 
+// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
+// method
 #ifdef __WXUNIVERSAL__
-    IMPLEMENT_DYNAMIC_CLASS(wxWindowGTK, wxWindowBase)
-#else
+    IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
+#else // __WXGTK__
     IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
-#endif
+#endif // __WXUNIVERSAL__/__WXGTK__
 
 void wxWindowGTK::Init()
 {
@@ -2274,6 +2358,7 @@ void wxWindowGTK::Init()
     // GTK specific
     m_widget = (GtkWidget *) NULL;
     m_wxwindow = (GtkWidget *) NULL;
+    m_focusWidget = (GtkWidget *) NULL;
 
     // position/size
     m_x = 0;
@@ -2288,7 +2373,7 @@ void wxWindowGTK::Init()
 
     m_noExpose = FALSE;
     m_nativeSizeEvent = FALSE;
-
+    
     m_hasScrolling = FALSE;
     m_isScrolling = FALSE;
 
@@ -2304,6 +2389,7 @@ void wxWindowGTK::Init()
 
     m_isStaticBox = FALSE;
     m_isRadioButton = FALSE;
+    m_isListBox = FALSE;
     m_isFrame = FALSE;
     m_acceptsFocus = FALSE;
 
@@ -2462,6 +2548,8 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
     if (m_parent)
         m_parent->DoAddChild( this );
+        
+    m_focusWidget = m_wxwindow;
 
     PostCreation();
 
@@ -2475,6 +2563,9 @@ wxWindowGTK::~wxWindowGTK()
     if (g_focusWindow == this)
         g_focusWindow = NULL;
 
+    if (g_activeFrame == this)
+        g_activeFrame = NULL;
+
     m_isBeingDeleted = TRUE;
     m_hasVMT = FALSE;
 
@@ -2551,12 +2642,12 @@ 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)
         {
-            /* these get reported to wxWindows -> wxPaintEvent */
+            // these get reported to wxWindows -> wxPaintEvent
 
             gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
 
@@ -2573,35 +2664,32 @@ void wxWindowGTK::PostCreation()
             }
         }
 
-#if (GTK_MINOR_VERSION > 0)
-        /* these are called when the "sunken" or "raised" borders are drawn */
+        // these are called when the "sunken" or "raised" borders are drawn */
         gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
           GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
 
         gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
           GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
-#endif
     }
 
-    if (m_wxwindow && m_needParent)
-    {
-        gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event",
-            GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
+    // focus handling
 
-        gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event",
-            GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
-    }
-    else
-    {
-        // For dialogs and frames, we are interested mainly in
-        // m_widget's focus.
+    if (m_focusWidget == NULL)
+        m_focusWidget = m_widget;
 
-        gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
-            GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
+#if 0
+    if (GetClassInfo() && GetClassInfo()->GetClassName())
+        wxPrintf( GetClassInfo()->GetClassName() );
+    wxPrintf( ".\n" );
+#endif
 
-        gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
-            GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
-    }
+    gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
+        GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
+
+    gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
+         GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
+
+    // connect to the various key and mouse handlers
 
     GtkWidget *connect_widget = GetConnectWidget();
 
@@ -2691,6 +2779,14 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
     if (m_resizing) return; /* I don't like recursions */
     m_resizing = TRUE;
 
+    int currentX, currentY;
+    GetPosition(&currentX, &currentY);
+    if (x == -1)
+        x = currentX;
+    if (y == -1)
+        y = currentY;
+    AdjustForParentClientOrigin(x, y, sizeFlags);
+
     if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
     {
         /* don't set the size for children of wxNotebook, just take the values. */
@@ -2787,11 +2883,19 @@ void wxWindowGTK::OnInternalIdle()
         g_sendActivateEvent = -1;
 
         wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
+    }
 
-        wxActivateEvent event(wxEVT_ACTIVATE_APP, activate, GetId());
-        event.SetEventObject(this);
-
-        (void)GetEventHandler()->ProcessEvent(event);
+    if ( g_activeFrameLostFocus )
+    {
+        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);
+            g_activeFrame = NULL;
+        }
+        g_activeFrameLostFocus = FALSE;
     }
 
     wxCursor cursor = m_cursor;
@@ -2986,7 +3090,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;
 }
@@ -3067,7 +3171,7 @@ bool wxWindowGTK::Show( bool show )
     return TRUE;
 }
 
-static void wxWindowNotifyEnable(wxWindow* win, bool enable)
+static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
 {
     win->OnParentEnable(enable);
 
@@ -3084,7 +3188,7 @@ static void wxWindowNotifyEnable(wxWindow* win, bool enable)
     }
 }
 
-bool wxWindow::Enable( bool enable )
+bool wxWindowGTK::Enable( bool enable )
 {
     wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
 
@@ -3151,11 +3255,13 @@ void wxWindowGTK::SetFocus()
     if (m_wxwindow)
     {
         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
+        {
+            // see comment in gtk_window_focus_out_callback()
+            gs_widgetLastFocus = m_wxwindow;
             gtk_widget_grab_focus (m_wxwindow);
-        return;
+        }
     }
-
-    if (m_widget)
+    else if (m_widget)
     {
         if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
         {
@@ -3394,7 +3500,7 @@ void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
     wxWindowBase::DoSetToolTip(tip);
 
     if (m_tooltip)
-        m_tooltip->Apply( this );
+        m_tooltip->Apply( (wxWindow *)this );
 }
 
 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
@@ -3605,7 +3711,7 @@ void wxWindowGTK::ApplyWidgetStyle()
 // Pop-up menu stuff
 //-----------------------------------------------------------------------------
 
-#if wxUSE_MENUS
+#if wxUSE_MENUS_NATIVE
 
 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
 {
@@ -3628,16 +3734,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 )
+static 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 )
@@ -3652,6 +3771,7 @@ 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;
 
@@ -3660,12 +3780,12 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
 
     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)
@@ -3677,7 +3797,7 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
     return TRUE;
 }
 
-#endif // wxUSE_MENUS
+#endif // wxUSE_MENUS_NATIVE
 
 #if wxUSE_DRAG_AND_DROP
 
@@ -3741,15 +3861,13 @@ void wxWindowGTK::CaptureMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
-    wxCHECK_RET( g_captureWindow == NULL, wxT("CaptureMouse called twice") );
-
     GdkWindow *window = (GdkWindow*) NULL;
     if (m_wxwindow)
         window = GTK_PIZZA(m_wxwindow)->bin_window;
     else
         window = GetConnectWidget()->window;
 
-    if (!window) return;
+    wxCHECK_RET( window, _T("CaptureMouse() failed") );
 
     wxCursor* cursor = & m_cursor;
     if (!cursor->Ok())
@@ -3772,7 +3890,7 @@ void wxWindowGTK::ReleaseMouse()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
 
-    wxCHECK_RET( g_captureWindow, wxT("ReleaseMouse called twice") );
+    wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
 
     GdkWindow *window = (GdkWindow*) NULL;
     if (m_wxwindow)