ssokolow / quicktile

Adds window-tiling hotkeys to any X11 desktop. (An analogue to WinSplit Revolution for people who don't want to use Compiz Grid)
https://ssokolow.com/quicktile/
GNU General Public License v2.0
860 stars 78 forks source link

Bug detected - A programming error has been detected during the execution of this program #131

Closed rushvora closed 11 months ago

rushvora commented 2 years ago

On booting into the OS, this crash dialog box came up. Screenshot below.

Screenshot-20211019103101-1382x392

Quicktile fails to work at this moment, but I can successfully run quicktile --daemonize and everything works as expected. This error also does not happen consistently, it happens sporadically. Most of the time when I boot up, quicktile does not crash.

OS details - EndeavourOS; Build ID: 2021.08.27 uname -r = 5.14.12-arch1-1 DE = Gnome 40.4.0 Windowing System - X11

Display Config 1440p 144hz display (ASUS VG27AQ) 4K 60Hz display (LG 27UK650)

Fractional scaling is enabled, ASUS is the main display, 100% scaling, LG is the secondary display, 150% scaling.

Hardware AMD Ryzen 5600X ASUS TUF Gaming X570 Plus NVIDIA RTX 3080 FE 32GB 3600 CL16 RAM 1TB NVME SSD boot drive

The contents of the details section is as below

Traceback (most recent call last):
  File '/usr/bin/quicktile', line 33, <module>()
    if __name__ == '__main__':
        sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
        sys.exit(load_entry_point('QuickTile==0.4.1', 'console_scripts', 'quicktile')())
    Variables (B=Builtin, G=Global, L=Local):
     -     sys.exit (L): <built-in function exit>
     - load_entry_point (L): <function importlib_load_entry_point at
       0x7f3dbbb1a040>

  File '/usr/lib/python3.9/site-
    packages/QuickTile-0.4.1-py3.9.egg/quicktile/__main__.py', line 382, main()
        try:
            winman = WindowManager(x_display=x_display)
        except XInitError as err:
    Variables (B=Builtin, G=Global, L=Local):
     -       winman (N): None
     - WindowManager (G): <class 'quicktile.wm.WindowManager'>
     -    x_display (L): <Xlib.display.Display object at 0x7f3db6d0c9a0>

  File '/usr/lib/python3.9/site-
    packages/QuickTile-0.4.1-py3.9.egg/quicktile/wm.py', line 98,
    __init__(self=<quicktile.wm.WindowManager object>, screen=None,
    x_display=<Xlib.display.Display object>)
            self.usable_region = UsableRegion()
            self.update_geometry_cache()
            # TODO: Hook monitor-added and monitor-removed and regenerate this
    Variables (B=Builtin, G=Global, L=Local):
     - self.update_geometry_cache (L): <bound method
       WindowManager.update_geometry_cache of <quicktile.wm.WindowManager object
       at 0x7f3db59d1400>>

  File '/usr/lib/python3.9/site-
    packages/QuickTile-0.4.1-py3.9.egg/quicktile/wm.py', line 145,
    update_geometry_cache(self=<quicktile.wm.WindowManager object>)
                win = self.x_display.create_resource_object('window', wid)
                result = self.get_property(
                    win, '_NET_WM_STRUT_PARTIAL', Xatom.CARDINAL)
    Variables (B=Builtin, G=Global, L=Local):
     -       result (L): None
     - self.get_property (L): <bound method WindowManager.get_property of
       <quicktile.wm.WindowManager object at 0x7f3db59d1400>>
     -          win (L): <Window 0x00c00003>
     - Xatom.CARDINAL (G): 6

  File '/usr/lib/python3.9/site-
    packages/QuickTile-0.4.1-py3.9.egg/quicktile/wm.py', line 311,
    get_property(self=<quicktile.wm.WindowManager object>, win=<Window
    0x00c00003>, name=450, prop_type=6, empty=None)
            result = win.get_full_property(name, prop_type)
            return result.value if result else empty
    Variables (B=Builtin, G=Global, L=Local):
     -       result (N): None
     - win.get_full_property (L): <bound method Window.get_full_property of
       <Window 0x00c00003>>
     -         name (L): 450
     -    prop_type (L): 6

  File '/usr/lib/python3.9/site-packages/Xlib/xobject/drawable.py', line 472,
    get_full_property(self=<Window 0x00c00003>, property=450, property_type=6,
    sizehint=10)
        def get_full_property(self, property, property_type, sizehint = 10):
            prop = self.get_property(property, property_type, 0, sizehint)
            if prop:
    Variables (B=Builtin, G=Global, L=Local):
     -         prop (N): None
     - self.get_property (L): <bound method Window.get_property of <Window
       0x00c00003>>
     -     property (L): 450
     - property_type (L): 6
     -     sizehint (L): 10

  File '/usr/lib/python3.9/site-packages/Xlib/xobject/drawable.py', line 455,
    get_property(self=<Window 0x00c00003>, property=450, property_type=6,
    offset=0, length=10, delete=0)
        def get_property(self, property, property_type, offset, length, delete = 0):
            r = request.GetProperty(display = self.display,
                                    delete = delete,
    Variables (B=Builtin, G=Global, L=Local):
     -            r (N): None
     - request.GetProperty (G): <class 'Xlib.protocol.request.GetProperty'>
     -      display (N): None
     - self.display (L): <Xlib.display._BaseDisplay object at 0x7f3db6d0c9d0>
     -       delete (L): None
     -       window (N): None
     -      self.id (L): 12582915
     -     property (L): 450
     -         type (B): <class 'type'>
     - property_type (L): 6
     -  long_offset (N): None
     -       offset (L): None
     -  long_length (N): None
     -       length (L): 10

  File '/usr/lib/python3.9/site-packages/Xlib/protocol/rq.py', line 1369,
    __init__(self=<GetProperty serial = 23, data = None, error = <...number =
    23, major_opcode = 20, minor_opcode = 0>, display=<Xlib.display._BaseDisplay
    object>, defer=0, *args=(), **keys={'delete': 0, 'long_length': 10,
    'long_offset': 0, 'property': 450, 'type': 6, 'window': 12582915})
            if not defer:
                self.reply()
    Variables (B=Builtin, G=Global, L=Local):
     -   self.reply (L): <bound method ReplyRequest.reply of <GetProperty serial
       = 23, data = None, error = <class 'Xlib.error.BadWindow'>: code = 3,
       resource_id = <Resource 0x00c00003>, sequence_number = 23, major_opcode =
       20, minor_opcode = 0>>

  File '/usr/lib/python3.9/site-packages/Xlib/protocol/rq.py', line 1389,
    reply(self=<GetProperty serial = 23, data = None, error = <...number = 23,
    major_opcode = 20, minor_opcode = 0>)
            if self._error:
                raise self._error
    Variables (B=Builtin, G=Global, L=Local):
     -  self._error (L): BadWindow(<Xlib.display._BaseDisplay object at
       0x7f3db6d0c9d0>, b'\x00\x03\x17\x00\x03\x00\xc0\x00\x00\x00\x14\x00\x00\x
       00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0
       0')
BadWindow: <class 'Xlib.error.BadWindow'>: code = 3, resource_id = <Resource 0x00c00003>, sequence_number = 23, major_opcode = 20, minor_opcode = 0

Do let me know if more details are needed.

ssokolow commented 2 years ago

Ugh. Looks like another way X.org can raise an error that I didn't anticipate and catch.

This sort of thing really makes me wonder if I should rewrite QuickTile in Rust so I can just see the potential error returns in the function signatures.

I haven't double-checked the code yet but, purely from the backtrace and your description, it looks like a race condition where QuickTile is erroring out if it tries to gather information on space reserved by panels at the wrong moment during your desktop's startup process and getting slapped with an error along the lines of "the window you asked for information on went away after you looked up its ID but before you queried it".

This is a pretty busy time for me, so I'm not sure when I'll get to this, but leave the bug open and I'll try to find time eventually.

rushvora commented 2 years ago

@ssokolow Understood. This bug doesn't happen often enough to be an annoyance, and when it does happen, I can just run quicktile --daemonize and get it working perfectly fine.

WillMeakin commented 2 years ago

If it helps anyone I had this error when I put quicktile --daemonize & disown in ~/.bashrc. I fixed it by adding the Quicktile application to my distro's "Apps to start at login".

ssokolow commented 11 months ago

Sorry for taking so long to get to this. It looks like it's probably a race condition where QuickTile gets a list of open windows and then tries to query each one to see if it's reserved any space for panels (because there's no standard workarea thing the WM sets that works properly with non-rectangular multi-monitor desktops), so I just added some code to catch the error and convert it into a "this is probably harmless" warning message.

Since I've never encountered this and race conditions are a huge pain to reproduce reliably, even if you are experiencing them, I'm going to assume this is fixed now. Please reopen if it still causes problems.