Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: chrome/browser/gtk/dialogs_gtk.cc

Issue 4321003: GTK: Allow file I/O in file dialog functions functions on the UI thread.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <gtk/gtk.h> 5 #include <gtk/gtk.h>
6 #include <map> 6 #include <map>
7 #include <set> 7 #include <set>
8 8
9 #include "app/gtk_signal.h" 9 #include "app/gtk_signal.h"
10 #include "app/l10n_util.h" 10 #include "app/l10n_util.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/message_loop.h" 13 #include "base/message_loop.h"
14 #include "base/mime_util.h" 14 #include "base/mime_util.h"
15 #include "base/sys_string_conversions.h" 15 #include "base/sys_string_conversions.h"
16 #include "base/thread.h"
17 #include "base/thread_restrictions.h"
16 #include "base/utf_string_conversions.h" 18 #include "base/utf_string_conversions.h"
17 #include "base/thread.h"
18 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/browser_thread.h" 20 #include "chrome/browser/browser_thread.h"
20 #include "chrome/browser/shell_dialogs.h" 21 #include "chrome/browser/shell_dialogs.h"
21 #include "grit/generated_resources.h" 22 #include "grit/generated_resources.h"
22 23
23 // The size of the preview we display for selected image files. We set height 24 // The size of the preview we display for selected image files. We set height
24 // larger than width because generally there is more free space vertically 25 // larger than width because generally there is more free space vertically
25 // than horiztonally (setting the preview image will alway expand the width of 26 // than horiztonally (setting the preview image will alway expand the width of
26 // the dialog, but usually not the height). The image's aspect ratio will always 27 // the dialog, but usually not the height). The image's aspect ratio will always
27 // be preserved. 28 // be preserved.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 // Check whether response_id corresponds to the user cancelling/closing the 90 // Check whether response_id corresponds to the user cancelling/closing the
90 // dialog. Used as a helper for the below callbacks. 91 // dialog. Used as a helper for the below callbacks.
91 bool IsCancelResponse(gint response_id); 92 bool IsCancelResponse(gint response_id);
92 93
93 // Common function for OnSelectSingleFileDialogResponse and 94 // Common function for OnSelectSingleFileDialogResponse and
94 // OnSelectSingleFolderDialogResponse. 95 // OnSelectSingleFolderDialogResponse.
95 void SelectSingleFileHelper(GtkWidget* dialog, 96 void SelectSingleFileHelper(GtkWidget* dialog,
96 gint response_id, 97 gint response_id,
97 bool allow_folder); 98 bool allow_folder);
98 99
100 // Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog.
101 GtkWidget* CreateFileOpenHelper(const std::string& title,
102 const FilePath& default_path,
103 gfx::NativeWindow parent);
104
105 // Wrapper for file_util::DirectoryExists() that allow access on the UI
106 // thread. Use this only in the file dialog functions, where it's ok
107 // because the file dialog has to do many stats anyway. One more won't
108 // hurt too badly and it's likely already cached.
109 bool CallDirectoryExistsOnUIThread(const FilePath& path);
110
99 // Callback for when the user responds to a Save As or Open File dialog. 111 // Callback for when the user responds to a Save As or Open File dialog.
100 CHROMEGTK_CALLBACK_1(SelectFileDialogImpl, void, 112 CHROMEGTK_CALLBACK_1(SelectFileDialogImpl, void,
101 OnSelectSingleFileDialogResponse, gint); 113 OnSelectSingleFileDialogResponse, gint);
102 114
103 // Callback for when the user responds to a Select Folder dialog. 115 // Callback for when the user responds to a Select Folder dialog.
104 CHROMEGTK_CALLBACK_1(SelectFileDialogImpl, void, 116 CHROMEGTK_CALLBACK_1(SelectFileDialogImpl, void,
105 OnSelectSingleFolderDialogResponse, gint); 117 OnSelectSingleFolderDialogResponse, gint);
106 118
107 // Callback for when the user responds to a Open Multiple Files dialog. 119 // Callback for when the user responds to a Open Multiple Files dialog.
108 CHROMEGTK_CALLBACK_1(SelectFileDialogImpl, void, 120 CHROMEGTK_CALLBACK_1(SelectFileDialogImpl, void,
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 gtk_widget_destroy(dialog); 334 gtk_widget_destroy(dialog);
323 } 335 }
324 336
325 void SelectFileDialogImpl::FileNotSelected(GtkWidget* dialog) { 337 void SelectFileDialogImpl::FileNotSelected(GtkWidget* dialog) {
326 void* params = PopParamsForDialog(dialog); 338 void* params = PopParamsForDialog(dialog);
327 if (listener_) 339 if (listener_)
328 listener_->FileSelectionCanceled(params); 340 listener_->FileSelectionCanceled(params);
329 gtk_widget_destroy(dialog); 341 gtk_widget_destroy(dialog);
330 } 342 }
331 343
344 bool SelectFileDialogImpl::CallDirectoryExistsOnUIThread(const FilePath& path) {
345 base::ThreadRestrictions::ScopedAllowIO allow_io;
346 return file_util::DirectoryExists(path);
347 }
348
349 GtkWidget* SelectFileDialogImpl::CreateFileOpenHelper(
350 const std::string& title,
351 const FilePath& default_path,
352 gfx::NativeWindow parent) {
353 GtkWidget* dialog =
354 gtk_file_chooser_dialog_new(title.c_str(), parent,
355 GTK_FILE_CHOOSER_ACTION_OPEN,
356 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
357 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
358 NULL);
359 AddFilters(GTK_FILE_CHOOSER(dialog));
360
361 if (!default_path.empty()) {
362 if (CallDirectoryExistsOnUIThread(default_path)) {
363 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
364 default_path.value().c_str());
365 } else {
366 // If the file doesn't exist, this will just switch to the correct
367 // directory. That's good enough.
368 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
369 default_path.value().c_str());
370 }
371 } else if (!last_opened_path_->empty()) {
372 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
373 last_opened_path_->value().c_str());
374 }
375 return dialog;
376 }
377
332 GtkWidget* SelectFileDialogImpl::CreateSelectFolderDialog( 378 GtkWidget* SelectFileDialogImpl::CreateSelectFolderDialog(
333 const std::string& title, 379 const std::string& title,
334 const FilePath& default_path, 380 const FilePath& default_path,
335 gfx::NativeWindow parent) { 381 gfx::NativeWindow parent) {
336 std::string title_string = !title.empty() ? title : 382 std::string title_string = !title.empty() ? title :
337 l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE); 383 l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE);
338 384
339 GtkWidget* dialog = 385 GtkWidget* dialog =
340 gtk_file_chooser_dialog_new(title_string.c_str(), parent, 386 gtk_file_chooser_dialog_new(title_string.c_str(), parent,
341 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, 387 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
342 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 388 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
343 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, 389 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
344 NULL); 390 NULL);
345 391
346 if (!default_path.empty()) { 392 if (!default_path.empty()) {
347 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), 393 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
348 default_path.value().c_str()); 394 default_path.value().c_str());
349 } else if (!last_opened_path_->empty()) { 395 } else if (!last_opened_path_->empty()) {
350 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), 396 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
351 last_opened_path_->value().c_str()); 397 last_opened_path_->value().c_str());
352 } 398 }
353 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); 399 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
354 g_signal_connect(dialog, "response", 400 g_signal_connect(dialog, "response",
355 G_CALLBACK(OnSelectSingleFolderDialogResponseThunk), this); 401 G_CALLBACK(OnSelectSingleFolderDialogResponseThunk), this);
356 return dialog; 402 return dialog;
357 } 403 }
358 404
359 GtkWidget* SelectFileDialogImpl::CreateFileOpenDialog(const std::string& title, 405 GtkWidget* SelectFileDialogImpl::CreateFileOpenDialog(
360 const FilePath& default_path, gfx::NativeWindow parent) { 406 const std::string& title,
407 const FilePath& default_path,
408 gfx::NativeWindow parent) {
361 std::string title_string = !title.empty() ? title : 409 std::string title_string = !title.empty() ? title :
362 l10n_util::GetStringUTF8(IDS_OPEN_FILE_DIALOG_TITLE); 410 l10n_util::GetStringUTF8(IDS_OPEN_FILE_DIALOG_TITLE);
363 411 GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent);
364 GtkWidget* dialog =
365 gtk_file_chooser_dialog_new(title_string.c_str(), parent,
366 GTK_FILE_CHOOSER_ACTION_OPEN,
367 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
368 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
369 NULL);
370
371 AddFilters(GTK_FILE_CHOOSER(dialog));
372 if (!default_path.empty()) {
373 if (file_util::DirectoryExists(default_path)) {
374 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
375 default_path.value().c_str());
376 } else {
377 // If the file doesn't exist, this will just switch to the correct
378 // directory. That's good enough.
379 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
380 default_path.value().c_str());
381 }
382 } else if (!last_opened_path_->empty()) {
383 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
384 last_opened_path_->value().c_str());
385 }
386 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); 412 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
387 g_signal_connect(dialog, "response", 413 g_signal_connect(dialog, "response",
388 G_CALLBACK(OnSelectSingleFileDialogResponseThunk), this); 414 G_CALLBACK(OnSelectSingleFileDialogResponseThunk), this);
389 return dialog; 415 return dialog;
390 } 416 }
391 417
392 GtkWidget* SelectFileDialogImpl::CreateMultiFileOpenDialog( 418 GtkWidget* SelectFileDialogImpl::CreateMultiFileOpenDialog(
393 const std::string& title, 419 const std::string& title,
394 const FilePath& default_path, 420 const FilePath& default_path,
395 gfx::NativeWindow parent) { 421 gfx::NativeWindow parent) {
396 std::string title_string = !title.empty() ? title : 422 std::string title_string = !title.empty() ? title :
397 l10n_util::GetStringUTF8(IDS_OPEN_FILES_DIALOG_TITLE); 423 l10n_util::GetStringUTF8(IDS_OPEN_FILES_DIALOG_TITLE);
398 424 GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent);
399 GtkWidget* dialog =
400 gtk_file_chooser_dialog_new(title_string.c_str(), parent,
401 GTK_FILE_CHOOSER_ACTION_OPEN,
402 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
403 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
404 NULL);
405
406 AddFilters(GTK_FILE_CHOOSER(dialog));
407 if (!default_path.empty()) {
408 if (file_util::DirectoryExists(default_path)) {
409 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
410 default_path.value().c_str());
411 } else {
412 // If the file doesn't exist, this will just switch to the correct
413 // directory. That's good enough.
414 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
415 default_path.value().c_str());
416 }
417 } else if (!last_opened_path_->empty()) {
418 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
419 last_opened_path_->value().c_str());
420 }
421 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE); 425 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
422 g_signal_connect(dialog, "response", 426 g_signal_connect(dialog, "response",
423 G_CALLBACK(OnSelectMultiFileDialogResponseThunk), this); 427 G_CALLBACK(OnSelectMultiFileDialogResponseThunk), this);
424 return dialog; 428 return dialog;
425 } 429 }
426 430
427 GtkWidget* SelectFileDialogImpl::CreateSaveAsDialog(const std::string& title, 431 GtkWidget* SelectFileDialogImpl::CreateSaveAsDialog(const std::string& title,
428 const FilePath& default_path, gfx::NativeWindow parent) { 432 const FilePath& default_path, gfx::NativeWindow parent) {
429 std::string title_string = !title.empty() ? title : 433 std::string title_string = !title.empty() ? title :
430 l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE); 434 l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 } 512 }
509 513
510 FilePath path(filename); 514 FilePath path(filename);
511 g_free(filename); 515 g_free(filename);
512 516
513 if (allow_folder) { 517 if (allow_folder) {
514 FileSelected(dialog, path); 518 FileSelected(dialog, path);
515 return; 519 return;
516 } 520 }
517 521
518 // We're accessing the disk from the UI thread here, but in this case it's 522 if (CallDirectoryExistsOnUIThread(path))
519 // ok because we may have just done lots of stats in the file selection
520 // dialog. One more won't hurt too badly.
521 if (file_util::DirectoryExists(path))
522 FileNotSelected(dialog); 523 FileNotSelected(dialog);
523 else 524 else
524 FileSelected(dialog, path); 525 FileSelected(dialog, path);
525 } 526 }
526 527
527 void SelectFileDialogImpl::OnSelectSingleFileDialogResponse( 528 void SelectFileDialogImpl::OnSelectSingleFileDialogResponse(
528 GtkWidget* dialog, gint response_id) { 529 GtkWidget* dialog, gint response_id) {
529 return SelectSingleFileHelper(dialog, response_id, false); 530 return SelectSingleFileHelper(dialog, response_id, false);
530 } 531 }
531 532
(...skipping 12 matching lines...) Expand all
544 GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); 545 GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
545 if (!filenames) { 546 if (!filenames) {
546 FileNotSelected(dialog); 547 FileNotSelected(dialog);
547 return; 548 return;
548 } 549 }
549 550
550 std::vector<FilePath> filenames_fp; 551 std::vector<FilePath> filenames_fp;
551 for (GSList* iter = filenames; iter != NULL; iter = g_slist_next(iter)) { 552 for (GSList* iter = filenames; iter != NULL; iter = g_slist_next(iter)) {
552 FilePath path(static_cast<char*>(iter->data)); 553 FilePath path(static_cast<char*>(iter->data));
553 g_free(iter->data); 554 g_free(iter->data);
554 if (file_util::DirectoryExists(path)) 555 if (CallDirectoryExistsOnUIThread(path))
555 continue; 556 continue;
556 filenames_fp.push_back(path); 557 filenames_fp.push_back(path);
557 } 558 }
558 g_slist_free(filenames); 559 g_slist_free(filenames);
559 560
560 if (filenames_fp.empty()) { 561 if (filenames_fp.empty()) {
561 FileNotSelected(dialog); 562 FileNotSelected(dialog);
562 return; 563 return;
563 } 564 }
564 MultiFilesSelected(dialog, filenames_fp); 565 MultiFilesSelected(dialog, filenames_fp);
(...skipping 12 matching lines...) Expand all
577 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth, 578 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth,
578 kPreviewHeight, NULL); 579 kPreviewHeight, NULL);
579 g_free(filename); 580 g_free(filename);
580 if (pixbuf) { 581 if (pixbuf) {
581 gtk_image_set_from_pixbuf(GTK_IMAGE(preview_), pixbuf); 582 gtk_image_set_from_pixbuf(GTK_IMAGE(preview_), pixbuf);
582 g_object_unref(pixbuf); 583 g_object_unref(pixbuf);
583 } 584 }
584 gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(chooser), 585 gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(chooser),
585 pixbuf ? TRUE : FALSE); 586 pixbuf ? TRUE : FALSE);
586 } 587 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698