class Subtle::Config

  1. src/subtle/ruby.c
Superclass: Object

Document-class: Config

Config class for DSL evaluation

Methods

Public Instance

  1. grab
  2. gravity
  3. on
  4. screen
  5. set
  6. style
  7. sublet
  8. tag
  9. view

Public Instance methods

grab(chain, value) -> nil
grab(chain, &blk) -> nil

Create a new grab either to start a program, with a predefined action or with a code block or start a program

grab "W-Return", "urxvt"

grab "W-S-1", :ViewJump1

grab "A-F2" do |c|
  puts c.name
end

grab "S-F3" do
  puts Subtlext::VERSION
end
[show source]
static VALUE
RubyConfigGrab(int argc,
  VALUE *argv,
  VALUE self)
{
  VALUE chain = Qnil, value = Qnil;

  rb_scan_args(argc, argv, "11", &chain, &value);

  if(rb_block_given_p()) value = rb_block_proc(); ///< Get proc

  RubyEvalGrab(chain, value);

  return Qnil;
}
gravity(name, value, tile) -> nil

Create a new gravity and optionally enable tiling, either horizonally (:horz) or vertically. (:vert) inside of the grid

subforge.org/projects/subtle/wiki/Gravity

gravity :top_left, [0, 0, 50, 50]

gravity :top_left, [0, 0, 50, 50], :vert
[show source]
static VALUE
RubyConfigGravity(int argc,
  VALUE *argv,
  VALUE self)
{
  VALUE name = Qnil, value = Qnil, tile = Qnil;

  rb_scan_args(argc, argv, "21", &name, &value, &tile);

  /* Check value type */
  if(T_SYMBOL == rb_type(name) && T_ARRAY == rb_type(value))
    {
      XRectangle geometry = { 0 };

      RubyArrayToGeometry(value, &geometry);

      /* Skip on checking only */
      if(!(subtle->flags & SUB_SUBTLE_CHECK))
        {
          SubGravity *g = NULL;

          /* Finally create new gravity */
          if((g = subGravityNew(SYM2CHAR(name), &geometry)))
            {
              /* Tile just clients with this gravity */
              if(T_SYMBOL == rb_type(tile))
                {
                  if(CHAR2SYM("horz")      == tile) g->flags |= SUB_GRAVITY_HORZ;
                  else if(CHAR2SYM("vert") == tile) g->flags |= SUB_GRAVITY_VERT;
                }

              subArrayPush(subtle->gravities, (void *)g);
            }
        }
    }
  else rb_raise(rb_eArgError, "Unknown value type for gravity");

  return Qnil;
}
on(event, &block) -> nil

Create a new event handler for a hook

on :client_focus do |s|
  puts s.name
end
[show source]
static VALUE
RubyConfigOn(int argc,
  VALUE *argv,
  VALUE self)
{
  VALUE event = Qnil, value = Qnil;

  rb_scan_args(argc, argv, "11", &event, &value);

  /* Check value type */
  if(T_SYMBOL == rb_type(event))
    {
      if(subtle->flags & SUB_SUBTLE_CHECK) return Qnil; ///< Skip on check

      if(rb_block_given_p()) value = rb_block_proc(); ///< Get proc

      RubyEvalHook(event, value);
    }
  else rb_raise(rb_eArgError, "Unknown value type for on");

  return Qnil;
}
screen(screenid, blk) -> nil

Split a physical screen in virtual ones

subforge.org/projects/subtle/wiki/Config/#Screens

screen 1 do
  virtual [  0, 0, 50, 100 ]
  virtual [ 50, 0, 50, 100 ]
