=begin
	Ruby X11 Client Library
	Copyright 2001 by Mathieu Bouchard

	X11/XID.rb: Remote Objects

	$Id: XID.rb,v 1.60 2001/07/07 21:27:24 matju Exp $

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

=end

require "X11/Base"

module X11 # the whole file
#----------------------------------------------------------------#

# forward declarations
class XID; end
class Drawable<XID; end
class Window<Drawable; end
class Pixmap<Drawable; end
class Visual  <XID; end
class Colormap<XID; end
class Cursor  <XID; end
class Atom    <XID; end
class Fontable<XID; end
class Graphics<Fontable; end
class Font<Fontable; end

#----------------------------------------------------------------#
# More Complex Types of Aggregates

class WindowAttributes < PartialTuple; fields_are \
	[:background_pixmap,Any.of Pixmap,BackgroundPixmapChoice],
	[:background_pixel,Colornum],
	[:border_pixmap,Any.of Pixmap,CopyFromParent],
	[:border_pixel,Colornum],
	[:bit_gravity,BitGravity],
	[:win_gravity,WinGravity],
	[:backing_store,BackingStore],
	[:backing_planes,Uint32],
	[:backing_pixel,Colornum],
	[:override_redirect,Bool],
	[:save_under,Bool],
	[:event_mask,EventMask],
	[:do_not_propagate_mask,DeviceEventMask],
	[:colormap,Any.of Colormap,CopyFromParent],
	[:cursor,Cursor]
end

class WindowConfig < PartialTuple; fields_are \
	[:point, Point],
	[:size,  Size],
	[:border_width, Uint16],
	[:sibling, Window],
	[:stack_mode, StackMode]
end

#----------------------------------------------------------------#
# Remote Object Classes

class Atom < XID
	Self = [:self,Atom]

	def_remote_with_reply :get_name, 17, [Self,
	], [
		[:name, Uint16, :length], 22,
		[:name, String8, :data]]

end

class Drawable < XID

	Self = [:self,Drawable]

	def_remote_with_reply :get_geometry, 14, [Self,
	], [
		[:depth, Uint8, :in_header],
		[:root, Window],
		[:rectangle, Rectangle],
		[:border_width, Uint16]]

	def_remote_with_reply :get_image, 73, [Self,
		[:format, ImageFormat, :in_header],
		[:rectangle, Rectangle],
		[:plane_mask, Uint32],
	], [
		[:depth, Uint8, :in_header],
		[:visual, Any.of Visual,None], 20,
		[:data, List.of Uint8]]

	def_remote_with_reply :query_best_size, 97, [Self,
		[:qlass, SizeClass, :in_header],
		[:size, Size],
	], [
		[:size, Size]]

end

class Window < Drawable

	Self = [:self, Window]

	#!@#$ constructor.
	def initialize(display,*args)
		case args.length
		when 0; super(display)
		when 1; super(display,args[0])
		else;   super(display); create(*args)
		end
	end

# category: windows

	def_remote :create, 1, [Self,
		[:depth, Uint8,:in_header],
		[:parent, Window],
		[:rectangle, Rectangle],
		[:border_width, Uint16],
		[:qlass, WindowClass],
		[:visual, Any.of Visual,CopyFromParent],
		[:window_attributes, WindowAttributes]]

	alias create_window create # 0.4 compat

	def_remote :change_attributes, 2, [Self,
		[:window_attributes, WindowAttributes]]

	def_remote_with_reply :get_attributes, 3, [Self,
	],[
		[:backing_store,BackingStore,:in_header],
		[:visual,Visual],
		[:qlass,WindowClass],
		[:bit_gravity,BitGravity],
		[:win_gravity,WinGravity],
		[:backing_planes,Uint32],
		[:backing_pixel,Colornum],
		[:save_under,Bool],
		[:map_is_installed,Bool],
		[:map_state,MapState],
		[:override_redirect,Bool],
		[:colormap,Any.of Colormap,CopyFromParent],
		[:all_event_masks,EventMask],
		[:your_event_mask,EventMask],
		[:do_not_propagate_mask,DeviceEventMask]]

	def_remote :close, 4, [Self]
	def_remote :close_subwindows, 5, [Self]

	def_remote :change_save_set, 6, [Self,
		[:change_type, ChangeType,:in_header]]

	def_remote :reparent, 7, [Self,
		[:parent, Window],
		[:point, Point]]

	def_remote   :map,  8, [Self]
	def_remote :unmap, 10, [Self]
	def_remote   :map_subwindows,  9, [Self]
	def_remote :unmap_subwindows, 11, [Self]

	def_remote :configure, 12, [Self,
		[:config, WindowConfig]]

	def_remote :circulate, 13, [Self,
		[:direction, CirculateDirection, :in_header]]

	def_remote_with_reply :query_tree, 15, [Self,
	], [
		[:root, Window],
		[:parent, Any.of Window,None],
		[:windows, Uint16, :length],
		[:windows, List.of(Window), :data]]

