about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--calmwm.h10
-rw-r--r--kbfunc.c9
-rw-r--r--menu.c76
-rw-r--r--search.c48
4 files changed, 135 insertions, 8 deletions
diff --git a/calmwm.h b/calmwm.h
index 5d96485..e08269b 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -73,6 +73,10 @@
 #define CWM_RCYCLE		0x0002
 #define CWM_INGROUP		0x0004
 
+/* menu */
+#define CWM_MENU_DUMMY 	0x0001
+#define CWM_MENU_FILE 		0x0002
+
 #define KBTOGROUP(X) ((X) - 1)
 
 union arg {
@@ -260,7 +264,7 @@ TAILQ_HEAD(cmd_q, cmd);
 struct menu {
 	TAILQ_ENTRY(menu)	 entry;
 	TAILQ_ENTRY(menu)	 resultentry;
-#define MENU_MAXENTRY		 50
+#define MENU_MAXENTRY		 200
 	char			 text[MENU_MAXENTRY + 1];
 	char			 print[MENU_MAXENTRY + 1];
 	void			*ctx;
@@ -355,6 +359,10 @@ void			 search_match_client(struct menu_q *, struct menu_q *,
 			     char *);
 void			 search_match_exec(struct menu_q *, struct menu_q *,
 			     char *);
+void			 search_match_exec_path(struct menu_q *, struct menu_q *,
+			     char *);
+void			 search_match_path_any(struct menu_q *, struct menu_q *,
+			     char *);
 void			 search_match_text(struct menu_q *, struct menu_q *,
 			     char *);
 void			 search_print_client(struct menu *, int);
diff --git a/kbfunc.c b/kbfunc.c
index e11a3cb..1920c5d 100644
--- a/kbfunc.c
+++ b/kbfunc.c
@@ -298,8 +298,9 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg)
 	}
 	xfree(path);
 
