mirror of
				https://codeberg.org/dwl/dwl-patches.git
				synced 2025-10-31 20:14:33 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			231 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| commit 2d7e19dc948aec61746fd858394a9c80d34a3216
 | |
| Author: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
 | |
| Date:   Sat Jul 13 01:05:20 2024 +0200
 | |
| 
 | |
|     Add menu command
 | |
| 
 | |
| diff --git a/config.def.h b/config.def.h
 | |
| index 22d2171..ecd2c67 100644
 | |
| --- a/config.def.h
 | |
| +++ b/config.def.h
 | |
| @@ -20,6 +20,12 @@ static const float fullscreen_bg[]         = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
 | |
|  /* logging */
 | |
|  static int log_level = WLR_ERROR;
 | |
|  
 | |
| +static const Menu menus[] = {
 | |
| +	/* command                            feed function        action function */
 | |
| +	{ "wmenu -i -l 5 -p Windows",         menuwinfeed,         menuwinaction    },
 | |
| +	{ "wmenu -i -p Layouts",              menulayoutfeed,      menulayoutaction },
 | |
| +};
 | |
| +
 | |
|  /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
 | |
|  static const Rule rules[] = {
 | |
|  	/* app_id             title       tags mask     isfloating   monitor */
 | |
| @@ -140,6 +146,8 @@ static const Key keys[] = {
 | |
|  	{ MODKEY,                    XKB_KEY_f,          setlayout,      {.v = &layouts[1]} },
 | |
|  	{ MODKEY,                    XKB_KEY_m,          setlayout,      {.v = &layouts[2]} },
 | |
|  	{ MODKEY,                    XKB_KEY_space,      setlayout,      {0} },
 | |
| +	{ MODKEY,                    XKB_KEY_o,          menu,           {.v = &menus[0]} },
 | |
| +	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O,          menu,           {.v = &menus[1]} },
 | |
|  	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space,      togglefloating, {0} },
 | |
|  	{ MODKEY,                    XKB_KEY_e,         togglefullscreen, {0} },
 | |
|  	{ MODKEY,                    XKB_KEY_0,          view,           {.ui = ~0} },
 | |
| diff --git a/dwl.c b/dwl.c
 | |
| index dc0437e..90bb09a 100644
 | |
| --- a/dwl.c
 | |
| +++ b/dwl.c
 | |
| @@ -241,6 +241,12 @@ typedef struct {
 | |
|  	struct wl_listener destroy;
 | |
|  } SessionLock;
 | |
|  
 | |
| +typedef struct {
 | |
| +	const char *cmd; /* command to run a menu */
 | |
| +	void (*feed)(FILE *f); /* feed input to menu */
 | |
| +	void (*action)(char *line); /* do action based on menu output */
 | |
| +} Menu;
 | |
| +
 | |
|  /* function declarations */
 | |
|  static void applybounds(Client *c, struct wlr_box *bbox);
 | |
|  static void applyrules(Client *c);
 | |
| @@ -298,6 +304,12 @@ static void killclient(const Arg *arg);
 | |
|  static void locksession(struct wl_listener *listener, void *data);
 | |
|  static void mapnotify(struct wl_listener *listener, void *data);
 | |
|  static void maximizenotify(struct wl_listener *listener, void *data);
 | |
| +static void menu(const Arg *arg);
 | |
| +static int menuloop(void *data);
 | |
| +static void menuwinfeed(FILE *f);
 | |
| +static void menuwinaction(char *line);
 | |
| +static void menulayoutfeed(FILE *f);
 | |
| +static void menulayoutaction(char *line);
 | |
|  static void monocle(Monitor *m);
 | |
|  static void motionabsolute(struct wl_listener *listener, void *data);
 | |
|  static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
 | |
| @@ -408,6 +420,11 @@ static struct wlr_box sgeom;
 | |
|  static struct wl_list mons;
 | |
|  static Monitor *selmon;
 | |
|  
 | |
| +static struct wl_event_source *menu_source;
 | |
| +static pid_t menu_pid;
 | |
| +static int menu_fd;
 | |
| +static const Menu *menu_current;
 | |
| +
 | |
|  #ifdef XWAYLAND
 | |
|  static void activatex11(struct wl_listener *listener, void *data);
 | |
|  static void associatex11(struct wl_listener *listener, void *data);
 | |
| @@ -675,6 +692,7 @@ cleanup(void)
 | |
|  	wlr_xwayland_destroy(xwayland);
 | |
|  	xwayland = NULL;
 | |
|  #endif
 | |
| +	wl_event_source_remove(menu_source);
 | |
|  	wl_display_destroy_clients(dpy);
 | |
|  	if (child_pid > 0) {
 | |
|  		kill(-child_pid, SIGTERM);
 | |
| @@ -1717,6 +1735,136 @@ maximizenotify(struct wl_listener *listener, void *data)
 | |
|  		wlr_xdg_surface_schedule_configure(c->surface.xdg);
 | |
|  }
 | |
|  
 | |
| +void
 | |
| +menu(const Arg *arg)
 | |
