electron12 でdialogを呼び出す(ContextBridge)

electron12対応へ、前回は

右クリックメニュー(ContextMenu)カスタム処理をmain-processへ移動した(electron 12対応) 

 まで。

 nodeIntegrationはともかくmoduleは将来廃止になるとのこと。

npmパッケージで逃げることもできるが、まとめて移行することに。

つまりいろいろなものをrender-processからmain-processへ移動することになり、ContextBridgeの導入を避けることができない。

 

 # electron11まで使えたdialog呼び出しコード

これまではrender-process側の適当なjsファイル内で完結する下記2行程度の記述で ダイアログを表示することができたのだが、ようはこれが使えなくなる。

 ``` js/mypage.js

const {dialog} = require("electron").remote;

dialog.showMessageBoxSync(null)

```

 

# contextIsolationを有効化

 エラーメッセージによると、ContextBridgeを使うには、contextIsolationを有効化しなければならない

(electron12からデフォルトでtrue)

# ページ上のjsでdialogは呼べない(renderer-process)

ContextBridgeでmain-processへ飛ばしてそこからrequest('electron').dialogを呼ばなければならない。

```

MN@daisy-bell:lina_dicto/$ git diff lina_dicto/js/index.js         }catch(err){
-               message_dialog('error', 'user preference error', "user preference load error:\n" + err.message);
+               window.myApi.message_dialog('error', 'user preference error', "user preference load error:\n" + err.message);
        }
 
 }, false)
```


 

# preload.js内でdialogは呼べない

最初はpreload.js内でdialogを呼ぼうとしたのだが、なぜかrequire('electron')からcontextBridge, ipcRendererのようにdialogを取り出すことができない。

(preload.js内でcontextBridge, ipcRenderer以外が使えないということかもしれない。

後のContextBridgeのサンプルコードなども、見る限りpreload.js自体はrender-process側ということのように見えるし。)

 

# ContextBridgeでdialogを呼び出す

 


 

諸々の非同期を経由で呼び出しているが、 dialog.showMessageBoxSync()はウィンドウを渡せばウィンドウはモーダルに動作する(意図どおりブロックする)ように見える。

(まあとりあえずエラー通知にしか使ってないのでそこはどちらでもよしとする。 )

ページ上のjs -> preload.js上のcontextBridge -> main-processのjs と飛ばす。


 ``` js/index.js (renderer-process)

 window.myApi.message_dialog('error', 'HELLO', 'hello!');

 ```

```preload.js

 const { contextBridge, ipcRenderer, } = require("electron");
contextBridge.exposeInMainWorld(
    "myApi", {

        message_dialog: (strtype, strtitle, strmessage) => {

            ipcRenderer.invoke('tomain-message-dialog', strtype, strtitle, strmessage);

```

``` index.js(main-process)

const { ipcMain } = require('electron');
ipcMain.handle('tomain-message-dialog', async (event, strtype, strtitle, strmessage) => {
    const { dialog } = require('electron');
    dialog.showMessageBoxSync(

            // win, // ここmain-processで生成したwindowを指定できる
            {
                type: strtype,
                buttons: ['OK'],
                title: strtitle,
                message: strmessage,
            });
});
```

 

TODO: 確認ダイアログを出してOK,NGを同期で返す。

(現行の互換動作。あるいはこれは諦めてもいい。今は不要なので)

TODO: ファイル読み出し結果を戻す

 TODO: ところでcontextIsolationが有効な時に nodeIntegration: trueが 無効になってない?

 

 

右クリックメニュー(ContextMenu)カスタム処理をmain-processへ移動した(electron 12対応)

右クリックメニュー(ContextMenu)カスタム処理をmain-processへ移動した。

electron 12へ移行するための対応の一部。

(移行作業としてはelectron11で移行作業をしてから12にアップデートするつもり)。


``` エラーメッセージ

 Uncaught ReferenceError: Menu is not defined
```


 



 

Menuはmein-processでいじるものになっていた模様。

