]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
added wxUSE_STDPATHS
[wxWidgets.git] / src / gtk / window.cpp
index 07ff8e6952608d62244f706502aa6f4a0807c955..e6a12132c279b24bb8a412e31693fefc51c3ca06 100644 (file)
@@ -28,6 +28,7 @@
 #include "wx/dialog.h"
 #include "wx/msgdlg.h"
 #include "wx/module.h"
+#include "wx/combobox.h"
 
 #if wxUSE_DRAG_AND_DROP
     #include "wx/dnd.h"
@@ -56,7 +57,7 @@
     #include "wx/thread.h"
 #endif
 
-#include <math.h>
+#include "wx/math.h"
 #include <ctype.h>
 
 #include "wx/gtk/private.h"
 #include <pango/pangox.h>
 #endif
 
-#ifdef __WXGTK20__
-    #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
-#else
-    #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
-#endif
 
 #ifdef __WXGTK20__
     #ifdef HAVE_XIM
@@ -235,28 +231,17 @@ static GdkGC *g_eraseGC = NULL;
 static wxWindowGTK  *g_captureWindow = (wxWindowGTK*) NULL;
 static bool g_captureWindowHasMouse = FALSE;
 
-/* extern */ wxWindowGTK  *g_focusWindow = (wxWindowGTK*) NULL;
+wxWindowGTK  *g_focusWindow = (wxWindowGTK*) NULL;
 
 // the last window which had the focus - this is normally never NULL (except
 // if we never had focus at all) as even when g_focusWindow is NULL it still
 // keeps its previous value
-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;
+wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL;
 
 // If a window get the focus set but has not been realized
 // yet, defer setting the focus to idle time.
 wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL;
 
-// 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
-// send any activate events at all
-static int        g_sendActivateEvent = -1;
-
 // hack: we need something to pass to gtk_menu_popup, so we store the time of
 // the last click here
 static guint32 gs_timeLastClick = 0; 
@@ -492,6 +477,34 @@ void wxgtk_window_size_request_callback(GtkWidget *widget,
     requisition->width = w;
 }
 
+
+extern "C"
+void wxgtk_combo_size_request_callback(GtkWidget *widget,
+                                       GtkRequisition *requisition,
+                                       wxComboBox *win)
+{
+    // This callback is actually hooked into the text entry
+    // of the combo box, not the GtkHBox.
+    
+    int w, h;
+    win->GetSize( &w, &h );
+    if (w < 2)
+        w = 2;
+    if (h < 2)
+        h = 2;
+
+    GtkCombo *gcombo = GTK_COMBO(win->m_widget);
+    
+    GtkRequisition entry_req;
+    entry_req.width = 2;
+    entry_req.height = 2;
+    (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request )
+        (gcombo->button, &entry_req );
+    
+    requisition->width = w - entry_req.width;
+    requisition->height = entry_req.height+4;  // TODO: why +4?
+}
+
 //-----------------------------------------------------------------------------
 // "expose_event" of m_wxwindow
 //-----------------------------------------------------------------------------
