]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/app.cpp
Second part of #15224 fix: AddRows, AddColumns (dghart)
[wxWidgets.git] / src / gtk / app.cpp
index a7c984dd3bdc1746228868bc6d204431b8a69cbb..2bd616a4ba5f4cf5783d18eccbda3aabd16f89ef 100644 (file)
@@ -2,7 +2,6 @@
 // Name:        src/gtk/app.cpp
 // Purpose:
 // Author:      Robert Roebling
-// Id:          $Id$
 // Copyright:   (c) 1998 Robert Roebling, Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
     #include <gpe/init.h>
 #endif
 
-#include "wx/gtk/private.h"
 #include "wx/apptrait.h"
+#include "wx/fontmap.h"
 
 #if wxUSE_LIBHILDON
     #include <hildon-widgets/hildon-program.h>
 #endif // wxUSE_LIBHILDON
 
-#include <gdk/gdkx.h>
+#if wxUSE_LIBHILDON2
+    #include <hildon/hildon.h>
+#endif // wxUSE_LIBHILDON2
+
+#include <gtk/gtk.h>
+#include "wx/gtk/private.h"
 
 //-----------------------------------------------------------------------------
 // link GnomeVFS
     wxFORCE_LINK_MODULE(gnome_vfs)
 #endif
 
-//-----------------------------------------------------------------------------
-// global data
-//-----------------------------------------------------------------------------
-
-static GtkWidget *gs_RootWindow = NULL;
-static wxArrayPtrVoid g_arrGdkEvents;
-
-//-----------------------------------------------------------------------------
-// wxYield
-//-----------------------------------------------------------------------------
-
-bool wxApp::DoYield(bool onlyIfNeeded, long eventsToProcess)
-{
-    if ( m_isInsideYield )
-    {
-        if ( !onlyIfNeeded )
-        {
-            wxFAIL_MSG( wxT("wxYield called recursively" ) );
-        }
-
-        return false;
-    }
-
-#if wxUSE_THREADS
-    if ( !wxThread::IsMain() )
-    {
-        // can't call gtk_main_iteration() from other threads like this
-        return true;
-    }
-#endif // wxUSE_THREADS
-
-    m_isInsideYield = true;
-    m_eventsToProcessInsideYield = eventsToProcess;
-
-#if wxUSE_LOG
-    // disable log flushing from here because a call to wxYield() shouldn't
-    // normally result in message boxes popping up &c
-    wxLog::Suspend();
-#endif
-
-    // NOTE: gtk_main_iteration() doesn't allow us to filter events, so we
-    //       rather use gtk_main_do_event() after filtering the events at
-    //       GDK level
-
-    GdkDisplay* disp = gtk_widget_get_display(gs_RootWindow);
-
-    // gdk_display_get_event() will transform X11 events into GDK events
-    // and will queue all of them in the display (private) structure;
-    // finally it will "unqueue" the last one and return it to us
-    GdkEvent* event = gdk_display_get_event(disp);
-    while (event)
-    {
-        // categorize the GDK event according to wxEventCategory.
-        // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
-        // for more info.
-
-        wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
-        switch (event->type)
-        {
-        case GDK_SELECTION_REQUEST:
-        case GDK_SELECTION_NOTIFY:
-        case GDK_SELECTION_CLEAR:
-        case GDK_OWNER_CHANGE:
-            cat = wxEVT_CATEGORY_CLIPBOARD;
-            break;
-
-
-        case GDK_KEY_PRESS:
-        case GDK_KEY_RELEASE:
-        case GDK_BUTTON_PRESS:
-        case GDK_2BUTTON_PRESS:
-        case GDK_3BUTTON_PRESS:
-        case GDK_BUTTON_RELEASE:
-        case GDK_SCROLL:        // generated from mouse buttons
-        case GDK_CLIENT_EVENT:
-            cat = wxEVT_CATEGORY_USER_INPUT;
-            break;
-
-
-        case GDK_PROXIMITY_IN:
-        case GDK_PROXIMITY_OUT:
-
-        case GDK_MOTION_NOTIFY:
-        case GDK_ENTER_NOTIFY:
-        case GDK_LEAVE_NOTIFY:
-        case GDK_VISIBILITY_NOTIFY:
-        case GDK_PROPERTY_NOTIFY:
-
-        case GDK_FOCUS_CHANGE:
-        case GDK_CONFIGURE:
-        case GDK_WINDOW_STATE:
-        case GDK_SETTING:
-        case GDK_DELETE:
-        case GDK_DESTROY:
-
-        case GDK_EXPOSE:
-        case GDK_NO_EXPOSE:
-        case GDK_MAP:
-        case GDK_UNMAP:
-        //case GDK_DAMAGE:
-
-        case GDK_DRAG_ENTER:
-        case GDK_DRAG_LEAVE:
-        case GDK_DRAG_MOTION:
-        case GDK_DRAG_STATUS:
-        case GDK_DROP_START:
-        case GDK_DROP_FINISHED:
-        case GDK_GRAB_BROKEN:
-            cat = wxEVT_CATEGORY_UI;
-            break;
-
-        default:
-            cat = wxEVT_CATEGORY_UNKNOWN;
-            break;
-        }
-
-        if (eventsToProcess & cat)
-            gtk_main_do_event(event);       // process it now
-        else
-            g_arrGdkEvents.Add(event);      // process it later
-
-        // get next event
-        event = gdk_display_get_event(disp);
-    }
-
-    if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
-    {
-        // It's necessary to call ProcessIdle() to update the frames sizes which
-        // might have been changed (it also will update other things set from
-        // OnUpdateUI() which is a nice (and desired) side effect). But we
-        // call ProcessIdle() only once since this is not meant for longish
-        // background jobs (controlled by wxIdleEvent::RequestMore() and the
-        // return value of Processidle().
-        ProcessIdle();      // ProcessIdle() also calls ProcessPendingEvents()
-    }
-    //else: if we are inside ~wxClipboardSync() and we call ProcessIdle() and
-    //      the user app contains an UI update handler which calls wxClipboard::IsSupported,
-    //      then we fall into a never-ending loop...
-
-    // put all unprocessed GDK events back in the queue
-    for (size_t i=0; i<g_arrGdkEvents.GetCount(); i++)
-    {
-        GdkEvent* ev = (GdkEvent*)g_arrGdkEvents[i];
-
-        // NOTE: gdk_display_put_event makes a copy of the event passed to it
-        gdk_display_put_event(disp, ev);
-        gdk_event_free(ev);
-    }
-
-    g_arrGdkEvents.Clear();
-
-#if wxUSE_LOG
-    // let the logs be flashed again
-    wxLog::Resume();
-#endif
-
-    m_isInsideYield = false;
-
-    return true;
-}
-
 //-----------------------------------------------------------------------------
 // local functions
 //-----------------------------------------------------------------------------