# category: properties

	def_remote :change_property, 18, [Self,
		[:mode, ChangePropertyMode, :in_header],
		[:property, Atom],
		[:tipe, Atom],
		[:format, Uint8.such_that {|x| [8,16,32].include? x }], 3,
		[:string, Uint32, :length],
		[:string, String8, :data]] #!@#$ of length (value_length * format)
	
	def_remote :delete_property, 19, [Self,
		[:property, Atom]]

	def_remote_with_reply :get_property, 20, [Self,
		[:delete, Bool, :in_header],
		[:property, Atom],
		[:tipe, Any.of Atom,AnyPropertyType],
		[:offset, Uint32],
		[:length, Uint32],
	], [
		[:format, Uint8.such_that {|x| [8,16,32].include? x }, :in_header],
		[:tipe, Atom],
		[:bytes_after, Uint32],
		[:string, Uint32, :length], 12,
		[:string, String8, :data]] #!@#$ of length (value_length * format)
		
	def_remote_with_reply :list_properties, 21, [Self,
	], [
		[:atoms, Uint16, :length], 22,
		[:atoms, List.of(Atom), :data]]

# category: grabs

	def_remote :grab_pointer, 26, [Self,
		[:owner_events, Bool, :in_header],
		[:event_mask, PointerEventMask],
		[:pointer_mode,  SyncMode],
		[:keyboard_mode, SyncMode],
		[:confine_to, Any.of Window,None],
		[:cursor,     Any.of Cursor,None],
		[:time, TimeOrNow]]
		
	def_remote :grab_button, 28, [Self,
		[:owner_events, Bool, :in_header],
		[:event_mask, PointerEventMask],
		[:pointer_mode,  SyncMode],
		[:keyboard_mode, SyncMode],
		[:confine_to, Any.of Window,None],
		[:cursor, Any.of Cursor,None],
		[:button, Any.of Button,AnyButton], 1,
		[:modifiers, Any.of KeyMask,AnyModifier]]

	def_remote_with_reply :grab_keyboard, 31, [Self,
		[:owner_events, Bool, :in_header],
		[:time, TimeOrNow],
		[:pointer_mode,  SyncMode],
		[:keyboard_mode, SyncMode],
	], [
		[:status, GrabStatus, :in_header]]

	def_remote :grab_key, 33, [Self,
		[:owner_events, Bool, :in_header],
		[:modifiers, Any.of KeyMask,AnyModifier],
		[:key, KeyCode],
		[:pointer_mode,  SyncMode],
		[:keyboard_mode, SyncMode]]

	def_remote :ungrab_key, 34, [Self,
		[:key, KeyCode, :in_header],
		[:modifiers, Any.of KeyMask,AnyModifier]]

