Class Subtle::Sublet < Object

Sublet class for interaction with sublets

Public instance methods

config → Hash

Get config hash from config

1 s.config
2 => { :interval => 30 }
[show source]
static VALUE
RubySubletConfig(VALUE self)
{
  SubPanel *p = NULL;
  VALUE hash = Qnil;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      /* Get config hash */
      if(NIL_P(hash = rb_hash_lookup(config_sublets, CHAR2SYM(p->sublet->name))))
        hash = rb_hash_new();
    }

  return hash;
}
configure → nil

Configure block for Sublet

[show source]
static VALUE
RubySubletConfigure(VALUE self,
  VALUE name)
{
  rb_need_block();

  /* Check value type */
  if(T_SYMBOL == rb_type(name))
    {
      SubPanel *p = NULL;

      Data_Get_Struct(self, SubPanel, p);
      if(p)
        {
          VALUE proc = Qnil;

          /* Assume latest sublet */
          proc            = rb_block_proc();
          p->sublet->name = strdup(SYM2CHAR(name));

          /* Define configure method */
          rb_funcall(rb_singleton_class(p->sublet->instance),
            rb_intern("define_method"),
            2, CHAR2SYM("__configure"), proc);
        }
    }
  else rb_raise(rb_eArgError, "Unknown value type for configure");

  return Qnil;
}
data → String or nil

Get data of Sublet

1 puts sublet.data
2 => "subtle"
[show source]
static VALUE
RubySubletDataReader(VALUE self)
{
  int i;
  VALUE string = Qnil;
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      if(0 < p->sublet->text->nitems)
        {
          /* Concat string */
          for(i = 0; i < p->sublet->text->nitems; i++)
            {
              SubTextItem *item = (SubTextItem *)p->sublet->text->items[i];

              if(Qnil == string) rb_str_new2(item->data.string);
              else rb_str_cat(string, item->data.string, strlen(item->data.string));
            }
        }
    }

  return string;
}
data=(string) → nil

Set data of Sublet

1 sublet.data = "subtle"
2 => nil
[show source]
static VALUE
RubySubletDataWriter(VALUE self,
  VALUE value)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      /* Check value type */
      if(T_STRING == rb_type(value))
        {
          SubStyle *s = &subtle->styles.sublets, *style = NULL;

          /* Select style */
          if(s->styles && (style = subArrayGet(s->styles, p->sublet->styleid)))
              s = style;

          p->sublet->width = subTextParse(p->sublet->text,
            subtle->styles.sublets.font, RSTRING_PTR(value)) +
            STYLE_WIDTH((*s));
        }
      else rb_raise(rb_eArgError, "Unknown value type");
    }

  return Qnil;
}
geometry → Subtlext::Geometry

Get geometry of a sublet

1 sublet.geometry
2 => #<Subtlext::Geometry:xxx>
[show source]
VALUE
RubySubletGeometryReader(VALUE self)
{
  SubPanel *p = NULL;
  VALUE geometry = Qnil;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      SubStyle *s = NULL;
      XRectangle geom = { 0 };
      VALUE subtlext = Qnil, klass = Qnil;

      /* Pick sublet style */
      if(subtle->styles.sublets.styles)
        s = subArrayGet(subtle->styles.sublets.styles, p->sublet->styleid);

      subPanelGeometry(p, s ? s : &subtle->styles.sublets, &geom);

      /* Create geometry object */
      subtlext = rb_const_get(rb_mKernel, rb_intern("Subtlext"));
      klass    = rb_const_get(subtlext, rb_intern("Geometry"));
      geometry = rb_funcall(klass, rb_intern("new"), 4,
        INT2FIX(geom.x), INT2FIX(geom.y), INT2FIX(geom.width),
        INT2FIX(geom.height));
    }

  return geometry;
}
grab(chain, &block) → nil

Add grabs to sublets

