packages feed

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 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`++[![CI](https://github.com/cdepillabout/screenshot-to-clipboard/actions/workflows/ci.yml/badge.svg)](https://github.com/cdepillabout/screenshot-to-clipboard/actions/workflows/ci.yml)+[![Hackage](https://img.shields.io/hackage/v/screenshot-to-clipboard.svg)](https://hackage.haskell.org/package/screenshot-to-clipboard)+[![Stackage LTS](http://stackage.org/package/screenshot-to-clipboard/badge/lts)](http://stackage.org/lts/package/screenshot-to-clipboard)+[![Stackage Nightly](http://stackage.org/package/screenshot-to-clipboard/badge/nightly)](http://stackage.org/nightly/package/screenshot-to-clipboard)+[![BSD3 license](https://img.shields.io/badge/license-BSD3-blue.svg)](./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