]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/toplevel.cpp
Fix for listbox problem, when created on invisible
[wxWidgets.git] / src / gtk / toplevel.cpp
index b91b944750fc2eb70e8e13aa2e8749b8129c6714..c5cbc54a40aeb2a750c09703897926ded776834a 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "wx/defs.h"
 
+#include "wx/toplevel.h"
 #include "wx/log.h"
 #include "wx/dialog.h"
 #include "wx/control.h"
@@ -61,10 +62,92 @@ extern bool g_isIdle;
 // data
 // ----------------------------------------------------------------------------
 
-extern wxList         wxPendingDelete;
+extern wxList           wxPendingDelete;
 
-extern int            g_openDialogs;
-extern wxWindowGTK   *g_delayedFocus;
+extern int              g_openDialogs;
+extern wxWindowGTK     *g_delayedFocus;
+
+// the frame that is currently active (i.e. its child has focus). It is
+// used to generate wxActivateEvents
+static wxTopLevelWindowGTK *g_activeFrame = (wxTopLevelWindowGTK*) NULL;
+static wxTopLevelWindowGTK *g_lastActiveFrame = (wxTopLevelWindowGTK*) 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;
+
+//-----------------------------------------------------------------------------
+// "focus_in_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_frame_focus_in_callback( GtkWidget *widget,
+                                         GdkEvent *WXUNUSED(event),
+                                         wxTopLevelWindowGTK *win )
+{
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+        
+    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_activeFrame = win;
+    g_lastActiveFrame = g_activeFrame;
+        
+    // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() );
+        
+    wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame);
+    wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
+    event.SetEventObject(g_activeFrame);
+    g_activeFrame->GetEventHandler()->ProcessEvent(event);
+
+    return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "focus_out_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_frame_focus_out_callback( GtkWidget *widget, 
+                                          GdkEventFocus *WXUNUSED(gdk_event), 
+                                          wxTopLevelWindowGTK *win )
+{
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+
+    // 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;
+        
+    // wxASSERT_MSG( (g_activeFrame == win), wxT("TLW deactivatd although it wasn't active") );
+        
+    // wxPrintf( wxT("inactive: %s\n"), win->GetTitle().c_str() );
+
+    if (g_activeFrame)
+    {
+        wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame);
+        wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
+        event.SetEventObject(g_activeFrame);
+        g_activeFrame->GetEventHandler()->ProcessEvent(event);
+
+        g_activeFrame = NULL;
+    }
+        
+    return FALSE;
+}
 
 //-----------------------------------------------------------------------------
 // "focus" from m_window
@@ -106,7 +189,6 @@ static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation*
 
         win->m_width = alloc->width;
         win->m_height = alloc->height;
-        win->m_queuedFullRedraw = TRUE;
         win->GtkUpdateSize();
     }
 }
@@ -142,6 +224,7 @@ gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *WX
     if (!win->m_hasVMT || !win->IsShown())
         return FALSE;
 
+
     int x = 0;
     int y = 0;
     gdk_window_get_root_origin( win->m_widget->window, &x, &y );
@@ -349,30 +432,57 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent,
     //     e.g. in wxTaskBarIconAreaGTK
     if (m_widget == NULL)
     {
-        GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
-
-        if (style & wxFRAME_TOOL_WINDOW)
-            win_type = GTK_WINDOW_POPUP;
-
         if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
         {
-            // there is no more GTK_WINDOW_DIALOG in 2.0
 #ifdef __WXGTK20__
-            win_type = GTK_WINDOW_TOPLEVEL;
+            m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+            // Tell WM that this is a dialog window and make it center
+            // on parent by default (this is what GtkDialog ctor does):
+            gtk_window_set_type_hint(GTK_WINDOW(m_widget),
+                                     GDK_WINDOW_TYPE_HINT_DIALOG);
+            gtk_window_set_position(GTK_WINDOW(m_widget),
+                                    GTK_WIN_POS_CENTER_ON_PARENT);
 #else
-            win_type = GTK_WINDOW_DIALOG;
+            m_widget = gtk_window_new(GTK_WINDOW_DIALOG);
 #endif
         }
+        else
+        {
+            m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+#if GTK_CHECK_VERSION(2,1,0)
+            if (style & wxFRAME_TOOL_WINDOW)
+            {
+                gtk_window_set_type_hint(GTK_WINDOW(m_widget),
+                                         GDK_WINDOW_TYPE_HINT_UTILITY);
+                
+                // On some WMs, like KDE, a TOOL_WINDOW will still show
+                // on the taskbar, but on Gnome a TOOL_WINDOW will not.
+                // For consistency between WMs and with Windows, we 
+                // should set the NO_TASKBAR flag which will apply
+                // the set_skip_taskbar_hint if it is available,
+                // ensuring no taskbar entry will appear.
+                style |= wxFRAME_NO_TASKBAR;
+            }
+#endif
 
-        m_widget = gtk_window_new( win_type );
+        }
     }
 
