I’m a novice at Qt in comparison to most here, but I reckon I’ve encountered a bug with KWin. However, I’d like to confirm that it’s not a fault of mine:
Specifically, adding
self.resize(self.minimumSizeHint())
to
Code
#!/usr/bin/env -S python3 ##### **Description** """ This allows management of the brightness of a monitor. It features multiple methods of interaction, and operates upon Windows and traditional Linux distributions (Fedora and OpenSUSE). """ ##### **Dependency Importation** import calendar import time from rich.console import Console from rich.markdown import Markdown #**Origin(s)**: [Stack Overflow](https://stackoverflow.com/revisions/76833666/1#:~:text=from%20rich.console%20import%20Console,%20%20%20%20console.print(md)) ##### **Metadata Definition** __LICENSE__: str = ["MIT"] __COPYRIGHT__: str = ["Copyright 2024 Roke Julian Lockhart Beedell"] __STATUS__: list = ["alpha"] __VERSION__: list = ["1720556480"] __MAINTAINERS__: list = ["[`RokeJulianLockhart`](https://dub.sh/jga)"] __CREDITS__: list = ["[`RokeJulianLockhart`](https://dub.sh/jga)"] if __name__ == "__main__": #**Information**: As [this](https://realpython.com/if-name-main-python/#:~:text=What%20Does%20if%20__name__%20==%20%22__main__%22%20Do%20in%20Python?) explains, this prevents invocation as a module, restricting it to run solely as a script. import sys if sys.version_info[0] != 3 or sys.version_info[1] < 7: #**Origin(s)**: [Avoiding `__init__.py` for Initial Imports](https://stackoverflow.com/revisions/6224814/2#:~:text=You%20should%20not%20use%20any,including%20real%20initial%20imports%2C%20here) Console().print(Markdown('This script requires Python version 3.')) raise SystemExit(-1) #**Information**: [Understanding `sys.exit(n)` in Python](https://stackoverflow.com/revisions/44894090/2#:~:text=The%20call%20sys.exit(n)%20tells%20the,answered) #**Task(s)**: convert to `wxwidgets`/`wxpython`?: \ #1. [wxWidgets Issue 19352: Migrated from Trac Ticket](https://github.com/wxWidgets/wxWidgets/issues/19352#issue-1100648687:~:text=Issue%20migrated%20from%20trac%20ticket,Thanks%20a%20lot!) #1. [wxWidgets: wxQt Project Information](https://www.wxwidgets.org/about/#:~:text=10%20and%0Aabove.-,wxqt,-%3A%20wxQt%20is%20a) ##### **Dependency Importation** import platform import subprocess import logging import shutil #```py #logging.basicConfig(level=logging.DEBUG) # #**Task(s)**: fix [*Placeholder*](https://github.com/Crozzers/screen_brightness_control/discussions/30#discussion-5041474) \. # #**Origin(s)**: [*Placeholder*](https://stackoverflow.com/revisions/41797120/1#:~:text=Try%20this-,logging.basicConfig(level=logging.DEBUG),-answered%20Jan%2022%2C) #``` ##### **Dependency Management** def which(package): """ A function that takes a package name as input, tries to import the package, and if it fails, installs the package using pip. Parameters: package (str): The name of the package to import or install. Returns: None """ try: return __import__(package) except ImportError: subprocess.check_call([sys.executable, "-m", "pip", "install", package]) #**Origin(s)**: [Installing Python Packages with `pip` from Script](https://stackoverflow.com/revisions/50255019/2#:~:text=The%20officially%20recommended%20way%20to,subprocess.check_call(%5Bsys.executable%2C%20%22%2Dm%22%2C%20%22pip%22%2C%20%22install%22%2C%20package%5D)) #**Origin(s): [*Placeholder*](https://stackoverflow.com/revisions/4527622/3#:~:text=package%20=%20'package_name',%20%20%20%20return%20None) Console().print(Markdown(package, 'exists.')) which(package='screen_brightness_control') which(package='PyQt5') which(package='rich') #```py #subprocess.check_call([sys.executable, "-m", "pip", "install", 'PySide6']) #**Task(s)**: ascertain whether this should be used instead, since it is official. https://www.pythonguis.com/faq/pyqt6-vs-pyside6/#:~:text=PySide2-,PyQt6%20vs%20PySide6,-What's%20the%20difference #``` ##### **Dependency Importation** import screen_brightness_control as sbc from PyQt5.QtWidgets import QMenu, QMenuBar, QApplication, QMainWindow, QVBoxLayout, QWidget, QSlider, QLineEdit, QPushButton, QTreeWidget, QTreeWidgetItem #**Task(s)**: replace with PyQt6. from PyQt5 import QtCore #**Task(s)**: replace with PyQt6. from PyQt5.QtCore import Qt #**Task(s)**: replace with PyQt6. ##### **Security** if platform.system() == 'Linux': import getpass import grp import os if getpass.getuser() not in str( subprocess.call(["powershell", "".join( [os.path.dirname(os.path.realpath(__file__)), ''])])): # <code>../ [-] `{title: "Configurator", id: "s3wrcl"}`{.JSON5}.dir/ [-] `{title: "Code", id: ""}`{.JSON5}.dir/ [x] ``{title: "`Get-SuperuserUsername`{.PS1}", id: "settlu"}``{.JSON5}.txt.PS1</code> #**Origin(s)**: \ #1. [*Placeholder*](https://stackoverflow.com/revisions/842096/4#:~:text=Look%20at%20getpass%20module,May%208%2C%202009%20at%2022:30) #1. [`in`](https://stackoverflow.com/revisions/3437070/7#:~:text=Use%20the%20in%20operator:,Note:%20This%20is%20case%2Dsensitive.) #1. [*Placeholder*](https://stackoverflow.com/revisions/3430395/13#:~:text=The%20special%20variable%20__file__%20contains,does%20the%20__file__%20variable%20mean/do?) #1. [*Placeholder*](https://stackoverflow.com/revisions/40311142/3#:~:text=For%20your%20stated%20scenario%2C%20there,Oct%2028%2C%202016%20at%2018:29) logging.getLogger().debug( getpass.getuser(), 'is not the superuser.') #**Task(s)**: Fix concatenation problems: `.debug("Houston, we have a %s", "thorny problem", exc_info=1)` works. try: grp.getgrnam('i2c') except Exception: try: subprocess.call(['sudo', 'groupadd', '--system', 'i2c']) grp.getgrnam('i2c') except Exception: logging.exception('Unable to create group i2c.') raise SystemExit(-1) else: logging.getLogger().debug('i2c exists.') if not [match for match in grp.getgrnam('i2c').gr_mem if getpass.getuser() in match]: #**Information**: [*Placeholder*](https://www.ddcutil.com/i2c_permissions/#:~:text=I2C%20Device%20Permissions-,I2C%20Device%20Permissions,$%20sudo%20chmod%20a+rw%20/dev/i2c%2D*,-Previous) \ #**Origin(s)**: [*Placeholder*](https://stackoverflow.com/revisions/15168560/2#:~:text=This%20answer%20builds%20upon%20the,print('Group%20somegrp%20does%20not%20exist.')) logging.exception(getpass.getuser(), 'is not part of the i2c group.') if subprocess.call(['sudo', 'usermod', getpass.getuser(), '-aG', 'i2c']) != 0: logging.exception('Unable to add user to i2c.') raise SystemExit(-1) else: logging.getLogger().debug(getpass.getuser(), 'added to i2c.') else: logging.getLogger().debug(getpass.getuser(), 'is part of i2c.') import shutil ddcutil_available = False logging.getLogger().debug('0: ddcutil_available = False') if shutil.which('ddcutil') is None: logging.getLogger().error('Code RSJQ4A: the ddcutils binary is unavailable.') ddcutil_available = False logging.getLogger().debug('1: ddcutil_available = False') elif os.path.exists(shutil.which('ddcutil')): ddcutil_available = True logging.getLogger().debug('2: ddcutil_available = True') else: ddcutil_available = False logging.getLogger().error('Invalid output of shutil. Defaulting to assumption that ddcutil is unavailable.') if (sbc.list_monitors(method='ddcutil') == sbc.list_monitors()) == False: logging.getLogger().error('Code RSJPK5: ddcutils is unable to acquire the list of monitors. Operations may become slow.') ddcutil_available = False logging.getLogger().debug('3: ddcutil_available = False') elif (sbc.list_monitors(method='ddcutil') == sbc.list_monitors()) == True: logging.getLogger().debug('4: ddcutil is available.') ddcutil_available = True logging.getLogger().debug('5: ddcutil_available = True') else: logging.exception('ddcutil_available contains invalid value.') raise Exception(1) ##### **GUI** class MainWindow(QMainWindow): """ * The class `MainWindow` inherits from `QMainWindow` and sets up a main window layout with monitor information. * `__init__`: Initializes the main window layout, sets up monitor list, slider, input area, and apply configuration button. * `on_click`: Handles the logic for applying the configuration to every checked monitor in the list. """ def __init__(self, *args, **kwargs): """ Initializes the MainWindow class. Args: *args: Variable length argument list. **kwargs: Arbitrary keyword arguments. Returns: None """ super(MainWindow, self).__init__(*args, **kwargs) layout_1 = QVBoxLayout() layout_1.setAlignment(QtCore.Qt.AlignTop) widget_1 = QWidget() widget_1.setLayout(layout_1) self.setCentralWidget(widget_1) self.resize(self.minimumSizeHint()) #**Origin(s)**: [Stack Overflow](https://stackoverflow.com/revisions/28667119/1#:~:text=is%20changed%20:-,self.resize(minimumSizeHint()),-This%20will%20shrink) monitor_list = QTreeWidget() layout_1.addWidget(monitor_list) #```py #monitor_list.setWindowTitle('Monitors') # #**Task(s)**: ascertain what this does. #``` headers = (['Model', 'Brightness']) monitor_list.setColumnCount(len(headers)) monitor_list.setHeaderLabels(headers) counter = 0 if ddcutil_available == True: #**Origin(s)**: [*Placeholder*](https://stackoverflow.com/revisions/11269627/7#:~:text=For%20python%20%3E=%203.3%2C%20Redirect,=%20os.system(%22echo%20'foo'%20%26%3E%20/dev/null%22)) while counter < len(sbc.list_monitors(method='ddcutil')): #**Task(s)**: this doesn't operate with more than 1 monitor attached. rowcount = monitor_list.topLevelItemCount() monitor_list.addTopLevelItem(QTreeWidgetItem(rowcount)) monitor_list.topLevelItem(rowcount).setText(rowcount, sbc.list_monitors(method='ddcutil')[counter]) if sbc.list_monitors(method='ddcutil')[rowcount] == sbc.list_monitors(method='ddcutil')[0]: monitor_list.topLevelItem(rowcount).setSelected(True) #**Origin(s)**: [*Placeholder*](https://stackoverflow.com/posts/30213421/revisions#:~:text=You%20can%20interact%20with%20the,%7D) else: monitor_list.topLevelItem(rowcount).setSelected(False) monitor_list.topLevelItem(rowcount).setCheckState(rowcount, QtCore.Qt.Unchecked) monitor_list.topLevelItem(rowcount).setFlags(monitor_list.topLevelItem(rowcount).flags() | QtCore.Qt.ItemIsUserCheckable) counter = counter + 1 if ddcutil_available == False: while counter < len(sbc.list_monitors()): #**Task(s)**: this doesn't operate with more than 1 monitor attached. rowcount = monitor_list.topLevelItemCount() monitor_list.addTopLevelItem(QTreeWidgetItem(rowcount)) monitor_list.topLevelItem(rowcount).setText(rowcount, sbc.list_monitors()[counter]) if sbc.list_monitors()[rowcount] == sbc.list_monitors()[0]: monitor_list.topLevelItem(rowcount).setSelected(True) #**Origin(s)**: [*Placeholder*](https://stackoverflow.com/posts/30213421/revisions#:~:text=You%20can%20interact%20with%20the,%7D) monitor_list.topLevelItem(rowcount).setCheckState(rowcount, QtCore.Qt.Checked) else: monitor_list.topLevelItem(rowcount).setSelected(False) monitor_list.topLevelItem(rowcount).setCheckState(rowcount, QtCore.Qt.Unchecked) monitor_list.topLevelItem(rowcount).setFlags(monitor_list.topLevelItem(rowcount).flags() | QtCore.Qt.ItemIsUserCheckable) counter = counter + 1 if not platform.system() == 'Windows' and not platform.system() == 'Darwin': logging.getLogger().debug("Unknown and consequently unsupported platform.") #```py #for monitor in sbc.list_monitors(): # Console().print(Markdown(monitor, ':', sbc.get_brightness(display=monitor), '%')) #``` chosen_display = 0 slider = QSlider(Qt.Orientation.Horizontal, self) layout_1.addWidget(slider) slider.setRange(0, 100) #**Task(s)**: add checkbox to override chosen colour with value provided by external device (brightness sensor) #```py #label = QLabel(sbc.list_monitors()[chosen_display], self) #layout_1.addWidget(label) # #**Task(s)**: this should be to the left of the input box. #``` if ddcutil_available == True: #**Origin(s)**: [Redirecting Output to `/dev/null` in Python 3.3+](https://stackoverflow.com/revisions/11269627/7#:~:text=For%20python%20%3E=%203.3%2C%20Redirect,=%20os.system(%22echo%20'foo'%20%26%3E%20/dev/null%22)) slider.setValue(sbc.get_brightness(method='ddcutil')[0]) #**Task(s)**: discover whether specification of a method is necessary, and if so, which to utilize. elif ddcutil_available == False: slider.setValue(sbc.get_brightness()[0]) #**Information**: `sbc.get_brightness(method='ddcutil')` is significantly more quick. if not platform.system() == 'Windows' and not platform.system() == 'Darwin': logging.getLogger().debug("Unknown and consequently unsupported platform.") input_area = QLineEdit(self) layout_1.addWidget(input_area) if ddcutil_available == True: #**Information**: [Pylint Singleton Comparison Convention](https://pylint.pycqa.org/en/latest/user_guide/messages/convention/singleton-comparison.html) input_area.setPlaceholderText(str(sbc.get_brightness(method='ddcutil')[chosen_display])) #**Task(s)**: discover whether specification of a method is necessary, and if so, which to utilize. else: input_area.setPlaceholderText(str(sbc.get_brightness()[chosen_display])) #**Task(s)**: discover whether specification of a method is necessary, and if so, which to utilize. if not platform.system() == 'Windows' and not platform.system() == 'Darwin': logging.getLogger().debug("Unknown and consequently unsupported platform.") application = QPushButton('Apply configuration', self) layout_1.addWidget(application) #```py #def onSlide(slider): # input_area.setPlaceholderText(slider.value()) #slider.valueChanged.connect(slider.valueChanged) #``` #**Information**: [*Placeholder*](https://www.reddit.com/r/QtFramework/comments/10ac5kg/comment/j4734je/?utm_source=share&utm_medium=web2x&context=3) def on_click(): #**Task(s)**: Use [*Placeholder*](https://stackoverflow.com/a/60785652/9731176) to apply to every checked monitor in list. if ddcutil_available == True: #**Information**: [*Placeholder*](https://pylint.pycqa.org/en/latest/user_guide/messages/convention/singleton-comparison.html) sbc.set_brightness(slider.value(), method='ddcutil') #**Origin(s)**: [*Placeholder*](https://stackoverflow.com/a/15765621/9731176) input_area.setPlaceholderText(str(sbc.get_brightness(method='ddcutil')[chosen_display])) elif ddcutil_available == False: sbc.set_brightness(slider.value()) input_area.setPlaceholderText(str(sbc.get_brightness()[chosen_display])) if not platform.system() == 'Windows' and not platform.system() == 'Darwin': logging.getLogger().debug("Unknown and consequently unsupported platform.") application.clicked.connect(on_click) application.click() #**Information**: [*Placeholder*](https://forum.qt.io/topic/94834/differences-between-qapplication-qguiappication-qcoreapplication-classes?_=1720556789808&lang=en-GB#:~:text=QCoreApplication%20%2D%20base%20class.%20Use,starts%20when%20you%20call%20app.exec();.) app = QApplication #**Information**: \ #1. Set attributes before `sys.argv` is passed to `QApplication` constructor. #1. [*Placeholder*](https://medium.com/analytics-vidhya/how-to-build-your-first-desktop-application-in-python-7568c7d74311#:~:text=the%20qquickwindow.setscenegraphbackend('software')%20should%20be%20included%20in%20your%20code%20as%20a%20fallback%20option%20for%20uses%20with%20old%20hardware%20specs%2C%20other%20than%20that%20they%20would%20see%20an%20error%20information%20as%20seen%20below%3A) from PyQt6.QtQuick import QQuickWindow QQuickWindow.setTextRenderType( QQuickWindow.TextRenderType.NativeTextRendering) #**Information**: Should enable High DPI scaling, but isn't necesssary for Qt6. app.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) #**Information**: [Ensures that widgets have native windows.](https://doc.qt.io/qt-6/qt.html#:~:text=qt%3A%3Aaa_nativewindows) app.setAttribute(QtCore.Qt.AA_NativeWindows, True) app = QApplication(sys.argv) main_window = MainWindow() main_window.show() #**Information**: Hardcoded exit code unnecessary because `sys.exit()` provides it. sys.exit(app.exec()) #**Information**: [`exec()` rather than `exec_()` is due to non-backward compatbility.](https://stackoverflow.com/revisions/22614643/4#:~:text=That's%20because%20until%20Python%203%2C,methods%20have%20been%20removed.%20...) raise SystemExit(-1)
and then resizing the window causes
The Wayland connection experienced a fatal error: Protocol error
as the full log explains:
Log
wl_subsurface@56: error 0: no parent The Wayland connection experienced a fatal error: Protocol error RokeJulianLockhart@sayw4i:~/Documents/pyside6$
Surely such a simple statement shouldn’t be able to bring crash the application, especially since it references that the protocol was incorrectly adhered to?
If it’s a fault of mine, I apologise for wasting time here, and I’ll go to the Qt forums instead for assistance. I am aware of how bad this code is - it’s part-way through a refactor from when it was truly dreadful.