From d51db6e39e0c50aa2ce2f02321b32e5f22c36fdc Mon Sep 17 00:00:00 2001 From: Donny Lawrence Date: Sun, 13 Jan 2019 11:46:57 -0500 Subject: [PATCH 01/12] Fix an instance where a macOS window will stick around when trying to have it destroyed. This commit also removes an extraneous call to [_window setReleasedWhenClosed], which is already set in cocoaPandaWindow's init method. --- panda/src/cocoadisplay/cocoaGraphicsWindow.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm index c3f23d4013..0a140109c7 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm @@ -711,8 +711,11 @@ close_window() { } if (_window != nil) { - [_window setReleasedWhenClosed: YES]; [_window close]; + + // Process events once more so any pending NSEvents are cleared. Not doing + // this causes the window to stick around after calling [_window close]. + process_events(); _window = nil; } From 2c513ba1c43811b328544eec0c722fa76d3d91c8 Mon Sep 17 00:00:00 2001 From: Donny Lawrence Date: Sun, 13 Jan 2019 19:07:43 -0500 Subject: [PATCH 02/12] Move handle_close_event() call to windowShouldClose, which only triggers when the close button is pressed by the user. --- panda/src/cocoadisplay/cocoaPandaWindowDelegate.h | 1 - panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/panda/src/cocoadisplay/cocoaPandaWindowDelegate.h b/panda/src/cocoadisplay/cocoaPandaWindowDelegate.h index 1a80ef056e..93d5b7b35b 100644 --- a/panda/src/cocoadisplay/cocoaPandaWindowDelegate.h +++ b/panda/src/cocoadisplay/cocoaPandaWindowDelegate.h @@ -34,7 +34,6 @@ class CocoaGraphicsWindow; - (void)windowDidBecomeKey:(NSNotification *)notification; - (void)windowDidResignKey:(NSNotification *)notification; - (BOOL)windowShouldClose:(id)sender; -- (void)windowWillClose:(NSNotification *)notification; // TODO: handle fullscreen on Lion. diff --git a/panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm b/panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm index 6b93410538..7e39748bd1 100644 --- a/panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm +++ b/panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm @@ -50,11 +50,11 @@ } - (BOOL) windowShouldClose:(id)sender { - return _graphicsWindow->handle_close_request(); -} - -- (void) windowWillClose:(NSNotification *)notification { - _graphicsWindow->handle_close_event(); + bool should_close = _graphicsWindow->handle_close_request(); + if (should_close) { + _graphicsWindow->handle_close_event(); + } + return should_close; } @end From a7c8827ddee0d40a605edd4d85fb3b1f55ec01b1 Mon Sep 17 00:00:00 2001 From: Younguk Kim Date: Thu, 28 Feb 2019 11:29:34 +0900 Subject: [PATCH 03/12] makepanda: add support for Visual Studio 2019 Closes #570 --- makepanda/makepanda.py | 2 +- makepanda/makepandacore.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 3341262452..05d639e7d1 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -159,7 +159,7 @@ def usage(problem): print(" --everything (enable every third-party lib)") print(" --directx-sdk=X (specify version of DirectX SDK to use: jun2010, aug2009, mar2009, aug2006)") print(" --windows-sdk=X (specify Windows SDK version, eg. 7.0, 7.1 or 10. Default is 7.1)") - print(" --msvc-version=X (specify Visual C++ version, eg. 10, 11, 12, 14. Default is 14)") + print(" --msvc-version=X (specify Visual C++ version, eg. 10, 11, 12, 14, 14.1, 14.2. Default is 14)") print(" --use-icl (experimental setting to use an intel compiler instead of MSVC on Windows)") print("") print("The simplest way to compile panda is to just type:") diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 74ce108adf..386570a0d8 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -78,6 +78,7 @@ MSVCVERSIONINFO = { (12,0): {"vsversion":(12,0), "vsname":"Visual Studio 2013"}, (14,0): {"vsversion":(14,0), "vsname":"Visual Studio 2015"}, (14,1): {"vsversion":(15,0), "vsname":"Visual Studio 2017"}, + (14,2): {"vsversion":(16,0), "vsname":"Visual Studio 2019"}, } ######################################################################## From 63fa340a51ae5d1f39b0bab903bf0a620ff63476 Mon Sep 17 00:00:00 2001 From: typewriter1 <40742741+typewriter1@users.noreply.github.com> Date: Mon, 25 Feb 2019 17:53:13 +0000 Subject: [PATCH 04/12] readme: Update download link for SDK to 1.10.1 Closes #566 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c4757d577..4d26a0a778 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Installing Panda3D ================== The latest Panda3D SDK can be downloaded from -[this page](https://www.panda3d.org/download/sdk-1-10-0/). +[this page](https://www.panda3d.org/download/sdk-1-10-1/). If you are familiar with installing Python packages, you can use the following comand: From 7f4491cb9887a2fa021059b922c4032f460aca82 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 2 Mar 2019 12:39:42 +0100 Subject: [PATCH 05/12] device: disable message loop in WinInputDeviceManager for now This was a change in aadc62a96c18d9911428da041e611f8c3b01a444 but seems to cause other problems, see #562 --- panda/src/device/winInputDeviceManager.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 515dc376d8..c989b0964c 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -397,11 +397,13 @@ on_input_device_removal(HANDLE handle) { */ void WinInputDeviceManager:: update() { + /* MSG msg; while (PeekMessage(&msg, _message_hwnd, WM_INPUT_DEVICE_CHANGE, WM_INPUT, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } + */ } /** From fa6c066b2f21856036cb24d482a7152406c6c2e2 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 3 Mar 2019 10:29:39 +0100 Subject: [PATCH 06/12] interrogate: enable true division in Python 2 as well This allows using "from __future__ import division" and get the expected result for divisions in Python 2. Fixes #529 --- dtool/src/interrogate/interfaceMakerPythonNative.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 5f351dbbc1..4d606c65d9 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -1690,7 +1690,6 @@ write_module_class(ostream &out, Object *obj) { SlottedFunctionDef def; def._answer_location = true_key; def._wrapper_type = slotted_def._wrapper_type; - def._min_version = 0x03000000; def._wrapper_name = func->_name + "_" + true_key; slots[true_key] = def; } From 92993fe8891257aed9d12967bd0fff0af03adfc4 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 3 Mar 2019 21:13:36 +0100 Subject: [PATCH 07/12] bullet: fix assert when setting mass before shape (#571) Requires compiling Bullet in debug mode to reproduce. --- panda/src/bullet/bulletRigidBodyNode.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/bullet/bulletRigidBodyNode.cxx b/panda/src/bullet/bulletRigidBodyNode.cxx index 6f5bff0d46..b97f768d1b 100644 --- a/panda/src/bullet/bulletRigidBodyNode.cxx +++ b/panda/src/bullet/bulletRigidBodyNode.cxx @@ -120,7 +120,7 @@ do_set_mass(PN_stdfloat mass) { btScalar bt_mass = mass; btVector3 bt_inertia(0.0, 0.0, 0.0); - if (bt_mass > 0.0) { + if (bt_mass > 0.0 && !_shapes.empty()) { _rigid->getCollisionShape()->calculateLocalInertia(bt_mass, bt_inertia); } From 155b1c38ade5b62872b4a60a1f27bb2e858a122e Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 3 Mar 2019 21:14:18 +0100 Subject: [PATCH 08/12] bullet: properly expose bullet_contact_added_callback symbol Fixes #571 (alongside 92993fe8891257aed9d12967bd0fff0af03adfc4) --- panda/src/bullet/bulletWorld.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/bullet/bulletWorld.h b/panda/src/bullet/bulletWorld.h index 9c709c1e91..67607923dd 100644 --- a/panda/src/bullet/bulletWorld.h +++ b/panda/src/bullet/bulletWorld.h @@ -43,7 +43,7 @@ class BulletPersistentManifold; class BulletShape; class BulletSoftBodyWorldInfo; -extern PT(CallbackObject) bullet_contact_added_callback; +extern EXPCL_PANDABULLET PT(CallbackObject) bullet_contact_added_callback; /** * From c337e58f4dbc02fb7bb1b60c7525c0ef518cee3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derzsi=20D=C3=A1niel?= Date: Mon, 4 Mar 2019 00:21:23 +0200 Subject: [PATCH 09/12] direct: Resolve DirectScrolledFrame crash on destroy Destroying DirectScrolledFrames currently crashes the game, because they are destroyed twice. This commit makes sure to destroy the scrolls only once. Closes #574 --- direct/src/gui/DirectScrolledFrame.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/direct/src/gui/DirectScrolledFrame.py b/direct/src/gui/DirectScrolledFrame.py index c44bc7a0fb..d5274de6fe 100644 --- a/direct/src/gui/DirectScrolledFrame.py +++ b/direct/src/gui/DirectScrolledFrame.py @@ -100,8 +100,10 @@ class DirectScrolledFrame(DirectFrame): simpleChildGui = self.guiDict.get(parts[-1]) if simpleChildGui: simpleChildGui.destroy() - self.verticalScroll.destroy() - self.horizontalScroll.destroy() - del self.verticalScroll - del self.horizontalScroll + if self.verticalScroll: + self.verticalScroll.destroy() + if self.horizontalScroll: + self.horizontalScroll.destroy() + self.verticalScroll = None + self.horizontalScroll = None DirectFrame.destroy(self) From 58df4064dab3605838117542b1716e4757a7e02a Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 14:23:11 +0100 Subject: [PATCH 10/12] ParticlePanel: fix Pmw error spam when hovering over File menu items Fixes #552 --- direct/src/tkpanels/ParticlePanel.py | 31 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/direct/src/tkpanels/ParticlePanel.py b/direct/src/tkpanels/ParticlePanel.py index 9c4ba56a79..47faa71cb6 100644 --- a/direct/src/tkpanels/ParticlePanel.py +++ b/direct/src/tkpanels/ParticlePanel.py @@ -96,22 +96,21 @@ class ParticlePanel(AppShell): ## MENUBAR ENTRIES ## # FILE MENU - # Get a handle on the file menu so commands can be inserted - # before quit item - fileMenu = self.menuBar.component('File-menu') - # MRM: Need to add load and save effects methods - fileMenu.insert_command( - fileMenu.index('Quit'), - label = 'Load Params', - command = self.loadParticleEffectFromFile) - fileMenu.insert_command( - fileMenu.index('Quit'), - label = 'Save Params', - command = self.saveParticleEffectToFile) - fileMenu.insert_command( - fileMenu.index('Quit'), - label = 'Print Params', - command = lambda s = self: s.particles.printParams()) + # Get a handle on the file menu, and delete the Quit item that AppShell + # created so we can add it back after adding the other items. + self.menuBar.deletemenuitems('File', 0, 0) + self.menuBar.addmenuitem('File', 'command', + label='Load Params', + command=self.loadParticleEffectFromFile) + self.menuBar.addmenuitem('File', 'command', + label='Save Params', + command=self.saveParticleEffectToFile) + self.menuBar.addmenuitem('File', 'command', + label='Print Params', + command=lambda s=self:s.particles.printParams()) + self.menuBar.addmenuitem('File', 'command', 'Quit this application', + label='Quit', + command=self.quit) # PARTICLE MANAGER MENU self.menuBar.addmenu('ParticleMgr', 'ParticleMgr Operations') From 45778b9e9fbf37719964298ae8acb552a86bb135 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 16:19:19 +0100 Subject: [PATCH 11/12] device: use threaded message loop on Windows (see #562) --- panda/src/device/winInputDeviceManager.cxx | 260 ++++++++++++++------- panda/src/device/winInputDeviceManager.h | 3 + 2 files changed, 177 insertions(+), 86 deletions(-) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index c989b0964c..232c612186 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -17,6 +17,22 @@ #if defined(_WIN32) && !defined(CPPPARSER) +#ifdef HAVE_THREADS +/** + * + */ +class InputThread : public Thread { +public: + InputThread(WinInputDeviceManager *manager) : + Thread("input", "input"), _manager(manager) {} + +private: + virtual void thread_main(); + + WinInputDeviceManager *_manager; +}; +#endif + /** * Initializes the input device manager by scanning which devices are currently * connected and setting up any platform-dependent structures necessary for @@ -37,7 +53,7 @@ WinInputDeviceManager() : _xinput_device2.local_object(); _xinput_device3.local_object(); -// This function is only available in Vista and later, so we use a wrapper. + // This function is only available in Vista and later, so we use a wrapper. HMODULE module = LoadLibraryA("cfgmgr32.dll"); if (module) { _CM_Get_DevNode_PropertyW = (pCM_Get_DevNode_Property)GetProcAddress(module, "CM_Get_DevNode_PropertyW"); @@ -45,83 +61,16 @@ WinInputDeviceManager() : _CM_Get_DevNode_PropertyW = nullptr; } - // Now create a message-only window for the raw input. - WNDCLASSEX wc = {}; - wc.cbSize = sizeof(WNDCLASSEX); - wc.lpfnWndProc = window_proc; - wc.hInstance = GetModuleHandle(nullptr); - wc.lpszClassName = "InputDeviceManager"; - if (!RegisterClassEx(&wc)) { - device_cat.warning() - << "Failed to register message-only window class.\n"; - return; - } - - _message_hwnd = CreateWindowEx(0, wc.lpszClassName, "InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); - if (!_message_hwnd) { - device_cat.warning() - << "Failed to create message-only window.\n"; - return; - } - - // Now listen for raw input devices using the created message loop. - RAWINPUTDEVICE rid[3]; - rid[0].usUsagePage = 1; - rid[0].usUsage = 4; // Joysticks - rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; - rid[0].hwndTarget = _message_hwnd; - rid[1].usUsagePage = 1; - rid[1].usUsage = 5; // Gamepads - rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; - rid[1].hwndTarget = _message_hwnd; - rid[2].usUsagePage = 1; - rid[2].usUsage = 8; // Multi-axis controllers (including 3D mice) - rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; - rid[2].hwndTarget = _message_hwnd; - if (!RegisterRawInputDevices(rid, 3, sizeof(RAWINPUTDEVICE))) { - device_cat.warning() - << "Failed to register raw input devices.\n"; - } - - // Do we have any XInput devices plugged in now? - int num_xinput = 0; - HANDLE xinput_handle; - RAWINPUTDEVICELIST devices[64]; - UINT num_devices = 64; - num_devices = GetRawInputDeviceList(devices, &num_devices, sizeof(RAWINPUTDEVICELIST)); - if (num_devices == (UINT)-1) { - return; - } - for (UINT i = 0; i < num_devices; ++i) { - if (devices[i].dwType != RIM_TYPEHID) { - continue; - } - HANDLE handle = devices[i].hDevice; - UINT size; - if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, nullptr, &size) != 0) { - continue; - } - - char *path = (char *)alloca(size); - if (path == nullptr || - GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (void *)path, &size) < 0) { - continue; - } - - if (strstr(path, "&IG_") != nullptr) { - xinput_handle = handle; - ++num_xinput; - } - } - if (num_xinput == 1) { - // There's only one XInput device, so we know which one it is. - on_input_device_arrival(xinput_handle); - } else if (num_xinput > 0) { - // Just poll all the XInput devices. - _xinput_device0.detect(this); - _xinput_device1.detect(this); - _xinput_device2.detect(this); - _xinput_device3.detect(this); + // If we have threading enabled, start a thread with a message-only window + // loop to listen for input events. +#ifdef HAVE_THREADS + if (Thread::is_threading_supported()) { + PT(Thread) thread = new InputThread(this); + thread->start(TP_normal, false); + } else +#endif + { + setup_message_loop(); } } @@ -131,8 +80,17 @@ WinInputDeviceManager() : WinInputDeviceManager:: ~WinInputDeviceManager() { if (_message_hwnd != nullptr) { - DestroyWindow(_message_hwnd); - _message_hwnd = nullptr; +#ifdef HAVE_THREADS + if (Thread::is_threading_supported()) { + HWND hwnd = _message_hwnd; + if (hwnd) { + SendMessage(hwnd, WM_QUIT, 0, 0); + } + } else +#endif + { + destroy_message_loop(); + } } } @@ -397,13 +355,111 @@ on_input_device_removal(HANDLE handle) { */ void WinInputDeviceManager:: update() { - /* - MSG msg; - while (PeekMessage(&msg, _message_hwnd, WM_INPUT_DEVICE_CHANGE, WM_INPUT, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); +} + +/** + * Sets up a Windows message loop. Should be called from the thread that will + * be handling the messages. + */ +HWND WinInputDeviceManager:: +setup_message_loop() { + _message_hwnd = 0; + + // Now create a message-only window for the raw input. + WNDCLASSEX wc = {}; + wc.cbSize = sizeof(WNDCLASSEX); + wc.lpfnWndProc = window_proc; + wc.hInstance = GetModuleHandle(nullptr); + wc.lpszClassName = "InputDeviceManager"; + if (!RegisterClassEx(&wc)) { + device_cat.warning() + << "Failed to register message-only window class for input device detection.\n"; + } else { + _message_hwnd = CreateWindowEx(0, wc.lpszClassName, "InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); + if (!_message_hwnd) { + device_cat.warning() + << "Failed to create message-only window for input device detection.\n"; + } + } + + // Now listen for raw input devices using the created message loop. + RAWINPUTDEVICE rid[3]; + rid[0].usUsagePage = 1; + rid[0].usUsage = 4; // Joysticks + rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + rid[0].hwndTarget = _message_hwnd; + rid[1].usUsagePage = 1; + rid[1].usUsage = 5; // Gamepads + rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + rid[1].hwndTarget = _message_hwnd; + rid[2].usUsagePage = 1; + rid[2].usUsage = 8; // Multi-axis controllers (including 3D mice) + rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + rid[2].hwndTarget = _message_hwnd; + if (!RegisterRawInputDevices(rid, 3, sizeof(RAWINPUTDEVICE))) { + device_cat.warning() + << "Failed to register raw input devices.\n"; + } + + // Do we have any XInput devices plugged in now? + int num_xinput = 0; + HANDLE xinput_handle; + RAWINPUTDEVICELIST devices[64]; + UINT num_devices = 64; + num_devices = GetRawInputDeviceList(devices, &num_devices, sizeof(RAWINPUTDEVICELIST)); + if (num_devices == (UINT)-1) { + num_devices = 0; + } + for (UINT i = 0; i < num_devices; ++i) { + if (devices[i].dwType != RIM_TYPEHID) { + continue; + } + HANDLE handle = devices[i].hDevice; + UINT size; + if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, nullptr, &size) != 0) { + continue; + } + + char *path = (char *)alloca(size); + if (path == nullptr || + GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (void *)path, &size) < 0) { + continue; + } + + if (strstr(path, "&IG_") != nullptr) { + xinput_handle = handle; + ++num_xinput; + } + } + if (num_xinput == 1) { + // There's only one XInput device, so we know which one it is. + on_input_device_arrival(xinput_handle); + } else if (num_xinput > 0) { + // Just poll all the XInput devices. + _xinput_device0.detect(this); + _xinput_device1.detect(this); + _xinput_device2.detect(this); + _xinput_device3.detect(this); + } + + return _message_hwnd; +} + +/** + * Tears down the message loop. Should be called from the thread that called + * setup_message_loop(). + */ +void WinInputDeviceManager:: +destroy_message_loop() { + HWND hwnd = nullptr; + { + LightMutexHolder holder(_lock); + std::swap(_message_hwnd, hwnd); + } + + if (hwnd) { + DestroyWindow(hwnd); } - */ } /** @@ -444,4 +500,36 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { return DefWindowProcW(hwnd, msg, wparam, lparam); } +#ifdef HAVE_THREADS +/** + * Thread entry point for the input listener thread. + */ +void InputThread:: +thread_main() { + WinInputDeviceManager *manager = _manager; + HWND hwnd = manager->setup_message_loop(); + if (!hwnd) { + return; + } + + if (device_cat.is_debug()) { + device_cat.debug() + << "Started input device listener thread.\n"; + } + + MSG msg; + while (GetMessage(&msg, nullptr, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (device_cat.is_debug()) { + device_cat.debug() + << "Stopping input device listener thread.\n"; + } + + manager->destroy_message_loop(); +} +#endif // HAVE_THREADS + #endif diff --git a/panda/src/device/winInputDeviceManager.h b/panda/src/device/winInputDeviceManager.h index e99a01f761..44eaa053dc 100644 --- a/panda/src/device/winInputDeviceManager.h +++ b/panda/src/device/winInputDeviceManager.h @@ -41,6 +41,9 @@ public: void on_input_device_arrival(HANDLE handle); void on_input_device_removal(HANDLE handle); + HWND setup_message_loop(); + void destroy_message_loop(); + private: // There are always exactly four of these in existence. XInputDevice _xinput_device0; From 8e4add0326292b398ef99f5c0f9033efdba21ff4 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 4 Mar 2019 16:46:28 +0100 Subject: [PATCH 12/12] interrogate: fix refcount trouble assigning PyObject* properties In particular, this fixes accessing PythonTask.__dict__ --- dtool/src/interrogate/functionRemap.cxx | 19 ++++++++++++++++--- .../interfaceMakerPythonNative.cxx | 6 +++++- dtool/src/interrogatedb/py_panda.I | 13 +++++++++++++ dtool/src/interrogatedb/py_panda.h | 2 ++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/dtool/src/interrogate/functionRemap.cxx b/dtool/src/interrogate/functionRemap.cxx index fabbb8a311..d5d6ab643c 100644 --- a/dtool/src/interrogate/functionRemap.cxx +++ b/dtool/src/interrogate/functionRemap.cxx @@ -397,17 +397,25 @@ get_call_str(const string &container, const vector_string &pexprs) const { } // It's not possible to assign arrays in C++, we have to copy them. - CPPArrayType *array_type = _parameters[_first_true_parameter]._remap->get_orig_type()->as_array_type(); + bool paren_close = false; + CPPType *param_type = _parameters[_first_true_parameter]._remap->get_orig_type(); + CPPArrayType *array_type = param_type->as_array_type(); if (array_type != nullptr) { call << "std::copy(" << expr << ", " << expr << " + " << *array_type->_bounds << ", "; - } else { + paren_close = true; + } + else if (TypeManager::is_pointer_to_PyObject(param_type)) { + call << "Dtool_Assign_PyObject(" << expr << ", "; + paren_close = true; + } + else { call << expr << " = "; } _parameters[_first_true_parameter]._remap->pass_parameter(call, get_parameter_expr(_first_true_parameter, pexprs)); - if (array_type != nullptr) { + if (paren_close) { call << ')'; } @@ -772,6 +780,11 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak _return_value_destructor = builder.get_destructor_for(return_meat_type); } + if (_type == T_getter && TypeManager::is_pointer_to_PyObject(return_type)) { + _manage_reference_count = true; + _return_value_needs_management = true; + } + // Check for a special meaning by name and signature. size_t first_param = 0; if (_has_this) { diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 4d606c65d9..c617b6597e 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -5979,7 +5979,11 @@ write_function_instance(ostream &out, FunctionRemap *remap, indent(out, indent_level) << "}\n"; } - return_expr = manage_return_value(out, indent_level, remap, "return_value"); + if (TypeManager::is_pointer_to_PyObject(remap->_return_type->get_orig_type())) { + indent(out, indent_level) << "Py_XINCREF(return_value);\n"; + } else { + return_expr = manage_return_value(out, indent_level, remap, "return_value"); + } return_expr = remap->_return_type->temporary_to_return(return_expr); } diff --git a/dtool/src/interrogatedb/py_panda.I b/dtool/src/interrogatedb/py_panda.I index 12f20f1f1e..d6b95efe35 100644 --- a/dtool/src/interrogatedb/py_panda.I +++ b/dtool/src/interrogatedb/py_panda.I @@ -90,6 +90,19 @@ INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, i Py_RETURN_RICHCOMPARE(cmpval, 0, op); } +/** + * Utility function for assigning a PyObject pointer while managing refcounts. + */ +ALWAYS_INLINE void +Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value) { + PyObject *prev_value = ptr; + if (prev_value != value) { + Py_XINCREF(value); + ptr = value; + Py_XDECREF(prev_value); + } +} + /** * Converts the enum value to a C long. */ diff --git a/dtool/src/interrogatedb/py_panda.h b/dtool/src/interrogatedb/py_panda.h index 353af53608..026d1c6858 100644 --- a/dtool/src/interrogatedb/py_panda.h +++ b/dtool/src/interrogatedb/py_panda.h @@ -238,6 +238,8 @@ EXPCL_PYPANDA PyObject *_Dtool_Return(PyObject *value); #define Dtool_Return(value) _Dtool_Return(value) #endif +ALWAYS_INLINE void Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value); + /** * Wrapper around Python 3.4's enum library, which does not have a C API. */