PyObject * py_guiQt_main(PyObject* self) { (void)self; // This is called from Python and replaces the main() control. // It might make sense to assert that we are the main thread. // However, there is no good cross-platform way to do this (afaik). // We could use Python... For now, we just hope that Qt behaves sane. // Anyway, on the Python side, we should have called this // in the main thread. int ret = 0; { PyScopedGIUnlock giunlock; QtApp::prepareInit(); // Keep it static. Noone should access it when we return // from here, but I like to be safe anyway. static QtApp app; setupMenu(); if(!app.openMainWindow()) { PyScopedGIL gil; PyErr_SetString(PyExc_SystemError, "guiQt.main: failed to create main window"); return NULL; } { PyScopedGIL gil; PyObject* initRet = handleModuleCommand("main", "handleApplicationInit", NULL); if(!initRet) { PyErr_SetString(PyExc_SystemError, "guiQt.main: main.handleApplicationInit() error"); return NULL; } Py_DECREF(initRet); } // Enter the Qt main event loop. ret = app.exec(); // Note that it depends on the Qt backend whether we return here or not. } PyErr_SetObject(PyExc_SystemExit, PyInt_FromLong(ret)); return NULL; }
bool QtApp::openWindow(const std::string& name) { assert(QThread::currentThread() == qApp->thread()); PyScopedGIL gil; PyObject* rootObj = handleModuleCommand("gui", "RootObjs.__getitem__", "(s)", name.c_str()); if(!rootObj) return false; // Python errs already handled in handleModuleCommand PyQtGuiObject* control = NULL; control = (PyQtGuiObject*) PyObject_GetAttrString(rootObj, "guiObj"); if(!control) { if(PyErr_Occurred()) PyErr_Print(); Py_DECREF(rootObj); return false; } if((PyObject*) control == Py_None) Py_CLEAR(control); if(control) { if(PyType_IsSubtype(Py_TYPE(control), &QtGuiObject_Type)) { QtBaseWidget::ScopedRef win(control->widget); if(win) { win->show(); return true; } // continue with existing control but create new window } else { printf("Qt open window: existing rootObj.guiObj is of wrong type\n"); // reset and continue with new control creation Py_CLEAR(control); } } if(!control) { control = (PyQtGuiObject*) PyObject_CallFunction((PyObject*) &QtGuiObject_Type, NULL); if(!control) { if(PyErr_Occurred()) PyErr_Print(); Py_DECREF(rootObj); return false; } assert(control->root == NULL); control->root = control; Py_XINCREF(control->root); assert(control->subjectObject == NULL); control->subjectObject = PyObject_GetAttrString(rootObj, "obj"); if(!control->subjectObject) { if(PyErr_Occurred()) PyErr_Print(); Py_DECREF(rootObj); Py_DECREF(control); return false; } } if(PyObject_SetAttrString(rootObj, "guiObj", (PyObject*) control) < 0) { if(PyErr_Occurred()) PyErr_Print(); Py_DECREF(rootObj); Py_DECREF(control); return false; } // check subjectObject { PyObject* subjectObject = PyObject_GetAttrString(rootObj, "obj"); if(!subjectObject) { if(PyErr_Occurred()) PyErr_Print(); // continue, maybe it doesn't matter } else { if(subjectObject != control->subjectObject) { printf("Qt open window: got new subject object\n"); // strange, but just overtake and continue Py_CLEAR(control->subjectObject); control->subjectObject = subjectObject; subjectObject = NULL; } } Py_XDECREF(subjectObject); } QtBaseWidget* win = new QtBaseWidget(control); win->setAttribute(Qt::WA_DeleteOnClose); // set title { PyObject* title = PyObject_GetAttrString(rootObj, "title"); std::string titleStr; if(!title || !pyStr(title, titleStr)) { if(PyErr_Occurred()) PyErr_Print(); win->setWindowTitle(QString::fromStdString(name)); } else { win->setWindowTitle(QString::fromStdString(titleStr)); } Py_XDECREF(title); } Vec size = control->setupChilds(); win->setMinimumSize(size.x, size.y); // ... win->show(); control->layout(); Py_DECREF(rootObj); Py_DECREF(control); return true; }