Clipboard 2.2.0.3 → 2.3.0.0
raw patch · 6 files changed
+244/−128 lines, 6 filesdep +X11dep +directorydep +unixPVP ok
version bump matches the API change (PVP)
Dependencies added: X11, directory, unix, utf8-string
API changes (from Hackage documentation)
+ System.Clipboard: getClipboardString :: IO (Maybe String)
+ System.Clipboard: modifyClipboardString :: (String -> String) -> IO Bool
+ System.Clipboard: setClipboardString :: String -> IO ()
Files
- Clipboard.cabal +38/−29
- README.md +1/−1
- System/Clipboard.hs +36/−97
- System/Clipboard/Windows.hs +62/−0
- System/Clipboard/X11.hs +106/−0
- license +1/−1
Clipboard.cabal view
@@ -1,33 +1,36 @@-Name: Clipboard -Version: 2.2.0.3 -Author: Sævar Berg, Daniel Díaz -Homepage: http://haskell.org/haskellwiki/Clipboard -License: BSD3 -License-file: license -Maintainer: Daniel Díaz [dhelta `dot` diaz `at` gmail `dot` com] -Category: System -Stability: Stable -Synopsis: System clipboard interface. -Bug-reports: https://github.com/Daniel-Diaz/Clipboard/issues +Name: Clipboard +Version: 2.3.0.0 +Author: Sævar Berg (Windows), Matthew Bekkema (X11), Daniel Díaz (Maintainer) +Homepage: http://haskell.org/haskellwiki/Clipboard +License: BSD3 +License-file: license +Maintainer: dhelta.diaz `at` gmail.com +Category: System +Stability: Stable +Synopsis: System clipboard interface. +Bug-reports: https://github.com/Daniel-Diaz/Clipboard/issues Description: - /Clipboard/ is a library for easily interfacing with the system clipboard with additional unicode support. - Currently, only in a Windows system. - . - For example, if you type: - . - > $ setClipboardString "Hello, World!" - . - Then you have @\"Hello, World!\"@ available to be pasted wherever you want. - . - Now, if you type: - . - > $ modifyClipboardString reverse - . - You will have @\"!dlroW ,olleH\"@ in your clipboard. So: - . - > $ getClipboardString - > "!dlroW ,olleH" -Build-type: Simple + /Clipboard/ is a library for easily interfacing with the system clipboard with additional unicode support. + Currently, only in a Windows or GNU/Linux (X11) system. + . + For example, if you type: + . + > $ setClipboardString "Hello, World!" + . + Then you have @\"Hello, World!\"@ available to be pasted wherever you want. + . + Now, if you type: + . + > $ modifyClipboardString reverse + . + You will have @\"!dlroW ,olleH\"@ in your clipboard. So: + . + > $ getClipboardString + > "!dlroW ,olleH" + . + The X11 version depends on the @X11@ package, so you will need the X11 development library + available on your system at compile time. You can install it by @sudo apt-get install libxrandr-dev@. +Build-type: Simple Cabal-version: >= 1.6 Extra-source-files: README.md @@ -41,5 +44,11 @@ if os(windows) Build-depends: base == 4.* , Win32 >= 2.2.0.0 && < 2.4 + Other-modules: System.Clipboard.Windows else Build-depends: base == 4.* + , X11 == 1.6.* + , utf8-string + , unix + , directory + Other-modules: System.Clipboard.X11
README.md view
@@ -4,4 +4,4 @@ ## Limitations -I'm so sorry, but this library **only works on Windows**. Contributions are welcome! :)+I'm so sorry, but this library **only works on Windows and GNU/Linux (X11)**. Contributions are welcome! :)
System/Clipboard.hs view
@@ -1,97 +1,36 @@- -{-# LANGUAGE CPP #-} - --- | System clipboard interface with unicode support. --- --- For more information, see "Graphics.Win32.GDI.Clip" --- or documentation for /GetClipboardData/ on MSDN. -module System.Clipboard - ( -#if defined(mingw32_HOST_OS) || defined(__MINGW32__) - -- * Clipboard interface - setClipboardString - , getClipboardString - , modifyClipboardString - -- * Clipboard format - , cF_UNICODETEXT -#else - -- * Undefined - - -- | This library currently only works in Windows. - -- If you want to contribute, please, don't hesitate - -- in visit the Git repository at <https://github.com/Daniel-Diaz/Clipboard>. -#endif - ) where - -#if defined(mingw32_HOST_OS) || defined(__MINGW32__) - -import System.Win32.Mem - (globalAlloc, globalLock, globalUnlock, copyMemory, gHND) -import Graphics.Win32.GDI.Clip - ( openClipboard, closeClipboard, emptyClipboard, - getClipboardData, setClipboardData - , cF_TEXT, ClipboardFormat - , isClipboardFormatAvailable) -import Foreign.C - (withCAString, peekCAString, withCWString, peekCWString) -import Foreign.Ptr - (castPtr, nullPtr) -import Data.List - (genericLength) -import Control.Exception - (bracket_, bracket) -import Data.Maybe - (isJust) - --- | Clipboard format of Unicode text. -cF_UNICODETEXT :: ClipboardFormat -cF_UNICODETEXT = 13 - --- | Puts a string on the clipboard, using the 'cF_UNICODETEXT' clipboard format. -setClipboardString :: String -> IO () -setClipboardString str = - withCWString str $ \cstring -> do - mem <- globalAlloc gHND strLen - bracket (globalLock mem) globalUnlock $ \mem' -> do - copyMemory mem' (castPtr cstring) strLen - bracket_ (openClipboard nullPtr) closeClipboard $ do - emptyClipboard - setClipboardData cF_UNICODETEXT mem' - return () - where - strLen = 2 * (genericLength str + 1) - --- | Gets the contents of the clipboard as a 'String'. --- Returns 'Nothing' if the clipboard content is not --- of type 'cF_TEXT' or 'cF_UNICODETEXT', i.e. it --- doesn't contain /textual/ data. -getClipboardString :: IO (Maybe String) -getClipboardString = - bracket_ (openClipboard nullPtr) closeClipboard $ do - isUnicodeAvailable <- isClipboardFormatAvailable cF_UNICODETEXT - if isUnicodeAvailable - then do handle <- getClipboardData cF_UNICODETEXT - mem <- globalLock handle - str <- peekCWString (castPtr mem) - globalUnlock mem - return $ Just str - else do isAnsiAvailable <- isClipboardFormatAvailable cF_TEXT - if isAnsiAvailable - then do handle <- getClipboardData cF_TEXT - mem <- globalLock handle - str <- peekCAString (castPtr mem) - globalUnlock mem - return $ Just str - else return Nothing - --- | Modifies the clipboard content. --- If the clipboard has /textual/ data, this function modifies its content, --- and return 'True'. Otherwise, it does nothing and return 'False'. -modifyClipboardString :: (String -> String) -> IO Bool -modifyClipboardString f = do - s <- getClipboardString - case s of - Nothing -> return False - Just sc -> setClipboardString (f sc) >> return True - -#endif ++{-# LANGUAGE CPP #-}++-- | System Clipboard Interface. It should work on both Windows and Unix (X11).+-- The latter is still experimental.+module System.Clipboard+ ( -- * Clipboard interface+ setClipboardString+ , getClipboardString+ , modifyClipboardString+ ) where++#if defined(mingw32_HOST_OS) || defined(__MINGW32__)+import qualified System.Clipboard.Windows as OS+#else+import qualified System.Clipboard.X11 as OS+#endif++-- | Writes a string to the clipboard.+setClipboardString :: String -> IO ()+setClipboardString = OS.setClipboardString++-- | Gets the contents of the clipboard as a 'String'.+-- Returns 'Nothing' if the clipboard doesn't contain /textual/ data.+getClipboardString :: IO (Maybe String)+getClipboardString = OS.getClipboardString++-- | Modifies the clipboard content.+-- If the clipboard has /textual/ data, this function modifies its content+-- and return 'True'. Otherwise, it does nothing and return 'False'.+modifyClipboardString :: (String -> String) -> IO Bool+modifyClipboardString f = do+ s <- getClipboardString+ case s of+ Nothing -> return False+ Just sc -> setClipboardString (f sc) >> return True
+ System/Clipboard/Windows.hs view
@@ -0,0 +1,62 @@+-- | System clipboard interface with unicode support. +-- +-- For more information, see "Graphics.Win32.GDI.Clip" +-- or documentation for /GetClipboardData/ on MSDN. +module System.Clipboard.Windows + ( + setClipboardString + , getClipboardString + ) where + +import System.Win32.Mem + (globalAlloc, globalLock, globalUnlock, copyMemory, gHND) +import Graphics.Win32.GDI.Clip + ( openClipboard, closeClipboard, emptyClipboard, + getClipboardData, setClipboardData + , cF_TEXT, ClipboardFormat + , isClipboardFormatAvailable) +import Foreign.C + (withCAString, peekCAString, withCWString, peekCWString) +import Foreign.Ptr + (castPtr, nullPtr) +import Data.List + (genericLength) +import Control.Exception + (bracket_, bracket) +import Data.Maybe + (isJust) + +cF_UNICODETEXT :: ClipboardFormat +cF_UNICODETEXT = 13 + +setClipboardString :: String -> IO () +setClipboardString str = + withCWString str $ \cstring -> do + mem <- globalAlloc gHND strLen + bracket (globalLock mem) globalUnlock $ \mem' -> do + copyMemory mem' (castPtr cstring) strLen + bracket_ (openClipboard nullPtr) closeClipboard $ do + emptyClipboard + setClipboardData cF_UNICODETEXT mem' + return () + where + strLen = 2 * (genericLength str + 1) + +getClipboardString :: IO (Maybe String) +getClipboardString = + bracket_ (openClipboard nullPtr) closeClipboard $ do + isUnicodeAvailable <- isClipboardFormatAvailable cF_UNICODETEXT + if isUnicodeAvailable + then do handle <- getClipboardData cF_UNICODETEXT + mem <- globalLock handle + str <- peekCWString (castPtr mem) + globalUnlock mem + return $ Just str + else do isAnsiAvailable <- isClipboardFormatAvailable cF_TEXT + if isAnsiAvailable + then do handle <- getClipboardData cF_TEXT + mem <- globalLock handle + str <- peekCAString (castPtr mem) + globalUnlock mem + return $ Just str + else return Nothing
+ System/Clipboard/X11.hs view
@@ -0,0 +1,106 @@+module System.Clipboard.X11+( getClipboardString+, setClipboardString+) where++import Graphics.X11.Xlib+import Graphics.X11.Xlib.Extras+import System.Posix.Process (forkProcess)++import Data.Maybe+import Data.Functor+import Control.Monad+import System.IO (hClose, stdin, stdout, stderr)+import System.Directory (setCurrentDirectory)+import Foreign.C.Types (CChar, CUChar)+import Foreign.Marshal.Array (withArrayLen)+import Codec.Binary.UTF8.String (decode, encode)++getClipboardString :: IO (Maybe String)+getClipboardString = do+ (display, window, clipboard) <- initialSetup+ inp <- internAtom display "clipboard_get" False+ target <- internAtom display "UTF8_STRING" True+ xConvertSelection display clipboard target inp window currentTime+ ret <- clipboardInputWait display window inp+ cleanup display window+ return ret++clipboardInputWait :: Display -> Window -> Atom -> IO (Maybe String)+clipboardInputWait display window inp = do+ ev <- getNextEvent display+ if ev_event_type ev == selectionNotify+ then (charsToString <$>) <$> getWindowProperty8 display inp window+ else clipboardInputWait display window inp++charsToString :: [CChar] -> String+charsToString = decode . map fromIntegral+++setClipboardString :: String -> IO ()+setClipboardString str = do+ (display, window, clipboard) <- initialSetup+ xSetSelectionOwner display clipboard window currentTime+ void $ forkProcess $ do+ hClose stdin+ hClose stdout+ hClose stderr+ setCurrentDirectory "/"+ clipboardOutputWait display $ stringToChars str+ cleanup display window++clipboardOutputWait :: Display -> [CUChar] -> IO ()+clipboardOutputWait display str = do+ let loop = clipboardOutputWait display str+ ev <- getNextEvent display+ case ev of+ SelectionRequest { ev_requestor = req+ , ev_target = target+ , ev_property = prop+ , ev_selection = sel+ , ev_time = time} -> do+ target' <- getAtomName display target+ res <- handleOutput display req prop target' str+ sendSelectionNotify display req sel target res time+ loop+ _ -> unless (ev_event_type ev == selectionClear) loop++handleOutput :: Display -> Window -> Atom -> Maybe String -> [CUChar] -> IO Atom+handleOutput display req prop (Just "UTF8_STRING") str = do+ prop' <- getAtomName display prop+ if isNothing prop' then handleOutput display req prop Nothing str else do+ target <- internAtom display "UTF8_STRING" True+ void $ withArrayLen str $ \len str' ->+ xChangeProperty display req prop target 8 propModeReplace str'+ (fromIntegral len)+ return prop+handleOutput _ _ _ _ _ = return none++sendSelectionNotify :: Display -> Window -> Atom -> Atom -> Atom -> Time ->+ IO ()+sendSelectionNotify display req sel target prop time = allocaXEvent $ \ev -> do+ setEventType ev selectionNotify+ setSelectionNotify ev req sel target prop time+ sendEvent display req False 0 ev++stringToChars :: String -> [CUChar]+stringToChars = map fromIntegral . encode+++initialSetup :: IO (Display, Window, Atom)+initialSetup = do+ display <- openDisplay ""+ window <- createSimpleWindow display (defaultRootWindow display)+ 0 0 1 1 0 0 0+ clipboard <- internAtom display "CLIPBOARD" True+ return (display, window, clipboard)++cleanup :: Display -> Window -> IO ()+cleanup display window = do+ destroyWindow display window+ closeDisplay display++getNextEvent :: Display -> IO Event+getNextEvent display = allocaXEvent $ \ev -> do+ nextEvent display ev+ getEvent ev
license view
@@ -1,4 +1,4 @@-Copyright (c)2011, Daniel Díaz +Copyright (c)2015, Daniel Díaz All rights reserved.