@@ -632,7 +645,7 @@ static void gtk_window_draw_callback( GtkWidget *widget,
 #ifndef __WXUNIVERSAL__
     GtkPizza *pizza = GTK_PIZZA (widget);
 
-    if (win->GetThemeEnabled())
+    if (win->GetThemeEnabled() && win->GetBackgroundStyle() == wxBG_STYLE_SYSTEM)
     {
         wxWindow *parent = win->GetParent();
         while (parent && !parent->IsTopLevel())
@@ -976,6 +989,7 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event,
         gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
 
     event.SetTimestamp( gdk_event->time );
+    event.SetId(win->GetId());
     event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
     event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
     event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
@@ -983,6 +997,11 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event,
     event.m_scanCode = gdk_event->keyval;
     event.m_rawCode = (wxUint32) gdk_event->keyval;
     event.m_rawFlags = 0;
+#if wxUSE_UNICODE
+    event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
+#endif
+    wxGetMousePosition( &x, &y );
+    win->ScreenToClient( &x, &y );
     event.m_x = x;
     event.m_y = y;
     event.SetEventObject( win );
@@ -1123,48 +1142,113 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
         return FALSE;
     if (g_blockEventsOnDrag)
         return FALSE;
-    
-#ifdef __WXGTK20__
-    // We have to pass key press events through GTK+'s Input Method context
-    // object in order to get correct characters. By doing so, we loose the
-    // ability to let other GTK+'s handlers (namely, widgets' default signal
-    // handlers) handle the signal by returning false from this callback.
-    // Because GTK+ sends the events to parent widgets as well, we can't
-    // afford loosing it, otherwise native widgets inserted into wxPanel
-    // would break in subtle ways (e.g. spacebar would no longer toggle
-    // wxCheckButton's state). Therefore, we only pass the event to IM if it
-    // originated in this window's widget, which we detect by checking if we've
-    // seen the same event before (no events from children are lost this way,
-    // because gtk_window_key_press_callback is installed for native controls
-    // as well and the wxKeyEvent it creates propagates upwards).
-    static GdkEventKey s_lastEvent;
-    
-    bool useIM = (win->m_imData != NULL) &&
-                 memcmp(gdk_event, &s_lastEvent, sizeof(GdkEventKey)) != 0;
-    
-    s_lastEvent = *gdk_event;
-#endif
-    
+
+
     wxKeyEvent event( wxEVT_KEY_DOWN );
-    if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+    bool ret = false;
+    bool return_after_IM = false;
+
+    if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+    {
+        // Emit KEY_DOWN event
+        ret = win->GetEventHandler()->ProcessEvent( event );
+    }
+    else 
     {
-        // unknown key pressed, ignore (the event would be useless anyhow)
+        // Return after IM processing as we cannot do
+        // anything with it anyhow.
+        return_after_IM = true;
+    }
+
 #ifdef __WXGTK20__
-        if ( useIM )
+    // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
+    // When we get a key_press event here, it could be originate
+    // from the current widget or its child widgets.  However, only the widget
+    // with the INPUT FOCUS can generate the INITIAL key_press event.  That is, 
+    // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
+    // originated from its child widgets and shouldn't be passed to IM context.
+    // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
+    // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS.  Besides, when current
+    // widgets has both IM context and input focus, the event should be filtered 
+    // by gtk_im_context_filter_keypress().
+    // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
+    if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
+    {
+        // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
+        // docs, if IM filter returns true, no further processing should be done.
+        // we should send the key_down event anyway. 
+        bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
+        win->m_imData->lastKeyEvent = NULL;
+        if (intercepted_by_IM)
         {
-            // it may be useful for the input method, though:
-            win->m_imData->lastKeyEvent = gdk_event;
-            bool ret = gtk_im_context_filter_keypress(win->m_imData->context,
-                                                      gdk_event);
-            win->m_imData->lastKeyEvent = NULL;
-            return ret;
+            wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
+            return true;
         }
-#endif
-        return FALSE;
     }
+#endif
+    if (return_after_IM)
+        return true;
 
-    // Emit KEY_DOWN event
-    bool ret = win->GetEventHandler()->ProcessEvent( event );
+#ifndef __WXGTK20__     
+    // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
+    // in the "commit" handler.
+    
+    // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
+    // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose 
+    // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are 
+    // composed of more than one character, which means gdk_event->length will always 
+    // greater than one. When gtk_event->length == 1, this may be an ASCII character
+    // and can be translated by wx.  However, when MBCS characters are sent by IM, 
+    // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
+    // nor should we pass it to controls. The following explanation was excerpted
+    // from GDK documentation.
+    // gint length : the length of string.
+    // gchar *string : a null-terminated multi-byte string containing the composed
+    // characters resulting from the key press. When text is being input, in a GtkEntry
+    // for example, it is these characters which should be added to the input buffer.
+    // When using Input Methods to support internationalized text input, the composed
+    // characters appear here after the pre-editing has been completed.
+
+    if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
+    {
+        // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
+        #if wxUSE_UNICODE   // GTK+ 1.2 is not UTF-8 based.
+            const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
+            if( !string )
+                return false;
+        #else
+            const char* string = gdk_event->string;
+        #endif
+
+        // Implement OnCharHook by checking ancesteror top level windows
+        wxWindow *parent = win;
+        while (parent && !parent->IsTopLevel())
+            parent = parent->GetParent();
+
+        for( const wxChar* pstr = string; *pstr; pstr++ )
+        {
+        #if wxUSE_UNICODE
+            event.m_uniChar = *pstr;
+            // Backward compatible for ISO-8859-1
+            event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
+        #else
+            event.m_keyCode = *pstr;
+        #endif
+            if (parent)
+            {
+                event.SetEventType( wxEVT_CHAR_HOOK );
+                ret = parent->GetEventHandler()->ProcessEvent( event );
+            }
+            if (!ret)
+            {
+                event.SetEventType(wxEVT_CHAR);
+                win->GetEventHandler()->ProcessEvent( event );
+            }
+        }
+        return true;
+    }
+    
+#endif  // #ifndef  __WXGTK20__
 
 #if wxUSE_ACCEL
     if (!ret)
@@ -1190,41 +1274,22 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
     // will only be sent if it is not in an accelerator table.
     if (!ret)
     {
-#ifdef __WXGTK20__
-        if (useIM)
-        {
-            // 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.
-            win->m_imData->lastKeyEvent = gdk_event;
-            if ( gtk_im_context_filter_keypress(win->m_imData->context,
-                                                gdk_event) )
-            {
-                win->m_imData->lastKeyEvent = NULL;
-                wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
-                return TRUE;
-            }
-            else
-                win->m_imData->lastKeyEvent = NULL;
-        }
-#endif
-
         long key_code;
         KeySym keysym = gdk_event->keyval;
         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
         key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
         if ( !key_code )
         {
-            if ( gdk_event->length == 1 )
-            {
-                key_code = (unsigned char)gdk_event->string[0];
-            }
-            else if ( wxIsAsciiKeysym(keysym) )
+            if ( wxIsAsciiKeysym(keysym) )
             {
                 // ASCII key
                 key_code = (unsigned char)keysym;
             }
+            // gdk_event->string is actually deprecated
+            else if ( gdk_event->length == 1 )
+            {
+                key_code = (unsigned char)gdk_event->string[0];
+            }
         }
 
         if ( key_code )
@@ -1251,6 +1316,10 @@ static gint gtk_window_key_press_callback( GtkWidget *widget,
         }
     }
 
+
+
+
+
     // win is a control: tab can be propagated up
     if ( !ret &&
          ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
@@ -1337,24 +1406,13 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context,
     }
 
 #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;
-    wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
+    const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str );
 #else
-    wchar_t unistr[2];
-    unistr[0] = g_utf8_get_char(str);
-    unistr[1] = 0;
-    wxCharBuffer ansistr(wxConvLocal.cWC2MB(unistr));
-    // We cannot handle characters that cannot be represented in 
-    // current locale's charset in non-Unicode mode:
-    if (ansistr.data() == NULL)
-        return;
-    event.m_keyCode = ansistr[0u];
-    wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), (wxChar)event.m_keyCode);
+    const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str );
+    const wxCharBuffer data = wxConvLocal.cWC2MB( wdata );
 #endif // wxUSE_UNICODE
