~ubuntu-branches/ubuntu/karmic/gears/karmic

« back to all changes in this revision

Viewing changes to gears/desktop/desktop_cr.cc

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Lesicnik
  • Date: 2009-04-30 19:15:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090430191525-0790sb5wzg8ou0xb
Tags: upstream-0.5.21.0~svn3334+dfsg
ImportĀ upstreamĀ versionĀ 0.5.21.0~svn3334+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2008, Google Inc.
 
2
//
 
3
// Redistribution and use in source and binary forms, with or without 
 
4
// modification, are permitted provided that the following conditions are met:
 
5
//
 
6
//  1. Redistributions of source code must retain the above copyright notice, 
 
7
//     this list of conditions and the following disclaimer.
 
8
//  2. Redistributions in binary form must reproduce the above copyright notice,
 
9
//     this list of conditions and the following disclaimer in the documentation
 
10
//     and/or other materials provided with the distribution.
 
11
//  3. Neither the name of Google Inc. nor the names of its contributors may be
 
12
//     used to endorse or promote products derived from this software without
 
13
//     specific prior written permission.
 
14
//
 
15
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
16
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
20
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
21
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
22
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 
 
26
#include "gears/desktop/desktop_cr.h"
 
27
 
 
28
#include "gears/base/chrome/browsing_context_cr.h"
 
29
#include "gears/base/chrome/module_cr.h"
 
30
#include "gears/base/common/paths.h"
 
31
#include "gears/base/common/string_utils.h"
 
32
#include "gears/desktop/desktop.h"
 
33
#include "gears/ui/common/html_dialog.h"
 
34
 
 
35
// We keep track of the set of URLs that have open shortcuts dialogs, so we
 
36
// don't open 2 at once.
 
37
static std::set<std::string16> *g_open_shortcuts_dialogs;
 
38
 
 
39
static void RegisterOpenDialog(const std::string16 &url) {
 
40
  if (!g_open_shortcuts_dialogs)
 
41
    g_open_shortcuts_dialogs = new std::set<std::string16>;
 
42
  g_open_shortcuts_dialogs->insert(url);
 
43
}
 
44
 
 
45
static void UnregisterOpenDialog(const std::string16 &url) {
 
46
  assert(g_open_shortcuts_dialogs);
 
47
  g_open_shortcuts_dialogs->erase(url);
 
48
  if (g_open_shortcuts_dialogs->empty()) {
 
49
    delete g_open_shortcuts_dialogs;
 
50
    g_open_shortcuts_dialogs = NULL;
 
51
  }
 
52
}
 
53
 
 
54
// Like UTF8ToString16, but treats NULL as "".
 
55
static bool MaybeUTF8ToString16(const char *in, std::string16 *out) {
 
56
  return in == NULL || UTF8ToString16(in, out);
 
57
}
 
58
 
 
59
// Handles the results of the async icon fetch.  It relies on
 
60
// ModelessShortcutsDialog to manage its lifetime.
 
61
class ShortcutIconHandler : public Desktop::IconHandlerInterface {
 
62
 public:
 
63
  ShortcutIconHandler(ModelessShortcutsDialog *shortcut_dialog,
 
64
                      int index)
 
65
      : shortcut_dialog_(shortcut_dialog),
 
66
        index_(index),
 
67
        abort_interface_(NULL) {
 
68
    assert(0 <= index_ && index_ < 4);
 
69
  }
 
70
 
 
71
  ~ShortcutIconHandler() {
 
72
    Abort();
 
73
  }
 
74
 
 
75
  virtual void ProcessIcon(bool success,
 
76
                           const std::string16 &icon_error) {
 
77
    // TODO(mpcomplete): handle error?
 
78
    // Specifically when !success.
 
79
    shortcut_dialog_->IconRequestFinished(index_);
 
80
  }
 
81
 
 
82
  virtual Desktop::IconData *mutable_icon() {
 
83
    switch (index_) {
 
84
      case 0:
 
85
        return &shortcut_dialog_->shortcut_info_.icon16x16;
 
86
      case 1:
 
87
        return &shortcut_dialog_->shortcut_info_.icon32x32;
 
88
      case 2:
 
89
        return &shortcut_dialog_->shortcut_info_.icon48x48;
 
90
      case 3:
 
91
        return &shortcut_dialog_->shortcut_info_.icon128x128;
 
92
    }
 
93
    return NULL;
 
94
  }
 
95
 
 
96
  virtual void set_abort_interface(Desktop::AbortInterface *abort_interface) {
 
97
    abort_interface_ = abort_interface;
 
98
  }
 
99
 
 
100
  bool Abort() {
 
101
    if (!abort_interface_) {
 
102
      return true;
 
103
    }
 
104
    return abort_interface_->Abort();
 
105
  }
 
106
 
 
107
 private:
 
108
  ModelessShortcutsDialog *shortcut_dialog_;
 
109
  int index_;
 
110
  Desktop::AbortInterface *abort_interface_;
 
111
  DISALLOW_EVIL_CONSTRUCTORS(ShortcutIconHandler);
 
112
};
 
