lib/firewatir/x11.rb in firewatir-1.6.5 vs lib/firewatir/x11.rb in firewatir-1.6.6.rc1

- old
+ new

@@ -1,192 +1,192 @@ -require 'dl/import' -require 'dl/struct' - -require 'singleton' - -module X11 - class << self - include X11 # Do this so we can call imported libraries directly on X11 - end - - # Load the X11 library - extend DL::Importable - dlload "libX11.so" - - # Import necessary functions from X11 here. - import("XOpenDisplay", "unsigned long", ["char*"]) - import("XScreenCount", "int", ["unsigned long"]) - import("XRootWindow", "unsigned long", ["unsigned long","int"]) - - import("XFree", "int", ["void*"]) - - import("XFetchName", "int", ["unsigned long","unsigned long","char**"]) - import("XGetClassHint", "int", ["unsigned long","unsigned long","void*"]) - import("XQueryTree", "int", ["unsigned long","unsigned long","unsigned long*","unsigned long*","unsigned long**","unsigned int*"]) - - import("XSetInputFocus", "int", ["unsigned long","unsigned long","int","long"]) - import("XSendEvent", "int", ["unsigned long","unsigned long","int","long","void*"]) - import("XFlush", "int", ["unsigned long"]) - - # Structs we will use in API calls. - # Pointer structs are necessary when the API uses a pointer parameter for a return value. - ULPPointer = struct [ - "long* value" - ] - ULPointer = struct [ - "long value" - ] - CPPointer = struct [ - "char* value" - ] - UIPointer = struct [ - "int value" - ] - # Info about window class - XClassHint = struct [ - "char* res_name", - "char* res_class" - ] - # Event struct for key presses - XKeyEvent = struct [ - "int type", - "long serial", - "int send_event", - "long display", - "long window", - "long root", - "long subwindow", - "long time", - "int x", - "int y", - "int x_root", - "int y_root", - "int state", - "int keycode", - "int same_screen" - ] - - # End of library imports. - - # X11 Display. Singleton -- assumes single display. - # Assumes the current display is the same as the one running FireFox. - # Represented by memory pointer (which we treat in-code as an unsigned long). - class Display - include Singleton - - def initialize - @xdisplay = X11.xOpenDisplay(""); - end - - # Array of screens associated with this display. - def screens - nScreens = X11.xScreenCount(@xdisplay); - (0...nScreens).collect{|n| Screen.new(n,@xdisplay)} - end - end - - # A display screen, for multi-monitor displays like mine ;-) - # Represented by display pointer and screen number. - class Screen - def initialize(screen_num,xdisplay) - @screen_num = screen_num - @xdisplay = xdisplay - end - - # Root window containing all other windows in this screen. - def root_window - Window.new(X11.xRootWindow(@xdisplay,@screen_num),@screen_num,@xdisplay) - end - end - - # An X11 Window (toplevel window, widget, applet, etc.) - # Represented by its XID, an unsigned long. - class Window - attr_reader :xid, :name, :class, :hint, :parent - - def initialize(xid,screen_num,xdisplay,parent=nil) - @xid = xid - @screen_num = screen_num - @xdisplay = xdisplay - @parent = parent - load_standard - end - - # Child windows - def children - tree[:children].collect{|c| Window.new(c,@screen_num,@xdisplay,self)} - end - - # XID of parent window - def parent_xid - parent ? parent.xid : nil - end - - # Send a key press to this window - def send_key(key=:enter,sleep=nil) - # TODO expand this list out, add support for shift, etc. - @@keys = {:enter => 36, :tab => 23} unless defined?@@keys - keycode = @@keys[key] - X11.xSetInputFocus(@xdisplay, @xid, 1, 0) - sleep(sleep) if sleep - e = create_key_event - e.keycode = keycode - e.type = 2 # press - X11.xSendEvent(@xdisplay,@xid,1,1,e) - e.type = 3 # release - X11.xSendEvent(@xdisplay,@xid,1,2,e) - X11.xFlush(@xdisplay) - end - - private - - # Retrieve this window's portion of the window tree - # Includes display root, parent, and children - def tree - tree = {:children => [], :parent => 0, :root => 0} - children = ULPPointer.malloc - root = ULPointer.malloc - parent = ULPointer.malloc - n = UIPointer.malloc - r=X11.xQueryTree(@xdisplay,@xid,root,parent,children,n) - tree[:parent] = parent.value - tree[:root] = root.value - tree[:children] = children.value.to_s(4*n.value).unpack("L*") if children.value - tree - end - - # Load some standard attributes (name and class) - def load_standard - name = CPPointer.malloc - if X11.xFetchName(@xdisplay,@xid,name) != 0 - @name = name.value.to_s - X11.xFree name.value - end - classHint = XClassHint.malloc - res = X11.xGetClassHint(@xdisplay,@xid,classHint) - if res != 0 then - @class = classHint.res_name.to_s - @hint = classHint.res_class.to_s - X11.xFree classHint.res_name - X11.xFree classHint.res_class - end - end - - # Create an X11 Key Event for this window and set defaults - def create_key_event - ke = XKeyEvent.malloc - ke.serial = 0 - ke.send_event = 1 - ke.display = @xdisplay - ke.window = @xid - ke.subwindow = 0 - ke.root = tree[:root] - ke.time = Time.now.sec - ke.state = 0 - ke.same_screen = 0 - return ke - end - - end - -end - +require 'dl/import' +require 'dl/struct' + +require 'singleton' + +module X11 + class << self + include X11 # Do this so we can call imported libraries directly on X11 + end + + # Load the X11 library + extend DL::Importable + dlload "libX11.so" + + # Import necessary functions from X11 here. + import("XOpenDisplay", "unsigned long", ["char*"]) + import("XScreenCount", "int", ["unsigned long"]) + import("XRootWindow", "unsigned long", ["unsigned long","int"]) + + import("XFree", "int", ["void*"]) + + import("XFetchName", "int", ["unsigned long","unsigned long","char**"]) + import("XGetClassHint", "int", ["unsigned long","unsigned long","void*"]) + import("XQueryTree", "int", ["unsigned long","unsigned long","unsigned long*","unsigned long*","unsigned long**","unsigned int*"]) + + import("XSetInputFocus", "int", ["unsigned long","unsigned long","int","long"]) + import("XSendEvent", "int", ["unsigned long","unsigned long","int","long","void*"]) + import("XFlush", "int", ["unsigned long"]) + + # Structs we will use in API calls. + # Pointer structs are necessary when the API uses a pointer parameter for a return value. + ULPPointer = struct [ + "long* value" + ] + ULPointer = struct [ + "long value" + ] + CPPointer = struct [ + "char* value" + ] + UIPointer = struct [ + "int value" + ] + # Info about window class + XClassHint = struct [ + "char* res_name", + "char* res_class" + ] + # Event struct for key presses + XKeyEvent = struct [ + "int type", + "long serial", + "int send_event", + "long display", + "long window", + "long root", + "long subwindow", + "long time", + "int x", + "int y", + "int x_root", + "int y_root", + "int state", + "int keycode", + "int same_screen" + ] + + # End of library imports. + + # X11 Display. Singleton -- assumes single display. + # Assumes the current display is the same as the one running FireFox. + # Represented by memory pointer (which we treat in-code as an unsigned long). + class Display + include Singleton + + def initialize + @xdisplay = X11.xOpenDisplay(""); + end + + # Array of screens associated with this display. + def screens + nScreens = X11.xScreenCount(@xdisplay); + (0...nScreens).collect{|n| Screen.new(n,@xdisplay)} + end + end + + # A display screen, for multi-monitor displays like mine ;-) + # Represented by display pointer and screen number. + class Screen + def initialize(screen_num,xdisplay) + @screen_num = screen_num + @xdisplay = xdisplay + end + + # Root window containing all other windows in this screen. + def root_window + Window.new(X11.xRootWindow(@xdisplay,@screen_num),@screen_num,@xdisplay) + end + end + + # An X11 Window (toplevel window, widget, applet, etc.) + # Represented by its XID, an unsigned long. + class Window + attr_reader :xid, :name, :class, :hint, :parent + + def initialize(xid,screen_num,xdisplay,parent=nil) + @xid = xid + @screen_num = screen_num + @xdisplay = xdisplay + @parent = parent + load_standard + end + + # Child windows + def children + tree[:children].collect{|c| Window.new(c,@screen_num,@xdisplay,self)} + end + + # XID of parent window + def parent_xid + parent ? parent.xid : nil + end + + # Send a key press to this window + def send_key(key=:enter,sleep=nil) + # TODO expand this list out, add support for shift, etc. + @@keys = {:enter => 36, :tab => 23} unless defined?@@keys + keycode = @@keys[key] + X11.xSetInputFocus(@xdisplay, @xid, 1, 0) + sleep(sleep) if sleep + e = create_key_event + e.keycode = keycode + e.type = 2 # press + X11.xSendEvent(@xdisplay,@xid,1,1,e) + e.type = 3 # release + X11.xSendEvent(@xdisplay,@xid,1,2,e) + X11.xFlush(@xdisplay) + end + + private + + # Retrieve this window's portion of the window tree + # Includes display root, parent, and children + def tree + tree = {:children => [], :parent => 0, :root => 0} + children = ULPPointer.malloc + root = ULPointer.malloc + parent = ULPointer.malloc + n = UIPointer.malloc + r=X11.xQueryTree(@xdisplay,@xid,root,parent,children,n) + tree[:parent] = parent.value + tree[:root] = root.value + tree[:children] = children.value.to_s(4*n.value).unpack("L*") if children.value + tree + end + + # Load some standard attributes (name and class) + def load_standard + name = CPPointer.malloc + if X11.xFetchName(@xdisplay,@xid,name) != 0 + @name = name.value.to_s + X11.xFree name.value + end + classHint = XClassHint.malloc + res = X11.xGetClassHint(@xdisplay,@xid,classHint) + if res != 0 then + @class = classHint.res_name.to_s + @hint = classHint.res_class.to_s + X11.xFree classHint.res_name + X11.xFree classHint.res_class + end + end + + # Create an X11 Key Event for this window and set defaults + def create_key_event + ke = XKeyEvent.malloc + ke.serial = 0 + ke.send_event = 1 + ke.display = @xdisplay + ke.window = @xid + ke.subwindow = 0 + ke.root = tree[:root] + ke.time = Time.now.sec + ke.state = 0 + ke.same_screen = 0 + return ke + end + + end + +end +