end
[show source]
static VALUE
RubyConfigScreen(VALUE self,
  VALUE screenid)
{
  rb_need_block();

  /* Check value type */
  if(FIXNUM_P(screenid))
    {
      int idx = FIX2INT(screenid);
      VALUE klass = Qnil, options = Qnil, params = Qnil, value = Qnil;
      if(subtle->flags & SUB_SUBTLE_CHECK) return Qnil; ///< Skip on check

      /* Sanity check */
      if(idx - 1 > subtle->screens->ndata)
        {
          rb_raise(rb_eArgError, "Invalid screeen id `%d'", idx);

          return Qnil;
        }

      /* Collect options */
      klass   = rb_const_get(mod, rb_intern("Options"));
      options = rb_funcall(klass, rb_intern("new"), 1, self);
      rb_obj_instance_eval(0, 0, options);
      params  = rb_iv_get(options, "@params");

      /* Eval virtuals */
      if(T_ARRAY == rb_type(value = rb_hash_lookup(params,
          CHAR2SYM("virtual"))))
        {
          int i, count = 0, vgeom[4] = { 0 };
          VALUE entry = Qnil;
          SubScreen *s = SCREEN(subArrayGet(subtle->screens, idx - 1));

          if(s && !(s->flags & SUB_SCREEN_VIRTUAL)) ///< Do this just once
            {
              for(i = 0; Qnil != (entry = rb_ary_entry(value, i)); i++)
                {
                  if(FIXNUM_P(entry))
                    {
                      vgeom[count++] = FIX2INT(entry);

                      if(4 == count)
                        {
                          SubScreen *vscreen = NULL;

                          vscreen = subScreenNew(
                            s->geom.x + (s->geom.width *  vgeom[0] / 100),
                            s->geom.y + (s->geom.height * vgeom[1] / 100),
                            s->geom.width  * vgeom[2] / 100,
                            s->geom.height * vgeom[3] / 100);
                          vscreen->flags |= SUB_SCREEN_VIRTUAL;

                          subArrayInsert(subtle->screens,
                            (idx++ - 1), (void *)vscreen);

                          count = 0;
                        }
                    }
                }

              subArrayRemove(subtle->screens, (void *)s);

              subScreenResize();
            }
        }
    }
  else rb_raise(rb_eArgError, "Unexpected value type for screen `%s'",
    rb_obj_classname(screenid));

  return Qnil;
}
set(option, value) -> nil

Set various WM options

subforge.org/projects/subtle/wiki/Config#Settings

set :urgent_dialogs, true
[show source]
static VALUE
RubyConfigSet(VALUE self,
  VALUE option,
  VALUE value)
{
  /* Check value type */
  if(T_SYMBOL == rb_type(option))
    {
      switch(rb_type(value))
        {
          case T_FIXNUM: /* {{{ */
            if(CHAR2SYM("step") == option ||
                CHAR2SYM("increase_step") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK))
                  subtle->step = FIX2INT(value);
              }
            else if(CHAR2SYM("snap") == option ||
                CHAR2SYM("border_snap") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK))
                  subtle->snap = FIX2INT(value);
              }
            else if(CHAR2SYM("gravity") == option ||
                CHAR2SYM("default_gravity") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK))
                  subtle->gravity = value; ///< Store for later
              }
            else subSubtleLogWarn("Unknown option `:%s'\n", SYM2CHAR(option));
            break; /* }}} */
          case T_SYMBOL: /* {{{ */
            if(CHAR2SYM("gravity") == option ||
                CHAR2SYM("default_gravity") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK))
                  subtle->gravity = value; ///< Store for later
              }
            else subSubtleLogWarn("Unknown option `:%s'\n", SYM2CHAR(option));
            break; /* }}} */
          case T_TRUE:
          case T_FALSE: /* {{{ */
            if(CHAR2SYM("urgent") == option ||
                CHAR2SYM("urgent_dialogs") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK) && Qtrue == value)
                  subtle->flags |= SUB_SUBTLE_URGENT;
              }
            else if(CHAR2SYM("resize") == option ||
                CHAR2SYM("honor_size_hints") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK) && Qtrue == value)
                  subtle->flags |= SUB_SUBTLE_RESIZE;
              }
            else if(CHAR2SYM("tiling") == option ||
                CHAR2SYM("gravity_tiling") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK) && Qtrue == value)
                  subtle->flags |= SUB_SUBTLE_TILING;
              }
            else if(CHAR2SYM("click_to_focus") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK) && Qtrue == value)
                  subtle->flags |= SUB_SUBTLE_FOCUS_CLICK;
              }
            else if(CHAR2SYM("skip_pointer_warp") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK) && Qtrue == value)
                  subtle->flags |= SUB_SUBTLE_SKIP_WARP;
              }
            else if(CHAR2SYM("skip_urgent_warp") == option)
              {
                if(!(subtle->flags & SUB_SUBTLE_CHECK) && Qtrue == value)
                  subtle->flags |= SUB_SUBTLE_SKIP_URGENT_WARP;
              }
            else subSubtleLogWarn("Unknown option `:%s'\n", SYM2CHAR(option));
            break; /* }}} */
          case T_STRING: /* {{{ */
            if(CHAR2SYM("wmname") == option)
              {
                /* Set support window to root (broken Java)
                 * and update WM_NAME */
                if(!(subtle->flags & SUB_SUBTLE_CHECK))
                  {
                    Window root = ROOT;

                    subEwmhSetWindows(ROOT,
                      SUB_EWMH_NET_SUPPORTING_WM_CHECK, &root, 1);
                    subEwmhSetString(root, SUB_EWMH_NET_WM_NAME,
                      RSTRING_PTR(value));
                  }
              }
            else subSubtleLogWarn("Unknown option `:%s'\n", SYM2CHAR(option));
            break; /* }}} */
          default:
            rb_raise(rb_eArgError, "Unexpected value type for option `%s'",
              SYM2CHAR(option));
        }
    }
  else rb_raise(rb_eArgError, "Unexpected value type for set");

  return Qnil;
}
style(name, blk) -> nil

