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