############################################################################
#
#	File:     enqueue.icn
#
#	Subject:  Procedures for queued events
#
#	Author:   Gregg M. Townsend
#
#	Date:     May 2, 2001
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#	These procedures manipulate Icon window events.
#
#	Enqueue(W, eventcode, x, y, modkeys, interval) posts an event.
#
#	pack_modkeys(s)		encodes the modifier keys for an event.
#	unpack_modkeys(n)	decodes a modifier key value.
#
#	pack_intrvl(n)		encodes an event interval.
#	unpack_intrvl(n)	decodes an event interval.
#
############################################################################
#
#      Icon's event queue is a list accessed via Pending(); the list
#   can be inspected or altered by the Icon program.  An event is stored
#   as three consecutive entries on the list.  The first is the event code:
#   a string for a keypress, or an integer for any other event.  The next
#   two list entries are integers, interpreted as a packed structure:
#	0000 0000 0000 0SMC  XXXX XXXX XXXX XXXX   (second entry)
#	0EEE MMMM MMMM MMMM  YYYY YYYY YYYY YYYY   (third entry)
#
#   The fields have these meanings:
#	X...X	&x: 16-bit signed x-coordinate value
#	Y...Y	&y: 16-bit signed y-coordinate value
#	SMC	&shift, &meta, and &control (modifier keys)
#	E...M	&interval, interpreted as  M * 16 ^ E
#	0	currently unused; should be zero
#
#
#      pack_modkeys(s) encodes a set of modifier keys, returning an
#   integer with the corresponding bits set.  The string s contains
#   any combination of the letters c, m, and s to specify the bits
#   desired.
#
#      pack_intrvl(n) encodes an interval of n milliseconds and returns
#   a left-shifted integer suitable for combining with a y-coordinate.
#
#      unpack_modkeys(n) returns a string containing 0 to 3 of the
#   letters c, m, and s, depending on which modifier key bits are
#   set in the argument n.
#
#      unpack_intrvl(n) discards the rightmost 16 bits of the integer
#   n (the y-coordinate) and decodes the remainder to return an
#   integer millisecond count.
#
#      Enqueue([window,] eventcode, x, y, modkeys, interval) synthesizes
#   and enqueues an event for a window, packing the interval and modifier
#   keys (specified as above) into the correct places.  Default values
#   are:
#	eventcode = &null
#	x = 0
#	y = 0
#	interval = 0
#	modkeys = ""
#
############################################################################
#
#  Requires:  Version 9 graphics
#
############################################################################


#  pack_intrvl(n) -- encode event interval

procedure pack_intrvl(n)			#: encode event interval
   local e

   n := integer(n) | runerr(101, n)	# ensure integer
   n <:= 0				# ensure nonnegative
   e := 0				# assume exponent of 0

   while n >= 16r1000 do {		# if too big
      n := ishift(n, -4)		# reduce significance
      e +:= 16r1000			# increase exponent
   }
   return ishift(e + n, 16)		# return shifted result
end


#  unpack_intrvl(n) -- decode event interval

procedure unpack_intrvl(n)			#: decode event interval
   local e

   n := integer(n) | runerr(101, n)	# ensure integer
   e := iand(ishift(n, -28), 7)		# exponent
   n := iand(ishift(n, -16), 16rFFF)	# mantissa
   return ishift(n, 4 * e)
end


#  pack_modkeys(s) -- encode modifier keys

procedure pack_modkeys(s)			#: encode modifier keys
   local b, c

   b := 0
   s := string(s) | runerr(103, s)		# ensure string value
   every c := !s do case c of {			# set bit for each flag
      "c":	b := ior(b, 16r10000)
      "m":	b := ior(b, 16r20000)
      "s":	b := ior(b, 16r40000)
      default:	runerr(205, s)			# diagnose bad flag
      }
   return b					# return result
end


#  unpack_modkeys(n) -- decode modifier keys

procedure unpack_modkeys(n)			#: decode modifier keys
   local s

   n := integer(n) | runerr(101, n)		# ensure integer
   s := ""
   if iand(n, 16r10000) ~= 0 then s ||:= "c"	# check each bit
   if iand(n, 16r20000) ~= 0 then s ||:= "m"
   if iand(n, 16r40000) ~= 0 then s ||:= "s"
   return s					# return result string
end


#  Enqueue(window, eventcode, x, y, modkeys, interval) -- enqueue event

procedure Enqueue(win, eventcode, x, y, modkeys, interval)	#: enqueue event
   static type

   initial type := proc("type", 0)	# protect attractive name

   if type(win) ~== "window" then {
      win :=: eventcode :=: x :=: y :=: modkeys :=: interval
      win := &window
      }
   /x := 0
   /y := 0
   x +:= WAttrib(win, "dx")
   y +:= WAttrib(win, "dy")
   return put(Pending(win),
      eventcode,
      ior(pack_modkeys(\modkeys | ""), iand(x, 16rFFFF)),
      ior(pack_intrvl(\interval | 0), iand(y, 16rFFFF)))
end
