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。

Blenderの Apply Modifier ボタン/Apply All Modifierメニュー がなくなった( blender 2.93.5 )

 手元の2.93.5で、Blenderから"Apply Modifier"ボタンが無くなっていました。 同じく手元にある中では、2.90.1では存在しているので、最近(?)なくなったようです。 https://blender.stackexchange.com...