# category: other

	def_remote_with_reply :query_pointer, 38, [Self,
	], [
		[:same_screen, Bool, :in_header],
		[:root, Window],
		[:child, Any.of Window,None],
		[:root_point, Point],
		[:win_point,  Point],
		[:mask, KeyButMask]]

	def_remote_with_reply :get_motion_events, 39, [Self,
		[:start, TimeOrNow],
		[:stop,  TimeOrNow],
	], [
		[:events, Uint32, :length], 20,
		[:events, List.of(TimeCoord), :data]]

	def_remote_with_reply :translate_coordinates, 40, [Self,
		[:to_window, Window],
		[:from_point, Point],
	], [
		[:same_screen, Bool, :in_header],
		[:child, Any.of Window,None],
		[:to_point, Point]]

	def_remote :clear_area, 61, [Self,
		[:exposures, Bool, :in_header],
		[:rectangle, Rectangle]]

	def clear; clear_area false, Rectangle[Point[0,0],Size[0,0]]; end

	def_remote_with_reply :list_installed_colormaps, 83, [Self,
	], [
		[:colormaps, Uint16, :length], 2,
		[:colormaps, List.of(Colormap), :data]]

	def_remote :rotate_properties, 114, [Self,
		[:properties, Uint16, :length],
		[:delta, Int16],
		[:properties, List.of(Atom), :data]]

end

class Pixmap < Drawable

	Self = [:self, Pixmap]

	#!@#$ constructor.

	def_remote :create, 53, [Self,
		[:depth, Uint8, :in_header],
		[:drawable, Drawable], #?
		[:size, Size]]
	def_remote :free, 54, [Self]

end

#???
class ColorItem < Tuple; fields_are \
	[:pixel, Uint32],
	[:rgb, RGB],
	[:flags, DoColor], 1
end		

class Colormap < XID

	Self = [:self,Colormap]

	#!@#$ constructor.

	def_remote :create, 78, [Self,
		[:alloc,  ColormapAlloc, :in_header],
		[:window, Window],
		[:visual, Visual]]

	def_remote :free, 79, [Self]
	def_remote :copy_and_free, 80, [Self, [:source, Colormap]]
	def_remote :install,   81, [Self]
	def_remote :uninstall, 82, [Self]

	def_remote_with_reply :alloc_color, 84, [Self,
		[:rgb, RGB], 2,
	], [
		[:rgb, RGB], 2,
		[:pixel, Colornum]]

	def_remote_with_reply :alloc_named_color, 85, [Self,
		[:name, Uint16, :length], 2,
		[:name, String8, :data],
	], [
		[:pixel, Colornum],
		[:exact_rgb,  RGB],
		[:visual_rgb, RGB]]

	def_remote_with_reply :alloc_color_cells, 86, [Self,
		[:contiguous, Bool, :in_header],
		[:colors, Uint16],
		[:planes, Uint16],
	], [
		[:pixels, Uint16, :length],
		[:masks,  Uint16, :length], 20,
		[:pixels, List.of(Colornum), :data],
		[:masks,  List.of(Uint32),   :data]]

	def_remote_with_reply :alloc_color_planes, 87, [Self,
		[:contiguous, Bool, :in_header],
		[:colors, Uint16],
		[:reds,   Uint16],
		[:greens, Uint16],
		[:blues,  Uint16],
	], [
		[:pixels, Uint16, :length], 2,
		[:red_mask,   Uint32],
		[:green_mask, Uint32],
		[:blue_mask,  Uint32], 8,
		[:pixels, List.of(Uint32), :data]]
	
	def_remote :free_colors, 88, [Self,
		[:plane_mask, Uint32],
		[:pixels, List.of Uint32]]

	def_remote :store_colors, 89, [Self,
		[:items, List.of ColorItem]]

	def_remote :store_named_color, 90, [Self,
		[:flags, DoColor, :in_header],
		[:pixel, Colornum],
		[:name, Uint16, :length], 2,
		[:name, String8, :data]]
		
	def_remote_with_reply :query_colors, 91, [Self,
		[:pixels, List.of Colornum],
	], [
		[:colors, Uint16, :length], 22,
		[:colors, List.of(RGB), :data]]

	def_remote_with_reply :lookup_color, 92, [Self,
		[:name, Uint16, :length], 2,
		[:name, String8, :data],
	], [
		[:exact_rgb, RGB],
		[:visual_rgb, RGB]]

