Browse Source

! NEW LAUNCHER ! Uicb function 'launcher', new [lauchers] section and 'l' infobarelement. See default wmfsrc please

Martin Duquesnoy 12 years ago
parent
commit
99bb7e0812
10 changed files with 354 additions and 9 deletions
  1. 1 0
      Makefile.in
  2. 33 0
      src/config.c
  3. 4 0
      src/config.h
  4. 58 4
      src/infobar.c
  5. 1 1
      src/infobar.h
  6. 196 0
      src/launcher.c
  7. 13 0
      src/launcher.h
  8. 11 1
      src/wmfs.c
  9. 15 1
      src/wmfs.h
  10. 22 2
      wmfsrc

+ 1 - 0
Makefile.in

@@ -11,6 +11,7 @@ SRCS=                 \
       src/ewmh.c      \
       src/infobar.c   \
       src/layout.c    \
+      src/launcher.c  \
       src/parse_api.c \
       src/parse.c     \
       src/screen.c    \

+ 33 - 0
src/config.c

@@ -267,6 +267,38 @@ config_rule(void)
      free(ks);
 }
 
+static void
+config_launcher(void)
+{
+     struct conf_sec *sec, **ks;
+     struct launcher *l;
+     int n, i;
+
+     /* [launchers] */
+     sec = fetch_section_first(NULL, "launchers");
+     ks = fetch_section(sec, "launcher");
+     n = fetch_section_count(ks);
+
+     SLIST_INIT(&W->h.launcher);
+
+     /* [launcher] */
+     for(i = 0; i < n; ++i)
+     {
+          l = xcalloc(1, sizeof(struct launcher));
+
+          l->name    = xstrdup(fetch_opt_first(ks[i], "default", "name").str);
+          l->prompt  = xstrdup(fetch_opt_first(ks[i], ":",       "prompt").str);
+          l->command = xstrdup(fetch_opt_first(ks[i], "spawn",   "command").str);
+
+          if((l->width = fetch_opt_first(ks[i], "150", "width").num) <= 0)
+               l->width = 150;
+
+          SLIST_INSERT_HEAD(&W->h.launcher, l, next);
+     }
+
+     free(ks);
+}
+
 static void
 config_keybind(void)
 {
@@ -338,6 +370,7 @@ config_init(void)
      config_client();
      config_bars();
      config_rule();
+     config_launcher();
 
      free_conf();
 }

+ 4 - 0
src/config.h

@@ -18,6 +18,7 @@
 #include "mouse.h"
 #include "screen.h"
 #include "infobar.h"
+#include "launcher.h"
 
 #define THEME_DEFAULT (SLIST_FIRST(&W->h.theme))
 
@@ -88,6 +89,9 @@ static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] =
      { "screen_move_client_next", uicb_screen_move_client_next },
      { "screen_move_client_prev", uicb_screen_move_client_prev },
 
+     /* Launcher */
+     { "launcher", uicb_launcher },
+
      { NULL, NULL }
 };
 

+ 58 - 4
src/infobar.c

@@ -18,6 +18,8 @@ static void infobar_elem_status_init(struct element *e);
 static void infobar_elem_status_update(struct element *e);
 static void infobar_elem_systray_init(struct element *e);
 static void infobar_elem_systray_update(struct element *e);
+static void infobar_elem_launcher_init(struct element *e);
+static void infobar_elem_launcher_update(struct element *e);
 
 const struct elem_funcs
 {
@@ -26,9 +28,10 @@ const struct elem_funcs
      void (*func_update)(struct element *e);
 } elem_funcs[] =
 {
-     { 't', infobar_elem_tag_init,     infobar_elem_tag_update },
-     { 's', infobar_elem_status_init,  infobar_elem_status_update },
-     { 'y', infobar_elem_systray_init, infobar_elem_systray_update },
+     { 't', infobar_elem_tag_init,      infobar_elem_tag_update },
+     { 's', infobar_elem_status_init,   infobar_elem_status_update },
+     { 'y', infobar_elem_systray_init,  infobar_elem_systray_update },
+     { 'l', infobar_elem_launcher_init, infobar_elem_launcher_update },
      { '\0', NULL, NULL }
 };
 
@@ -218,12 +221,60 @@ infobar_elem_systray_update(struct element *e)
      systray_update();
 }
 