+    if( !(const wxChar*)data )
+        return;
 
     bool ret = false;
 
@@ -1362,16 +1420,28 @@ static void gtk_wxwindow_commit_cb (GtkIMContext *context,
     wxWindow *parent = window;
     while (parent && !parent->IsTopLevel())
         parent = parent->GetParent();
-    if (parent)
-    {
-        event.SetEventType( wxEVT_CHAR_HOOK );
-        ret = parent->GetEventHandler()->ProcessEvent( event );
-    }
 
-    if (!ret)
+    for( const wxChar* pstr = data; *pstr; pstr++ )
     {
-        event.SetEventType(wxEVT_CHAR);
-        ret = window->GetEventHandler()->ProcessEvent( event );
+#if wxUSE_UNICODE
+        event.m_uniChar = *pstr;
+        // Backward compatible for ISO-8859-1
+        event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
+        wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
+#else
+        event.m_keyCode = *pstr;
+#endif  // wxUSE_UNICODE
+        if (parent)
+        {
+            event.SetEventType( wxEVT_CHAR_HOOK );
+            ret = parent->GetEventHandler()->ProcessEvent( event );
+        }
+
+        if (!ret)
+        {
+            event.SetEventType(wxEVT_CHAR);
+            ret = window->GetEventHandler()->ProcessEvent( event );
+        }
     }
 }
 #endif
@@ -1703,21 +1773,6 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
     // a chance to correct this
     win->FixUpMouseEvent(widget, event.m_x, event.m_y);
 
