Chromiumを手探る
思いつき
シークレットウィンドウって便利ですよね。
でもあれなんでウィンドウしかないんでしょうね。タブごとにモード切り替えとかできたら便利だろうに。
ということで、chrome code searchを用いてソースを探って弄って、chromiumにそんな機能を搭載してみようじゃないか、という初心者の無謀なチャレンジです。1
(GDBとかでデバッグしようとしたり、XCodeで追っかけたりしようかと思ったが無理だった。XCodeに至ってはなぜかbuildもできなかった。つらい)
codeをひたすら追ってみる
まずは「とりあえずwindowかtabをopenするのに関連してる関数を見つけてそれを追っていけばなんか見つかるやろ」作戦です。2 いやいやこれがつらいのなんのその。
適当に "new_window command" とかで検索かけると/src/chrome/app/chrome_command_ids.h L.31
からそれっぽいものが見つかりました。
// Window management commands #define IDC_NEW_WINDOW 34000 #define IDC_NEW_INCOGNITO_WINDOW 34001
/src/chrome/browser/app_controller_mac.mm L.1046
から
switch (tag) { case IDC_NEW_TAB: // Create a new tab in an existing browser window (which we activate) if // possible. if (Browser* browser = ActivateBrowser(lastProfile)) { chrome::ExecuteCommand(browser, IDC_NEW_TAB); break; } FALLTHROUGH; // To create new window. case IDC_NEW_WINDOW: CreateBrowser(lastProfile); break;
まずはTABについて見てみます。
ActivateBrowser(lastProfile) について/src/chrome/browser/app_controller_mac.mm L.138
にて
Browser* ActivateBrowser(Profile* profile) { Browser* browser = chrome::FindLastActiveWithProfile( profile->IsGuestSession() ? profile->GetOffTheRecordProfile() : profile); if (browser) browser->window()->Activate(); return browser; }
ExecuteCommand(browser, IDC_NEW_TAB) について/src/chrome/browser/ui/browser_commands.cc L.336
にて
bool ExecuteCommand(Browser* browser, int command) { return browser->command_controller()->ExecuteCommand(command); }
command_updater_impl.h
のL.34に
// Overriden from CommandUpdater:
とあったので見てみると、L.40にて
bool CommandUpdaterImpl::ExecuteCommand(int id) { return ExecuteCommandWithDisposition(id, WindowOpenDisposition::CURRENT_TAB); }
ExecuteCommandWithDisposition(id, WindowOpenDisposition::CURRENT_TAB)
について
/src/chrome/browser/ui/browser_command_controller.cc L.288
にて
bool BrowserCommandController::ExecuteCommandWithDisposition( int id, WindowOpenDisposition disposition) {
すると同じソースにswitch(id)
から
L.340
// Window management commands case IDC_NEW_WINDOW: NewWindow(browser_); break; case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(browser_); break;
とか
L.351
case IDC_NEW_TAB: { NewTab(browser_);
を発見。ようやくそれらしいものを見つけました。
おそらくbrowser_
というのはWindowOpenDisposition disposition
で指定されたWindowOpenDispositonの二個上のclass(?)を表しているっぽいですね。
とりあえずWindowについて、/src/chrome/browser/ui/browser_commands.cc L.576
にて
void NewWindow(Browser* browser) { NewEmptyWindow(browser->profile()->GetOriginalProfile()); }
"NewEmptyWindow"で検索をかけると/src/chrome/browser/ui/browser_commands.cc L.382
にて
void NewEmptyWindow(Profile* profile) { bool incognito = profile->IsOffTheRecord(); PrefService* prefs = profile->GetPrefs(); if (incognito) { if (IncognitoModePrefs::GetAvailability(prefs) == IncognitoModePrefs::DISABLED) { incognito = false; } } else if (profile->IsGuestSession() || (browser_defaults::kAlwaysOpenIncognitoWindow && IncognitoModePrefs::ShouldLaunchIncognito( *base::CommandLine::ForCurrentProcess(), prefs))) { incognito = true; } if (incognito) { base::RecordAction(UserMetricsAction("NewIncognitoWindow")); OpenEmptyWindow(profile->GetOffTheRecordProfile()); } else { base::RecordAction(UserMetricsAction("NewWindow")); SessionService* session_service = SessionServiceFactory::GetForProfileForSessionRestore( profile->GetOriginalProfile()); if (!session_service || !session_service->RestoreIfNecessary(std::vector<GURL>())) { OpenEmptyWindow(profile->GetOriginalProfile()); } } } Browser* OpenEmptyWindow(Profile* profile) { Browser* browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile, true)); AddTabAt(browser, GURL(), -1, true); browser->window()->Show(); return browser; }
これやん。やったぜ。 この枠組みをopen tabみたいなところに流用すればいいのでは? ということで今度はtabの方を見てみます。
"NewTab"で検索をかけると、すこし関係なさそうではあるのですが、いろんなタブの開き方をまとめているような感じのソースを見つけました。(上の方にAddTabTypes
とか書いてる)
/src/chrome/browser/ui/tabs/tab_strip_model.h L.101
にて
// Enumerates different ways to open a new tab. Does not apply to opening // existing links or searches in a new tab, only to brand new empty tabs. enum NewTab { // New tab was opened using the new tab button on the tab strip. NEW_TAB_BUTTON, // New tab was opened using the menu command - either through the keyboard // shortcut, or by opening the menu and selecting the command. Applies to // both app menu and the menu bar's File menu (on platforms that have one). NEW_TAB_COMMAND, // New tab was opened through the context menu on the tab strip. NEW_TAB_CONTEXT_MENU, // Number of enum entries, used for UMA histogram reporting macros. NEW_TAB_ENUM_COUNT, };
同様に検索すると/src/chrome/browser/ui/browser_commands.cc L. 594
にて
void NewTab(Browser* browser) { base::RecordAction(UserMetricsAction("NewTab")); // TODO(asvitkine): This is invoked programmatically from several places. // Audit the code and change it so that the histogram only gets collected for // user-initiated commands. UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND, TabStripModel::NEW_TAB_ENUM_COUNT); if (browser->is_type_tabbed()) { AddTabAt(browser, GURL(), -1, true); browser->tab_strip_model()->GetActiveWebContents()->RestoreFocus(); } else { ScopedTabbedBrowserDisplayer displayer(browser->profile()); Browser* b = displayer.browser(); AddTabAt(b, GURL(), -1, true); b->window()->Show(); // The call to AddBlankTabAt above did not set the focus to the tab as its // window was not active, so we have to do it explicitly. // See http://crbug.com/6380. b->tab_strip_model()->GetActiveWebContents()->RestoreFocus(); } }
共通なのはAddTabAt()
なのでここを見ればいいのかも?
とりあえず現時点の動作としては、
・windowを開くときにincognitoかどうか判断
→profileを決定 (GetOffTheRecordProfile()かGetOriginalProfile()か)
→OpenEmptyWindowの中でBrowser *browser
を決定 (引数にprofileあり)
→AddTabAt(browser, GURL(), -1, true)でTabが作られてshow();で多分Tabが表示
・tabを開くときはprofileがwindowと違いprofileについてincognitoかどうか判定がない →なぜならwindowを開く時点(NewEmptyWindow())でincognitoの値を決定しているから →ならばtabを開くときにNewEmptyTab()みたいな関数を入れてincognitoの判定をtab作成のステップに移せばいけるのでは
まとめ
ソースを見る限り意外と実装は簡単そう...? だが現実はそんな甘くないんだろうな、と想像しつつ次回へ続きます。
-
実は大学の後期実験 大規模ソフトウェアを手探る だったりします。↩