// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/gtk/first_run_dialog.h" #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/message_loop.h" #include "chrome/browser/gtk/gtk_chrome_link_button.h" #include "chrome/browser/process_singleton.h" #include "chrome/browser/shell_integration.h" #include "chrome/common/gtk_util.h" #include "chrome/common/platform_util.h" #include "chrome/installer/util/google_update_settings.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" #if defined(USE_LINUX_BREAKPAD) #include "chrome/app/breakpad_linux.h" #endif // static bool FirstRunDialog::Show(Profile* profile, ProcessSingleton* process_singleton) { int response = -1; // Object deletes itself. FirstRunDialog* first_run = new FirstRunDialog(profile, response); // Prevent further launches of Chrome until First Run UI is done. process_singleton->Lock(GTK_WINDOW(first_run->dialog_)); // TODO(port): it should be sufficient to just run the dialog: // int response = gtk_dialog_run(GTK_DIALOG(dialog)); // but that spins a nested message loop and hoses us. :( // http://code.google.com/p/chromium/issues/detail?id=12552 // Instead, run a loop and extract the response manually. g_signal_connect(first_run->dialog_, "response", G_CALLBACK(HandleOnResponseDialog), first_run); gtk_widget_show_all(first_run->dialog_); MessageLoop::current()->Run(); process_singleton->Unlock(); return (response == GTK_RESPONSE_ACCEPT); } FirstRunDialog::FirstRunDialog(Profile* profile, int& response) : dialog_(NULL), report_crashes_(NULL), make_default_(NULL), import_data_(NULL), import_profile_(NULL), profile_(profile), response_(response), importer_host_(new ImporterHost()) { dialog_ = gtk_dialog_new_with_buttons( l10n_util::GetStringUTF8(IDS_FIRSTRUN_DLG_TITLE).c_str(), NULL, // No parent (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), GTK_STOCK_QUIT, GTK_RESPONSE_REJECT, NULL); gtk_util::AddButtonToDialog(dialog_, l10n_util::GetStringUTF8(IDS_FIRSTRUN_DLG_OK).c_str(), GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT); // Normally we would do the following: // gtk_widget_realize(dialog_); // gtk_util::SetWindowSizeFromResources(GTK_WINDOW(dialog_), // IDS_FIRSTRUN_DIALOG_WIDTH_CHARS, // -1, // false); // resizable // But because the first run dialog has extra widgets in Windows, the // resources specify a dialog that is way too big. So instead in just this // one case we let GTK size the dialog itself and just mark it non-resizable // manually: gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE); g_signal_connect(dialog_, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox; gtk_box_set_spacing(GTK_BOX(content_area), 18); GtkWidget* vbox = gtk_vbox_new(FALSE, 12); #if defined(GOOGLE_CHROME_BUILD) GtkWidget* check_label = gtk_label_new( l10n_util::GetStringUTF8(IDS_OPTIONS_ENABLE_LOGGING).c_str()); gtk_label_set_line_wrap(GTK_LABEL(check_label), TRUE); GtkWidget* learn_more_link = gtk_chrome_link_button_new( l10n_util::GetStringUTF8(IDS_LEARN_MORE).c_str()); // Stick it in an hbox so it doesn't expand to the whole width. GtkWidget* learn_more_hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(learn_more_hbox), gtk_util::IndentWidget(learn_more_link), FALSE, FALSE, 0); g_signal_connect(learn_more_link, "clicked", G_CALLBACK(OnLearnMoreLinkClicked), this); report_crashes_ = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(report_crashes_), check_label); GtkWidget* report_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); gtk_box_pack_start(GTK_BOX(report_vbox), report_crashes_, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(report_vbox), learn_more_hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), report_vbox, FALSE, FALSE, 0); #endif make_default_ = gtk_check_button_new_with_label( l10n_util::GetStringUTF8(IDS_FR_CUSTOMIZE_DEFAULT_BROWSER).c_str()); gtk_box_pack_start(GTK_BOX(vbox), make_default_, FALSE, FALSE, 0); GtkWidget* combo_hbox = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing); import_data_ = gtk_check_button_new_with_label( l10n_util::GetStringUTF8(IDS_FR_CUSTOMIZE_IMPORT).c_str()); gtk_box_pack_start(GTK_BOX(combo_hbox), import_data_, FALSE, FALSE, 0); import_profile_ = gtk_combo_box_new_text(); gtk_box_pack_start(GTK_BOX(combo_hbox), import_profile_, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), combo_hbox, FALSE, FALSE, 0); // Detect any supported browsers that we can import from and fill // up the combo box. If none found, disable import data checkbox. int profiles_count = importer_host_->GetAvailableProfileCount(); if (profiles_count > 0) { for (int i = 0; i < profiles_count; i++) { std::wstring profile = importer_host_->GetSourceProfileNameAt(i); gtk_combo_box_append_text(GTK_COMBO_BOX(import_profile_), WideToUTF8(profile).c_str()); } gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(import_data_), TRUE); gtk_combo_box_set_active(GTK_COMBO_BOX(import_profile_), 0); } else { gtk_combo_box_append_text(GTK_COMBO_BOX(import_profile_), l10n_util::GetStringUTF8(IDS_IMPORT_NO_PROFILE_FOUND).c_str()); gtk_combo_box_set_active(GTK_COMBO_BOX(import_profile_), 0); gtk_widget_set_sensitive(import_data_, FALSE); gtk_widget_set_sensitive(import_profile_, FALSE); } gtk_box_pack_start(GTK_BOX(content_area), vbox, FALSE, FALSE, 0); } void FirstRunDialog::OnDialogResponse(GtkWidget* widget, int response) { bool import_started = false; gtk_widget_hide_all(dialog_); response_ = response; if (response == GTK_RESPONSE_ACCEPT) { // Mark that first run has ran. FirstRun::CreateSentinel(); // Check if user has opted into reporting. if (report_crashes_ && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(report_crashes_))) { #if defined(USE_LINUX_BREAKPAD) if (GoogleUpdateSettings::SetCollectStatsConsent(true)) { InitCrashReporter(); } #endif } else { GoogleUpdateSettings::SetCollectStatsConsent(false); } // If selected set as default browser. if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(make_default_))) ShellIntegration::SetAsDefaultBrowser(); // Import data if selected. if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(import_data_))) { const ProfileInfo& source_profile = importer_host_->GetSourceProfileInfoAt( gtk_combo_box_get_active(GTK_COMBO_BOX(import_profile_))); int items = SEARCH_ENGINES + HISTORY + FAVORITES + HOME_PAGE + PASSWORDS; // TODO(port): Should we do the actual import in a new process like // Windows? StartImportingWithUI(GTK_WINDOW(dialog_), items, importer_host_.get(), source_profile, profile_, this, true); import_started = true; } } if (!import_started) FirstRunDone(); } // static void FirstRunDialog::OnLearnMoreLinkClicked(GtkButton *button, FirstRunDialog* first_run) { platform_util::OpenExternal(GURL( l10n_util::GetStringUTF8(IDS_LEARN_MORE_REPORTING_URL))); } void FirstRunDialog::FirstRunDone() { // Set preference to show first run bubble and welcome page. FirstRun::SetShowFirstRunBubblePref(); FirstRun::SetShowWelcomePagePref(); gtk_widget_destroy(dialog_); MessageLoop::current()->Quit(); delete this; }