-    if (m_parent && (((GTK_IS_WINDOW(m_parent->m_widget)) &&
+    wxWindow *topParent = wxGetTopLevelParent(m_parent);
+    if (topParent && (((GTK_IS_WINDOW(topParent->m_widget)) &&
                      (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
                     (style & wxFRAME_FLOAT_ON_PARENT)))
     {
-        gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
+        gtk_window_set_transient_for( GTK_WINDOW(m_widget),
+                                      GTK_WINDOW(topParent->m_widget) );
+    }
+
+#if GTK_CHECK_VERSION(2,2,0)
+    if (style & wxFRAME_NO_TASKBAR)
+    {
+        gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE);
     }
+#endif
 
     if (!name.IsEmpty())
         gtk_window_set_wmclass( GTK_WINDOW(m_widget), wxGTK_CONV( name ), wxGTK_CONV( name ) );
@@ -445,6 +555,12 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent,
     gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
         GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
 
+    // activation
+    gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
+        GTK_SIGNAL_FUNC(gtk_frame_focus_in_callback), (gpointer)this );
+    gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
+        GTK_SIGNAL_FUNC(gtk_frame_focus_out_callback), (gpointer)this );
+            
     // decorations
     if ((m_miniEdge > 0) || (style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
     {
@@ -505,76 +621,100 @@ wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
     {
         gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
     }
+    
+    if (g_activeFrame == this)
+        g_activeFrame = NULL;
+    if (g_lastActiveFrame == this)
+        g_lastActiveFrame = NULL;
 }
 
 
 
 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
 {
-    if (show == m_fsIsShowing) return FALSE; // return what?
+    if (show == m_fsIsShowing)
+        return FALSE; // return what?
 
     m_fsIsShowing = show;
-
-    GdkWindow *window = m_widget->window;
+    
     wxX11FullScreenMethod method =
         wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
                                  (WXWindow)GDK_ROOT_WINDOW());
 
-    if (show)
+#if GTK_CHECK_VERSION(2,2,0)
+    // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
+    //     to switch to fullscreen, which is not always available. We must
+    //     check if WM supports the spec and use legacy methods if it
+    //     doesn't.
+    if (method == wxX11_FS_WMSPEC)
     {
-        m_fsSaveFlag = style;
-        GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
-        GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
-
-        int screen_width,screen_height;
-        wxDisplaySize( &screen_width, &screen_height );
-
-               gint client_x, client_y, root_x, root_y;
-               gint width, height;
-
-        if (method != wxX11_FS_WMSPEC)
-        {
-            // don't do it always, Metacity hates it
-            m_fsSaveGdkFunc = m_gdkFunc;
-            m_fsSaveGdkDecor = m_gdkDecor;
-            m_gdkFunc = m_gdkDecor = 0;
-            gdk_window_set_decorations(window, (GdkWMDecoration)0);
-            gdk_window_set_functions(window, (GdkWMFunction)0);
-        }
-
-               gdk_window_get_origin (m_widget->window, &root_x, &root_y);
-               gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
-                                        &width, &height, NULL);
-
-               gdk_window_move_resize (m_widget->window, -client_x, -client_y,
-                                       screen_width + 1, screen_height + 1);
+        if (show)
+            gtk_window_fullscreen( GTK_WINDOW( m_widget ) );
+        else
+            gtk_window_unfullscreen( GTK_WINDOW( m_widget ) );
 
-        wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
-                                (WXWindow)GDK_ROOT_WINDOW(),
-                                (WXWindow)GDK_WINDOW_XWINDOW(window),
-                                show, &m_fsSaveFrame, method);
+        return TRUE;
     }
     else
+#endif // GTK+ >= 2.2.0
     {
-        if (method != wxX11_FS_WMSPEC)
+        GdkWindow *window = m_widget->window;
+
+        if (show)
         {
-            // don't do it always, Metacity hates it
-            m_gdkFunc = m_fsSaveGdkFunc;
-            m_gdkDecor = m_fsSaveGdkDecor;
-            gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
-            gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
+            m_fsSaveFlag = style;
+            GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
+            GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
+
+            int screen_width,screen_height;
+            wxDisplaySize( &screen_width, &screen_height );
+
+            gint client_x, client_y, root_x, root_y;
+            gint width, height;
+
+            if (method != wxX11_FS_WMSPEC)
+            {
+                // don't do it always, Metacity hates it
+                m_fsSaveGdkFunc = m_gdkFunc;
+                m_fsSaveGdkDecor = m_gdkDecor;
+                m_gdkFunc = m_gdkDecor = 0;
+                gdk_window_set_decorations(window, (GdkWMDecoration)0);
+                gdk_window_set_functions(window, (GdkWMFunction)0);
+            }
+
+            gdk_window_get_origin (m_widget->window, &root_x, &root_y);
+            gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
+                         &width, &height, NULL);
+
+            gdk_window_move_resize (m_widget->window, -client_x, -client_y,
+                        screen_width + 1, screen_height + 1);
+
+            wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
+                                    (WXWindow)GDK_ROOT_WINDOW(),
+                                    (WXWindow)GDK_WINDOW_XWINDOW(window),
+                                    show, &m_fsSaveFrame, method);
+        }
+        else
+        {
+            if (method != wxX11_FS_WMSPEC)
+            {
+                // don't do it always, Metacity hates it
+                m_gdkFunc = m_fsSaveGdkFunc;
+                m_gdkDecor = m_fsSaveGdkDecor;
+                gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
+                gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
+            }
+
+            wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
+                                    (WXWindow)GDK_ROOT_WINDOW(),
+                                    (WXWindow)GDK_WINDOW_XWINDOW(window),
+                                    show, &m_fsSaveFrame, method);
+
+            SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
+                    m_fsSaveFrame.width, m_fsSaveFrame.height);
         }
