chromiumのタブをいじる(2)

この記事は東京大学電子情報工学科3年の後期実験である「大規模ソフトウェアを手探る」で行われた班活動を記事にしたものです．
以下の記事の続きになっています．
[chromiumのタブをいじる(１)][1]
(1)でのアクティブタブを拡大する機能の有効/無効を切り替えるショートカットを作成した記事です。

[1]:https://qiita.com/kons_9/items/9a9e3bf268a6e97f7e5a

## 実行環境
Ubuntu 18.04.5 (LTS)


## ソースコードを眺める
[ソースコードを検索できるサイト](https://source.chromium.org/)を用いて、ショートカットに関わる機能がどこに実装されているのかを探していく。

まず、先輩の記事
https://doss-gitlab.eidos.ic.i.u-tokyo.ac.jp/sneeze/chromium/-/wikis/doss-4-Sneeze-%E6%9C%80%E7%B5%82%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88
を参考に、ショートカットが定義されている場所を発見した。

[chrome/browser/ui/views/accelerator_table.cc:27](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/views/accelerator_table.cc;l=27)

```cpp:accelerator_table.cc
const AcceleratorMapping kAcceleratorMap[] = {
...
    {ui::VKEY_TAB, ui::EF_CONTROL_DOWN, IDC_SELECT_NEXT_TAB},
    {ui::VKEY_NEXT, ui::EF_CONTROL_DOWN, IDC_SELECT_NEXT_TAB},
    {ui::VKEY_TAB, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
     IDC_SELECT_PREVIOUS_TAB},
    {ui::VKEY_PRIOR, ui::EF_CONTROL_DOWN, IDC_SELECT_PREVIOUS_TAB},
...
}
```
こんなかんじで、ショートカットが定義されている。（例えば、Tab + Ctrl で次のタブを選択。) 

