diff --git a/CMakeLists.txt b/CMakeLists.txt index 306fa9f..8071b33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ set(wmfs_src src/frame.c src/infobar.c src/init.c + src/launcher.c src/layout.c src/menu.c src/mouse.c diff --git a/src/config.c b/src/config.c index a2a87b4..5b5764b 100644 --- a/src/config.c +++ b/src/config.c @@ -315,10 +315,7 @@ conf_menu_section(cfg_t *cfg_m) int i, j; conf.nmenu = cfg_size(cfg_m, "set_menu"); - - if(!conf.nmenu) - return; - + CHECK(conf.nmenu); conf.menu = emalloc(conf.nmenu, sizeof(Menu)); for(i = 0; i < conf.nmenu; ++i) @@ -358,6 +355,27 @@ conf_menu_section(cfg_t *cfg_m) return; } +void +conf_launcher_section(cfg_t *cfg_l) +{ + int i; + + conf.nlauncher = cfg_size(cfg_l, "set_launcher"); + CHECK(conf.nlauncher); + conf.launcher = emalloc(conf.nlauncher, sizeof(Launcher)); + + for(i = 0; i < conf.nlauncher; ++i) + { + cfgtmp = cfg_getnsec(cfg_l, "set_launcher", i); + + conf.launcher[i].name = alias_to_str(strdup(cfg_getstr(cfgtmp, "name"))); + conf.launcher[i].prompt = alias_to_str(strdup(cfg_getstr(cfgtmp, "prompt"))); + conf.launcher[i].command = alias_to_str(strdup(cfg_getstr(cfgtmp, "command"))); + } + + return; +} + void conf_keybind_section(cfg_t *cfg_k) { @@ -420,6 +438,7 @@ init_conf(void) conf_layout_section(cfg_getsec(cfg, "layouts")); conf_tag_section(cfg_getsec(cfg, "tags")); conf_menu_section(cfg_getsec(cfg, "menu")); + conf_launcher_section(cfg_getsec(cfg, "launcher")); conf_keybind_section(cfg_getsec(cfg, "keys")); cfg_free(cfg); diff --git a/src/config_struct.h b/src/config_struct.h index 7fe45c8..d10485e 100644 --- a/src/config_struct.h +++ b/src/config_struct.h @@ -175,6 +175,24 @@ cfg_opt_t menu_opts[] = /* }}} */ +/* LAUNCHER {{{ */ + +cfg_opt_t launchers_opts[] = +{ + CFG_STR("name", "launcher", CFGF_NONE), + CFG_STR("prompt", "Execute:", CFGF_NONE), + CFG_STR("command", "exec", CFGF_NONE), + CFG_END() +}; + +cfg_opt_t launcher_opts[] = +{ + CFG_SEC("set_launcher", launchers_opts, CFGF_MULTI), + CFG_END() +}; + +/* }}} */ + /* KEYBIND {{{ */ cfg_opt_t key_opts[] = @@ -212,15 +230,16 @@ cfg_opt_t alias_opts[] = cfg_opt_t opts[] = { - CFG_SEC("misc", misc_opts, CFGF_NONE), - CFG_SEC("alias", alias_opts, CFGF_NONE), - CFG_SEC("root", root_opts, CFGF_NONE), - CFG_SEC("client", client_opts, CFGF_NONE), - CFG_SEC("bar", bar_opts, CFGF_NONE), - CFG_SEC("layouts", layouts_opts, CFGF_NONE), - CFG_SEC("tags", tags_opts, CFGF_NONE), - CFG_SEC("menu", menu_opts, CFGF_NONE), - CFG_SEC("keys", keys_opts, CFGF_NONE), + CFG_SEC("misc", misc_opts, CFGF_NONE), + CFG_SEC("alias", alias_opts, CFGF_NONE), + CFG_SEC("root", root_opts, CFGF_NONE), + CFG_SEC("client", client_opts, CFGF_NONE), + CFG_SEC("bar", bar_opts, CFGF_NONE), + CFG_SEC("layouts", layouts_opts, CFGF_NONE), + CFG_SEC("tags", tags_opts, CFGF_NONE), + CFG_SEC("menu", menu_opts, CFGF_NONE), + CFG_SEC("launcher", launcher_opts, CFGF_NONE), + CFG_SEC("keys", keys_opts, CFGF_NONE), CFG_END() }; diff --git a/src/infobar.c b/src/infobar.c index c1d4e3e..5a30d73 100644 --- a/src/infobar.c +++ b/src/infobar.c @@ -199,94 +199,3 @@ uicb_infobar_togglepos(uicb_t cmd) return; } - -/** Create a launcher in the infobar for execute - * a system command (with spawn) - * \param cmd uicb_t type unused - * \todo manage Home, End and arrows key - */ -void -uicb_launcher(uicb_t cmd) -{ - XEvent ev; - KeySym ks; - char tmp[32] = { 0 }; - char buf[512] = { 0 }; - int pos = 0; - int lrun = 1; - - screen_get_sel(); - - BarWindow *launch = barwin_create(infobar[selscreen].bar->win, - /* X */ - (infobar[selscreen].layout_button->geo.x - + textw(tags[selscreen][seltag[selscreen]].layout.symbol) + PAD), - /* Y */ - SHADH, - /* WIDTH */ - (sgeo[0].width - - (infobar[selscreen].layout_button->geo.x - + textw(tags[selscreen][seltag[selscreen]].layout.symbol) + PAD) - SHADH), - /* HEIGHT */ - infobar[selscreen].geo.height - SHADH, - /* COLOR */ - conf.colors.bar, conf.colors.text, - /* OPTION */ - False, False, True); - barwin_map(launch); - barwin_refresh_color(launch); - /* Draw Prompt */ - barwin_draw_text(launch, 2, font->height, LPROMPT); - barwin_refresh(launch); - - while(XGrabKeyboard(dpy, ROOT, True, GrabModeAsync, - GrabModeAsync, CurrentTime) != GrabSuccess) - sleep(500); - - while(lrun) - { - if(ev.type == KeyPress) - { - XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0); - - /* Check Ctrl-c / Ctrl-d */ - if(ev.xkey.state & ControlMask) - if(ks == XK_c - || ks == XK_d) - ks = XK_Escape; - - switch(ks) - { - case XK_Return: - uicb_spawn(buf); - lrun = 0; - break; - case XK_Escape: - lrun = 0; - break; - case XK_BackSpace: - if(pos) - buf[--pos] = 0; - break; - default: - strncat(buf, tmp, sizeof(buf)); - ++pos; - break; - } - barwin_refresh_color(launch); - barwin_draw_text(launch, 2, font->height, LPROMPT); - barwin_draw_text(launch, textw(LPROMPT) + textw(" "), font->height, buf); - barwin_refresh(launch); - } - else - getevent(ev); - XNextEvent(dpy, &ev); - } - XUngrabKeyboard(dpy, CurrentTime); - barwin_delete(launch); - - return; -} - - - diff --git a/src/launcher.c b/src/launcher.c new file mode 100644 index 0000000..873411d --- /dev/null +++ b/src/launcher.c @@ -0,0 +1,109 @@ +/* +* launcher.c +* Copyright © 2008 Martin Duquesnoy +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following disclaimer +* in the documentation and/or other materials provided with the +* distribution. +* * Neither the name of the nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "wmfs.h" + +void +launcher_execute(Launcher launcher) +{ + XEvent ev; + KeySym ks; + char tmp[32] = { 0 }; + char buf[512] = { 0 }; + int pos = 0; + Bool run = True; + + int x = (infobar[selscreen].layout_button->geo.x + + textw(tags[selscreen][seltag[selscreen]].layout.symbol) + PAD); + + XGrabKeyboard(dpy, ROOT, True, GrabModeAsync, GrabModeAsync, CurrentTime); + + barwin_draw_text(infobar[selscreen].bar, x, font->height, launcher.prompt); + + while(run) + { + if(ev.type == KeyPress) + { + XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0); + + /* Check Ctrl-c / Ctrl-d */ + if(ev.xkey.state & ControlMask) + if(ks == XK_c + || ks == XK_d) + ks = XK_Escape; + switch(ks) + { + case XK_Return: + spawn("%s %s", launcher.command, buf); + run = 0; + break; + case XK_Escape: + run = 0; + break; + case XK_BackSpace: + if(pos) + buf[--pos] = 0; + break; + default: + strncat(buf, tmp, sizeof(buf)); + ++pos; + break; + } + barwin_refresh_color(infobar[selscreen].bar); + barwin_draw_text(infobar[selscreen].bar, x, font->height, launcher.prompt); + barwin_draw_text(infobar[selscreen].bar, x + textw(launcher.prompt) + textw(" "), font->height, buf); + barwin_refresh(infobar[selscreen].bar); + } + else + getevent(ev); + XNextEvent(dpy, &ev); + } + + infobar_draw(selscreen); + + XUngrabKeyboard(dpy, CurrentTime); + + return; + +} + +void +uicb_launcher(uicb_t cmd) +{ + int i; + + for(i = 0; i < conf.nlauncher; ++i) + if(!strcmp(cmd, conf.launcher[i].name)) + launcher_execute(conf.launcher[i]); + + return; +} diff --git a/src/structs.h b/src/structs.h index 7c5efae..f48f54e 100644 --- a/src/structs.h +++ b/src/structs.h @@ -231,6 +231,14 @@ typedef struct MenuItem *item; } Menu; +/* Launcher struct */ +typedef struct +{ + char *name; + char *prompt; + char *command; +} Launcher; + /* Alias struct */ typedef struct { @@ -297,13 +305,16 @@ typedef struct Alias alias[256]; Layout layout[NUM_OF_LAYOUT]; Menu *menu; + Launcher *launcher; int *ntag; Bool tag_round; Bool layout_system; /* Switch: False, Menu: True. */ + /* Number of... */ int nkeybind; int nbutton; int nlayout; int nmenu; + int nlauncher; } Conf; /* Config.c struct */ diff --git a/src/util.c b/src/util.c index a7eb7aa..163ef1e 100644 --- a/src/util.c +++ b/src/util.c @@ -194,13 +194,20 @@ get_mouse_pos(void) return ret; } + /** Execute a sh command * \param cmd Command */ void -uicb_spawn(uicb_t cmd) +spawn(const char *format, ...) { char *sh = NULL; + char cmd[512]; + va_list ap; + + va_start(ap, format); + vsprintf(cmd, format, ap); + va_end(ap); if(!(sh = getenv("SHELL"))) sh = "/bin/sh"; @@ -221,3 +228,12 @@ uicb_spawn(uicb_t cmd) return; } + +/** Execute a sh command + * \param cmd Command (uicb_t type) +*/ +void +uicb_spawn(uicb_t cmd) +{ + spawn(cmd); +} diff --git a/src/wmfs.h b/src/wmfs.h index d91d46f..209bf4c 100644 --- a/src/wmfs.h +++ b/src/wmfs.h @@ -119,7 +119,6 @@ void infobar_draw_layout(int sc); void infobar_draw_taglist(int sc); void infobar_destroy(void); void uicb_infobar_togglepos(uicb_t); -void uicb_launcher(uicb_t); /* client.c */ void client_attach(Client *c); @@ -203,6 +202,11 @@ void menu_focus_item(Menu *menu, int item, BarWindow *winitem[]); void menu_draw_item_name(Menu *menu, int item, BarWindow *winitem[]); int menu_get_longer_string(MenuItem *mt, int nitem); void uicb_menu(uicb_t cmd); + +/* launcher.c */ +void launcher_execute(Launcher launcher); +void uicb_launcher(uicb_t); + /* mouse.c */ void mouse_move(Client *c); void mouse_resize(Client *c); @@ -223,6 +227,7 @@ Layout layout_name_to_struct(Layout lt[], char *name, int n, func_name_list_t ll char* alias_to_str(char *conf_choice); /* }}} */ XRectangle get_mouse_pos(void); +void spawn(const char *str, ...); void uicb_spawn(uicb_t); /* tag.c */ @@ -266,7 +271,6 @@ void uicb_set_mwfact(uicb_t); void uicb_set_nmaster(uicb_t); void uicb_set_layout(uicb_t cmd); - /* init.c */ void init(void); void init_root(void); diff --git a/wmfsrc b/wmfsrc index b0d1196..0ed40b2 100644 --- a/wmfsrc +++ b/wmfsrc @@ -118,6 +118,22 @@ menu } } +launcher +{ + set_launcher + { + name = "launcher_exec" + prompt = "Exec: " + command = "exec" + } + set_launcher + { + name = "launcher_ssh" + prompt = "ssh to: " + command = "urxvt -e ssh" + } +} + keys { # general keybind @@ -139,7 +155,9 @@ keys key { mod = {"Alt", "Shift"} key = "l" func = "set_nmaster" cmd = "+1" } key { mod = {"Alt", "Shift"} key = "h" func = "set_nmaster" cmd = "-1" } - key { mod = { "Alt" } key = "p" func = "launcher" } + # Launchers + key { mod = { "Alt" } key = "p" func = "launcher" cmd = "launcher_exec" } + key { mod = { "Alt", "Control" } key = "p" func = "launcher" cmd = "launcher_ssh" } # tag manipulation keybind key { mod = {"Alt"} key = "F1" func = "tag" cmd = "1" }