@@ -217,9 +60,9 @@ wx_emission_hook(GSignalInvocationHint*, guint, const GValue*, gpointer data)
     wxApp* app = wxTheApp;
     if (app != NULL)
         app->WakeUpIdle();
-    gulong* hook_id = (gulong*)data;
+    bool* hook_installed = (bool*)data;
     // record that hook is not installed
-    *hook_id = 0;
+    *hook_installed = false;
     // remove hook
     return false;
 }
@@ -230,28 +73,30 @@ static void wx_add_idle_hooks()
 {
     // "event" hook
     {
-        static gulong hook_id = 0;
-        if (hook_id == 0)
+        static bool hook_installed;
+        if (!hook_installed)
         {
-            static guint sig_id = 0;
+            static guint sig_id;
             if (sig_id == 0)
                 sig_id = g_signal_lookup("event", GTK_TYPE_WIDGET);
-            hook_id = g_signal_add_emission_hook(
-                sig_id, 0, wx_emission_hook, &hook_id, NULL);
+            hook_installed = true;
+            g_signal_add_emission_hook(
+                sig_id, 0, wx_emission_hook, &hook_installed, NULL);
         }
     }
     // "size_allocate" hook
-    // Needed to match the behavior of the old idle system,
+    // Needed to match the behaviour of the old idle system,
     // but probably not necessary.
     {
-        static gulong hook_id = 0;
-        if (hook_id == 0)
+        static bool hook_installed;
+        if (!hook_installed)
         {
-            static guint sig_id = 0;
+            static guint sig_id;
             if (sig_id == 0)
                 sig_id = g_signal_lookup("size_allocate", GTK_TYPE_WIDGET);
-            hook_id = g_signal_add_emission_hook(
-                sig_id, 0, wx_emission_hook, &hook_id, NULL);
+            hook_installed = true;
+            g_signal_add_emission_hook(
+                sig_id, 0, wx_emission_hook, &hook_installed, NULL);
         }
     }
 }
