タグ別アーカイブ: JavaScript

MessageBox.show @ Gjs and PyGObject

JavaScript の static メソッドはインスタンスからは呼び出しできない。

#!/usr/bin/gjs
 
class A {
    constructor(arg) {
        this.num = 'instance';
    }
    static static_method() {
        return 'staticmethod';
    }
}
A.num = 'static';
a = new A();
print(a.num); //=> instance
print(A.num); //=> static

print(A.static_method()); //=> staticmethod
print(a.static_method()); //=> ERROR!

当然である。
JavaScript の class は prototype の別表現でしかないから。

#!/usr/bin/gjs

function A() {}
A.func = function() {
    return 'staticmethod';
}
A.prototype.func = function() {
    return 'instancemethod';
}

print(A.func()); //=> staticmethod
let a = new A();
print(a.func()); //=> instancemethod

Python,C# 等の他言語ではインスタンスからでも呼び出しできる。

#!/usr/bin/env python3
 
class A:
    def __init__(self):
        self.num = 'instance'
    @staticmethod
    def static_method():
        return 'staticmethod'

A.num = 'static'
a = A()
print(a.num) #=> instance
print(A.num) #=> static

print(a.static_method()) #=> staticmethod
print(A.static_method()) #=> staticmethod

特に C# でよく見るけど、わざわざインスタンスを作ってからスタティックメソッドを使っている人の異様な多さを見ると JavaScript みたいなアクセスのほうがいいような。

そんなことより。
スタティックメソッドとインスタンスメソッドで同じ名前を指定してもいいんだ。
あまり自分のコードでスタティックを作らないから知らなかったよ。

ということで。
GtkMessageDialog で MessageBox.show を作ってみよう。
MessageBox.Show ではどちらの言語のコーディングスタイルにも合わないからね。
Gir の Gtk.Widget には show メソッドがあるけど無視できる。

#!/usr/bin/gjs

const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;

var MessageBox = GObject.registerClass({
    GTypeName: "MessageBox"
}, class MessageBox extends Gtk.MessageDialog {
    _init(text) {
        super._init({
            buttons: Gtk.ButtonsType.OK,
            text: text,
            secondary_text: "test"
        });
    }
    static show(text) {
        //let dlg = new MessageBox(text); @ error!
        let dlg = new this(text);
        dlg.run();
        dlg.destroy();
    }
});

Gtk.init(null);
MessageBox.show("Message");

new this(text) って変な感じ。

#!/usr/bin/env python3

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

class MessageBox (Gtk.MessageDialog):
    def __init__(self, text):
        Gtk.MessageDialog.__init__(
            self,
            buttons=Gtk.ButtonsType.OK,
            text=text,
            secondary_text="test" )
    @staticmethod
    def show(text):
        #dlg = self(text) @ error!
        dlg = MessageBox(text)
        dlg.run()
        dlg.destroy()

#Gtk.init(None) @ no need
MessageBox.show("Message")

PyGObject だとこう。

GUI を作っている時の print 代わりに。

Gjs: GdkPixbuf Memory leak

comipoli がガッツリメモリリークしてる、と今更気がつく。
抜き出しすると、001.jpg – 200.jpg を用意して。
JavaScriptでゼロ埋め処理 – Qiita
ゼロ詰めはこの方法を利用しました。

#!/usr/bin/gjs

const System = imports.system;
const GObject = imports.gi.GObject;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Gdk = imports.gi.Gdk;
const GdkPixbuf = imports.gi.GdkPixbuf;
const PATH = '/home/sasakima-nao/erohon/';

var AWindow = GObject.registerClass({
    GTypeName: "AWindow"
}, class AWindow extends Gtk.ApplicationWindow {
    _init(app) {
        super._init({application: app});
        this.d = new Gtk.DrawingArea();
        this.d.connect('draw', (widget, cr)=> {
            if (this.pixbuf) {
                let aw = widget.get_allocated_width();
                let ah = widget.get_allocated_height();
                let buf = this.pixbuf.scale_simple(aw, ah, GdkPixbuf.InterpType.BILINEAR);
                Gdk.cairo_set_source_pixbuf(cr, buf, 0, 0);
                cr.paint();
            }
        });
        this.add(this.d);
        this.pixbuf = null;
        this.count = 0;
        GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, ()=> {
            this.count += 1;
            if (this.count == 200)
                return false;
            let f = `${PATH}${('00'+this.count).slice(-3)}.jpg`;
            this.pixbuf = GdkPixbuf.Pixbuf.new_from_file(f);
            this.d.queue_draw();
            return true;
        });
        this.show_all();
    }
});

