Class Subtle::Config < Object

Public instance methods

grab(chain, value) → nil
grab(chain, &blk) → nil

Create grabs

1 grab "A-F1", :ViewJump1
[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 gravity and optionally enable tiling, either horizonally (:horz) or vertically. (: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;
}
load_config(file) → true or false

Load config file

1 load_config "gravities.rb"
2 => true
[show source]
static VALUE
RubyConfigLoadConfig(VALUE self,
  VALUE file)
{
  int state = 0;
  char buf[100] = { 0 };
  VALUE rargs[2] = { Qnil };

  /* Check if file exists otherwise try to find it */
  if(-1 == access(RSTRING_PTR(file), R_OK))
    {
      int len = 0;
      char *home = NULL, *dirs = NULL, *tok = NULL,
        tokens[200] = { 0 }, *tokensp = tokens;

      /* Combine XDG paths */
      if((home = getenv("XDG_CONFIG_HOME")))
        len += snprintf(tokens, sizeof(tokens), "%s", home);
      else len += snprintf(tokens, sizeof(tokens), "%s/.config",
        getenv("HOME"));

      if((dirs = getenv("XDG_CONFIG_DIRS")))
        len += snprintf(tokens + len, sizeof(tokens), ":%s", dirs);
      else len += snprintf(tokens + len, sizeof(tokens), ":%s/%s",
        "/etc/xdg", PKG_NAME);

      if((home = getenv("XDG_DATA_HOME")))
        {
          snprintf(buf, sizeof(buf), "%s:%s/%s/sublets",
            tokens, home, PKG_NAME);
        }
      else snprintf(buf, sizeof(buf), "%s:%s/.local/share/%s/sublets",
        tokens, getenv("HOME"), PKG_NAME);

      /* Search file in XDG paths */
      while((tok = strsep(&tokensp, ":")))
        {
          /* Check if config file exists in tok or tok/subtle */
          snprintf(buf, sizeof(buf), "%s/%s", tok, RSTRING_PTR(file));

          if(-1 != access(buf, R_OK)) break;
          else
            {
              snprintf(buf, sizeof(buf), "%s/%s/%s",
                tok, PKG_NAME, RSTRING_PTR(file));

              if(-1 != access(buf, R_OK)) break;
            }
        }
    }
  else snprintf(buf, sizeof(buf), "%s", RSTRING_PTR(file));

  printf("Reading file `%s'\n", buf);

  /* Carefully load and eval file */
  rargs[0] = rb_str_new2(buf);
  rargs[1] = self;

  rb_protect(RubyWrapEvalFile, (VALUE)&rargs, &state);
  if(state)
    {
      subSubtleLogWarn("Cannot load file `%s'\n", buf);
      RubyBacktrace();

      return Qfalse;
    }

  return Qtrue;
}
method_missing (...)

Check error of missing methods

[show source]
static VALUE
RubyConfigMissing(int argc,
  VALUE *argv,
  VALUE self)
{
  char *name = NULL;
  VALUE missing = Qnil, args = Qnil;

  rb_scan_args(argc, argv, "1*", &missing, &args);

  name = (char *)rb_id2name(SYM2ID(missing));

  subSubtleLogWarn("Cannot find method `%s'\n", name);

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

Event block for hooks

[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(name, blk) → nil

Set options for screen

[show source]
static VALUE
RubyConfigScreen(VALUE self,
  VALUE id)
{
  VALUE params = Qnil, value = Qnil, klass = Qnil, options = Qnil;
  SubScreen *s = NULL;

  /* FIXME: rb_need_block() */
  if(!rb_block_given_p()) 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");

  /* Check value type */
  if(FIXNUM_P(id))
    {
      int flags = 0, vid = -1;
      Pixmap stipple = None;
      VALUE top = Qnil, bottom = Qnil;

      /* Get options */
      if(T_HASH == rb_type(params))
        {
          if(!NIL_P(value = RubyValueToIcon(rb_hash_lookup(params,
              CHAR2SYM("stipple")))))
            {
              flags   |= SUB_SCREEN_STIPPLE;
              stipple  = NUM2LONG(rb_iv_get(value, "@pixmap"));
            }
          if(T_ARRAY == rb_type(value = rb_hash_lookup(params,
              CHAR2SYM("top"))))
            {
              top = value; /// Lazy eval
              rb_ary_push(shelter, value); ///< Protect from GC
            }
          if(T_ARRAY == rb_type(value = rb_hash_lookup(params,
              CHAR2SYM("bottom"))))
            {
              bottom = value; ///< Lazy eval
              rb_ary_push(shelter, value); ///< Protect from GC
            }
          if(T_FIXNUM == rb_type(value = rb_hash_lookup(params,
              CHAR2SYM("view"))))
            vid = FIX2INT(value);
        }

      /* Skip on checking only */
      if(!(subtle->flags & SUB_SUBTLE_CHECK))
        {
          if((s = subArrayGet(subtle->screens, FIX2INT(id) - 1)))
            {
              s->flags   |= (flags|SUB_RUBY_DATA);
              s->top      = top;
              s->bottom   = bottom;
              s->stipple  = stipple;

              if(-1 != vid) s->viewid = vid;
            }
        }
    }
  else rb_raise(rb_eArgError, "Unknown value type for screen");

  return Qnil;
}
set(option, value) → nil

Set options

[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;
}
singleton_method_added (p1)

Updated methods list when singleton methods are added

[show source]
static VALUE
RubyConfigAdded(VALUE self,
  VALUE name)
{
  /* Append method name to methods list */
  rb_ary_push(config_methods, name);

  subSubtleLogDebugRuby("Added: singleton method=`%s'\n", SYM2CHAR(name));

  return Qnil;
}
style(name, blk) → nil

Add style values

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

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

      /* Select style struct */
      if(CHAR2SYM("all")            == name) s = &subtle->styles.all;
      else if(CHAR2SYM("views")     == name) s = &subtle->styles.views;
      else if(CHAR2SYM("title")     == name) s = &subtle->styles.title;
      else if(CHAR2SYM("sublets")   == name) s = &subtle->styles.sublets;
      else if(CHAR2SYM("separator") == name) s = &subtle->styles.separator;
      else if(CHAR2SYM("clients")   == name) s = &subtle->styles.clients;
      else if(CHAR2SYM("subtle")    == name) s = &subtle->styles.subtle;
      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 styles */
      RubyEvalStyle(name, s, rb_iv_get(options, "@params"));

      /* Eval styles */
      if(T_HASH == rb_type((styles = rb_iv_get(options, "@styles"))))
        rb_hash_foreach(styles, RubyForeachStyle, (VALUE)s);

    }
  else rb_raise(rb_eArgError, "Unexpected value type for style `%s'",
    rb_obj_classname(name));

  return Qnil;
}
sublet(name, blk) → nil

Configure a sublet

[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

Add a new tag

1 tag "foobar", "regex"
2 
3 tag "foobar" do
4   regex = "foobar"
5 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(T_ARRAY == rb_type(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 geometry */
      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"))))
        {
          /* Check type */
          if(CHAR2SYM("normal")       == value) flags = SUB_CLIENT_TYPE_NORMAL;
          else if(CHAR2SYM("desktop") == value) flags = SUB_CLIENT_TYPE_DESKTOP;
          else if(CHAR2SYM("dock")    == value) flags = SUB_CLIENT_TYPE_DOCK;
          else if(CHAR2SYM("toolbar") == value) flags = SUB_CLIENT_TYPE_TOOLBAR;
          else if(CHAR2SYM("splash")  == value) flags = SUB_CLIENT_TYPE_SPLASH;
          else if(CHAR2SYM("dialog")  == value) flags = SUB_CLIENT_TYPE_DIALOG;
        }

      /* Check state properties */
      if(Qtrue == (value = rb_hash_lookup(params,
        CHAR2SYM("borderless")))) flags |= SUB_CLIENT_MODE_BORDERLESS;

      if(Qtrue == (value = rb_hash_lookup(params,
        CHAR2SYM("center")))) flags |= SUB_CLIENT_MODE_CENTER;

      if(Qtrue == (value = rb_hash_lookup(params,
        CHAR2SYM("fixed")))) flags |= SUB_CLIENT_MODE_FIXED;

      if(Qtrue == (value = rb_hash_lookup(params,
        CHAR2SYM("float")))) flags |= SUB_CLIENT_MODE_FLOAT;

      if(Qtrue == (value = rb_hash_lookup(params,
        CHAR2SYM("full")))) flags |= SUB_CLIENT_MODE_FULL;

      if(Qtrue == (value = rb_hash_lookup(params,
        CHAR2SYM("resize")))) flags |= SUB_CLIENT_MODE_RESIZE;

      if(Qtrue == (value = rb_hash_lookup(params,
        CHAR2SYM("urgent")))) flags |= SUB_CLIENT_MODE_URGENT;

      if(Qtrue == (value = rb_hash_lookup(params,
        CHAR2SYM("zaphod")))) flags |= SUB_CLIENT_MODE_ZAPHOD;

      /* Set stick screen */
      if(RTEST(value = rb_hash_lookup(params, CHAR2SYM("stick"))))
        {
          /* Either screen id or just true */
          if(FIXNUM_P(value))
            {
              screenid  = FIX2INT(value);
              flags    |= SUB_CLIENT_MODE_STICK;
            }
          else if(Qtrue == value) flags |= SUB_CLIENT_MODE_STICK;
        }

      /* 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_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

Add a new view

1 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 */
      if(T_ARRAY == rb_type(value = rb_hash_lookup(params,
          CHAR2SYM("match"))))
        match = rb_hash_lookup(rb_ary_entry(value, 0), Qnil); ///< Lazy eval

      /* Check dynamic */
      if(Qtrue == (value = rb_hash_lookup(params,
          CHAR2SYM("dynamic"))))
        flags |= SUB_VIEW_DYNAMIC;

      /* Check icon only */
      if(Qtrue == (value = rb_hash_lookup(params,
          CHAR2SYM("icon_only"))))
        flags |= SUB_VIEW_ICON_ONLY;

      /* 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;
}