labwc icon indicating copy to clipboard operation
labwc copied to clipboard

Primary workspace

Open 5trixs0f opened this issue 2 months ago • 6 comments

Adding the "firstDesktop" feature as described in the scope document. Allows for users to set the "primary" workspace in rc.xml which will be switched to immediately after the server is initialized.

5trixs0f avatar Dec 08 '25 01:12 5trixs0f

I think we need to add <!-- <primary>Workspace 1</primary> --> in rc.xml.all as it should contain all the possible configuration entries.

tokyo4j avatar Dec 08 '25 08:12 tokyo4j

Updated to reflect the logic changes, also changed name to 'firstDesktop' as that's whats in the scope document and closer to the convention elsewhere in rc.xml. This moves the logic for primary selection into workspaces_init and alters workspaces_switch_to to check if this is an "initial" workspace selection. Also updated the docs and rc.xml.all.

Let me know how you feel about it! I think this is a bit cleaner but it does come with the cost of adding an argument to switch_to.

EDIT: Forgot to mention. Tested this under the following conditions 1. firstDesktop matches an existing desktop, 2. firstDesktop does not match (defaults to first), 3. firstDesktop is empty, and 4. firstDesktop is not defined.

5trixs0f avatar Dec 08 '25 21:12 5trixs0f

I think something like this is cleaner (only slightly tested though):

diff
diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd
index 4e7d7ad8..6771e8f1 100644
--- a/docs/labwc-config.5.scd
+++ b/docs/labwc-config.5.scd
@@ -569,6 +569,12 @@ extending outward from the snapped edge.
 	is 1. The number attribute is optional. If the number attribute is
 	specified, names.name is not required.
 
+*<desktops><firstDesktop>*
+	Define the default starting workspace at login. The default workspace
+	name must match one of the names defined in <dekstops><names>. If no
+	firstDesktop is defined or no matching firstDesktop can be found then
+	the default will be selected as the first workspace in <desktops><names>.
+
 *<desktops><popupTime>*
 	Define the timeout after which to hide the workspace OSD.
 	A setting of 0 disables the OSD. Default is 1000 ms.
diff --git a/docs/rc.xml.all b/docs/rc.xml.all
index f3d046d4..093b42fc 100644
--- a/docs/rc.xml.all
+++ b/docs/rc.xml.all
@@ -175,6 +175,7 @@
     Workspaces can be configured like this:
     <desktops>
       <popupTime>1000</popupTime>
+      <firstDesktop>Workspace 1</firstDesktop>
       <names>
         <name>Workspace 1</name>
         <name>Workspace 2</name>
