From 9d21d491573247d3f0046412cc8e7ee93968deff Mon Sep 17 00:00:00 2001 From: "Michal Krenek (Mikos)" Date: Thu, 30 Mar 2017 14:27:33 +0200 Subject: [PATCH] Always open console on Windows (but hide it) Otherwise program crashes when trying to communicate with subprocess (e.g. soapy_power) if started in pythonw.exe, bacause console is missing. --- MANIFEST.in | 1 - PKGBUILD | 2 +- README.rst | 2 +- qspectrumanalyzer.py | 5 - qspectrumanalyzer/__main__.py | 31 ++++- qspectrumanalyzer/backends/__init__.py | 9 +- qspectrumanalyzer/backends/soapy_power.py | 15 +-- qspectrumanalyzer/qspectrumanalyzer.svg | 133 ++++++++++++++++++++++ qspectrumanalyzer/windows.py | 48 ++++++++ setup.py | 33 ++++-- soapy_power.py | 5 - 11 files changed, 247 insertions(+), 37 deletions(-) delete mode 100755 qspectrumanalyzer.py mode change 100755 => 100644 qspectrumanalyzer/__main__.py create mode 100644 qspectrumanalyzer/qspectrumanalyzer.svg create mode 100644 qspectrumanalyzer/windows.py delete mode 100755 soapy_power.py diff --git a/MANIFEST.in b/MANIFEST.in index db446d0..38f74e8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,3 @@ include LICENSE include README.rst include qspectrumanalyzer.desktop include qspectrumanalyzer.png -include qspectrumanalyzer.svg diff --git a/PKGBUILD b/PKGBUILD index 39bfe0a..a42122d 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -2,7 +2,7 @@ pkgname=qspectrumanalyzer pkgver=2.1.0 pkgrel=1 -pkgdesc="Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power, rx_power, rtl_power, hackrf_sweep and other backends)" +pkgdesc="Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power, rtl_power, hackrf_sweep, rx_power and other backends)" arch=('any') url="https://github.com/xmikos/qspectrumanalyzer" license=('GPL3') diff --git a/README.rst b/README.rst index ecd6ac7..dc4c381 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ QSpectrumAnalyzer ================= Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power, -rx_power, rtl_power, hackrf_sweep and other backends) +rtl_power, hackrf_sweep, rx_power and other backends) Screenshots ----------- diff --git a/qspectrumanalyzer.py b/qspectrumanalyzer.py deleted file mode 100755 index 825e1e6..0000000 --- a/qspectrumanalyzer.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python3 -from qspectrumanalyzer.__main__ import main - -if __name__ == '__main__': - main() diff --git a/qspectrumanalyzer/__main__.py b/qspectrumanalyzer/__main__.py old mode 100755 new mode 100644 index 14ef0a8..638951f --- a/qspectrumanalyzer/__main__.py +++ b/qspectrumanalyzer/__main__.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -import sys, signal, time +import sys, os, signal, time, argparse from Qt import QtCore, QtGui, QtWidgets, __binding__ @@ -17,6 +17,8 @@ from qspectrumanalyzer.ui_qspectrumanalyzer_persistence import Ui_QSpectrumAnaly from qspectrumanalyzer.ui_qspectrumanalyzer_colors import Ui_QSpectrumAnalyzerColors from qspectrumanalyzer.ui_qspectrumanalyzer import Ui_QSpectrumAnalyzerMainWindow +debug = False + # Allow CTRL+C and/or SIGTERM to kill us (PyQt blocks it otherwise) signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) @@ -240,6 +242,10 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai super().__init__(parent) self.setupUi(self) + # Set window icon + icon_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "qspectrumanalyzer.svg") + self.setWindowIcon(QtGui.QIcon(icon_path)) + # Create plot widgets and update UI self.spectrumPlotWidget = SpectrumPlotWidget(self.mainPlotLayout) self.waterfallPlotWidget = WaterfallPlotWidget(self.waterfallPlotLayout, self.histogramPlotLayout) @@ -612,7 +618,28 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai def main(): - app = QtWidgets.QApplication(sys.argv) + global debug + + # Parse command line arguments + parser= argparse.ArgumentParser( + prog="qspectrumanalyzer", + description="Spectrum analyzer for multiple SDR platforms", + ) + parser.add_argument("--debug", action="store_true", + help="detailed debugging messages") + parser.add_argument("--version", action="version", + version="%(prog)s {}".format(__version__)) + args, unparsed_args = parser.parse_known_args() + debug = args.debug + + # Hide console window on Windows + if sys.platform == 'win32' and not debug: + from qspectrumanalyzer import windows + if windows.is_attached_console_visible(): + windows.set_attached_console_visible(False) + + # Start PyQt application + app = QtWidgets.QApplication(sys.argv[:1] + unparsed_args) app.setOrganizationName("QSpectrumAnalyzer") app.setOrganizationDomain("qspectrumanalyzer.eutopia.cz") app.setApplicationName("QSpectrumAnalyzer") diff --git a/qspectrumanalyzer/backends/__init__.py b/qspectrumanalyzer/backends/__init__.py index 3402edf..06b8fb8 100644 --- a/qspectrumanalyzer/backends/__init__.py +++ b/qspectrumanalyzer/backends/__init__.py @@ -82,10 +82,11 @@ class BasePowerThread(QtCore.QThread): """Terminate power process""" with self._shutdown_lock: if self.process: - try: - self.process.terminate() - except ProcessLookupError: - pass + if self.process.poll() is None: + try: + self.process.terminate() + except ProcessLookupError: + pass self.process.wait() self.process = None diff --git a/qspectrumanalyzer/backends/soapy_power.py b/qspectrumanalyzer/backends/soapy_power.py index cfd4c5c..35c4545 100644 --- a/qspectrumanalyzer/backends/soapy_power.py +++ b/qspectrumanalyzer/backends/soapy_power.py @@ -140,13 +140,14 @@ class PowerThread(BasePowerThread): """Stop soapy_power process""" with self._shutdown_lock: if self.process: - try: - if sys.platform == 'win32': - self.process.send_signal(signal.CTRL_BREAK_EVENT) - else: - self.process.terminate() - except ProcessLookupError: - pass + if self.process.poll() is None: + try: + if sys.platform == 'win32': + self.process.send_signal(signal.CTRL_BREAK_EVENT) + else: + self.process.terminate() + except ProcessLookupError: + pass self.process.wait() self.process = None diff --git a/qspectrumanalyzer/qspectrumanalyzer.svg b/qspectrumanalyzer/qspectrumanalyzer.svg new file mode 100644 index 0000000..5c12b4c --- /dev/null +++ b/qspectrumanalyzer/qspectrumanalyzer.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/qspectrumanalyzer/windows.py b/qspectrumanalyzer/windows.py new file mode 100644 index 0000000..3ce9637 --- /dev/null +++ b/qspectrumanalyzer/windows.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# +# Copyright © Spyder Project Contributors +# Licensed under the terms of the MIT License +# (see spyder/__init__.py for details) + +"""Windows-specific utilities""" + + +from ctypes import windll + + +# --- Window control --- + +SW_SHOW = 5 # activate and display +SW_SHOWNA = 8 # show without activation +SW_HIDE = 0 + +GetConsoleWindow = windll.kernel32.GetConsoleWindow +ShowWindow = windll.user32.ShowWindow +IsWindowVisible = windll.user32.IsWindowVisible + +# Handle to console window associated with current Python +# interpreter procss, 0 if there is no window +console_window_handle = GetConsoleWindow() + +def set_attached_console_visible(state): + """Show/hide system console window attached to current process. + Return it's previous state. + + Availability: Windows""" + flag = {True: SW_SHOW, False: SW_HIDE} + return bool(ShowWindow(console_window_handle, flag[state])) + +def is_attached_console_visible(): + """Return True if attached console window is visible""" + return IsWindowVisible(console_window_handle) + +def set_windows_appusermodelid(): + """Make sure correct icon is used on Windows 7 taskbar""" + try: + return windll.shell32.SetCurrentProcessExplicitAppUserModelID("spyder.Spyder") + except AttributeError: + return "SetCurrentProcessExplicitAppUserModelID not found" + + +# [ ] the console state asks for a storage container +# [ ] reopen console on exit - better die open than become a zombie diff --git a/setup.py b/setup.py index 33deb4e..4148fd7 100755 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ try: setup_entry_points = { "console_scripts": [ Executable('QSpectrumAnalyzer=qspectrumanalyzer.__main__:main', - console=False, icon_file='qspectrumanalyzer.ico'), + console=True, icon_file='qspectrumanalyzer.ico'), Executable('soapy_power=soapypower.__main__:main', console=True), ], @@ -39,7 +39,8 @@ except ImportError: setup( name="QSpectrumAnalyzer", version=__version__, - description="Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power, rx_power, rtl_power, hackrf_sweep and other backends)", + description=("Spectrum analyzer for multiple SDR platforms " + "(PyQtGraph based GUI for soapy_power, rtl_power, hackrf_sweep, rx_power and other backends)"), long_description=open('README.rst').read(), author="Michal Krenek (Mikos)", author_email="m.krenek@gmail.com", @@ -48,19 +49,20 @@ setup( packages=["qspectrumanalyzer", "qspectrumanalyzer.backends"], package_data={ "qspectrumanalyzer": [ + "qspectrumanalyzer.svg", "*.ui", "languages/*.qm", - "languages/*.ts" - ] + "languages/*.ts", + ], }, data_files=[ ("share/applications", ["qspectrumanalyzer.desktop"]), - ("share/pixmaps", ["qspectrumanalyzer.png"]) + ("share/pixmaps", ["qspectrumanalyzer.png"]), ], install_requires=[ - "soapy_power>=1.5.0", + "soapy_power>=1.6.0", "pyqtgraph>=0.10.0", - "Qt.py" + "Qt.py", ], classifiers=[ "Development Status :: 4 - Beta", @@ -75,17 +77,26 @@ setup( "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Topic :: Communications :: Ham Radio", - "Topic :: Scientific/Engineering :: Visualization" + "Topic :: Scientific/Engineering :: Visualization", ], options={ 'build_qt': { 'packages': ['qspectrumanalyzer'], 'languages': ['cs'], - 'replacement_bindings': 'Qt' + 'replacement_bindings': 'Qt', + }, + 'build_exe': { + 'datas': [ + ('qspectrumanalyzer/qspectrumanalyzer.svg', 'qspectrumanalyzer'), + ('qspectrumanalyzer/*.ui', 'qspectrumanalyzer'), + ('qspectrumanalyzer/languages/*.ts', 'qspectrumanalyzer/languages'), + ('qspectrumanalyzer/languages/*.qm', 'qspectrumanalyzer/languages'), + ('README.rst', '.'), + ('LICENSE', '.'), + ], }, - 'build_exe': {}, 'bdist_msi': { - 'upgrade_code': '30740ef4-84e7-4e67-8e4a-12b53492c387', + 'upgrade_code': '{30740EF4-84E7-4E67-8E4A-12B53492C387}', 'shortcuts': [ 'ProgramMenuFolder\\QSpectrumAnalyzer=QSpectrumAnalyzer', ], diff --git a/soapy_power.py b/soapy_power.py deleted file mode 100755 index b8765f6..0000000 --- a/soapy_power.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python3 -from soapypower.__main__ import main - -if __name__ == '__main__': - main()