Programming」カテゴリーアーカイブ

Gedit 3.14 Plugin

そろそろ新しい Fedora が出るので準備をしなければ。
ベータが出ているようなので試す、面倒だから久々に仮想マシン。

boxes

Boxes(qemu-kvm) はやはり超簡単というか全自動です。
Fedora on Fedora なら 3D デスクトップもストレスが無いのが嬉しい。
細かい指定はできないけどテスト目的には十分すぎる。

ただ Live 中はフル HD なのを認識したのにインストール後は SXGA に。
相変わらずよく解らない認識をする、フル HD 固定だとそれも困るわけですが。
筆者はウインドウモードで使うので 1440×900 に固定。

インストール直後に生 XML から iso を排除する必要はなくなったみたい。
Boxes の設定画面[デバイス]の CD/DVD の所で取り外しできる。

cd_dvd

Alt+Space がウインドウメニューに割り当てされているや。
US キーボードなのでコレで入力切り替えできないと不便なんだよ。
まあ設定で簡単に変えられるのでちゃっちゃと変更。

header_bar

いやぁ、見事に GtkHeaderBar 化されて…
っておい Eye of GNOME さん、あんたが一番メニューバー邪魔でしょ。
これ以上の変更点レビューは正式版の時に。

とにかく Gedit はメニューバーが無いので以前の自作プラグイン達は使えない。

Apps/Gedit/PythonPluginHowTo – GNOME Wiki!
残念ながら 2014.11.16 現在チュートリアルは以前のままだ。

Gedit 3.12 をスルーしたおかげで日本語の先人を見つけた。

うぇーん、GNOME 3.12 にしたら、自家製Linespacing が動かないよー | (まだ無題 ; そのうち変更するかも)

メニュー項目は GMenu 化、GtkApplication 側に登録。
ハンドラは GAction として GtkWindow 側に登録するみたい。
GtkUIManager 関連を消すのを忘れているみたいですけど。

なんか上手くいかないので QuickOpen のソースを参考に少し作り替え。
*.plugin ファイルは以前と同じでいいようです。

#-*- coding:utf-8 -*-

from gi.repository import GObject, Gedit, Gtk, Gio

class TestTestAppActivatable(GObject.Object, Gedit.AppActivatable):
    """
        Set GMenu and Accelerator
    """
    app = GObject.property(type=Gedit.App)

    def __init__(self):
        GObject.Object.__init__(self)

    def do_activate(self):
        # Set Accelerator
        # (key, action name[win.xxxxx], parameter or None)
        self.app.add_accelerator("<Control>B", "win.action_name", None)
        # Append Menu
        self.menu_ext = self.extend_menu("tools-section")
        item = Gio.MenuItem.new("imouto",  "win.action_name")
        self.menu_ext.append_menu_item(item)

    def do_deactivate(self):
        # Remove Accelerator
        self.app.remove_accelerator("win.action_name", None)

class TestTest(GObject.Object, Gedit.WindowActivatable):
    """
        Set GAction
    """
    __gtype_name__ = "TestTest"
    window = GObject.property(type=Gedit.Window)
    def __init__(self):
        GObject.Object.__init__(self)

    def do_activate(self):
        # Set Action
        # (action name, parameter or None)
        action = Gio.SimpleAction.new("action_name", None)
        action.connect('activate', self.on_activate)
        self.window.add_action(action)

    def do_deactivate(self):
        # Remove Action
        self.window.remove_action("action_name")

    def do_update_state(self):
        pass

    def on_activate(self, action, data=None):
        self.messagebox("Yamete Oni-chan")

    def messagebox(self, text):
        dlg = Gtk.MessageDialog(
                self.window,
                Gtk.DialogFlags.MODAL,
                Gtk.MessageType.WARNING,
                Gtk.ButtonsType.OK,
                text)
        r = dlg.run()
        dlg.destroy()

gedit314_plugin

こんな感じで。

とりあえずアクション名を決める。
GtkApplication 側で使う場合は win.xxxxx と接頭子を付ける。
こうしないとメニューがアクティブにならなかった。

次はアクション名にアクセラレータキーに紐付ける
そしてメニューに表示する文字列を決め GMenu を作成。
それをメニューのどこかに突っ込む。
file-section, tools-section, view-section-2 等々。

本体側は先程のアクション名で GAction を作る。
シグナルハンドラをセットし本体に登録、コッチは簡単だね。
後は今迄どおりでいいみたい。