ApplicationMenuカスタム処理をmain-processへ移動した(electron 12対応)

を参照 。

 

main-processのindex.jsの先頭付近に移動した。

```

  7 require(path.join(__dirname, 'main-process/application-menu.js'))¬
  8 require(path.join(__dirname, 'main-process/context-menu.js'))

```

 electron-api-demosでは`  Menu.setApplicationMenu()`はコールバックに仕込んでいたが、コンテキストメニューではしていないので、踏襲してそのまま呼び出しで済ませることにした。

```

 10 const {Menu, MenuItem, app, ipcMain} = require('electron')¬
 11 let menu = new Menu();¬
 12 ¬
 13 menu.append(new MenuItem({¬
 14 >-------label: 'Copy',¬
 15 >-------accelerator: 'CmdOrCtrl+C',¬
 16 >-------role: 'copy'¬
 17 }));¬

 ```

 

またコンテキストメニュー表示のコールバックも、 renderer-processでしていたのをelectron-api-demosの通りにmain-processへ移した。

rendererとmain-processでイベント が違う。

Before:

``` (renderer-process)

 11 >------->-------window.addEventListener('contextmenu', function (e) {¬
 12 >------->------->-------e.preventDefault();¬
 13 >------->------->-------menu.popup(remote.getCurrentWindow());¬
 14 >------->-------}, false);¬

```

After: 'main-process/application-menu.js'(main-process)
 ```

app.on('browser-window-created', (event, win) => {
  win.webContents.on('context-menu', (e, params) => {
    menu.popup(win, params.x, params.y)
  })
})

ipcMain.on('show-context-menu', (event) => {
  const win = BrowserWindow.fromWebContents(event.sender)
  menu.popup(win)
})

```

 

 

 

ApplicationMenuのときと同じく、Rendererに持たせたmoduleを呼び出す機能は動作しない。

 

そちらは後でpreload.js, ipcRendererなどを使う方式へ移行する。

ApplicationMenuカスタム処理をmain-processへ移動した(electron 12対応)

ApplicationMenu(画面上部のメニューバー)カスタム処理をmain-processへ移動した。

electron 12へ移行するための対応の一部。

(移行作業としてはelectron11で移行作業をしてから12にアップデートするつもり)。


``` エラーメッセージ

 Uncaught ReferenceError: require is not defined
    at menu.js:3

```

```menu.js:3

const remote = require('electron').remote;

```

 


 

だが根本的にはMenuはmein-processでいじるものになっていた模様。

electron-api-demos ではそうしている。

```electron-api-demos main.js

function loadDemos () {
  const files = glob.sync(path.join(__dirname, 'main-process/**/*.js'))
  files.forEach((file) => { require(file) })
}

``` 

ただしこの時点でelectron-api-demosはelectron9を使っていた。

(いろいろ言いたいことはあるが略)


Before:

``` index.html

<script type="text/javascript" src="./js/menu.js"></script>

```

After:

```

 require(path.join(__dirname, 'js/menu.js'))

```

これだけでもMenuカスタムが動作するようになってしまう。

ようは`  Menu.setApplicationMenu()`を呼んでしまえばOKのようだが、electron-api-demosではコールバックに仕込むことをオススメしている模様。

```

app.on('ready', () => {
  const menu = Menu.buildFromTemplate(template) // テンプレートを変数に格納
  Menu.setApplicationMenu(menu)
})

```


これをすることで、Menuカスタムは動作するし、Quit(App.quit()呼び出し)などは動作するが、Rendererに持たせたmoduleを呼び出す機能は動作しない。

 

そちらは後でpreload.js, ipcRendererなどを使う方式へ移行するとして、とりあえず次は右クリックのContextMenu。

Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換する

 Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換することができるが、上手く変換されない場合がある。   以前作った魔法陣イラスト素材をイラスト素材ストックサイトへ登録しようと思い立ち、改めて素材用にラスタライズ変換をかけようとした。   ラスタライズ変換...