var AApplication = GObject.registerClass({
    GTypeName: "FlApplication"
}, class FlApplication extends Gtk.Application {
    _init(v) {
        GLib.set_prgname("AApplication");
        super._init();
    }
    vfunc_startup() {
        super.vfunc_startup();
        new AWindow(this);
    }
    vfunc_activate() {
        this.active_window.present();
    }
});

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

動かす。

ガベージコレクションは仕事をしろよ。。。。。
完全に GdkPixbuf が原因だよな、自前で破棄しなきゃいけなかったのか。

Reference Counting and Memory Mangement: GDK-PixBuf Reference Manual

buf.unref() では非推奨の gdk_pixbuf_unref を呼び出ししそうだ。
でも JavaScript には call があるじゃないか。
$dispose() を呼び出ししたほうがいいとかもどこかで見つけた。

//buf.unref();
GObject.Object.prototype.unref.call(buf);
cr.$dispose();

結果

動かしてしばらくたってからこんなエラーを吐いて落ちる。
どうやらガベージコレクタが GdkPixbuf を見つけられない意味っぽい。
つまりガベージコレクションは仕事をしているけど実は破棄できない。
結果ゾンビになったメモリ領域が大量発生、なのね。
だけど自前で破棄するとエラー、どうしろっての。。。。。

javascript の delete は単なるプロパティの削除だ。
this にくっつけたりあれやこれや十日間やったけど破棄する手段が見つからない。

もう C で作り直しするしか手段が無いかなぁとも。
こんだけスクリプト言語押しをしといて今更感が凄いけど。
って PyGObject だとどうなんだろう?どうせ同じだと思うけど実験。

#!/usr/bin/env python3

import sys, gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, Gdk, GdkPixbuf

PATH = '/home/sasakima-nao/erohon/'

class AWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app)
        self.d = Gtk.DrawingArea()
        self.d.connect('draw', self.on_draw)
        self.add(self.d)
        self.pixbuf = None
        self.count = 0
        GLib.timeout_add(200, self.read_pixbuf)
        self.show_all()

    def on_draw(self, widget, cr):
        if (self.pixbuf):
            aw = widget.get_allocated_width()
            ah = widget.get_allocated_height()
            buf = self.pixbuf.scale_simple(aw, ah, GdkPixbuf.InterpType.BILINEAR)
            Gdk.cairo_set_source_pixbuf(cr, buf, 0, 0)
            cr.paint()

    def read_pixbuf(self):
        self.count += 1
        if self.count == 200:
            return False
        f = '{0}{1:03d}.jpg'.format(PATH, self.count)
        self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(f)
        self.d.queue_draw()
        return True

class AApplication(Gtk.Application):
    __gtype_name__ = 'AApplication'
    def __init__(self):
        GLib.set_prgname('AApplication')
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        AWindow(self)
    
    def do_activate(self):
        self.props.active_window.present()

AApplication().run(sys.argv)

まさかの問題無し!

やっていることは完全に同じなのに PyGObject では普通に破棄されている。
自前でバイナリを扱えるかどうかの差なのですかね。
筆者はいったい十日間何をやっていたんだ!
まあ検索しまくって色々勉強になったけど。
comipoli は PyGObject に戻します、メソッド名付けるのメンドイけど。

GraalVM Community Edition

JavaでJavaScriptを実行する「Nashorn」が非推奨に、ECMAScriptの速い進化に追いつけないと。代替案はGraalVM ? Publickey

今頃知った、覚書ページはどうしよう?
てか色々検索したけど GraalVM って何なのかよくワカラン。
とりあえず公式サイトのインストールページでも。

Getting started with GraalVM

js や node コマンドが含まれているみたい。
GNOME だと mozjs と被るヤン、モノホン node.js 入れていたら被るヤン!
使う時だけ先にパスが通るようにする必要があるな。

ダウンロードした tar.gz を展開、とりあえずホームに置く。
~/bin に以下を jjjs という仮の名前で置いて +x パーミッション。

#!/bin/sh

