Class Subtlext::Client < Object

Class for interaction with clients

Attributes

flags [R] Bitfield of window states
instance [R] Instance of WM_CLASS
klass [R] Class of WM_CLASS
name [R] WM_NAME
role [R] Window role
win [R] Window id

Public class methods

current → Subtlext::Client

Get current active Client.

1 Subtlext::Client.current
2 => #<Subtlext::Client:xxx>
[show source]
VALUE
subextClientSingCurrent(VALUE self)
{
  VALUE client = Qnil;
  unsigned long *focus = NULL;

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Get current client */
  if((focus = (unsigned long *)subSharedPropertyGet(display,
      DefaultRootWindow(display), XA_WINDOW,
      XInternAtom(display, "_NET_ACTIVE_WINDOW", False), NULL)))
    {
      /* Update client values */
      if(RTEST(client = subextClientInstantiate(*focus)))
        subextClientUpdate(client);

      free(focus);
    }
  else rb_raise(rb_eStandardError, "Invalid current window");

  return client;
}
find(value) → Array
[value] → Array

Find Client by a given value which can be of following type:

Fixnum
Array index of the _NET_CLIENT_LIST property list.
String
Regexp match against both WM_CLASS values.
Hash
Instead of just match WM_CLASS match against following properties:
:name
Match against WM_NAME
:instance
Match against first value of WM_NAME
:class
Match against second value of WM_NAME
:gravity
Match against window Gravity
:role
Match against WM_ROLE
:pid
Match against window pid

With one of following keys: :title, :name, :class, :gravity