@@ -271,14 +116,15 @@ bool wxApp::DoIdle()
         // Needed if an idle event handler runs a new event loop,
         // for example by showing a dialog.
 #if wxUSE_THREADS
-        wxMutexLocker lock(*m_idleMutex);
+        wxMutexLocker lock(m_idleMutex);
 #endif
         id_save = m_idleSourceId;
         m_idleSourceId = 0;
         wx_add_idle_hooks();
-#ifdef __WXDEBUG__
+
+#if wxDEBUG_LEVEL
         // don't generate the idle events while the assert modal dialog is shown,
-        // this matches the behavior of wxMSW
+        // this matches the behaviour of wxMSW
         if (m_isInAssert)
             return false;
 #endif
@@ -287,35 +133,35 @@ bool wxApp::DoIdle()
     gdk_threads_enter();
     bool needMore;
     do {
+        ProcessPendingEvents();
+
         needMore = ProcessIdle();
     } while (needMore && gtk_events_pending() == 0);
     gdk_threads_leave();
 
 #if wxUSE_THREADS
-    wxMutexLocker lock(*m_idleMutex);
+    wxMutexLocker lock(m_idleMutex);
 #endif
-    // if a new idle source was added during ProcessIdle
-    if (m_idleSourceId != 0)
-    {
-        // remove it
-        g_source_remove(m_idleSourceId);
-        m_idleSourceId = 0;
-    }
 
-    // Pending events can be added asynchronously,
-    // need to keep idle source if any have appeared
-    needMore = needMore || HasPendingEvents();
-
-    // if more idle processing requested
-    if (needMore)
+    bool keepSource = false;
+    // if a new idle source has not been added, either as a result of idle
+    // processing above or by another thread calling WakeUpIdle()
+    if (m_idleSourceId == 0)
     {
-        // keep this source installed
-        m_idleSourceId = id_save;
-        return true;
+        // if more idle processing was requested or pending events have appeared
+        if (needMore || HasPendingEvents())
+        {
+            // keep this source installed
+            m_idleSourceId = id_save;
+            keepSource = true;
+        }
+        else // add hooks and remove this source
+            wx_add_idle_hooks();
     }
-    // add hooks and remove this source
-    wx_add_idle_hooks();
-    return false;
+    // else remove this source, leave new one installed
+    // we must keep an idle source, otherwise a wakeup could be lost
+
+    return keepSource;
 }
 
 //-----------------------------------------------------------------------------
@@ -324,12 +170,14 @@ bool wxApp::DoIdle()
 
 GtkWidget* wxGetRootWindow()
 {
-    if (gs_RootWindow == NULL)
+    static GtkWidget *s_RootWindow = NULL;
+
+    if (s_RootWindow == NULL)
     {
-        gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
-        gtk_widget_realize( gs_RootWindow );
+        s_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+        gtk_widget_realize( s_RootWindow );
     }
-    return gs_RootWindow;
+    return s_RootWindow;
 }
 
 //-----------------------------------------------------------------------------
@@ -340,12 +188,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
 
 wxApp::wxApp()
 {
-#ifdef __WXDEBUG__
     m_isInAssert = false;
-#endif // __WXDEBUG__
-#if wxUSE_THREADS
-    m_idleMutex = NULL;
-#endif
     m_idleSourceId = 0;
 }
 
@@ -355,6 +198,10 @@ wxApp::~wxApp()
 
 bool wxApp::SetNativeTheme(const wxString& theme)
 {
+#ifdef __WXGTK3__
+    wxUnusedVar(theme);
+    return false;
+#else
     wxString path;
     path = gtk_rc_get_theme_dir();
     path += "/";
@@ -375,6 +222,7 @@ bool wxApp::SetNativeTheme(const wxString& theme)
     gtk_rc_reparse_all_for_settings(gtk_settings_get_default(), TRUE);
 
     return true;
+#endif
 }
 
 bool wxApp::OnInitGui()
@@ -382,6 +230,7 @@ bool wxApp::OnInitGui()
     if ( !wxAppBase::OnInitGui() )
         return false;
 
+#ifndef __WXGTK3__
     // if this is a wxGLApp (derived from wxApp), and we've already
     // chosen a specific visual, then derive the GdkVisual from that
     if ( GetXVisualInfo() )
