Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sway workspaces #191

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions nwg_panel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1230,10 +1230,6 @@ def edit_sway_taskbar(self, *args):
self.ckb_show_layout.set_label(voc["show-layout"])
self.ckb_show_layout.set_active(settings["show-layout"])

self.ckb_hide_empty = builder.get_object("hide-empty")
self.ckb_hide_empty.set_label(voc["hide-empty"])
self.ckb_hide_empty.set_active(settings["hide-empty"])

self.workspace_buttons = builder.get_object("workspace-buttons")
self.workspace_buttons.set_label(voc["workspaces-as-buttons"])
self.workspace_buttons.set_active(settings["workspace-buttons"])
Expand Down Expand Up @@ -1288,7 +1284,6 @@ def update_sway_taskbar(self):
settings["show-app-icon"] = self.ckb_show_app_icon.get_active()
settings["show-app-name"] = self.ckb_show_app_name.get_active()
settings["show-layout"] = self.ckb_show_layout.get_active()
settings["hide-empty"] = self.ckb_hide_empty.get_active()
settings["workspace-buttons"] = self.workspace_buttons.get_active()
settings["all-workspaces"] = self.ckb_all_workspaces.get_active()
settings["mark-autotiling"] = self.ckb_mark_autotiling.get_active()
Expand Down Expand Up @@ -1752,7 +1747,9 @@ def edit_sway_workspaces(self, *args):
"mark-autotiling": True,
"mark-content": True,
"show-layout": True,
"angle": 0.0
"angle": 0.0,
"hide-empty": False,
"hide-other-outputs": False,
}
for key in defaults:
check_key(settings, key, defaults[key])
Expand Down Expand Up @@ -1801,6 +1798,14 @@ def edit_sway_workspaces(self, *args):
self.ws_show_name.set_label(voc["show-window-name"])
self.ws_show_name.set_active(settings["show-name"])

self.ws_hide_empty = builder.get_object("hide-empty")
self.ws_hide_empty.set_label(voc["hide-empty"])
self.ws_hide_empty.set_active(settings["hide-empty"])

self.ws_hide_other_outputs = builder.get_object("hide-other-outputs")
self.ws_hide_other_outputs.set_label(voc["hide-other-outputs"])
self.ws_hide_other_outputs.set_active(settings["hide-other-outputs"])

self.ws_image_size = builder.get_object("image-size")
self.ws_image_size.set_numeric(True)
adj = Gtk.Adjustment(value=0, lower=8, upper=129, step_increment=1, page_increment=10, page_size=1)
Expand Down Expand Up @@ -1837,8 +1842,11 @@ def update_sway_workspaces(self):
settings = self.panel["sway-workspaces"]

val = self.eb_workspaces_menu.get_text()
if val:
if val is not None:
print('numbers', repr(settings["numbers"]), repr(val.split()))
settings["numbers"] = val.split()
print('numbers', repr(settings["numbers"]), repr(val.split()))


val = self.ws_custom_labels.get_text()
settings["custom-labels"] = val.split()
Expand All @@ -1854,6 +1862,14 @@ def update_sway_workspaces(self):
if val is not None:
settings["show-name"] = val

val = self.ws_hide_other_outputs.get_active()
if val is not None:
settings["hide-other-outputs"] = val

val = self.ws_hide_empty.get_active()
if val is not None:
settings["hide-empty"] = val

settings["image-size"] = int(self.ws_image_size.get_value())

settings["name-length"] = int(self.ws_name_length.get_value())
Expand Down
41 changes: 26 additions & 15 deletions nwg_panel/glade/config_sway_workspaces.glade
Original file line number Diff line number Diff line change
Expand Up @@ -154,20 +154,6 @@
<property name="top-attach">8</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="hide-empty">
<property name="label" translatable="yes">Hide empty workspaces</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="halign">start</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">8</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="angle">
<property name="visible">True</property>
Expand Down Expand Up @@ -240,7 +226,32 @@
</packing>
</child>
<child>
<placeholder/>
<object class="GtkCheckButton" id="hide-empty">
<property name="label" translatable="yes">Hide empty workspaces</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="halign">start</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">10</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="hide-other-outputs">
<property name="label" translatable="yes">Hide workspaces in other outputs</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="halign">start</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">10</property>
</packing>
</child>
<child>
<placeholder/>
Expand Down
1 change: 1 addition & 0 deletions nwg_panel/langs/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"header-icon-size": "Header icon size",
"height": "Height",
"hide-empty": "Hide empty workspaces",
"hide-other-outputs": "Hide workspaces on other outputs",
"homogeneous": "Homogeneous",
"homogeneous-tooltip": "Sets equal columns width be default if 'Modules center' not empty.",
"horizontal-padding": "Horizontal padding",
Expand Down
16 changes: 12 additions & 4 deletions nwg_panel/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,20 @@ def instantiate_content(panel, container, content_list, icons_path=""):