export PATH=~/graalvm-ce-1.0.0-rc6/bin:$PATH
[[ $# -eq 0 ]] && js --jvm || js --jvm $1

これで振り分けできる、print, console.log 両方使えてワロタ!
インポートは Nashorn と同じみたい、ES6 はどうなった?

const System  = Java.type("java.lang.System");
 
class GraalvmTest {
    constructor() {
        System.out.println("May I ask your name?");
        let console = System.console();
        let s = console.readLine();
        print(`Hello ${s} !`);
    }
}
new GraalvmTest();

カオス!

ES6 も完全に使えるようです。
Nashorn のもどかしさもないし結構面白いかも。
OpenJDK ベースだし次の Fedora には入っているのかな?

flex-box vender prefix

本日やっと HTML5 Test Page の書き換えが終わりました。
やっと古いページの一掃が終わったぞい。
どう書き換えするか散々迷ったけど ES6 で全部動的作成することに。

CSS3 TestPage – L’Isola di Niente

思い付きでヘッダは上部にマウスカーソルを動かすとヒョッコリ出すように。
もちろん comipoli Web 版で使うため、linux 版はフルスクリーンで出しているもん。
やはり同じにしたいじゃないの。

こうやって色々作ってみると本当に今の Web はスタンドアロンなアプリと変わらない。
普通のアプリみたいに作れるのは楽しい、去年までこんなこと考えられなかったのに。
ES6 様々です。

ところで実際に書き換えてみて解ったんだけど。

.flex {
    /*display: -webkit-flex;
    display: -moz-flex;
    display: -ms-flex;*/
    display: flex;
    flex-wrap: wrap;
    /*-webkit-flex-wrap: wrap;*/
    text-align: left;
    margin: 5px 0px;
}

2018.08 の現在 flex-box は vender prefix はもういらないのね。
根暗用 OS は持っていないので -ms-* は知らないけど、どうでもいいよね!

JavaScript MessageBox

ガンガンONLINE 等で漫画を読み進めると最後に HTML なダイアログが出る。
これと同じようなダイアログを作りたい。

サイズは alert や GtkMessageDialog のように文字列の流さに合わせたい。
閉じるボタンも当然付いている状態で出したい。

CSS で縦横センタリング! 要素を画面中央に『ドン!!』と表示する方法 | phiary

検索で一番上にでてくる有名な手段だけど width, height 指定必須。

console.log(div.style.width);

は空文字だ。

不定な流さの文字列タグの横幅を得る手段が見つからない、困った。
別の手段に頭を切り換える必要がありそうだ。

position:absolute で中央に配置するやり方 | YouKnow.jp
CSSで要素を上下や左右から中央寄せする7つの方法 | 株式会社グランフェアズ

transform:translate というのがいいみたいだ。
両方 vender prefix が付いているけど 2018.08 な現在はどうなのかな。
早速試してみよう。

messageBox(id) {
    let div = document.createElement("div");
    div.style.backgroundColor = "#EEE";
    div.style.position = "absolute";
    div.style.display = "block";
    div.style.zIndex = "101";
    // Centering
    div.style.left = "50%";
    div.style.top = "50%";
    div.style.transform = "translate(-50%,-50%)";
    // Border
    div.style.border = "1px solid #7c93b2";
    div.style.borderRadius = "3pt";
    div.style.boxShadow = "5px 5px";
    //
    let paragraph = document.createElement("p");
    paragraph.textContent = document.getElementById(id).value;
    paragraph.style.textAlign = "center";
    //
    let close = document.createElement("p");
    close.textContent = "Close";
    close.style.textAlign = "center";
    close.style.backgroundColor = "#CCC";
    close.style.border = "1px solid #7c93b2";
    close.style.borderRadius = "5pt";
    close.addEventListener("click", ()=> {
        div.removeChild(paragraph);
        div.removeChild(close);
        document.body.removeChild(div);
    });
    div.appendChild(paragraph);
    div.appendChild(close);
    document.body.appendChild(div);
}

vender prefix 無しで safari, firefox, google-chrome イケる!
何も問題ない、お試しは以下に。
ES6 Web TestPage – L’Isola di Niente

ところで google-chrome のデベロッパーツールをよく見ると。。。。。

box-shadow なんて style があるのをポップアップのおかげで知った。
いやいやツールは使ってみるものだ、早速利用しました。