• 作成:

スクリーンショット環境をimport(ImageMagick)からgnome-screenshotに移行できなかったので, PyGObjectで「最近開いたファイル」を追加するスクリプトを書きました

最近スクリーンショットを撮ることが増えたので, gnome-screenshotに移行しようとしました.

importの不便な点は, スクリーンショットが「最近開いたファイル」に表示されないため, 選択するのが面倒ということです.

当初はimportで取得したファイルをどうにかして「最近開いたファイル」に登録することを考えていましたが, gnome-screenshotを使えば自動登録されるのでそれで良いことに気がつきました.

以前のスクリーンショット取得関数は以下です. これをxmonadで呼び出していました.

takeScreenShot :: X ()
takeScreenShot = do
    home <- liftIO getHomeDirectory
    time <- liftIO $ formatTime defaultTimeLocale "%Y-%m-%d-%H-%M-%S" <$> getZonedTime
    let path = concat [home, "/Pictures/", "screenshot-", time, ".png"]
    spawn $ concat ["import", " " , path, " && eog ", path]

gnome-screenshotはデフォルトで起動するとScreenshot from 2018-01-06 13-58-50.pngなどというスペース混じりの醜悪なファイルを作成するので, これは是正しないといけない. 面倒かなと思ったのですが, --file=でファイル名を取得するだけなので簡単でした.

importは起動したあとにマウスをクリックするか, マウスをドラッグするかでウィンドウのスクリーンショットを撮るか, 領域のスクリーンショットを撮るか選択するようになっているので関数は1つだけで良かった. しかしgnome-screenshotは起動する時にどちらを撮るかオプションで選択しないといけない.

なので事前に--windowオプションを付ける. と思ったのですが--windowオプションを付けてもウィンドウ単体ではなく画面全体のスクリーンショットを撮ってしまう. なんで? Gnomeじゃないと正常に動作しないんですかね.

M-<Print>キーでエリア指定でスクリーンショット撮るように設定したのですがこのキーが反応しない.

他のスクリーンショットプログラム使うかなと思ったのですが, 思い返すとimportでもウィンドウを撮ることはほとんどなくて, いつもエリア指定でスクリーンショットを撮っていたことに気がつきました. ならエリア指定だけで良いやと割り切りました.

新しい関数を作ってそれで割り切る.

takeScreenshotArea :: X ()
takeScreenshotArea = do
    home <- liftIO getHomeDirectory
    time <- liftIO $ formatTime defaultTimeLocale "%Y-%m-%d-%H-%M-%S" <$> getZonedTime
    spawn $ "gnome-screenshot --area --file=" <> concat [home, "/Pictures/", "screenshot-", time, ".png"]

と思ったのですが, 以下のようなエラーが起きてスクリーンショットコマンドが作動しないことがあります.

** (gnome-screenshot:32143): WARNING **: Couldn't connect to accessibility bus: Failed to connect to socket /tmp/dbus-YKiDqeiYUm: 接続を拒否されました
** Message: Unable to select area using GNOME Shell's builtin screenshot interface, resorting to fallback X11.
** Message: Unable to use GNOME Shell's builtin screenshot interface, resorting to fallback X11.

(gnome-screenshot:32143): Gdk-CRITICAL **: gdk_pixbuf_get_from_surface: assertion 'width > 0 && height > 0' failed

(gnome-screenshot:32143): Gtk-CRITICAL **: gtk_window_resize: assertion 'width > 0' failed

** (gnome-screenshot:32143): CRITICAL **: Unable to capture a screenshot of any window

全く動かないならともかく, 動いたり動かなかったりするので原因がさっぱりわからない.

この問題について調べてみたのですが, Fedoraのこのバージョンはサポートが終了するというコメントが引っかかりました. Bug 1366963 – Unable to capture a screenshot of any window

そう言えばportageに存在するgnome-screenshotのバージョンは3.22.0で, そしてGitHubに存在するgnome-screenshotのリリースは3.26.0ですね.

このバージョンには問題があるのかもしれません.

PyGObject使ってファイルを登録するコードを書くべきかと思いましたが, やはり出来ることならgnome-screenshotを使いたいですね.

どうにかする方法がわからなかったので結局PyGObjectで「最近開いたファイル」を追加するスクリプトを書きました.

How does one add an item to GTK's "recently used" file list from Python? - Stack Overflow を大いに参考にしました.

takeScreenshot :: X ()
takeScreenshot = do
    home <- liftIO getHomeDirectory
    time <- liftIO $ formatTime defaultTimeLocale "%Y-%m-%d-%H-%M-%S" <$> getZonedTime
    let path = concat [home, "/Pictures/", "screenshot-", time, ".png"]
    spawn $ concat ["import ", path, " && .xmonad/recent-add-item.py ", path]
#!/usr/bin/env python3

import os.path
import sys

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject

Gtk.RecentManager.get_default().add_item('file://' + os.path.abspath(sys.argv[1]))
GObject.idle_add(Gtk.main_quit)
Gtk.main()

これで「最近開いたファイル」にスクリーンショットファイルが追加されるので解決! これぐらいPythonじゃなくて素のコマンドラインで追加させてくれ.