Class for interaction with views
Methods
Public Class
Public Instance
Public Class methods
Get currently active View.
Subtlext::View.current => #<Subtlext::View:xxx>
VALUE subextViewSingCurrent(VALUE self) { int nnames = 0; char **names = NULL; long *tags = NULL; unsigned long *cur_view = NULL; VALUE view = Qnil; subextSubtlextConnect(NULL); ///< Implicit open connection /* Fetch data */ names = subSharedPropertyGetStrings(display, DefaultRootWindow(display), XInternAtom(display, "_NET_DESKTOP_NAMES", False), &nnames); cur_view = (unsigned long *)subSharedPropertyGet(display, DefaultRootWindow(display), XA_CARDINAL, XInternAtom(display, "_NET_CURRENT_DESKTOP", False), NULL); tags = (long *)subSharedPropertyGet(display, ROOT, XA_CARDINAL, XInternAtom(display, "SUBTLE_VIEW_TAGS", False), NULL); /* Check results */ if(names && cur_view && tags) { /* Create instance */ view = subextViewInstantiate(names[*cur_view]); rb_iv_set(view, "@id", INT2FIX(*cur_view)); rb_iv_set(view, "@tags", LONG2NUM(tags[*cur_view])); } if(names) XFreeStringList(names); if(cur_view) free(cur_view); if(tags) free(tags); return view; }
Find View by a given value which can be of following type:
Fixnum |
Array index of the |
String |
Regexp match against name of Views, returns a View on single match or an Array on multiple matches. |
Symbol |
Either :current for current View, :all for an array of all Views or any string for an exact match. |
Subtlext::View.find(1) => [#<Subtlext::View:xxx>] Subtlext::View.find("subtle") => [#<Subtlext::View:xxx>] Subtlext::View[".*"] => [#<Subtlext::View:xxx>, #<Subtlext::View:xxx>] Subtlext::View["subtle"] => [] Subtlext::View[:terms] => #<Subtlext::View:xxx>]
VALUE subextViewSingFind(VALUE self, VALUE value) { return ViewFind(value, False); }
Find first View by a given value which can be of following type:
Fixnum |
Array index of the |
String |
Regexp match against name of Views, returns a View on single match or an Array on multiple matches. |
Symbol |
Either :current for current View, :all for an array of all Views or any string for an exact match. |
Subtlext::View.first(1) => #<Subtlext::View:xxx> Subtlext::View.first("subtle") => #<Subtlext::View:xxx>
VALUE subextViewSingFirst(VALUE self, VALUE value) { return ViewFind(value, True); }
Get an array of all Views based on the _NET_DESKTOP_NAMES
property list.
Subtlext::View.list => [#<Subtlext::View:xxx>, #<Subtlext::View:xxx>] Subtlext::View.list => []
VALUE subextViewSingList(VALUE self) { int i, nnames = 0; long *tags = NULL; char **names = NULL; VALUE meth = Qnil, klass = Qnil, array = Qnil, v = Qnil; subextSubtlextConnect(NULL); ///< Implicit open connection /* Fetch data */ klass = rb_const_get(mod, rb_intern("View")); meth = rb_intern("new"); array = rb_ary_new(); names = subSharedPropertyGetStrings(display, DefaultRootWindow(display), XInternAtom(display, "_NET_DESKTOP_NAMES", False), &nnames); tags = (long *)subSharedPropertyGet(display, ROOT, XA_CARDINAL, XInternAtom(display, "SUBTLE_VIEW_TAGS", False), NULL); /* Check results */ if(names && tags) { for(i = 0; i < nnames; i++) { if(!NIL_P(v = rb_funcall(klass, meth, 1, rb_str_new2(names[i])))) { rb_iv_set(v, "@id", INT2FIX(i)); rb_iv_set(v, "@tags", LONG2NUM(tags[i])); rb_ary_push(array, v); } } } if(names) XFreeStringList(names); if(tags) free(tags); return array; }
Create a new View object locally without calling save automatically.
The View won't be visible until save is called.
view = Subtlext::View.new("subtle") => #<Subtlext::View:xxx>
VALUE subextViewInit(VALUE self, VALUE name) { if(T_STRING != rb_type(name)) rb_raise(rb_eArgError, "Unexpected value-type `%s'", rb_obj_classname(name)); /* Init object */ rb_iv_set(self, "@id", Qnil); rb_iv_set(self, "@name", name); rb_iv_set(self, "@tags", INT2FIX(0)); subextSubtlextConnect(NULL); ///< Implicit open connection return self; }
Get an array of all visible Views on connected Screens.
Subtlext::View.visible => [#<Subtlext::View:xxx>, #<Subtlext::View:xxx>] Subtlext::View.visible => []
VALUE subextViewSingVisible(VALUE self) { int i, nnames = 0, *tags = NULL; char **names = NULL; unsigned long *visible = NULL; VALUE meth = Qnil, klass = Qnil, array = Qnil, v = Qnil; subextSubtlextConnect(NULL); ///< Implicit open connection /* Fetch data */ meth = 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); visible = (unsigned long *)subSharedPropertyGet(display, DefaultRootWindow(display), XA_CARDINAL, XInternAtom(display, "SUBTLE_VISIBLE_VIEWS", False), NULL); tags = (int *)subSharedPropertyGet(display, ROOT, XA_CARDINAL, XInternAtom(display, "SUBTLE_VIEW_TAGS", False), NULL); /* Check results */ if(names && visible && tags) { for(i = 0; i < nnames; i++) { /* Create view on match */ if(*visible & (1L << (i + 1)) && !NIL_P(v = rb_funcall(klass, meth, 1, rb_str_new2(names[i])))) { rb_iv_set(v, "@id", INT2FIX(i)); rb_iv_set(v, "@tags", INT2FIX(tags[i])); rb_ary_push(array, v); } } } if(names) XFreeStringList(names); if(visible) free(visible); if(tags) free(tags); return array; }
Public Instance methods
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 id)
object1 <=> object2 => 0
static VALUE SubtlextEqualSpaceId(VALUE self, VALUE other) { return SubtlextSpaceship(self, other, "@id"); }
Whether both objects have the same values (based on id)
object1 == object2 => true
static VALUE SubtlextEqualId(VALUE self, VALUE other) { return SubtlextEqual(self, other, "@id", False); }
Get arbitrary persistent property string or symbol value
object["wm"] => "subtle" object[:wm] => "subtle"
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; }
Set arbitrary persistent property string or symbol value
Symbols are implictly converted to string, to remove a property just set it
to nil
.
object["wm"] = "subtle" => nil object[:wm] = "subtle" => nil object[:wm] = nil => nil
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; }
Get an array of visible Clients on this View.
view.clients => [#<Subtlext::Client:xxx>, #<Subtlext::Client:xxx>] view.clients => []
VALUE subextViewClients(VALUE self) { int i, nclients = 0; Window *clients = NULL; VALUE id = Qnil, klass = Qnil, meth = Qnil, array = Qnil, client = Qnil; unsigned long *view_tags = NULL; /* Check ruby object */ rb_check_frozen(self); GET_ATTR(self, "@id", id); subextSubtlextConnect(NULL); ///< Implicit open connection /* Fetch data */ klass = rb_const_get(mod, rb_intern("Client")); meth = rb_intern("new"); array = rb_ary_new(); clients = subextSubtlextWindowList("_NET_CLIENT_LIST", &nclients); view_tags = (unsigned long *)subSharedPropertyGet(display, DefaultRootWindow(display), XA_CARDINAL, XInternAtom(display, "SUBTLE_VIEW_TAGS", False), NULL); /* Check results */ if(clients && view_tags) { for(i = 0; i < nclients; i++) { unsigned long *client_tags = NULL, *flags = NULL; /* Fetch window data */ client_tags = (unsigned long *)subSharedPropertyGet(display, clients[i], XA_CARDINAL, XInternAtom(display, "SUBTLE_CLIENT_TAGS", False), NULL); flags = (unsigned long *)subSharedPropertyGet(display, clients[i], XA_CARDINAL, XInternAtom(display, "SUBTLE_CLIENT_FLAGS", False), NULL); /* Check if there are common tags or window is stick */ if((client_tags && view_tags[FIX2INT(id)] & *client_tags) || (flags && *flags & SUB_EWMH_STICK)) { if(RTEST(client = rb_funcall(klass, meth, 1, LONG2NUM(clients[i])))) { subextClientUpdate(client); rb_ary_push(array, client); } } if(client_tags) free(client_tags); if(flags) free(flags); } } if(clients) free(clients); if(view_tags) free(view_tags); return array; }
VALUE subextViewAskCurrent(VALUE self) { VALUE id = Qnil, ret = Qfalse;; unsigned long *cur_view = NULL; /* Check ruby object */ rb_check_frozen(self); GET_ATTR(self, "@id", id); /* Check results */ if((cur_view = (unsigned long *)subSharedPropertyGet(display, DefaultRootWindow(display), XA_CARDINAL, XInternAtom(display, "_NET_CURRENT_DESKTOP", False), NULL))) { if(FIX2INT(id) == *cur_view) ret = Qtrue; free(cur_view); } return ret; }
Whether both objects have the same values and types (based on id)
object1.eql? object2 => true
static VALUE SubtlextEqualTypedId(VALUE self, VALUE other) { return SubtlextEqual(self, other, "@id", True); }
SubtlextTagAsk {{{
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; }
Convert this object to hash.
puts object.hash => 1746246187916025425
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; }
VALUE subextViewIcon(VALUE self) { unsigned long nicons = 0; VALUE id = Qnil, ret = Qnil; unsigned long *icons = NULL; /* Check ruby object */ rb_check_frozen(self); GET_ATTR(self, "@id", id); subextSubtlextConnect(NULL); ///< Implicit open connection /* Check results */ if((icons = (unsigned long *)subSharedPropertyGet(display, DefaultRootWindow(display), XA_CARDINAL, XInternAtom(display, "SUBTLE_VIEW_ICONS", False), &nicons))) { int iid = FIX2INT(id); /* Check if id is in range and icon available */ if(0 <= iid && iid < nicons && -1 != icons[iid]) { /* Create new icon */ ret = rb_funcall(rb_const_get(mod, rb_intern("Icon")), rb_intern("new"), 1, LONG2NUM(icons[iid])); } free(icons); } return ret; }
Set this View to the current active one
view.jump => #<Subtlext::View:xxx>
VALUE subextViewJump(VALUE self) { VALUE id = Qnil; SubMessageData data = { { 0, 0, 0, 0, 0 } }; /* Check ruby object */ rb_check_frozen(self); GET_ATTR(self, "@id", id); subextSubtlextConnect(NULL); ///< Implicit open connection /* Send message */ data.l[0] = FIX2INT(id); data.l[2] = -1; subSharedMessage(display, DefaultRootWindow(display), "_NET_CURRENT_DESKTOP", data, 32, True); return self; }
Remove this View from subtle and freeze this object.
view.kill => nil
VALUE subextViewKill(VALUE self) { VALUE id = Qnil; SubMessageData data = { { 0, 0, 0, 0, 0 } }; /* Check ruby object */ rb_check_frozen(self); GET_ATTR(self, "@id", id); subextSubtlextConnect(NULL); ///< Implicit open connection /* Send message */ data.l[0] = FIX2INT(id); subSharedMessage(display, DefaultRootWindow(display), "SUBTLE_VIEW_KILL", data, 32, True); rb_obj_freeze(self); ///< Freeze object return Qnil; }
Select next View, but doesn't cycle list.
view.next => #<Subtlext::View:xxx>
VALUE subextViewSelectNext(VALUE self) { return ViewSelect(self, SUB_VIEW_NEXT); }
Select prev View, but doesn't cycle list.
view.prev => #<Subtlext::View:xxx>
VALUE subextViewSelectPrev(VALUE self) { return ViewSelect(self, SUB_VIEW_PREV); }
Save new View object.
view.save => #<Subtlext::View:xxx>
VALUE subextViewSave(VALUE self) { int id = -1; VALUE name = Qnil; /* Check ruby object */ rb_check_frozen(self); GET_ATTR(self, "@name", name); subextSubtlextConnect(NULL); ///< Implicit open connection /* Create view if needed */ if(-1 == (id = subextSubtlextFindString("_NET_DESKTOP_NAMES", RSTRING_PTR(name), NULL, SUB_MATCH_EXACT))) { SubMessageData data = { { 0, 0, 0, 0, 0 } }; snprintf(data.b, sizeof(data.b), "%s", RSTRING_PTR(name)); subSharedMessage(display, DefaultRootWindow(display), "SUBTLE_VIEW_NEW", data, 8, True); id = subextSubtlextFindString("_NET_DESKTOP_NAMES", RSTRING_PTR(name), NULL, SUB_MATCH_EXACT); } /* Guess view id */ if(-1 == id) { int nnames = 0; char **names = NULL; /* Get names of views */ if((names = subSharedPropertyGetStrings(display, DefaultRootWindow(display), XInternAtom(display, "_NET_DESKTOP_NAMES", False), &nnames))) { id = nnames; ///< New id should be last if(names) XFreeStringList(names); } } /* Set properties */ rb_iv_set(self, "@id", INT2FIX(id)); return self; }
Set style state of this Object, use nil to reset state.
object.style = :blue => nil
static VALUE SubtlextStyle(VALUE self, VALUE value) { char *prop = NULL; VALUE id = Qnil, str = Qnil; SubMessageData data = { { 0, 0, 0, 0, 0 } }; /* Check ruby object */ rb_check_frozen(self); GET_ATTR(self, "@id", id); /* Check object type */ if(rb_obj_is_instance_of(self, rb_const_get(mod, rb_intern("View")))) prop = "SUBTLE_VIEW_STYLE"; else prop = "SUBTLE_SUBLET_STYLE"; /* Check value type */ switch(rb_type(value)) { case T_SYMBOL: str = rb_sym_to_s(value); case T_STRING: snprintf(data.b, sizeof(data.b), "%d#%s", (int)FIX2INT(id), RSTRING_PTR(str)); subSharedMessage(display, ROOT, prop, data, 32, True); break; case T_NIL: snprintf(data.b, sizeof(data.b), "%d#", (int)FIX2INT(id)); subSharedMessage(display, ROOT, prop, data, 32, True); break; default: rb_raise(rb_eArgError, "Unexpected value-type `%s'", rb_obj_classname(value)); } return Qnil; }
Add an existing tag to window
object.tag("subtle") => nil object.tag([ #<Subtlext::Tag:xxx>, #<Subtlext::Tag:xxx> ]) => nil object + "subtle" => nil
static VALUE SubtlextTagAdd(VALUE self, VALUE value) { return SubtlextTag(self, value, 1); }
Get list of tags for window
object.tags => [#<Subtlext::Tag:xxx>, #<Subtlext::Tag:xxx>]
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; }
Set or remove all tags at once
# Set new tags object.tags=([ #<Subtlext::Tag:xxx>, #<Subtlext::Tag:xxx> ]) => nil # Remove all tags object.tags=([]) => nil
static VALUE SubtlextTagWriter(VALUE self, VALUE value) { return SubtlextTag(self, value, 0); }
Convert this View object to string.
puts view => "subtle"
VALUE subextViewToString(VALUE self) { VALUE name = Qnil; /* Check ruby object */ GET_ATTR(self, "@name", name); return name; }
Remove an existing tag from window
object.untag("subtle") => nil object.untag([ #<Subtlext::Tag:xxx>, #<Subtlext::Tag:xxx> ]) => nil object - "subtle" => nil
static VALUE SubtlextTagDel(VALUE self, VALUE value) { return SubtlextTag(self, value, -1); }
VALUE subextViewUpdate(VALUE self) { long *tags = NULL, ntags = 0; VALUE id = Qnil; /* Check ruby object */ rb_check_frozen(self); GET_ATTR(self, "@id", id); subextSubtlextConnect(NULL); ///< Implicit open connection /* Fetch tags */ if((tags = (long *)subSharedPropertyGet(display, ROOT, XA_CARDINAL, XInternAtom(display, "SUBTLE_VIEW_TAGS", False), (unsigned long *)&ntags))) { int idx = FIX2INT(id); rb_iv_set(self, "@tags", LONG2NUM(idx < ntags ? tags[idx] : 0)); free(tags); } return self; }