SelectionF

module SelectionF where 
import FudUTF8(decodeUTF8,encodeUTF8)
import Command
import CompOps((>=^<), (>^=<))
import Cont(conts,cmdContK')
import Shells(unmappedShellF)
import Event
import Fudget
import FRequest
import Xcommand
import GetWindowProperty
import InternAtom
--import Message(Message(..))
import NullF
import LayoutF(nullLF)
import Spops(putSP,getSP)
import Loops(loopThroughRightF)
import EitherUtils(stripEither)
import SerCompF(absF)
import Xtypes

{- 
Supports cut/paste of UTF-8 encoded Unicode Strings.
Cut/paste of Unicode strings between two fudgets program works.
Cut/paste between a fudget program and xterm -u8 from XFree86 4.0 works.
/TH 2000-04-02
-}

data SelCmd a = Sel a | ClearSel | PasteSel  deriving (Eq, Ord)
data SelEvt a = LostSel | SelNotify a  deriving (Eq, Ord)

data ESelCmd a = OwnSel | SelCmd (SelCmd a) deriving (Eq, Ord)
data ESelEvt a =  WantSel | SelEvt (SelEvt a) deriving (Eq, Ord)

eselectionF :: F (ESelCmd String) (ESelEvt String)
eselectionF =
    (stripEither >^=< unmappedShellF [] selK nullLF) >=^<
    Left where
 selK =
    conts (flip internAtomK True) 
      ["PRIMARY", "STRING", "NONE", "ATOM"] $ 
      \ [primaryA, stringA, noneA, atomA] ->
    conts (flip internAtomK False) ["FUDGETS_UTF8","UTF8_STRING"] $
      \ [fudgetsA, utf8A] -> let
      sevt = High. SelEvt
      l =
	  getK $ \ev ->
	  case ev of
	    High esc -> case esc of
	      SelCmd sc -> case sc of
		 Sel t -> l -- select t
		 ClearSel -> deselect
		 PasteSel -> paste_utf8string -- try UTF-8 first...
	      OwnSel -> select
	    Low (XEvt ev) -> case ev of
	      SelectionClear s | s == primaryA -> putK (sevt LostSel) l
	      SelectionRequest t w s -> selectionrequest t w s
	      SelectionNotify t s -> selectionnotify s
	      _ -> l
	    Low _ -> l
      selectionrequest time w sel@(Selection s t p) =
	if t `notElem` [stringA,utf8A]
	then notify time w (Selection s noneA p) l
	else
	  let p' = if p == noneA then t else p
	      wait (High (SelCmd (Sel t))) = Just t
	      wait _ = Nothing
	  in cmdContK' (High WantSel) wait $ \rawtext ->
	     let text = if t==utf8A
	                then encodeUTF8 rawtext
			else rawtext in
	     xcommandK (ChangeProperty w p' t 8 propModeReplace text) $
	     notify time w (Selection s t p') l
      notify t w sel = xcommandK (SendEvent w False [] (SelectionNotify t sel))
      paste_string = paste' stringA
      paste_utf8string = paste' utf8A
      paste' typ =
	  xcommandK (ConvertSelection (Selection primaryA typ fudgetsA)) l
      paste_failed = putK (sevt (SelNotify "")) l
      selectionnotify sel@(Selection s t p) =
          if p==noneA
	  then if t==utf8A  -- UTF8_STRING wasn't supported, try STRING
	       then paste_string
	       else paste_failed
	  else if t `notElem` [stringA,utf8A]
	       then paste_failed
	       else getWindowPropertyK 0 p True t $ 
			  \(typ, format, nitems, after,seltext) ->
		    let s' = if t==utf8A then decodeUTF8 seltext else seltext in
		    putK (sevt (SelNotify s')) l
      select = select' True
      deselect = select' False
      -- should check that setselectionowner succeeded.
      select' b = xcommandK (SetSelectionOwner b primaryA) l
    in l

selectionF :: F (SelCmd String) (SelEvt String)
selectionF = loopThroughRightF (absF (selSP "")) (eselectionF) where
  selSP text = 
    let same = selSP text 
	toesel = Left
	toout = Right in
    getSP $ \msg -> case msg of
	Right ocmd -> case ocmd of
	   Sel t -> putSP (toesel OwnSel) $ selSP t
	   _ -> putSP (toesel (SelCmd ocmd)) same
	Left esevt -> case esevt of
	   WantSel -> putSP (toesel (SelCmd (Sel text))) same
	   SelEvt se -> putSP (toout se) same