mirror of
				https://github.com/DreamMaoMao/maomaowm.git
				synced 2025-10-29 05:40:21 -04:00 
			
		
		
		
	feat: wlr-ext-workspace support
This commit is contained in:
		
							parent
							
								
									8a4175eeda
								
							
						
					
					
						commit
						aaae66113d
					
				
					 5 changed files with 218 additions and 4 deletions
				
			
		|  | @ -76,3 +76,7 @@ int regex_match(const char *pattern, const char *str) { | |||
| 	pcre2_code_free(re); | ||||
| 	return ret >= 0; | ||||
| } | ||||
| 
 | ||||
| void wl_list_append(struct wl_list *list, struct wl_list *object) { | ||||
| 	wl_list_insert(list->prev, object); | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| /* See LICENSE.dwm file for copyright and license details. */ | ||||
| #include <wayland-util.h> | ||||
| 
 | ||||
| void die(const char *fmt, ...); | ||||
| void *ecalloc(size_t nmemb, size_t size); | ||||
| int fd_set_nonblock(int fd); | ||||
| int regex_match(const char *pattern_mb, const char *str_mb); | ||||
| void wl_list_append(struct wl_list *list, struct wl_list *object); | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| #include "dwl-ipc.h" | ||||
| #include "ext-workspace.h" | ||||
| #include "foreign-toplevel.h" | ||||
| #include "text-input.h" | ||||
							
								
								
									
										184
									
								
								src/ext-protocol/ext-workspace.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								src/ext-protocol/ext-workspace.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,184 @@ | |||
| #include <wlr/types/wlr_ext_workspace_v1.h> | ||||
| 
 | ||||
| typedef struct Monitor Monitor; | ||||
| 
 | ||||
| struct workspace { | ||||
| 	struct wl_list link; // Link in global workspaces list
 | ||||
| 	unsigned int tag;	 // Numeric identifier (1-9, 0=overview)
 | ||||
| 	Monitor *m;			 // Associated monitor
 | ||||
| 	struct wlr_ext_workspace_handle_v1 *ext_workspace; // Protocol object
 | ||||
| 	/* Event listeners */ | ||||
| 	struct wl_listener activate; | ||||
| 	struct wl_listener deactivate; | ||||
| 	struct wl_listener assign; | ||||
| 	struct wl_listener remove; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_ext_workspace_manager_v1 *ext_manager; | ||||
| struct wl_list workspaces; | ||||
| 
 | ||||
| void goto_workspace(struct workspace *target) { | ||||
| 	unsigned int tag; | ||||
| 	tag = 1 << (target->tag - 1); | ||||
| 	if (target->tag == 0) { | ||||
| 		toggleoverview(&(Arg){.i = -1}); | ||||
| 		return; | ||||
| 	} else { | ||||
| 		view(&(Arg){.ui = tag}, true); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_ext_workspace_activate(struct wl_listener *listener, | ||||
| 										  void *data) { | ||||
| 	struct workspace *workspace = | ||||
| 		wl_container_of(listener, workspace, activate); | ||||
| 	goto_workspace(workspace); | ||||
| 	wlr_log(WLR_INFO, "ext activating workspace %d", workspace->tag); | ||||
| } | ||||
| 
 | ||||
| static const char *get_name_from_tag(unsigned int tag) { | ||||
| 	static const char *names[] = {"overview", "1", "2", "3", "4", | ||||
| 								  "5",		  "6", "7", "8", "9"}; | ||||
| 	return (tag < sizeof(names) / sizeof(names[0])) ? names[tag] : NULL; | ||||
| } | ||||
| 
 | ||||
| void destroy_workspace(struct workspace *workspace) { | ||||
| 	wl_list_remove(&workspace->activate.link); | ||||
| 	wlr_ext_workspace_handle_v1_destroy(workspace->ext_workspace); | ||||
| 	wl_list_remove(&workspace->link); | ||||
| 	free(workspace); | ||||
| } | ||||
| 
 | ||||
| void cleanup_workspaces_by_monitor(Monitor *m) { | ||||
| 	struct workspace *workspace, *tmp; | ||||
| 	wl_list_for_each_safe(workspace, tmp, &workspaces, link) { | ||||
| 		if (workspace->m == m) { | ||||
| 			destroy_workspace(workspace); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void remove_workspace_by_tag(unsigned int tag, Monitor *m) { | ||||
| 	struct workspace *workspace, *tmp; | ||||
| 	wl_list_for_each_safe(workspace, tmp, &workspaces, link) { | ||||
| 		if (workspace->tag == tag && workspace->m == m) { | ||||
| 			destroy_workspace(workspace); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void add_workspace_by_tag(int tag, Monitor *m) { | ||||
| 	const char *name = get_name_from_tag(tag); | ||||
| 
 | ||||
| 	struct workspace *workspace = ecalloc(1, sizeof(*workspace)); | ||||
| 	wl_list_append(&workspaces, &workspace->link); | ||||
| 
 | ||||
| 	workspace->tag = tag; | ||||
| 	workspace->m = m; | ||||
| 	workspace->ext_workspace = wlr_ext_workspace_handle_v1_create( | ||||
| 		ext_manager, name, WLR_EXT_WORKSPACE_HANDLE_V1_CAP_ACTIVATE); | ||||
| 	wlr_ext_workspace_handle_v1_set_group(workspace->ext_workspace, | ||||
| 										  m->ext_group); | ||||
| 	wlr_ext_workspace_handle_v1_set_name(workspace->ext_workspace, name); | ||||
| 	workspace->activate.notify = handle_ext_workspace_activate; | ||||
| 	wl_signal_add(&workspace->ext_workspace->events.activate, | ||||
| 				  &workspace->activate); | ||||
| } | ||||
| 
 | ||||
| unsigned int get_tag_status(unsigned int tag) { | ||||
| 	Client *c; | ||||
| 	unsigned int status = 0; | ||||
| 	wl_list_for_each(c, &clients, link) { | ||||
| 		if (c->tags & 1 << (tag - 1) & TAGMASK) { | ||||
| 			if (c->isurgent) { | ||||
| 				status = 2; | ||||
| 				break; | ||||
| 			} | ||||
| 			status = 1; | ||||
| 		} | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| unsigned int get_tags_first_tag_num(unsigned int source_tags) { | ||||
| 	unsigned int i, tag; | ||||
| 	tag = 0; | ||||
| 
 | ||||
| 	if (!source_tags) { | ||||
| 		return selmon->pertag->curtag; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; !(tag & 1) && source_tags != 0 && i < LENGTH(tags); i++) { | ||||
| 		tag = source_tags >> i; | ||||
| 	} | ||||
| 
 | ||||
| 	if (i == 1) { | ||||
| 		return 1; | ||||
| 	} else if (i > 9) { | ||||
| 		return 9; | ||||
| 	} else { | ||||
| 		return i; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void dwl_ext_workspace_printstatus(Monitor *m) { | ||||
| 	unsigned int current_tag; | ||||
| 	struct workspace *w; | ||||
| 	unsigned int tag_status = 0; | ||||
| 	bool is_active = false; | ||||
| 
 | ||||
| 	current_tag = get_tags_first_tag_num(m->tagset[m->seltags]); | ||||
| 
 | ||||
| 	wl_list_for_each(w, &workspaces, link) { | ||||
| 		if (w && w->m == m) { | ||||
| 			is_active = (w->tag == current_tag) || m->isoverview; | ||||
| 			tag_status = get_tag_status(w->tag); | ||||
| 			if (is_active) { | ||||
| 				wlr_ext_workspace_handle_v1_set_urgent(w->ext_workspace, false); | ||||
| 				wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, false); | ||||
| 			} else if (tag_status == 2) { | ||||
| 				wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, false); | ||||
| 				wlr_ext_workspace_handle_v1_set_urgent(w->ext_workspace, true); | ||||
| 			} else if (tag_status == 1) { | ||||
| 				wlr_ext_workspace_handle_v1_set_urgent(w->ext_workspace, false); | ||||
| 				wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, false); | ||||
| 			} else { | ||||
| 				wlr_ext_workspace_handle_v1_set_urgent(w->ext_workspace, false); | ||||
| 				wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, true); | ||||
| 			} | ||||
| 
 | ||||
| 			if (m->tagset[m->seltags] & (1 << (w->tag - 1)) & TAGMASK) { | ||||
| 				wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, false); | ||||
| 				wlr_ext_workspace_handle_v1_set_active(w->ext_workspace, true); | ||||
| 			} else { | ||||
| 				wlr_ext_workspace_handle_v1_set_active(w->ext_workspace, false); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void refresh_monitors_workspaces_status(Monitor *m) { | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (m->isoverview) { | ||||
| 		for (i = 1; i <= LENGTH(tags); i++) { | ||||
| 			remove_workspace_by_tag(i, m); | ||||
| 		} | ||||
| 		add_workspace_by_tag(0, m); | ||||
| 	} else { | ||||
| 		remove_workspace_by_tag(0, m); | ||||
| 		for (i = 1; i <= LENGTH(tags); i++) { | ||||
| 			add_workspace_by_tag(i, m); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	dwl_ext_workspace_printstatus(m); | ||||
| } | ||||
| 
 | ||||
| void workspaces_init() { | ||||
| 	/* Create the global workspace manager with activation capability */ | ||||
| 	ext_manager = wlr_ext_workspace_manager_v1_create(dpy, 1); | ||||
| 	/* Initialize the global workspaces list */ | ||||
| 	wl_list_init(&workspaces); | ||||
| } | ||||
							
								
								
									
										31
									
								
								src/mango.c
									
										
									
									
									
								
							
							
						
						
									
										31
									
								
								src/mango.c
									
										
									
									
									
								
							|  | @ -423,6 +423,7 @@ struct Monitor { | |||
| 	unsigned int visible_tiling_clients; | ||||
| 	struct wlr_scene_optimized_blur *blur; | ||||
| 	char last_surface_ws_name[256]; | ||||
| 	struct wlr_ext_workspace_group_handle_v1 *ext_group; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|  | @ -645,6 +646,7 @@ static bool check_hit_no_border(Client *c); | |||
| static void reset_keyboard_layout(void); | ||||
| static void client_update_oldmonname_record(Client *c, Monitor *m); | ||||
| static void pending_kill_client(Client *c); | ||||
| static unsigned int get_tags_first_tag_num(unsigned int source_tags); | ||||
| static void set_layer_open_animaiton(LayerSurface *l, struct wlr_box geo); | ||||
| static void init_fadeout_layers(LayerSurface *l); | ||||
| static void layer_actual_size(LayerSurface *l, unsigned int *width, | ||||
|  | @ -1984,6 +1986,11 @@ void cleanupmon(struct wl_listener *listener, void *data) { | |||
| 			wlr_layer_surface_v1_destroy(l->layer_surface); | ||||
| 	} | ||||
| 
 | ||||
| 	// clean ext-workspaces grouplab
 | ||||
| 	wlr_ext_workspace_group_handle_v1_output_leave(m->ext_group, m->wlr_output); | ||||
| 	wlr_ext_workspace_group_handle_v1_destroy(m->ext_group); | ||||
| 	cleanup_workspaces_by_monitor(m); | ||||
| 
 | ||||
| 	wl_list_remove(&m->destroy.link); | ||||
| 	wl_list_remove(&m->frame.link); | ||||
| 	wl_list_remove(&m->link); | ||||
|  | @ -2582,8 +2589,6 @@ void createmon(struct wl_listener *listener, void *data) { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	printstatus(); | ||||
| 
 | ||||
| 	/* The xdg-protocol specifies:
 | ||||
| 	 * | ||||
| 	 * If the fullscreened surface is not opaque, the compositor must make | ||||
|  | @ -2612,6 +2617,15 @@ void createmon(struct wl_listener *listener, void *data) { | |||
| 		wlr_scene_optimized_blur_set_size(m->blur, m->m.width, m->m.height); | ||||
| 		// wlr_scene_node_set_enabled(&m->blur->node, 1);
 | ||||
| 	} | ||||
| 	m->ext_group = wlr_ext_workspace_group_handle_v1_create( | ||||
| 		ext_manager, WLR_EXT_WORKSPACE_HANDLE_V1_CAP_ACTIVATE); | ||||
| 	wlr_ext_workspace_group_handle_v1_output_enter(m->ext_group, m->wlr_output); | ||||
| 
 | ||||
| 	for (i = 1; i <= LENGTH(tags); i++) { | ||||
| 		add_workspace_by_tag(i, m); | ||||
| 	} | ||||
| 
 | ||||
| 	printstatus(); | ||||
| } | ||||
| 
 | ||||
| void // fix for 0.5
 | ||||
|  | @ -3773,7 +3787,11 @@ printstatus(void) { | |||
| 		if (!m->wlr_output->enabled) { | ||||
| 			continue; | ||||
| 		} | ||||
| 		dwl_ipc_output_printstatus(m); // 更新waybar上tag的状态 这里很关键
 | ||||
| 		// Update workspace active states
 | ||||
| 		dwl_ext_workspace_printstatus(m); | ||||
| 
 | ||||
| 		// Update IPC output status
 | ||||
| 		dwl_ipc_output_printstatus(m); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -4662,6 +4680,9 @@ void setup(void) { | |||
| 		wlr_xdg_foreign_registry_create(dpy); | ||||
| 	wlr_xdg_foreign_v1_create(dpy, foreign_registry); | ||||
| 	wlr_xdg_foreign_v2_create(dpy, foreign_registry); | ||||
| 
 | ||||
| 	// ext-workspace协议
 | ||||
| 	workspaces_init(); | ||||
| #ifdef XWAYLAND | ||||
| 	/*
 | ||||
| 	 * Initialise the XWayland X server. | ||||
|  | @ -4808,7 +4829,6 @@ int hidecursor(void *data) { | |||
| 
 | ||||
| // 显示所有tag 或 跳转到聚焦窗口的tag
 | ||||
| void toggleoverview(const Arg *arg) { | ||||
| 
 | ||||
| 	Client *c; | ||||
| 
 | ||||
| 	if (selmon->isoverview && ov_tab_mode && arg->i != -1 && selmon->sel) { | ||||
|  | @ -4839,6 +4859,7 @@ void toggleoverview(const Arg *arg) { | |||
| 	} else if (!selmon->isoverview && !selmon->sel) { | ||||
| 		target = (1 << (selmon->pertag->prevtag - 1)); | ||||
| 		view(&(Arg){.ui = target}, false); | ||||
| 		refresh_monitors_workspaces_status(selmon); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -4864,6 +4885,8 @@ void toggleoverview(const Arg *arg) { | |||
| 	if (ov_tab_mode && selmon->isoverview && selmon->sel) { | ||||
| 		focusstack(&(Arg){.i = 1}); | ||||
| 	} | ||||
| 
 | ||||
| 	refresh_monitors_workspaces_status(selmon); | ||||
| } | ||||
| 
 | ||||
| void unlocksession(struct wl_listener *listener, void *data) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 DreamMaoMao
						DreamMaoMao