]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/src/helpers.cpp
fix text scrolling in GTK2 (patch 703988)
[wxWidgets.git] / wxPython / src / helpers.cpp
index c47bd837c5b72ec034ba8a54dad1dc7398b5b056..57b971ae57ad73e7bd8d21bfd0b22cd2bf78d6fe 100644 (file)
 #include <wx/gtk/win_gtk.h>
 #endif
 
+#include <wx/clipbrd.h>
+#include <wx/mimetype.h>
+#include <wx/image.h>
+
 //----------------------------------------------------------------------
 
 #if PYTHON_API_VERSION <= 1007 && wxUSE_UNICODE
 
 //----------------------------------------------------------------------
 
-#ifdef __WXGTK__
-int  WXDLLEXPORT wxEntryStart( int& argc, char** argv );
-#else
-int  WXDLLEXPORT wxEntryStart( int argc, char** argv );
-#endif
-int  WXDLLEXPORT wxEntryInitGui();
-void WXDLLEXPORT wxEntryCleanup();
-
 wxPyApp* wxPythonApp = NULL;  // Global instance of application object
 bool wxPyDoCleanup = FALSE;
 bool wxPyDoingCleanup = FALSE;
@@ -334,6 +330,7 @@ void wxPyApp::SetMacHelpMenuTitleName(const wxString& val) {
 //----------------------------------------------------------------------
 
 
+#if 0
 static char* wxPyCopyCString(const wxChar* src)
 {
     wxWX2MBbuf buff = (wxWX2MBbuf)wxConvCurrent->cWX2MB(src);
@@ -366,13 +363,13 @@ static wxChar* wxPyCopyWString(const wxChar *src)
     return copystring(src);
 }
 #endif
+#endif
 
 
 //----------------------------------------------------------------------
 
-// This is where we pick up the first part of the wxEntry functionality...
-// The rest is in __wxStart and  __wxCleanup.  This function is called when
-// wxcmodule is imported.  (Before there is a wxApp object.)
+// This function is called when the wxc module is imported to do some initial
+// setup.  (Before there is a wxApp object.)
 void __wxPreStart(PyObject* moduleDict)
 {
 
@@ -386,72 +383,60 @@ void __wxPreStart(PyObject* moduleDict)
     wxPyTMutex = new wxMutex;
 #endif
 
-    wxApp::CheckBuildOptions(wxBuildOptions());
+    // Ensure that the build options in the DLL (or whatever) match this build
+    wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "wxPython");
 
+    // Create an exception object to use for wxASSERTions
     wxPyAssertionError = PyErr_NewException("wxPython.wxc.wxPyAssertionError",
                                             PyExc_AssertionError, NULL);
     PyDict_SetItemString(moduleDict, "wxPyAssertionError", wxPyAssertionError);
-
-
-    // Bail out if there is already a wxApp created.  This means that the
-    // toolkit has already been initialized, as in embedding wxPython in
-    // a C++ wxWindows app, so we don't need to call wxEntryStart.
-    if (wxTheApp != NULL) {
-        return;
-    }
-    wxPyDoCleanup = TRUE;
-
-    int argc = 0;
-    char** argv = NULL;
-    PyObject* sysargv = PySys_GetObject("argv");
-    if (sysargv != NULL) {
-        argc = PyList_Size(sysargv);
-        argv = new char*[argc+1];
-        int x;
-        for(x=0; x<argc; x++) {
-           PyObject *item = PyList_GetItem(sysargv, x);
-            argv[x] = wxPyCopyCString(Py2wxString(item));
-       }
-        argv[argc] = NULL;
-    }
-
-    wxEntryStart(argc, argv);
-    delete [] argv;
 }
 
 
