Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <dlfcn.h>
7 #include <fcntl.h>
8 #include <glib.h>
9 #include <gtk/gtk.h>
10 #include <string.h>
12 #include <cctype>
14 #include "mozilla/NullPtr.h"
15 #include "crashreporter.h"
16 #include "crashreporter_gtk_common.h"
18 using std::string;
19 using std::vector;
21 using namespace CrashReporter;
23 static GtkWidget* gViewReportButton = 0;
24 static GtkWidget* gCommentTextLabel = 0;
25 static GtkWidget* gCommentText = 0;
26 static GtkWidget* gEmailMeCheck = 0;
27 static GtkWidget* gEmailEntryLabel = 0;
28 static GtkWidget* gEmailEntry = 0;
30 static bool gEmailFieldHint = true;
31 static bool gCommentFieldHint = true;
33 // handle from dlopen'ing libgnome
34 static void* gnomeLib = nullptr;
35 // handle from dlopen'ing libgnomeui
36 static void* gnomeuiLib = nullptr;
38 static void LoadSettings()
39 {
40 /*
41 * NOTE! This code needs to stay in sync with the preference checking
42 * code in in nsExceptionHandler.cpp.
43 */
45 StringTable settings;
46 if (ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true)) {
47 if (settings.find("Email") != settings.end()) {
48 gtk_entry_set_text(GTK_ENTRY(gEmailEntry), settings["Email"].c_str());
49 gEmailFieldHint = false;
50 }
51 if (settings.find("EmailMe") != settings.end()) {
52 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gEmailMeCheck),
53 settings["EmailMe"][0] != '0');
54 }
55 if (settings.find("IncludeURL") != settings.end() &&
56 gIncludeURLCheck != 0) {
57 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck),
58 settings["IncludeURL"][0] != '0');
59 }
60 bool enabled;
61 if (settings.find("SubmitReport") != settings.end())
62 enabled = settings["SubmitReport"][0] != '0';
63 else
64 enabled = ShouldEnableSending();
65 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck),
66 enabled);
67 }
68 }
70 void SaveSettings()
71 {
72 /*
73 * NOTE! This code needs to stay in sync with the preference setting
74 * code in in nsExceptionHandler.cpp.
75 */
77 StringTable settings;
79 ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true);
80 if (!gEmailFieldHint)
81 settings["Email"] = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
82 else
83 settings.erase("Email");
85 settings["EmailMe"] =
86 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)) ? "1" : "0";
87 if (gIncludeURLCheck != 0)
88 settings["IncludeURL"] =
89 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))
90 ? "1" : "0";
91 settings["SubmitReport"] =
92 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))
93 ? "1" : "0";
95 WriteStringsToFile(gSettingsPath + "/" + kIniFile,
96 "Crash Reporter", settings, true);
97 }
99 void SendReport()
100 {
101 // disable all our gui controls, show the throbber + change the progress text
102 gtk_widget_set_sensitive(gSubmitReportCheck, FALSE);
103 gtk_widget_set_sensitive(gViewReportButton, FALSE);
104 gtk_widget_set_sensitive(gCommentText, FALSE);
105 if (gIncludeURLCheck)
106 gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
107 gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
108 gtk_widget_set_sensitive(gEmailEntry, FALSE);
109 gtk_widget_set_sensitive(gCloseButton, FALSE);
110 if (gRestartButton)
111 gtk_widget_set_sensitive(gRestartButton, FALSE);
112 gtk_widget_show_all(gThrobber);
113 gtk_label_set_text(GTK_LABEL(gProgressLabel),
114 gStrings[ST_REPORTDURINGSUBMIT].c_str());
116 #ifdef MOZ_ENABLE_GCONF
117 LoadProxyinfo();
118 #endif
120 // and spawn a thread to do the sending
121 GError* err;
122 gSendThreadID = g_thread_create(SendThread, nullptr, TRUE, &err);
123 }
125 static void ShowReportInfo(GtkTextView* viewReportTextView)
126 {
127 GtkTextBuffer* buffer =
128 gtk_text_view_get_buffer(viewReportTextView);
130 GtkTextIter start, end;
131 gtk_text_buffer_get_start_iter(buffer, &start);
132 gtk_text_buffer_get_end_iter(buffer, &end);
134 gtk_text_buffer_delete(buffer, &start, &end);
136 for (StringTable::iterator iter = gQueryParameters.begin();
137 iter != gQueryParameters.end();
138 iter++) {
139 gtk_text_buffer_insert(buffer, &end, iter->first.c_str(), -1);
140 gtk_text_buffer_insert(buffer, &end, ": ", -1);
141 gtk_text_buffer_insert(buffer, &end, iter->second.c_str(), -1);
142 gtk_text_buffer_insert(buffer, &end, "\n", -1);
143 }
145 gtk_text_buffer_insert(buffer, &end, "\n", -1);
146 gtk_text_buffer_insert(buffer, &end,
147 gStrings[ST_EXTRAREPORTINFO].c_str(), -1);
148 }
150 void UpdateSubmit()
151 {
152 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
153 gtk_widget_set_sensitive(gViewReportButton, TRUE);
154 gtk_widget_set_sensitive(gCommentText, TRUE);
155 if (gIncludeURLCheck)
156 gtk_widget_set_sensitive(gIncludeURLCheck, TRUE);
157 gtk_widget_set_sensitive(gEmailMeCheck, TRUE);
158 gtk_widget_set_sensitive(gEmailEntry,
159 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)));
160 gtk_label_set_text(GTK_LABEL(gProgressLabel),
161 gStrings[ST_REPORTPRESUBMIT].c_str());
162 } else {
163 gtk_widget_set_sensitive(gViewReportButton, FALSE);
164 gtk_widget_set_sensitive(gCommentText, FALSE);
165 if (gIncludeURLCheck)
166 gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
167 gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
168 gtk_widget_set_sensitive(gEmailEntry, FALSE);
169 gtk_label_set_text(GTK_LABEL(gProgressLabel), "");
170 }
171 }
173 static void ViewReportClicked(GtkButton* button,
174 gpointer userData)
175 {
176 GtkDialog* dialog =
177 GTK_DIALOG(gtk_dialog_new_with_buttons(gStrings[ST_VIEWREPORTTITLE].c_str(),
178 GTK_WINDOW(gWindow),
179 GTK_DIALOG_MODAL,
180 GTK_STOCK_OK,
181 GTK_RESPONSE_OK,
182 nullptr));
184 GtkWidget* scrolled = gtk_scrolled_window_new(0, 0);
185 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), scrolled);
186 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
187 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
188 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
189 GTK_SHADOW_IN);
191 GtkWidget* viewReportTextView = gtk_text_view_new();
192 gtk_container_add(GTK_CONTAINER(scrolled), viewReportTextView);
193 gtk_text_view_set_editable(GTK_TEXT_VIEW(viewReportTextView), FALSE);
194 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(viewReportTextView),
195 GTK_WRAP_WORD);
196 gtk_widget_set_size_request(GTK_WIDGET(viewReportTextView), -1, 100);
198 ShowReportInfo(GTK_TEXT_VIEW(viewReportTextView));
200 gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
201 gtk_widget_set_size_request(GTK_WIDGET(dialog), 400, 200);
202 gtk_widget_show_all(GTK_WIDGET(dialog));
203 gtk_dialog_run(dialog);
204 gtk_widget_destroy(GTK_WIDGET(dialog));
205 }
207 static void CommentChanged(GtkTextBuffer* buffer, gpointer userData)
208 {
209 GtkTextIter start, end;
210 gtk_text_buffer_get_start_iter(buffer, &start);
211 gtk_text_buffer_get_end_iter(buffer, &end);
212 const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
213 if (comment[0] == '\0' || gCommentFieldHint)
214 gQueryParameters.erase("Comments");
215 else
216 gQueryParameters["Comments"] = comment;
217 }
219 static void CommentInsert(GtkTextBuffer* buffer,
220 GtkTextIter* location,
221 gchar* text,
222 gint len,
223 gpointer userData)
224 {
225 GtkTextIter start, end;
226 gtk_text_buffer_get_start_iter(buffer, &start);
227 gtk_text_buffer_get_end_iter(buffer, &end);
228 const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
230 // limit to 500 bytes in utf-8
231 if (strlen(comment) + len > MAX_COMMENT_LENGTH) {
232 g_signal_stop_emission_by_name(buffer, "insert-text");
233 }
234 }
236 static void UpdateHintText(GtkWidget* widget, gboolean gainedFocus,
237 bool* hintShowing, const char* hintText)
238 {
239 GtkTextBuffer* buffer = nullptr;
240 if (GTK_IS_TEXT_VIEW(widget))
241 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
243 if (gainedFocus) {
244 if (*hintShowing) {
245 if (buffer == nullptr) { // sort of cheating
246 gtk_entry_set_text(GTK_ENTRY(widget), "");
247 }
248 else { // GtkTextView
249 gtk_text_buffer_set_text(buffer, "", 0);
250 }
251 gtk_widget_modify_text(widget, GTK_STATE_NORMAL, nullptr);
252 *hintShowing = false;
253 }
254 }
255 else {
256 // lost focus
257 const char* text = nullptr;
258 if (buffer == nullptr) {
259 text = gtk_entry_get_text(GTK_ENTRY(widget));
260 }
261 else {
262 GtkTextIter start, end;
263 gtk_text_buffer_get_start_iter(buffer, &start);
264 gtk_text_buffer_get_end_iter(buffer, &end);
265 text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
266 }
268 if (text == nullptr || text[0] == '\0') {
269 *hintShowing = true;
271 if (buffer == nullptr) {
272 gtk_entry_set_text(GTK_ENTRY(widget), hintText);
273 }
274 else {
275 gtk_text_buffer_set_text(buffer, hintText, -1);
276 }
278 gtk_widget_modify_text(widget, GTK_STATE_NORMAL,
279 >k_widget_get_style(widget)->text[GTK_STATE_INSENSITIVE]);
280 }
281 }
282 }
284 static gboolean CommentFocusChange(GtkWidget* widget, GdkEventFocus* event,
285 gpointer userData)
286 {
287 UpdateHintText(widget, event->in, &gCommentFieldHint,
288 gStrings[ST_COMMENTGRAYTEXT].c_str());
290 return FALSE;
291 }
293 static void UpdateEmail()
294 {
295 const char* email = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
296 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck))) {
297 gtk_widget_set_sensitive(gEmailEntry, TRUE);
298 } else {
299 email = "";
300 gtk_widget_set_sensitive(gEmailEntry, FALSE);
301 }
302 if (email[0] == '\0' || gEmailFieldHint)
303 gQueryParameters.erase("Email");
304 else
305 gQueryParameters["Email"] = email;
306 }
308 static void EmailMeClicked(GtkButton* sender, gpointer userData)
309 {
310 UpdateEmail();
311 }
313 static void EmailChanged(GtkEditable* editable, gpointer userData)
314 {
315 UpdateEmail();
316 }
318 static gboolean EmailFocusChange(GtkWidget* widget, GdkEventFocus* event,
319 gpointer userData)
320 {
321 UpdateHintText(widget, event->in, &gEmailFieldHint,
322 gStrings[ST_EMAILGRAYTEXT].c_str());
324 return FALSE;
325 }
327 typedef struct _GnomeProgram GnomeProgram;
328 typedef struct _GnomeModuleInfo GnomeModuleInfo;
329 typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
330 const GnomeModuleInfo *, int,
331 char **, const char *, ...);
332 typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
334 void TryInitGnome()
335 {
336 gnomeLib = dlopen("libgnome-2.so.0", RTLD_LAZY);
337 if (!gnomeLib)
338 return;
340 gnomeuiLib = dlopen("libgnomeui-2.so.0", RTLD_LAZY);
341 if (!gnomeuiLib)
342 return;
344 _gnome_program_init_fn gnome_program_init =
345 (_gnome_program_init_fn)(dlsym(gnomeLib, "gnome_program_init"));
346 _libgnomeui_module_info_get_fn libgnomeui_module_info_get =
347 (_libgnomeui_module_info_get_fn)(dlsym(gnomeuiLib, "libgnomeui_module_info_get"));
349 if (gnome_program_init && libgnomeui_module_info_get) {
350 gnome_program_init("crashreporter", "1.0", libgnomeui_module_info_get(),
351 gArgc, gArgv, nullptr);
352 }
354 }
356 /* === Crashreporter UI Functions === */
358 /*
359 * Anything not listed here is in crashreporter_gtk_common.cpp:
360 * UIInit
361 * UIShowDefaultUI
362 * UIError_impl
363 * UIGetIniPath
364 * UIGetSettingsPath
365 * UIEnsurePathExists
366 * UIFileExists
367 * UIMoveFile
368 * UIDeleteFile
369 * UIOpenRead
370 * UIOpenWrite
371 */
373 void UIShutdown()
374 {
375 if (gnomeuiLib)
376 dlclose(gnomeuiLib);
377 // Don't dlclose gnomeLib as libgnomevfs and libORBit-2 use atexit().
378 }
380 bool UIShowCrashUI(const string& dumpfile,
381 const StringTable& queryParameters,
382 const string& sendURL,
383 const vector<string>& restartArgs)
384 {
385 gDumpFile = dumpfile;
386 gQueryParameters = queryParameters;
387 gSendURL = sendURL;
388 gRestartArgs = restartArgs;
389 if (gQueryParameters.find("URL") != gQueryParameters.end())
390 gURLParameter = gQueryParameters["URL"];
392 gWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
393 gtk_window_set_title(GTK_WINDOW(gWindow),
394 gStrings[ST_CRASHREPORTERTITLE].c_str());
395 gtk_window_set_resizable(GTK_WINDOW(gWindow), FALSE);
396 gtk_window_set_position(GTK_WINDOW(gWindow), GTK_WIN_POS_CENTER);
397 gtk_container_set_border_width(GTK_CONTAINER(gWindow), 12);
398 g_signal_connect(gWindow, "delete-event", G_CALLBACK(WindowDeleted), 0);
399 g_signal_connect(gWindow, "key_press_event", G_CALLBACK(check_escape), nullptr);
401 GtkWidget* vbox = gtk_vbox_new(FALSE, 6);
402 gtk_container_add(GTK_CONTAINER(gWindow), vbox);
404 GtkWidget* titleLabel = gtk_label_new("");
405 gtk_box_pack_start(GTK_BOX(vbox), titleLabel, FALSE, FALSE, 0);
406 gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
407 char* markup = g_strdup_printf("<b>%s</b>",
408 gStrings[ST_CRASHREPORTERHEADER].c_str());
409 gtk_label_set_markup(GTK_LABEL(titleLabel), markup);
410 g_free(markup);
412 GtkWidget* descriptionLabel =
413 gtk_label_new(gStrings[ST_CRASHREPORTERDESCRIPTION].c_str());
414 gtk_box_pack_start(GTK_BOX(vbox), descriptionLabel, TRUE, TRUE, 0);
415 // force the label to line wrap
416 gtk_widget_set_size_request(descriptionLabel, 400, -1);
417 gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE);
418 gtk_label_set_selectable(GTK_LABEL(descriptionLabel), TRUE);
419 gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0, 0.5);
421 // this is honestly how they suggest you indent a section
422 GtkWidget* indentBox = gtk_hbox_new(FALSE, 0);
423 gtk_box_pack_start(GTK_BOX(vbox), indentBox, FALSE, FALSE, 0);
424 gtk_box_pack_start(GTK_BOX(indentBox), gtk_label_new(""), FALSE, FALSE, 6);
426 GtkWidget* innerVBox1 = gtk_vbox_new(FALSE, 0);
427 gtk_box_pack_start(GTK_BOX(indentBox), innerVBox1, TRUE, TRUE, 0);
429 gSubmitReportCheck =
430 gtk_check_button_new_with_label(gStrings[ST_CHECKSUBMIT].c_str());
431 gtk_box_pack_start(GTK_BOX(innerVBox1), gSubmitReportCheck, FALSE, FALSE, 0);
432 g_signal_connect(gSubmitReportCheck, "clicked",
433 G_CALLBACK(SubmitReportChecked), 0);
435 // indent again, below the "submit report" checkbox
436 GtkWidget* indentBox2 = gtk_hbox_new(FALSE, 0);
437 gtk_box_pack_start(GTK_BOX(innerVBox1), indentBox2, FALSE, FALSE, 0);
438 gtk_box_pack_start(GTK_BOX(indentBox2), gtk_label_new(""), FALSE, FALSE, 6);
440 GtkWidget* innerVBox = gtk_vbox_new(FALSE, 0);
441 gtk_box_pack_start(GTK_BOX(indentBox2), innerVBox, TRUE, TRUE, 0);
442 gtk_box_set_spacing(GTK_BOX(innerVBox), 6);
444 GtkWidget* viewReportButtonBox = gtk_hbutton_box_new();
445 gtk_box_pack_start(GTK_BOX(innerVBox), viewReportButtonBox, FALSE, FALSE, 0);
446 gtk_box_set_spacing(GTK_BOX(viewReportButtonBox), 6);
447 gtk_button_box_set_layout(GTK_BUTTON_BOX(viewReportButtonBox), GTK_BUTTONBOX_START);
449 gViewReportButton =
450 gtk_button_new_with_label(gStrings[ST_VIEWREPORT].c_str());
451 gtk_box_pack_start(GTK_BOX(viewReportButtonBox), gViewReportButton, FALSE, FALSE, 0);
452 g_signal_connect(gViewReportButton, "clicked", G_CALLBACK(ViewReportClicked), 0);
454 GtkWidget* scrolled = gtk_scrolled_window_new(0, 0);
455 gtk_container_add(GTK_CONTAINER(innerVBox), scrolled);
456 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
457 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
458 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
459 GTK_SHADOW_IN);
461 gCommentTextLabel = gtk_label_new(gStrings[ST_COMMENTGRAYTEXT].c_str());
462 gCommentText = gtk_text_view_new();
463 gtk_label_set_mnemonic_widget(GTK_LABEL(gCommentTextLabel), gCommentText);
464 gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(gCommentText), FALSE);
465 g_signal_connect(gCommentText, "focus-in-event", G_CALLBACK(CommentFocusChange), 0);
466 g_signal_connect(gCommentText, "focus-out-event", G_CALLBACK(CommentFocusChange), 0);
468 GtkTextBuffer* commentBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gCommentText));
469 g_signal_connect(commentBuffer, "changed", G_CALLBACK(CommentChanged), 0);
470 g_signal_connect(commentBuffer, "insert-text", G_CALLBACK(CommentInsert), 0);
472 gtk_container_add(GTK_CONTAINER(scrolled), gCommentText);
473 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gCommentText),
474 GTK_WRAP_WORD);
475 gtk_widget_set_size_request(GTK_WIDGET(gCommentText), -1, 100);
477 if (gQueryParameters.find("URL") != gQueryParameters.end()) {
478 gIncludeURLCheck =
479 gtk_check_button_new_with_label(gStrings[ST_CHECKURL].c_str());
480 gtk_box_pack_start(GTK_BOX(innerVBox), gIncludeURLCheck, FALSE, FALSE, 0);
481 g_signal_connect(gIncludeURLCheck, "clicked", G_CALLBACK(IncludeURLClicked), 0);
482 // on by default
483 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), TRUE);
484 }
486 gEmailMeCheck =
487 gtk_check_button_new_with_label(gStrings[ST_CHECKEMAIL].c_str());
488 gtk_box_pack_start(GTK_BOX(innerVBox), gEmailMeCheck, FALSE, FALSE, 0);
489 g_signal_connect(gEmailMeCheck, "clicked", G_CALLBACK(EmailMeClicked), 0);
491 GtkWidget* emailIndentBox = gtk_hbox_new(FALSE, 0);
492 gtk_box_pack_start(GTK_BOX(innerVBox), emailIndentBox, FALSE, FALSE, 0);
493 gtk_box_pack_start(GTK_BOX(emailIndentBox), gtk_label_new(""),
494 FALSE, FALSE, 9);
496 gEmailEntryLabel = gtk_label_new(gStrings[ST_EMAILGRAYTEXT].c_str());
497 gEmailEntry = gtk_entry_new();
498 gtk_label_set_mnemonic_widget(GTK_LABEL(gEmailEntryLabel), gEmailEntry);
499 gtk_box_pack_start(GTK_BOX(emailIndentBox), gEmailEntry, TRUE, TRUE, 0);
500 g_signal_connect(gEmailEntry, "changed", G_CALLBACK(EmailChanged), 0);
501 g_signal_connect(gEmailEntry, "focus-in-event", G_CALLBACK(EmailFocusChange), 0);
502 g_signal_connect(gEmailEntry, "focus-out-event", G_CALLBACK(EmailFocusChange), 0);
504 GtkWidget* progressBox = gtk_hbox_new(FALSE, 6);
505 gtk_box_pack_start(GTK_BOX(vbox), progressBox, TRUE, TRUE, 0);
507 // Get the throbber image from alongside the executable
508 char* dir = g_path_get_dirname(gArgv[0]);
509 char* path = g_build_filename(dir, "Throbber-small.gif", nullptr);
510 g_free(dir);
511 gThrobber = gtk_image_new_from_file(path);
512 gtk_box_pack_start(GTK_BOX(progressBox), gThrobber, FALSE, FALSE, 0);
514 gProgressLabel =
515 gtk_label_new(gStrings[ST_REPORTPRESUBMIT].c_str());
516 gtk_box_pack_start(GTK_BOX(progressBox), gProgressLabel, TRUE, TRUE, 0);
517 // force the label to line wrap
518 gtk_widget_set_size_request(gProgressLabel, 400, -1);
519 gtk_label_set_line_wrap(GTK_LABEL(gProgressLabel), TRUE);
521 GtkWidget* buttonBox = gtk_hbutton_box_new();
522 gtk_box_pack_end(GTK_BOX(vbox), buttonBox, FALSE, FALSE, 0);
523 gtk_box_set_spacing(GTK_BOX(buttonBox), 6);
524 gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END);
526 gCloseButton =
527 gtk_button_new_with_label(gStrings[ST_QUIT].c_str());
528 gtk_box_pack_start(GTK_BOX(buttonBox), gCloseButton, FALSE, FALSE, 0);
529 gtk_widget_set_can_default(gCloseButton, TRUE);
530 g_signal_connect(gCloseButton, "clicked", G_CALLBACK(CloseClicked), 0);
532 gRestartButton = 0;
533 if (restartArgs.size() > 0) {
534 gRestartButton = gtk_button_new_with_label(gStrings[ST_RESTART].c_str());
535 gtk_box_pack_start(GTK_BOX(buttonBox), gRestartButton, FALSE, FALSE, 0);
536 gtk_widget_set_can_default(gRestartButton, TRUE);
537 g_signal_connect(gRestartButton, "clicked", G_CALLBACK(RestartClicked), 0);
538 }
540 gtk_widget_grab_focus(gSubmitReportCheck);
542 gtk_widget_grab_default(gRestartButton ? gRestartButton : gCloseButton);
544 LoadSettings();
546 UpdateEmail();
547 UpdateSubmit();
549 UpdateHintText(gCommentText, FALSE, &gCommentFieldHint,
550 gStrings[ST_COMMENTGRAYTEXT].c_str());
551 UpdateHintText(gEmailEntry, FALSE, &gEmailFieldHint,
552 gStrings[ST_EMAILGRAYTEXT].c_str());
554 gtk_widget_show_all(gWindow);
555 // stick this here to avoid the show_all above...
556 gtk_widget_hide(gThrobber);
558 gtk_main();
560 return gDidTrySend;
561 }