macOS Monterey の JXA は NSRect のバグが無くなった。
ということで、今の知識で NSWindow を作ってみたらどうなるか。
いや PyObjC のほうが簡単なんだけど、デフォルトで入っていないのが。
JXA ならどんな Mac でもそのまま動かせるという利点があるので捨て難い。
ただ JXA では PyObjC みたいに class にできないんだよなぁ。
ネットで簡単に見つかる方法では全部グローバル変数にするしかないのが。
そもそも JavaScript の class は他の言語の class とは違うし。
なので GNOME の Gjs もアクロバットな手段で class っぽくしている。
ObjC.registerSubclass を上手く利用してソレっぽくやってみよう。
追加メソッドはどう書けばいいのかな?とか。
#!/usr/bin/osascript
ObjC.import('Cocoa');
//let wins = [];
ObjC.registerSubclass({
name: 'AppDelegate',
protocols: ['NSApplicationDelegate'],
methods: {
'applicationDidFinishLaunching:': function (notification) {
let window = $.MyWindow.alloc.initWithContentRectStyleMaskBackingDefer(
$.NSMakeRect(0, 0, 300, 100),
$.NSTitledWindowMask
| $.NSClosableWindowMask
| $.NSMiniaturizableWindowMask
| $.NSResizableWindowMask,
$.NSBackingStoreBuffered,
false
);
window.makeKeyAndOrderFront(window);
$.NSApp.activateIgnoringOtherApps(true);
//wins.push(window);
}
}
});
ObjC.registerSubclass({
name: 'WinDelegate',
protocols: ['NSWindowDelegate'],
methods: {
'windowWillClose:': function(notification) {
console.log('MyApp Close !');
return $.NSApp.terminate(0);
}
}
});
ObjC.registerSubclass({
name: 'MyWindow',
superclass: 'NSWindow',
propertyies: {},
methods: {
'initWithContentRect:styleMask:backing:defer:': function
(contentRect, style, backingStoreType, flag) {
let _this = ObjC.super(this).initWithContentRectStyleMaskBackingDefer(
contentRect, style, backingStoreType, flag);
_this.title = $('JXA NSWindow');
_this.delegate = $.WinDelegate.new;
// Button
let button = $.NSButton.buttonWithTitleTargetAction('button', this, 'onButtonClick:');
button.setFrame($.NSMakeRect(10, 10, 200, 36));
_this.contentView.addSubview(button);
// return
return _this;
},
'onButtonClick:': {
types: ['void', ['id']],
implementation: function(sender) {
sender.setTitle('Clicked!');
}
}
}
});
/**
* Application
*/
$.NSApplication.sharedApplication;
$.NSApp.setActivationPolicy($.NSApplicationActivationPolicyRegular);
$.NSApp.mainMenu = function() {
let mainMenu = $.NSMenu.new;
let itemApp = $.NSMenuItem.new;
mainMenu.addItem(itemApp);
let menuApp = $.NSMenu.new;
itemApp.setSubmenu(menuApp);
// quit menu
let itemQuit = $.NSMenuItem.new;
itemQuit.initWithTitleActionKeyEquivalent('Quit App', 'terminate:', 'q');
menuApp.addItem(itemQuit);
return mainMenu;
}();
$.NSApp.setDelegate($.AppDelegate.new);
$.NSApp.run;
こんな感じになった、
ボタンのハンドラは delegate ではなく this に届くようだ。
オーバーライドは types 指定不要なのね、ふむふむ。
これだけ解れば応用でなんとかなりそう。
ただ PyObjC と違って NSWindow がガベージコレクションされないんだが。
let 指定ならばハンドラを抜けたら破棄されるはずなんだけど、何故だ?
Python とは破棄対象の選定方法が違うんだろう、知らんけど。
ところで Monterey で今頃気がついたんだけど。
iOS みたいに充電の保留機能が付いたんだね。
筆者は滅多に持ち歩かないんで意味はないかもだがけど。