blob: c0b26402f89ac697057f4213807b4f648473bcca [file] [log] [blame]
[email protected]9e790bd2011-01-10 23:48:541// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]bac8784c2009-02-19 02:36:362// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Need to include this before any other file because it defines
6// IPC_MESSAGE_LOG_ENABLED. We need to use it to define
[email protected]8bf55ca2011-10-17 22:15:277// IPC_MESSAGE_MACROS_LOG_ENABLED so that all_messages.h will generate the
[email protected]bac8784c2009-02-19 02:36:368// ViewMsgLog et al. functions.
[email protected]946d1b22009-07-22 23:57:219#include "ipc/ipc_message.h"
[email protected]bac8784c2009-02-19 02:36:3610
11#ifdef IPC_MESSAGE_LOG_ENABLED
12#define IPC_MESSAGE_MACROS_LOG_ENABLED
13
[email protected]8bf55ca2011-10-17 22:15:2714// We need to do this real early to be sure IPC_MESSAGE_MACROS_LOG_ENABLED
15// doesn't get undefined.
16#include "chrome/common/all_messages.h"
17
[email protected]9e790bd2011-01-10 23:48:5418#include "chrome/browser/ui/views/about_ipc_dialog.h"
[email protected]bac8784c2009-02-19 02:36:3619
20#include <set>
21
22#include "base/string_util.h"
[email protected]34b99632011-01-01 01:01:0623#include "base/threading/thread.h"
[email protected]bac8784c2009-02-19 02:36:3624#include "base/time.h"
[email protected]be1ce6a72010-08-03 14:35:2225#include "base/utf_string_conversions.h"
[email protected]1a3aba82010-11-08 23:52:5426#include "chrome/app/chrome_command_ids.h"
[email protected]ac344c8a2010-11-09 01:24:3427#include "chrome/app/chrome_dll_resource.h"
[email protected]bac8784c2009-02-19 02:36:3628#include "chrome/browser/browser_process.h"
[email protected]c96531e82011-01-26 03:11:1429#include "chrome/browser/ui/browser_dialogs.h"
[email protected]bac8784c2009-02-19 02:36:3630#include "chrome/common/chrome_constants.h"
[email protected]bac8784c2009-02-19 02:36:3631#include "net/url_request/url_request.h"
32#include "net/url_request/url_request_job.h"
[email protected]2362e4f2009-05-08 00:34:0533#include "views/controls/button/text_button.h"
[email protected]17dee5e2009-05-29 06:02:1934#include "views/controls/native/native_view_host.h"
[email protected]9ef7d4b2011-01-27 02:17:2135#include "views/layout/grid_layout.h"
[email protected]5d8054ef2011-01-26 22:46:3636#include "views/layout/layout_constants.h"
[email protected]2362e4f2009-05-08 00:34:0537#include "views/widget/widget.h"
[email protected]bac8784c2009-02-19 02:36:3638
39namespace {
40
41// We don't localize this UI since this is a developer-only feature.
42const wchar_t kStartTrackingLabel[] = L"Start tracking";
43const wchar_t kStopTrackingLabel[] = L"Stop tracking";
44const wchar_t kClearLabel[] = L"Clear";
45const wchar_t kFilterLabel[] = L"Filter...";
46
47enum {
48 kTimeColumn = 0,
49 kChannelColumn,
50 kMessageColumn,
51 kFlagsColumn,
52 kDispatchColumn,
53 kProcessColumn,
54 kParamsColumn,
55};
56
57// This class registers the browser IPC logger functions with IPC::Logging.
58class RegisterLoggerFuncs {
59 public:
60 RegisterLoggerFuncs() {
[email protected]21fa3a12010-12-08 23:34:1661 IPC::Logging::set_log_function_map(&g_log_function_mapping);
[email protected]bac8784c2009-02-19 02:36:3662 }
63};
64
65RegisterLoggerFuncs g_register_logger_funcs;
66
67// The singleton dialog box. This is non-NULL when a dialog is active so we
68// know not to create a new one.
[email protected]c96531e82011-01-26 03:11:1469AboutIPCDialog* g_active_dialog = NULL;
[email protected]bac8784c2009-02-19 02:36:3670
71std::set<int> disabled_messages;
72
73// Settings dialog -------------------------------------------------------------
74
75bool init_done = false;
76HWND settings_dialog = NULL;
[email protected]21fa3a12010-12-08 23:34:1677// Settings.
78CListViewCtrl* messages = NULL;
[email protected]bac8784c2009-02-19 02:36:3679
80void OnCheck(int id, bool checked) {
81 if (!init_done)
82 return;
83
84 if (checked)
85 disabled_messages.erase(id);
86 else
87 disabled_messages.insert(id);
88}
89
[email protected]bac8784c2009-02-19 02:36:3690void InitDialog(HWND hwnd) {
[email protected]21fa3a12010-12-08 23:34:1691 messages = new CListViewCtrl(::GetDlgItem(hwnd, IDC_Messages));
92
93 messages->SetViewType(LVS_REPORT);
94 messages->SetExtendedListViewStyle(LVS_EX_CHECKBOXES);
95 messages->ModifyStyle(0, LVS_SORTASCENDING | LVS_NOCOLUMNHEADER);
96 messages->InsertColumn(0, L"id", LVCFMT_LEFT, 230);
97
98 LogFunctionMap* log_functions = IPC::Logging::log_function_map();
99 for (LogFunctionMap::iterator i = log_functions->begin();
100 i != log_functions->end(); ++i) {
101 std::string name;
102 (*i->second)(&name, NULL, NULL);
103 if (name.empty())
104 continue; // Will happen if the message file isn't included above.
105 std::wstring wname = UTF8ToWide(name);
106
107 int index = messages->InsertItem(
108 LVIF_TEXT | LVIF_PARAM, 0, wname.c_str(), 0, 0, 0, i->first);
109
110 messages->SetItemText(index, 0, wname.c_str());
111
112 if (disabled_messages.find(i->first) == disabled_messages.end())
113 messages->SetCheckState(index, TRUE);
114 }
115
[email protected]bac8784c2009-02-19 02:36:36116 init_done = true;
117}
118
119void CloseDialog() {
[email protected]21fa3a12010-12-08 23:34:16120 delete messages;
121 messages = NULL;
[email protected]bac8784c2009-02-19 02:36:36122
123 init_done = false;
124
125 ::DestroyWindow(settings_dialog);
126 settings_dialog = NULL;
127
128 /* The old version of this code stored the last settings in the preferences.
129 But with this dialog, there currently isn't an easy way to get the profile
[email protected]21fa3a12010-12-08 23:34:16130 to save in the preferences.
[email protected]bac8784c2009-02-19 02:36:36131 Profile* current_profile = profile();
132 if (!current_profile)
133 return;
134 PrefService* prefs = current_profile->GetPrefs();
[email protected]da6ce5602009-12-07 23:09:32135 if (!prefs->FindPreference(prefs::kIpcDisabledMessages))
[email protected]bac8784c2009-02-19 02:36:36136 return;
137 ListValue* list = prefs->GetMutableList(prefs::kIpcDisabledMessages);
138 list->Clear();
139 for (std::set<int>::const_iterator itr = disabled_messages_.begin();
140 itr != disabled_messages_.end();
141 ++itr) {
142 list->Append(Value::CreateIntegerValue(*itr));
143 }
144 */
145}
146
147void OnButtonClick(int id) {
[email protected]21fa3a12010-12-08 23:34:16148 int count = messages->GetItemCount();
149 for (int i = 0; i < count; ++i)
150 messages->SetCheckState(i, id == IDC_MessagesAll);
[email protected]bac8784c2009-02-19 02:36:36151}
152
153INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
154 switch (msg) {
155 case WM_INITDIALOG:
156 InitDialog(hwnd);
157 return FALSE; // Don't set keyboard focus.
158 case WM_SYSCOMMAND:
159 if (wparam == SC_CLOSE) {
160 CloseDialog();
161 return FALSE;
162 }
163 break;
164 case WM_NOTIFY: {
165 NMLISTVIEW* info = reinterpret_cast<NM_LISTVIEW*>(lparam);
[email protected]21fa3a12010-12-08 23:34:16166 if (wparam == IDC_Messages && info->hdr.code == LVN_ITEMCHANGED) {
[email protected]bac8784c2009-02-19 02:36:36167 if (info->uChanged & LVIF_STATE) {
168 bool checked = (info->uNewState >> 12) == 2;
169 OnCheck(static_cast<int>(info->lParam), checked);
170 }
171 return FALSE;
172 }
173 break;
174 }
175 case WM_COMMAND:
176 if (HIWORD(wparam) == BN_CLICKED)
177 OnButtonClick(LOWORD(wparam));
178 break;
179 }
180 return FALSE;
181}
182
183void RunSettingsDialog(HWND parent) {
184 if (settings_dialog)
185 return;
186 HINSTANCE module_handle = GetModuleHandle(chrome::kBrowserResourcesDll);
187 settings_dialog = CreateDialog(module_handle,
188 MAKEINTRESOURCE(IDD_IPC_SETTINGS),
189 NULL,
190 &DialogProc);
191 ::ShowWindow(settings_dialog, SW_SHOW);
192}
193
194} // namespace
195
196// AboutIPCDialog --------------------------------------------------------------
197
198AboutIPCDialog::AboutIPCDialog()
199 : track_toggle_(NULL),
200 clear_button_(NULL),
201 filter_button_(NULL),
202 table_(NULL),
203 tracking_(false) {
204 SetupControls();
[email protected]8e8bb6d2010-12-13 08:18:55205 IPC::Logging::GetInstance()->SetConsumer(this);
[email protected]bac8784c2009-02-19 02:36:36206}
207
208AboutIPCDialog::~AboutIPCDialog() {
[email protected]c96531e82011-01-26 03:11:14209 g_active_dialog = NULL;
[email protected]8e8bb6d2010-12-13 08:18:55210 IPC::Logging::GetInstance()->SetConsumer(NULL);
[email protected]bac8784c2009-02-19 02:36:36211}
212
213// static
214void AboutIPCDialog::RunDialog() {
[email protected]c96531e82011-01-26 03:11:14215 if (!g_active_dialog) {
216 g_active_dialog = new AboutIPCDialog;
[email protected]2fdd00a2011-06-13 21:56:26217 views::Widget::CreateWindow(g_active_dialog)->Show();
[email protected]bac8784c2009-02-19 02:36:36218 } else {
[email protected]c144a322011-04-26 18:09:03219 // TODO(brettw) it would be nice to focus the existing window.
[email protected]bac8784c2009-02-19 02:36:36220 }
221}
222
223void AboutIPCDialog::SetupControls() {
[email protected]8d0f8002011-01-21 12:52:29224 views::GridLayout* layout = views::GridLayout::CreatePanel(this);
[email protected]bac8784c2009-02-19 02:36:36225 SetLayoutManager(layout);
226
[email protected]48c8fa62009-03-16 23:25:13227 track_toggle_ = new views::TextButton(this, kStartTrackingLabel);
228 clear_button_ = new views::TextButton(this, kClearLabel);
229 filter_button_ = new views::TextButton(this, kFilterLabel);
[email protected]bac8784c2009-02-19 02:36:36230
[email protected]17dee5e2009-05-29 06:02:19231 table_ = new views::NativeViewHost;
[email protected]bac8784c2009-02-19 02:36:36232
233 static const int first_column_set = 1;
234 views::ColumnSet* column_set = layout->AddColumnSet(first_column_set);
235 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
236 33.33f, views::GridLayout::FIXED, 0, 0);
237 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
238 33.33f, views::GridLayout::FIXED, 0, 0);
239 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
240 33.33f, views::GridLayout::FIXED, 0, 0);
241
242 static const int table_column_set = 2;
243 column_set = layout->AddColumnSet(table_column_set);
244 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
245 100.0f, views::GridLayout::FIXED, 0, 0);
246
247 layout->StartRow(0, first_column_set);
248 layout->AddView(track_toggle_);
249 layout->AddView(clear_button_);
250 layout->AddView(filter_button_);
[email protected]11d62932011-02-10 23:41:42251 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
[email protected]bac8784c2009-02-19 02:36:36252 layout->StartRow(1.0f, table_column_set);
253 layout->AddView(table_);
254}
255
256gfx::Size AboutIPCDialog::GetPreferredSize() {
257 return gfx::Size(800, 400);
258}
259
260views::View* AboutIPCDialog::GetContentsView() {
261 return this;
262}
263
264int AboutIPCDialog::GetDialogButtons() const {
265 // Don't want OK or Cancel.
266 return 0;
267}
268
[email protected]956b3d32011-09-28 09:38:48269string16 AboutIPCDialog::GetWindowTitle() const {
270 return ASCIIToUTF16("about:ipc");
[email protected]bac8784c2009-02-19 02:36:36271}
272
273void AboutIPCDialog::Layout() {
274 if (!message_list_.m_hWnd) {
[email protected]10946072011-05-20 15:40:45275 HWND parent_window = GetWidget()->GetNativeView();
[email protected]bac8784c2009-02-19 02:36:36276
[email protected]ffe88f72009-09-04 20:55:11277 RECT rect = {0, 0, 10, 10};
[email protected]bac8784c2009-02-19 02:36:36278 HWND list_hwnd = message_list_.Create(parent_window,
279 rect, NULL, WS_CHILD | WS_VISIBLE | LVS_SORTASCENDING);
280 message_list_.SetViewType(LVS_REPORT);
281 message_list_.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
282
283 int column_index = 0;
284 message_list_.InsertColumn(kTimeColumn, L"time", LVCFMT_LEFT, 80);
285 message_list_.InsertColumn(kChannelColumn, L"channel", LVCFMT_LEFT, 110);
286 message_list_.InsertColumn(kMessageColumn, L"message", LVCFMT_LEFT, 240);
287 message_list_.InsertColumn(kFlagsColumn, L"flags", LVCFMT_LEFT, 50);
288 message_list_.InsertColumn(kDispatchColumn, L"dispatch (ms)", LVCFMT_RIGHT,
289 80);
290 message_list_.InsertColumn(kProcessColumn, L"process (ms)", LVCFMT_RIGHT,
291 80);
292 message_list_.InsertColumn(kParamsColumn, L"parameters", LVCFMT_LEFT, 500);
293
294 table_->Attach(list_hwnd);
295 }
296
297 View::Layout();
298}
299
300void AboutIPCDialog::Log(const IPC::LogData& data) {
301 if (disabled_messages.find(data.type) != disabled_messages.end())
302 return; // Message type is filtered out.
303
304 base::Time sent = base::Time::FromInternalValue(data.sent);
305 base::Time::Exploded exploded;
306 sent.LocalExplode(&exploded);
307 if (exploded.hour > 12)
308 exploded.hour -= 12;
309
310 std::wstring sent_str = StringPrintf(L"%02d:%02d:%02d.%03d",
311 exploded.hour, exploded.minute, exploded.second, exploded.millisecond);
312
313 int count = message_list_.GetItemCount();
314 int index = message_list_.InsertItem(count, sent_str.c_str());
315
316 message_list_.SetItemText(index, kTimeColumn, sent_str.c_str());
[email protected]9a3a293b2009-06-04 22:28:16317 message_list_.SetItemText(index, kChannelColumn,
318 ASCIIToWide(data.channel).c_str());
[email protected]bac8784c2009-02-19 02:36:36319
[email protected]252cad62010-08-18 18:33:57320 std::string message_name;
[email protected]bac8784c2009-02-19 02:36:36321 IPC::Logging::GetMessageText(data.type, &message_name, NULL, NULL);
[email protected]252cad62010-08-18 18:33:57322 message_list_.SetItemText(index, kMessageColumn,
323 UTF8ToWide(message_name).c_str());
324 message_list_.SetItemText(index, kFlagsColumn,
325 UTF8ToWide(data.flags).c_str());
[email protected]bac8784c2009-02-19 02:36:36326
327 int64 time_to_send = (base::Time::FromInternalValue(data.receive) -
328 sent).InMilliseconds();
329 // time can go backwards by a few ms (see Time), don't show that.
330 time_to_send = std::max(static_cast<int>(time_to_send), 0);
331 std::wstring temp = StringPrintf(L"%d", time_to_send);
332 message_list_.SetItemText(index, kDispatchColumn, temp.c_str());
333
334 int64 time_to_process = (base::Time::FromInternalValue(data.dispatch) -
335 base::Time::FromInternalValue(data.receive)).InMilliseconds();
336 time_to_process = std::max(static_cast<int>(time_to_process), 0);
337 temp = StringPrintf(L"%d", time_to_process);
338 message_list_.SetItemText(index, kProcessColumn, temp.c_str());
339
[email protected]252cad62010-08-18 18:33:57340 message_list_.SetItemText(index, kParamsColumn,
341 UTF8ToWide(data.params).c_str());
[email protected]bac8784c2009-02-19 02:36:36342 message_list_.EnsureVisible(index, FALSE);
343}
344
345bool AboutIPCDialog::CanResize() const {
346 return true;
347}
348
[email protected]a071e652009-09-03 20:58:01349void AboutIPCDialog::ButtonPressed(
350 views::Button* button, const views::Event& event) {
[email protected]bac8784c2009-02-19 02:36:36351 if (button == track_toggle_) {
352 if (tracking_) {
353 track_toggle_->SetText(kStartTrackingLabel);
354 tracking_ = false;
[email protected]d55aaa132009-09-28 21:08:04355 g_browser_process->SetIPCLoggingEnabled(false);
[email protected]bac8784c2009-02-19 02:36:36356 } else {
357 track_toggle_->SetText(kStopTrackingLabel);
358 tracking_ = true;
[email protected]d55aaa132009-09-28 21:08:04359 g_browser_process->SetIPCLoggingEnabled(true);
[email protected]bac8784c2009-02-19 02:36:36360 }
361 track_toggle_->SchedulePaint();
362 } else if (button == clear_button_) {
363 message_list_.DeleteAllItems();
364 } else if (button == filter_button_) {
[email protected]10946072011-05-20 15:40:45365 RunSettingsDialog(GetWidget()->GetNativeView());
[email protected]bac8784c2009-02-19 02:36:36366 }
367}
368
[email protected]c96531e82011-01-26 03:11:14369namespace browser {
370
371void ShowAboutIPCDialog() {
372 AboutIPCDialog::RunDialog();
373}
374
375} // namespace browser
376
[email protected]f0a51fb52009-03-05 12:46:38377#endif // IPC_MESSAGE_LOG_ENABLED