Eye of GNOME プラグインは変更しなくてもいいかな?と思ったけどダメだった。
と思ったら *.plugin の Loader=python3 書き換えだけでイケた。

eog314plugin

Python3 なので unicode 等の処理をお忘れなく。

GtkMenuButton F10

Y901x 1.1.2 公開、日は変わってしまったけど。

y901x112

メニューバーを取り払ったよ。
ラジオメニューじゃ解りづらい再生速度アスペクト比切り替えもステータスバーに移した。

GtkHeaderBar and GStreamer | PaePoi
Mini GtkButton | PaePoi

つーか、今頃になってやっと上記を実装した、半年も前だったのか。
使い道の例だと思ってください、多分作った本人しか使っていないアプリなので。

所で F10 キーでメインメニューがドロップするのは知っているよね。
GtkMenuButton ではこれを自分で実装しないといけないみたい。
こんな感じでいいみたい、F10 ってシステム管理じゃなかったんだ。
ちょっと具体的に追記

#!/usr/bin/env python3

class Win(Gtk.ApplicationWindow):
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app)
        # GtkAccelGroup
        accelgroup = Gtk.AccelGroup.new()
        self.add_accel_group(accelgroup)
        # Preference button
        preferencebutton = Gtk.MenuButton.new()
        image_gear = Gtk.Image.new_from_icon_name("emblem-system-symbolic", Gtk.IconSize.MENU)
        preferencebutton.set_image(image_gear)
        # Set F10 Accel
        preferencebutton.add_accelerator("clicked", accelgroup, Gdk.KEY_F10, 0, Gtk.AccelFlags.VISIBLE)
        # HeaderBar
        headerbar = Gtk.HeaderBar()
        headerbar.pack_end(preferencebutton)

ついでに今頃気が付いた。
Alt+F10 で最大化切り替えできる、これは便利だ。
まあシステム設定で変更できるんだけど。

後 Y901 伝統の Z キーでフルスクリーンは実装できなかった。
一応強引な手段もあるけど GNOME デフォルトの F11 のみでいいかなと。

次は Alt+Enter でプロパティ表示を実装したいな。
一度弄り始めると急に色々思い付くんだよね。