-	if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
-	    search_match_exec, NULL)) != NULL) {
+	if ((mi = menu_filter(sc, &menuq, label, NULL,
+	    CWM_MENU_DUMMY | CWM_MENU_FILE,
+	    search_match_exec_path, NULL)) != NULL) {
 		if (mi->text[0] == '\0')
 			goto out;
 		switch (cmd) {
@@ -376,7 +377,7 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
 	xfree(lbuf);
 	(void)fclose(fp);
 
-	if ((mi = menu_filter(sc, &menuq, "ssh", NULL, 1,
+	if ((mi = menu_filter(sc, &menuq, "ssh", NULL, CWM_MENU_DUMMY,
 	    search_match_exec, NULL)) != NULL) {
 		if (mi->text[0] == '\0')
 			goto out;
@@ -403,7 +404,7 @@ kbfunc_client_label(struct client_ctx *cc, union arg *arg)
 	TAILQ_INIT(&menuq);
 
 	/* dummy is set, so this will always return */
-	mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1,
+	mi = menu_filter(cc->sc, &menuq, "label", cc->label, CWM_MENU_DUMMY,
 	    search_match_text, NULL);
 
 	if (!mi->abort) {
diff --git a/menu.c b/menu.c
index 4a532a9..e32994b 100644
--- a/menu.c
+++ b/menu.c
@@ -28,6 +28,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #include "calmwm.h"
 
@@ -37,10 +38,11 @@
 enum ctltype {
 	CTL_NONE = -1,
 	CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
-	CTL_ABORT, CTL_ALL
+	CTL_TAB, CTL_ABORT, CTL_ALL
 };
 
 struct menu_ctx {
+	struct screen_ctx 	*sc;
 	char			 searchstr[MENU_MAXENTRY + 1];
 	char			 dispstr[MENU_MAXENTRY*2 + 1];
 	char			 promptstr[MENU_MAXENTRY + 1];
@@ -54,6 +56,7 @@ struct menu_ctx {
 	int			 height;
 	int			 width;
 	int			 num;
+	int 			 flags;
 	int			 x;
 	int			 y;
     	void (*match)(struct menu_q *, struct menu_q *, char *);
@@ -93,7 +96,7 @@ menu_init(struct screen_ctx *sc)
 
 struct menu *
 menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
-    char *initial, int dummy,
+    char *initial, int flags, 
     void (*match)(struct menu_q *, struct menu_q *, char *),
     void (*print)(struct menu *, int))
 {
@@ -114,6 +117,8 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
 	xsave = mc.x;
 	ysave = mc.y;
 
+	mc.sc = sc;
+	mc.flags = flags;
 	if (prompt == NULL) {
 		evmask = MENUMASK;
 		mc.promptstr[0] = '\0';
@@ -181,7 +186,8 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
 		}
 	}
 out:
-	if (dummy == 0 && mi->dummy) { /* no mouse based match */
+	if ((mc.flags & CWM_MENU_DUMMY) == 0 && mi->dummy) {
+	       	/* no mouse based match */
 		xfree(mi);
 		mi = NULL;
 	}
@@ -200,6 +206,38 @@ out:
 }
 
 static struct menu *
+menu_complete_path(struct menu_ctx *mc)
+{
+	struct menu		*mi, *mr;
+	struct menu_q		 menuq;
+	char *path = NULL;
+
+	path = xcalloc(1, sizeof(mr->text));
+	mr = xcalloc(1, sizeof(*mr));
+
+	TAILQ_INIT(&menuq);
+	if ((mi = menu_filter(mc->sc, &menuq, mc->searchstr, NULL,
+	    CWM_MENU_DUMMY, search_match_path_any, NULL)) != NULL) {
+		mr->abort = mi->abort;
+		mr->dummy = mi->dummy;
+		strlcpy(path, mi->text, sizeof(mi->text));
+	}
+	
+	while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
+		TAILQ_REMOVE(&menuq, mi, entry);
+		xfree(mi);
+	}
+
+	if (path[0] != '\0') 
+		snprintf(mr->text, sizeof(mr->text), "%s \"%s\"",
+			mc->searchstr, path);
+	else if (!mr->abort)
+		strlcpy(mr->text,  mc->searchstr, sizeof(mr->text));
+	xfree(path);
+	return (mr);
+}
+
+static struct menu *
 menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
     struct menu_q *resultq)
 {
@@ -257,6 +295,35 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
 		mc->searchstr[0] = '\0';
 		mc->changed = 1;
 		break;
+	case CTL_TAB:
+		if ((mi = TAILQ_FIRST(resultq)) != NULL) {
+			/* 
+			 * - We are in exec_path menu mode
+			 * - There's only one result
+			 * - It is equal to the input
+			 * We got a command, launch the file menu
+			 */
+			if ((mc->flags & CWM_MENU_FILE) &&
+			    (TAILQ_NEXT(mi, resultentry) == NULL) &&
+			    (strncmp(mc->searchstr, mi->text,
+					strlen(mi->text))) == 0)
+				return (menu_complete_path(mc));
+
+			/* 
+			 * Put common prefix of the results into searchstr
+			 */
+			(void)strlcpy(mc->searchstr,
+					mi->text, sizeof(mc->searchstr));
+			while ((mi = TAILQ_NEXT(mi, resultentry)) != NULL) {
+				i = 0;
+				while (tolower(mc->searchstr[i]) ==
+					       tolower(mi->text[i]))
+					i++;
+				mc->searchstr[i] = '\0';
+			}
+			mc->changed = 1;
+		}
+		break;
 	case CTL_ALL:
 		mc->list = !mc->list;
 		break;
@@ -484,6 +551,9 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
 	case XK_Return:
 		*ctl = CTL_RETURN;
 		break;
+	case XK_Tab:
+		*ctl = CTL_TAB;
+		break;
 	case XK_Up:
 		*ctl = CTL_UP;
 		break;
diff --git a/search.c b/search.c
index 8d58067..e19c9c8 100644
--- a/search.c
+++ b/search.c
@@ -29,9 +29,12 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <glob.h>
 
 #include "calmwm.h"
 
+#define PATH_EXEC 	0x1
+
 static int	strsubmatch(char *, char *, int);
 
 /*
@@ -161,6 +164,43 @@ search_print_client(struct menu *mi, int list)
 	}
 }
 
+static void
+search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search, int flag)
+{
+	struct menu	*mi;
+	char 		 pattern[MAXPATHLEN];
+	glob_t		 g;
+	int		 i;
+
+	TAILQ_INIT(resultq);
+
+	(void)strlcpy(pattern, search, sizeof(pattern));
+	(void)strlcat(pattern, "*", sizeof(pattern));
+
+	if (glob(pattern, GLOB_MARK, NULL, &g) != 0)
+		return;
+	for (i = 0; i < g.gl_pathc; i++) {
+		if ((flag & PATH_EXEC) && access(g.gl_pathv[i], X_OK))
+			continue;
+		mi = xcalloc(1, sizeof(*mi));
+		(void)strlcpy(mi->text, g.gl_pathv[i], sizeof(mi->text));
+		TAILQ_INSERT_TAIL(resultq, mi, resultentry);
+	}
+	globfree(&g);
+}
+
+void 
+search_match_path_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
+{
+	return (search_match_path(menuq, resultq, search, PATH_EXEC));
+}
+
+void 
+search_match_path_any(struct menu_q *menuq, struct menu_q *resultq, char *search)
+{
+	return (search_match_path(menuq, resultq, search, 0));
+}
+
 void
 search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
 {
@@ -196,6 +236,14 @@ search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
 	}
 }
 
+void
+search_match_exec_path(struct menu_q *menuq, struct menu_q *resultq, char *search)
+{
+	search_match_exec(menuq, resultq, search);
+	if (TAILQ_EMPTY(resultq))
+		search_match_path_exec(menuq, resultq, search);
+}
+
 static int
 strsubmatch(char *sub, char *str, int zeroidx)
 {