diff --git a/include/config/rcxml.h b/include/config/rcxml.h
index 3e4f15a2..3b1a6399 100644
--- a/include/config/rcxml.h
+++ b/include/config/rcxml.h
@@ -168,6 +168,7 @@ struct rcxml {
 	struct {
 		int popuptime;
 		int min_nr_workspaces;
+		char *primary_workspace;
 		char *prefix;
 		struct wl_list workspaces;  /* struct workspace.link */
 	} workspace_config;
diff --git a/src/config/rcxml.c b/src/config/rcxml.c
index d3694337..3847e254 100644
--- a/src/config/rcxml.c
+++ b/src/config/rcxml.c
@@ -1299,6 +1299,8 @@ entry(xmlNode *node, char *nodename, char *content)
 		wl_list_append(&rc.workspace_config.workspaces, &workspace->link);
 	} else if (!strcasecmp(nodename, "popupTime.desktops")) {
 		rc.workspace_config.popuptime = atoi(content);
+	} else if (!strcasecmp(nodename, "firstDesktop.desktops")) {
+		xstrdup_replace(rc.workspace_config.primary_workspace, content);
 	} else if (!strcasecmp(nodename, "number.desktops")) {
 		rc.workspace_config.min_nr_workspaces = MAX(1, atoi(content));
 	} else if (!strcasecmp(nodename, "popupShow.resize")) {
@@ -1953,6 +1955,7 @@ rcxml_finish(void)
 	zfree(rc.icon_theme_name);
 	zfree(rc.fallback_app_icon_name);
 	zfree(rc.workspace_config.prefix);
+	zfree(rc.workspace_config.primary_workspace);
 	zfree(rc.tablet.output_name);
 	zfree(rc.window_switcher.thumbnail_label_format);
 
diff --git a/src/workspaces.c b/src/workspaces.c
index f56d170a..b14d1d49 100644
--- a/src/workspaces.c
+++ b/src/workspaces.c
@@ -209,18 +209,11 @@ add_workspace(struct server *server, const char *name)
 	workspace->name = xstrdup(name);
 	workspace->tree = wlr_scene_tree_create(server->view_tree);
 	wl_list_append(&server->workspaces.all, &workspace->link);
-	if (!server->workspaces.current) {
-		server->workspaces.current = workspace;
-	} else {
-		wlr_scene_node_set_enabled(&workspace->tree->node, false);
-	}
-
-	bool active = server->workspaces.current == workspace;
+	wlr_scene_node_set_enabled(&workspace->tree->node, false);
 
 	/* cosmic */
 	workspace->cosmic_workspace = lab_cosmic_workspace_create(server->workspaces.cosmic_group);
 	lab_cosmic_workspace_set_name(workspace->cosmic_workspace, name);
-	lab_cosmic_workspace_set_active(workspace->cosmic_workspace, active);
 
 	workspace->on_cosmic.activate.notify = handle_cosmic_workspace_activate;
 	wl_signal_add(&workspace->cosmic_workspace->events.activate,
@@ -231,7 +224,6 @@ add_workspace(struct server *server, const char *name)
 		server->workspaces.ext_manager, /*id*/ NULL);
 	lab_ext_workspace_assign_to_group(workspace->ext_workspace, server->workspaces.ext_group);
 	lab_ext_workspace_set_name(workspace->ext_workspace, name);
-	lab_ext_workspace_set_active(workspace->ext_workspace, active);
 
 	workspace->on_ext.activate.notify = handle_ext_workspace_activate;
 	wl_signal_add(&workspace->ext_workspace->events.activate,
@@ -398,6 +390,26 @@ workspaces_init(struct server *server)
 	wl_list_for_each(conf, &rc.workspace_config.workspaces, link) {
 		add_workspace(server, conf->name);
 	}
+
+	struct workspace *initial = NULL;
+	struct workspace *first = wl_container_of(
+		server->workspaces.all.next, first, link);
+	const char *initial_name = rc.workspace_config.primary_workspace;
+	if (initial_name) {
+		initial = workspaces_find(first, initial_name, /*wrap*/ false);
+		if (!initial) {
+			wlr_log(WLR_ERROR, "No primary workspace matching %s", initial_name);
+		}
+	}
+	if (!initial) {
+		initial = first;
+	}
+
+	server->workspaces.current = initial;
+	wlr_scene_node_set_enabled(&initial->tree->node, true);
+	lab_ext_workspace_set_active(initial->ext_workspace, true);
+	lab_cosmic_workspace_set_active(initial->cosmic_workspace, true);
 }
 
 /*

Basically we manually set the initial workspace and not switch to it after the fact. Another thing I wondered about is we should change the term firstDesktop to something like initial, selected or startup. That would allow a config like <desktops number="5" startup="3" />. But it might be confused with some kind of dynamic desktop creation..

Consolatis avatar Dec 09 '25 12:12 Consolatis

I had thought about putting this in add_workspace but at the time I didn't want to modify the logic in there too much as default workspace selection was already happening there. This is definitely the cleanest way to do this. I'll toy around with this and get a commit out tonight.

I like initial as I think that's pretty clear as to the intent and I think it would be hard to mistake that to mean anything other than "the workspace I start out on".

5trixs0f avatar Dec 09 '25 20:12 5trixs0f

Sorry for the delay, I've pushed the changes discussed and updated the docs as well.

5trixs0f avatar Dec 12 '25 17:12 5trixs0f

Slightly tested and it seems to work fine. LGTM.

Now we just wait for labwc 0.9.3 to release and need to remember to squash the commits when merging.

Consolatis avatar Dec 13 '25 11:12 Consolatis

workspaces_find() accepts some fixed strings like current. Could you cherry-pick https://github.com/tokyo4j/labwc/commit/0e1626f7187c6d637a6a89ce6dfa38ad9421c260 and use workspace_find_by_name() instead?

tokyo4j avatar Dec 13 '25 23:12 tokyo4j

Appreciate the feedback, I'll work through the docs and fix up the comments.

workspaces_find() accepts some fixed strings like current. Could you cherry-pick tokyo4j@0e1626f and use workspace_find_by_name() instead?

Just so I understand, would you like me to implement the workspace_find_by_name() function as it shows up in that commit or would you like me implement some of the logic in the workspace searching? I only ask for compatibility with tokyo4j@0e1626f

5trixs0f avatar Dec 17 '25 02:12 5trixs0f

Just so I understand, would you like me to implement the workspace_find_by_name() function as it shows up in that commit or would you like me implement some of the logic in the workspace searching? I only ask for compatibility with tokyo4j@0e1626f

You can use git cherry-pick [my commit] and rebase your branch on it.

tokyo4j avatar Dec 17 '25 04:12 tokyo4j