Class for interaction with trays
Methods
Public Class
Public Instance
Public Instance Aliases
click | -> | send_button | |
to_s | -> | to_str |
Aliases |
Attributes
Public Class methods
Find Tray by a given value which can be of following type:
Fixnum |
Array index of the | ||||||
String |
Regexp match against both | ||||||
Hash |
Instead of just match
| ||||||
Symbol |
Either :all for an array of all Trays or any string for an exact match. |
Subtlext::Tray.find(1) => [#<Subtlext::Tray:xxx>] Subtlext::Tray.find("subtle") => [#<Subtlext::Tray:xxx>] Subtlext::Tray[".*"] => [#<Subtlext::Tray:xxx>, #<Subtlext::Tray:xxx>] Subtlext::Tray["subtle"] => [] Subtlext::Tray[:terms] => [#<Subtlext::Tray:xxx>] Subtlext::Tray[name: "subtle"] => [#<Subtlext::Tray:xxx>]
VALUE subextTraySingFind(VALUE self, VALUE value) { return TrayFind(value, False); }
Find first Tray by a given value which can be of following type:
Fixnum |
Array index of the | ||||||
String |
Regexp match against both | ||||||
Hash |
Instead of just match
| ||||||
Symbol |
Either :all for an array of all Trays or any string for an exact match. |
Subtlext::Tray.first(1) => #<Subtlext::Tray:xxx> Subtlext::Tray.first("subtle") => #<Subtlext::Tray:xxx>
VALUE subextTraySingFirst(VALUE self, VALUE value) { return TrayFind(value, True); }
Get an array of all Trays based on SUBTLE_TRAY_LIST
property
list.
Subtlext::Tray.list => [#<Subtlext::Tray:xxx>, #<Subtlext::Tray:xxx>] Subtlext::Tray.list => []
VALUE subextTraySingList(VALUE self) { int i, ntrays = 0; Window *trays = NULL; VALUE meth = Qnil, klass = Qnil, array = Qnil; subextSubtlextConnect(NULL); ///< Implicit open connection /* Fetch data */ meth = rb_intern("new"); klass = rb_const_get(mod, rb_intern("Tray")); array = rb_ary_new(); /* Check results */ if((trays = subextSubtlextWindowList("SUBTLE_TRAY_LIST", &ntrays))) { for(i = 0; i < ntrays; i++) { VALUE t = rb_funcall(klass, meth, 1, LONG2NUM(trays[i])); if(!NIL_P(t)) subextTrayUpdate(t); rb_ary_push(array, t); } free(trays); } return array; }
Create a new Tray object locally without calling save automatically.
The Tray won't be visible until save is called.
tag = Subtlext::Tray.new("subtle") => #<Subtlext::Tray:xxx>
VALUE subextTrayInit(VALUE self, VALUE win) { if(!FIXNUM_P(win) && T_BIGNUM != rb_type(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, "@klass", Qnil); rb_iv_set(self, "@title", Qnil); subextSubtlextConnect(NULL); ///< Implicit open connection return self; }
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 win)
object1 <=> object2 => 0
static VALUE SubtlextEqualSpaceWindow(VALUE self, VALUE other) { return SubtlextSpaceship(self, other, "@win"); }
Whether both objects have the same values (based on win)
object1 == object2 => true
static VALUE SubtlextEqualWindow(VALUE self, VALUE other) { return SubtlextEqual(self, other, "@win", 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; }
Whether both objects have the same value and types (based on win)
object1.eql? object2 => true
static VALUE SubtlextEqualTypedWindow(VALUE self, VALUE other) { return SubtlextEqual(self, other, "@win", True); }
Set focus to window
object.focus => nil
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; }
Check if window has focus
object.focus? => true object.focus? => false
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; }
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; }
Send a close signal to Client and freeze this object.
tray.kill => nil
VALUE subextTrayKill(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; }
Get window pid
object.pid => 123
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; }
Emulate a click on a window with optional button and x/y position
object.send_button => nil object.send_button(2) => Object
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; }
Emulate a keypress on a window
object.send_key("d") => Object
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; }
Convert this Tray object to string.
puts tray => "subtle"
VALUE subextTrayToString(VALUE self) { VALUE name = Qnil; /* Check ruby object */ GET_ATTR(self, "@name", name); return name; }
VALUE subextTrayUpdate(VALUE self) { Window win = None; /* Check ruby object */ rb_check_frozen(self); subextSubtlextConnect(NULL); ///< Implicit open connection /* Get tray values */ win = NUM2LONG(rb_iv_get(self, "@win")); /* Check values */ if(0 <= win) { char *wmname = NULL, *wminstance = NULL, *wmclass = NULL; /* Get name, instance and class */ subSharedPropertyClass(display, win, &wminstance, &wmclass); subSharedPropertyName(display, win, &wmname, wmclass); /* Set properties */ 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)); free(wmname); free(wminstance); free(wmclass); } else rb_raise(rb_eStandardError, "Invalid tray id `%#lx`", win); return self; }