1 grab "A-b" do |s|
2   puts s.name
3 end
[show source]
static VALUE
RubySubletGrab(VALUE self,
  VALUE name)
{
  /* Check value type */
  if(T_SYMBOL == rb_type(name) && rb_block_given_p())
    {
      SubPanel *p = NULL;

      Data_Get_Struct(self, SubPanel, p);
      if(p)
        {
          int i;
          char buf[64] = { 0 };
          VALUE meth = Qnil;

          /* Add proc as instance method */
          snprintf(buf, sizeof(buf), "__grab_%s", SYM2CHAR(name));

          rb_funcall(rb_singleton_class(p->sublet->instance),
            rb_intern("define_method"), 2, CHAR2SYM(buf), rb_block_proc());

          meth = rb_obj_method(p->sublet->instance, CHAR2SYM(buf));

          /* Find grabs with this symbol */
          for(i = 0; i < subtle->grabs->ndata; i++)
            {
              SubGrab *g = GRAB(subtle->grabs->data[i]);

              if(g->flags & SUB_RUBY_DATA && g->data.num == name)
                {
                  g->flags    ^= (SUB_RUBY_DATA|SUB_GRAB_PROC);
                  g->data.num  = (unsigned long)meth;

                  rb_ary_push(shelter, meth); ///< Protect from GC
                }
            }
        }
    }
  else rb_raise(rb_eArgError, "Unknown value type for grab");

  return Qnil;
}
helper → nil

Helper block for Sublet

1 helper do |s|
2   def test
3     puts "test"
4   end
5 end
[show source]
static VALUE
RubySubletHelper(VALUE self)
{
  SubPanel *p = NULL;

  rb_need_block();

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      /* Instance eval the block */
      rb_yield_values(1, p->sublet->instance);
      rb_obj_instance_eval(0, 0, p->sublet->instance);
    }

  return Qnil;
}
hide → nil

Hide sublet from panel

1 sublet.hide
2 => nil
[show source]
static VALUE
RubySubletHide(VALUE self,
  VALUE value)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      p->flags |= SUB_PANEL_HIDDEN;

      /* Update screens */
      subScreenUpdate();
      subScreenRender();
    }

  return Qnil;
}
interval → Fixnum

Get interval time of Sublet

1 puts sublet.interval
2 => 60
[show source]
static VALUE
RubySubletIntervalReader(VALUE self)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);

  return p ? INT2FIX(p->sublet->interval) : Qnil;
}
interval=(fixnum) → nil

Set interval time of Sublet

1 sublet.interval = 60
2 => nil
[show source]
static VALUE
RubySubletIntervalWriter(VALUE self,
  VALUE value)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      if(FIXNUM_P(value))
        {
          p->sublet->interval = FIX2INT(value);
          p->sublet->time     = subSubtleTime() + p->sublet->interval;

          if(0 < p->sublet->interval)
            p->sublet->flags |= SUB_SUBLET_INTERVAL;
          else p->sublet->flags &= ~SUB_SUBLET_INTERVAL;
        }
      else rb_raise(rb_eArgError, "Unknown value type `%s'", rb_obj_classname(value));
    }

  return Qnil;
}
method_missing (...)

Dispatcher for Sublet instance variables - internal use only

[show source]
static VALUE
RubySubletDispatcher(int argc,
  VALUE *argv,
  VALUE self)
{
  VALUE missing = Qnil, args = Qnil, ret = Qnil;

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

  /* Dispatch calls */
  if(rb_respond_to(self, rb_to_id(missing))) ///< Intance methods
    ret = rb_funcall2(self, rb_to_id(missing), --argc, ++argv);
  else ///< Instance variables
    {
      char buf[20] = { 0 };
      char *name = (char *)rb_id2name(SYM2ID(missing));

      snprintf(buf, sizeof(buf), "@%s", name);

      if(index(name, '='))
        {
          int len = 0;
          VALUE value = Qnil;

          value    = rb_ary_entry(args, 0); ///< Get first arg
          len      = strlen(name);
          buf[len] = '\0'; ///< Overwrite equal sign

          rb_funcall(self, rb_intern("instance_variable_set"), 2, CHAR2SYM(buf), value);
        }
      else ret = rb_funcall(self, rb_intern("instance_variable_get"), 1, CHAR2SYM(buf));
    }

  return ret;
}
name → String

Get name of Sublet

1 puts sublet.name
2 => "sublet"
[show source]
static VALUE
RubySubletNameReader(VALUE self)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);

  return p ? rb_str_new2(p->sublet->name) : Qnil;
}
on(event, &block) → nil

Event block for hooks