end

#----------------------------------------------------------------#
# Fonts and Graphics

class FontProp < Tuple; fields_are \
	[:name, Atom],
	[:value, Uint32]
end

class CharInfo < Tuple; fields_are \
	[:bearing_l, Int16],
	[:bearing_r, Int16],
	[:width,   Int16],
	[:ascent,  Int16],
	[:descent, Int16],
	[:attributes, Uint16]
end

class Font < Fontable

	Self = [:self,Font]

	#!@#$ constructor.

	def_remote :open, 45, [Self,
		[:name, Uint16, :length], 2,
		[:name, String8, :data]]

	def_remote :close, 46, [Self]
end

class Fontable < XID

	Self = [:self,Fontable]

	def_remote_with_reply :query, 47, [Self
	], [

		#!@#$ the next 12 fields could become FontInfo
		#!@#$ except for :properties.
		[:min_bounds, CharInfo], 4,
		[:max_bounds, CharInfo], 4,
		[:min_char_or_byte2, Uint16], #!@#$ :min_char ?
		[:max_char_or_byte2, Uint16],
		[:default_char, Uint16],
		[:properties, Uint16, :length],
		[:draw_direction, DrawDirection],
		[:min_byte1, Uint8], #!@#$ :min_row ?
		[:max_byte1, Uint8],
		[:all_chars_exist, Bool],
		[:font_ascent, Uint16],
		[:font_descent, Uint16],

		[:char_infos, Uint32, :length],
		[:properties, List.of(FontProp), :data],
		[:char_infos, List.of(CharInfo), :data]]

	def query_text_extents(text8,&proc)
		#text16 = text8.sub /(.)/, "\0\1"
		text16 = (0...text8.length).map {|i| text8[i] }
		query_text_extents_16(text16,&proc)
	end

	def_remote_with_reply :query_text_extents_16, 48, [Self,
		[:string, Uint1, :length], # modulo 2 (!!!)
		[:string, String16, :data],
	], [
		[:draw_direction, DrawDirection, :in_header],
		[:font_ascent,  Int16],
		[:font_descent, Int16],
		[:overall_ascent,  Int16],
		[:overall_descent, Int16],
		[:overall_width, Int32],
		[:overall_left,  Int32],
		[:overall_right, Int32]]

end

class Cursor < XID

	Self = [:self,Cursor]

	#!@#$ constructor.

	def_remote :create, 93, [Self,
		[:source, Pixmap],
		[:mask, Any.of Pixmap,None],
		[:foreground, RGB],
		[:background, RGB],
		[:hot_spot, Uint16]]

	def_remote :create_from_glyph, 94, [Self,
		[:source, Font],
		[:mask, Any.of Font,None],
		[:source_char, Uint16],
		[:mask_char,   Uint16],
		[:foreground, RGB],
		[:background, RGB]]
	
	def_remote :free, 95, [Self]

	def_remote :recolor, 96, [Self,
		[:foreground, RGB],
		[:background, RGB]]
end

class GraphicsInfo < PartialTuple; fields_are \
	[:function,   GCFunction],
	[:plane_mask, Uint32],
	[:foreground, Colornum],
	[:background, Colornum],
	[:line_width, Uint16],
	[:line_style, GCLineStyle],
	[:cap_style,  GCCapStyle],
	[:join_style, GCJoinStyle],
	[:fill_style, GCFillStyle],
	[:fill_rule,  GCFillRule],
	[:tile,       Pixmap],
	[:stipple,    Pixmap],
	[:ts_origin_x,Int16],
	[:ts_origin_y,Int16],
	[:font,       Font],
	[:subwindow_mode, GCSubwindowMode],
	[:graphics_exposures, Bool],
	[:clip_origin_x, Int16],
	[:clip_origin_y, Int16],
	[:clip_mask, Pixmap],
	[:dash_offset, Uint16],
	[:dashes, Uint8],
	[:arc_mode, GCArcMode]
