1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Need to include this before any other file because it defines
6 // IPC_MESSAGE_LOG_ENABLED. We need to use it to define
7 // IPC_MESSAGE_MACROS_LOG_ENABLED so that all_messages.h will generate the
8 // ViewMsgLog et al. functions.
9 #include "ipc/ipc_message.h"
11 #ifdef IPC_MESSAGE_LOG_ENABLED
12 #include "content/public/common/content_ipc_logging.h"
13 #define IPC_MESSAGE_MACROS_LOG_ENABLED
14 #define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
15 content::RegisterIPCLogger(msg_id, logger)
17 // We need to do this real early to be sure IPC_MESSAGE_MACROS_LOG_ENABLED
18 // doesn't get undefined.
19 #include "chrome/common/all_messages.h"
21 #include "chrome/browser/ui/views/about_ipc_dialog.h"
25 #include "base/memory/singleton.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/threading/thread.h"
29 #include "base/time/time.h"
30 #include "chrome/app/chrome_command_ids.h"
31 #include "chrome/app/chrome_dll_resource.h"
32 #include "chrome/browser/ui/browser_dialogs.h"
33 #include "chrome/common/chrome_constants.h"
34 #include "content/public/browser/browser_ipc_logging.h"
35 #include "net/url_request/url_request.h"
36 #include "net/url_request/url_request_job.h"
37 #include "ui/views/controls/button/label_button.h"
38 #include "ui/views/controls/native/native_view_host.h"
39 #include "ui/views/layout/grid_layout.h"
40 #include "ui/views/layout/layout_constants.h"
41 #include "ui/views/widget/widget.h"
45 // We don't localize this UI since this is a developer-only feature.
46 const wchar_t kStartTrackingLabel
[] = L
"Start tracking";
47 const wchar_t kStopTrackingLabel
[] = L
"Stop tracking";
48 const wchar_t kClearLabel
[] = L
"Clear";
49 const wchar_t kFilterLabel
[] = L
"Filter...";
61 // The singleton dialog box. This is non-NULL when a dialog is active so we
62 // know not to create a new one.
63 AboutIPCDialog
* g_dialog
= NULL
;
65 std::set
<int> disabled_messages
;
67 // Settings dialog -------------------------------------------------------------
69 bool init_done
= false;
70 HWND settings_dialog
= NULL
;
72 CListViewCtrl
* messages
= NULL
;
74 void OnCheck(int id
, bool checked
) {
79 disabled_messages
.erase(id
);
81 disabled_messages
.insert(id
);
84 void InitDialog(HWND hwnd
) {
85 messages
= new CListViewCtrl(::GetDlgItem(hwnd
, IDC_Messages
));
87 messages
->SetViewType(LVS_REPORT
);
88 messages
->SetExtendedListViewStyle(LVS_EX_CHECKBOXES
);
89 messages
->ModifyStyle(0, LVS_SORTASCENDING
| LVS_NOCOLUMNHEADER
);
90 messages
->InsertColumn(0, L
"id", LVCFMT_LEFT
, 230);
92 LogFunctionMap
* log_functions
= IPC::Logging::log_function_map();
93 for (LogFunctionMap::iterator
i(log_functions
->begin());
94 i
!= log_functions
->end(); ++i
) {
96 (*i
->second
)(&name
, NULL
, NULL
);
98 continue; // Will happen if the message file isn't included above.
99 std::wstring wname
= base::UTF8ToWide(name
);
101 int index
= messages
->InsertItem(
102 LVIF_TEXT
| LVIF_PARAM
, 0, wname
.c_str(), 0, 0, 0, i
->first
);
104 messages
->SetItemText(index
, 0, wname
.c_str());
106 if (disabled_messages
.find(i
->first
) == disabled_messages
.end())
107 messages
->SetCheckState(index
, TRUE
);
119 ::DestroyWindow(settings_dialog
);
120 settings_dialog
= NULL
;
122 /* The old version of this code stored the last settings in the preferences.
123 But with this dialog, there currently isn't an easy way to get the profile
124 to save in the preferences.
125 Profile* current_profile = profile();
126 if (!current_profile)
128 PrefService* prefs = current_profile->GetPrefs();
129 if (!prefs->FindPreference(prefs::kIpcDisabledMessages))
131 base::ListValue* list = prefs->GetMutableList(prefs::kIpcDisabledMessages);
133 for (std::set<int>::const_iterator itr = disabled_messages_.begin();
134 itr != disabled_messages_.end();
136 list->Append(new base::FundamentalValue(*itr));
141 void OnButtonClick(int id
) {
142 int count
= messages
->GetItemCount();
143 for (int i
= 0; i
< count
; ++i
)
144 messages
->SetCheckState(i
, id
== IDC_MessagesAll
);
147 INT_PTR CALLBACK
DialogProc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
) {
151 return FALSE
; // Don't set keyboard focus.
153 if (wparam
== SC_CLOSE
) {
159 NMLISTVIEW
* info
= reinterpret_cast<NM_LISTVIEW
*>(lparam
);
160 if (wparam
== IDC_Messages
&& info
->hdr
.code
== LVN_ITEMCHANGED
) {
161 if (info
->uChanged
& LVIF_STATE
) {
162 bool checked
= (info
->uNewState
>> 12) == 2;
163 OnCheck(static_cast<int>(info
->lParam
), checked
);
170 if (HIWORD(wparam
) == BN_CLICKED
)
171 OnButtonClick(LOWORD(wparam
));
177 void RunSettingsDialog(HWND parent
) {
180 HINSTANCE module_handle
= GetModuleHandle(chrome::kBrowserResourcesDll
);
181 settings_dialog
= CreateDialog(module_handle
,
182 MAKEINTRESOURCE(IDD_IPC_SETTINGS
),
185 ::ShowWindow(settings_dialog
, SW_SHOW
);
190 // AboutIPCDialog --------------------------------------------------------------
192 AboutIPCDialog::AboutIPCDialog()
193 : track_toggle_(NULL
),
195 filter_button_(NULL
),
199 IPC::Logging::GetInstance()->SetConsumer(this);
202 AboutIPCDialog::~AboutIPCDialog() {
204 IPC::Logging::GetInstance()->SetConsumer(NULL
);
208 void AboutIPCDialog::RunDialog() {
210 g_dialog
= new AboutIPCDialog
;
211 views::DialogDelegate::CreateDialogWidget(g_dialog
, NULL
, NULL
)->Show();
213 // TODO(brettw) it would be nice to focus the existing window.
217 void AboutIPCDialog::SetupControls() {
218 views::GridLayout
* layout
= views::GridLayout::CreatePanel(this);
219 SetLayoutManager(layout
);
221 track_toggle_
= new views::LabelButton(this, kStartTrackingLabel
);
222 clear_button_
= new views::LabelButton(this, kClearLabel
);
223 filter_button_
= new views::LabelButton(this, kFilterLabel
);
225 table_
= new views::NativeViewHost
;
227 static const int first_column_set
= 1;
228 views::ColumnSet
* column_set
= layout
->AddColumnSet(first_column_set
);
229 column_set
->AddColumn(views::GridLayout::CENTER
, views::GridLayout::CENTER
,
230 33.33f
, views::GridLayout::FIXED
, 0, 0);
231 column_set
->AddColumn(views::GridLayout::CENTER
, views::GridLayout::CENTER
,
232 33.33f
, views::GridLayout::FIXED
, 0, 0);
233 column_set
->AddColumn(views::GridLayout::CENTER
, views::GridLayout::CENTER
,
234 33.33f
, views::GridLayout::FIXED
, 0, 0);
236 static const int table_column_set
= 2;
237 column_set
= layout
->AddColumnSet(table_column_set
);
238 column_set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
,
239 100.0f
, views::GridLayout::FIXED
, 0, 0);
241 layout
->StartRow(0, first_column_set
);
242 layout
->AddView(track_toggle_
);
243 layout
->AddView(clear_button_
);
244 layout
->AddView(filter_button_
);
245 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
246 layout
->StartRow(1.0f
, table_column_set
);
247 layout
->AddView(table_
);
250 gfx::Size
AboutIPCDialog::GetPreferredSize() {
251 return gfx::Size(800, 400);
254 int AboutIPCDialog::GetDialogButtons() const {
255 return ui::DIALOG_BUTTON_NONE
;
258 base::string16
AboutIPCDialog::GetWindowTitle() const {
259 return base::ASCIIToUTF16("about:ipc");
262 void AboutIPCDialog::Layout() {
263 if (!message_list_
.m_hWnd
) {
264 HWND parent_window
= GetWidget()->GetNativeView();
266 RECT rect
= {0, 0, 10, 10};
267 HWND list_hwnd
= message_list_
.Create(parent_window
,
268 rect
, NULL
, WS_CHILD
| WS_VISIBLE
| LVS_SORTASCENDING
);
269 message_list_
.SetViewType(LVS_REPORT
);
270 message_list_
.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT
);
272 int column_index
= 0;
273 message_list_
.InsertColumn(kTimeColumn
, L
"time", LVCFMT_LEFT
, 80);
274 message_list_
.InsertColumn(kChannelColumn
, L
"channel", LVCFMT_LEFT
, 110);
275 message_list_
.InsertColumn(kMessageColumn
, L
"message", LVCFMT_LEFT
, 240);
276 message_list_
.InsertColumn(kFlagsColumn
, L
"flags", LVCFMT_LEFT
, 50);
277 message_list_
.InsertColumn(kDispatchColumn
, L
"dispatch (ms)", LVCFMT_RIGHT
,
279 message_list_
.InsertColumn(kProcessColumn
, L
"process (ms)", LVCFMT_RIGHT
,
281 message_list_
.InsertColumn(kParamsColumn
, L
"parameters", LVCFMT_LEFT
, 500);
283 table_
->Attach(list_hwnd
);
289 void AboutIPCDialog::Log(const IPC::LogData
& data
) {
290 if (disabled_messages
.find(data
.type
) != disabled_messages
.end())
291 return; // Message type is filtered out.
293 base::Time sent
= base::Time::FromInternalValue(data
.sent
);
294 base::Time::Exploded exploded
;
295 sent
.LocalExplode(&exploded
);
296 if (exploded
.hour
> 12)
299 std::wstring sent_str
= base::StringPrintf(L
"%02d:%02d:%02d.%03d",
300 exploded
.hour
, exploded
.minute
, exploded
.second
, exploded
.millisecond
);
302 int count
= message_list_
.GetItemCount();
303 int index
= message_list_
.InsertItem(count
, sent_str
.c_str());
305 message_list_
.SetItemText(index
, kTimeColumn
, sent_str
.c_str());
306 message_list_
.SetItemText(index
, kChannelColumn
,
307 base::ASCIIToWide(data
.channel
).c_str());
309 std::string message_name
;
310 IPC::Logging::GetMessageText(data
.type
, &message_name
, NULL
, NULL
);
311 message_list_
.SetItemText(index
, kMessageColumn
,
312 base::UTF8ToWide(message_name
).c_str());
313 message_list_
.SetItemText(index
, kFlagsColumn
,
314 base::UTF8ToWide(data
.flags
).c_str());
316 int64 time_to_send
= (base::Time::FromInternalValue(data
.receive
) -
317 sent
).InMilliseconds();
318 // time can go backwards by a few ms (see Time), don't show that.
319 time_to_send
= std::max(static_cast<int>(time_to_send
), 0);
320 std::wstring temp
= base::StringPrintf(L
"%d", time_to_send
);
321 message_list_
.SetItemText(index
, kDispatchColumn
, temp
.c_str());
323 int64 time_to_process
= (base::Time::FromInternalValue(data
.dispatch
) -
324 base::Time::FromInternalValue(data
.receive
)).InMilliseconds();
325 time_to_process
= std::max(static_cast<int>(time_to_process
), 0);
326 temp
= base::StringPrintf(L
"%d", time_to_process
);
327 message_list_
.SetItemText(index
, kProcessColumn
, temp
.c_str());
329 message_list_
.SetItemText(index
, kParamsColumn
,
330 base::UTF8ToWide(data
.params
).c_str());
331 message_list_
.EnsureVisible(index
, FALSE
);
334 bool AboutIPCDialog::CanResize() const {
338 bool AboutIPCDialog::UseNewStyleForThisDialog() const {
342 void AboutIPCDialog::ButtonPressed(
343 views::Button
* button
, const ui::Event
& event
) {
344 if (button
== track_toggle_
) {
346 track_toggle_
->SetText(kStartTrackingLabel
);
348 content::EnableIPCLogging(false);
350 track_toggle_
->SetText(kStopTrackingLabel
);
352 content::EnableIPCLogging(true);
354 track_toggle_
->SchedulePaint();
355 } else if (button
== clear_button_
) {
356 message_list_
.DeleteAllItems();
357 } else if (button
== filter_button_
) {
358 RunSettingsDialog(GetWidget()->GetNativeView());
364 void ShowAboutIPCDialog() {
365 AboutIPCDialog::RunDialog();
368 } // namespace chrome
370 #endif // IPC_MESSAGE_LOG_ENABLED