Closed super-ibby closed 1 year ago
Hi! This looks awesome!!! Thank you!
Let me check if this works in all versions and cases. Beforehand, it seems to be a much better solution than AppleScript, which is usually slow, tricky and complex. I can not merge it because the typing checks have failed. I don't know if you can see the results, that's why I'm attaching them here:
The new
WindowDelegate
class can be used to run operations on the main thread where required. I'm thinking this class can be extended with additional methods to replace other uses of AppleScript in the code.
This sounds like heaven to me. Please let me know any progress you make or if I can help in any way (I never heard about this new class neither I am an AppKit expert, but I can help to investigate, test, ...). Replacing AppleScript as much as possible is like a dream come true!!!
Thank you SO MUCH!
Hi @Kalmat , I've added type hints now.
results
member dictionary in WindowDelegate
results
is meant to be the pyobjc
selector
as a bytes
tring.results
is set to Any
to allow the class to be extended with additional methods. For example, at the moment, it has one method to get the titlebar height and border width. So the results would be a tuple
in this case, but if we introduce another method in the future, the result may be a single value.I hope that makes sense!
Replacing AppleScript as much as possible is like a dream come true!!!
I will have a look to see if I can replace more usages of AppleScript with AppKit. (On my spare time of course! 😄 )
I hope that makes sense!
It makes sense! We will see what it turns out to be in the future. Perhaps we can define a type indicator or similar. For now, it's ok!
I will have a look to see if I can replace more usages of AppleScript with AppKit. (On my spare time of course! 😄 )
Wow! That would be amazing. Of course in your spare time... this is just for fun! No obligation, no hurries... Thank you!
Hi @Kalmat ,
I've just noticed you have an entry point (if __name__ == '__main__'
) in _pywinctl_macos.py
. When I run the file as a script, I get the following error:
Traceback (most recent call last):
File "/Users/ibby/Developer/PyWinCtl/src/pywinctl/_pywinctl_macos.py", line 478, in <module>
class WindowDelegate(AppKit.NSObject): # Cannot put into a closure as subsequent calls will cause a re-registration error due to subclassing NSObject.
objc.error: WindowDelegate is overriding existing Objective-C class
(This is the re-registration error I allude to in the comment next to the class definition.)
However, if I use the file as a module and import from it, I do not get an error. Also, if I copy the WindowDelegate
class definition into a new python file, and run that file, I get no errors. For example:
from typing import Any, Dict, Optional
import AppKit
class WindowDelegate(AppKit.NSObject): # Cannot put into a closure as subsequent calls will cause a re-registration error due to subclassing NSObject.
"""Helps run window operations on the main thread."""
results: Dict[bytes, Any] = {} # Store results here. Not ideal, but may be better than using a global.
@staticmethod
def run_on_main_thread(selector: bytes, obj: Optional[Any]=None, wait: Optional[bool]=True) -> Any:
"""Runs a method of this object on the main thread."""
WindowDelegate.alloc().performSelectorOnMainThread_withObject_waitUntilDone_(selector, obj, wait)
return WindowDelegate.results.get(selector)
def getTitleBarHeightAndBorderWidth(self) -> None:
"""Updates results with title bar height and border width."""
frame_width = 100
window = AppKit.NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
((0, 0), (frame_width, 100)),
AppKit.NSTitledWindowMask,
AppKit.NSBackingStoreBuffered,
False,
)
titlebar_height = int(window.titlebarHeight())
# print(titlebar_height)
content_rect = window.contentRectForFrameRect_(window.frame())
x1 = AppKit.NSMinX(content_rect)
x2 = AppKit.NSMaxX(content_rect)
border_width = int(frame_width - (x2 - x1))
# print(border_width)
result = titlebar_height, border_width
WindowDelegate.results[b'getTitleBarHeightAndBorderWidth'] = result
def foo(self): # Just to test.
print('foo')
if __name__ == '__main__':
wd = WindowDelegate.alloc()
wd.foo()
Therefore, something seems odd with the _pywinctl_macos.py
entry point. I've not figured it out yet, but wanted to check with you if you've seen something similar.
Hi @Kalmat , I have found a way to get the titlebar height and border width using AppKit rather than subprocess calls to run an AppleScript. This should result in some performance improvements, though I've not measured this!
The new
WindowDelegate
class can be used to run operations on the main thread where required. I'm thinking this class can be extended with additional methods to replace other uses of AppleScript in the code.Please let me know what you think.
Thanks!