if item == "sway-workspaces":
if sway:
if "sway-workspaces" in panel:
workspaces = SwayWorkspaces(panel["sway-workspaces"], common.i3, icons_path=icons_path)
if "sway-workspaces" not in panel:
print("'sway-workspaces' not defined in this panel instance")
else:
output = None
if "output" in panel:
output = "{}".format(panel["output"])

workspaces = SwayWorkspaces(panel["sway-workspaces"], common.i3,
icons_path=icons_path,
output=output)

container.pack_start(workspaces, False, False, panel["items-padding"])
common.workspaces_list.append(workspaces)
else:
print("'sway-workspaces' not defined in this panel instance")

else:
print("'sway-workspaces' ignored")

Expand Down
123 changes: 85 additions & 38 deletions nwg_panel/modules/sway_workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@


class SwayWorkspaces(Gtk.Box):
def __init__(self, settings, i3, icons_path):
def __init__(self, settings, i3, icons_path, output):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
self.settings = settings
self.i3 = i3
self.panel_output = output
self.num_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
self.ws_num2box = {}
self.ws_num2lbl = {}
Expand All @@ -34,6 +35,7 @@ def build_box(self):
check_key(self.settings, "mark-autotiling", True)
check_key(self.settings, "mark-content", True)
check_key(self.settings, "hide-empty", False)
check_key(self.settings, "hide-other-outputs", False)
check_key(self.settings, "show-layout", True)
check_key(self.settings, "angle", 0.0)
if self.settings["angle"] != 0.0:
Expand All @@ -42,27 +44,17 @@ def build_box(self):
# prevent from #142
ws_num = -1
if self.i3.get_tree().find_focused():
ws_num, win_name, win_id, non_empty, win_layout, numbers = self.find_details()

if len(self.settings["custom-labels"]) == 1 or len(self.settings["custom-labels"]) == len(self.settings["numbers"]):
self.settings["custom-labels"] *= len(self.settings["numbers"])
else:
self.settings["custom-labels"] = []

if len(self.settings["focused-labels"]) == 1 or len(self.settings["focused-labels"]) == len(self.settings["numbers"]):
self.settings["focused-labels"] *= len(self.settings["numbers"])
else:
self.settings["focused-labels"] = []
ws_num, win_name, win_id, non_empty, win_layout, numbers, ws_defs = self.find_details()

self.pack_start(self.num_box, False, False, 0)

for idx, num in enumerate(self.settings["numbers"]):
if num == str(ws_num) and self.settings["focused-labels"]:
label = self.settings["focused-labels"][idx]
elif self.settings["custom-labels"]:
label = self.settings["custom-labels"][idx]
else:
label = str(num)
try:
int_num = int(num)
except:
int_num = 0

label = self.get_ws_label(int_num, focused = (str(num) == str(ws_num)))

eb, lbl = self.build_number(num, label)
self.num_box.pack_start(eb, False, False, 0)
Expand Down Expand Up @@ -114,9 +106,47 @@ def build_number(self, num, label):

return eb, lbl

def get_ws_label(self, num, idx = None, ws_defs = None, focused = False):
"""
Get the text to display for a workspace:
- num: the number of the workspace (as integer)
- idx: the index of the workspace in ws_defs (if defined)
- focused: if the workspace is currently focused
- ws_defs: as returned by find_details()
"""

# config_idx is the index of the current workspace in the
# configuration. It is the index of the workspace in the
# numbers config field, or the an index based on the
# workspace number, first workspace being number 1
config_idx = None
if num in self.settings["numbers"]:
config_idx = self.settings["numbers"].index(num)
elif len(self.settings["numbers"]) == 0:
config_idx = num - 1
Copy link
Contributor

@moetayuko moetayuko Apr 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

settings["numbers"] is stored as a list of str, int-based lookup fails here


if focused:
labels = self.settings["focused-labels"]
else:
labels = self.settings["custom-labels"]
Comment on lines +128 to +131
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously it fallbacks to custom-labels if focused-labels not defined, need to implement this as well.