113
 
 
114
// Simply here so that ShortcutIconHandler can be forward
 
115
// declared in the header file.
 
116
ModelessShortcutsDialog::ModelessShortcutsDialog(CPBrowsingContext context)
 
117
    : browsing_context_(context), results_ready_(false),
 
118
      shortcut_data_(NULL) {
 
119
}
 
120
 
 
121
ModelessShortcutsDialog::~ModelessShortcutsDialog() {
 
122
}
 
123
 
 
124
static void ResultsReadyCallback(Json::Value *result, void *closure) {
 
125
  ModelessShortcutsDialog* dialog =
 
126
      static_cast<ModelessShortcutsDialog *>(closure);
 
127
  dialog->ResultsReady();
 
128
}
 
129
 
 
130
bool ModelessShortcutsDialog::ShowDialog(GearsShortcutData2 *shortcut_data) {
 
131
  const char* name = CP_GET_MINOR_VERSION(CP::version()) >= 6 ?
 
132
      shortcut_data->orig_name : shortcut_data->name;
 
133
  if (!UTF8ToString16(name, &shortcut_info_.app_name) ||
 
134
      !UTF8ToString16(shortcut_data->url, &shortcut_info_.app_url) ||
 
135
      !MaybeUTF8ToString16(shortcut_data->icons[0].url,
 
136
                           &shortcut_info_.icon16x16.url) ||
 
137
      !MaybeUTF8ToString16(shortcut_data->icons[1].url,
 
138
                           &shortcut_info_.icon32x32.url) ||
 
139
      !MaybeUTF8ToString16(shortcut_data->icons[2].url,
 
140
                           &shortcut_info_.icon48x48.url) ||
 
141
      !MaybeUTF8ToString16(shortcut_data->icons[3].url,
 
142
                           &shortcut_info_.icon128x128.url) ||
 
143
      !MaybeUTF8ToString16(shortcut_data->description,
 
144
                           &shortcut_info_.app_description)) {
 
145
    return false;
 
146
  }
 
147
 
 
148
  // Make sure we pass validation on the shortcut name.
 
149
  EnsureStringValidPathComponent(shortcut_info_.app_name, false);
 
150
  if (shortcut_info_.app_name.length() > kUserPathComponentMaxChars)
 
151
    shortcut_info_.app_name.resize(kUserPathComponentMaxChars);
 
152
 
 
153
  // Only allow one dialog for this URL.
 
154
  if (g_open_shortcuts_dialogs &&
 
155
      g_open_shortcuts_dialogs->find(shortcut_info_.app_url) !=
 
156
          g_open_shortcuts_dialogs->end())
 
157
    return false;
 
158
 
 
159
  SecurityOrigin security_origin;
 
160
  if (!security_origin.InitFromUrl(shortcut_info_.app_url.c_str()))
 
161
    return false;
 
162
 
 
163
  // TODO(mpcomplete): We'll probably want to override behavior if the
 
164
  // shortcut exists - ie, show an edit dialog.
 
165
  // TODO(mpcomplete): The browsing_context Chrome gives us here is an HWND.
 
166
  // We need to associate it with an URLRequestContext.
 
167
  scoped_refptr<CRBrowsingContext> cr_context(
 
168
      new CRBrowsingContext(browsing_context_));
 
169
  desktop_.reset(new Desktop(security_origin, cr_context.get()));
 
170
  dialog_.reset(new HtmlDialog(cr_context.get()));
 
171
 
 
172
  const int kShortcutsDialogWidth = 360;
 
173
  const int kShortcutsDialogHeight = 240;
 
174
 
 
175
  if (!desktop_->ValidateShortcutInfo(&shortcut_info_, false) ||
 
176
      !PrefetchIcons() ||
 
177
      !desktop_->InitializeDialog(&shortcut_info_,
 
178
                                  dialog_.get(),
 
179
                                  Desktop::DIALOG_STYLE_SIMPLE) ||
 
180
      dialog_->DoModeless(STRING16(L"shortcuts_dialog.html"),
 
181
                          kShortcutsDialogWidth, kShortcutsDialogHeight,
 
182
                          ResultsReadyCallback, this) != HTML_DIALOG_SUCCESS)
 
183
    return false;
 
184
 
 
185
  shortcut_data_ = shortcut_data;
 
186
 
 
187
  // Keep track of this dialog being open.
 
188
  RegisterOpenDialog(shortcut_info_.app_url);
 
189
  return true;
 
190
}
 
