OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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. | |
4 | |
5 #include "chrome/browser/ui/views/apps/jumplist_updater_win.h" | |
6 | |
7 #include <propvarutil.h> | |
8 #include <shobjidl.h> | |
9 #include <windows.h> | |
10 // This include needs to go out of order to prevent compilation errors because | |
tapted
2014/02/12 10:16:28
It's actually pretty common to always ensure <wind
| |
11 // propidl.h does not check whether PID_FIRST_USABLE is already defined. | |
12 #include <propkey.h> | |
13 | |
14 #include "base/command_line.h" | |
15 #include "base/path_service.h" | |
16 #include "base/win/scoped_comptr.h" | |
17 #include "base/win/scoped_propvariant.h" | |
18 #include "base/win/windows_version.h" | |
19 #include "chrome/browser/profiles/profile.h" | |
20 #include "chrome/common/chrome_constants.h" | |
21 #include "chrome/common/chrome_switches.h" | |
22 | |
23 namespace { | |
24 | |
25 void AddShellLink(base::win::ScopedComPtr<IObjectCollection> collection, | |
26 const std::wstring& application, | |
27 const std::wstring& switches, | |
28 const JumpListUpdater::ListItem& list_item) { | |
29 base::win::ScopedComPtr<IShellLink> link; | |
30 HRESULT result = link.CreateInstance(CLSID_ShellLink, NULL, | |
31 CLSCTX_INPROC_SERVER); | |
32 if (FAILED(result)) | |
33 return; | |
34 | |
35 // Set the application path to invoke for each link. | |
36 result = link->SetPath(application.c_str()); | |
tapted
2014/02/12 10:16:28
( would become SetPath(command_line.GetProgram().v
| |
37 if (FAILED(result)) | |
38 return; | |
39 | |
40 // Set the command line args. | |
tapted
2014/02/12 10:16:28
And, e.g., I think this would be nicer if you coul
| |
41 std::wstring arguments(switches); | |
42 if (!list_item.command_line_args.empty()) { | |
43 arguments.push_back(L' '); | |
44 arguments += list_item.command_line_args; | |
45 } | |
46 if (!arguments.empty()) { | |
47 result = link->SetArguments(arguments.c_str()); | |
48 if (FAILED(result)) | |
49 return; | |
50 } | |
51 | |
52 // Set the icon. This can be allowed to fail. | |
53 if (!list_item.icon_path.empty()) | |
54 link->SetIconLocation(list_item.icon_path.value().c_str(), 0); | |
tapted
2014/02/12 10:16:28
This could potentially use chrome.exe, and just pr
| |
55 | |
56 // Set the title. This must be added as a property. | |
57 base::win::ScopedComPtr<IPropertyStore> property_store; | |
58 result = link.QueryInterface(property_store.Receive()); | |
59 if (FAILED(result)) | |
60 return; | |
61 | |
62 base::win::ScopedPropVariant property_title; | |
63 result = InitPropVariantFromString(list_item.title.c_str(), | |
tapted
2014/02/12 10:16:28
I'm a bit unfamiliar with this stuff, but can you
| |
64 property_title.Receive()); | |
65 if (FAILED(result)) | |
66 return; | |
67 | |
68 result = property_store->SetValue(PKEY_Title, property_title.get()); | |
69 if (FAILED(result)) | |
70 return; | |
71 | |
72 result = property_store->Commit(); | |
73 if (FAILED(result)) | |
74 return; | |
75 | |
76 // Add this IShellLink to the given collection. | |
77 collection->AddObject(link); | |
78 } | |
79 | |
80 void AddTasks(base::win::ScopedComPtr<ICustomDestinationList> jumplist, | |
81 const std::wstring& application, | |
82 const std::wstring& switches, | |
83 const std::vector<JumpListUpdater::ListItem>& items) { | |
84 // Create a collection to store items for the "Tasks" category of the | |
85 // jump list. | |
86 base::win::ScopedComPtr<IObjectCollection> collection; | |
87 HRESULT result = collection.CreateInstance(CLSID_EnumerableObjectCollection, | |
88 NULL, CLSCTX_INPROC_SERVER); | |
89 if (FAILED(result)) | |
90 return; | |
91 | |
92 // Add list items. | |
93 for (std::vector<JumpListUpdater::ListItem>::const_iterator it = | |
94 items.begin(); it != items.end(); ++it) { | |
95 AddShellLink(collection, application, switches, *it); | |
96 } | |
97 | |
98 // Cast to IObjectArray and update the jump list's "Tasks". | |
99 base::win::ScopedComPtr<IObjectArray> object_array; | |
100 result = collection.QueryInterface(object_array.Receive()); | |
101 if (FAILED(result)) | |
102 return; | |
103 | |
104 jumplist->AddUserTasks(object_array); | |
105 } | |
106 | |
107 } // namespace | |
108 | |
109 // static | |
110 void JumpListUpdater::AppendArgs(const std::string& switch_string, | |
111 const base::string16& value, | |
112 base::string16* command_line_args) { | |
113 DCHECK(command_line_args); | |
114 CommandLine command_line(CommandLine::NO_PROGRAM); | |
115 if (value.empty()) | |
116 command_line.AppendSwitch(switch_string); | |
117 else | |
118 command_line.AppendSwitchNative(switch_string, value); | |
119 | |
120 if (!command_line_args->empty()) | |
121 command_line_args->push_back(L' '); | |
122 *command_line_args += command_line.GetCommandLineString(); | |
123 } | |
124 | |
125 JumpListUpdater::JumpListUpdater( | |
126 Profile* profile, | |
127 const base::string16& app_user_model_id) | |
128 : profile_(profile), | |
129 app_user_model_id_(app_user_model_id) { | |
130 PathService::Get(base::FILE_EXE, &chrome_path_); | |
131 | |
132 // Set up common command line switches. | |
133 base::FilePath user_data_dir = CommandLine::ForCurrentProcess()-> | |
134 GetSwitchValuePath(switches::kUserDataDir); | |
tapted
2014/02/12 10:16:28
Do other things do it like this? It feels unreliab
| |
135 if (!user_data_dir.empty()) | |
tapted
2014/02/12 10:16:28
nit: curlies for multi-line if
| |
136 AppendArgs(switches::kUserDataDir, | |
137 user_data_dir.value(), | |
138 &default_chrome_switches_); | |
139 } | |
140 | |
141 JumpListUpdater::~JumpListUpdater() {} | |
142 | |
143 void JumpListUpdater::Update(const std::vector<ListItem>& items) { | |
144 // Check all the preconditions for creating a jump list. | |
145 if (chrome_path_.empty()) | |
146 return; | |
147 | |
148 if (base::win::GetVersion() < base::win::VERSION_WIN7) | |
149 return; | |
150 | |
151 // Create the jump list. | |
152 base::win::ScopedComPtr<ICustomDestinationList> jumplist; | |
153 HRESULT result = jumplist.CreateInstance(CLSID_DestinationList, NULL, | |
154 CLSCTX_INPROC_SERVER); | |
155 if (FAILED(result)) | |
156 return; | |
157 | |
158 // Associate the jump list with this application. | |
159 jumplist->SetAppID(app_user_model_id_.c_str()); | |
160 | |
161 // Start transaction to modify the jump list. | |
162 UINT max_slots; // unused | |
tapted
2014/02/12 10:16:28
nit: ` // Unused.` (with 2 spaces between code an
| |
163 base::win::ScopedComPtr<IObjectArray> removed; // unused | |
164 result = jumplist->BeginList(&max_slots, __uuidof(*removed), | |
165 reinterpret_cast<void**>(&removed)); | |
tapted
2014/02/12 10:16:28
would `removed.ReceiveVoid()` work here in place o
| |
166 if (FAILED(result)) | |
167 return; | |
168 | |
169 // Add items to the predefined "Tasks" category. | |
170 AddTasks(jumplist, | |
171 chrome_path_.value(), | |
172 default_chrome_switches_, | |
173 items); | |
174 | |
175 // Commit changes to the jump list. | |
176 jumplist->CommitList(); | |
177 } | |
OLD | NEW |