-// Start the user application, user App's OnInit method is a parameter here
+
+// Initialize wxWindows and bootstrap the user application by calling the
+// wxApp's OnInit, which is a parameter to this funciton.  See wxApp.__init__
+// in _extras.py to learn how the bootstrap is started.
 PyObject* __wxStart(PyObject* /* self */, PyObject* args)
 {
     PyObject*   onInitFunc = NULL;
-    PyObject*   arglist;
-    PyObject*   result;
+    PyObject*   arglist= NULL;
+    PyObject*   result = NULL;
+    PyObject*   pyint = NULL;
     long        bResult;
 
     if (!PyArg_ParseTuple(args, "O", &onInitFunc))
         return NULL;
 
-    // This is the next part of the wxEntry functionality...
+    // Get any command-line args passed to this program from the sys module
     int argc = 0;
-    wxChar** argv = NULL;
+    char** argv = NULL;
     PyObject* sysargv = PySys_GetObject("argv");
     if (sysargv != NULL) {
         argc = PyList_Size(sysargv);
-        argv = new wxChar*[argc+1];
+        argv = new char*[argc+1];
         int x;
         for(x=0; x<argc; x++) {
             PyObject *pyArg = PyList_GetItem(sysargv, x);
-            argv[x] = wxPyCopyWString(Py2wxString(pyArg));
+            argv[x] = PyString_AsString(pyArg);
         }
         argv[argc] = NULL;
     }
 
-    wxPythonApp->argc = argc;
-    wxPythonApp->argv = argv;
+    if (! wxEntryStart(argc, argv) ) {
+        PyErr_SetString(PyExc_SystemError,      // is this the right one?
+                        "wxEntryStart failed!");
+        goto error;
+    }
+    delete [] argv;
+
+
+    // The stock objects were all NULL when they were loaded into
+    // SWIG generated proxies, so re-init those now...
+    wxPy_ReinitStockObjects();
 
-    wxEntryInitGui();
 
-    // Call the Python App's OnInit function
+    // Call the Python wxApp's OnInit function
     arglist = PyTuple_New(0);
     result = PyEval_CallObject(onInitFunc, arglist);
     Py_DECREF(arglist);
@@ -459,7 +444,7 @@ PyObject* __wxStart(PyObject* /* self */, PyObject* args)
         return NULL;
     }
 
-    PyObject* pyint = PyNumber_Int(result);
+    pyint = PyNumber_Int(result);
     if (! pyint) {
         PyErr_SetString(PyExc_TypeError, "OnInit should return a boolean value");
         goto error;
@@ -486,6 +471,7 @@ PyObject* __wxStart(PyObject* /* self */, PyObject* args)
 }
 
 
+
 void __wxCleanup() {
     wxPyDoingCleanup = TRUE;
     if (wxPyDoCleanup)
@@ -548,6 +534,102 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
     return Py_None;
 }
 