+static void
+infobar_elem_launcher_init(struct element *e)
+{
+     struct barwin *b;
+
+     if(!(W->flags & WMFS_LAUNCHER))
+          e->geo.w = 1;
+
+     infobar_elem_placement(e);
+
+     if(!(b = SLIST_FIRST(&e->bars)))
+     {
+          b = barwin_new(e->infobar->bar->win, e->geo.x, 0, e->geo.w, e->geo.h, 0, 0, false);
+          b->fg = e->infobar->theme->bars.fg;
+          b->bg = e->infobar->theme->bars.bg;
+          SLIST_INSERT_HEAD(&e->bars, b, enext);
+     }
+     else
+     {
+          barwin_move(b, e->geo.x, e->geo.y);
+          barwin_resize(b, e->geo.w, e->geo.h);
+     }
+
+     barwin_refresh_color(b);
+     barwin_refresh(b);
+}
+
+static void
+infobar_elem_launcher_update(struct element *e)
+{
+     struct barwin *b = SLIST_FIRST(&e->bars);
+     int l;
+
+     if(!(W->flags & WMFS_LAUNCHER))
+          return;
+
+     barwin_refresh_color(b);
+
+     l = draw_textw(e->infobar->theme, e->data) + 2;
+     draw_text(b->dr, e->infobar->theme, 1, TEXTY(e->infobar->theme, e->geo.h), b->fg, e->data);
+
+     /* Cursor */
+     XDrawLine(W->dpy, b->dr, W->gc, l, 2, l, e->geo.h - 4);
+
+     barwin_refresh(b);
+}
+
 #define ELEM_INIT(a)                                  \
      do {                                             \
           e = xcalloc(1, sizeof(struct element));     \
           SLIST_INIT(&e->bars);                       \
           e->infobar = i;                             \
           e->type = j;                                \
+          e->data = NULL;                             \
           e->align = a;                               \
           e->func_init = elem_funcs[j].func_init;     \
           e->func_update = elem_funcs[j].func_update; \
@@ -336,6 +387,8 @@ infobar_elem_reinit(struct infobar *i)
 {
      struct element *e;
 
+     barwin_refresh_color(i->bar);
+
      TAILQ_FOREACH(e, &i->elements, next)
      {
           /* Status element found, scan from the tail now */
@@ -361,6 +414,8 @@ infobar_elem_reinit(struct infobar *i)
           e->func_init(e);
           e->func_update(e);
      }
+
+     barwin_refresh(i->bar);
 }
 
 struct infobar*
@@ -412,7 +467,6 @@ infobar_remove(struct infobar *i)
 
      free(i->elemorder);
      free(i->name);
-     free(i->status);
 
      if(i == W->systray.infobar)
           systray_freeicons();

+ 1 - 1
src/infobar.h

@@ -10,7 +10,7 @@
 #include "util.h"
 #include "tag.h"
 
-enum { ElemTag = 0, ElemStatus, ElemSystray, ElemCustom, ElemLast };
+enum { ElemTag = 0, ElemStatus, ElemSystray, ElemLauncher, ElemCustom, ElemLast };
 
 struct infobar *infobar_new(struct screen *s, char *name, struct theme *theme, enum barpos pos, const char *elem);
 void infobar_elem_update(struct infobar *i, int type);

+ 196 - 0
src/launcher.c

@@ -0,0 +1,196 @@
+/*
+ *  wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
+ *  For license, see COPYING.
+ */
+
+#include <X11/Xutil.h>
+#include <string.h>
+
+#include "wmfs.h"
+#include "event.h"
+#include "util.h"
+#include "infobar.h"
+#include "config.h"
+
+#define LAUNCHER_INIT_ELEM(width)                       \
+     SLIST_FOREACH(ib, &W->screen->infobars, next)      \
+     {                                                  \
+          TAILQ_FOREACH(e, &ib->elements, next)         \
+               if(e->type == ElemLauncher)              \
+               {                                        \
+                    e->geo.w = width;                   \
+                    e->data = data;                     \
+               }                                        \
+          infobar_elem_reinit(ib);                      \
+     }
+
+static void
+launcher_process(struct launcher *l)
+{
+     struct infobar *ib;
+     struct element *e;
+     bool loop = true;
+     char buf[512] = { 0 };
+     char tmp[32] = { 0 };
+     char *p, *data, *arg, *cmd = xstrdup(l->command);
+     int i, pos = 0, histpos = 0;
+     void (*func)(Uicb);
+     XEvent ev;
+     KeySym ks;
+
+     W->flags |= WMFS_LAUNCHER;
+
+     /* Prepare elements */
+     xasprintf(&data, "%s ", l->prompt);
+     LAUNCHER_INIT_ELEM(l->width);
+
+     XGrabKeyboard(W->dpy, W->root, true, GrabModeAsync, GrabModeAsync, CurrentTime);
+
+     while(loop)
+     {
+          XNextEvent(W->dpy, &ev);
+
+          if(ev.type != KeyPress)
+          {
+               EVENT_HANDLE(&ev);
+               continue;
+          }
+
+          /* Get pressed key */
+          XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0);
+
+          /* Check Ctrl-c / Ctrl-d */
+          if(ev.xkey.state & ControlMask)
+          {
+               switch(ks)
+               {
+               case XK_c:
+               case XK_d:
+                    ks = XK_Escape;
+                    break;
+               case XK_p:
+                    ks = XK_Up;
+                    break;
+               case XK_n:
+                    ks = XK_Down;
+                    break;
+               }
+          }
+
+          /* Check if there is a keypad */
+          if(IsKeypadKey(ks) && ks == XK_KP_Enter)
+               ks = XK_Return;
+
+          /* Manage pressed keys */
+          switch(ks)
+          {
+          case XK_Up:
+               if(l->nhisto)
+               {
+                    if(histpos >= (int)l->nhisto)
+                         histpos = 0;
+                    strncpy(buf, l->histo[l->nhisto - ++histpos], sizeof(buf));
+                    pos = strlen(buf);
+               }
+               break;
+
+          case XK_Down:
+               if(l->nhisto && histpos > 0 && histpos < (int)l->nhisto)
+               {
+                    strncpy(buf, l->histo[l->nhisto - --histpos], sizeof(buf));
+                    pos = strlen(buf);
+               }
+               break;
+
+          case XK_Return:
+               /* Get function name only, if cmds are added in command */
+               arg = NULL;
+               if((p = strchr(cmd, ' ')))
+               {
+                    *p = '\0';
+                    xasprintf(&arg, "%s %s", p + 1, buf);
+               }
+
+               if((func = uicb_name_func(cmd)))
+               {
+                    if(arg)
+                    {
+                         func(arg);
+                         free(arg);
+                    }
+                    else
+                         func(buf);
+               }
+
+               /* Histo */
+               if(l->nhisto + 1 > HISTOLEN)
+               {
+                    for(i = l->nhisto - 1; i > 1; --i)
+                         strncpy(l->histo[i], l->histo[i - 1], sizeof(l->histo[i]));
+
+                    l->nhisto = 0;
+               }
+               /* Store in histo array */
+               strncpy(l->histo[l->nhisto++], buf, sizeof(buf));
+
+               loop = false;
+               break;
+
+          case XK_Escape:
+               loop = false;
+               break;
+
+          /* TODO: Completion */
+          case XK_Tab:
+               break;
+
+          case XK_BackSpace:
+               if(pos)
+                    buf[--pos] = '\0';
+               break;
+
+          default:
+               strncat(buf, tmp, sizeof(tmp));
+               ++pos;
+               break;
+          }
+
+          free(data);
+          xasprintf(&data, "%s %s", l->prompt, buf);
+
+          /* Update EVERY launcher element of the screen */
+          SLIST_FOREACH(ib, &W->screen->infobars, next)
+          {
+               TAILQ_FOREACH(e, &ib->elements, next)
+               {
+                    if(e->type != ElemLauncher)
+                         continue;
+
+                    e->data = data;
+                    e->func_update(e);
+               }
+          }
+     }
+
+     XUngrabKeyboard(W->dpy, CurrentTime);
+
+     free(cmd);
+
+     /* 'Close' launcher elements */
+     W->flags ^= WMFS_LAUNCHER;
+     data = NULL;
+     LAUNCHER_INIT_ELEM(1);
+}
+
+void
+uicb_launcher(Uicb cmd)
+{
+     struct launcher *l;
+
+     SLIST_FOREACH(l, &W->h.launcher, next)
+          if(!strcmp(l->name, cmd))
+          {
+               launcher_process(l);
+               break;
+          }
+}