-    if ( event_type == wxEVT_RIGHT_DOWN )
-    {
-        // generate a "context menu" event: this is similar to right mouse
-        // click under many GUIs except that it is generated differently
-        // (right up under MSW, ctrl-click under Mac, right down here) and
-        //
-        // (a) it's a command event and so is propagated to the parent
-        // (b) under 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);
-    }
-
     // find the correct window to send the event too: it may be a different one
     // from the one which got it at GTK+ level because some control don't have
     // their own X window and thus cannot get any events.
@@ -1746,6 +1801,23 @@ static gint gtk_window_button_press_callback( GtkWidget *widget,
         return TRUE;
     }
 
+    if (event_type == wxEVT_RIGHT_DOWN)
+    {
+        // generate a "context menu" event: this is similar to right mouse
+        // click under many GUIs except that it is generated differently
+        // (right up under MSW, ctrl-click under Mac, right down here) and
+        //
+        // (a) it's a command event and so is propagated to the parent
+        // (b) under some ports it can be generated from kbd too
+        // (c) it uses screen coords (because of (a))
+        wxContextMenuEvent evtCtx(
+            wxEVT_CONTEXT_MENU,
+            win->GetId(),
+            win->ClientToScreen(event.GetPosition()));
+        evtCtx.SetEventObject(win);
+        return win->GetEventHandler()->ProcessEvent(evtCtx);
+    }
+
     return FALSE;
 }
 
@@ -1938,7 +2010,20 @@ static gint gtk_window_wheel_callback (GtkWidget * widget,
 
     return FALSE;
 }
-#endif
+
+//-----------------------------------------------------------------------------
+// "popup-menu"
+//-----------------------------------------------------------------------------
+static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
+{
+    wxContextMenuEvent event(
+        wxEVT_CONTEXT_MENU,
+        win->GetId(),
+        wxPoint(-1, -1));
+    event.SetEventObject(win);
+    return win->GetEventHandler()->ProcessEvent(event);
+}
+#endif // __WXGTK20__
 
 //-----------------------------------------------------------------------------
 // "focus_in_event"
@@ -1964,7 +2049,7 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
                                           wxWindow *win )
 {
     DEBUG_MAIN_THREAD
-
+    
     if (g_isIdle)
         wxapp_install_idle_handler();
 
@@ -1973,23 +2058,6 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
         gtk_im_context_focus_in(win->m_imData->context);
 #endif
 
-    if (!win->m_hasVMT) return FALSE;
-    if (g_blockEventsOnDrag) return FALSE;
-
-    switch ( g_sendActivateEvent )
-    {
-        case -1:
-            // we've got focus from outside, synthetize wxActivateEvent
-            g_sendActivateEvent = 1;
-            break;
-
-        case 0:
-            // another our window just lost focus, it was already ours before
-            // - don't send any wxActivateEvent
-            g_sendActivateEvent = -1;
-            break;
-    }
-
     g_focusWindowLast =
     g_focusWindow = win;
 
@@ -2010,36 +2078,12 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
     }
 #endif // wxUSE_CARET
 
