Skip to content

Commit

Permalink
- Improved Open Display function to timeout after 60 seconds, fixes p…
Browse files Browse the repository at this point in the history
…ossible startup failure on boot for some distros.
  • Loading branch information
rbreaves committed Feb 11, 2020
2 parents f4cef73 + ab679dd commit eac62fb
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 2 deletions.
115 changes: 115 additions & 0 deletions kintopy/kinto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env python
#
# Kinto - Python implementation of Xlib
#
# Based on code by Stephan Sokolow
# Source: https://gist.github.com/ssokolow/e7c9aae63fb7973e4d64cff969a78ae8
from contextlib import contextmanager
import Xlib
import Xlib.display

# Connect to the X server and get the root window
disp = Xlib.display.Display()
root = disp.screen().root

# Prepare the property names we use so they can be fed into X11 APIs
NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW')
NET_WM_NAME = disp.intern_atom('_NET_WM_NAME') # UTF-8
WM_NAME = disp.intern_atom('WM_NAME') # Legacy encoding
NET_WM_CLASS = disp.intern_atom('_NET_WM_CLASS') # UTF-8
WM_CLASS = disp.intern_atom('WM_CLASS')

last_seen = { 'xid': None, 'title': None }

@contextmanager
def window_obj(win_id):
"""Simplify dealing with BadWindow (make it either valid or None)"""
window_obj = None
if win_id:
try:
window_obj = disp.create_resource_object('window', win_id)
except Xlib.error.XError:
pass
yield window_obj

def get_active_window():
"""Return a (window_obj, focus_has_changed) tuple for the active window."""
win_id = root.get_full_property(NET_ACTIVE_WINDOW,Xlib.X.AnyPropertyType).value[0]

focus_changed = (win_id != last_seen['xid'])
if focus_changed:
with window_obj(last_seen['xid']) as old_win:
if old_win:
old_win.change_attributes(event_mask=Xlib.X.NoEventMask)

last_seen['xid'] = win_id
with window_obj(win_id) as new_win:
if new_win:
new_win.change_attributes(event_mask=Xlib.X.PropertyChangeMask)

return win_id, focus_changed

def _get_window_class_inner(win_obj):
for atom in (NET_WM_CLASS, WM_CLASS):
try:
window_class = win_obj.get_full_property(atom, 0)

except UnicodeDecodeError: # Apparently a Debian distro package bug
title = "<could not decode characters>"
else:
if window_class:
win_class = window_class.value.split('\x00')[1]
if isinstance(win_class, bytes):
# Apparently COMPOUND_TEXT is so arcane that this is how
# tools like xprop deal with receiving it these days
win_class = win_class.split('\x00')[1].decode('latin1', 'replace')
return win_class
else:
title = "<unnamed window>"

return "{} (XID: {})".format(title, win_obj.id)

def get_window_class(win_id):
"""Look up the window name for a given X11 window ID"""
if not win_id:
last_seen['title'] = "<no window id>"
return last_seen['title']

title_changed = False
with window_obj(win_id) as wobj:
if wobj:
win_title = _get_window_class_inner(wobj)
title_changed = (win_title != last_seen['title'])
last_seen['title'] = win_title

return last_seen['title'], title_changed

def handle_xevent(event):
# Loop through, ignoring events until we're notified of focus/title change
if event.type != Xlib.X.PropertyNotify:
return

changed = False
if event.atom == NET_ACTIVE_WINDOW:
if get_active_window()[1]:
changed = changed or get_window_class(last_seen['xid'])[1]
elif event.atom in (NET_WM_CLASS, WM_CLASS):
changed = changed or get_window_class(last_seen['xid'])[1]

if changed:
handle_change(last_seen)

def handle_change(new_state):
"""Replace this with whatever you want to actually do"""
print(new_state['title'])

if __name__ == '__main__':
# Listen for _NET_ACTIVE_WINDOW changes
root.change_attributes(event_mask=Xlib.X.PropertyChangeMask)

# Prime last_seen with whatever window was active when we started this
get_window_class(get_active_window()[0])
handle_change(last_seen)

while True: # next_event() sleeps until we get an event
handle_xevent(disp.next_event())
Binary file modified kintox11/binary/kintox11
Binary file not shown.
15 changes: 13 additions & 2 deletions kintox11/src/kintox11.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,20 @@ int strcicmp(char const *a, char const *b)
}

Display* open_display(){
int i;
Display* d = XOpenDisplay(NULL);
for (i = 0; i < 60; i++) {
if(d == NULL){
printf("fail to open X server display...\n");
}
else{
break;
}
sleep(1);
}
if(d == NULL){
printf("fail to open X server display...\n");
printf("fail to open X server display for 1 minute...\n");
printf("Kintox11 is now exiting...\n");
exit(1);
}
return d;
Expand Down Expand Up @@ -109,7 +120,7 @@ Window get_top_window(Display* d, Window start){
XFree(children);

if(xerror){
printf("fail to get top window: %d\n",w);
printf("fail to get top window: %ld\n",w);
exit(1);
}

Expand Down

0 comments on commit eac62fb

Please sign in to comment.