We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
client_focus and focus_change hooks seem to mean the same thing

# Issue description

There are two hooks with similar names: `client_focus` and `focus_change`. I can't tell what their distinction is conceptually.

We should either clarify the distinction (if there is one) or merge them.

# Qtile version

Master 55cc226

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `libqtile/hook.py`
Content:
```
1 # Copyright (c) 2009-2010 Aldo Cortesi
2 # Copyright (c) 2010 Lee McCuller
3 # Copyright (c) 2010 matt
4 # Copyright (c) 2010, 2014 dequis
5 # Copyright (c) 2010, 2012, 2014 roger
6 # Copyright (c) 2011 Florian Mounier
7 # Copyright (c) 2011 Kenji_Takahashi
8 # Copyright (c) 2011 Paul Colomiets
9 # Copyright (c) 2011 Tzbob
10 # Copyright (c) 2012-2015 Tycho Andersen
11 # Copyright (c) 2012 Craig Barnes
12 # Copyright (c) 2013 Tao Sauvage
13 # Copyright (c) 2014 Sean Vig
14 #
15 # Permission is hereby granted, free of charge, to any person obtaining a copy
16 # of this software and associated documentation files (the "Software"), to deal
17 # in the Software without restriction, including without limitation the rights
18 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 # copies of the Software, and to permit persons to whom the Software is
20 # furnished to do so, subject to the following conditions:
21 #
22 # The above copyright notice and this permission notice shall be included in
23 # all copies or substantial portions of the Software.
24 #
25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 # SOFTWARE.
32 
33 import asyncio
34 import contextlib
35 from typing import Dict, Set
36 
37 from libqtile import utils
38 from libqtile.log_utils import logger
39 
40 subscriptions = {}  # type: Dict
41 SKIPLOG = set()  # type: Set
42 
43 
44 def clear():
45     subscriptions.clear()
46 
47 
48 class Subscribe:
49     def __init__(self):
50         hooks = set([])
51         for i in dir(self):
52             if not i.startswith("_"):
53                 hooks.add(i)
54         self.hooks = hooks
55 
56     def _subscribe(self, event, func):
57         lst = subscriptions.setdefault(event, [])
58         if func not in lst:
59             lst.append(func)
60         return func
61 
62     def startup_once(self, func):
63         """Called when Qtile has started on first start
64 
65         This hook is called exactly once per session (i.e. not on each
66         ``lazy.restart()``).
67 
68         **Arguments**
69 
70         None
71         """
72         return self._subscribe("startup_once", func)
73 
74     def startup(self, func):
75         """Called when qtile is started
76 
77         **Arguments**
78 
79         None
80         """
81         return self._subscribe("startup", func)
82 
83     def startup_complete(self, func):
84         """Called when qtile is started after all resources initialized
85 
86         **Arguments**
87 
88         None
89         """
90         return self._subscribe("startup_complete", func)
91 
92     def shutdown(self, func):
93         """Called before qtile is shutdown
94 
95         **Arguments**
96 
97         None
98         """
99         return self._subscribe("shutdown", func)
100 
101     def restart(self, func):
102         """Called before qtile is restarted
103 
104         **Arguments**
105 
106         None
107         """
108         return self._subscribe("restart", func)
109 
110     def setgroup(self, func):
111         """Called when group is changed
112 
113         **Arguments**
114 
115         None
116         """
117         return self._subscribe("setgroup", func)
118 
119     def addgroup(self, func):
120         """Called when group is added
121 
122         **Arguments**
123 
124             * name of new group
125         """
126         return self._subscribe("addgroup", func)
127 
128     def delgroup(self, func):
129         """Called when group is deleted
130 
131         **Arguments**
132 
133             * name of deleted group
134         """
135         return self._subscribe("delgroup", func)
136 
137     def changegroup(self, func):
138         """Called whenever a group change occurs
139 
140         **Arguments**
141 
142         None
143         """
144         return self._subscribe("changegroup", func)
145 
146     def focus_change(self, func):
147         """Called when focus is changed
148 
149         **Arguments**
150 
151         None
152         """
153         return self._subscribe("focus_change", func)
154 
155     def float_change(self, func):
156         """Called when a change in float state is made
157 
158         **Arguments**
159 
160         None
161         """
162         return self._subscribe("float_change", func)
163 
164     def group_window_add(self, func):
165         """Called when a new window is added to a group
166 
167         **Arguments**
168 
169             * ``Group`` receiving the new window
170             * ``Window`` added to the group
171         """
172         return self._subscribe("group_window_add", func)
173 
174     def client_new(self, func):
175         """Called before Qtile starts managing a new client
176 
177         Use this hook to declare windows static, or add them to a group on
178         startup. This hook is not called for internal windows.
179 
180         **Arguments**
181 
182             * ``Window`` object
183 
184         Examples
185         --------
186 
187         ::
188 
189             @libqtile.hook.subscribe.client_new
190             def func(c):
191                 if c.name == "xterm":
192                     c.togroup("a")
193                 elif c.name == "dzen":
194                     c.cmd_static(0)
195         """
196         return self._subscribe("client_new", func)
197 
198     def client_managed(self, func):
199         """Called after Qtile starts managing a new client
200 
201         Called after a window is assigned to a group, or when a window is made
202         static.  This hook is not called for internal windows.
203 
204         **Arguments**
205 
206             * ``Window`` object of the managed window
207         """
208         return self._subscribe("client_managed", func)
209 
210     def client_killed(self, func):
211         """Called after a client has been unmanaged
212 
213         **Arguments**
214 
215             * ``Window`` object of the killed window.
216         """
217         return self._subscribe("client_killed", func)
218 
219     def client_focus(self, func):
220         """Called whenever focus changes
221 
222         **Arguments**
223 
224             * ``Window`` object of the new focus.
225         """
226         return self._subscribe("client_focus", func)
227 
228     def client_mouse_enter(self, func):
229         """Called when the mouse enters a client
230 
231         **Arguments**
232 
233             * ``Window`` of window entered
234         """
235         return self._subscribe("client_mouse_enter", func)
236 
237     def client_name_updated(self, func):
238         """Called when the client name changes
239 
240         **Arguments**
241 
242             * ``Window`` of client with updated name
243         """
244         return self._subscribe("client_name_updated", func)
245 
246     def client_urgent_hint_changed(self, func):
247         """Called when the client urgent hint changes
248 
249         **Arguments**
250 
251             * ``Window`` of client with hint change
252         """
253         return self._subscribe("client_urgent_hint_changed", func)
254 
255     def layout_change(self, func):
256         """Called on layout change
257 
258         **Arguments**
259 
260             * layout object for new layout
261             * group object on which layout is changed
262         """
263         return self._subscribe("layout_change", func)
264 
265     def net_wm_icon_change(self, func):
266         """Called on `_NET_WM_ICON` chance
267 
268         **Arguments**
269 
270             * ``Window`` of client with changed icon
271         """
272         return self._subscribe("net_wm_icon_change", func)
273 
274     def selection_notify(self, func):
275         """Called on selection notify
276 
277         **Arguments**
278 
279             * name of the selection
280             * dictionary describing selection, containing ``owner`` and
281               ``selection`` as keys
282         """
283         return self._subscribe("selection_notify", func)
284 
285     def selection_change(self, func):
286         """Called on selection change
287 
288         **Arguments**
289 
290             * name of the selection
291             * dictionary describing selection, containing ``owner`` and
292               ``selection`` as keys
293         """
294         return self._subscribe("selection_change", func)
295 
296     def screen_change(self, func):
297         """Called when the output configuration is changed (e.g. via randr in X11).
298 
299         **Arguments**
300 
301             * ``xproto.randr.ScreenChangeNotify`` event (X11) or None (Wayland).
302 
303         """
304         return self._subscribe("screen_change", func)
305 
306     def current_screen_change(self, func):
307         """Called when the current screen (i.e. the screen with focus) changes
308 
309         **Arguments**
310 
311         None
312         """
313         return self._subscribe("current_screen_change", func)
314 
315     def enter_chord(self, func):
316         """Called when key chord begins
317 
318         **Arguments**
319 
320             * name of chord(mode)
321         """
322         return self._subscribe("enter_chord", func)
323 
324     def leave_chord(self, func):
325         """Called when key chord ends
326 
327         **Arguments**
328 
329         None
330         """
331         return self._subscribe("leave_chord", func)
332 
333 
334 subscribe = Subscribe()
335 
336 
337 class Unsubscribe(Subscribe):
338     """
339     This class mirrors subscribe, except the _subscribe member has been
340     overridden to removed calls from hooks.
341     """
342     def _subscribe(self, event, func):
343         lst = subscriptions.setdefault(event, [])
344         try:
345             lst.remove(func)
346         except ValueError:
347             raise utils.QtileError(
348                 "Tried to unsubscribe a hook that was not"
349                 " currently subscribed"
350             )
351 
352 
353 unsubscribe = Unsubscribe()
354 
355 
356 def _fire_async_event(co):
357     loop = None
358     with contextlib.suppress(RuntimeError):
359         loop = asyncio.get_running_loop()
360 
361     if loop is None:
362         asyncio.run(co)
363     else:
364         asyncio.ensure_future(co)
365 
366 
367 def fire(event, *args, **kwargs):
368     if event not in subscribe.hooks:
369         raise utils.QtileError("Unknown event: %s" % event)
370     if event not in SKIPLOG:
371         logger.debug("Internal event: %s(%s, %s)", event, args, kwargs)
372     for i in subscriptions.get(event, []):
373         try:
374             if asyncio.iscoroutinefunction(i):
375                 _fire_async_event(i(*args, **kwargs))
376             elif asyncio.iscoroutine(i):
377                 _fire_async_event(i)
378             else:
379                 i(*args, **kwargs)
380         except:  # noqa: E722
381             logger.exception("Error in hook %s", event)
382
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/libqtile/hook.py b/libqtile/hook.py
--- a/libqtile/hook.py
+++ b/libqtile/hook.py
@@ -144,7 +144,8 @@
         return self._subscribe("changegroup", func)
 
     def focus_change(self, func):
-        """Called when focus is changed
+        """Called when focus is changed, including moving focus between groups or when
+        focus is lost completely
 
         **Arguments**
 
@@ -217,7 +218,7 @@
         return self._subscribe("client_killed", func)
 
     def client_focus(self, func):
-        """Called whenever focus changes
+        """Called whenever focus moves to a client window
 
         **Arguments**

{"golden_diff": "diff --git a/libqtile/hook.py b/libqtile/hook.py\n--- a/libqtile/hook.py\n+++ b/libqtile/hook.py\n@@ -144,7 +144,8 @@\n         return self._subscribe(\"changegroup\", func)\n \n     def focus_change(self, func):\n-        \"\"\"Called when focus is changed\n+        \"\"\"Called when focus is changed, including moving focus between groups or when\n+        focus is lost completely\n \n         **Arguments**\n \n@@ -217,7 +218,7 @@\n         return self._subscribe(\"client_killed\", func)\n \n     def client_focus(self, func):\n-        \"\"\"Called whenever focus changes\n+        \"\"\"Called whenever focus moves to a client window\n \n         **Arguments**\n", "issue": "client_focus and focus_change hooks seem to mean the same thing\n\r\n# Issue description\r\n\r\nThere are two hooks with similar names: `client_focus` and `focus_change`. I can't tell what their distinction is conceptually.\r\n\r\nWe should either clarify the distinction (if there is one) or merge them.\r\n\r\n# Qtile version\r\n\r\nMaster 55cc226\n", "before_files": [{"content": "# Copyright (c) 2009-2010 Aldo Cortesi\n# Copyright (c) 2010 Lee McCuller\n# Copyright (c) 2010 matt\n# Copyright (c) 2010, 2014 dequis\n# Copyright (c) 2010, 2012, 2014 roger\n# Copyright (c) 2011 Florian Mounier\n# Copyright (c) 2011 Kenji_Takahashi\n# Copyright (c) 2011 Paul Colomiets\n# Copyright (c) 2011 Tzbob\n# Copyright (c) 2012-2015 Tycho Andersen\n# Copyright (c) 2012 Craig Barnes\n# Copyright (c) 2013 Tao Sauvage\n# Copyright (c) 2014 Sean Vig\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\nimport asyncio\nimport contextlib\nfrom typing import Dict, Set\n\nfrom libqtile import utils\nfrom libqtile.log_utils import logger\n\nsubscriptions = {}  # type: Dict\nSKIPLOG = set()  # type: Set\n\n\ndef clear():\n    subscriptions.clear()\n\n\nclass Subscribe:\n    def __init__(self):\n        hooks = set([])\n        for i in dir(self):\n            if not i.startswith(\"_\"):\n                hooks.add(i)\n        self.hooks = hooks\n\n    def _subscribe(self, event, func):\n        lst = subscriptions.setdefault(event, [])\n        if func not in lst:\n            lst.append(func)\n        return func\n\n    def startup_once(self, func):\n        \"\"\"Called when Qtile has started on first start\n\n        This hook is called exactly once per session (i.e. not on each\n        ``lazy.restart()``).\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"startup_once\", func)\n\n    def startup(self, func):\n        \"\"\"Called when qtile is started\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"startup\", func)\n\n    def startup_complete(self, func):\n        \"\"\"Called when qtile is started after all resources initialized\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"startup_complete\", func)\n\n    def shutdown(self, func):\n        \"\"\"Called before qtile is shutdown\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"shutdown\", func)\n\n    def restart(self, func):\n        \"\"\"Called before qtile is restarted\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"restart\", func)\n\n    def setgroup(self, func):\n        \"\"\"Called when group is changed\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"setgroup\", func)\n\n    def addgroup(self, func):\n        \"\"\"Called when group is added\n\n        **Arguments**\n\n            * name of new group\n        \"\"\"\n        return self._subscribe(\"addgroup\", func)\n\n    def delgroup(self, func):\n        \"\"\"Called when group is deleted\n\n        **Arguments**\n\n            * name of deleted group\n        \"\"\"\n        return self._subscribe(\"delgroup\", func)\n\n    def changegroup(self, func):\n        \"\"\"Called whenever a group change occurs\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"changegroup\", func)\n\n    def focus_change(self, func):\n        \"\"\"Called when focus is changed\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"focus_change\", func)\n\n    def float_change(self, func):\n        \"\"\"Called when a change in float state is made\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"float_change\", func)\n\n    def group_window_add(self, func):\n        \"\"\"Called when a new window is added to a group\n\n        **Arguments**\n\n            * ``Group`` receiving the new window\n            * ``Window`` added to the group\n        \"\"\"\n        return self._subscribe(\"group_window_add\", func)\n\n    def client_new(self, func):\n        \"\"\"Called before Qtile starts managing a new client\n\n        Use this hook to declare windows static, or add them to a group on\n        startup. This hook is not called for internal windows.\n\n        **Arguments**\n\n            * ``Window`` object\n\n        Examples\n        --------\n\n        ::\n\n            @libqtile.hook.subscribe.client_new\n            def func(c):\n                if c.name == \"xterm\":\n                    c.togroup(\"a\")\n                elif c.name == \"dzen\":\n                    c.cmd_static(0)\n        \"\"\"\n        return self._subscribe(\"client_new\", func)\n\n    def client_managed(self, func):\n        \"\"\"Called after Qtile starts managing a new client\n\n        Called after a window is assigned to a group, or when a window is made\n        static.  This hook is not called for internal windows.\n\n        **Arguments**\n\n            * ``Window`` object of the managed window\n        \"\"\"\n        return self._subscribe(\"client_managed\", func)\n\n    def client_killed(self, func):\n        \"\"\"Called after a client has been unmanaged\n\n        **Arguments**\n\n            * ``Window`` object of the killed window.\n        \"\"\"\n        return self._subscribe(\"client_killed\", func)\n\n    def client_focus(self, func):\n        \"\"\"Called whenever focus changes\n\n        **Arguments**\n\n            * ``Window`` object of the new focus.\n        \"\"\"\n        return self._subscribe(\"client_focus\", func)\n\n    def client_mouse_enter(self, func):\n        \"\"\"Called when the mouse enters a client\n\n        **Arguments**\n\n            * ``Window`` of window entered\n        \"\"\"\n        return self._subscribe(\"client_mouse_enter\", func)\n\n    def client_name_updated(self, func):\n        \"\"\"Called when the client name changes\n\n        **Arguments**\n\n            * ``Window`` of client with updated name\n        \"\"\"\n        return self._subscribe(\"client_name_updated\", func)\n\n    def client_urgent_hint_changed(self, func):\n        \"\"\"Called when the client urgent hint changes\n\n        **Arguments**\n\n            * ``Window`` of client with hint change\n        \"\"\"\n        return self._subscribe(\"client_urgent_hint_changed\", func)\n\n    def layout_change(self, func):\n        \"\"\"Called on layout change\n\n        **Arguments**\n\n            * layout object for new layout\n            * group object on which layout is changed\n        \"\"\"\n        return self._subscribe(\"layout_change\", func)\n\n    def net_wm_icon_change(self, func):\n        \"\"\"Called on `_NET_WM_ICON` chance\n\n        **Arguments**\n\n            * ``Window`` of client with changed icon\n        \"\"\"\n        return self._subscribe(\"net_wm_icon_change\", func)\n\n    def selection_notify(self, func):\n        \"\"\"Called on selection notify\n\n        **Arguments**\n\n            * name of the selection\n            * dictionary describing selection, containing ``owner`` and\n              ``selection`` as keys\n        \"\"\"\n        return self._subscribe(\"selection_notify\", func)\n\n    def selection_change(self, func):\n        \"\"\"Called on selection change\n\n        **Arguments**\n\n            * name of the selection\n            * dictionary describing selection, containing ``owner`` and\n              ``selection`` as keys\n        \"\"\"\n        return self._subscribe(\"selection_change\", func)\n\n    def screen_change(self, func):\n        \"\"\"Called when the output configuration is changed (e.g. via randr in X11).\n\n        **Arguments**\n\n            * ``xproto.randr.ScreenChangeNotify`` event (X11) or None (Wayland).\n\n        \"\"\"\n        return self._subscribe(\"screen_change\", func)\n\n    def current_screen_change(self, func):\n        \"\"\"Called when the current screen (i.e. the screen with focus) changes\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"current_screen_change\", func)\n\n    def enter_chord(self, func):\n        \"\"\"Called when key chord begins\n\n        **Arguments**\n\n            * name of chord(mode)\n        \"\"\"\n        return self._subscribe(\"enter_chord\", func)\n\n    def leave_chord(self, func):\n        \"\"\"Called when key chord ends\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"leave_chord\", func)\n\n\nsubscribe = Subscribe()\n\n\nclass Unsubscribe(Subscribe):\n    \"\"\"\n    This class mirrors subscribe, except the _subscribe member has been\n    overridden to removed calls from hooks.\n    \"\"\"\n    def _subscribe(self, event, func):\n        lst = subscriptions.setdefault(event, [])\n        try:\n            lst.remove(func)\n        except ValueError:\n            raise utils.QtileError(\n                \"Tried to unsubscribe a hook that was not\"\n                \" currently subscribed\"\n            )\n\n\nunsubscribe = Unsubscribe()\n\n\ndef _fire_async_event(co):\n    loop = None\n    with contextlib.suppress(RuntimeError):\n        loop = asyncio.get_running_loop()\n\n    if loop is None:\n        asyncio.run(co)\n    else:\n        asyncio.ensure_future(co)\n\n\ndef fire(event, *args, **kwargs):\n    if event not in subscribe.hooks:\n        raise utils.QtileError(\"Unknown event: %s\" % event)\n    if event not in SKIPLOG:\n        logger.debug(\"Internal event: %s(%s, %s)\", event, args, kwargs)\n    for i in subscriptions.get(event, []):\n        try:\n            if asyncio.iscoroutinefunction(i):\n                _fire_async_event(i(*args, **kwargs))\n            elif asyncio.iscoroutine(i):\n                _fire_async_event(i)\n            else:\n                i(*args, **kwargs)\n        except:  # noqa: E722\n            logger.exception(\"Error in hook %s\", event)\n", "path": "libqtile/hook.py"}], "after_files": [{"content": "# Copyright (c) 2009-2010 Aldo Cortesi\n# Copyright (c) 2010 Lee McCuller\n# Copyright (c) 2010 matt\n# Copyright (c) 2010, 2014 dequis\n# Copyright (c) 2010, 2012, 2014 roger\n# Copyright (c) 2011 Florian Mounier\n# Copyright (c) 2011 Kenji_Takahashi\n# Copyright (c) 2011 Paul Colomiets\n# Copyright (c) 2011 Tzbob\n# Copyright (c) 2012-2015 Tycho Andersen\n# Copyright (c) 2012 Craig Barnes\n# Copyright (c) 2013 Tao Sauvage\n# Copyright (c) 2014 Sean Vig\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\nimport asyncio\nimport contextlib\nfrom typing import Dict, Set\n\nfrom libqtile import utils\nfrom libqtile.log_utils import logger\n\nsubscriptions = {}  # type: Dict\nSKIPLOG = set()  # type: Set\n\n\ndef clear():\n    subscriptions.clear()\n\n\nclass Subscribe:\n    def __init__(self):\n        hooks = set([])\n        for i in dir(self):\n            if not i.startswith(\"_\"):\n                hooks.add(i)\n        self.hooks = hooks\n\n    def _subscribe(self, event, func):\n        lst = subscriptions.setdefault(event, [])\n        if func not in lst:\n            lst.append(func)\n        return func\n\n    def startup_once(self, func):\n        \"\"\"Called when Qtile has started on first start\n\n        This hook is called exactly once per session (i.e. not on each\n        ``lazy.restart()``).\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"startup_once\", func)\n\n    def startup(self, func):\n        \"\"\"Called when qtile is started\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"startup\", func)\n\n    def startup_complete(self, func):\n        \"\"\"Called when qtile is started after all resources initialized\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"startup_complete\", func)\n\n    def shutdown(self, func):\n        \"\"\"Called before qtile is shutdown\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"shutdown\", func)\n\n    def restart(self, func):\n        \"\"\"Called before qtile is restarted\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"restart\", func)\n\n    def setgroup(self, func):\n        \"\"\"Called when group is changed\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"setgroup\", func)\n\n    def addgroup(self, func):\n        \"\"\"Called when group is added\n\n        **Arguments**\n\n            * name of new group\n        \"\"\"\n        return self._subscribe(\"addgroup\", func)\n\n    def delgroup(self, func):\n        \"\"\"Called when group is deleted\n\n        **Arguments**\n\n            * name of deleted group\n        \"\"\"\n        return self._subscribe(\"delgroup\", func)\n\n    def changegroup(self, func):\n        \"\"\"Called whenever a group change occurs\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"changegroup\", func)\n\n    def focus_change(self, func):\n        \"\"\"Called when focus is changed, including moving focus between groups or when\n        focus is lost completely\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"focus_change\", func)\n\n    def float_change(self, func):\n        \"\"\"Called when a change in float state is made\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"float_change\", func)\n\n    def group_window_add(self, func):\n        \"\"\"Called when a new window is added to a group\n\n        **Arguments**\n\n            * ``Group`` receiving the new window\n            * ``Window`` added to the group\n        \"\"\"\n        return self._subscribe(\"group_window_add\", func)\n\n    def client_new(self, func):\n        \"\"\"Called before Qtile starts managing a new client\n\n        Use this hook to declare windows static, or add them to a group on\n        startup. This hook is not called for internal windows.\n\n        **Arguments**\n\n            * ``Window`` object\n\n        Examples\n        --------\n\n        ::\n\n            @libqtile.hook.subscribe.client_new\n            def func(c):\n                if c.name == \"xterm\":\n                    c.togroup(\"a\")\n                elif c.name == \"dzen\":\n                    c.cmd_static(0)\n        \"\"\"\n        return self._subscribe(\"client_new\", func)\n\n    def client_managed(self, func):\n        \"\"\"Called after Qtile starts managing a new client\n\n        Called after a window is assigned to a group, or when a window is made\n        static.  This hook is not called for internal windows.\n\n        **Arguments**\n\n            * ``Window`` object of the managed window\n        \"\"\"\n        return self._subscribe(\"client_managed\", func)\n\n    def client_killed(self, func):\n        \"\"\"Called after a client has been unmanaged\n\n        **Arguments**\n\n            * ``Window`` object of the killed window.\n        \"\"\"\n        return self._subscribe(\"client_killed\", func)\n\n    def client_focus(self, func):\n        \"\"\"Called whenever focus moves to a client window\n\n        **Arguments**\n\n            * ``Window`` object of the new focus.\n        \"\"\"\n        return self._subscribe(\"client_focus\", func)\n\n    def client_mouse_enter(self, func):\n        \"\"\"Called when the mouse enters a client\n\n        **Arguments**\n\n            * ``Window`` of window entered\n        \"\"\"\n        return self._subscribe(\"client_mouse_enter\", func)\n\n    def client_name_updated(self, func):\n        \"\"\"Called when the client name changes\n\n        **Arguments**\n\n            * ``Window`` of client with updated name\n        \"\"\"\n        return self._subscribe(\"client_name_updated\", func)\n\n    def client_urgent_hint_changed(self, func):\n        \"\"\"Called when the client urgent hint changes\n\n        **Arguments**\n\n            * ``Window`` of client with hint change\n        \"\"\"\n        return self._subscribe(\"client_urgent_hint_changed\", func)\n\n    def layout_change(self, func):\n        \"\"\"Called on layout change\n\n        **Arguments**\n\n            * layout object for new layout\n            * group object on which layout is changed\n        \"\"\"\n        return self._subscribe(\"layout_change\", func)\n\n    def net_wm_icon_change(self, func):\n        \"\"\"Called on `_NET_WM_ICON` chance\n\n        **Arguments**\n\n            * ``Window`` of client with changed icon\n        \"\"\"\n        return self._subscribe(\"net_wm_icon_change\", func)\n\n    def selection_notify(self, func):\n        \"\"\"Called on selection notify\n\n        **Arguments**\n\n            * name of the selection\n            * dictionary describing selection, containing ``owner`` and\n              ``selection`` as keys\n        \"\"\"\n        return self._subscribe(\"selection_notify\", func)\n\n    def selection_change(self, func):\n        \"\"\"Called on selection change\n\n        **Arguments**\n\n            * name of the selection\n            * dictionary describing selection, containing ``owner`` and\n              ``selection`` as keys\n        \"\"\"\n        return self._subscribe(\"selection_change\", func)\n\n    def screen_change(self, func):\n        \"\"\"Called when the output configuration is changed (e.g. via randr in X11).\n\n        **Arguments**\n\n            * ``xproto.randr.ScreenChangeNotify`` event (X11) or None (Wayland).\n\n        \"\"\"\n        return self._subscribe(\"screen_change\", func)\n\n    def current_screen_change(self, func):\n        \"\"\"Called when the current screen (i.e. the screen with focus) changes\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"current_screen_change\", func)\n\n    def enter_chord(self, func):\n        \"\"\"Called when key chord begins\n\n        **Arguments**\n\n            * name of chord(mode)\n        \"\"\"\n        return self._subscribe(\"enter_chord\", func)\n\n    def leave_chord(self, func):\n        \"\"\"Called when key chord ends\n\n        **Arguments**\n\n        None\n        \"\"\"\n        return self._subscribe(\"leave_chord\", func)\n\n\nsubscribe = Subscribe()\n\n\nclass Unsubscribe(Subscribe):\n    \"\"\"\n    This class mirrors subscribe, except the _subscribe member has been\n    overridden to removed calls from hooks.\n    \"\"\"\n    def _subscribe(self, event, func):\n        lst = subscriptions.setdefault(event, [])\n        try:\n            lst.remove(func)\n        except ValueError:\n            raise utils.QtileError(\n                \"Tried to unsubscribe a hook that was not\"\n                \" currently subscribed\"\n            )\n\n\nunsubscribe = Unsubscribe()\n\n\ndef _fire_async_event(co):\n    loop = None\n    with contextlib.suppress(RuntimeError):\n        loop = asyncio.get_running_loop()\n\n    if loop is None:\n        asyncio.run(co)\n    else:\n        asyncio.ensure_future(co)\n\n\ndef fire(event, *args, **kwargs):\n    if event not in subscribe.hooks:\n        raise utils.QtileError(\"Unknown event: %s\" % event)\n    if event not in SKIPLOG:\n        logger.debug(\"Internal event: %s(%s, %s)\", event, args, kwargs)\n    for i in subscriptions.get(event, []):\n        try:\n            if asyncio.iscoroutinefunction(i):\n                _fire_async_event(i(*args, **kwargs))\n            elif asyncio.iscoroutine(i):\n                _fire_async_event(i)\n            else:\n                i(*args, **kwargs)\n        except:  # noqa: E722\n            logger.exception(\"Error in hook %s\", event)\n", "path": "libqtile/hook.py"}]}