Skip to content

Commit

Permalink
[BUGFIX] --leave-fullscreen
Browse files Browse the repository at this point in the history
 - `--leave-fullscreen` doesn't work if no workspace has been provided;
 closes #30
 - some minor code cleanup
  • Loading branch information
open-dynaMIX committed Jan 18, 2019
1 parent 914b2bd commit 8079901
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 60 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# v2.2.1

# Fixes
- `--leave-fullscreen` doesn't work if no workspace has been provided #30


# v2.2.0

# Features
Expand Down
37 changes: 19 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,25 @@ A run-or-raise-application-launcher for [i3 window manager](https://i3wm.org/).

## Features

- If a provided application is running, focus it's window, otherwise
run it
- Provide a regex for window class, instance and/or title to compare
with running windows
- Optionally enable case-insensitive comparison
- Optionally provide a workspace to use for raising and running
- Optionally provide an initial workspace to run the application
- Optionally use the scratchpad for raising and running
- Optionally provide a con_mark for raising and running
- workspace_auto_back_and_forth (if enabled) remains functional
- Optionally cycle through matching windows (this will break
workspace_auto_back_and_forth if more than one window matches
the given properties)
- Created windows will always be moved to the expected workspace. This
fixes the behaviour of applications that don't implement
startup-notifications. By default this works for windows created
within 2 seconds. The timeout is configurable with
`-l/--event-time-limit`
- If a provided application is running, focus it's window, otherwise
run it
- Provide a regex for window class, instance and/or title to compare
with running windows
- Optionally enable case-insensitive comparison
- Optionally provide a workspace to use for raising and running
- Optionally provide an initial workspace to run the application
- Optionally use the scratchpad for raising and running
- Optionally provide a con_mark for raising and running
- workspace_auto_back_and_forth (if enabled) remains functional
- Optionally cycle through matching windows (this will break
workspace_auto_back_and_forth if more than one window matches
the given properties)
- Optionally leave fullscreen on target workspace
- Created windows will always be moved to the expected workspace. This
fixes the behaviour of applications that don't implement
startup-notifications. By default this works for windows created
within 2 seconds. The timeout is configurable with
`-l/--event-time-limit`

## Installation

Expand Down
86 changes: 45 additions & 41 deletions raiseorlaunch/raiseorlaunch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

__title__ = 'raiseorlaunch'
__description__ = 'A run-or-raise-application-launcher for i3 window manager.'
__version__ = '2.2.0'
__version__ = '2.2.1'
__license__ = 'MIT'
__author__ = 'Fabio Rämi'

Expand Down Expand Up @@ -82,18 +82,15 @@ def __init__(self,
self.wm_instance = wm_instance
self.wm_title = wm_title
self.workspace = workspace
self.target_workspace = (
target_workspace if target_workspace else workspace)
self.target_workspace = target_workspace or workspace
self.scratch = scratch
self.con_mark = con_mark
self.ignore_case = ignore_case
self.event_time_limit = event_time_limit
self.cycle = cycle
self.leave_fullscreen = leave_fullscreen

self.regex_flags = []
if self.ignore_case:
self.regex_flags.append(re.IGNORECASE)
self.regex_flags = [re.IGNORECASE] if self.ignore_case else []

self._check_args()

Expand Down Expand Up @@ -162,9 +159,8 @@ def _compare_running(self, window):
for (pattern, value) in [(self.wm_class, window.window_class),
(self.wm_instance, window.window_instance),
(self.wm_title, window.name)]:
if pattern:
if not self._match_regex(pattern, value):
return False
if pattern and not self._match_regex(pattern, value):
return False

logger.debug('Window match: {}'.format(self._log_format_con(window)))
return True
Expand Down Expand Up @@ -317,16 +313,48 @@ def move_con_to_workspace_by_name(window, workspace):
logger.debug('Moving window to workspace: {}'.format(workspace))
window.command('move container to workspace {}'.format(workspace))

def leave_fullscreen_on_workspace(self, workspace_name, exceptions=None):
"""
Make sure no application is in fullscreen mode on provided workspace.
Args:
workspace_name: str
exceptions: list of Con()
Returns:
None
"""
exceptions = exceptions if exceptions else []
cons_on_ws = self.tree.find_named(
'^{}$'.format(workspace_name)
)
cons = cons_on_ws[0].find_fullscreen() if cons_on_ws else []
for con in cons:
if con.type == 'workspace' or con in exceptions:
continue
logger.debug(
'Leaving fullscreen for con: {}'.format(
self._log_format_con(con)
)
)
con.command('fullscreen')

def _choose_if_multiple(self, running):
"""
If multiple windows are found, determine which one to raise.
If init_workspace is set, prefer a window on that workspace,
otherwise use the first in the tree.
Args:
running: list of Con()
Returns:
Instance of Con().
"""
if len(running) == 1:
return running[0]

window = running[0]
if self.target_workspace:
multi_msg = ('Found multiple windows that match the '
Expand All @@ -350,16 +378,16 @@ def _handle_running(self, running):
Args:
running: List of Con() instances.
"""
# there is no need to do anything if self.leave_fullscreen is True,
# because focussing the window will take care of that.

if self.cycle and len(running) > 1:
for w in running:
if w.focused:
self._handle_running_cycle(running)
return

if len(running) > 1:
window = self._choose_if_multiple(running)
else:
window = running[0]
window = self._choose_if_multiple(running)

logger.debug('Application is running on workspace "{}": {}'
.format(window.workspace().name,
Expand Down Expand Up @@ -438,7 +466,8 @@ def _handle_not_running(self):
self.switch_to_workspace_by_name(self.target_workspace)

if self.leave_fullscreen:
self.leave_fullscreen_on_workspace(self.target_workspace)
self.leave_fullscreen_on_workspace(
self.target_workspace or self.current_ws.name)

self.i3.on("window::new", self._callback_new_window)
self.run_command()
Expand All @@ -461,40 +490,15 @@ def _callback_new_window(self, connection, event):
self.show_scratch(window)
if self.con_mark:
self.set_con_mark(window)
if self.target_workspace:
target_ws = self.target_workspace
else:
target_ws = self.current_ws.name

target_ws = self.target_workspace or self.current_ws.name

# This is necessary, because window.workspace() returns None
w = connection.get_tree().find_by_id(window.id)

if not w.workspace().name == target_ws:
self.move_con_to_workspace_by_name(w, target_ws)

def leave_fullscreen_on_workspace(self, workspace_name, exceptions=None):
"""
Make sure no application is in fullscreen mode on provided workspace.
:param workspace_name: str
:param exceptions: list of Con()
:return: None
"""
exceptions = exceptions if exceptions else []
cons_on_ws = self.tree.find_named(
'^{}$'.format(workspace_name)
)
cons = cons_on_ws[0].find_fullscreen() if cons_on_ws else []
for con in cons:
if con.type == 'workspace' or con in exceptions:
continue
logger.debug(
'Leaving fullscreen for con: {}'.format(
self._log_format_con(con)
)
)
con.command('fullscreen')

def run(self):
"""
Search for running window that matches provided properties
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

setup(
name='raiseorlaunch',
version='2.2.0',
version='2.2.1',
description='A run-or-raise-application-launcher for i3 window manager.',
long_description=long_description,
long_description_content_type="text/markdown",
Expand Down

0 comments on commit 8079901

Please sign in to comment.