Set propeties of named styles

style :title do
  foreground "#fecf35"
end
[show source]
static VALUE
RubyConfigStyle(VALUE self,
  VALUE name)
{
  rb_need_block();

  /* Check value type */
  if(T_SYMBOL == rb_type(name))
    {
      SubStyle *style = NULL;
      VALUE klass = Qnil, options = Qnil, styles = Qnil;

      /* Select style struct */
      if(CHAR2SYM("all")               == name) style = &subtle->styles.all;
      else if(CHAR2SYM("views")        == name) style = &subtle->styles.views;
      else if(CHAR2SYM("title")        == name) style = &subtle->styles.title;
      else if(CHAR2SYM("sublets")      == name) style = &subtle->styles.sublets;
      else if(CHAR2SYM("separator")    == name) style = &subtle->styles.separator;
      else if(CHAR2SYM("clients")      == name) style = &subtle->styles.clients;
      else if(CHAR2SYM("panel_top")    == name) style = &subtle->styles.panel_top;
      else if(CHAR2SYM("panel_bottom") == name) style = &subtle->styles.panel_bot;
      else if(CHAR2SYM("tray")         == name) style = &subtle->styles.tray;
      else
        {
          subSubtleLogWarn("Unexpected style name `:%s'\n", SYM2CHAR(name));

          return Qnil;
        }

      if(subtle->flags & SUB_SUBTLE_CHECK) return Qnil; ///< Skip on check

      /* Collect options */
      klass   = rb_const_get(mod, rb_intern("Options"));
      options = rb_funcall(klass, rb_intern("new"), 1, self);
      rb_obj_instance_eval(0, 0, options);

      /* Eval style before nested styles */
      RubyEvalStyle(name, style, rb_iv_get(options, "@params"));

      /* Eval styles */
      if(T_HASH == rb_type((styles = rb_iv_get(options, "@styles"))))
        rb_hash_foreach(styles, RubyForeachStyle, (VALUE)style);
    }
  else rb_raise(rb_eArgError, "Unexpected value type for style `%s'",
    rb_obj_classname(name));

  return Qnil;
}
sublet(name, blk) -> nil

Set properties of sublets

subforge.org/projects/subtle/wiki/Sublets

sublet :clock do
  interval 20
  foreground    "#eeeeee"
  background    "#000000"
  format_string "%H:%M:%S"