Symbol
Either :current for current View, :all for an array of all Views or any string for an exact match.
 1 Subtlext::Client.find(1)
 2 => [#<Subtlext::Client:xxx>]
 3 
 4 Subtlext::Client.find("subtle")
 5 => [#<Subtlext::Client:xxx>]
 6 
 7 Subtlext::Client[".*"]
 8 => [#<Subtlext::Client:xxx>, #<Subtlext::Client:xxx>]
 9 
10 Subtlext::Client["subtle"]
11 => []
12 
13 Subtlext::Client[:terms]
14 => [#<Subtlext::Client:xxx>]
15 
16 Subtlext::Client[name: "subtle"]
17 => [#<Subtlext::Client:xxx>]
[show source]
VALUE
subextClientSingFind(VALUE self,
  VALUE value)
{
  return ClientFind(value, False);
}
first(value) → Subtlext::Client or nil

Find first Client by a given value which can be of following type:

Fixnum
Array index of the _NET_CLIENT_LIST property list.
String
Regexp match against both WM_CLASS values.
Hash
Instead of just match WM_CLASS match against following properties:
:name
Match against WM_NAME
:instance
Match against first value of WM_NAME
:class
Match against second value of WM_NAME
:gravity
Match against window Gravity
:role
Match against WM_ROLE
:pid
Match against window pid

With one of following keys: :title, :name, :class, :gravity

Symbol
Either :current for current View, :all for an array of all Views or any string for an exact match.
1 Subtlext::Client.first(1)
2 => #<Subtlext::Client:xxx>
3 
4 Subtlext::Client.first("subtle")
5 => #<Subtlext::Client:xxx>
6 
7 Subtlext::Client.first(name: "subtle")
8 => #<Subtlext::Client:xxx>
[show source]
VALUE
subextClientSingFirst(VALUE self,
  VALUE value)
{
  return ClientFind(value, True);
}
list → Array

Get an array of all Clients based on _NET_CLIENT_LIST property list.

1 Subtlext::Client.list
2 => [#<Subtlext::Client:xxx>, #<Subtlext::Client:xxx>]
3 
4 Subtlext::Client.list
5 => []
[show source]
VALUE
subextClientSingList(VALUE self)
{
  int i, nclients = 0;
  Window *clients = NULL;
  VALUE meth = Qnil, klass = Qnil, array = Qnil, client = Qnil;

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Fetch data */
  meth    = rb_intern("new");
  array   = rb_ary_new();
  klass   = rb_const_get(mod, rb_intern("Client"));
  clients = subextSubtlextWindowList("_NET_CLIENT_LIST", &nclients);

  /* Check results */
  if(clients)
    {
      for(i = 0; i < nclients; i++)
        {
          /* Create client */
          if(RTEST(client = rb_funcall(klass, meth, 1, LONG2NUM(clients[i]))))
            {
              subextClientUpdate(client);
              rb_ary_push(array, client);
            }
        }

      free(clients);
    }

  return array;
}
new(win) → Subtlext::Client

Create a new Client object locally without calling save automatically.

The Client won’t be visible until save is called.

1 client = Subtlext::Client.new(1)
2 => #<Subtlext::Client:xxx>
[show source]
VALUE
subextClientInit(VALUE self,
  VALUE win)
{
  if(!FIXNUM_P(win))
    rb_raise(rb_eArgError, "Unexpected value-type `%s'",
      rb_obj_classname(win));

  /* Init object */
  rb_iv_set(self, "@win",      win);
  rb_iv_set(self, "@name",     Qnil);
  rb_iv_set(self, "@instance", Qnil);
  rb_iv_set(self, "@klass",    Qnil);
  rb_iv_set(self, "@role",     Qnil);
  rb_iv_set(self, "@geometry", Qnil);
  rb_iv_set(self, "@gravity",  Qnil);
  rb_iv_set(self, "@screen",   Qnil);
  rb_iv_set(self, "@flags",    Qnil);
  rb_iv_set(self, "@tags",     INT2FIX(0));

  subextSubtlextConnect(NULL); ///< Implicit open connection

  return self;
}
recent → Array

Get array of the last five active Clients.

1 Subtlext::Client.recent
2 => [ #<Subtlext::Client:xxx> ]
[show source]
VALUE
subextClientSingRecent(VALUE self)
{
  int i, nclients = 0;
  Window *clients = NULL;
  VALUE meth = Qnil, klass = Qnil, array = Qnil, client = Qnil;

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Fetch data */
  meth    = rb_intern("new");
  array   = rb_ary_new();
  klass   = rb_const_get(mod, rb_intern("Client"));
  clients = subextSubtlextWindowList("_NET_ACTIVE_WINDOW", &nclients);

  /* Check results */
  if(clients)
    {
      for(i = 0; i < nclients; i++)
        {
          /* Create client */
          if(!NIL_P(client = rb_funcall(klass, meth, 1, LONG2NUM(clients[i]))))
            {
              subextClientUpdate(client);
              rb_ary_push(array, client);
            }
        }

      free(clients);
    }

  return array;
}
select → Subtlext::Client or nil

Click on a wondow and get the selected Client.

1 Subtlext::Client.select
2 => #<Subtlext::Client:xxx>
[show source]
VALUE
subextClientSingSelect(VALUE self)
{
  VALUE win = subextSubtleSingSelect(self);

  return None != NUM2LONG(win) ? subextClientSingFind(self, win) : Qnil;
}
spawn(cmd) → Subtlext::Client

Spawn a command and returns a Client object.

1 spawn("xterm")
2 => #<Subtlext::Client:xxx>
[show source]
VALUE
subextClientSingSpawn(VALUE self,
  VALUE cmd)
{
  VALUE ret = Qnil;

  /* Check object type */
  if(T_STRING == rb_type(cmd))
    {
      pid_t pid = 0;

      subextSubtlextConnect(NULL); ///< Implicit open connection

      /* Create client with empty window id since we cannot
       * know the real window id at this point (race) */
      if(0 < (pid = subSharedSpawn(RSTRING_PTR(cmd))))
        {
          ret = subextClientInstantiate((Window)pid);
          rb_iv_set(ret, "@pid", INT2FIX((int)pid));
        }
    }
  else rb_raise(rb_eArgError, "Unexpected value-type `%s'",
    rb_obj_classname(cmd));

  return ret;
}
visible → Array

Get array of all visible Client on all Views.

1 Subtlext::Client.visible
2 => [#<Subtlext::Client:xxx>, #<Subtlext::Client:xxx>]
3 
4 Subtlext::Client.visible
5 => []
[show source]
VALUE
subextClientSingVisible(VALUE self)
{
  int i, nclients = 0;
  Window *clients = NULL;
  unsigned long *visible = NULL;
  VALUE meth = Qnil, klass = Qnil, array = Qnil, client = Qnil;

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Fetch data */
  meth    = rb_intern("new");
  array   = rb_ary_new();
  klass   = rb_const_get(mod, rb_intern("Client"));
  clients = subextSubtlextWindowList("_NET_CLIENT_LIST", &nclients);
  visible = (unsigned long *)subSharedPropertyGet(display,
    DefaultRootWindow(display), XA_CARDINAL, XInternAtom(display,
    "SUBTLE_VISIBLE_TAGS", False), NULL);

  /* Check results */
  if(clients && visible)
    {
      for(i = 0; i < nclients; i++)
        {
          unsigned long *tags = (unsigned long *)subSharedPropertyGet(display,
            clients[i], XA_CARDINAL, XInternAtom(display,
            "SUBTLE_CLIENT_TAGS", False), NULL);

          /* Create client on match */
          if(tags && *tags && *visible & *tags &&
              RTEST(client = rb_funcall(klass, meth, 1, LONG2NUM(clients[i]))))
            {
              subextClientUpdate(client);
              rb_ary_push(array, client);
            }

          if(tags) free(tags);
        }
    }

  if(clients) free(clients);
  if(visible) free(visible);

  return array;
}

Public instance methods

+ (p1)

Alias for tag

- (p1)

Alias for untag

<=>(other) → -1, 0 or 1

Whether both objects have the same value. Returns -1, 0 or 1 when self is less than, equal to or grater than other. (based on win)

1 object1 <=> object2
2 => 0
[show source]
static VALUE
SubtlextEqualSpaceWindow(VALUE self,
  VALUE other)
{
  return SubtlextSpaceship(self, other, "@win");
}
==(other) → True or False

Whether both objects have the same values (based on win)

1 object1 == object2
2 => true
[show source]
static VALUE
SubtlextEqualWindow(VALUE self,
  VALUE other)
{
  return SubtlextEqual(self, other, "@win", False);
}
[value] → String or Nil

Get arbitrary persistent property string or symbol value

1 object["wm"]
2 => "subtle"
3 
4 object[:wm]
5 => "subtle"
[show source]
static VALUE
SubtlextPropReader(VALUE self,
  VALUE key)
{
  char *prop = NULL;
  VALUE ret = Qnil;

  /* Check ruby object */
  rb_check_frozen(self);

  /* Check object type */
  switch(rb_type(key))
    {
      case T_STRING: prop = RSTRING_PTR(key);      break;
      case T_SYMBOL: prop = (char *)SYM2CHAR(key); break;
      default:
        rb_raise(rb_eArgError, "Unexpected key value type `%s'",
          rb_obj_classname(key));

        return Qnil;
    }

  /* Check results */
  if(prop)
    {
      char propname[255] = { 0 }, *name = NULL, *result = NULL;
      Window win = ROOT;
      VALUE val = Qnil;

      /* Sanitize property name */
      name = strdup(prop);
      SubtlextStringify(name);

      /* Check object type */
      if(rb_obj_is_instance_of(self, rb_const_get(mod, rb_intern("View"))))
        {
          GET_ATTR(self, "@name", val);
          snprintf(propname, sizeof(propname), "SUBTLE_PROPERTY_%s_%s",
            RSTRING_PTR(val), name);
        }
      else ///< Client
        {
          GET_ATTR(self, "@win", val);
          win = NUM2LONG(val);
          snprintf(propname, sizeof(propname), "SUBTLE_PROPERTY_%s", name);
        }

      /* Get actual property */
      if((result = subSharedPropertyGet(display, win, XInternAtom(display,
          "UTF8_STRING", False), XInternAtom(display, propname, False), NULL)))
        {
          ret = rb_str_new2(result);

          free(result);
        }

      free(name);
    }

  return ret;
}
[key]= value → Nil

Set arbitrary persistent property string or symbol value

Symbols are implictly converted to string, to remove a property just set it to nil.

1 object["wm"] = "subtle"
2 => nil
3 
4 object[:wm] = "subtle"
5 => nil
6 
7 object[:wm] = nil
8 => nil
[show source]
static VALUE
SubtlextPropWriter(VALUE self,
  VALUE key,
  VALUE value)
{
  VALUE val = Qnil, str = value;
  char *prop = NULL, *name = NULL, propname[255] = { 0 };
  Window win = ROOT;

  /* Check ruby object */
  rb_check_frozen(self);

  /* Check object type */
  switch(rb_type(key))
    {
      case T_STRING: prop = RSTRING_PTR(key);      break;
      case T_SYMBOL: prop = (char *)SYM2CHAR(key); break;
      default:
        rb_raise(rb_eArgError, "Unexpected key value-type `%s'",
          rb_obj_classname(key));

        return Qnil;
    }

  /* Sanitize property name */
  name = strdup(prop);
  SubtlextStringify(name);

  /* Assemble property name */
  if(rb_obj_is_instance_of(self, rb_const_get(mod, rb_intern("View"))))
    {
      GET_ATTR(self, "@name", val);
      snprintf(propname, sizeof(propname), "SUBTLE_PROPERTY_%s_%s",
        RSTRING_PTR(val), name);
    }
  else ///< Client
    {
      GET_ATTR(self, "@win", val);
      win = NUM2LONG(val);
      snprintf(propname, sizeof(propname), "SUBTLE_PROPERTY_%s", name);
    }

  /* Check value type */
  switch(rb_type(value))
    {
      case T_SYMBOL: str = rb_sym_to_s(value);
      case T_STRING:
        XChangeProperty(display, win, XInternAtom(display, propname, False),
          XInternAtom(display, "UTF8_STRING", False), 8, PropModeReplace,
          (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
        break;
      case T_NIL:
        XDeleteProperty(display, win, XInternAtom(display, propname, False));
        break;
      default:
        rb_raise(rb_eArgError, "Unexpected value value-type `%s'",
          rb_obj_classname(value));
    }

  XSync(display, False); ///< Sync all changes

  if(name) free(name);

  return Qnil;
}
alive? → true or false

Check if client is alive.

1 client.alive?
2 => true
3 
4 client.alive?
5 => false
[show source]
VALUE
subextClientAskAlive(VALUE self)
{
  VALUE ret = Qfalse, win = Qnil;
  XWindowAttributes attrs;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Fetch client attributes */
  if(!XGetWindowAttributes(display, NUM2LONG(win), &attrs))
    rb_obj_freeze(self);
  else ret = Qtrue;

  return ret;
}
click (...)

Alias for send_button

eql?(other) → True or False

Whether both objects have the same value and types (based on win)

1 object1.eql? object2
2 => true
[show source]
static VALUE
SubtlextEqualTypedWindow(VALUE self,
  VALUE other)
{
  return SubtlextEqual(self, other, "@win", True);
}
flags=(array) → Subtlext::Client

Set multiple flags at once. Flags can be one or a combination of the following:

:full
Set fullscreen mode
:float
Set floating mode
:stick
Set sticky mode
:resize
Set resize mode
:urgent
Set urgent mode
:zaphod
Set zaphod mode
:fixed
Set fixed mode
:borderless
Set borderless mode
1 client.flags = [ :float, :stick ]
2 => nil
[show source]
VALUE
subextClientFlagsWriter(VALUE self,
  VALUE value)
{
  /* Check object type */
  if(T_ARRAY == rb_type(value))
    {
      int i, flags = 0;
      VALUE entry = Qnil;

      /* Translate flags */
      for(i = 0; Qnil != (entry = rb_ary_entry(value, i)); ++i)
        {
          if(CHAR2SYM("full")            == entry) flags |= SUB_EWMH_FULL;
          else if(CHAR2SYM("float")      == entry) flags |= SUB_EWMH_FLOAT;
          else if(CHAR2SYM("stick")      == entry) flags |= SUB_EWMH_STICK;
          else if(CHAR2SYM("resize")     == entry) flags |= SUB_EWMH_RESIZE;
          else if(CHAR2SYM("urgent")     == entry) flags |= SUB_EWMH_URGENT;
          else if(CHAR2SYM("zaphod")     == entry) flags |= SUB_EWMH_ZAPHOD;
          else if(CHAR2SYM("fixed")      == entry) flags |= SUB_EWMH_FIXED;
          else if(CHAR2SYM("borderless") == entry) flags |= SUB_EWMH_BORDERLESS;
        }

      ClientFlagsSet(self, flags, False);
    }

  return self;
}
focus → nil

Set focus to window

1 object.focus
2 => nil
[show source]
static VALUE
SubtlextFocus(VALUE self)
{
  VALUE win = Qnil;
  SubMessageData data = { { 0, 0, 0, 0, 0 } };

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  /* Send message */
  data.l[0] = NUM2LONG(win);

  subSharedMessage(display, ROOT, "_NET_ACTIVE_WINDOW", data, 32, True);

  return self;
}
geometry → Subtlext::Geometry

Get Client Geometry.

1 client.geometry
2 => #<Subtlext::Geometry:xxx>
[show source]
VALUE
subextClientGeometryReader(VALUE self)
{
  VALUE win = Qnil, geom = Qnil;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Load on demand */
  if(NIL_P((geom = rb_iv_get(self, "@geometry"))))
    {
      XRectangle geometry = { 0 };

      subSharedPropertyGeometry(display, NUM2LONG(win), &geometry);

      geom = subextGeometryInstantiate(geometry.x, geometry.y,
        geometry.width, geometry.height);

      rb_iv_set(self, "@geometry", geom);
    }

  return geom;
}
geometry=(x, y, width, height) → Fixnum
geometry=(array) → Array
geometry=(hash) → Hash
geometry=(string) → String
geometry=(geometry) → Subtlext::Geometry

Set Client geometry.

 1 client.geometry = 0, 0, 100, 100
 2 => 0
 3 
 4 client.geometry = [ 0, 0, 100, 100 ]
 5 => [ 0, 0, 100, 100 ]
 6 
 7 client.geometry = { x: 0, y: 0, width: 100, height: 100 }
 8 => { x: 0, y: 0, width: 100, height: 100 }
 9 
10 client.geometry = "0x0+100+100"
11 => "0x0+100+100"
12 
13 client.geometry = Subtlext::Geometry(0, 0, 100, 100)
14 => #<Subtlext::Geometry:xxx>
[show source]
VALUE
subextClientGeometryWriter(int argc,
  VALUE *argv,
  VALUE self)
{
  VALUE klass = Qnil, geom = Qnil;

  /* Check ruby object */
  rb_check_frozen(self);
  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Delegate arguments */
  klass = rb_const_get(mod, rb_intern("Geometry"));
  geom  = rb_funcall2(klass, rb_intern("new"), argc, argv);

  /* Update geometry */
  if(RTEST(geom))
    {
      VALUE win = Qnil;
      SubMessageData data = { { 0, 0, 0, 0, 0 } };

      GET_ATTR(self, "@win", win);

      data.l[1] = FIX2INT(rb_iv_get(geom,  "@x"));
      data.l[2] = FIX2INT(rb_iv_get(geom,  "@y"));
      data.l[3] = FIX2INT(rb_iv_get(geom,  "@width"));
      data.l[4] = FIX2INT(rb_iv_get(geom,  "@height"));

      subSharedMessage(display, NUM2LONG(win),
        "_NET_MOVERESIZE_WINDOW", data, 32, True);

      rb_iv_set(self, "@geometry", geom);
    }

  return geom;
}
gravity → Subtlext::Gravity

Get Client Gravity.

1 client.gravity
2 => #<Subtlext::Gravity:xxx>
[show source]
VALUE
subextClientGravityReader(VALUE self)
{
  VALUE win = Qnil, gravity = Qnil;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Load on demand */
  if(NIL_P((gravity = rb_iv_get(self, "@gravity"))))
    {
      int *id = NULL;
      char buf[5] = { 0 };

      /* Get gravity */
      if((id = (int *)subSharedPropertyGet(display, NUM2LONG(win), XA_CARDINAL,
          XInternAtom(display, "SUBTLE_CLIENT_GRAVITY", False), NULL)))
        {
          /* Create gravity */
          snprintf(buf, sizeof(buf), "%d", *id);
          gravity = subextGravityInstantiate(buf);

          subextGravitySave(gravity);

          rb_iv_set(self, "@gravity", gravity);

          free(id);
        }
    }

  return gravity;
}
gravity=(fixnum) → Fixnum
gravity=(symbol) → Symbol
gravity=(object) → Object
gravity=(hash) → Hash

Set Client Gravity either for current or for specific View.

 1 # Set gravity for current view
 2 client.gravity = 0
 3 => #<Subtlext::Gravity:xxx>
 4 
 5 client.gravity = :center
 6 => #<Subtlext::Gravity:xxx>
 7 
 8 client.gravity = Subtlext::Gravity[0]
 9 => #<Subtlext::Gravity:xxx>
10 
11 # Set gravity for specific view
12 client.gravity = { :terms => :center }
13 => #<Subtlext::Gravity:xxx>
[show source]
VALUE
subextClientGravityWriter(VALUE self,
  VALUE value)
{
  /* Check ruby object */
  rb_check_frozen(self);

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Check value type */
  switch(rb_type(value))
    {
      case T_FIXNUM:
      case T_SYMBOL:
      case T_STRING: ClientGravity(Qnil, value, self); break;
      case T_OBJECT:
        if(rb_obj_is_instance_of(value,
            rb_const_get(mod, rb_intern("Gravity"))))
          ClientGravity(Qnil, value, self);
        break;
      case T_HASH:
        rb_hash_foreach(value, ClientGravity, self);
        break;
      default: rb_raise(rb_eArgError, "Unexpected value-type `%s'",
        rb_obj_classname(value));
    }

  /* Reset gravity */
  rb_iv_set(self, "@gravity", Qnil);

  return value;
}
has_focus? → true or false

Check if window has focus

1 object.focus?
2 => true
3 
4 object.focus?
5 => false
[show source]
static VALUE
SubtlextAskFocus(VALUE self)
{
  VALUE ret = Qfalse, win = Qnil;
  unsigned long *focus = NULL;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  /* Fetch data */
  if((focus = (unsigned long *)subSharedPropertyGet(display, ROOT,
      XA_WINDOW, XInternAtom(display, "_NET_ACTIVE_WINDOW", False), NULL)))
    {
      if(*focus == NUM2LONG(win)) ret = Qtrue;

      free(focus);
    }

  return ret;
}
has_tag? (p1)

SubtlextTagAsk {{{

[show source]
static VALUE
SubtlextTagAsk(VALUE self,
  VALUE value)
{
  VALUE sym = Qnil, tag = Qnil, ret = Qfalse;

  /* Check ruby object */
  rb_check_frozen(self);

  /* Check value type */
  switch(rb_type(value))
    {
      case T_STRING: sym = CHAR2SYM(RSTRING_PTR(value)); break;
      case T_SYMBOL:
      case T_OBJECT: sym = value;                        break;
      default: rb_raise(rb_eArgError, "Unexpected value-type `%s'",
        rb_obj_classname(value));
    }

  /* Find tag */
  if(RTEST(tag = subextTagSingFirst(Qnil, sym)))
    {
      VALUE id = Qnil, tags = Qnil;

      /* Get properties */
      id   = rb_iv_get(tag,  "@id");
      tags = rb_iv_get(self, "@tags");

      if(FIX2INT(tags) & (1L << (FIX2INT(id) + 1))) ret = Qtrue;
    }

  return ret;
}
hash → Hash

Convert this object to hash.

1 puts object.hash
2 => 1746246187916025425
[show source]
static VALUE
SubtlextHash(VALUE self)
{
  VALUE str = Qnil, id = rb_intern("to_str");

  /* Convert to string */
  if(rb_respond_to(self, id))
    str = rb_funcall(self, id, 0, Qnil);

  return T_STRING == rb_type(str) ? INT2FIX(rb_str_hash(str)) : Qnil;
}
is_borderless? → true or false

Check if Client is borderless.

1 client.is_borderless?
2 => true
3 
4 client.is_borderless?
5 => false
[show source]
VALUE
subextClientFlagsAskBorderless(VALUE self)
{
  return ClientFlagsGet(self, SUB_EWMH_BORDERLESS);
}
is_fixed? → true or false

Check if Client is fixed.

1 client.is_fixed?
2 => true
3 
4 client.is_fixed?
5 => false
[show source]
VALUE
subextClientFlagsAskFixed(VALUE self)
{
  return ClientFlagsGet(self, SUB_EWMH_FIXED);
}
is_float? → true or false

Check if Client is floating.

1 client.is_float?
2 => true
3 
4 client.is_float?
5 => false
[show source]
VALUE
subextClientFlagsAskFloat(VALUE self)
{
  return ClientFlagsGet(self, SUB_EWMH_FLOAT);
}
is_full? → true or false

Check if Client is fullscreen.

1 client.is_full?
2 => true
3 
4 client.is_full?
5 => false
[show source]
VALUE
subextClientFlagsAskFull(VALUE self)
{
  return ClientFlagsGet(self, SUB_EWMH_FULL);
}
is_resize? → true or false

Check if Client uses size hints.

1 client.is_resize?
2 => true
3 
4 client.is_resize?
5 => false
[show source]
VALUE
subextClientFlagsAskResize(VALUE self)
{
  return ClientFlagsGet(self, SUB_EWMH_RESIZE);
}
is_stick? → true or false

Check if Client is sticky.

1 client.is_stick?
2 => true
3 
4 client.is_stick?
5 => false
[show source]
VALUE
subextClientFlagsAskStick(VALUE self)
{
  return ClientFlagsGet(self, SUB_EWMH_STICK);
}
is_urgent? → true or false

Check if Client is urgent.

1 client.is_urgent?
2 => true
3 
4 client.is_urgent?
5 => false
[show source]
VALUE
subextClientFlagsAskUrgent(VALUE self)
{
  return ClientFlagsGet(self, SUB_EWMH_URGENT);
}
is_zaphod? → true or false

Check if Client is zaphod.

1 client.is_zaphod?
2 => true
3 
4 client.is_zaphod?
5 => false
[show source]
VALUE
subextClientFlagsAskZaphod(VALUE self)
{
  return ClientFlagsGet(self, SUB_EWMH_ZAPHOD);
}
kill → nil

Send a close signal to Client and freeze this object.

1 client.kill
2 => nil
[show source]
VALUE
subextClientKill(VALUE self)
{
  VALUE win = Qnil;
  SubMessageData data = { { 0, 0, 0, 0, 0 } };

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Send message */
  data.l[0] = CurrentTime;
  data.l[1] = 2; ///< Claim to be a pager

  subSharedMessage(display, NUM2LONG(win),
    "_NET_CLOSE_WINDOW", data, 32, True);

  rb_obj_freeze(self);

  return Qnil;
}
lower → Subtlext::Client

Move Client window to bottom of window stack.

1 client.raise
2 => nil
[show source]
VALUE
subextClientRestackLower(VALUE self)
{
  return ClientRestack(self, Below);
}
pid => Fixnum

Get window pid

1 object.pid
2 => 123
[show source]
static VALUE
SubtlextPidReader(VALUE self)
{
  Window win = None;
  VALUE pid = Qnil;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  /* Load on demand */
  if(NIL_P((pid = rb_iv_get(self, "@pid"))))
    {
      int *id = NULL;

      /* Get pid */
      if((id = (int *)subSharedPropertyGet(display, win, XA_CARDINAL,
          XInternAtom(display, "_NET_WM_PID", False), NULL)))
        {
          pid = INT2FIX(*id);

          rb_iv_set(self, "@pid", pid);

          free(id);
        }
    }

  return pid;
}
raise → Subtlext::Client

Move Client window to top of window stack.

1 client.raise
2 => nil
[show source]
VALUE
subextClientRestackRaise(VALUE self)
{
  return ClientRestack(self, Above);
}
retag ()

SubtlextTagReload {{{

[show source]
static VALUE
SubtlextTagReload(VALUE self)
{
  VALUE win = Qnil;
  SubMessageData data = { { 0, 0, 0, 0, 0 } };

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  /* Send message */
  data.l[0] = NUM2LONG(win);

  subSharedMessage(display, ROOT, "SUBTLE_CLIENT_RETAG", data, 32, True);

  return Qnil;
}
save ()

Alias for update

screen → Subtlext::Screen

Get Client Screen.

1 client.screen
2 => #<Subtlext::Screen:xxx>
[show source]
VALUE
subextClientScreenReader(VALUE self)
{
  VALUE screen = Qnil, win = Qnil;
  int *id = NULL;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  /* Get screen */
  if((id = (int *)subSharedPropertyGet(display, NUM2LONG(win), XA_CARDINAL,
      XInternAtom(display, "SUBTLE_CLIENT_SCREEN", False), NULL)))
    {
      screen = subextScreenSingFind(self, INT2FIX(*id));

      free(id);
    }

  return screen;
}
send_button(button, x, y) → Object

Emulate a click on a window with optional button and x/y position

1 object.send_button
2 => nil
3 
4 object.send_button(2)
5 => Object
[show source]
static VALUE
SubtlextSendButton(int argc,
  VALUE *argv,
  VALUE self)
{
  Window subwin = None;
  XEvent event = { 0 };
  VALUE button = Qnil, x = Qnil, y = Qnil, win = Qnil;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  rb_scan_args(argc, argv, "03", &button, &x, &y);

  /* Assemble button event */
  event.type                  = EnterNotify;
  event.xcrossing.window      = NUM2LONG(win);
  event.xcrossing.root        = ROOT;
  event.xcrossing.subwindow   = NUM2LONG(win);
  event.xcrossing.same_screen = True;
  event.xcrossing.x           = FIXNUM_P(x) ? FIX2INT(x) : 5;
  event.xcrossing.y           = FIXNUM_P(y) ? FIX2INT(y) : 5;

  /* Translate window x/y to root x/y */
  XTranslateCoordinates(display, event.xcrossing.window,
    event.xcrossing.root, event.xcrossing.x, event.xcrossing.y,
    &event.xcrossing.x_root, &event.xcrossing.y_root, &subwin);

  //XSetInputFocus(display, event.xany.window, RevertToPointerRoot, CurrentTime);
  XSendEvent(display, NUM2LONG(win), True, EnterWindowMask, &event);

  /* Send button press event */
  event.type           = ButtonPress;
  event.xbutton.button = FIXNUM_P(button) ? FIX2INT(button) : 1;

  XSendEvent(display, NUM2LONG(win), True, ButtonPressMask, &event);
  XFlush(display);

  usleep(12000);

  /* Send button release event */
  event.type = ButtonRelease;

  XSendEvent(display, NUM2LONG(win), True, ButtonReleaseMask, &event);
  XFlush(display);

  return self;
}
send_key(key, x, y) → Object

Emulate a keypress on a window

1 object.send_key("d")
2 => Object
[show source]
static VALUE
SubtlextSendKey(int argc,
  VALUE *argv,
  VALUE self)
{
  VALUE keys = Qnil, x = Qnil, y = Qnil, win = Qnil;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  rb_scan_args(argc, argv, "12", &keys, &x, &y);

  /* Check object type */
  if(T_STRING == rb_type(keys))
    {
      int mouse = False;
      unsigned int code = 0, state = 0;
      char *tokens = NULL, *tok = NULL, *save = NULL;
      Window subwin = None;
      KeySym sym = None;
      XEvent event = { 0 };

      /* Assemble enter event */
      event.type                  = EnterNotify;
      event.xcrossing.window      = NUM2LONG(win);
      event.xcrossing.root        = ROOT;
      event.xcrossing.subwindow   = NUM2LONG(win);
      event.xcrossing.same_screen = True;
      event.xcrossing.x           = FIXNUM_P(x) ? FIX2INT(x) : 5;
      event.xcrossing.y           = FIXNUM_P(y) ? FIX2INT(y) : 5;

      /* Translate window x/y to root x/y */
      XTranslateCoordinates(display, event.xcrossing.window,
        event.xcrossing.root, event.xcrossing.x, event.xcrossing.y,
        &event.xcrossing.x_root, &event.xcrossing.y_root, &subwin);

      XSendEvent(display, NUM2LONG(win), True, EnterWindowMask, &event);

      /* Parse keys */
      tokens = strdup(RSTRING_PTR(keys));
      tok    = strtok_r(tokens, " ", &save);

      while(tok)
        {
          /* Parse key chain */
          if(NoSymbol == (sym = subSharedParseKey(display,
              tok, &code, &state, &mouse)))
            {
              rb_raise(rb_eStandardError, "Unknown key");

              return Qnil;
            }

          /* Check mouse */
          if(True == mouse)
            {
              rb_raise(rb_eNotImpError, "Use #send_button instead");

              return Qnil;
            }

#ifdef HAVE_X11_EXTENSIONS_XTEST_H
          XTestGrabControl(display, True);

          /* Send key press/release events */
          SubtlextSendModifier(state, True);
          XTestFakeKeyEvent(display, code, True, CurrentTime);
          XTestFakeKeyEvent(display, code, False, CurrentTime);
          SubtlextSendModifier(state, False);

          XTestGrabControl(display, False);
#else /* HAVE_X11_EXTENSIONS_XTEST_H */
          /* Send key press event */
          event.type         = KeyPress;
          event.xkey.state   = state;
          event.xkey.keycode = code;

          XSendEvent(display, NUM2LONG(win), True, KeyPressMask, &event);
          XFlush(display);

          usleep(12000);

          /* Send key release event */
          event.type = KeyRelease;

          XSendEvent(display, NUM2LONG(win), True, KeyReleaseMask, &event);
#endif /* HAVE_X11_EXTENSIONS_XTEST_H */

          tok = strtok_r(NULL, " ", &save);
        }

      XFlush(display);

      free(tokens);
    }
  else rb_raise(rb_eArgError, "Unexpected value-type `%s'",
    rb_obj_classname(keys));

  return self;
}
tag(value) → nil
+(value) → nil

Add an existing tag to window

1 object.tag("subtle")
2 => nil
3 
4 object.tag([ #<Subtlext::Tag:xxx>, #<Subtlext::Tag:xxx> ])
5 => nil
6 
7 object + "subtle"
8 => nil
[show source]
static VALUE
SubtlextTagAdd(VALUE self,
  VALUE value)
{
  return SubtlextTag(self, value, 1);
}
tags → Array

Get list of tags for window

1 object.tags
2 => [#<Subtlext::Tag:xxx>, #<Subtlext::Tag:xxx>]
[show source]
static VALUE
SubtlextTagReader(VALUE self)
{
  char **tags = NULL;
  int i, ntags = 0, value_tags = 0;
  VALUE method = Qnil, klass = Qnil, t = Qnil;
  VALUE array = rb_ary_new();

  /* Check ruby object */
  rb_check_frozen(self);

  /* Fetch data */
  method     = rb_intern("new");
  klass      = rb_const_get(mod, rb_intern("Tag"));
  value_tags = FIX2INT(rb_iv_get(self, "@tags"));

  /* Check results */
  if((tags = subSharedPropertyGetStrings(display, ROOT,
      XInternAtom(display, "SUBTLE_TAG_LIST", False), &ntags)))
    {
      for(i = 0; i < ntags; i++)
        {
          if(value_tags & (1L << (i + 1)))
            {
              /* Create new tag */
              t = rb_funcall(klass, method, 1, rb_str_new2(tags[i]));
              rb_iv_set(t, "@id", INT2FIX(i));
              rb_ary_push(array, t);
            }
        }

      XFreeStringList(tags);
    }

  return array;
}
tags=(value) → nil

Set or remove all tags at once

1 # Set new tags
2 object.tags=([ #<Subtlext::Tag:xxx>, #<Subtlext::Tag:xxx> ])
3 => nil
4 
5 # Remove all tags
6 object.tags=([])
7 => nil
[show source]
static VALUE
SubtlextTagWriter(VALUE self,
  VALUE value)
{
  return SubtlextTag(self, value, 0);
}
to_s ()

Alias for to_str

to_str → String

Convert this Client object to string.

1 puts client
2 => "subtle"
[show source]
VALUE
subextClientToString(VALUE self)
{
  VALUE name = Qnil;

  /* Check ruby object */
  GET_ATTR(self, "@name", name);

  return name;
}
toggle_borderless → Subtlext::Client

Toggle Client borderless state.

1 client.toggle_borderless
2 => nil
[show source]
VALUE
subextClientFlagsToggleBorderless(VALUE self)
{
  return ClientFlagsSet(self, SUB_EWMH_BORDERLESS, True);
}
toggle_fixed → Subtlext::Client

Toggle Client fixed state.

1 client.toggle_fixed
2 => nil
[show source]
VALUE
subextClientFlagsToggleFixed(VALUE self)
{
  return ClientFlagsSet(self, SUB_EWMH_FIXED, True);
}
toggle_float → Subtlext::Client

Toggle Client floating state.

1 client.toggle_float
2 => nil
[show source]
VALUE
subextClientFlagsToggleFloat(VALUE self)
{
  return ClientFlagsToggle(self, "_NET_WM_STATE_ABOVE", SUB_EWMH_FLOAT);
}
toggle_full → Subtlext::Client

Toggle Client fullscreen state.

1 client.toggle_full
2 => nil
[show source]
VALUE
subextClientFlagsToggleFull(VALUE self)
{
  return ClientFlagsToggle(self, "_NET_WM_STATE_FULLSCREEN", SUB_EWMH_FULL);
}
toggle_stick → Subtlext::Client

Toggle Client resize state.

1 client.toggle_stick
2 => nil
[show source]
VALUE
subextClientFlagsToggleResize(VALUE self)
{
  return ClientFlagsSet(self, SUB_EWMH_RESIZE, True);
}
toggle_stick → Subtlext::Client

Toggle Client sticky state.

1 client.toggle_stick
2 => nil
[show source]
VALUE
subextClientFlagsToggleStick(VALUE self)
{
  return ClientFlagsToggle(self, "_NET_WM_STATE_STICKY", SUB_EWMH_STICK);
}
toggle_urgent → Subtlext::Client

Toggle Client urgent state.

1 client.toggle_urgent
2 => nil
[show source]
VALUE
subextClientFlagsToggleUrgent(VALUE self)
{
  return ClientFlagsSet(self, SUB_EWMH_URGENT, True);
}
toggle_zaphod → Subtlext::Client

Toggle Client zaphod state.

1 client.toggle_zaphod
2 => nil
[show source]
VALUE
subextClientFlagsToggleZaphod(VALUE self)
{
  return ClientFlagsSet(self, SUB_EWMH_ZAPHOD, True);
}
untag(value) → nil
-(value) → nil

Remove an existing tag from window

1 object.untag("subtle")
2 => nil
3 
4 object.untag([ #<Subtlext::Tag:xxx>, #<Subtlext::Tag:xxx> ])
5 => nil
6 
7 object - "subtle"
8 => nil
[show source]
static VALUE
SubtlextTagDel(VALUE self,
  VALUE value)
{
  return SubtlextTag(self, value, -1);
}
update → Subtlext::Client

Update Client properties based on required Client window id.

1 client.update
2 => nil
[show source]
VALUE
subextClientUpdate(VALUE self)
{
  Window win = None;

  rb_check_frozen(self);
  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Check values */
  if(0 <= (win = NUM2LONG(rb_iv_get(self, "@win"))))
    {
      int *tags = NULL, *flags = NULL;
      char *wmname = NULL, *wminstance = NULL, *wmclass = NULL, *role = NULL;

      /* Fetch name, instance and class */
      subSharedPropertyClass(display, win, &wminstance, &wmclass);
      subSharedPropertyName(display, win, &wmname, wmclass);

      /* Fetch tags, flags and role */
      tags  = (int *)subSharedPropertyGet(display, win, XA_CARDINAL,
        XInternAtom(display, "SUBTLE_CLIENT_TAGS", False), NULL);
      flags = (int *)subSharedPropertyGet(display, win, XA_CARDINAL,
        XInternAtom(display, "SUBTLE_CLIENT_FLAGS", False), NULL);
      role  = subSharedPropertyGet(display, win, XA_STRING,
        XInternAtom(display, "WM_WINDOW_ROLE", False), NULL);

      /* Set properties */
      rb_iv_set(self, "@tags",     tags  ? INT2FIX(*tags)  : INT2FIX(0));
      rb_iv_set(self, "@flags",    flags ? INT2FIX(*flags) : INT2FIX(0));
      rb_iv_set(self, "@name",     rb_str_new2(wmname));
      rb_iv_set(self, "@instance", rb_str_new2(wminstance));
      rb_iv_set(self, "@klass",    rb_str_new2(wmclass));
      rb_iv_set(self, "@role",     role ? rb_str_new2(role) : Qnil);

      /* Set to nil for on demand loading */
      rb_iv_set(self, "@geometry", Qnil);
      rb_iv_set(self, "@gravity",  Qnil);

      if(tags)  free(tags);
      if(flags) free(flags);
      if(role)  free(role);
      free(wmname);
      free(wminstance);
      free(wmclass);
    }
  else rb_raise(rb_eStandardError, "Invalid client id `%#lx'", win);

  return self;
}
views → Array

Get array of Views Client is visible.

1 client.views
2 => [#<Subtlext::View:xxx>, #<Subtlext::View:xxx>]
3 
4 client.views
5 => nil
[show source]
VALUE
subextClientViewList(VALUE self)
{
  int i, nnames = 0;
  char **names = NULL;
  VALUE win = Qnil, array = Qnil, method = Qnil, klass = Qnil;
  unsigned long *view_tags = NULL, *client_tags = NULL, *flags = NULL;

  /* Check ruby object */
  rb_check_frozen(self);
  GET_ATTR(self, "@win", win);

  subextSubtlextConnect(NULL); ///< Implicit open connection

  /* Fetch data */
  method  = rb_intern("new");
  klass   = rb_const_get(mod, rb_intern("View"));
  array   = rb_ary_new();
  names   = subSharedPropertyGetStrings(display, DefaultRootWindow(display),
    XInternAtom(display, "_NET_DESKTOP_NAMES", False), &nnames);
  view_tags   = (unsigned long *)subSharedPropertyGet(display,
    DefaultRootWindow(display), XA_CARDINAL, XInternAtom(display,
    "SUBTLE_VIEW_TAGS", False), NULL);
  client_tags = (unsigned long *)subSharedPropertyGet(display, NUM2LONG(win),
    XA_CARDINAL, XInternAtom(display, "SUBTLE_CLIENT_TAGS", False), NULL);
  flags       = (unsigned long *)subSharedPropertyGet(display, NUM2LONG(win),
    XA_CARDINAL, XInternAtom(display, "SUBTLE_CLIENT_FLAGS", False), NULL);

  /* Check results */
  if(names && view_tags && client_tags)
    {
      for(i = 0; i < nnames; i++)
        {
          /* Check if there are common tags or window is stick */
          if((view_tags[i] & *client_tags) ||
              (flags && *flags & SUB_EWMH_STICK))
            {
              /* Create new view */
              VALUE v = rb_funcall(klass, method, 1, rb_str_new2(names[i]));

              rb_iv_set(v, "@id", INT2FIX(i));
              rb_ary_push(array, v);
            }
        }

    }

  if(names)       XFreeStringList(names);
  if(view_tags)   free(view_tags);
  if(client_tags) free(client_tags);
  if(flags)       free(flags);

  return array;
}