Skip to content

Commit b1de743

Browse files
author
Tony Crisci
authored
Merge pull request #144 from sergey-trotsyuk/example/focus-app-and-window-fixes
i3-focus example fixes
2 parents ef213c6 + 70d5392 commit b1de743

File tree

6 files changed

+81
-21
lines changed

6 files changed

+81
-21
lines changed

examples/i3-focus/focus-current-app-window.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
parser = ArgumentParser(prog='i3-app-focus.py',
1111
description='''
12-
i3-app-focus.py is dmenu-based script for creating dynamic window switcher for current app.
12+
i3-app-focus.py is dmenu-based script for creating dynamic app switcher.
1313
''',
1414
epilog='''
1515
Additional arguments found after "--" will be passed to dmenu.

examples/i3-focus/focus-window.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env python3
2+
3+
import re
4+
from argparse import ArgumentParser
5+
from functools import reduce
6+
import i3ipc
7+
from tools import App, Lists, Menu, Sockets
8+
9+
10+
parser = ArgumentParser(prog='i3-app-focus.py',
11+
description='''
12+
i3-app-focus.py is dmenu-based script for creating dynamic app switcher.
13+
''',
14+
epilog='''
15+
Additional arguments found after "--" will be passed to dmenu.
16+
''')
17+
parser.add_argument('--menu', default='dmenu', help='The menu command to run (ex: --menu=rofi)')
18+
parser.add_argument('--socket-file', default='/tmp/i3-app-focus.socket', help='Socket file path')
19+
(args, menu_args) = parser.parse_known_args()
20+
21+
22+
sockets = Sockets(args.socket_file)
23+
containers_info = sockets.get_containers_history()
24+
25+
i3 = i3ipc.Connection()
26+
menu = Menu(i3, args.menu, menu_args)
27+
menu.show_menu_container_info(containers_info)

examples/i3-focus/history-server.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
#!/usr/bin/env python3
22

3-
# i3 get_tree does not contain information about focus throw all workspaces,
4-
# so scripts those use it can sort windows only with workspace groupping.
5-
# This server accumulates window focus history and does not pay attention on workspaces.
6-
73
import os
84
import socket
95
import selectors
@@ -12,6 +8,7 @@
128
from argparse import ArgumentParser
139
import i3ipc
1410

11+
1512
MAX_WIN_HISTORY = 15
1613

1714
parser = ArgumentParser(prog='i3-app-focus.py',
@@ -39,11 +36,12 @@ def run(self):
3936
t.start()
4037

4138
def _on_window_focus(self, i3conn, event):
42-
if not self._is_window(event.container):
39+
window_id = event.container.id
40+
con = self.i3.get_tree().find_by_id(window_id)
41+
if not self._is_window(con):
4342
return
4443

4544
with self.window_list_lock:
46-
window_id = event.container.id
4745
if window_id in self.window_list:
4846
self.window_list.remove(window_id)
4947
self.window_list.insert(0, window_id)
@@ -69,6 +67,7 @@ def accept(sock):
6967
"window": con.window,
7068
"window_title": con.window_title,
7169
"window_class": con.window_class,
70+
"window_role": con.window_role,
7271
"focused": con.focused
7372
})
7473

examples/i3-focus/tools/app.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,30 @@ def get_window_class(self):
1212
return self._container_info["window_class"]
1313

1414
def get_title(self):
15-
# i3 = i3ipc.Connection()
16-
# print("\n\n")
17-
# print(vars(i3.get_tree().find_by_id(self._container_info["id"])))
15+
window_class = self._container_info["window_class"]
16+
method_name = '_get_title_' + window_class.replace('-', '_').lower()
17+
method = getattr(self, method_name, self._get_title_based_on_class)
18+
return method()
19+
20+
def _get_title_based_on_class(self):
21+
return self._container_info["window_class"].replace('-', ' ').title()
22+
23+
def _get_title_based_on_title(self):
1824
return re.match(r"^.*?\s*(?P<title>[^-—]+)$", self._container_info["window_title"]).group("title")
25+
26+
# App specific functions
27+
28+
def _get_title_google_chrome(self):
29+
is_browser_in_app_mode = self._container_info["window_role"] == "pop-up"
30+
if is_browser_in_app_mode:
31+
return self._get_title_based_on_title() + ' (Chrome)'
32+
33+
return self._get_title_based_on_class()
34+
35+
def _get_title_st_256color(self):
36+
title = self._get_title_based_on_title()
37+
38+
if self._container_info["window_title"] != "Simple Terminal":
39+
return title + ' (ST)'
40+
41+
return title

examples/i3-focus/tools/lists.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,11 @@ def find_all_by_focused_app(infos):
2121

2222
focused_app = App(focused_info)
2323

24-
focused_app_windows_by_class = list(filter(lambda i: i["window_class"] == focused_app.get_window_class(), infos))
24+
focused_app_windows_by_class = list(filter(lambda i: App(i).get_title() == focused_app.get_title(), infos))
2525
return focused_app_windows_by_class
2626

2727
@staticmethod
2828
def find_app_by_title(title, apps):
2929
for a in apps:
3030
if a.get_title() == title:
3131
return a
32-
33-
@staticmethod
34-
def find_container_info_by_title(title, infos):
35-
for i in infos:
36-
if i["window_title"] == title:
37-
return i

examples/i3-focus/tools/menu.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from collections import deque
22
from subprocess import check_output
3-
from . import Lists
3+
from . import Lists, App
44

55
class Menu:
66
def __init__(self, i3, menu, menu_args):
@@ -23,9 +23,26 @@ def show_menu_app(self, apps):
2323
con.command('focus');
2424

2525
def show_menu_container_info(self, containers_info):
26-
titles = list(map(lambda i: i["window_title"], containers_info))
27-
selected_title = self.show_menu(titles)
28-
selected_info = Lists.find_container_info_by_title(selected_title, containers_info)
26+
titles = self._get_titles_with_app_prefix(containers_info)
27+
titles_with_suffix = self._add_uniqu_suffix(titles)
28+
infos_by_title = dict(zip(titles_with_suffix, containers_info))
29+
selected_title = self.show_menu(titles_with_suffix)
30+
selected_info = infos_by_title[selected_title]
2931
tree = self._i3.get_tree()
3032
con = tree.find_by_id(selected_info["id"])
3133
con.command('focus');
34+
35+
def _get_titles_with_app_prefix(self, containers_info):
36+
return list(map(lambda i: App(i).get_title() + ': ' + i["window_title"], containers_info))
37+
38+
def _add_uniqu_suffix(self, titles):
39+
counters = dict()
40+
titles_with_suffix = []
41+
for title in titles:
42+
counters[title] = counters[title] + 1 if title in counters else 1
43+
if counters[title] > 1:
44+
title = f'{title} ({counters[title]})'
45+
46+
titles_with_suffix.append(title)
47+
48+
return titles_with_suffix

0 commit comments

Comments
 (0)