Ubuntu での動作確認は明日やろう(ぉい!
個人的には超有名な某ゲームエンジンと同じ名前であるあの糞デスクトップ環境はガン無視したいんだけどユーザー数がなぁ…

GtkToggleButton and keyboard

GtkToggleButton のシグナルには activate と clicked がある。

activate は On 時のみ、clicked は On/Off 両方シグナルが発生する。
マウス等でクリック時だけでなく gtk_button_clicked() 関数にも反応する。

なので GtkToggleButton を Off させる場合に困る場合がある。
トグルなので二度押しで上るわけだが複数ボタンで排他制御を行う場合に。
更にキーボードでも同様に動作するようにとなると…

activate では二度押しで上るのを検知できない。
clicked では排他で上るボタンからもシグナルが飛んでくる。

activate は使えそうもないので clicked にするしかない。
Off 検知を逃すのとキーボードでつじつまを合わせるのに一苦労。
そのためアクロバチックなコードを今まで書いていた。

class Y901window(Gtk.ApplicationWindow):
    def __init__(self, app):
        #
        # etc...
        #
        self.toolbox.one.connect("clicked", self.on_rep_btn, 1)
        self.toolbox.all.connect("clicked", self.on_rep_btn, 2)
        self.toolbox.rdm.connect("clicked", self.on_rep_btn, 3)
        #
        # etc...
        #

    def on_keydown(self, accelGroup, window, keyval, modifier):
        if keyval == Gdk.KEY_F7:
            self.toolbox.one.clicked()
        elif keyval == Gdk.KEY_F8:
            self.toolbox.all.clicked()
        elif keyval == Gdk.KEY_F9:
            self.toolbox.rdm.clicked()
        ''' old
        if keyval == Gdk.KEY_F7:
            self.on_rep_btn(None, 1)
        elif keyval == Gdk.KEY_F8:
            self.on_rep_btn(None, 2)
        elif keyval == Gdk.KEY_F9:
            self.on_rep_btn(None, 3)'''

    def on_rep_btn(self, widget, num):
        if widget.get_active():
            if self.settingwin.repeat != num:
                self.toolbox.one.set_active(num == 1)
                self.toolbox.all.set_active(num == 2)
                self.toolbox.rdm.set_active(num == 3)
                self.settingwin.repeat = num
        else:
            if not self.toolbox.one.get_active() and not self.toolbox.all.get_active() and not self.toolbox.rdm.get_active():
                self.settingwin.repeat = 0
        ''' old
        if widget == None:
            if num == 0:
                self.toolbox.one.set_active(False)
                self.toolbox.all.set_active(False)
                self.toolbox.rdm.set_active(False)
            elif num == 3:
                self.toolbox.one.set_active(False)
                self.toolbox.all.set_active(False)
                self.toolbox.rdm.set_active(True)
            elif num == 2:
                self.toolbox.one.set_active(False)
                self.toolbox.all.set_active(True)
                self.toolbox.rdm.set_active(False)
            elif num == 1:
                self.toolbox.one.set_active(True)
                self.toolbox.all.set_active(False)
                self.toolbox.rdm.set_active(False)
        else:
            if widget.get_active():
                if self.settingwin.repeat != num:
                    action = self.actiongroup.get_action(ac2_str[num])
                    action.set_current_value(num)
                    if num != 3:
                        self.toolbox.rdm.set_active(False)
                    if num != 2:
                        self.toolbox.all.set_active(False)
                    if num != 1:
                        self.toolbox.one.set_active(False)
            else:
                if self.settingwin.repeat == num:
                    action = self.actiongroup.get_action(ac2_str[0])
                    action.set_current_value(0)
                    self.toolbox.one.set_active(False)
                    self.toolbox.all.set_active(False)
                    self.toolbox.rdm.set_active(False)'''

最初に書いたとおり gtk_button_clicked() 関数にも反応だからコッチを使う。
これでマウスクリックと直接呼び出しとを振り分けする必要はなくなった。

排他を if 文で振り分けしていた部分はこの手があった。
今まで何をやってきたのかと情け無くなった。

排他トグルで All Off は All Off の場合のみ処理すればいい。
それ以外だったら必ずどこかが On になっているということだから。
散々悩んだことなのに解ってしまえばこんなにアッサリ。

ということで、こんなにコードが短くなった。
強引に短くするドヤ顔コードは吐き気がするけど正攻法で短くするのは気持ちいい。

GtkActionGroup の処理が取り除かれているけど気にしないで。
メニューバーを GNOME の意向に合わせ取っ払っているだけなので。
iPhone を使うようになってから更にメニューバーが邪魔に思えてきた。
何故あんなのが普及したのか謎と考えるくらいに。

gst direction next frame

JavaScript でスマホゲームもいいけどメインの GTK+ もやらねば。
久々に Y901x の更新、ポーズからコマ戻しが上手くいく方法を見つけたので。

# self.player @ playbin
# self.settingwin @ My Setting

def set_next_frame(self, rate):
    """
        1 frame up down (rate 1.0 or -1.0)
    """
    if self.settingwin.direction != rate:
        self.settingwin.direction = rate
        self.set_playback_direction(rate)
    event = Gst.Event.new_step(Gst.Format.BUFFERS, 1, 1.0, True, False)
    self.player.send_event(event)

def set_playback_direction(self, rate):
    """
        Change direction
    """
    pos = self.player.query_position(Gst.Format.TIME)[1]
    if rate >= 0.0:
        self.player.seek(
                rate,
                Gst.Format.TIME,
                Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
                Gst.SeekType.SET, pos,
                Gst.SeekType.SET, -1)
    else:
        self.player.seek(
                rate,
                Gst.Format.TIME,
                Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
                Gst.SeekType.SET, 0,
                Gst.SeekType.SET, pos)

def on_play(self, widget, data=None):
    if self.settingwin.direction == -1.0:
        self.settingwin.direction = 1.0
        self.set_playback_direction(1.0)
    if self.player.get_state(1)[1] == Gst.State.PLAYING:
        self.player.set_state(Gst.State.PAUSED)
    else:
        self.player.set_state(Gst.State.PLAYING)

逆転させる手続きを分離して send_event するだけだった。
GLib.idle_add とか色々試したのに実はこんなに簡単だった…

これなら関数を抜けるので逆転した後で 1 コマ移動ということになるのかな。
再生開始で正転に戻すのを忘れないようにと。

それと手段が全然解らず困り果てていたシークバー上のマウスホイール。
event.direction 引数が Gdk.ScrollDirection.SMOOTH になるのよ。
Gdk.ScrollDirection.UP, DOWN になる記事以外見当たらなかったし。

http://nullege.com/codes/show/src%40p%40i%40pitivi-HEAD%40pitivi%40utils%40widgets.py/1035/gi.repository.Gdk.ScrollDirection.UP/python

そういうことだったのか!
やっぱり GPL のコードを見たほうが圧倒的に参考になるね。
何も作品を作っていなさそうな人って何故勉強しているのか、日本人に多過ぎ。

def on_seek_scroll_event(self, widget, event):
    """
        Mouse Wheel event
        widget @ GtkScale
    """
    delta = 0
    if event.direction in [Gdk.ScrollDirection.UP, Gdk.ScrollDirection.RIGHT]:
        delta = 1
    elif event.direction in [Gdk.ScrollDirection.DOWN, Gdk.ScrollDirection.LEFT]:
        delta = -1
    elif event.direction in [Gdk.ScrollDirection.SMOOTH]:
        unused_res, delta_x, delta_y = event.get_scroll_deltas()
        if delta_x:
            delta = math.copysign(1, delta_x)
        elif delta_y:
            delta = math.copysign(1, -delta_y)
    if delta:
        location = widget.get_value() - (delta * 10000000000)
        if location > 0 and location < self.playinfo.duration:
            self.set_play_position(location)
            self.put_time_status(location)

これで約 10 秒送りなホイールスクロールが可能になった。
Fedora 20 でしか試していないけど多分 GNOME なら大丈夫だろう。
次バージョン早く出ないかなぁ、20 が安定しているからいいけど半年サイクルに慣れ過ぎた。

Gtk+ 3.10 on Ubuntu 14.04

Ubuntu 14.04 が出たが Fedora な筆者はどうでも…よくない。
GtkHeaderBar や GtkStackSwitcher は Unity 環境ではどうなるか確認せねば。
使用感とかは他人に任せてと。

筆者が書いた下記サンプルコードで試してみる。
GTK+ 3.10 – L’Isola di Niente

gtkheaderbar

GtkHeaderBar はそのまま使えるけど標準とは異なるものになってしまう。
つまり標準の Nautilus とかは改造しているということだったのか。

それに枠に影がなくなるのでウインドウが重なると境界が解らない。
更に最大化しても上部バーと一体化せず一段下へと標準とは異なる動作に。
というか、リサイズできなくなる。

なんだよ、つまり GtkHeaderBar は使えないということじゃないか。
詰めが甘いのか意図的なのかは解らないけど。
GtkStack, GtkStackSwitcher, GtkListBox は問題なく使えるようです。

GtkHeaderBar and GStreamer | PaePoi

GTK+ 3.10 なのだからこの動画の画面が出ない症状は同じだった。
いや GNOME だと真っ黒だけど Unity だと透明になる、音だけなのは同じ。
でも Totem 3.12 は GtkHeaderBar 採用になっているんだよな。
このあたりは Fedora 21 の時に。

appmenu

ApplicationMenu は GNOME と同様になるようにしたようです。
なのに何故か Nautilus 等のメニューバーは古いものを採用。

nautilus_gnome

menubar_ubuntu

同じ Nautilus 3.10.1 のはずなのに何だよこの違い。
というかこれなら 3.8 のままでいいじゃないか、と思うのだが。

他にも GNOME 3.10 を知っている人ならツッコミ所が多々。
3.10 で GtkStackSwitcher になった部分が全部 GtkNotebook に変更って。
ユニバーサルアクセス設定等の GtkListBox も同様、これは古いアプリのまま?
GtkHeaderBar 以外は特に問題ないのに何故古いままな UI に戻すやら。

他にも GNOME がボタンをアイコン化した部分等も何故か文字列ボタンに戻している。
GNOME プロジェクトの成果物に昔ながらの UI をわざわざ被せた感じ。
おかしいな、Unity ってタッチパネル向けに振った UI じゃなかったか?

独自にやっていたらベースの GNOME アプリ側もやってきたので色々あるだろうけど。
3.12 は Gedit も Totem も GtkHeaderBar になるんだが、どうするのだろう。

当面 GTK+ アプリは Unity 環境専用ビルドを別途で用意する必要あり。
なんて嫌だぞこのやろう。