+ 13 - 0
src/launcher.h

@@ -0,0 +1,13 @@
+/*
+ *  wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
+ *  For license, see COPYING.
+ */
+
+#ifndef LAUNCHER_H
+#define LAUNCHER_H
+
+#include "wmfs.h"
+
+void uicb_launcher(Uicb cmd);
+
+#endif /* LAUNCHER_H */

+ 11 - 1
src/wmfs.c

@@ -406,6 +406,7 @@ wmfs_quit(void)
      struct theme *t;
      struct client *c;
      struct mousebind *m;
+     struct launcher *l;
 
      ewmh_update_wmfs_props();
 
@@ -419,7 +420,6 @@ wmfs_quit(void)
           client_remove(c);
      }
 
-
      /* Will free:
       *
       * Screens -> tags
@@ -460,6 +460,16 @@ wmfs_quit(void)
           free(k);
      }
 
+     while(!SLIST_EMPTY(&W->h.launcher))
+     {
+          l = SLIST_FIRST(&W->h.launcher);
+          SLIST_REMOVE_HEAD(&W->h.launcher, next);
+          free((void*)l->name);
+          free((void*)l->prompt);
+          free((void*)l->command);
+          free(l);
+     }
+
      while(!SLIST_EMPTY(&W->h.mousebind))
      {
           m = SLIST_FIRST(&W->h.mousebind);

+ 15 - 1
src/wmfs.h

@@ -123,6 +123,7 @@ struct element
      struct infobar *infobar;
      struct status_ctx *statusctx;
      int type;
+     char *data;
      enum position align;
      void (*func_init)(struct element *e);
      void (*func_update)(struct element *e);
@@ -140,7 +141,6 @@ struct infobar
      enum barpos pos;
      char *elemorder;
      char *name;
-     char *status;
      TAILQ_HEAD(esub, element) elements;
      SLIST_ENTRY(infobar) next;
 };
@@ -275,6 +275,18 @@ struct rule
      SLIST_ENTRY(rule) next;
 };
 
+struct launcher
+{
+     char *name;
+     char *prompt;
+     char *command;
+#define HISTOLEN 64
+     char histo[HISTOLEN][256];
+     int nhisto;
+     int width;
+     SLIST_ENTRY(launcher) next;
+};
+
 struct _systray
 {
      struct geo geo;
@@ -298,6 +310,7 @@ struct wmfs
 #define WMFS_RELOAD   0x04
 #define WMFS_SYSTRAY  0x08
 #define WMFS_LOG      0x10
+#define WMFS_LAUNCHER 0x20
      Flags flags;
      GC gc, rgc;
      Atom *net_atom;
@@ -325,6 +338,7 @@ struct wmfs
           SLIST_HEAD(, theme) theme;
           SLIST_HEAD(, rule) rule;
           SLIST_HEAD(, mousebind) mousebind;
+          SLIST_HEAD(, launcher) launcher;
      } h;
 
      /*

+ 22 - 2
wmfsrc

@@ -65,11 +65,12 @@
   # t  Tags
   # s  Statustext (will take available space)
   # y  Systray (can be set only ONE time among all element)
+  # l  Launcher (will be expended at launcher use)
 
   [bar]
      position = 0
      screen = 0
-     elements = "tsy"   # element order in bar
+     elements = "tlsy"   # element order in bar
      theme = "default"
   [/bar]
 
@@ -135,6 +136,22 @@
 
 [/rules]
 
+[launchers]
+
+  # command can be an uicb function or an uicb function + extension (see example)
+  [launcher]
+     name = "exec"
+     prompt = "Run:"
+
+     # Example of uicb + ext:
+     #   command = "spawn xterm -e"
+     command = "spawn"
+
+     width = 150
+  [/launcher]
+
+[/launchers]
+
 [keys]
 
   [key] mod = {"Super"} key = "Return" func = "spawn" cmd = "urxvt || xterm" [/key]
@@ -215,6 +232,9 @@
 
   # Layout set historic travelling function (TESTING)
   [key] mod = {"Super"} key = "o" func = "layout_prev_set" [/key]
-  [key] mod = {"Super"} key = "p" func = "layout_next_set" [/key]
+  [key] mod = {"Super", "Shift"} key = "o" func = "layout_next_set" [/key]
+
+  # Launcher
+  [key] mod = {"Super"} key = "p" func = "launcher" cmd = "exec" [/key]
 
 [/keys]