git のキソのキソ 2
おはようございます。今日は寝坊してしまいました...
早起きを習慣化していきたいのですが、前日の夜にこなすタスクがしっかりあるとなかなか難しいですね。
(あと朝起きた時、尋常じゃないほど鬱なのどうにかしたい)
では、前回に引き続き git についてお話ししていきたいと思います!
リポジトリ
前回、git のホスティングサービスを利用してオンライン上に他の人と共有できるディレクトリを作成できることをお話ししたと思います。
この「他の人と共有できるディレクトリ」という表現は、実は間違っているんですよね 笑
どういうことか説明していきたいと思います。
ディレクトリとリポジトリ
そもそも git というのは、少し難しい表現にはなってしまいますが一言でいうと、「分散型バージョン管理システム」です。
どういうことかというと、サーバに Git というアクセスできるデータベースが一つある、というわけではなくて、サーバにも各々のPCにもデータベースが存在している、ということです。
ここでいうデータベースとは、ソースコードなど全てのデータのバージョンを管理・保持しているものを指します。1
データベースが貯蓄されているのが文字通り「リポジトリ」であり、当然のことながら「ディレクトリ」とは全く別物です。 ( 筆者はこのことの理解をせずに git を使おうとしてはうまく行かず失敗ばかりしてました )
ここで、サーバにある Git というデータベースのことを「リモートリポジトリ」、各々のPCにある Git というデータベースを「ローカルリポジトリ」と呼びます。
実際の動き
ではどのようにデータがリポジトリに記録されていくのか、仕組みを簡単に説明します。実際に使うコマンドも記載しておきますね。
例えばあるプロジェクトに参加することになり、そのバージョンが git で管理されていたとします。
まずはそのリモートのリポジトリを自分のPCにコピーしてローカルリポジトリを作成します。
コマンド: git clone (リモートリポジトリのurl)
そこには今までにあった変更が全て記載されているので、もちろん自分のPCには今のディレクトリに、そのプロジェクトで作成されたデータと隠しディレクトリとして .git ファイルが存在します。
そのデータに自分が変更を加えたなら、ローカルリポジトリに変更した内容を書き加えます。
コマンド: git add (変更したファイル)
2
さらにリモートリポジトリにその変更を書き加える前に、その変更についてのコメントを書き加えます。
コマンド: git commit -m "こんな変更をしました"
ここまでしたらリモートに push したいところですが、筆者はその前にコンフリクトを起こさない為にも、先にリモートリポジトリの変更をローカルリポジトリに書き加えます。
コマンド: git pull origin master
これが全て確認できてから、リモートに push します。
コマンド: git push -u origin master
まとめ
これが git のキソのキソだと思います。これさえ分かっておけば、とりあえずは困らないかと。
正直これより先の git の基礎の内容は自分もまだ勉強中なので、理解し次第 git シリーズとしてまとめていきたいですね!
参考
git のキソのキソ 1
おはようございます!
身につけるためにも文章力を磨くためにもタイプ速度あげるためにも、少しでも学んだことがあれば記事を書いていこうと思いました。
Qiitaではないので何番煎じになろうとも自分のアウトプットのために書いていくのでご了承ください 笑
git
タイトルにもある通り、今日は git の使い方についてお話ししたいと思います。
とはいっても自分もこの前初めて触ったばっかりなのであまり詳しくはないのですが、理解したことだけつらつらと述べていきます。
git とは
git というのはご存知の方も多いと思いますが、あるプロジェクトのバージョン管理をしたいときに主に用いられる、オンライン上のディレクトリのようなものです。
どういうことかというと、 ・自分の作成したデータをオンライン上のディレクトリにあげる ↓ ・同じチームの人がそのディレクトリからそのデータを自分のPCまで引っ張ってくる ↓ ・またその人が作成したデータをオンライン上のディレクトリにあげる ↓ ・・・ このように、他の人とディレクトリを共有しながらプロジェクトを進めていける素晴らしい機能です!
git のサーバー
git はオンライン上でデータのやり取りをするので、そのためには専用のサーバが必要になります。
ただサーバーを立てるのって管理とか面倒ですよね。
ということで存在するのが git のホスティングサイトです。有名なやつですと、例えば GitHub とかですね。
こうしたホスティングサイトのサービスを利用することで、容易にプロジェクトを立ち上げられサーバの管理もしなくてすみます。
ただしサービスごとに利点・欠点は存在するらしいので気をつけましょう! (正直、git 初学者には長所短所なんてわからないのです)
今日はここまでにします。この程度の執筆に30分かかるので、根気よくコツコツやっていきたいと思います。笑
参考
atom-beautify のショートカットキーが使えない
自分は基本エディタにAtomを使用しているのですが、自力でインデントとか綺麗にするの超めんどくさい...
ということで atom-beautify を入れてみることにしました。
atom-beautify のinstall
普通に Atom エディタの設定から Install を選択。" atom-beautify " で検索すれば出てきます。
ショートカットキーの設定
毎回 Packages->Atom Beautify->Beautify から実行するのも面倒なのでショートカットキーを調べてみたら、Macでも「Control + alt (option) + b」で実行可能とのこと。 いざやってみると
" Could Not Find ' Uncrustify ' . The Program May Not Be Installed. "
と言われてしまいました。
なので、
brew install uncrustify
で Uncrustify をインストールしましたが、ここから何をすればいいのかなかなか分かりませんでした。
(ちなむと Mac の場合、Finder で不可視ファイルを表示するのは「Command + Shift + . 」で出来ます。)
install した uncrustify をどこのディレクトリに置けばいいのか問題
はじめは/usr/local/Celler/
に uncrustify というディレクトリができていたので、これを/Users/(username)/.atom/packages
とかに移動させては「違うなぁ」ということを繰り返してました。
調べたら Windows の場合にのみ、展開して得た uncrustify.exe を packages 下に置かなければならないだけで Mac だと何も触らなくていいみたいですね。この原理はちょっとまだ分かっていないのでそのうちちゃんと調べたいです。
uncrustify の config 設定問題
どうやら Uncrustify はインストールするだけじゃなく、詳細なconfigを書いた uncrustify.cfg を用意して、Atom の Settings -> Packages -> Atom Beautify からそれぞれの言語に対して絶対パスを通す必要があるそうです。(自分は絶対パスの記入でタイポしていて無駄に悩んでいました笑)
自分の場合は/Users/(username)/
下に/.uncrustify/uncrustify.cfg
を作成しました。
config の内容は以下の記事を参考にさせていただきました。
ただ Uncrustify もアップデートされているようで、Uncrustify の default config をみてみると、上記のサイトに掲載されている設定に一部誤りが含まれていたので、以下に自分の変更点をまとめておきます。
・align_number_left を align_number_right に変更 ・L.314, L.338, L.597のコメントアウトに対して日本語であるせいかエラーが吐かれているので適当に改行 ・L.485 D言語のテンプレート sp_before_template_paren が { number } になっていたので { ignore, add, remove, force } に変更 (自分は ignore を選びました) ・ mod_full_brace_if_chain = false の下に mod_full_brace_if_chain_only = false を挿入 ・sp_func_call_user_paren = remove の下に sp_func_call_user_inside_fparen = ignore, sp_func_call_user_paren_paren = ignore の挿入
下二つは必要なかったかもしれませんが、default config にあってこちらになかったのを発見してしまったので一応追加しておきました。
まとめ
以上で atom-beautify とそのショートカットキーの導入が完了しました。 情弱すぎてこの実装にさえ一時間ほどかかってしまったのでちょっと悲しいです...笑 しかし、これからは快適な Atom 生活でどんどん強くなっていきたいですね!
自分のように困っている方の助けになれば幸いです。
参考
・Macのショートカットキー - 不可視ファイルの表示/非表示を切り替える - PC設定のカルマ ・atomにatom-beautifyを入れた時にハマったこと | one more step ・意識の高さからかコードフォーマッター設定を公開 ・PATHを通すために環境変数の設定を理解する (Mac OS X) ・Atomエディタでatom-beautifyを使ってPHPのソースコードを整形する(追記あり) - そうだ車輪と名づけよう 7th ・http://uncrustify.sourceforge.net/default.cfg
Chromiumを手探る 3
この記事は前回からの連載(?)です。よろしければそちらから。
タブがシークレットモードで開かなかった原因
前回設定した関数 NewEmptyTab() の中で
void NewEmptyTab(Browser* browser, Profile* profile){ // incognitoとbrowser->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; }
つまり、おそらく NewIncognitoTab() が呼ばれる ↓ profile->IsOffTheRecord() なので incognito = true になる ↓ IncognitoModePrefs::GetAvailability(prefs) == IncognitoModePrefs::DISABLED なので incognito = false になってしまう ↓ 普通のタブが開く という挙動になってしまったのが原因だと考えました。
てかわざわざこんなことしなくても SetProfile() って関数作って NewTab() と NewIncognitoTab() の中で profile をセットすればいいだけじゃね?と思ってしまいました。実はこれは相方のアイデアなのですが、潔く丸パクリすることにしました。決断力。
改装
NewTab() と NewIncognitoTab() は以下のようにコードを変えました。(大事だと思ったので丸々載せますが基本元のNewTab()と構成は一緒です)
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); browser->SetProfile(browser->profile()->GetOriginalProfile()); 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(); } } void NewIncognitoTab(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); browser->SetProfile(browser->profile()->GetOffTheRecordProfile()); 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(); } }
そして browser.h
には
class Browser : public TabStripModelObserver, ・・・ { public : ・・・ // Accessors //////////////////////////////////////////////////////////////// ・・・ void SetProfile(Profile* profile) { profile_ = profile; } ・・・ }
さらに、タブによってprofileを変えるために browser.h
内の Profile* const profile_;
から const
を削除して Profile* profile_;
にしました。
また、よくよくみていくと tab_activity_watcher.cc
にて
namespace resource_coordinator { class TabActivityWatcher::WebContentsData : public content::WebContentsObserver, public content::WebContentsUserData<WebContentsData>, public content::RenderWidgetHost::InputEventObserver { ・・・ private : explicit WebContentsData(content::WebContents* web_contents) : WebContentsObserver(web_contents) { DCHECK(!web_contents->GetBrowserContext()->IsOffTheRecord()); tab_metrics_.web_contents = web_contents; web_contents->GetRenderViewHost()->GetWidget()->AddInputEventObserver(this); ・・・ } ・・・ } }
と DCHECK で OffTheRecord() のチェックが入ってしまっているので、この一行を削除しました。
結果
画像ではわかりにくいですが無事実装できました!!
やっぱりひとまずとはいえ完成すると嬉しいですね!w
課題
実は先ほどの画像の状態で、もう一度元のタブに戻った時の画像がこちらなのですが、なんか変ですよね...?
おそらくこのタブを開いた時は browser->profile() が GetOriginalProfile() だったのに、新しいシークレットタブを開いたせいで profile が GetOffTheRecordProfile() になってしまっているせいで、なんらかのコンフリクトが生じてしまっています。
この画像のタブで検索をしてみても新しいタブが開かれてしまうんですよね...
選択するタブを切り替える時の動作を追うことができればそこでまた profile を変更するようにすれば良いと思うのですが、残念ながら講義時間中ではそこまで追いきれませんでした。1
後は見てお気づきかとは思いますが GUI やショートカットキーの割り当てですね。画像ではショートカットキーが割り当てられているような雰囲気を醸していますがこれはハリボテで押しても何も反応しませんw
相方は Linux で行なっていたのでキーの割り当てが比較的簡単にできていそうでしたが、macOS は何か特殊らしくよくわからなかったですね。時間を見つけてまた取り組みたいところです。
感想
さて、初めてこんな複雑なプログラムに触れて見ましたが、意外とたのしかったです。なんというか、これを趣味にするのもわかる気がする。。。
自分はプログラミング完全初心者2で、特に c++ や java なんかは見たこともほとんどないレベルだったのですが、まあやっていくうちになんとなく読めてなんとなーく書けるようになっていきました。
なので初心者の方々も気軽に触ってみてはいかがでしょうか。
次回以降の演習で chromium を手探る方は無理ない程度に無理して頑張ってください!
Chromiumを手探る 2
前回に引き続き、chromiumにシークレットタブを導入することを目標に奮闘していきます。 記載忘れていましたが使用しているOSは macOS High Sierra です。
いざ実装
はじめに
今日のこの記事を読んで真似してみようとしてくださる方がもしいらっしゃるならば、必ず一度は最後まで目を通してからにしてください。
NewIncognitoTab() の追加
まずは Window について NewWindow(Browser* browser_);
NewIncognitoWindow(Browser* browser)
があるので、Tab についても同様にNewTab(Browser* browser_);
NewIncognitoTab(Browser* browser)
を追加して Window の構造を真似してみます。
/src/chrome/browser/ui/browser_commands.cc
に
void NewTab(Browser* browser){ NewEmptyTab(browser, browser->profile()->GetOriginalProfile()); } void NewIncognitoTab(Browser* browser){ // よくわからないフラグなのでコピーだけしておく #if 0 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP) feature_engagement::IncognitoWindowTrackerFactory::GetInstance() ->GetForProfile(browser->profile()) ->OnIncognitoWindowOpened(); #endif #endif NewEmptyTab(browser, browser->profile()->GetOffTheRecordProfile()); } void NewEmptyTab(Browser* browser, Profile* profile){ // incognitoとbrowser->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("NewIncognitoTab")); // 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.NewIncognitoTab", TabStripModel::NEW_TAB_COMMAND, TabStripModel::NEW_TAB_ENUM_COUNT); SetTabProfile(profile()->GetOffTheRecordProfile()); 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(); } }else{ 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); SessionService* session_service = SessionServiceFactory::GetForProfileForSessionRestore(profile->GetOriginalProfile()); if (!session_service || !session_service->RestoreIfNecessary(std::vector<GURL>())) { SetTabProfile(profile()->GetOriginalProfile()); 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(); } } } } Browser* SetTabProfile(Profile* profile) { Browser* browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile, true)); return browser; }
当然ヘッダーにも新しく作った関数を入れておきます。
これで後はシークレットタブを開くGUIやらショートカットーキーを用意すれば大丈夫だとこの時は信じていました。
Chromiumのメニューにボタンを追加
chrome_command_ids.h
に大量のIDC_...
が定義されているので
#define IDC_NEW_INCOGNITO_TAB 34002
を追加。 ここからは chrome code search で IDC_NEW_TAB を検索してヒットしたところを全部読んで必要な関数とかをどんどん追記していきます。(以下長くなります)
browser_command_controller.cc
に
bool BrowserCommandController::IsReservedCommandOrKey( int command_id, const content::NativeWebKeyboardEvent& event) { ・・・ return command_id == IDC_CLOSE_TAB || command_id == IDC_CLOSE_WINDOW || command_id == IDC_NEW_INCOGNITO_TAB || ・・・ }
や
bool BrowserCommandController::ExecuteCommandWithDisposition( int id, WindowOpenDisposition disposition) { ・・・ switch (id) { ・・・ case IDC_NEW_INCOGNITO_TAB: { NewIncognitoTab(browser_); #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP) // This is not in NewTab() to avoid tracking programmatic creation of new // tabs by extensions. auto* new_tab_tracker = feature_engagement::NewTabTrackerFactory::GetInstance() ->GetForProfile(profile()); new_tab_tracker->OnNewTabOpened(); new_tab_tracker->CloseBubble(); #endif break; }
void BrowserCommandController::InitCommandState() { ・・・ command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_TAB, true); ・・・ }
Cmd + Shift + T で新しいシークレットタブを開きたかったので accelerator.cc
に
namespace{ ・・・ const AcceleratorMapping kAcceleratorMap[] = { ・・・ #if 1 {ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_PLATFORM_ACCELERATOR, IDC_NEW_INCOGNITO_TAB}, #else {ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_PLATFORM_ACCELERATOR, IDC_RESTORE_TAB}, #endif ・・・ } ・・・ }
とし、タブ修復のキーを消す形にしました。
tab_strip_model.cc
に
// static bool TabStripModel::ContextMenuCommandToBrowserCommand(int cmd_id, int* browser_cmd) { switch (cmd_id) { case CommandNewTab: *browser_cmd = IDC_NEW_TAB; break; case CommandNewIncognitoTab: *browser_cmd = IDC_NEW_INCOGNITO_TAB; break; ・・・ } return true; }
ちゃんとヘッダーにも CommandNewIncognitoTab を追加しています。
app_menu_model.cc
に
void AppMenuModel::LogMenuMetrics(int command_id) { base::TimeDelta delta = timer_.Elapsed(); switch (command_id) { ・・・ case IDC_NEW_INCOGNITO_TAB: if (!uma_action_recorded_) { UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.NewIncognitoTab", delta); } LogMenuAction(MENU_ACTION_NEW_INCOGNITO_TAB); break; ・・・ } ・・・ }
void AppMenuModel::Build() { ・・・ if (ShouldShowNewIncognitoWindowMenuItem()){ AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW); AddItemWithStringId(IDC_NEW_INCOGNITO_TAB, IDS_NEW_INCOGNITO_TAB); } ・・・ }
MENU_ACTION_NEW_INCOGNITO_TAB を定義したいので、app_menu_model.h
に
enum AppMenuAction { ・・・ MENU_ACTION_NEW_INCOGNITO_TAB = 10, ・・・ }
を追加。
IDS_NEW_INCOGNITO_TAB を定義したいので、global_menu_bar_x11.cc
に
namespace{ ・・・ GlobalMenuBarCommand file_menu[] = { ・・・ { IDS_NEW_INCOGNITO_TAB, IDC_NEW_INCOGNITO_TAB }, ・・・ } ・・・ }
を追加。
system_menu_model_builder.cc
に
void SystemMenuModelBuilder::BuildSystemMenuForBrowserWindow( ui::SimpleMenuModel* model) { ・・・ model->AddItemWithStringId(IDC_NEW_INCOGNITO_TAB, IDS_NEW_INCOGNITO_TAB); ・・・ }
新しい定数が出てきたので startup_resources_mac.txt
に
IDS_NEW_INCOGNITO_TAB_MAC 366
を追加。
generated_resources.grd
に
・・・ <grit base_dir="." latest_public_release="0" current_release="1" output_all_resource_defines="false" source_lang_id="en" enc_check="möl"> <outputs> ・・・ <release seq="1" allow_pseudo="false"> <messages fallback_to_english="true"> ・・・ <if expr="not is_android"> <if expr="not use_titlecase"> ・・・ <message name="IDS_NEW_INCOGNITO_TAB" desc="The text label of a menu item for opening a new incognito tab"> New &incognito tab </message> ・・・ </if> <if expr="use_titlecase"> ・・・ <message name="IDS_NEW_INCOGNITO_TAB" desc="In Title Case: The text label of a menu item for opening a new incognito tab"> New &Incognito Tab </message> ・・・ </if> </if> ・・・ <if expr="is_macosx"> ・・・ <message name="IDS_NEW_INCOGNITO_TAB_MAC" desc="The Mac menu item for opening a new incognito tab in the file menu."> New Incognito Tab </message> ・・・ </if> ・・・ </messages> </release> </grit>
app_controller_mac.mm
に
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { ・・・ if (action == @selector(commandDispatch:) || action == @selector(commandFromDock:)) { ・・・ if (menuState_ && // NULL in tests. menuState_->SupportsCommand(tag)) { switch (tag) { ・・・ case IDC_NEW_INCOGNITO_TAB: ・・・ } } ・・・ } ・・・ } - (void)commandDispatch:(id)sender { ・・・ switch (tag) { ・・・ case IDC_NEW_INCOGNITO_TAB: // Create a new tab in an existing browser window (which we activate) if // possible. if (Browser* browser = ActivateBrowser(lastProfile->GetOffTheRecordProfile())) { chrome::ExecuteCommand(browser, IDC_NEW_INCOGNITO_TAB); break; } FALLTHROUGH; // To create new window. } }
- (void)initMenuState { menuState_ = std::make_unique<CommandUpdaterImpl>(nullptr); menuState_->UpdateCommandEnabled(IDC_NEW_TAB, true); menuState_->UpdateCommandEnabled(IDC_NEW_INCOGNITO_TAB, true); ・・・ }
cocoa とかいう macOS でしか使わなさそうなファイルの中にも aceelerator がいたので編集します。
accelerators_cocoa.mm
にて
namespace { const struct AcceleratorMapping { int command_id; int modifiers; // The ui::EventFlag modifiers ui::KeyboardCode key_code; // The key used for cross-platform compatibility. } kAcceleratorMap[] = { ・・・ #if 1 {IDC_NEW_INCOGNITO_TAB, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_T}, #else {IDC_RESTORE_TAB, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, ui::VKEY_T}, #endif ・・・ } ・・・ }
今度は NEW_TAB で当たってみました。
ash なので意味がないかもしれませんが、accelerators.h
に
namespace ash{ enum AcceleratorAction{ ・・・ NEW_INCOGNITO_TAB, ・・・ } }
accelerators.cc
に
namespace ash { const AcceleratorData kAcceleratorData[] = { ・・・ #if 1 {true, ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, NEW_INCOGNITO_TAB}, #else {true, ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, RESTORE_TAB}, #endif ・・・ } const size_t kAcceleratorDataLength = arraysize(kAcceleratorData); }
ビルドしてみたが...?
おそらく大体の変更が終了したのでひとまずビルドしてみることに。 1回目は上記の全てをきちんと行えていたわけではないので、出てくるエラーを修正しながら根性でビルドビルドビルド......
ついにビルドが終わった!!といって意気揚々と起動してみるわけですよ。 読者の方々は察していると思いますが、ね。。。
メニューには "New Incognito Tab" と表示されますが、クリックしても普通のタブが開かれてしまいます。 (スクショ撮り忘れたのでお見せできなくて申し訳ない)
果たして原因はなんなのでしょうか...次回へ続く。
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作成のステップに移せばいけるのでは
まとめ
ソースを見る限り意外と実装は簡単そう...? だが現実はそんな甘くないんだろうな、と想像しつつ次回へ続きます。
-
実は大学の後期実験 大規模ソフトウェアを手探る だったりします。↩