191
 
 
192
void ModelessShortcutsDialog::ResultsReady() {
 
193
  results_ready_ = true;
 
194
 
 
195
  if (dialog_->result == Json::Value::null ||
 
196
      !dialog_->result["allow"].isBool() ||
 
197
      !dialog_->result["allow"].asBool()) {
 
198
    // The user doesn't want to create the shortcut, so cancel the icon fetch
 
199
    // and handle the results immediately.
 
200
    AbortPrefetchIcons();
 
201
    HandleDialogResults();
 
202
    return;
 
203
  }
 
204
 
 
205
  if (AreIconsReady() && results_ready_)
 
206
    HandleDialogResults();
 
207
}
 
208
 
 
209
bool ModelessShortcutsDialog::PrefetchIcons() {
 
210
  std::string16 error;
 
211
  for (size_t i = 0; i < 4; ++i) {
 
212
    icon_handler_[i].reset(new ShortcutIconHandler(this, i));
 
213
    if (!desktop_->FetchIcon(icon_handler_[i]->mutable_icon(), &error,
 
214
                             icon_handler_[i].get())) {
 
215
      return false;
 
216
    }
 
217
  }
 
218
 
 
219
  return true;
 
220
}
 
221
 
 
222
void ModelessShortcutsDialog::AbortPrefetchIcons() {
 
223
  for (size_t i = 0; i < 4; ++i) {
 
224
    if (icon_handler_[i].get()) {
 
225
      // Deleting icon handlers will abort any pending
 
226
      // fetches.
 
227
      icon_handler_[i].reset();
 
228
    }
 
229
  }
 
230
}
 
231
 
 
232
void ModelessShortcutsDialog::IconRequestFinished(int index) {
 
233
  // Figure out which icon this fetch was for, and mark the fetch as done by
 
234
  // clearing it.
 
235
  icon_handler_[index].reset();
 
236
  if (AreIconsReady() && results_ready_)
 
237
    HandleDialogResults();
 
238
}
 
239
 
 
240
bool ModelessShortcutsDialog::AreIconsReady() {
 
241
  for (size_t i = 0; i < 4; ++i) {
 
242
    if (icon_handler_[i].get())
 
243
      return false;
 
244
  }
 
245
 
 
246
  return true;
 
247
}
 
248
 
 
249
void ModelessShortcutsDialog::HandleDialogResults() {
 
250
  bool success = desktop_->HandleDialogResults(&shortcut_info_, dialog_.get());
 
251
  UnregisterOpenDialog(shortcut_info_.app_url);
 
252
 
 
253
  bool allow = dialog_->result["allow"].asBool();
 
254
 
 
255
  // Notify Chrome that the user's choice is ready.
 
256
  GearsCreateShortcutResult result = {
 
257
    shortcut_data_,
 
258
    (allow && success) ? CPERR_SUCCESS : CPERR_FAILURE
 
259
  };
 
260
  CP::browser_funcs().handle_command(
 
261
      CP::cpid(), browsing_context_,
 
262
      GEARSBROWSERCOMMAND_CREATE_SHORTCUT_DONE, &result);
 
263
 
 
264
  delete this;
 
265
}
 
266
 
 
267
// Helper to convert a Desktop::ShortcutInfo to the right format for Chrome.
 
