screenshot-to-clipboard (empty) → 0.1.0.0
raw patch · 5 files changed
+185/−0 lines, 5 filesdep +basedep +bytestringdep +filepath
Dependencies added: base, bytestring, filepath, gi-gdk, gi-gdkpixbuf, gi-gio, gi-glib, gi-gtk, haskell-gi-base, process, screenshot-to-clipboard, temporary, text
Files
- CHANGELOG.md +5/−0
- README.md +47/−0
- app/Main.hs +6/−0
- screenshot-to-clipboard.cabal +50/−0
- src/ScreenshotToClipboard.hs +77/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for screenshot-to-clipboard++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ README.md view
@@ -0,0 +1,47 @@++# `screenshot-to-clipboard`++[](https://github.com/cdepillabout/screenshot-to-clipboard/actions/workflows/ci.yml)+[](https://hackage.haskell.org/package/screenshot-to-clipboard)+[](http://stackage.org/lts/package/screenshot-to-clipboard)+[](http://stackage.org/nightly/package/screenshot-to-clipboard)+[](./LICENSE)++This program provides a simple way to take a screenshot and copy it to your+system clipboard.++When you run `screenshot-to-clipboard`, it internally runs the+[`import`](https://imagemagick.org/script/import.php) program from+[ImageMagick](https://imagemagick.org) to take a screenshot, and then uses+[GTK](https://www.gtk.org/) to copy that screenshot to your system clipboard.++## Installation++The recommended installation procedure is to use Nix. With Nix installed, just do:++```console+$ git clone git@github.com:cdepillabout/screenshot-to-clipboard+$ cd screenshot-to-clipboard/+$ nix-build+```++You can run this program with the output `result/bin/screenshot-to-clipboard` program.++`screenshot-to-clipboard` is also available in Nixpkgs, starting with+NixOS-22.11 as `haskellPackages.screenshot-to-clipboard`.++It is also possible to build with `cabal` (or `stack`), but you are responsible for+installing necessary system libraries. You'll likely need both `imagemagick`,+and the development packages for GTK.++## Usage++If you run `screenshot-to-clipboard`, it will turn your cursor into a+cross-hair. Click and drag to select a portion of the screen to take a+screenshot. This screenshot will be copied to your system clipboard. You can+paste it into another application.++`screenshot-to-clipboard` will continue running until you've copied _something+else_ into your system clipboard. See the long comment in+[`src/ScreenshotToClipboard.hs`](./src/ScreenshotToClipboard.hs) for why this+is necessary.
+ app/Main.hs view
@@ -0,0 +1,6 @@+module Main where++import ScreenshotToClipboard (defaultMain)++main :: IO ()+main = defaultMain
+ screenshot-to-clipboard.cabal view
@@ -0,0 +1,50 @@+cabal-version: 2.4+name: screenshot-to-clipboard+version: 0.1.0.0+synopsis: Take screenshot and copy it to the system clipboard.+description:+ This is a small program that shells out to imagemagick to take a screenshot,+ and then uses GTK to copy it to the system clipboard.+homepage: https://github.com/cdepillabout/screenshot-to-clipboard+bug-reports: https://github.com/cdepillabout/screenshot-to-clipboard/issues+license: BSD-3-Clause+author: Dennis Gosnell+maintainer: cdep.illabout@gmail.com+copyright: 2022 Dennis Gosnell+category: Utils+extra-source-files:+ CHANGELOG.md+ README.md++library+ hs-source-dirs: src+ exposed-modules: ScreenshotToClipboard+ other-modules: Paths_screenshot_to_clipboard+ autogen-modules: Paths_screenshot_to_clipboard+ build-depends: base >= 4.15 && < 5+ , bytestring+ , filepath+ , gi-gdk+ , gi-gdkpixbuf+ , gi-gio+ , gi-glib+ , gi-gtk+ , haskell-gi-base+ , process+ , temporary+ , text+ default-language: Haskell2010+ ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates+ -- default-extensions: DataKinds+ -- , DefaultSignatures+ -- other-extensions: TemplateHaskell+ -- , UndecidableInstances+ -- pkgconfig-depends: gtk+-3.0+ -- , vte-2.91 >= 0.46++executable screenshot-to-clipboard+ main-is: Main.hs+ build-depends: base+ , screenshot-to-clipboard+ hs-source-dirs: app+ default-language: Haskell2010
+ src/ScreenshotToClipboard.hs view
@@ -0,0 +1,77 @@++module ScreenshotToClipboard where++import Control.Monad (when)+import Data.Functor (void)+import Data.IORef (IORef, newIORef, atomicModifyIORef')+import GI.Gdk (displayGetDefault)+import GI.GdkPixbuf (pixbufNewFromFile)+import GI.Gtk (clipboardGetDefault, clipboardStore, clipboardSetCanStore, clipboardSetImage, onClipboardOwnerChange)+import qualified GI.Gtk as Gtk+import System.Exit (ExitCode(ExitSuccess))+import System.FilePath ((</>))+import System.IO.Temp (withSystemTempDirectory)+import System.Process (readProcessWithExitCode)++defaultMain :: IO ()+defaultMain =+ withSystemTempDirectory "screenshot-to-clipboard" $ \tempdir -> do+ void $ Gtk.init Nothing+ let imgPath = tempdir </> "image.png"++ -- Take screenshot with `import` program from imagemagick.+ (importExitCode, _, _) <- readProcessWithExitCode "import" [imgPath] ""+ when (importExitCode /= ExitSuccess) $+ err "error when calling `import` to take a screenshot"++ -- Load screenshot into GDK Pixbuf.+ imgPixbuf <-+ maybe (err "could not load screenshot image file with gdk pixbuf") pure =<< pixbufNewFromFile imgPath++ -- Get the current display, since it is needed to get the clipboard.+ display <-+ maybe (err "could not get default display from GDK") pure =<< displayGetDefault++ -- Get the clipboard and set hint that it should be able to store.+ clipboard <- clipboardGetDefault display+ clipboardSetCanStore clipboard Nothing++ -- Add callback for when the clipboard contents change.+ numberOfCallsIORef <- newIORef 0+ void $+ onClipboardOwnerChange clipboard $+ const (clipboardOwnerChangeCallback numberOfCallsIORef)++ -- Load the screenshot into the clipboard and store it.+ clipboardSetImage clipboard imgPixbuf+ clipboardStore clipboard++ -- Start GTK main loop.+ Gtk.main+ where+ err :: String -> a+ err e = error $ "screenshot-to-clipboard: " <> e++ -- This callback is called everytime the clipboard changes. It counts the+ -- number of times it has been called, and it will end the program after+ -- having been called two times.+ --+ -- The first time this function is called will be when this program copies+ -- the screenshot to the clipboard. This program then hangs around,+ -- waiting for something else to be copied to the clipboard. It tells the+ -- GTK mainloop to exit only after having been called a second time.+ --+ -- The reason for this is because with XMonad (and other non-Gnome window+ -- managers?), it appears that there is nothing that will persist the+ -- screenshot after copying it to the clipboard if this program exits. So+ -- this program needs to continue running at leaset until ANOTHER program+ -- actually pastes the screenshot that has been copied to the clipboard.+ --+ -- However, this program gets no notification when another program has+ -- pasted the screenshot. In order to work around this lack of+ -- information, this program will just keep running until it sees that+ -- something else has been copied to the clipboard.+ clipboardOwnerChangeCallback :: IORef Int -> IO ()+ clipboardOwnerChangeCallback numberOfCallsIORef = do+ newNum <- atomicModifyIORef' numberOfCallsIORef (\num -> (num + 1, num + 1))+ when (newNum >= 2) $ Gtk.mainQuit