From da2fe515967194116e7ceec3d096cb1db8be6735 Mon Sep 17 00:00:00 2001 From: Vidar Hokstad Date: Thu, 11 Jan 2024 19:24:49 +0000 Subject: [PATCH] Cleanups, more automated lookups of atoms to avoid needing to dereference constants. More constants and requestsm including SendEvent, and a helper for ClientMessage, w/example --- example/client_message.rb | 13 +++++++++++ lib/X11/display.rb | 43 +++++++++++++++++++++++++++++-------- lib/X11/form.rb | 45 ++++++++++++++++++++++++++++++++++++++- lib/X11/protocol.rb | 10 ++++----- lib/X11/screen.rb | 24 +++++---------------- 5 files changed, 100 insertions(+), 35 deletions(-) create mode 100644 example/client_message.rb diff --git a/example/client_message.rb b/example/client_message.rb new file mode 100644 index 0000000..73f521e --- /dev/null +++ b/example/client_message.rb @@ -0,0 +1,13 @@ + +$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) + +require 'X11' + +display = X11::Display.new + +display.client_message( + mask: X11::Form::SubstructureNotifyMask | X11::Form::SubstructureRedirectMask, + type: :_NET_CURRENT_DESKTOP, + data: ARGV.shift.to_i +) + diff --git a/lib/X11/display.rb b/lib/X11/display.rb index 880b449..ad335f5 100644 --- a/lib/X11/display.rb +++ b/lib/X11/display.rb @@ -316,6 +316,12 @@ module X11 def atom(name) return name if name.is_a?(Integer) # Allow atom(atom_integer_or_symbol) + begin + return Form::Atoms.const_get(name.to_sym) if Form::Atoms.const_defined?(name.to_sym) + rescue + # const_defined? will throw if name isn't a valid constant name, but + # that's fine + end name = name.to_sym intern_atom(false, name) if !@atoms[name] @atoms[name] @@ -404,7 +410,10 @@ module X11 def u8(*args) = args.pack("c*") def u16(*args) = args.pack("v*") def u32(*args) = args.pack("V*") - def atom_enum(val) = open_enum(val, {cardinal: Form::CardinalAtom, atom: Form::AtomAtom, window: Form::WindowAtom}) + def atom_enum(val) + open_enum(val, {cardinal: Form::CardinalAtom, atom: Form::AtomAtom, window: Form::WindowAtom}) || atom(val) + end + def window(*args) args.each {|a| raise "Window expected" if a.nil? } u32(*args) @@ -415,7 +424,7 @@ module X11 def set_input_focus(revert_to, focus, time=:now) # FIXME: This is an experiment. # Upside: Simpler. Downside: Doesn't work server-side. - # + # Probably a bad idea. revert_to = open_enum(revert_to, {none: 0, pointer_root: 1, parent: 2}) focus = open_enum(focus, {none: 0, pointer_root: 1 }) time = open_enum(time, {current_time: 0, now: 0}) @@ -455,9 +464,8 @@ module X11 def configure_window(window, x: nil, y: nil, width: nil, height: nil, border_width: nil, sibling: nil, stack_mode: nil) - mask = 0 values = [] - + mask = 0 mask |= set_value(values, 0x001, x) mask |= set_value(values, 0x002, y) mask |= set_value(values, 0x004, width) @@ -480,7 +488,9 @@ module X11 end - def create_gc(window, foreground: nil, background: nil) + def create_gc(window, foreground: nil, background: nil, + graphics_exposures: nil + ) mask = 0 args = [] @@ -489,12 +499,27 @@ module X11 # https://tronche.com/gui/x/xlib/GC/manipulating.html#XGCValues mask |= set_value(args, 0x04, foreground) mask |= set_value(args, 0x08, background) + mask |= set_value(args, 0x10000, graphics_exposures) gc = new_id write_request(X11::Form::CreateGC.new(gc, window, mask, args)) gc end + def send_event(...) = write_request(Form::SendEvent.new(...)) + def client_message(window: default_root, type: :ClientMessage, format: 32, destination: default_root, mask: 0, data: [], propagate: true) + f = {8 => "C20", 16 => "S10", 32 => "L5"}[format] + p f + data = (Array(data).map{|item|atom(item)} +[0]*20).pack(f) + event = Form::ClientMessage.new( + format, 0, window, atom(type), data + ) + event.code =33 + pp event + + send_event(propagate, destination, mask, event) + end + def put_image(*args) = write_request(X11::Form::PutImage.new(*args)) def clear_area(*args) = write_request(X11::Form::ClearArea.new(*args)) def copy_area(*args) = write_request(X11::Form::CopyArea.new(*args)) @@ -560,19 +585,19 @@ module X11 end when :rgb24 @rgb24 ||= formats.formats.find do |f| - f.type == 1 && + f.type == 1 && f.depth == 24 && f.direct.red == 16 && - f.direct.green == 8 && + f.direct.green == 8 && f.direct.blue == 0 end when :argb24 @argb24 ||= formats.formats.find do |f| - f.type == 1 && + f.type == 1 && f.depth == 32 && f.direct.alpha == 24 && f.direct.red == 16 && - f.direct.green == 8 && + f.direct.green == 8 && f.direct.blue == 0 end else diff --git a/lib/X11/form.rb b/lib/X11/form.rb index 18fe805..db5dc3d 100644 --- a/lib/X11/form.rb +++ b/lib/X11/form.rb @@ -184,6 +184,29 @@ module X11 end end + # # Predefined constants, that can be used in the form of symbols + + module Atoms + PRIMARY = 1 + SECONDARY = 2 + ARC = 3 + ATOM = 4 + BITMAP = 5 + CARDINAL = 6 + COLORMAP = 7 + CURSOR = 8 + #... + STRING = 31 + VISUALID = 32 + WINDOW = 33 + WM_COMMAND = 34 + WM_HINTS = 35 + end + + PointerWindow = 0 + InputFocus = 1 + + # FIXME: Deprecated in favour of the Constants module AtomAtom=4 CardinalAtom=6 WindowAtom=33 @@ -286,6 +309,9 @@ module X11 field :minor_opcode, Uint16 field :major_opcode, Uint8 unused 21 + + # The original request + attr_accessor :request end # XRender structures @@ -329,8 +355,9 @@ module X11 field :colormap, Colormap end - # Requests + # # Requests + # Constants, p112 onwards CopyFromParent = 0 InputOutput = 1 InputOnly = 2 @@ -358,12 +385,17 @@ module X11 PointerMotionMask = 0x000040 PointerMotionHintMask = 0x000080 Button1MotionMask = 0x000100 + # 0x200 .. 0x40000; page 113 ExposureMask = 0x008000 + VisibilityChangeMask = 0x010000 StructureNotifyMask = 0x020000 + ResizeRedirectMask = 0x040000 SubstructureNotifyMask = 0x080000 SubstructureRedirectMask=0x100000 FocusChangeMask = 0x200000 PropertyChangeMask = 0x400000 + ColormapChangeMask = 0x800000 + OwnerGrabButtonMask = 0x100000 class CreateWindow < BaseForm field :opcode, Uint8, value: 1 @@ -592,6 +624,15 @@ module X11 field :value, String8, :string end + class SendEvent < BaseForm + field :opcode, Uint8, value: 25 + field :propagate, Bool + field :request_length, Uint16, value: 11 + field :destination, Window + field :event_mask, Uint32 + field :event, Uint32 # FIXME: This is wrong, and will break on parsing. + end + class GrabButton < BaseForm field :opcode, Uint8, value: 28 field :owner_events, Bool @@ -678,6 +719,7 @@ module X11 ForegroundMask = 0x04 BackgroundMask = 0x08 FontMask = 0x4000 + GraphicsExposures = 0x10000 class CreateGC < BaseForm field :opcode, Uint8, value: 55 @@ -1002,6 +1044,7 @@ module X11 unused 1 field :sequence_number, Uint16 field :event, Window + field :window, Window field :above_sibling, Window field :x, Int16 field :y, Int16 diff --git a/lib/X11/protocol.rb b/lib/X11/protocol.rb index 6309b3a..be93a6e 100644 --- a/lib/X11/protocol.rb +++ b/lib/X11/protocol.rb @@ -1,14 +1,12 @@ module X11 module Protocol - # endiness of your machine + # endianess of your machine BYTE_ORDER = case [1].pack("L") - when "\0\0\0\1" - "B".ord - when "\1\0\0\0" - "l".ord + when "\0\0\0\1" then "B".ord + when "\1\0\0\0" then "l".ord else raise ByteOrderError.new "Cannot determine byte order" - end + end MAJOR = 11 MINOR = 0 diff --git a/lib/X11/screen.rb b/lib/X11/screen.rb index 324b738..669e9a1 100644 --- a/lib/X11/screen.rb +++ b/lib/X11/screen.rb @@ -7,25 +7,11 @@ module X11 @internal = data end - def root - @internal.root - end - - def root_depth - @internal.root_depth - end - - def root_visual - @internal.root_visual - end - - def width - @internal.width_in_pixels - end - - def height - @internal.height_in_pixels - end + def root = @internal.root + def root_depth = @internal.root_depth + def root_visual = @internal.root_visual + def width = @internal.width_in_pixels + def height = @internal.height_in_pixels def to_s "#"