| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <FCConfig.h>
|
| |
|
| | #if HAVE_CONFIG_H
|
| | # include <config.h>
|
| | #endif
|
| |
|
| | #ifdef _MSC_VER
|
| | # pragma warning(disable : 4005)
|
| | #endif
|
| |
|
| | #include <QApplication>
|
| | #include <QIcon>
|
| | #if defined(Q_OS_WIN)
|
| | # include <windows.h>
|
| | #elif defined(Q_WS_X11)
|
| | # include <QX11EmbedWidget>
|
| | #endif
|
| | #include <thread>
|
| |
|
| |
|
| | #include <App/Application.h>
|
| | #include <Base/Exception.h>
|
| | #include <Base/Factory.h>
|
| | #include <Base/Interpreter.h>
|
| | #include <Base/PyObjectBase.h>
|
| | #include <Gui/Application.h>
|
| | #include <Gui/BitmapFactory.h>
|
| | #include <Gui/MainWindow.h>
|
| | #include <Gui/StartupProcess.h>
|
| | #include <Gui/SoFCDB.h>
|
| | #include <Gui/Quarter/Quarter.h>
|
| | #include <Inventor/SoDB.h>
|
| | #include <Inventor/SoInteraction.h>
|
| | #include <Inventor/nodekits/SoNodeKit.h>
|
| |
|
| |
|
| | static bool _isSetupWithoutGui = false;
|
| |
|
| | static QWidget* setupMainWindow();
|
| |
|
| | class QtApplication: public QApplication
|
| | {
|
| | public:
|
| | QtApplication(int& argc, char** argv)
|
| | : QApplication(argc, argv)
|
| | {}
|
| | bool notify(QObject* receiver, QEvent* event) override
|
| | {
|
| | try {
|
| | return QApplication::notify(receiver, event);
|
| | }
|
| | catch (const Base::SystemExitException& e) {
|
| | exit(e.getExitCode());
|
| | return true;
|
| | }
|
| | }
|
| | };
|
| |
|
| | #if defined(Q_OS_WIN)
|
| | HHOOK hhook;
|
| |
|
| | LRESULT CALLBACK FilterProc(int nCode, WPARAM wParam, LPARAM lParam)
|
| | {
|
| | if (qApp) {
|
| | qApp->sendPostedEvents(0, -1);
|
| | }
|
| | return CallNextHookEx(hhook, nCode, wParam, lParam);
|
| | }
|
| | #endif
|
| |
|
| | static PyObject* FreeCADGui_showMainWindow(PyObject* , PyObject* args)
|
| | {
|
| | if (_isSetupWithoutGui) {
|
| | PyErr_SetString(
|
| | PyExc_RuntimeError,
|
| | "Cannot call showMainWindow() after calling setupWithoutGUI()\n"
|
| | );
|
| | return nullptr;
|
| | }
|
| |
|
| | PyObject* inThread = Py_False;
|
| | if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &inThread)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | static bool thr = false;
|
| | if (!qApp) {
|
| | if (Base::asBoolean(inThread) && !thr) {
|
| | thr = true;
|
| | std::thread t([]() {
|
| | static int argc = 0;
|
| | static char** argv = {nullptr};
|
| | QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
| |
|
| |
|
| |
|
| | QtApplication app(argc, argv);
|
| | if (setupMainWindow()) {
|
| | app.exec();
|
| | }
|
| | });
|
| | t.detach();
|
| | }
|
| | else {
|
| |
|
| |
|
| |
|
| | #if defined(Q_OS_WIN)
|
| | static int argc = 0;
|
| | static char** argv = {0};
|
| | (void)new QApplication(argc, argv);
|
| |
|
| | hhook = SetWindowsHookEx(WH_GETMESSAGE, FilterProc, 0, GetCurrentThreadId());
|
| | #elif !defined(QT_NO_GLIB)
|
| | static int argc = 0;
|
| | static char** argv = {nullptr};
|
| | (void)new QApplication(argc, argv);
|
| | #else
|
| | PyErr_SetString(PyExc_RuntimeError, "Must construct a QApplication before a QPaintDevice\n");
|
| | return nullptr;
|
| | #endif
|
| | }
|
| | }
|
| | else if (!qobject_cast<QApplication*>(qApp)) {
|
| | PyErr_SetString(PyExc_RuntimeError, "Cannot create widget when no GUI is being used\n");
|
| | return nullptr;
|
| | }
|
| |
|
| | if (!thr) {
|
| | if (!setupMainWindow()) {
|
| | PyErr_SetString(PyExc_RuntimeError, "Cannot create main window\n");
|
| | return nullptr;
|
| | }
|
| | }
|
| |
|
| |
|
| | Base::ILogger* console = Base::Console().get("Console");
|
| | if (console) {
|
| | console->bMsg = true;
|
| | console->bWrn = true;
|
| | console->bErr = true;
|
| | }
|
| |
|
| | Py_INCREF(Py_None);
|
| | return Py_None;
|
| | }
|
| |
|
| | static PyObject* FreeCADGui_exec_loop(PyObject* , PyObject* args)
|
| | {
|
| | if (!PyArg_ParseTuple(args, "")) {
|
| | return nullptr;
|
| | }
|
| |
|
| | if (!qApp) {
|
| | PyErr_SetString(PyExc_RuntimeError, "Must construct a QApplication before a QPaintDevice\n");
|
| | return nullptr;
|
| | }
|
| | else if (!qobject_cast<QApplication*>(qApp)) {
|
| | PyErr_SetString(PyExc_RuntimeError, "Cannot create widget when no GUI is being used\n");
|
| | return nullptr;
|
| | }
|
| |
|
| | qApp->exec();
|
| |
|
| | Py_INCREF(Py_None);
|
| | return Py_None;
|
| | }
|
| |
|
| | static PyObject* FreeCADGui_setupWithoutGUI(PyObject* , PyObject* args)
|
| | {
|
| | if (!PyArg_ParseTuple(args, "")) {
|
| | return nullptr;
|
| | }
|
| |
|
| | if (!Gui::Application::Instance) {
|
| | static Gui::Application* app = new Gui::Application(false);
|
| | _isSetupWithoutGui = true;
|
| | Q_UNUSED(app);
|
| | }
|
| | if (!SoDB::isInitialized()) {
|
| |
|
| | SoDB::init();
|
| | SoNodeKit::init();
|
| | SoInteraction::init();
|
| | }
|
| | if (!Gui::SoFCDB::isInitialized()) {
|
| | Gui::SoFCDB::init();
|
| | }
|
| |
|
| | Py_INCREF(Py_None);
|
| | return Py_None;
|
| | }
|
| |
|
| | static PyObject* FreeCADGui_embedToWindow(PyObject* , PyObject* args)
|
| | {
|
| | char* pointer;
|
| | if (!PyArg_ParseTuple(args, "s", &pointer)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | QWidget* widget = Gui::getMainWindow();
|
| | if (!widget) {
|
| | PyErr_SetString(Base::PyExc_FC_GeneralError, "No main window");
|
| | return nullptr;
|
| | }
|
| |
|
| | std::string pointer_str = pointer;
|
| | std::stringstream str(pointer_str);
|
| |
|
| | #if defined(Q_OS_WIN)
|
| | void* window = 0;
|
| | str >> window;
|
| | HWND winid = (HWND)window;
|
| |
|
| | LONG oldLong = GetWindowLong(winid, GWL_STYLE);
|
| | SetWindowLong(winid, GWL_STYLE, oldLong | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
|
| |
|
| |
|
| | SetParent((HWND)widget->winId(), winid);
|
| |
|
| | QEvent embeddingEvent(QEvent::EmbeddingControl);
|
| | QApplication::sendEvent(widget, &embeddingEvent);
|
| | #elif defined(Q_WS_X11)
|
| | WId winid;
|
| | str >> winid;
|
| |
|
| | QX11EmbedWidget* x11 = new QX11EmbedWidget();
|
| | widget->setParent(x11);
|
| | x11->embedInto(winid);
|
| | x11->show();
|
| | #else
|
| | PyErr_SetString(PyExc_NotImplementedError, "Not implemented for this platform");
|
| | return nullptr;
|
| | #endif
|
| |
|
| | Py_INCREF(Py_None);
|
| | return Py_None;
|
| | }
|
| |
|
| | struct PyMethodDef FreeCADGui_methods[] = {
|
| | {"showMainWindow",
|
| | FreeCADGui_showMainWindow,
|
| | METH_VARARGS,
|
| | "showMainWindow() -- Show the main window\n"
|
| | "If no main window does exist one gets created"},
|
| | {"exec_loop",
|
| | FreeCADGui_exec_loop,
|
| | METH_VARARGS,
|
| | "exec_loop() -- Starts the event loop\n"
|
| | "Note: this will block the call until the event loop has terminated"},
|
| | {"setupWithoutGUI",
|
| | FreeCADGui_setupWithoutGUI,
|
| | METH_VARARGS,
|
| | "setupWithoutGUI() -- Uses this module without starting\n"
|
| | "an event loop or showing up any GUI\n"},
|
| | {"embedToWindow",
|
| | FreeCADGui_embedToWindow,
|
| | METH_VARARGS,
|
| | "embedToWindow() -- Embeds the main window into another window\n"},
|
| | {nullptr, nullptr, 0, nullptr}
|
| | };
|
| |
|
| | static QWidget* setupMainWindow()
|
| | {
|
| | if (!Gui::Application::Instance) {
|
| | static Gui::Application* app = new Gui::Application(true);
|
| | Q_UNUSED(app);
|
| | }
|
| |
|
| | if (!Gui::MainWindow::getInstance()) {
|
| | static bool hasMainWindow = false;
|
| | if (hasMainWindow) {
|
| |
|
| |
|
| | return nullptr;
|
| | }
|
| |
|
| | Gui::StartupProcess process;
|
| | process.execute();
|
| |
|
| | Base::PyGILStateLocker lock;
|
| |
|
| | App::Application::Config()["DontOverrideStdIn"] = "";
|
| | Gui::MainWindow* mw = new Gui::MainWindow();
|
| | hasMainWindow = true;
|
| |
|
| | QIcon icon = qApp->windowIcon();
|
| | if (icon.isNull()) {
|
| | qApp->setWindowIcon(
|
| | Gui::BitmapFactory().pixmap(App::Application::Config()["AppIcon"].c_str())
|
| | );
|
| | }
|
| | mw->setWindowIcon(qApp->windowIcon());
|
| |
|
| | try {
|
| | Gui::StartupPostProcess postProcess(mw, *Gui::Application::Instance, qApp);
|
| | postProcess.setLoadFromPythonModule(true);
|
| | postProcess.execute();
|
| | }
|
| | catch (const Base::Exception&) {
|
| | return nullptr;
|
| | }
|
| | }
|
| | else {
|
| | Gui::getMainWindow()->show();
|
| | }
|
| |
|
| | return Gui::getMainWindow();
|
| | }
|
| |
|
| | PyMOD_INIT_FUNC(FreeCADGui)
|
| | {
|
| | try {
|
| |
|
| | Base::Interpreter().loadModule("FreeCAD");
|
| | App::Application::Config()["AppIcon"] = "freecad";
|
| | App::Application::Config()["SplashScreen"] = "freecadsplash";
|
| | App::Application::Config()["CopyrightInfo"] = "\xc2\xa9 Juergen Riegel, Werner Mayer, Yorik van Havre and others 2001-2025\n";
|
| | App::Application::Config()["LicenseInfo"] = "FreeCAD is free and open-source software licensed under the terms of LGPL2+ license.\n";
|
| | App::Application::Config()["CreditsInfo"] = "FreeCAD would not be possible without the FreeCAD community.\n";
|
| |
|
| |
|
| |
|
| |
|
| | if (Base::Type::fromName("Gui::BaseView").isBad()) {
|
| | Gui::Application::initApplication();
|
| | }
|
| | static struct PyModuleDef FreeCADGuiModuleDef = {
|
| | PyModuleDef_HEAD_INIT,
|
| | "FreeCADGui",
|
| | "FreeCAD GUI module\n",
|
| | -1,
|
| | FreeCADGui_methods,
|
| | nullptr,
|
| | nullptr,
|
| | nullptr,
|
| | nullptr
|
| | };
|
| | PyObject* module = PyModule_Create(&FreeCADGuiModuleDef);
|
| | return module;
|
| | }
|
| | catch (const Base::Exception& e) {
|
| | PyErr_Format(PyExc_ImportError, "%s\n", e.what());
|
| | }
|
| | catch (...) {
|
| | PyErr_SetString(PyExc_ImportError, "Unknown runtime error occurred");
|
| | }
|
| | return nullptr;
|
| | }
|
| |
|