[show source]
static VALUE
RubySubletOn(VALUE self,
  VALUE event)
{
  /* Check value type */
  if(T_SYMBOL == rb_type(event) && rb_block_given_p())
    {
      SubPanel *p = NULL;

      Data_Get_Struct(self, SubPanel, p);
      if(p)
        {
          char buf[64] = { 0 };
          int i, arity = 0;
          VALUE proc = Qnil, sing = Qnil, meth = Qnil;

          RubyMethods methods[] =
          {
            { CHAR2SYM("run"),        CHAR2SYM("__run"),    SUB_SUBLET_RUN,    1 },
            { CHAR2SYM("data"),       CHAR2SYM("__data"),   SUB_SUBLET_DATA,   2 },
            { CHAR2SYM("watch"),      CHAR2SYM("__watch"),  SUB_SUBLET_WATCH,  1 },
            { CHAR2SYM("unload"),     CHAR2SYM("__unload"), SUB_SUBLET_UNLOAD, 1 },
            { CHAR2SYM("mouse_down"), CHAR2SYM("__down"),   SUB_PANEL_DOWN,    4 },
            { CHAR2SYM("mouse_over"), CHAR2SYM("__over"),   SUB_PANEL_OVER,    1 },
            { CHAR2SYM("mouse_out"),  CHAR2SYM("__out"),    SUB_PANEL_OUT,     1 }
          };

          /* Collect stuff */
          proc  = rb_block_proc();
          arity = rb_proc_arity(proc);
          sing  = rb_singleton_class(p->sublet->instance);
          meth  = rb_intern("define_method");

          /* Special hooks */
          for(i = 0; LENGTH(methods) > i; i++)
            {
              if(methods[i].sym == event)
                {
                  /* Check proc arity */
                  if(-1 == arity || (1 <= arity && methods[i].arity >= arity))
                    {
                      /* Add flags */
                      if(methods[i].flags & (SUB_PANEL_DOWN|
                          SUB_PANEL_OVER|SUB_PANEL_OUT))
                        p->flags |= methods[i].flags;
                      else p->sublet->flags |= methods[i].flags;

                      /* Create instance method from proc */
                      rb_funcall(sing, meth, 2, methods[i].real, proc);

                      return Qnil;
                    }
                  else rb_raise(rb_eArgError, "Wrong number of arguments (%d for %d)",
                    arity, methods[i].arity);
               }
            }

          /* Generic hooks */
          snprintf(buf, sizeof(buf), "__hook_%s", SYM2CHAR(event));
          rb_funcall(sing, meth, 2, CHAR2SYM(buf), proc);

          RubyEvalHook(event, rb_obj_method(p->sublet->instance,
            CHAR2SYM(buf)));
        }
    }
  else rb_raise(rb_eArgError, "Unknown value type for on");

  return Qnil;
}
render → nil

Render a Sublet

1 sublet.render
2 => nil
[show source]
static VALUE
RubySubletRender(VALUE self)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p) subScreenRender();

  return Qnil;
}
screen → Subtlext::Screen

Get screen of a sublet

1 sublet.screen
2 => #<Subtlext::screen:xxx>
[show source]
VALUE
RubySubletScreenReader(VALUE self)
{
  SubPanel *p = NULL;
  VALUE screen = Qnil;

  Data_Get_Struct(self, SubPanel, p);
  if(p) screen = RubySubtleToSubtlext(p->screen);

  return screen;
}
show → nil

Show sublet on panel

1 sublet.show
2 => nil
[show source]
static VALUE
RubySubletShow(VALUE self)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      p->flags &= ~SUB_PANEL_HIDDEN;

      /* Update screens */
      subScreenUpdate();
      subScreenRender();
    }

  return Qnil;
}
style=(string) → nil
style=(symbol) → nil

Set style of Sublet

1 sublet.style = :subtle
2 => nil
[show source]
static VALUE
RubySubletStyleWriter(VALUE self,
  VALUE value)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      /* Check value type */
      if(FIXNUM_P(value))
        {
          SubStyle *s = &subtle->styles.sublets, *style = NULL;

          /* Select style */
          if(s->styles && (style = subArrayGet(s->styles, FIX2INT(value))))
            {
              s                  = style;
              p->sublet->styleid = FIX2INT(value);
            }

          p->sublet->width = subTextParse(p->sublet->text,
            subtle->styles.sublets.font, RSTRING_PTR(value)) +
            STYLE_WIDTH((*s));
        }
      else rb_raise(rb_eArgError, "Unknown value type");
    }

  return Qnil;
}
unwatch → true or false

Remove watch from Sublet