@@ -419,34 +268,19 @@ bool wxApp::OnInitGui()
             }
         }
     }
+#endif
 
-#if wxUSE_LIBHILDON
-    m_hildonProgram = hildon_program_get_instance();
-    if ( !m_hildonProgram )
+#if wxUSE_LIBHILDON || wxUSE_LIBHILDON2
+    if ( !GetHildonProgram() )
     {
         wxLogError(_("Unable to initialize Hildon program"));
         return false;
     }
-#endif // wxUSE_LIBHILDON
+#endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2
 
     return true;
 }
 
-GdkVisual *wxApp::GetGdkVisual()
-{
-    GdkVisual *visual = NULL;
-
-    XVisualInfo *xvi = (XVisualInfo *)GetXVisualInfo();
-    if ( xvi )
-        visual = gdkx_visual_get( xvi->visualid );
-    else
-        visual = gdk_drawable_get_visual( wxGetRootWindow()->window );
-
-    wxASSERT( visual );
-
-    return visual;
-}
-
 // use unusual names for the parameters to avoid conflict with wxApp::arg[cv]
 bool wxApp::Initialize(int& argc_, wxChar **argv_)
 {
@@ -464,38 +298,48 @@ bool wxApp::Initialize(int& argc_, wxChar **argv_)
     // gtk+ 2.0 supports Unicode through UTF-8 strings
     wxConvCurrent = &wxConvUTF8;
 
+#ifdef __UNIX__
     // decide which conversion to use for the file names
 
     // (1) this variable exists for the sole purpose of specifying the encoding
     //     of the filenames for GTK+ programs, so use it if it is set
-    wxString encName(wxGetenv(_T("G_FILENAME_ENCODING")));
-    encName = encName.BeforeFirst(_T(','));
-    if (encName.CmpNoCase(_T("@locale")) == 0)
+    wxString encName(wxGetenv(wxT("G_FILENAME_ENCODING")));
+    encName = encName.BeforeFirst(wxT(','));
+    if (encName.CmpNoCase(wxT("@locale")) == 0)
         encName.clear();
     encName.MakeUpper();
-#if wxUSE_INTL
     if (encName.empty())
     {
+#if wxUSE_INTL
         // (2) if a non default locale is set, assume that the user wants his
         //     filenames in this locale too
         encName = wxLocale::GetSystemEncodingName().Upper();
+
+        // But don't consider ASCII in this case.
+        if ( !encName.empty() )
+        {
+#if wxUSE_FONTMAP
+            wxFontEncoding enc = wxFontMapperBase::GetEncodingFromName(encName);
+            if ( enc == wxFONTENCODING_DEFAULT )
+#else // !wxUSE_FONTMAP
+            if ( encName == wxT("US-ASCII") )
+#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
+            {
+                // This means US-ASCII when returned from GetEncodingFromName().
+                encName.clear();
+            }
+        }
+#endif // wxUSE_INTL
+
         // (3) finally use UTF-8 by default
-        if (encName.empty() || encName == _T("US-ASCII"))
-            encName = _T("UTF-8");
-        wxSetEnv(_T("G_FILENAME_ENCODING"), encName);
+        if ( encName.empty() )
+            encName = wxT("UTF-8");
+        wxSetEnv(wxT("G_FILENAME_ENCODING"), encName);
     }
-#else
-    if (encName.empty())
-        encName = _T("UTF-8");
 
-    // if wxUSE_INTL==0 it probably indicates that only "C" locale is supported
-    // by the program anyhow so prevent GTK+ from calling setlocale(LC_ALL, "")
-    // from gtk_init_check() as it does by default
-    gtk_disable_setlocale();
-
-#endif // wxUSE_INTL
     static wxConvBrokenFileNames fileconv(encName);
     wxConvFileName = &fileconv;
+#endif // __UNIX__
 
 
     bool init_result;
@@ -513,13 +357,17 @@ bool wxApp::Initialize(int& argc_, wxChar **argv_)
 
     int argcGTK = argc_;
 
+    // Prevent gtk_init_check() from changing the locale automatically for
+    // consistency with the other ports that don't do it. If necessary,
+    // wxApp::SetCLocale() may be explicitly called.
+    gtk_disable_setlocale();
+
 #ifdef __WXGPE__
     init_result = true;  // is there a _check() version of this?
     gpe_application_init( &argcGTK, &argvGTK );
 #else
-    init_result = gtk_init_check( &argcGTK, &argvGTK );
+    init_result = gtk_init_check( &argcGTK, &argvGTK ) != 0;
 #endif
-    wxUpdateLocaleIsUtf8();
 
     if ( argcGTK != argc_ )
     {
@@ -592,18 +440,13 @@ bool wxApp::Initialize(int& argc_, wxChar **argv_)
         return false;
     }
 
-    // we can not enter threads before gtk_init is done
+    // we cannot enter threads before gtk_init is done
     gdk_threads_enter();
 
-    wxSetDetectableAutoRepeat( true );
-
 #if wxUSE_INTL
     wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
 #endif
 
-#if wxUSE_THREADS
-    m_idleMutex = new wxMutex;
-#endif
     // make sure GtkWidget type is loaded, idle hooks need it
     g_type_class_ref(GTK_TYPE_WIDGET);
     WakeUpIdle();
@@ -622,20 +465,12 @@ void wxApp::CleanUp()
     gdk_threads_leave();
 
     wxAppBase::CleanUp();
-
-    // delete this mutex as late as possible as it's used from WakeUpIdle(), in
-    // particular do it after calling the base class CleanUp() which can result
-    // in it being called
-#if wxUSE_THREADS
-    delete m_idleMutex;
-    m_idleMutex = NULL;
-#endif
 }
 
 void wxApp::WakeUpIdle()
 {
 #if wxUSE_THREADS
-    wxMutexLocker lock(*m_idleMutex);
+    wxMutexLocker lock(m_idleMutex);
 #endif
     if (m_idleSourceId == 0)
         m_idleSourceId = g_idle_add_full(G_PRIORITY_LOW, wxapp_idle_callback, NULL, NULL);
@@ -646,7 +481,7 @@ void wxApp::WakeUpIdle()
 bool wxApp::EventsPending()
 {
 #if wxUSE_THREADS
-    wxMutexLocker lock(*m_idleMutex);
+    wxMutexLocker lock(m_idleMutex);
 #endif
     if (m_idleSourceId != 0)
     {
@@ -657,25 +492,30 @@ bool wxApp::EventsPending()
     return gtk_events_pending() != 0;
 }
 
-#ifdef __WXDEBUG__
-
 void wxApp::OnAssertFailure(const wxChar *file,
                             int line,
                             const wxChar* func,
                             const wxChar* cond,
                             const wxChar *msg)
 {
-
+    // there is no need to do anything if asserts are disabled in this build
+    // anyhow
+#if wxDEBUG_LEVEL
     // block wx idle events while assert dialog is showing
     m_isInAssert = true;
 
     wxAppBase::OnAssertFailure(file, line, func, cond, msg);
 
     m_isInAssert = false;
+#else // !wxDEBUG_LEVEL
+    wxUnusedVar(file);
+    wxUnusedVar(line);
+    wxUnusedVar(func);
+    wxUnusedVar(cond);
+    wxUnusedVar(msg);
+#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
 }
 
-#endif // __WXDEBUG__
-
 #if wxUSE_THREADS
 void wxGUIAppTraits::MutexGuiEnter()
 {
@@ -687,3 +527,31 @@ void wxGUIAppTraits::MutexGuiLeave()
     gdk_threads_leave();
 }
 #endif // wxUSE_THREADS
+
+/* static */
+bool wxApp::GTKIsUsingGlobalMenu()
+{
+    static int s_isUsingGlobalMenu = -1;
+    if ( s_isUsingGlobalMenu == -1 )
+    {
+        // Currently we just check for this environment variable because this
+        // is how support for the global menu is implemented under Ubuntu.
+        //
+        // If we ever get false positives, we could also check for
+        // XDG_CURRENT_DESKTOP env var being set to "Unity".
+        wxString proxy;
+        s_isUsingGlobalMenu = wxGetEnv("UBUNTU_MENUPROXY", &proxy) &&
+                                !proxy.empty() && proxy != "0";
+    }
+
+    return s_isUsingGlobalMenu == 1;
+}
+
+#if wxUSE_LIBHILDON || wxUSE_LIBHILDON2
+// Maemo-specific method: get the main program object
+HildonProgram *wxApp::GetHildonProgram()
+{
+    return hildon_program_get_instance();
+}
+
+#endif // wxUSE_LIBHILDON || wxUSE_LIBHILDON2