-    g_activeFrameLostFocus = FALSE;
-
-    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);
-        g_activeFrame->GetEventHandler()->ProcessEvent(event);
-
-        // Don't send focus events in addition to activate
-        // if (win == g_activeFrame)
-        //    return TRUE;
-    }
-
     // does the window itself think that it has the focus?
     if ( !win->m_hasFocus )
     {
         // not yet, notify it
         win->m_hasFocus = TRUE;
-
+        
         if ( DoSendFocusEvents(win) )
         {
            gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
@@ -2066,29 +2110,9 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk
         gtk_im_context_focus_out(win->m_imData->context);
 #endif
 
-    if (!win->m_hasVMT) return FALSE;
-    if (g_blockEventsOnDrag) return FALSE;
-
     wxLogTrace( TRACE_FOCUS,
                 _T("%s: focus out"), win->GetName().c_str() );
 
-    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 = wxFindFocusedChild(win);
     if ( winFocus )
@@ -2119,11 +2143,11 @@ static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk
         wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
         event.SetEventObject( win );
 
-        if (win->GetEventHandler()->ProcessEvent( event ))
-        {
-            gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
-            return TRUE;
-        }
+        // even if we did process the event in wx code, still let GTK itself
+        // process it too as otherwise bad things happen, especially in GTK2
+        // where the text control simply aborts the program if it doesn't get
+        // the matching focus out event
+        (void)win->GetEventHandler()->ProcessEvent( event );
     }
 
     return FALSE;
@@ -2363,7 +2387,7 @@ static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
 // because it is static and so couldn't be made virtual
 // ----------------------------------------------------------------------------
 
-wxWindow *wxWindowBase::FindFocus()
+wxWindow *wxWindowBase::DoFindFocus()
 {
     // the cast is necessary when we compile in wxUniversal mode
     return (wxWindow *)g_focusWindow;
@@ -2646,6 +2670,8 @@ void wxWindowGTK::Init()
 
     m_clipPaintRegion = FALSE;
 
+    m_needsStyleChange = false;
+
     m_cursor = *wxSTANDARD_CURSOR;
 
 #ifdef __WXGTK20__
@@ -2794,9 +2820,6 @@ wxWindowGTK::~wxWindowGTK()
     if (g_focusWindow == this)
         g_focusWindow = NULL;
 
-    if (g_activeFrame == this)
-        g_activeFrame = NULL;
-
     if ( g_delayedFocus == this )
         g_delayedFocus = NULL;
 
@@ -2899,14 +2922,17 @@ void wxWindowGTK::PostCreation()
 
     // focus handling
 
-    if (m_focusWidget == NULL)
-        m_focusWidget = m_widget;
-
-    gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
-        GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
+    if (!GTK_IS_WINDOW(m_widget))
+    {
+        if (m_focusWidget == NULL)
+            m_focusWidget = m_widget;
+            
+        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 );
+        gtk_signal_connect_after( 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
 
@@ -2934,13 +2960,20 @@ void wxWindowGTK::PostCreation()
                             GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
     }
 
-    if ( !GTK_IS_COMBO(m_widget))
+    if (GTK_IS_COMBO(m_widget))
+    {
+        GtkCombo *gcombo = GTK_COMBO(m_widget);
+    
+        gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
+                            GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
+                            (gpointer) this );
+    }
+    else
     {
         // This is needed if we want to add our windows into native
-        // GTK control, such as the toolbar. With this callback, the
+        // GTK controls, such as the toolbar. With this callback, the
         // toolbar gets to know the correct size (the one set by the
-        // programmer). Sadly, it misbehaves for wxComboBox. FIXME
-        // when moving to GTK 2.0.
+        // programmer). Sadly, it misbehaves for wxComboBox.
         gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
                             GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
                             (gpointer) this );
@@ -2976,6 +3009,8 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
 #ifdef __WXGTK20__
     gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
       GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
+    g_signal_connect(widget, "popup_menu",
+        G_CALLBACK(wxgtk_window_popup_menu_callback), this);
 #endif
 
     gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
@@ -3067,22 +3102,37 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags
         if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
         if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
 
-        int border = 0;
+        int left_border = 0;
+        int right_border = 0;
+        int top_border = 0;
         int bottom_border = 0;
 
-#ifndef __WXGTK20__
+        /* the default button has a border around it */
         if (GTK_WIDGET_CAN_DEFAULT(m_widget))
         {
-            /* the default button has a border around it */
-            border = 6;
+#ifdef __WXGTK20__
+            GtkBorder *default_outside_border = NULL;
+            gtk_widget_style_get( m_widget, "default_outside_border", &default_outside_border, NULL );
+            if (default_outside_border)
+            {
+                left_border += default_outside_border->left;
+                right_border += default_outside_border->right;
+                top_border += default_outside_border->top;
+                bottom_border += default_outside_border->bottom;
+                g_free( default_outside_border );
+            }
+#else
+            left_border = 6;
+            right_border = 6;
+            top_border = 6;
             bottom_border = 5;
-        }
 #endif
+        }
 
-        DoMoveWindow( m_x-border,
-                      m_y-border,
-                      m_width+2*border,
-                      m_height+border+bottom_border );
+        DoMoveWindow( m_x-top_border,
+                      m_y-left_border,
+                      m_width+left_border+right_border,
+                      m_height+top_border+bottom_border );
     }
 
     if (m_hasScrolling)
@@ -3119,33 +3169,16 @@ void wxWindowGTK::OnInternalIdle()
     if ( m_dirtyTabOrder )
         RealizeTabOrder();
 #endif
