月別アーカイブ: 2022年4月

mpv: Ctrl+q @ Close all MPV Windows

Fedora で mpv を使って困ること。
Ctrl+q で複数起動したすべての mpv を終了できないこと。

だって GNOME のアプリは全部そうなっているんだもの。
そういえば Chrome が Fedora では終了できないな、狐はできるのに。
コレは GNOME アプリ同様 Ctrl+w 連続押しで代用できるのでまあよし。

macOS では command+q ですね、サードパーティすら全部。
そりゃ macOS はウインドウを全部閉じても終了できないんだから必須機能。
唯一 Finder だけが不可、ファイルマネージャは常に起動しているし。

でも Nautilus は Ctrl+q で全部のウインドウを閉じてくれる動作をする。
そんなこんなで、凄く気になるんですよ。

で、よく考えたら UNIX には killall コマンドがあった。
Linux ではコマンドと GUI の区別が無いんだから使えるかも。
ということで Lua スクリプト。

-- ~/.config/mpv/scripts/mpv_ctrl_q.lua

-- Ctrl+q @ Close all MPV Windows.
function on_close_all()
    os.execute('killall mpv')
end
mp.add_key_binding('Ctrl+q', 'close_all_func', on_close_all)

これをスクリプトディレクトリに突っ込んで。
おぉ自分を含めて全部終了してくれる、やったね。
macOS では GUI は区別されているから無理だと思う。
統一されたキーボード操作が無い某 OS はどうでもいいね。

ついでに、最近の mpv osc 設定。
シークバーは QuickTime のようにフローティングもできると知った。

# ~/.config/mpv/script-opts/osc.conf

# 動画に合わせた OSC リサイズ無効
vidscale=no

# 薄くする
boxalpha=180

# 常にトータル時間
timetotal=yes

# タイトルはファイル名 -- タイトル名
title=${filename} -- ${media-title}

# シークバーのみに、弄る時に枠外になるのを防げる
layout=slimbox
seekbarstyle=diamond
valign=0.95

kogera

てかシークバーだけにできるんだ、こりゃいいわ。
だって osc ってシークバーしか使わないよねみんな。

kogera

QuickTime も再生ボタンとか消せないかなぁって。
macOS では動画はほとんど見ないので QuickTime のままです。
ちなみに QuickTime だけで動画の切り貼りやリサイズ保存ができる。
筆者の編集範囲ならコイツだけで完了するので重宝していたりします。

GTK4: GtkRadioButton to GtkCheckButton

GTK4 は GtkRadioButton が廃止されていた。
え、GTK4 製な gnome-text-editor のメニューにはラジオボタンがあるぞ?
継承元である GtkCheckButton のドキュメントを見てみた。

Gtk.CheckButton

なるほど、GtkCheckButton に統合されたってことなんだね。
グループ化すると自動的に丸い形になるのか、よしやってみよう。

#!/usr/bin/env python3

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

class RadioWin(Gtk.ApplicationWindow):
    '''
        GTK4: GtkRadioButton
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        root = None
        for s in ['Leica', 'SIGMA', 'Panasonic']:
            # GtkRadioButton to GtkCheckButton
            r = Gtk.RadioButton(label=s, group=root)
            #r = Gtk.CheckButton(label=s, group=root)
            r.connect('toggled', self.on_radio_toggled)
            if not root:
                root = r
                r.props.active = True
            vbox.pack_start(r, False, False, 0)
            #vbox.append(r)
        self.add(vbox)
        #self.set_child(vbox)
        self.show_all()
 
    def on_radio_toggled(self, button):
        if button.props.active:
            self.props.title = button.props.label

def app_activate(a):
    w = RadioWin(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

GTK3

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class RadioWin(Gtk.ApplicationWindow):
    '''
        GTK4: GtkRadioButton
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        root = None
        for s in ['Leica', 'SIGMA', 'Panasonic']:
            # GtkRadioButton to GtkCheckButton
            #r = Gtk.RadioButton(label=s, group=root)
            r = Gtk.CheckButton(label=s, group=root)
            r.connect('toggled', self.on_radio_toggled)
            if not root:
                root = r
                r.props.active = True
            #vbox.pack_start(r, False, False, 0)
            vbox.append(r)
        #self.add(vbox)
        self.set_child(vbox)
        #self.show_all()
 
    def on_radio_toggled(self, button):
        if button.props.active:
            self.props.title = button.props.label

