diff --git a/Clipboard.cabal b/Clipboard.cabal
--- a/Clipboard.cabal
+++ b/Clipboard.cabal
@@ -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
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -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! :)
diff --git a/System/Clipboard.hs b/System/Clipboard.hs
--- a/System/Clipboard.hs
+++ b/System/Clipboard.hs
@@ -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
diff --git a/System/Clipboard/Windows.hs b/System/Clipboard/Windows.hs
new file mode 100644
--- /dev/null
+++ b/System/Clipboard/Windows.hs
@@ -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
diff --git a/System/Clipboard/X11.hs b/System/Clipboard/X11.hs
new file mode 100644
--- /dev/null
+++ b/System/Clipboard/X11.hs
@@ -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
diff --git a/license b/license
--- a/license
+++ b/license
@@ -1,4 +1,4 @@
-Copyright (c)2011, Daniel Díaz
+Copyright (c)2015, Daniel Díaz
 
 All rights reserved.
 