| +{
 | |
| +	FILE *f;
 | |
| +	pid_t pid;
 | |
| +	int fd_right[2], fd_left[2];
 | |
| +
 | |
| +	if (!selmon || menu_pid != 0)
 | |
| +		return;
 | |
| +
 | |
| +	menu_current = arg->v;
 | |
| +
 | |
| +	if (pipe(fd_right) == -1 || pipe(fd_left) == -1)
 | |
| +		return;
 | |
| +	if ((pid = fork()) == -1)
 | |
| +		return;
 | |
| +	if (pid == 0) {
 | |
| +		close(fd_right[1]);
 | |
| +		close(fd_left[0]);
 | |
| +		dup2(fd_right[0], STDIN_FILENO);
 | |
| +		close(fd_right[0]);
 | |
| +		dup2(fd_left[1], STDOUT_FILENO);
 | |
| +		close(fd_left[1]);
 | |
| +
 | |
| +		execl("/bin/sh", "/bin/sh", "-c", menu_current->cmd, NULL);
 | |
| +		die("dwl: execl %s failed:", "/bin/sh");
 | |
| +	}
 | |
| +
 | |
| +	close(fd_right[0]);
 | |
| +	close(fd_left[1]);
 | |
| +
 | |
| +	if (!(f = fdopen(fd_right[1], "w")))
 | |
| +		return;
 | |
| +	menu_current->feed(f);
 | |
| +	fclose(f);
 | |
| +
 | |
| +	menu_pid = pid;
 | |
| +	menu_fd = fd_left[0];
 | |
| +	wl_event_source_timer_update(menu_source, 10);
 | |
| +}
 | |
| +
 | |
| +int
 | |
| +menuloop(void *data)
 | |
| +{
 | |
| +	FILE *f;
 | |
| +	pid_t pid;
 | |
| +	char line[256], *s;
 | |
| +
 | |
| +	/* If process is still running, wait for another 50 ms */
 | |
| +	if ((pid = waitpid(menu_pid, NULL, WNOHANG)) == 0) {
 | |
| +		wl_event_source_timer_update(menu_source, 10);
 | |
| +		return 0;
 | |
| +	}
 | |
| +
 | |
| +	menu_pid = 0;
 | |
| +
 | |
| +	if (!(f = fdopen(menu_fd, "r")))
 | |
| +		return 0;
 | |
| +	if (fgets(line, sizeof(line), f)) {
 | |
| +		if ((s = strchr(line, '\n')))
 | |
| +			*s = '\0';
 | |
| +		menu_current->action(line);
 | |
| +	}
 | |
| +	fclose(f);
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +void
 | |
| +menuwinfeed(FILE *f)
 | |
| +{
 | |
| +	Client *c;
 | |
| +	const char *title;
 | |
| +
 | |
| +	wl_list_for_each(c, &fstack, flink) {
 | |
| +		if (!(title = client_get_title(c)))
 | |
| +			continue;
 | |
| +		fprintf(f, "%s\n", title);
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +void
 | |
| +menuwinaction(char *line)
 | |
| +{
 | |
| +	Client *c;
 | |
| +	Monitor *prevm = selmon;
 | |
| +	const char *title;
 | |
| +
 | |
| +	if (!selmon)
 | |
| +		return;
 | |
| +
 | |
| +	wl_list_for_each(c, &fstack, flink) {
 | |
| +		if (!(title = client_get_title(c)))
 | |
| +			continue;
 | |
| +		if (strcmp(line, title) == 0)
 | |
| +			goto found;
 | |
| +	}
 | |
| +	return;
 | |
| +
 | |
| +found:
 | |
| +	focusclient(c, 1);
 | |
| +	wlr_cursor_move(cursor, NULL, selmon->m.x - prevm->m.x , 0);
 | |
| +	selmon->seltags ^= 1; /* toggle sel tagset */
 | |
| +	selmon->tagset[selmon->seltags] = c->tags;
 | |
| +	arrange(selmon);
 | |
| +	printstatus();
 | |
| +}
 | |
| +
 | |
| +void
 | |
| +menulayoutfeed(FILE *f)
 | |
| +{
 | |
| +	unsigned int i;
 | |
| +	for (i = 0; i < LENGTH(layouts); i++)
 | |
| +		fprintf(f, "%s\n", layouts[i].symbol);
 | |
| +}
 | |
| +
 | |
| +void
 | |
| +menulayoutaction(char *line)
 | |
| +{
 | |
| +	unsigned int i;
 | |
| +	Arg a;
 | |
| +	for (i = 0; i < LENGTH(layouts); i++)
 | |
| +		if (strcmp(line, layouts[i].symbol) == 0)
 | |
| +			goto found;
 | |
| +	return;
 | |
| +
 | |
| +found:
 | |
| +	a.v = &layouts[i];
 | |
| +	setlayout(&a);
 | |
| +}
 | |
| +
 | |
|  void
 | |
|  monocle(Monitor *m)
 | |
|  {
 | |
| @@ -2576,6 +2724,10 @@ setup(void)
 | |
|  	 * e.g when running in the x11 backend or the wayland backend and the
 | |
|  	 * compositor has Xwayland support */
 | |
|  	unsetenv("DISPLAY");
 | |
| +
 | |
| +	menu_source = wl_event_loop_add_timer(
 | |
| +			wl_display_get_event_loop(dpy), menuloop, NULL);
 | |
| +
 | |
|  #ifdef XWAYLAND
 | |
|  	/*
 | |
|  	 * Initialise the XWayland X server.
 | 