1 unwatch
2 => true
[show source]
static VALUE
RubySubletUnwatch(VALUE self)
{
  VALUE ret = Qfalse;
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      /* Probably a socket */
      if(p->sublet->flags & SUB_SUBLET_SOCKET)
        {
          XDeleteContext(subtle->dpy, subtle->windows.support, p->sublet->watch);
          subEventWatchDel(p->sublet->watch);

          p->sublet->flags &= ~SUB_SUBLET_SOCKET;
          p->sublet->watch  = 0;

          ret = Qtrue;
        }
#ifdef HAVE_SYS_INOTIFY_H
      /* Inotify file */
      else if(p->sublet->flags & SUB_SUBLET_INOTIFY)
        {
          subSubtleLogDebug("Inotify: remove watch=%d\n", p->sublet->watch);

          XDeleteContext(subtle->dpy, subtle->windows.support, p->sublet->watch);
          inotify_rm_watch(subtle->notify, p->sublet->watch);

          p->sublet->flags &= ~SUB_SUBLET_INOTIFY;
          p->sublet->watch  = 0;

          ret = Qtrue;
        }
#endif /* HAVE_SYS_INOTIFY_H */
    }

  return ret;
}
warn(string) → nil

Print sublet warning

1 sublet.warn("test")
2 => "<WARNING SUBLET sublet> test"
[show source]
static VALUE
RubySubletWarn(VALUE self,
  VALUE str)
{
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p && T_STRING == rb_type(str))
    subSubtleLogSubletError(p->sublet->name, RSTRING_PTR(str));

  return Qnil;
}
watch(source) → true or false

Add watch file via inotify or socket

1 watch "/path/to/file"
2 => true
3 
4 @socket = TCPSocket("localhost", 6600)
5 watch @socket
[show source]
static VALUE
RubySubletWatch(VALUE self,
  VALUE value)
{
  VALUE ret = Qfalse;
  SubPanel *p = NULL;

  Data_Get_Struct(self, SubPanel, p);
  if(p)
    {
      if(!(p->sublet->flags & (SUB_SUBLET_SOCKET|SUB_SUBLET_INOTIFY)) &&
          RTEST(value))
        {
          /* Socket file descriptor or ruby socket */
          if(FIXNUM_P(value) || rb_respond_to(value, rb_intern("fileno")))
            {
              int flags = 0;

              p->sublet->flags |= SUB_SUBLET_SOCKET;

              /* Get socket file descriptor */
              if(FIXNUM_P(value)) p->sublet->watch = FIX2INT(value);
              else
                {
                  p->sublet->watch = FIX2INT(rb_funcall(value, rb_intern("fileno"),
                    0, NULL));
                }

              XSaveContext(subtle->dpy, subtle->windows.support,
                p->sublet->watch, (void *)p);
              subEventWatchAdd(p->sublet->watch);

              /* Set nonblocking */
              if(-1 == (flags = fcntl(p->sublet->watch, F_GETFL, 0))) flags = 0;
              fcntl(p->sublet->watch, F_SETFL, flags | O_NONBLOCK);

              ret = Qtrue;
            }
#ifdef HAVE_SYS_INOTIFY_H
          else if(T_STRING == rb_type(value)) /// Inotify file
            {
              char buf[100] = { 0 };

#ifdef HAVE_WORDEXP_H
              /* Expand tildes in path */
              wordexp_t we;

              if(0 == wordexp(RSTRING_PTR(value), &we, 0))
                {
                  snprintf(buf, sizeof(buf), "%s", we.we_wordv[0]);

                  wordfree(&we);
                }
              else
#endif /* HAVE_WORDEXP_H */
              snprintf(buf, sizeof(buf), "%s", RSTRING_PTR(value));

              /* Create inotify watch */
              if(0 < (p->sublet->watch = inotify_add_watch(
                  subtle->notify, buf, IN_MODIFY)))
                {
                  p->sublet->flags |= SUB_SUBLET_INOTIFY;

                  XSaveContext(subtle->dpy, subtle->windows.support,
                    p->sublet->watch, (void *)p);
                  subSubtleLogDebug("Inotify: add watch=%s\n", buf);

                  ret = Qtrue;
                }
              else subSubtleLogWarn("Cannot watch file `%s': %s\n",
                buf, strerror(errno));
            }
#endif /* HAVE_SYS_INOTIFY_H */
          else rb_raise(rb_eArgError, "Unexpected value-type `%s'",
            rb_obj_classname(value));
        }
    }

  return ret;
}