268
static void ConvertToGearsShortcutData(
 
269
    const Desktop::ShortcutInfo &info,
 
270
    GearsShortcutData *shortcut_data) {
 
271
  memset(shortcut_data, 0, sizeof(*shortcut_data));
 
272
  shortcut_data->url = CP::String16ToUTF8Dup(info.app_url);
 
273
  shortcut_data->name = CP::String16ToUTF8Dup(info.app_name);
 
274
  shortcut_data->description = CP::String16ToUTF8Dup(info.app_description);
 
275
  if (!info.icon16x16.url.empty()) {
 
276
    shortcut_data->icons[0].width = shortcut_data->icons[0].height = 16;
 
277
    shortcut_data->icons[0].url = CP::String16ToUTF8Dup(info.icon16x16.url);
 
278
  }
 
279
  if (!info.icon32x32.url.empty()) {
 
280
    shortcut_data->icons[1].width = shortcut_data->icons[1].height = 32;
 
281
    shortcut_data->icons[1].url = CP::String16ToUTF8Dup(info.icon32x32.url);
 
282
  }
 
283
  if (!info.icon48x48.url.empty()) {
 
284
    shortcut_data->icons[2].width = shortcut_data->icons[2].height = 48;
 
285
    shortcut_data->icons[2].url = CP::String16ToUTF8Dup(info.icon48x48.url);
 
286
  }
 
287
  if (!info.icon128x128.url.empty()) {
 
288
    shortcut_data->icons[3].width = shortcut_data->icons[3].height = 128;
 
289
    shortcut_data->icons[3].url = CP::String16ToUTF8Dup(info.icon128x128.url);
 
290
  }
 
291
}
 
292
 
 
293
bool GetAllShortcuts(GearsShortcutList *shortcut_list) {
 
294
  // Build the list in a temporary vector for ease of use.
 
295
  std::vector<GearsShortcutData> shortcuts;
 
296
  size_t num_shortcuts = 0;
 
297
 
 
298
  PermissionsDB *permissions = PermissionsDB::GetDB();
 
299
  if (!permissions) {
 
300
    return false;
 
301
  }
 
302
 
 
303
  std::vector<SecurityOrigin> origins;
 
304
  if (!permissions->GetOriginsWithShortcuts(&origins)) {
 
305
    LOG16((L"GetOriginsWithShortcuts() failed"));
 
306
    return false;
 
307
  }
 
308
 
 
309
  for (size_t i = 0; i < origins.size(); ++i) {
 
310
    std::vector<std::string16> names;
 
311
    if (!permissions->GetOriginShortcuts(origins[i], &names)) {
 
312
      LOG16((L"GetOriginShortcuts(%s) failed", origins[i].full_url().c_str()));
 
313
      continue;
 
314
    }
 
315
 
 
316
    // This is a conservative resize (since we skip disallowed shortcuts).
 
317
    shortcuts.resize(num_shortcuts + names.size());
 
318
    for (size_t j = 0; j < names.size(); ++j) {
 
319
      Desktop::ShortcutInfo info;
 
320
      bool allow = false;
 
321
      if (!permissions->GetShortcut(origins[i], names[j].c_str(),
 
322
                                    &info.app_url,
 
323
                                    &info.icon16x16.url,
 
324
                                    &info.icon32x32.url,
 
325
                                    &info.icon48x48.url,
 
326
                                    &info.icon128x128.url,
 
327
                                    &info.app_description,
 
328
                                    &allow)) {
 
329
        LOG16((L"GetShortcut(%s) failed",
 
330
               origins[i].full_url().c_str(), names[j].c_str()));
 
331
        continue;
 
332
      }
 
333
      if (!allow)
 
334
        continue;  // Skip disallowed shortcuts.
 
335
 
 
336
      info.app_name = names[j];
 
337
      ConvertToGearsShortcutData(info, &shortcuts[num_shortcuts++]);
 
338
    }
 
339
  }
 
340
 
 
341
  // Copy back out of our temporary vector.
 
342
  shortcut_list->num_shortcuts = num_shortcuts;
 
343
  if (num_shortcuts > 0) {
 
344
    shortcut_list->shortcuts = CP::Alloc<GearsShortcutData>(num_shortcuts);
 
345
    memcpy(shortcut_list->shortcuts, &shortcuts[0],
 
346
           sizeof(GearsShortcutData) * num_shortcuts);
 
347
  } else {
 
348
    shortcut_list->shortcuts = NULL;
 
349
  }
 
350
  return true;
 
351
}