+
+//---------------------------------------------------------------------------
+
+// The stock objects are no longer created when the wxc module is imported, but
+// only after the app object has been created.  This function will be called before
+// OnInit is called so we can hack the new pointer values into the obj.this attributes.
+
+void wxPy_ReinitStockObjects()
+{
+    char ptrbuf[128];
+    PyObject* obj;
+    PyObject* ptrobj;
+
+
+
+#define REINITOBJ(name, type) \
+    obj = PyDict_GetItemString(wxPython_dict, #name); \
+    wxASSERT_MSG(obj != NULL, wxT("Unable to find stock object for " #name)); \
+    SWIG_MakePtr(ptrbuf, (char *) name, "_" #type "_p"); \
+    ptrobj = PyString_FromString(ptrbuf); \
+    PyObject_SetAttrString(obj, "this", ptrobj); \
+    Py_DECREF(ptrobj)
+
+#define REINITOBJ2(name, type) \
+    obj = PyDict_GetItemString(wxPython_dict, #name); \
+    wxASSERT_MSG(obj != NULL, wxT("Unable to find stock object for " #name)); \
+    SWIG_MakePtr(ptrbuf, (char *) &name, "_" #type "_p"); \
+    ptrobj = PyString_FromString(ptrbuf); \
+    PyObject_SetAttrString(obj, "this", ptrobj); \
+    Py_DECREF(ptrobj)
+
+
+    REINITOBJ(wxNORMAL_FONT, wxFont);
+    REINITOBJ(wxSMALL_FONT, wxFont);
+    REINITOBJ(wxITALIC_FONT, wxFont);
+    REINITOBJ(wxSWISS_FONT, wxFont);
+
+    REINITOBJ(wxRED_PEN, wxPen);
+    REINITOBJ(wxCYAN_PEN, wxPen);
+    REINITOBJ(wxGREEN_PEN, wxPen);
+    REINITOBJ(wxBLACK_PEN, wxPen);
+    REINITOBJ(wxWHITE_PEN, wxPen);
+    REINITOBJ(wxTRANSPARENT_PEN, wxPen);
+    REINITOBJ(wxBLACK_DASHED_PEN, wxPen);
+    REINITOBJ(wxGREY_PEN, wxPen);
+    REINITOBJ(wxMEDIUM_GREY_PEN, wxPen);
+    REINITOBJ(wxLIGHT_GREY_PEN, wxPen);
+
+    REINITOBJ(wxBLUE_BRUSH, wxBrush);
+    REINITOBJ(wxGREEN_BRUSH, wxBrush);
+    REINITOBJ(wxWHITE_BRUSH, wxBrush);
+    REINITOBJ(wxBLACK_BRUSH, wxBrush);
+    REINITOBJ(wxTRANSPARENT_BRUSH, wxBrush);
+    REINITOBJ(wxCYAN_BRUSH, wxBrush);
+    REINITOBJ(wxRED_BRUSH, wxBrush);
+    REINITOBJ(wxGREY_BRUSH, wxBrush);
+    REINITOBJ(wxMEDIUM_GREY_BRUSH, wxBrush);
+    REINITOBJ(wxLIGHT_GREY_BRUSH, wxBrush);
+
+    REINITOBJ(wxBLACK, wxColour);
+    REINITOBJ(wxWHITE, wxColour);
+    REINITOBJ(wxRED, wxColour);
+    REINITOBJ(wxBLUE, wxColour);
+    REINITOBJ(wxGREEN, wxColour);
+    REINITOBJ(wxCYAN, wxColour);
+    REINITOBJ(wxLIGHT_GREY, wxColour);
+
+    REINITOBJ(wxSTANDARD_CURSOR, wxCursor);
+    REINITOBJ(wxHOURGLASS_CURSOR, wxCursor);
+    REINITOBJ(wxCROSS_CURSOR, wxCursor);
+
+    REINITOBJ2(wxNullBitmap, wxBitmap);
+    REINITOBJ2(wxNullIcon, wxIcon);
+    REINITOBJ2(wxNullCursor, wxCursor);
+    REINITOBJ2(wxNullPen, wxPen);
+    REINITOBJ2(wxNullBrush, wxBrush);
+    REINITOBJ2(wxNullPalette, wxPalette);
+    REINITOBJ2(wxNullFont, wxFont);
+    REINITOBJ2(wxNullColour, wxColour);
+
+    REINITOBJ(wxTheFontList, wxFontList);
+    REINITOBJ(wxThePenList, wxPenList);
+    REINITOBJ(wxTheBrushList, wxBrushList);
+    REINITOBJ(wxTheColourDatabase, wxColourDatabase);
+
+
+    REINITOBJ(wxTheClipboard, wxClipboard);
+    REINITOBJ(wxTheMimeTypesManager, wxMimeTypesManager);
+    REINITOBJ2(wxDefaultValidator, wxValidator);
+    REINITOBJ2(wxNullImage, wxImage);
+    REINITOBJ2(wxNullAcceleratorTable, wxAcceleratorTable);
+
+#undef REINITOBJ
+#undef REINITOBJ2
+}
+
 //---------------------------------------------------------------------------
 
 void wxPyClientData_dtor(wxPyClientData* self) {
@@ -587,21 +669,37 @@ void wxPyOORClientData_dtor(wxPyOORClientData* self) {
         Py_INCREF(deadObjectClass);
     }
 
-    // TODO:  If wxPyDOingCleanup, should we skip the code below?
 
-    // Clear the instance's dictionary, put the name of the old class into the
-    // instance, and then reset the class to be the dead class.
-    if (self->m_obj->ob_refcnt > 1) {  // but only if there is more than one reference
+    // Only if there is more than one reference to the object
+    if ( !wxPyDoingCleanup && self->m_obj->ob_refcnt > 1 ) {
         wxASSERT_MSG(PyInstance_Check(self->m_obj), wxT("m_obj not an instance!?!?!"));
+
+        // Call __del__, if there is one.
+        PyObject* func = PyObject_GetAttrString(self->m_obj, "__del__");
+        if (func) {
+            PyObject* rv = PyObject_CallMethod(self->m_obj, "__del__", NULL);
+            Py_XDECREF(rv);
+            Py_DECREF(func);
+        }
+        if (PyErr_Occurred())
+            PyErr_Clear();      // just ignore it for now
+
+        // Clear the instance's dictionary
         PyInstanceObject* inst = (PyInstanceObject*)self->m_obj;
         PyDict_Clear(inst->in_dict);
+
+        // put the name of the old class into the instance, and then reset the
+        // class to be the dead class.
         PyDict_SetItemString(inst->in_dict, "_name", inst->in_class->cl_name);
         inst->in_class = (PyClassObject*)deadObjectClass;
         Py_INCREF(deadObjectClass);
     }
+
+    // m_obj is DECREF's in the base class dtor...
     wxPyEndBlockThreads();
 }
 
+
 //---------------------------------------------------------------------------
 // Stuff used by OOR to find the right wxPython class type to return and to
 // build it.
@@ -1145,7 +1243,12 @@ size_t wxPyCBInputStream::OnSysWrite(const void *buffer, size_t bufsize) {
 
 off_t wxPyCBInputStream::OnSysSeek(off_t off, wxSeekMode mode) {
     wxPyBeginBlockThreads();
+#ifdef _LARGE_FILES
+    // off_t is a 64-bit value...
+    PyObject* arglist = Py_BuildValue("(Li)", off, mode);
+#else
     PyObject* arglist = Py_BuildValue("(ii)", off, mode);
+#endif
     PyObject* result = PyEval_CallObject(m_seek, arglist);
     Py_DECREF(arglist);
     Py_XDECREF(result);
@@ -1153,6 +1256,7 @@ off_t wxPyCBInputStream::OnSysSeek(off_t off, wxSeekMode mode) {
     return OnSysTell();
 }
 
+
 off_t wxPyCBInputStream::OnSysTell() const {
     wxPyBeginBlockThreads();
     PyObject* arglist = Py_BuildValue("()");
@@ -1160,7 +1264,13 @@ off_t wxPyCBInputStream::OnSysTell() const {
     Py_DECREF(arglist);
     off_t o = 0;
     if (result != NULL) {
+#ifdef _LARGE_FILES
+        if (PyLong_Check(result))
+            o = PyLong_AsLongLong(result);
+        else
+#else
         o = PyInt_AsLong(result);
+#endif
         Py_DECREF(result);
     };
     wxPyEndBlockThreads();
@@ -1196,29 +1306,50 @@ void wxPyCallback::EventThunker(wxEvent& event) {
     PyObject*       result;
     PyObject*       arg;
     PyObject*       tuple;
-
+    bool            checkSkip = FALSE;
 
     wxPyBeginBlockThreads();
     wxString className = event.GetClassInfo()->GetClassName();
 
-    if (className == wxT("wxPyEvent"))
-        arg = ((wxPyEvent*)&event)->GetSelf();
-    else if (className == wxT("wxPyCommandEvent"))
-        arg = ((wxPyCommandEvent*)&event)->GetSelf();
+    // If the event is one of these types then pass the original
+    // event object instead of the one passed to us.
+    if ( className == wxT("wxPyEvent") ) {
+        arg =       ((wxPyEvent*)&event)->GetSelf();
+        checkSkip = ((wxPyEvent*)&event)->GetCloned();
+    }
+    else if ( className == wxT("wxPyCommandEvent") ) {
+        arg =       ((wxPyCommandEvent*)&event)->GetSelf();
+        checkSkip = ((wxPyCommandEvent*)&event)->GetCloned();
+    }
     else {
         arg = wxPyConstructObject((void*)&event, className);
     }
 
+    // Call the event handler, passing the event object
     tuple = PyTuple_New(1);
-    PyTuple_SET_ITEM(tuple, 0, arg);
+    PyTuple_SET_ITEM(tuple, 0, arg);  // steals ref to arg
     result = PyEval_CallObject(func, tuple);
-    Py_DECREF(tuple);
-    if (result) {
-        Py_DECREF(result);
+    if ( result ) {
+        Py_DECREF(result);   // result is ignored, but we still need to decref it
         PyErr_Clear();       // Just in case...
     } else {
         PyErr_Print();
     }
+
+    if ( checkSkip ) {
+        // if the event object was one of our special types and
+        // it had been cloned, then we need to extract the Skipped
+        // value from the original and set it in the clone.
+        result = PyObject_CallMethod(arg, "GetSkipped", "");
+        if ( result ) {
+            event.Skip(PyInt_AsLong(result));
+            Py_DECREF(result);
+        } else {
+            PyErr_Print();
+        }
+    }
+
+    Py_DECREF(tuple);
     wxPyEndBlockThreads();
 }
 
@@ -1454,8 +1585,8 @@ IMPLEMENT_ABSTRACT_CLASS(wxPyEvent, wxEvent);
 IMPLEMENT_ABSTRACT_CLASS(wxPyCommandEvent, wxCommandEvent);
 
 
-wxPyEvent::wxPyEvent(int id)
-    : wxEvent(id) {
+wxPyEvent::wxPyEvent(int winid, wxEventType commandType)
+    : wxEvent(winid, commandType) {
 }