def app_activate(a):
    w = RadioWin(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

GTK4

RadioButton

うん唖然とするくらい同じだ、これなら GTK4 化に困らない。
そんなことより、GTK3 と GTK4 って思っていたより違うんだね。

GTK3 はデフォルトが非表示なせいか最初の toggled シグナルが発生しない。
GTK4 のウインドウのほうが少しだけ大きい、なんでだろう。
非アクティブ時のタイトルバー文字列が GTK4 だと濃いまま。
いやタイトルバーはヘッダーバーにすれば普通に薄くなるみたいですけど。

関係ないけど GtkApplication 部分はコレが一番短く書けるな。
今後のサンプルコードはコレでいこうと思う。

だいぶ GTK4 も解ってきたしまとめや自アプリの GTK4 化を。
したいんだけど Fedora 35 の PyGObject は DnD に不具合があるので。
text/uri-list の取得ができずファイルのドロップで開くことができない。
次の Fedora で修正されているはずなのでそれから本格的に。

Bluebird

今日は小牧山へ、夏鳥を求めて。

ooruri

オオルリ、幸せの青い鳥。
実は初めて実物を見たんだけどちっさ、まあそりゃヒタキ科ですしね。。
オオ** なのだからヒヨドリくらいのサイズだと勝手に思っていた。

sansyoukui

サンショウクイ、オスはモズのような黒い目線がカッコイイ。
けれど、いい角度で撮影できなかった。

sansyoukui

同メス、この鳥もメスは地味ですねぇ。
鳥ってなんでオスばかりに特徴があるんだろうね。

キビタキもいたんだけど撮影できず。
しかし旬の野鳥が近場のこんなところで見つかるんですねぇ。

GTK4: gtk_window_begin_move_drag

前々回に約束したドラッグで移動させる処理をなんとかした。

gtk_window_begin_move_drag は GTK4 で廃止された。
けれどこの関数って Gdk の処理を簡素化しただけだったみたい。
ということで下記をご覧ください。

#!/usr/bin/env python3
 
import gi, sys
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GdkPixbuf, Gdk, Gio

# Picture File
PNGFILE = 'test.png'

# CSS
APP_CSS = 'window { background-color: rgba(255, 255, 255, 0); }'.encode('utf-8')

class Win(Gtk.ApplicationWindow):
    '''
        GTK4: No Decorated Window
    '''
    def __init__(self, app):
        try:
            Gtk.ApplicationWindow.__init__(self, application=app, decorated=False)
            # Transparent
            provider = Gtk.CssProvider()
            provider.load_from_data(APP_CSS)
            context = self.get_style_context()
            context.add_provider_for_display(
                self.get_display(),
                provider,
                Gtk.STYLE_PROVIDER_PRIORITY_USER)
            # Mouse Move Signal
            click = Gtk.GestureClick()
            click.connect('pressed', self.on_gesture_click_pressed)
            self.add_controller(click)
            # Draw
            self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(PNGFILE)
            da = Gtk.DrawingArea()
            da.set_draw_func(self.da_draw_func)
            self.set_child(da)
            # Resize
            self.set_default_size(self.pixbuf.get_width(), self.pixbuf.get_height())
        except Exception as e:
            print(e, file=sys.stderr)
            app.quit()

    def da_draw_func(self, da, cr, width, height):
        Gdk.cairo_set_source_pixbuf(cr, self.pixbuf, 0, 0)
        cr.paint()

    def on_gesture_click_pressed(self, click, n_press, x, y):
        '''
            GTK4: gtk_window_begin_move_drag
        '''
        button = click.get_button()
        toplevel = self.get_surface() # GdkToplevel
        display = self.get_display()
        seat = display.get_default_seat()
        device = seat.get_pointer()
        s, win_x, win_y = device.get_surface_at_position()
        #print(f'{win_x}, {win_y}')
        time = device.get_timestamp()
        toplevel.begin_move(device, button, win_x, win_y, time)

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        # set Ctrl+Q
        self.set_accels_for_action('app.quit_action', ['<Control>Q'])
        quit_action = Gio.SimpleAction(name='quit_action')
        self.add_action(quit_action)
        quit_action.connect('activate', lambda a, p: self.quit())
        #
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)

Gdk の gdk_toplevel_begin_move という関数を使うんだけど。
与える引数がが gtk_window_begin_move_drag と同じじゃん。
いやその引数は自力で得る必要があるんだけーがさ。
とにかく上記で枠無しウインドウの移動ができるようになりました。

注意点として、前々回は released シグナルにしていたけど。
マウスドラッグは pressed シグナルでやらないと動作しません、当然だよね。
これに気が付かず筆者は一時間くらい無駄な時間を使ってしまった。

それと、コレをやると W クリックを検出できなかった。
press した時点で移動処理に入るので初回にリセットされるようだ。
非同期にするとか何か手段はあるのだろうけど、今日はココまで。
今回は Ctrl+Q で終了するようにした、GTK3 と変わっていなかった。

解ってしまえばこんなに簡単だったのね。
GtkGestureDrag でなんとかしようと無駄なコードをイッパイ書いたよ、ばかやろう。

Haru

今日の五条川、周辺な近所の田畑。

kiji

キジの夫婦、いやー久々に見つけた。
こんなにデカいんだからもっと見かけてもおかしくないはずだが。

kochidori

コチドリ、いやー夏鳥が見つかる時期ですね。
ここらでチドリはコイツしか見かけないなって。

hibari

ヒバリ、いやーやっとこさ撮れた。
今月頭からアホみたく鳴いているのに保護色強すぎで全然見つからない。

tsugumi

ツグミ、いやーってお前冬鳥だろ。
他の冬鳥は全然見なくなったけどコイツらだけは時期が違うのかな。

keri

ケリ、いやーお前やかましいんだよ!
人に見つかりたくないんならツグミみたく黙っていろよと。

他にもスズメやカワラヒワがやかましい、春ですね。
しかし近所だけでこんな色々な種類の野鳥がいるんですねって。
野鳥撮影は楽しいというより勉強になる。