機能に割り当てられた変数名は、以下で定義されている。
[chrome/app/chrome_command_ids.h](https://source.chromium.org/chromium/chromium/src/+/master:chrome/app/chrome_command_ids.h)

```cpp:chrome_command_ids.h
...
#define IDC_NEW_TAB                     34014
#define IDC_CLOSE_TAB                   34015
#define IDC_SELECT_NEXT_TAB             34016
#define IDC_SELECT_PREVIOUS_TAB         34017
...
```


そして、実際にコマンドが入力された時、コマンドの種類によって処理を振り分けている関数も発見した。
[chrome/browser/ui/browser_command_controller.cc:334](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/browser_command_controller.cc;l=334)
ExecuteCommandWithDisposition関数内を見てみると、chrome_command_ids.hで定義されたidによって、switch文で処理を振り分けている様子が分かる。

```cpp:browser_command_controller.cc
bool BrowserCommandController::ExecuteCommandWithDisposition(
    int id,
    WindowOpenDisposition disposition,
    base::TimeTicks time_stamp){
...

  switch (id) {

...

    case IDC_NEW_TAB: {
      NewTab(browser_);
      break;
    }
    case IDC_CLOSE_TAB:
      base::RecordAction(base::UserMetricsAction("CloseTabByKey"));
      CloseTab(browser_);
      break;
    case IDC_SELECT_NEXT_TAB:
      base::RecordAction(base::UserMetricsAction("Accel_SelectNextTab"));
      SelectNextTab(browser_,
                    {TabStripModel::GestureType::kKeyboard, time_stamp});
      break;
    case IDC_SELECT_PREVIOUS_TAB:
      base::RecordAction(base::UserMetricsAction("Accel_SelectPreviousTab"));
      SelectPreviousTab(browser_,
                        {TabStripModel::GestureType::kKeyboard, time_stamp});
      break;
    
...

}
```

## 変更
以上で注目してきた３つのファイルに、新たにコマンドを追加すべく、書き込んでいく。

accelerator_table.ccには、kAcceleratorMap内に、

```cpp:accelerator_table.cc
    {ui::VKEY_Q , ui::EF_PLATFORM_ACCELERATOR, IDC_CHANGE_ACTIVE_TAB_WIDTH}
```
の要素を追加した。ここで、Ctrl+Qでコマンド発動するよう定義している。(Ctrl+Qにしたのは他のコマンドと被らないようにするため。)

chrome_command_ids.h では、上で用いている IDC_CHANGE_ACTIVE_TAB_WIDTH を、

```cpp:chrome_command_ids.h
#define IDC_CHANGE_ACTIVE_TAB_WIDTH    34050
```

このように定義した。(34050という数字は適当に空き番号を探した。)

browser_command_controller.ccにも、新たなcaseを追加する。
その前にまずは、[chromiumのタブをいじる(１)][1]で眺めた、Tabの幅を管理している TabStripLayoutHelper クラスの中に、アクティブタブ拡大機能のオンオフを切り替えるためのフラグを作っておく。

[tab_strip_layout_helper.h](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/views/tabs/tab_strip_layout_helper.h;l=33)の、publicのメンバ変数に、静的メンバ変数としてフラグを作っておく。今回はフラグの名前をhoge にした。

```cpp:tab_strip_layout_helper.h
class TabStripLayoutHelper {
 public:
...
  static bool hoge;
...
};
```
そして、[tab_strip_layout_helper.cc](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/views/tabs/tab_strip_layout_helper.cc)内の適当なグローバルの位置で、hogeを初期化する。

```cpp:tab_strip_layout_helper.cc
bool TabStripLayoutHelper::hoge = false;
```

[chromiumのタブをいじる(１)][1]で眺めた、[TabStripLayoutHelper::UpdateIdealBounds()](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/views/tabs/tab_strip_layout_helper.cc;l=242)
の関数内では、hoge がtrue のときだけ、[chromiumのタブをいじる(１)][1]で作ったTabStripLayoutHelper::myCaluculateIdealBoundsでboundsを更新するようにすれば良い。


そしていよいよbrowser_command_controller.ccにも、新たなcaseを追加する。
先ほどのフラグが参照できるよう、browser_command_controller.ccの先頭で、tab_strip_layout_helper.ccをインクルードする。

```cpp:browser_command_controller.cc
#include "chrome/browser/ui/views/tabs/tab_strip_layout_helper.h"
```
そして、ExecuteCommandWithDispositionに新たにcaseを追加して、フラグを反転させた。

```cpp:browser_command_controller.cc
case IDC_CHANGE_ACTIVE_TAB_WIDTH:
      TabStripLayoutHelper::hoge = !TabStripLayoutHelper::hoge;
      break;
```

##ビルドして実行
ビルドは成功した。しかし出てきたChromiumのウィンドウでCtrl+Qを押しても、アクティブタブの広さが変わらない。なぜなのか？

##原因と解決策
原因追及すべく、[chrome/browser/ui/browser_command_controller.cc:334](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/browser_command_controller.cc;l=334)にブレークポイントをおいて、gdbで追跡してみると、[chrome/browser/ui/browser_command_controller.cc:343](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/browser_command_controller.cc;l=343)において、

```cpp:browser_command_controller.cc
  if (!SupportsCommand(id) || !IsCommandEnabled(id))
    return false;
```
で、SupportsCommand(id)がfalseを返しているためにExecuteCommandWithDisposition関数が終了していることが判明した。

SupportsCommand(id)は、[chrome/browser/ui/views/accelerator_table.h](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/command_updater_impl.cc;l=29;drc=929e790ad17a54008b3dac86cbe30751c968c2ce)で、commands_というmapの中から引数のidをkeyに持つコマンドがfindされればtrueを返すことが分かる。

コマンドを追加し、Enableにする関数[UpdateCommandEnabled](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/command_updater_impl.cc;drc=929e790ad17a54008b3dac86cbe30751c968c2ce;l=73)を班員が発見してくれた。UpdateCommandEnabled は[GetCommand](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/command_updater_impl.cc;drc=929e790ad17a54008b3dac86cbe30751c968c2ce;bpv=0;bpt=1;l=96)関数を呼び出している。Getcommand関数内では、idで指定されたコマンドがSupportsCommand(id)でfalseの場合は、command_のmapに新しい要素を追加する。

したがって、browser_command_controller.cc内の、BrowserCommandController::InitCommandState()内に、次のように追加した。

```cpp:browser_command_controller.cc
  command_updater_.UpdateCommandEnabled(IDC_CHANGE_ACTIVE_TAB_WIDTH,true);
```

これでビルドすると、無事コマンドが有効になっており、ショートカットでアクティブタブの拡大を切替できるようになった。

##感想
終始班員に助けられました。本当に感謝しています。

##別のテーマ

直近でactiveになったタブn個を大きくする。
[chromiumのタブをいじる(3)](https://qiita.com/momorrow/items/dc2a1611dfcbea51e56b)

グループ機能、ピン留め昨日のバグを取り除く。
[chromiumのタブをいじる(4)](https://qiita.com/kons_9/items/8e972449dbc9efa6d35f)