-
-        wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
-                                (WXWindow)GDK_ROOT_WINDOW(),
-                                (WXWindow)GDK_WINDOW_XWINDOW(window),
-                                show, &m_fsSaveFrame, method);
-
-        SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
-                m_fsSaveFrame.width, m_fsSaveFrame.height);
     }
 
-
     return TRUE;
 }
 
@@ -595,7 +735,10 @@ bool wxTopLevelWindowGTK::Show( bool show )
 
         GtkOnSize( m_x, m_y, m_width, m_height );
     }
-
+    
+    if (show)
+        gtk_widget_set_uposition( m_widget, m_x, m_y );
+    
     return wxWindow::Show( show );
 }
 
@@ -857,6 +1000,20 @@ void wxTopLevelWindowGTK::OnInternalIdle()
     }
 
     wxWindow::OnInternalIdle();
+    
+    // Synthetize activate events.
+    if ( g_sendActivateEvent != -1 )
+    {
+        bool activate = g_sendActivateEvent != 0;
+        
+        // if (!activate) wxPrintf( wxT("de") );
+        // wxPrintf( wxT("activate\n") );
+        
+        // do it only once
+        g_sendActivateEvent = -1;
+
+        wxTheApp->SetActive(activate, (wxWindow *)g_lastActiveFrame);
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -871,21 +1028,6 @@ void wxTopLevelWindowGTK::SetTitle( const wxString &title )
     gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
 }
 
-void wxTopLevelWindowGTK::DoSetIcon( const wxIcon &icon )
-{
-    if ( !icon.Ok() )
-        return;
-
-    if (!m_widget->window)
-        return;
-
-    wxMask *mask = icon.GetMask();
-    GdkBitmap *bm = (GdkBitmap *) NULL;
-    if (mask) bm = mask->GetBitmap();
-
-    gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
-}
-
 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
 {
     SetIcons( wxIconBundle( icon ) );
@@ -894,16 +1036,41 @@ void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
 {
     wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
-    GdkWindow* window = m_widget->window;
 
     wxTopLevelWindowBase::SetIcons( icons );
 
-    DoSetIcon( icons.GetIcon( -1 ) );
-    if ( window )
+#ifdef __WXGTK20__
+    GList *list = NULL;
+    size_t max = icons.m_icons.GetCount();
+
+    for (size_t i = 0; i < max; i++)
+    {
+        if (icons.m_icons[i].Ok())
+        {
+            list = g_list_prepend(list, icons.m_icons[i].GetPixbuf());
+        }
+    }
+    gtk_window_set_icon_list(GTK_WINDOW(m_widget), list);
+    g_list_free(list);
+    
+#else // !__WXGTK20__
+    GdkWindow* window = m_widget->window;
+    if (!window)
+        return;
+
+    wxIcon icon = icons.GetIcon(-1);
+    if (icon.Ok())
     {
-        wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
-                       (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
+        wxMask *mask = icon.GetMask();
+        GdkBitmap *bm = (GdkBitmap *) NULL;
+        if (mask) bm = mask->GetBitmap();
+
+        gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
     }
+
+    wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
+                   (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
+#endif // !__WXGTK20__
 }
 
 // ----------------------------------------------------------------------------
@@ -924,15 +1091,22 @@ void wxTopLevelWindowGTK::Maximize(bool maximize)
 
 bool wxTopLevelWindowGTK::IsMaximized() const
 {
+#ifdef __WXGTK20__
+    if(!m_widget->window)
+        return false;
+
+    return gdk_window_get_state(m_widget->window) & GDK_WINDOW_STATE_MAXIMIZED;
+#else
   //    wxFAIL_MSG( _T("not implemented") );
 
     // This is an approximation
     return FALSE;
+#endif
 }
 
 void wxTopLevelWindowGTK::Restore()
 {
-#ifdef __GTK20__
+#ifdef __WXGTK20__
     // "Present" seems similar enough to "restore"
     gtk_window_present( GTK_WINDOW( m_widget ) );
 #else
@@ -1038,4 +1212,8 @@ bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
     return do_shape_combine_region(window, region);
 }
 
-// vi:sts=4:sw=4:et
+bool wxTopLevelWindowGTK::IsActive()
+{
+    return (this == (wxTopLevelWindowGTK*)g_activeFrame);
+}
+