if labels and config_idx in range(len(labels)):
text = labels[config_idx]
elif labels and len(labels) == 1:
text = labels[0]
elif idx in range(len(ws_defs)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default value of ws_defs is None, which has no len()

text = ws_defs[idx]['name']
else:
text = str(num)

return text

def refresh(self):
if self.i3.get_tree().find_focused():
ws_num, win_name, win_id, non_empty, win_layout, numbers = self.find_details()
ws_num, win_name, win_id, non_empty, win_layout, numbers, ws_defs = self.find_details()

custom_labels = self.settings["custom-labels"]
focused_labels = self.settings["focused-labels"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not accessed


if len(self.settings["numbers"]) > 0:
numbers = self.settings["numbers"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if numbers is set in config, it's not guaranteed to match ws_defs

Expand All @@ -125,23 +155,15 @@ def refresh(self):
for num in self.ws_num2lbl:
self.ws_num2lbl[num].hide()

for _idx, num in enumerate(numbers):
idx = None
if num in self.settings["numbers"]:
idx = self.settings["numbers"].index(num)
for idx, num in enumerate(numbers):
focused = (str(num) == str(ws_num))
try:
int_num = int(num)
except:
int_num = 0

if idx is None:
text = str(num)
elif num == str(ws_num) and self.settings["focused-labels"]:
text = self.settings["focused-labels"][idx]
elif self.settings["custom-labels"]:
text = self.settings["custom-labels"][idx]
else:
text = str(num)
text = self.get_ws_label(int_num, idx, ws_defs,
focused = focused)

if num not in self.ws_num2lbl:
eb, lbl = self.build_number(num, text)
Expand All @@ -150,7 +172,7 @@ def refresh(self):

lbl = self.ws_num2lbl[num]

if not self.settings["hide-empty"] or int_num in non_empty or num == str(ws_num):
if not self.settings["hide-empty"] or int_num in non_empty or focused:
lbl.show()
else:
lbl.hide()
Expand All @@ -163,10 +185,10 @@ def refresh(self):
else:
if text.endswith("."):
text = text[0:-1]

lbl.set_text(text)

if num == str(ws_num):
if focused:
self.ws_num2box[num].set_property("name", "task-box-focused")
else:
self.ws_num2box[num].set_property("name", "task-box")
Expand Down Expand Up @@ -229,12 +251,30 @@ def find_details(self):
win_id = "" # app_id if available, else window_class
layout = None
numbers = []
ws_defs = []

for ws in workspaces:
numbers.append(str(ws.num))
_, _, name = ws.name.partition(':')
if len(name) == 0:
name = str(ws.num)

hide_other_outputs = self.settings["hide-other-outputs"] and self.panel_output is not None
if hide_other_outputs and ws.output != self.panel_output:
continue

ws_defs.append({
'num': int(ws.num),
'name': name
})
if ws.focused:
ws_num = ws.num

# Sort ws_defs before constructing numbers and names to ensure
# dynamic workspaces always appear in sorted order
ws_defs.sort(key = lambda ws: ws['num'])
for _idx, ws in enumerate(ws_defs):
numbers.append(ws['num'])

non_empty = []
if self.settings["show-name"] or self.settings["show-icon"]:
f = self.i3.get_tree().find_focused()
Expand Down Expand Up @@ -273,16 +313,23 @@ def find_details(self):
if not layout:
layout = f.parent.layout

return ws_num, win_name, win_id, non_empty, layout, numbers
return ws_num, win_name, win_id, non_empty, layout, numbers, ws_defs

def on_click(self, event_box, event_button, num):
nwg_panel.common.i3.command("workspace number {}".format(num))

def on_scroll(self, event_box, event):
hide_other_outputs = self.settings["hide-other-outputs"] and self.panel_output is not None
if event.direction == Gdk.ScrollDirection.UP:
nwg_panel.common.i3.command("workspace prev")
if hide_other_outputs:
nwg_panel.common.i3.command("workspace prev_on_output")
else:
nwg_panel.common.i3.command("workspace prev")
elif event.direction == Gdk.ScrollDirection.DOWN:
nwg_panel.common.i3.command("workspace next")
if hide_other_outputs:
nwg_panel.common.i3.command("workspace next_on_output")
else:
nwg_panel.common.i3.command("workspace next")

def on_enter_notify_event(self, widget, event):
widget.set_state_flags(Gtk.StateFlags.DROP_ACTIVE, clear=False)
Expand Down