-
-    // Update invalidated regions.
-    GtkUpdate();
-
-    // Synthetize activate events.
-    if ( g_sendActivateEvent != -1 )
+    // Update style if the window was not yet realized
+    // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
+    if (m_needsStyleChange)
     {
-        bool activate = g_sendActivateEvent != 0;
-
-        // do it only once
-        g_sendActivateEvent = -1;
-
-        wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
+        SetBackgroundStyle(GetBackgroundStyle());
+        m_needsStyleChange = false;
     }
 
-    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;
-    }
+    // Update invalidated regions.
+    GtkUpdate();
 
     wxCursor cursor = m_cursor;
     if (g_globalCursor.Ok()) cursor = g_globalCursor;
@@ -3419,7 +3452,7 @@ bool wxWindowGTK::Show( bool show )
         gtk_widget_hide( m_widget );
 
     wxShowEvent eventShow(GetId(), show);
-    eventShow.m_eventObject = this;
+    eventShow.SetEventObject(this);
 
     GetEventHandler()->ProcessEvent(eventShow);
 
@@ -3601,7 +3634,6 @@ void wxWindowGTK::GetTextExtent( const wxString& string,
 void wxWindowGTK::SetFocus()
 {
     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
-
     if ( m_hasFocus )
     {
         // don't do anything if we already have focus
@@ -3617,8 +3649,16 @@ void wxWindowGTK::SetFocus()
     }
     else if (m_widget)
     {
+#ifdef __WXGTK20__
+        if (GTK_IS_CONTAINER(m_widget))
+        {
+            gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
+        }
+        else
+#endif
         if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
         {
+        
             if (!GTK_WIDGET_REALIZED(m_widget))
             {
                 // we can't set the focus to the widget now so we remember that
@@ -3639,11 +3679,14 @@ void wxWindowGTK::SetFocus()
                 gtk_widget_grab_focus (m_widget);
             }
         }
-        else if (GTK_IS_CONTAINER(m_widget))
+        else 
+#ifndef __WXGTK20__
+        if (GTK_IS_CONTAINER(m_widget))
         {
-            SET_CONTAINER_FOCUS( m_widget, GTK_DIR_TAB_FORWARD );
+            gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
         }
         else
+#endif
         {
            wxLogTrace(TRACE_FOCUS,
                       _T("Can't set focus to %s(%s)"),
@@ -3768,18 +3811,28 @@ void wxWindowGTK::Raise()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (!m_widget->window) return;
-
-    gdk_window_raise( m_widget->window );
+    if (m_wxwindow && m_wxwindow->window)
+    {
+        gdk_window_raise( m_wxwindow->window );
+    }
+     else if (m_widget->window)
+    {
+        gdk_window_raise( m_widget->window );
+    }
 }
 
 void wxWindowGTK::Lower()
 {
     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
-    if (!m_widget->window) return;
-
-    gdk_window_lower( m_widget->window );
+    if (m_wxwindow && m_wxwindow->window)
+    {
+        gdk_window_lower( m_wxwindow->window );
+    }
+     else if (m_widget->window)
+    {
+        gdk_window_lower( m_widget->window );
+    }
 }
 
 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
@@ -3905,6 +3958,12 @@ void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
 void wxWindowGTK::Update()
 {
     GtkUpdate();
+
+    // when we call Update() we really want to update the window immediately on
+    // screen, even if itmeans flushing the entire queue and hence slowing down
+    // everything -- but it should still be done, it's just that Update() should
+    // be called very rarely
+    gdk_flush();
 }
 
 void wxWindowGTK::GtkUpdate()
@@ -3935,34 +3994,35 @@ void wxWindowGTK::GtkSendPaintEvents()
     // widget to draw on
     GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
 
-    if (GetThemeEnabled())
+    if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
     {
         // find ancestor from which to steal background
-        wxWindow *parent = GetParent();
-        while (parent && !parent->IsTopLevel())
-            parent = parent->GetParent();
+        wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
         if (!parent)
             parent = (wxWindow*)this;
 
-        wxRegionIterator upd( m_updateRegion );
-        while (upd)
+        if (GTK_WIDGET_MAPPED(parent->m_widget))
         {
-            GdkRectangle rect;
-            rect.x = upd.GetX();
-            rect.y = upd.GetY();
-            rect.width = upd.GetWidth();
-            rect.height = upd.GetHeight();
-
-            gtk_paint_flat_box( parent->m_widget->style,
-                        pizza->bin_window,
-                        (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
-                        GTK_SHADOW_NONE,
-                        &rect,
-                        parent->m_widget,
-                        (char *)"base",
-                        0, 0, -1, -1 );
-
-            upd ++;
+            wxRegionIterator upd( m_updateRegion );
+            while (upd)
+            {
+                GdkRectangle rect;
+                rect.x = upd.GetX();
+                rect.y = upd.GetY();
+                rect.width = upd.GetWidth();
+                rect.height = upd.GetHeight();
+
+                gtk_paint_flat_box( parent->m_widget->style,
+                            pizza->bin_window,
+                            (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
+                            GTK_SHADOW_NONE,
+                            &rect,
+                            parent->m_widget,
+                            (char *)"base",
+                            0, 0, -1, -1 );
+
+                upd ++;
+            }
         }
     }
     else
@@ -3989,7 +4049,7 @@ void wxWindowGTK::GtkSendPaintEvents()
         wxEraseEvent erase_event( GetId(), &dc );
         erase_event.SetEventObject( this );
 
-        if (!GetEventHandler()->ProcessEvent(erase_event))
+        if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
         {
             if (!g_eraseGC)
             {
@@ -4114,8 +4174,9 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
     }
 
     // apply style change (forceStyle=true so that new style is applied
-    // even if the bg colour changed from valid to wxNullColour):
-    ApplyWidgetStyle(true);
+    // even if the bg colour changed from valid to wxNullColour)
+    if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
+        ApplyWidgetStyle(true);
 
     return true;
 }
@@ -4230,6 +4291,9 @@ void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
         DoApplyWidgetStyle(style);
         gtk_rc_style_unref(style);
     }
+
+    // Style change may affect GTK+'s size calculation:
+    InvalidateBestSize();
 }
 
 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
@@ -4239,6 +4303,43 @@ void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
     gtk_widget_modify_style(m_widget, style);
 }
 
+bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
+{
+    wxWindowBase::SetBackgroundStyle(style);
+    
+    if (style == wxBG_STYLE_CUSTOM)
+    {
+        GdkWindow *window = (GdkWindow*) NULL;
+        if (m_wxwindow)
+            window = GTK_PIZZA(m_wxwindow)->bin_window;
+        else
+            window = GetConnectWidget()->window;
+
+        if (window)
+        {
+            // Make sure GDK/X11 doesn't refresh the window
+            // automatically.
+            gdk_window_set_back_pixmap( window, None, False );
+#ifdef __X__
+            Display* display = GDK_WINDOW_DISPLAY(window);
+            XFlush(display);
+#endif
+            m_needsStyleChange = false;
+        }
+        else
+            // Do in OnIdle, because the window is not yet available
+            m_needsStyleChange = true;
+        
+        // Don't apply widget style, or we get a grey background
+    }
+    else
+    {
+        // apply style change (forceStyle=true so that new style is applied
+        // even if the bg colour changed from valid to wxNullColour):
+        ApplyWidgetStyle(true);
+    }
+    return true;
+}
 
 //-----------------------------------------------------------------------------
 // Pop-up menu stuff
@@ -4252,9 +4353,10 @@ void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting  )
     *is_waiting = FALSE;
 }
 
-static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
+void SetInvokingWindow( wxMenu *menu, wxWindow* win )
 {
     menu->SetInvokingWindow( win );
+    
     wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
     while (node)
     {
@@ -4295,16 +4397,20 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
 
     wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
 
+    // NOTE: if you change this code, you need to update
+    //       the same code in taskbar.cpp as well. This
+    //       is ugly code duplication, I know,
+
     SetInvokingWindow( menu, this );
 
     menu->UpdateUI();
 
     bool is_waiting = true;
 
-    gtk_signal_connect( GTK_OBJECT(menu->m_menu),
-                        "hide",
-                        GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
-                        (gpointer)&is_waiting );
+    gulong handler = gtk_signal_connect( GTK_OBJECT(menu->m_menu),
+                                         "hide",
+                                         GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
+                                         (gpointer)&is_waiting );
 
     wxPoint pos;
     gpointer userdata;
@@ -4341,6 +4447,8 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
         gtk_main_iteration();
     }
 
+    gtk_signal_disconnect(GTK_OBJECT(menu->m_menu), handler);
+
     return true;
 }