Open Kalmat opened 1 year ago
Thanks!!! I'll study them and give some feedback on how it can cooperate with my lib.
Not at all!!! It's not meant for feedback, just to reuse it if it's useful in any way! Otherwise, you can just ignore it without thinking it twice! In fact, this all will go to the trash bin and will be replaced by your module!!!!
After reviewing all your comments, I separated set_property() and send_event() functions. Whilst set_property() is very simple (like setWmState() or setWmType() are), send_event() is not... That's what I was trying to explain about having simple/pre-defined functions and more "general"/complex functions for advanced users/inevitably complex actions. Like this:
def sendMessage(self, prop: str | int, data: list[int]):
if isinstance(prop, str):
prop = self.display.get_atom(prop)
if type(data) is str:
dataSize = 8
else:
data = (data + [0] * (5 - len(data)))[:5]
dataSize = 32
ev = Xlib.protocol.event.ClientMessage(window=self.win, client_type=prop, data=(dataSize, data))
mask = Xlib.X.SubstructureRedirectMask | Xlib.X.SubstructureNotifyMask
self.display.send_event(destination=self.rid, event=ev, event_mask=mask)
self.display.flush()
def setProperty(self, prop: str | int, data: list[int], mode: Xlib.X.Atom = Xlib.X.PropModeReplace):
if isinstance(prop, str):
prop = self.display.get_atom(prop)
# Format value can be 8, 16 or 32... depending on the content of data
format = 32
self.win.change_property(prop, Xlib.Xatom.ATOM, format, data, mode)
self.display.flush()
def setWmState(self, action: int, state: str | int, state2: str | int = 0):
if isinstance(state, str):
state = self.display.get_atom(state, True)
if isinstance(state2, str):
state2 = self.display.get_atom(state2, True)
self.setProperty(WM_STATE, [action, state, state2, 1])
self.display.flush()
def setWmType(self, prop: str | int, mode: Xlib.X.Atom = Xlib.X.PropModeReplace):
if isinstance(prop, str):
prop = self.display.get_atom(prop, False)
geom = self.win.get_geometry()
self.win.unmap()
self.setProperty(WM_WINDOW_TYPE, [prop], mode)
self.win.map()
self.display.flush()
self.setMoveResize(x=geom.x, y=geom.y, width=geom.width, height=geom.height)
def sendMessage(self, prop: str | int, data: list[int]): ... if type(data) is str: dataSize = 8 else: data = (data + [0] * (5 - len(data)))[:5] dataSize = 32 ...
Xlib's send_event
(and its usage in EWMH) has no dataSize
or data: str
type. That's for get/change_property
. A message is always for requests / actions, data is always a 5-length list of ints, always never used with strings.
self.display.send_event(destination=self.rid, event=ev, event_mask=mask)
There's no display.send_event(destination)
in Xlib. There's Window.send_event()
, self being the destination. So, for a window to send an event to the Root Window (as needed by many EWMH methods), that window needs a reference to the root window.
And it's not trivial to get a root reference from an Xlib's Window: you have Window.display
, but no reference to the sno
or screen
you need.
def setProperty(self, prop: str | int, data: list[int], mode: Xlib.X.Atom = Xlib.X.PropModeReplace): if isinstance(prop, str): prop = self.display.get_atom(prop) # Format value can be 8, 16 or 32... depending on the content of data format = 32 self.win.change_property(prop, Xlib.Xatom.ATOM, format, data, mode) self.display.flush()
Without allowing bytes
or format != 32, this setProperty
you suggest cannot be used for strings or 16-bit ints, and setTextProperty
will no longer be able to use it
Xlib's
send_event
(and its usage in EWMH) has nodataSize
ordata: str
type. That's forget/change_property
. A message is always for requests / actions, data is always a 5-length list of ints, always never used with strings.self.display.send_event(destination=self.rid, event=ev, event_mask=mask)
First off, this implementation is totally new (perhaps has some mistakes, though I successfully tested it using PyWinCtl), it's intended for internal use and therefore not adapted to a general module, and third, it will be replaced by your module! Sorry if I led you to a confusion, but I was not suggesting this implementation since it's clearly unsufficient and non-exportable, but the abstract idea of having a number of very simple functions that internally complete the necessary data without the need for the user to provide it (e.g. setWmState or SetWmType, setWmHint, setWmProtocol... and whatever can be simplified this way), completed with a more complex function which inevitably needs more data to fulfill.
Regarding ewwmh's setProperty(), it's in fact a send_event, which seems to need a dataSize, as part of the event structure (or is it a name misleading, which in fact means "format"?);
def _setProperty(self, _type, data, win=None, mask=None):
"""
Send a ClientMessage event to the root window
"""
if not win:
win = self.root
if type(data) is str:
dataSize = 8
else:
data = (data+[0]*(5-len(data)))[:5]
dataSize = 32
ev = protocol.event.ClientMessage(
window=win,
client_type=self.display.get_atom(_type), data=(dataSize, data))
if not mask:
mask = (X.SubstructureRedirectMask | X.SubstructureNotifyMask)
self.root.send_event(ev, event_mask=mask)
but, in this case, data it's completed internally as well as its data size (or is it format?). So, I can invoke it in this very simple ways: self.sendMessage(CLOSE_WINDOW, [])
or self.sendMessage(WM_CHANGE_STATE, [Xlib.Xutil.IconicState])
or self.sendMessage(WM_CHANGE_STATE, [Xlib.Xutil.IconicState])
, using just two input params.
Sorry again, but I'm sure your implementation will be much better than mine. I was pasting this only in case you needed to reuse any piece of it (like using X11 directly, which costed me a lot to get python working examples of it); and to give a practical example of simple/pre-defined/standard functions vs. more general/complex ones.
There's no
display.send_event(destination)
in Xlib. There'sWindow.send_event()
, self being the destination. So, for a window to send an event to the Root Window (as needed by many EWMH methods), that window needs a reference to the root window.
Sorry, I think I'm not properly catching your comment. If you write this:
display = Xlib.display.Display()
display.send_event(
the IDE will offer to auto-complete it, and will show this overload:
Xlib.display.Display def send_event(self,
destination: int,
event: Event,
event_mask: int = ...,
propagate: bool = ...,
onerror: None = ...) -> None
This is all Xlib (well, python-xlib, I mean), right? Or am I missing something? Anyway, I was just curious, since I guess there are many ways to accomplish the same thing. In my experience, self.display.send_event(destination=root, event)
is equivalent to self.root.send_event(event)
And it's not trivial to get a root reference from an Xlib's Window: you have
Window.display
, but no reference to thesno
orscreen
you need.
Right, that's why it's better to facilitate the job to the user. Thus, root can be an optional parameter. If the user doesn't know, and passes it unfulfilled, then it can be found by "brute force". Take a look to getAllScreens() function, but in this case it would be easier, just retrieving the windows id's from each root, and comparing it with the target id:
dsp = Xlib.display.Display() # Could window.display be used here to address the proper display, just in case? or get list of displays from d = opendir("/tmp/.X11-unix")
atom: int = dsp.get_atom(WINDOW_LIST_STACKING)
for i in range(dsp.screen_count()):
try:
screen = dsp.screen(i)
root = screen.root
except:
continue
windows = root.get_full_property(atom, Xlib.X.AnyPropertyType)
for w in windows:
if w == givenID:
dsp.close()
return root
dsp.close()
return None
Without allowing
bytes
or format != 32, thissetProperty
you suggest cannot be used for strings or 16-bit ints, andsetTextProperty
will no longer be able to use it
Totally right. Again, I was not suggesting this implementation, sorry. This implementation is incomplete and adapted to the needs of PyWinCtl solely.
Hi!
I am still preparing new version 0.1, but hopefully close to launch it. It's been long overdue mainly because of a multi-monitor issue, which led me to replace PyRect with a custom module (PyWinBox) and build another custom module to control monitors (PyMonCtl). I am still trying to find the way to test that all in an actual multi-monitor macOS setup. Not sure if you received a mail that I sent you (here: github@rodrigosilva.com, but not sure if it is correct) some days ago asking for your opinion (always very sharp and useful) on building those features as separate modules or as pywinctl submodules or completely integrated within (I finally decided to separate them, but still not sure if it's the optimal approach).
Also, as you know, my intention was to remove ewmh module, but it required a lot of investigation and testing. Regarding this, I think I already managed to have a (final/acceptable/preliminary-yet-usable?) version. I also decided to encapsulate it as a submodule. The question is: are you still interested in creating your own EWMH replacement? If so, just three comments: a) please, take a look at ewmhlib submodule within PyWinCtl 'dev' branch and let me know your thoughts, b) use it at your convenience for your new ewmh module (as well as my contribution and help if you need to), and c) I would love to include your new ewmh module within the next pywinctl version (I still have work to do before launching it because of the multi-monitor issue and, apart from this, I don't care about waiting if needed).
Hey man, long time no see you! Missing a LOT our discussions!
So, as said a few weeks (months?) ago, I'm in this new company, managing a huge project, with basically zero spare time for my personal projects. Even my prodigy git-restore-mtime
has a pile of issues and reports I'm unable to handle right now.
Same goes to my ewhm
initiative: as much as I'd love to dive into it once again, if only just to just finish the API and present a working prototype, I simply can't. Yes, I got your friendly email, it was the right address, and I'm truly sorry for not answering it.
So, what all of that means? Will I be able to discuss API and collaborate on an ewhm backend? No, not in the foreseeable future (2-3 months at least, might as well extend to 6-9). Have I abandoned my still unborn project? No, absolutely not, I'm still planning on resuming it as soon as I can: the old ewhm
deserves a proper replacement so it can proudly rest in peace. Am I really sad for not collaborating with your amazing PyWinCtrl project and help shaping it so it has a compatible API when I ever come back to ewhm? Hell yeah, a lot!
Hey! So good to know you are fine! I will patiently wait in such a case. Dont' worry!!! My best wishes for you in your new project. That's the kind of projects I definitely like and are worth to "suffer": huge and complex. I'm sure you will success!
Hi!!! It's a long long time no hearing from you! I really hope you are doing well.
I just wanted to share some things with you, if you have the time, of course:
I was just wondering if you will have the time to create this new module, or if you think it is worth I upload this one meanwhile you create yours (I would really appreciate your revision in this case, if possible). As I mentioned, I am not in a hurry yet, since I still have to manage to get a f***g mac!!!!
PS: I had not checked your github profile before... 139 repos?!?!?! and 273 stars! WOW!!! Man, you're a LEGEND!!! HAHAHAHAHA!
I'm pasting here the implementation of some ewmh functions (and some others I needed) just in case you can re-use it in any way. As I mentioned in a previous issue, these functions were intended to be used by myself exclusively, so they are not suitable as they are now for a general module and therefore some ideas I was also mentioning are not reflected here. Anyway, if this can be useful in any way, much better than throwing it all away!