GtkDrawingArea GdkEvent

あけましておめでとうございます。
昨日出した comipoli がバグだらけで今年も正月からプログラミング。

まだおかしい、button-press-event がタイトルバーに反応する。
多分 GtkHeaderBar 部分もクライアントエリアとして認識されているかと。
GNOME は GtkHeaderBar を推奨だけど使うとこんな弊害が色々出るんだよなぁ。

GtkDrawingArea で GdkEvent を取ればいいのだが、手段が解らなかった。
普段あまりネタが無いのに元旦にネタができるという。

日本語で見つかったサイトはココだけだった、GTK2 だけど。
GtkDrawingAreaに図形を表示する
2019 年にもなって手打ち HTML かつスマホ用タグ無しサイトってどうなんだ。。。。。
いやそれはどうでもよくて。

c – In GTK+3, how do I get a drawingarea to respond to mouse events? – Stack Overflow

やはり GTK3 も gtk_widget_add_events と can-focus プロパティか。
とにかくやってみよう。

Events: GDK 3 Reference Manual

GdkEventMask を調べたら GDK_BUTTON1_MOTION_MASK なんて便利そうなものが。
マウス左ボタンを押しっ放しで動かした場合のみ飛んでくるシグナルのようだ。
自分でフラグを用意しなくてもいいのね、早速。

#!/usr/bin/gjs

const System = imports.system;
const GObject = imports.gi.GObject;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Gdk = imports.gi.Gdk;

var DrawingWindow = GObject.registerClass({
    GTypeName: "DrawingWindow"
}, class DrawingWindow extends Gtk.ApplicationWindow {
    _init(app) {
        super._init({application: app});
        // var
        this.xy = [false, 0, 0];
        // HeadreBar
        let hb = new Gtk.HeaderBar({show_close_button: true});
        this.set_titlebar(hb);
        // DrawingArea
        let da = new Gtk.DrawingArea();//{can_focus: true});
        //da.set_events(
        da.add_events(
            Gdk.EventMask.BUTTON_PRESS_MASK |
            Gdk.EventMask.BUTTON_RELEASE_MASK |
            Gdk.EventMask.BUTTON1_MOTION_MASK |
            Gdk.EventMask.STRUCTURE_MASK );
        da.connect("button-release-event", (widget, event)=> {
            return false;
        });
        da.connect("button-press-event", (widget, event)=> {
            if (event.get_button()[1] === 1) {
                this.xy = event.get_coords();
                hb.set_title(`${this.xy[1]}/${this.xy[2]}`);
                widget.queue_draw();
            }
            return false;
        });
        da.connect("motion-notify-event", (widget, event)=> {
            this.xy = event.get_coords();
            hb.set_title(`${this.xy[1]}/${this.xy[2]}`);
            widget.queue_draw();
            return false;
        });
        da.connect("draw", (widget, cr)=> {
            cr.arc(this.xy[1], this.xy[2], 10.0, 0.0, 2*Math.PI);
            cr.fill();
        });
        this.add(da);
        // this
        this.resize(400, 400);
        this.show_all();
    }
});

var DrawingApplication = GObject.registerClass({
    GTypeName: "DrawingApplication"
}, class DrawingApplication extends Gtk.Application {
    _init(v) {
        GLib.set_prgname("Program");
        super._init({
            application_id: "org.sasakima.drawwin",
            flags: Gio.ApplicationFlags.HANDLES_OPEN
        });
    }
    vfunc_startup() {
        super.vfunc_startup();
        new DrawingWindow(this);
    }
    vfunc_open(files, hint) {
        this.active_window.present();
    }
    vfunc_activate() {
        this.active_window.present();
    }
});

new DrawingApplication().run([System.programInvocationName].concat(ARGV));

あれ?

cairo のクリアをしていないので追加描写だと思ったら書き換えされる。
逆にフォトレタッチみたく追加で描くにはどうすればいいんだ?
あぁヤルことが増えてしまった、それは後日ということで。
とにかくマウス左ボタンに追従する円のできあがり。

マウスだけなら can-focus プロパティはセットする必要が無いみたい。
GDK_KEY_PRESS_MASK 等を使うなら当然必須になると思うけど。

add_events, set_events のどちらでも動いた。
set は初期化、add は既にあるイベントに追加という振り分けみたい。
GtkDrawingArea は元々何もないので同じということね。

今年もこんな感じでいきます。