def compute_local_numbers(monitor_workspaces: List[i3ipc.Con], all_workspaces: List[i3ipc.Con], renumber_workspaces: bool) -> List[int]: monitor_workspace_ids = {ws.id for ws in monitor_workspaces} other_monitors_workspaces = [ ws for ws in all_workspaces if ws.id not in monitor_workspace_ids ] used_local_numbers = get_used_local_numbers(other_monitors_workspaces) logger.debug('Local numbers used by group in other monitors: %s', used_local_numbers) if renumber_workspaces: return get_lowest_free_local_numbers(len(monitor_workspaces), used_local_numbers) if used_local_numbers: last_used_local_number = max(used_local_numbers) else: last_used_local_number = 0 local_numbers = [] for workspace in monitor_workspaces: ws_metadata = parse_name(workspace.name) local_number = ws_metadata.local_number if local_number is None or (local_number in used_local_numbers): local_number = last_used_local_number + 1 last_used_local_number += 1 local_numbers.append(local_number) return local_numbers
def focus_workspace_number(self, group_context, target_local_number: int) -> None: target_workspace_name, _ = self._get_workspace_by_local_number( group=self._get_group_from_context(group_context), local_number=target_local_number) logger.debug('Derived workspace name: "%s"', target_workspace_name) self.i3_proxy.focus_workspace(target_workspace_name)
def organize_workspace_groups(self, workspace_groups: OrderedWorkspaceGroups, monitor_name: Optional[str] = None) -> None: if monitor_name is None: monitor_name = self.i3_proxy.get_focused_monitor_name() monitor_index = self.i3_proxy.get_monitor_index(monitor_name) group_to_all_workspaces = ws_names.get_group_to_workspaces( self.get_tree().workspaces()) for group_index, (group, workspaces) in enumerate(workspace_groups): logger.debug('Organizing workspace group: "%s" in monitor "%s"', group, monitor_name) local_numbers = ws_names.compute_local_numbers( workspaces, group_to_all_workspaces.get(group, []), self.config['renumber_workspaces']) for workspace, local_number in zip(workspaces, local_numbers): ws_metadata = ws_names.parse_name(workspace.name) ws_metadata.group = group ws_metadata.local_number = local_number ws_metadata.global_number = ws_names.compute_global_number( monitor_index, group_index, local_number) dynamic_name = '' # Add window icons if needed. if self.config['icons']['enable'] and ( self.config['icons']['enable_all_groups'] or group_index == 0): dynamic_name = self.icons_resolver.get_workspace_icons( workspace) ws_metadata.dynamic_name = dynamic_name new_name = ws_names.create_name(ws_metadata) self.i3_proxy.rename_workspace(workspace.name, new_name) workspace.name = new_name
def get_group_to_workspaces(workspaces: List[i3ipc.Con]) -> GroupToWorkspaces: group_to_workspaces = collections.OrderedDict() for workspace in workspaces: ws_metadata = parse_name(workspace.name) group = ws_metadata.group logger.debug('Workspace %s parsed as: %s', workspace.name, ws_metadata) if group not in group_to_workspaces: group_to_workspaces[group] = [] group_to_workspaces[group].append(workspace) return group_to_workspaces
def switch_active_group(self, target_group: str, focused_monitor_only: bool) -> None: focused_monitor_name = self.i3_proxy.get_focused_monitor_name() monitor_to_workspaces = self.i3_proxy.get_monitor_to_workspaces() for monitor, workspaces in monitor_to_workspaces.items(): group_exists = (target_group in ws_names.get_group_to_workspaces(workspaces)) if monitor == focused_monitor_name: logger.debug('Switching active group in focused monitor "%s"', monitor) elif not focused_monitor_only and group_exists: logger.debug( 'Non focused monitor %s has workspaces in the group "%s", ' 'switching to it.', monitor, target_group) else: continue self.switch_monitor_active_group(monitor, target_group) # NOTE: We only switch focus to the new workspace after renaming all the # workspaces in all monitors and groups. Otherwise, if the previously # focused workspace was renamed, i3's `workspace back_and_forth` will # switch focus to a non-existant workspace name. focused_group = ws_names.get_group( self.get_tree().find_focused().workspace()) # The target group is already focused, no need to do anything. if focused_group == target_group: return group_to_monitor_workspaces = ws_names.get_group_to_workspaces( monitor_to_workspaces[focused_monitor_name]) if target_group in group_to_monitor_workspaces: workspace_name = group_to_monitor_workspaces[target_group][0].name # The focused monitor doesn't have any workspaces in the target group, # so create one. else: workspace_name = self._create_new_active_group_workspace_name( focused_monitor_name, target_group) self.i3_proxy.focus_workspace(workspace_name, auto_back_and_forth=False)