end
[show source]
static VALUE
RubyConfigSublet(VALUE self,
  VALUE sublet)
{
  VALUE klass = Qnil, options = Qnil;

  rb_need_block();

  /* Check value type */
  if(T_SYMBOL == rb_type(sublet))
    {
      /* Collect options */
      klass   = rb_const_get(mod, rb_intern("Options"));
      options = rb_funcall(klass, rb_intern("new"), 1, self);
      rb_obj_instance_eval(0, 0, options);

      /* Clone to get rid of object instance and store it */
      rb_hash_aset(config_sublets, sublet,
        rb_obj_clone(rb_iv_get(options, "@params")));
    }
  else rb_raise(rb_eArgError, "Unknown value type for sublet");

  return Qnil;
}
tag(name, regex) -> nil
tag(name, blk) -> nil

Create a new tag either with a regexp or with a block to set additional properties

subforge.org/projects/subtle/wiki/Tagging

tag "terms", "xterm|[u]?rxvt"

tag "terms" do
  match "xterm|[u]?rxvt"
  gravity :center
end
[show source]
static VALUE
RubyConfigTag(int argc,
  VALUE *argv,
  VALUE self)
{
  int flags = 0, screenid = -1;
  unsigned long gravityid = 0;
  XRectangle geom = { 0 };
  VALUE name = Qnil, match = Qnil, params = Qnil, value = Qnil, proc = Qnil;

  rb_scan_args(argc, argv, "11", &name, &match);

  /* Call proc */
  if(rb_block_given_p())
    {
      VALUE klass = Qnil, options = Qnil;

      /* Collect options */
      klass   = rb_const_get(mod, rb_intern("Options"));
      options = rb_funcall(klass, rb_intern("new"), 1, self);
      rb_obj_instance_eval(0, 0, options);
      params  = rb_iv_get(options, "@params");

      /* Check matcher */
      if(!NIL_P(value = rb_hash_lookup(params, CHAR2SYM("match"))))
        match = value; ///< Lazy eval

      /* Set gravity */
      if(T_SYMBOL == rb_type(value = rb_hash_lookup(params,
          CHAR2SYM("gravity"))) || T_FIXNUM == rb_type(value) ||
          T_ARRAY == rb_type(value))
        {
          flags     |= SUB_TAG_GRAVITY;
          gravityid  = value; ///< Lazy eval
        }

      /* Set geometry */
      if(T_ARRAY == rb_type(value = rb_hash_lookup(params,
          CHAR2SYM("geometry"))))
        {
          flags |= SUB_TAG_GEOMETRY;
          RubyArrayToGeometry(value, &geom);
        }

      /* Set position */
      if(T_ARRAY == rb_type(value = rb_hash_lookup(params,
          CHAR2SYM("position"))))
        {
          flags |= SUB_TAG_POSITION;
          RubyArrayToGeometry(value, &geom);
        }

      /* Set window type */
      if(T_SYMBOL == rb_type(value = rb_hash_lookup(params,
          CHAR2SYM("type"))))
        RubySymbolToFlag(value, &flags);

      /* Set modes */
      if(T_SYMBOL == rb_type(value = rb_hash_lookup(params,
          CHAR2SYM("set"))))
        {
          RubySymbolToFlag(value, &flags);
        }
      else if(T_ARRAY == rb_type(value))
        {
          int i;
          VALUE entry = Qnil;

          /* Translate modes */
          for(i = 0; Qnil != (entry = rb_ary_entry(value, i)); i++)
            RubySymbolToFlag(entry, &flags);
        }

      /* Set stick screen */
      if(RTEST(value = rb_hash_lookup(params, CHAR2SYM("stick_to"))))
        {
          /* Set screen id if any */
          if(FIXNUM_P(value))
            {
              screenid  = FIX2INT(value);
              flags    |= (SUB_CLIENT_MODE_STICK|SUB_CLIENT_MODE_STICK_SCREEN);
            }
        }

      /* Set match proc */
      if(RTEST(value = rb_hash_lookup(params, CHAR2SYM("on_match"))))
        {
          proc   = value;
          flags |= SUB_TAG_PROC;

          rb_ary_push(shelter, proc); ///< Protect from GC
        }
    }

  /* Check value type */
  if(T_STRING == rb_type(name))
    {
      /* Skip on checking only */
      if(!(subtle->flags & SUB_SUBTLE_CHECK))
        {
          int duplicate = False;
          SubTag *t = NULL;

          /* Finally create and add new tag if no duplicate */
          if((t = subTagNew(RSTRING_PTR(name), &duplicate)) &&
              False == duplicate)
            {
              int i;
              VALUE entry = Qnil, rargs[2] = { 0 };

              /* Set tag values */
              t->flags     |= flags;
              t->gravityid  = gravityid;
              t->screenid   = screenid;
              t->geom       = geom;
              t->proc       = proc;

              /* Add matcher */
              rargs[0] = (VALUE)t;
              switch(rb_type(match))
                {
                  case T_HASH:
                    rargs[1] = 0; ///< Reset matcher count
                    rb_hash_foreach(match, RubyForeachMatcher, (VALUE)&rargs);
                    break;
                  case T_ARRAY:
                    for(i = 0; T_HASH == rb_type(entry =
                        rb_ary_entry(match, i)); i++)
                      {
                        rargs[1] = 0; ///< Reset matcher count
                        rb_hash_foreach(entry, RubyForeachMatcher, (VALUE)&rargs);
                      }
                    break;
                  case T_REGEXP:
                  case T_STRING:
                    RubyForeachMatcher(Qnil, match, (VALUE)&rargs);
                }

              subArrayPush(subtle->tags, (void *)t);
            }
        }
    }
  else rb_raise(rb_eArgError, "Unknown value type for tag");

  return Qnil;
}
view(name, regex) -> nil

