summaryrefslogtreecommitdiffstats
path: root/chrome/browser/first_run_gtk.cc
blob: 8d9fe18d5d4ff2fff817abe7d668d6bed2a1437e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 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/first_run.h"

#include "chrome/app/breakpad_linux.h"
// We need to reach through the browser process to tweak the metrics flag.
#include "chrome/browser/browser_process.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/installer/util/google_update_settings.h"

#include "base/message_loop.h"

namespace {

// Callback for the "response" signal of the first run dialog.
// Fills in the int* |data| with the dialog response and quits the message loop.
// See the TODO below for why this is necessary (it's a bug).
void DialogResponseCallback(GtkDialog* dialog, gint response,
                            gpointer data) {
  int* response_out = static_cast<int*>(data);
  *response_out = response;
  MessageLoop::current()->Quit();
}

}  // namespace

void OpenFirstRunDialog(Profile* profile, ProcessSingleton* process_singleton) {
#if defined(GOOGLE_CHROME_BUILD)
  GtkWidget* dialog = gtk_dialog_new_with_buttons(
      "Google Chrome Dev Build",
      NULL,  // No parent
      (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
      NULL);
  gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
  g_signal_connect(G_OBJECT(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);
  // Force a size on the vbox so the labels wrap.
  gtk_widget_set_size_request(vbox, 400, -1);

  GtkWidget* privacy_label = gtk_label_new(
      "This version of Google Chrome for Linux is not appropriate for "
      "general consumer use.  Certain privacy features are unavailable "
      "at this time as described in our privacy policy at");
  gtk_misc_set_alignment(GTK_MISC(privacy_label), 0, 0);
  gtk_label_set_line_wrap(GTK_LABEL(privacy_label), TRUE);
  gtk_box_pack_start(GTK_BOX(vbox), privacy_label, FALSE, FALSE, 0);

  GtkWidget* url_label = gtk_label_new(NULL);
  gtk_label_set_markup(GTK_LABEL(url_label),
      "<tt>http://www.google.com/chrome/intl/en/privacy_linux.html</tt>");
  // Set selectable to allow copy and paste.
  gtk_label_set_selectable(GTK_LABEL(url_label), TRUE);
  gtk_box_pack_start(GTK_BOX(vbox), url_label, FALSE, FALSE, 0);

  GtkWidget* intro_label = gtk_label_new(
      "This dialog would normally prompt you to import information from other "
      "browsers, but that is not yet fully implemented.\n"
      "Instead, we have only one important setting available: Crash dumps. "
      "We cannot fix your crashes without your crash reports, so there's "
      "little reason to run a dev channel build without turning them on.");
  gtk_misc_set_alignment(GTK_MISC(intro_label), 0, 0);
  gtk_label_set_line_wrap(GTK_LABEL(intro_label), TRUE);
  gtk_box_pack_start(GTK_BOX(vbox), intro_label, FALSE, FALSE, 0);

  GtkWidget* check = gtk_check_button_new();
  GtkWidget* check_label = gtk_label_new(NULL);
  gtk_label_set_markup(GTK_LABEL(check_label),
                       "<b>Optional:</b> Help make Google Chrome better by "
                       "automatically sending crash reports (and eventually "
                       "usage statistics, but that is also unimplemented) "
                       "to Google.");
  gtk_label_set_line_wrap(GTK_LABEL(check_label), TRUE);
  gtk_container_add(GTK_CONTAINER(check), check_label);
  gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0);

  #define UTF8_BULLET " \xE2\x80\xA2 "
  GtkWidget* crashinfo_label = gtk_label_new(NULL);
  gtk_label_set_markup(GTK_LABEL(crashinfo_label),
      "A crash dump contains:\n"
      UTF8_BULLET "Stacks and registers of all the threads in the crashing "
      "process\n"
      UTF8_BULLET "The current URL if a render process crashes\n"
      UTF8_BULLET "<tt>/proc/cpuinfo</tt>, <tt>/etc/lsb-release</tt>\n"
      UTF8_BULLET "Other misc information about the process (its "
      "<tt>/proc/pid/maps</tt>, <tt>/proc/pid/status</tt>, etc.)");
  gtk_misc_set_alignment(GTK_MISC(crashinfo_label), 0, 0);
  gtk_label_set_line_wrap(GTK_LABEL(crashinfo_label), TRUE);
  gtk_box_pack_start(GTK_BOX(vbox), crashinfo_label, FALSE, FALSE, 0);

  gtk_box_pack_start(GTK_BOX(content_area), vbox, FALSE, FALSE, 0);
  gtk_widget_show_all(vbox);

  // 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.
  int response = 0;
  g_signal_connect(G_OBJECT(dialog), "response",
                   G_CALLBACK(DialogResponseCallback), &response);
  gtk_widget_show(dialog);
  MessageLoop::current()->Run();
  // End of above TODO.

  if (response == GTK_RESPONSE_ACCEPT) {
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check))) {
      // They opted in.
      if (GoogleUpdateSettings::SetCollectStatsConsent(true)) {
        InitCrashReporter();
      }
    } else {
      GoogleUpdateSettings::SetCollectStatsConsent(false);
    }
  }

  gtk_widget_destroy(dialog);
#endif  // defined(GOOGLE_CHROME_BUILD)

  // Mark that first run has ran.
  FirstRun::CreateSentinel();
}