end

class Graphics < Fontable

	class << self
		@@remote = {}
		def remote(selector,*args)
			@@remote[selector] = args
		end
	end

	Self = [:self,Graphics]

	#!@#$ constructor.

	def_remote :create, 55, [Self,
		[:drawable, Drawable],
		[:graphics_info, GraphicsInfo]]
		
	def_remote :change, 56, [Self,
		[:graphics_info, GraphicsInfo]]

	def_remote :copy, 57, [
		[:source, Graphics],
		Self,
		[:value_mask, BitMask]]
		
	def_remote :set_dashes, 58, [Self,
		[:dash_offset, Uint16],
		[:dashes, Uint16, :length],
		[:dashes, List.of(Uint8), :data]]

	def_remote :set_clip_rectangles, 59, [Self,
		[:ordering, ClipRectangleOrdering, :in_header],
		[:clip_origin, Point],
		[:rectangles, List.of Rectangle]]

	def_remote :free, 60, [Self]
end

class TextItem8 < Tuple; fields_are \
	[:s,Uint8_but_255, :length],
	[:delta,Int8],
	[:s,String8, :data] #!@#$ shouldn't be padded?
end

class TextItem16 < Tuple; fields_are \
	[:s,Uint8_but_255, :length],
	[:delta,Int8],
	[:s,String16, :data] #!@#$ shouldn't be padded?
end

class TextItemFontShift < Tuple; fields_are \
	[:s,Uint8_only_255],
	[:font_number,Uint32BE] #!@#$ should be "Font as Uint32BE".
end

class GraphicsOnDrawable < Tuple; include RemoteObject; extend RemoteClass
fields_are \
	[:dr,Drawable],
	[:gfx,Graphics]

	Self = [:self, self]
	CM = [:coordinate_mode, CoordinateMode, :in_header]

	#!@#$ constructor.

	def xdisplay; dr.xdisplay; end

	def_remote :draw_points,   64, [Self, CM, [:points,  List.of Point]]
	def_remote :draw_lines,    65, [Self, CM, [:lines,   List.of Point]]
	def_remote :draw_segments, 66, [Self, CM, [:segments,List.of Segment]]
	def_remote :fill_polygon,  69, [Self, CM,
		[:shape, PolyShape], 2,
		[:points, List.of Point]]

	def_remote :draw_rectangles, 67, [Self, [:rectangles, List.of Rectangle]]
	def_remote :fill_rectangles, 70, [Self, [:rectangles, List.of Rectangle]]
	def_remote :draw_arcs,       68, [Self, [:arcs,       List.of Arc]]
	def_remote :fill_arcs,       71, [Self, [:arcs,       List.of Arc]]

	def_remote :put_image, 72, [Self,
		[:format, ImageFormat, :in_header],
		[:size, Size],
		[:point, Point],
		[:left_pad, Uint8],
		[:depth, Uint8], 2,
		[:data, List.of Uint8]]

	[
		[:draw_strings,   74,TextItem8],
		[:draw_strings_16,75,TextItem16],
	].each {|sym,req_id,texttype|
		# texttype = Any.of(texttype,TextItemFontShift)
		def_remote sym, req_id, [Self,
			[:point, Point],
			[:items, List.of(texttype)]]
	}

	def_remote :draw_image_string, 76, [Self,
		[:string, Uint8, :length_in_header],
		[:point, Point],
		[:string, String8, :data]]

	def_remote :draw_image_string_16, 77, [Self,
		[:string, Uint8, :length_in_header],
		[:point, Point],
		[:string, String16, :data]]

	def_remote :copy_area, 62, [
		[:from_drawable, Drawable],
		Self,
		[:from_point, Point],
		[:to_point, Point],
		[:size, Size]]

	def_remote :copy_plane, 63, [
		[:from_drawable, Drawable],
		Self,
		[:from_point, Point],
		[:to_point, Point],
		[:size, Size],
		[:bit_plane, Uint32]]

end

#----------------------------------------------------------------#
end # of module X11