Create a new view with a regex to match tags

subforge.org/projects/subtle/wiki/Views

view "foobar", "regex"
[show source]
static VALUE
RubyConfigView(int argc,
  VALUE *argv,
  VALUE self)
{
  int flags = 0;
  VALUE name = Qnil, match = Qnil, params = Qnil, value = Qnil, icon = value;

  rb_scan_args(argc, argv, "11", &name, &match);

  /* Call proc */
  if(rb_block_given_p())
    {
      VALUE klass = Qnil, options = Qnil;

      /* Collect options */
      klass    = rb_const_get(mod, rb_intern("Options"));
      options  = rb_funcall(klass, rb_intern("new"), 1, self);
      rb_obj_instance_eval(0, 0, options);
      params  = rb_iv_get(options, "@params");

      /* Check match */
      match = rb_hash_lookup(params, CHAR2SYM("match")); ///< Lazy eval

      /* Set modes */
      if(T_SYMBOL == rb_type(value = rb_hash_lookup(params,
          CHAR2SYM("set"))))
        {
          RubySymbolToFlag(value, &flags);
        }
      else if(T_ARRAY == rb_type(value))
        {
          int i;
          VALUE entry = Qnil;

          /* Translate modes */
          for(i = 0; Qnil != (entry = rb_ary_entry(value, i)); i++)
            RubySymbolToFlag(entry, &flags);
        }

      /* Check icon */
      icon = RubyValueToIcon(rb_hash_lookup(params, CHAR2SYM("icon")));
    }

  /* Check value type */
  if(T_STRING == rb_type(name))
    {
      /* Skip on checking only */
      if(!(subtle->flags & SUB_SUBTLE_CHECK))
        {
          SubView *v = NULL;
          char *re = NULL;

          /* Convert type */
          switch(rb_type(match))
            {
              case T_REGEXP:
                match = rb_funcall(match, rb_intern("source"), 0, NULL);
              case T_STRING:
                re = RSTRING_PTR(match);
                break;
            }

          /* Finally create new view */
          if((v = subViewNew(RSTRING_PTR(name), re)))
            {
              v->flags |= flags;

              subArrayPush(subtle->views, (void *)v);

              /* Add icon */
              if(!NIL_P(icon))
                {
                  v->flags |= SUB_VIEW_ICON;
                  v->icon   = ICON(subSharedMemoryAlloc(1, sizeof(SubIcon)));

                  RubyIconToIcon(icon, v->icon);

                  rb_ary_push(shelter, icon); ///< Protect from GC
                }
              else v->flags &= ~SUB_VIEW_ICON_ONLY;
            }
       }
    }
  else rb_raise(rb_eArgError, "Unknown value type for view");

  return Qnil;
}