summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkuchhal@chromium.org <kuchhal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-14 16:43:15 +0000
committerkuchhal@chromium.org <kuchhal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-14 16:43:15 +0000
commit4f26826dc91e9aa41f3adbda05f94c44581eddd8 (patch)
treef5de5a1b868c8b8d1cfc22c9e44dc77da23ccbae
parent88efb7ec99239eeecaa17d21f8635be1bce29cca (diff)
downloadchromium_src-4f26826dc91e9aa41f3adbda05f94c44581eddd8.zip
chromium_src-4f26826dc91e9aa41f3adbda05f94c44581eddd8.tar.gz
chromium_src-4f26826dc91e9aa41f3adbda05f94c44581eddd8.tar.bz2
Linux: Add first run search bubble.
Review URL: http://codereview.chromium.org/149501 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20625 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/first_run.cc25
-rw-r--r--chrome/browser/first_run_win.cc22
-rw-r--r--chrome/browser/gtk/bookmark_manager_gtk.cc26
-rw-r--r--chrome/browser/gtk/first_run_bubble.cc124
-rw-r--r--chrome/browser/gtk/first_run_bubble.h68
-rw-r--r--chrome/browser/gtk/first_run_dialog.cc13
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc30
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.h5
-rw-r--r--chrome/chrome.gyp2
-rw-r--r--chrome/common/gtk_util.cc21
-rw-r--r--chrome/common/gtk_util.h6
11 files changed, 295 insertions, 47 deletions
diff --git a/chrome/browser/first_run.cc b/chrome/browser/first_run.cc
index f0b0f74..712d3b1 100644
--- a/chrome/browser/first_run.cc
+++ b/chrome/browser/first_run.cc
@@ -15,6 +15,8 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
namespace {
@@ -87,3 +89,26 @@ bool FirstRun::CreateSentinel() {
return false;
return file_util::WriteFile(first_run_sentinel, "", 0) != -1;
}
+
+bool FirstRun::SetShowFirstRunBubblePref() {
+ PrefService* local_state = g_browser_process->local_state();
+ if (!local_state)
+ return false;
+ if (!local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble)) {
+ local_state->RegisterBooleanPref(prefs::kShouldShowFirstRunBubble, false);
+ local_state->SetBoolean(prefs::kShouldShowFirstRunBubble, true);
+ }
+ return true;
+}
+
+bool FirstRun::SetShowWelcomePagePref() {
+ PrefService* local_state = g_browser_process->local_state();
+ if (!local_state)
+ return false;
+ if (!local_state->IsPrefRegistered(prefs::kShouldShowWelcomePage)) {
+ local_state->RegisterBooleanPref(prefs::kShouldShowWelcomePage, false);
+ local_state->SetBoolean(prefs::kShouldShowWelcomePage, true);
+ }
+ return true;
+}
+
diff --git a/chrome/browser/first_run_win.cc b/chrome/browser/first_run_win.cc
index 4e58792..18b0a44 100644
--- a/chrome/browser/first_run_win.cc
+++ b/chrome/browser/first_run_win.cc
@@ -592,17 +592,6 @@ int FirstRun::ImportNow(Profile* profile, const CommandLine& cmdline) {
return observer.import_result();
}
-bool FirstRun::SetShowFirstRunBubblePref() {
- PrefService* local_state = g_browser_process->local_state();
- if (!local_state)
- return false;
- if (!local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble)) {
- local_state->RegisterBooleanPref(prefs::kShouldShowFirstRunBubble, false);
- local_state->SetBoolean(prefs::kShouldShowFirstRunBubble, true);
- }
- return true;
-}
-
bool FirstRun::SetOEMFirstRunBubblePref() {
PrefService* local_state = g_browser_process->local_state();
if (!local_state)
@@ -615,17 +604,6 @@ bool FirstRun::SetOEMFirstRunBubblePref() {
return true;
}
-bool FirstRun::SetShowWelcomePagePref() {
- PrefService* local_state = g_browser_process->local_state();
- if (!local_state)
- return false;
- if (!local_state->IsPrefRegistered(prefs::kShouldShowWelcomePage)) {
- local_state->RegisterBooleanPref(prefs::kShouldShowWelcomePage, false);
- local_state->SetBoolean(prefs::kShouldShowWelcomePage, true);
- }
- return true;
-}
-
//////////////////////////////////////////////////////////////////////////
namespace {
diff --git a/chrome/browser/gtk/bookmark_manager_gtk.cc b/chrome/browser/gtk/bookmark_manager_gtk.cc
index 77a7c6a..dab3508 100644
--- a/chrome/browser/gtk/bookmark_manager_gtk.cc
+++ b/chrome/browser/gtk/bookmark_manager_gtk.cc
@@ -329,28 +329,12 @@ void BookmarkManagerGtk::InitWidgets() {
l10n_util::GetStringUTF8(IDS_BOOKMARK_MANAGER_TITLE).c_str());
// Set the default size of the bookmark manager.
- // Windows has code to do this that uses ChromeFont; we could share it but
- // since we don't plan to use it elsewhere it's probably not worth the effort.
- PangoContext* context = gtk_widget_create_pango_context(window_);
- PangoFontMetrics* metrics =
- pango_context_get_metrics(context, window_->style->font_desc,
- pango_context_get_language(context));
- double chars = 0;
- StringToDouble(WideToUTF8(l10n_util::GetString(
- IDS_BOOKMARK_MANAGER_DIALOG_WIDTH_CHARS)), &chars);
- int width =
- pango_font_metrics_get_approximate_char_width(metrics) *
- static_cast<int>(chars) / PANGO_SCALE;
- double lines = 0;
- StringToDouble(WideToUTF8(l10n_util::GetString(
- IDS_BOOKMARK_MANAGER_DIALOG_HEIGHT_LINES)), &lines);
- int height =
- (pango_font_metrics_get_ascent(metrics) +
- pango_font_metrics_get_descent(metrics)) *
- static_cast<int>(lines) / PANGO_SCALE;
+ int width, height;
+ gtk_util::GetWidgetSizeFromResources(window_,
+ IDS_BOOKMARK_MANAGER_DIALOG_WIDTH_CHARS,
+ IDS_BOOKMARK_MANAGER_DIALOG_HEIGHT_LINES,
+ &width, &height);
gtk_window_set_default_size(GTK_WINDOW(window_), width, height);
- pango_font_metrics_unref(metrics);
- g_object_unref(context);
// Build the organize and tools menus.
organize_ = gtk_menu_item_new_with_label(
diff --git a/chrome/browser/gtk/first_run_bubble.cc b/chrome/browser/gtk/first_run_bubble.cc
new file mode 100644
index 0000000..05287a8
--- /dev/null
+++ b/chrome/browser/gtk/first_run_bubble.cc
@@ -0,0 +1,124 @@
+// 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_bubble.h"
+
+#include <gtk/gtk.h>
+
+#include "app/l10n_util.h"
+#include "chrome/browser/options_window.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/common/gtk_util.h"
+#include "grit/generated_resources.h"
+#include "grit/google_chrome_strings.h"
+
+namespace {
+// Markup for the text of the Omnibox search label
+const char kSearchLabelMarkup[] = "<big><b>%s</b></big>";
+
+// Padding for the buttons on first run bubble.
+const int kButtonPadding = 4;
+
+string16 GetDefaultSearchEngineName(Profile* profile) {
+ if (!profile) {
+ NOTREACHED();
+ return string16();
+ }
+ const TemplateURL* const default_provider =
+ profile->GetTemplateURLModel()->GetDefaultSearchProvider();
+ if (!default_provider) {
+ return string16();
+ }
+ return WideToUTF16(default_provider->short_name());
+}
+} // namespace
+
+// static
+void FirstRunBubble::Show(Profile* profile,
+ GtkWindow* parent,
+ const gfx::Rect& rect,
+ bool use_OEM_bubble) {
+ new FirstRunBubble(profile, parent, rect);
+}
+
+void FirstRunBubble::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
+ bool closed_by_escape) {
+ // TODO(port): Enable parent window
+}
+
+FirstRunBubble::FirstRunBubble(Profile* profile,
+ GtkWindow* parent,
+ const gfx::Rect& rect)
+ : profile_(profile),
+ parent_(parent),
+ content_(NULL),
+ bubble_(NULL) {
+ GtkWidget* label1 = gtk_label_new(NULL);
+ char* markup = g_markup_printf_escaped(kSearchLabelMarkup,
+ l10n_util::GetStringUTF8(IDS_FR_BUBBLE_TITLE).c_str());
+ gtk_label_set_markup(GTK_LABEL(label1), markup);
+ g_free(markup);
+ gtk_misc_set_alignment(GTK_MISC(label1), 0, .5);
+
+ GtkWidget* label2 = gtk_label_new(
+ l10n_util::GetStringUTF8(IDS_FR_BUBBLE_SUBTEXT).c_str());
+ gtk_misc_set_alignment(GTK_MISC(label2), 0, .5);
+ gtk_label_set_line_wrap(GTK_LABEL(label2), TRUE);
+
+ string16 search_engine = GetDefaultSearchEngineName(profile_);
+ GtkWidget* label3 = gtk_label_new(
+ l10n_util::GetStringFUTF8(IDS_FR_BUBBLE_QUESTION, search_engine).c_str());
+ gtk_misc_set_alignment(GTK_MISC(label3), 0, .5);
+ gtk_label_set_line_wrap(GTK_LABEL(label3), TRUE);
+
+ GtkWidget* keep_button = gtk_button_new_with_label(
+ l10n_util::GetStringFUTF8(IDS_FR_BUBBLE_OK, search_engine).c_str());
+ GtkWidget* change_button = gtk_button_new_with_label(
+ l10n_util::GetStringUTF8(IDS_FR_BUBBLE_CHANGE).c_str());
+
+ content_ = gtk_vbox_new(FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(content_), label1, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(content_), label2, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(content_), label3, TRUE, TRUE, 0);
+
+ GtkWidget* bottom = gtk_hbox_new(FALSE, 0);
+ // We want the buttons on the right, so just use an expanding label to fill
+ // all of the extra space on the right.
+ gtk_box_pack_start(GTK_BOX(bottom), gtk_label_new(""), TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(bottom), keep_button, FALSE, FALSE,
+ kButtonPadding);
+ gtk_box_pack_start(GTK_BOX(bottom), change_button, FALSE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(content_), bottom, TRUE, TRUE, 0);
+ // We want the focus to start on the keep entry, not on the change button.
+ gtk_container_set_focus_child(GTK_CONTAINER(content_), keep_button);
+
+ bubble_ = InfoBubbleGtk::Show(parent_, rect, content_, this);
+ if (!bubble_) {
+ NOTREACHED();
+ return;
+ }
+
+ g_signal_connect(content_, "destroy",
+ G_CALLBACK(&HandleDestroyThunk), this);
+ g_signal_connect(keep_button, "clicked",
+ G_CALLBACK(&HandleKeepButtonThunk), this);
+ g_signal_connect(change_button, "clicked",
+ G_CALLBACK(&HandleChangeButtonThunk), this);
+}
+
+void FirstRunBubble::HandleChangeButton() {
+ bubble_->Close();
+ ShowOptionsWindow(OPTIONS_PAGE_GENERAL, OPTIONS_GROUP_DEFAULT_SEARCH,
+ profile_);
+}
+
+void FirstRunBubble::HandleDestroy() {
+ content_ = NULL;
+ delete this;
+}
+
+void FirstRunBubble::HandleKeepButton() {
+ bubble_->Close();
+}
diff --git a/chrome/browser/gtk/first_run_bubble.h b/chrome/browser/gtk/first_run_bubble.h
new file mode 100644
index 0000000..6e7c817
--- /dev/null
+++ b/chrome/browser/gtk/first_run_bubble.h
@@ -0,0 +1,68 @@
+// 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.
+
+// This is the GTK implementation of the First Run bubble, the dialog box
+// presented on first run of Chromium. There can only ever be a single
+// bubble open, so the class presents only static methods.
+
+#ifndef CHROME_BROWSER_GTK_FIRST_RUN_BUBBLE_GTK_H_
+#define CHROME_BROWSER_GTK_FIRST_RUN_BUBBLE_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include "base/basictypes.h"
+#include "chrome/browser/gtk/info_bubble_gtk.h"
+#include "chrome/browser/profile.h"
+
+class FirstRunBubble : public InfoBubbleGtkDelegate {
+ public:
+ // Shows the first run bubble, pointing at |rect|.
+ static void Show(Profile* profile,
+ GtkWindow* parent,
+ const gfx::Rect& rect,
+ bool use_OEM_bubble);
+
+ // Implements the InfoBubbleGtkDelegate. We are notified when the bubble
+ // is about to be closed.
+ virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble,
+ bool closed_by_escape);
+ virtual bool CloseOnEscape() { return true; }
+
+ private:
+ FirstRunBubble(Profile* profile,
+ GtkWindow* parent,
+ const gfx::Rect& rect);
+ ~FirstRunBubble() { }
+
+ static void HandleChangeButtonThunk(GtkWidget* widget, gpointer user_data) {
+ reinterpret_cast<FirstRunBubble*>(user_data)->HandleChangeButton();
+ }
+ void HandleChangeButton();
+
+ static void HandleDestroyThunk(GtkWidget* widget, gpointer userdata) {
+ reinterpret_cast<FirstRunBubble*>(userdata)->HandleDestroy();
+ }
+ void HandleDestroy();
+
+ static void HandleKeepButtonThunk(GtkWidget* widget, gpointer user_data) {
+ reinterpret_cast<FirstRunBubble*>(user_data)->HandleKeepButton();
+ }
+ void HandleKeepButton();
+
+ // Our current profile.
+ Profile* profile_;
+
+ // The toplevel window our dialogs should be transient for.
+ GtkWindow* parent_;
+
+ // We let the InfoBubble own our content, and then we delete ourself
+ // when the widget is destroyed (when the InfoBubble is destroyed).
+ GtkWidget* content_;
+
+ InfoBubbleGtk* bubble_;
+
+ DISALLOW_COPY_AND_ASSIGN(FirstRunBubble);
+};
+
+#endif // CHROME_BROWSER_GTK_FIRST_RUN_BUBBLE_GTK_H_
diff --git a/chrome/browser/gtk/first_run_dialog.cc b/chrome/browser/gtk/first_run_dialog.cc
index 2646b6f..f7a104f 100644
--- a/chrome/browser/gtk/first_run_dialog.cc
+++ b/chrome/browser/gtk/first_run_dialog.cc
@@ -13,6 +13,7 @@
#include "chrome/installer/util/google_update_settings.h"
#include "grit/generated_resources.h"
#include "grit/google_chrome_strings.h"
+#include "grit/locale_settings.h"
// static
bool FirstRunDialog::Show(Profile* profile) {
@@ -35,6 +36,12 @@ FirstRunDialog::FirstRunDialog(Profile* profile, int& response)
GTK_RESPONSE_REJECT,
NULL);
gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE);
+ int width, height;
+ gtk_util::GetWidgetSizeFromResources(dialog_,
+ IDS_FIRSTRUN_DIALOG_WIDTH_CHARS,
+ IDS_FIRSTRUN_DIALOG_HEIGHT_LINES,
+ &width, &height);
+ gtk_window_set_default_size(GTK_WINDOW(dialog_), width, height);
g_signal_connect(G_OBJECT(dialog_), "delete-event",
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
@@ -42,8 +49,6 @@ FirstRunDialog::FirstRunDialog(Profile* profile, int& response)
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, 350, -1);
#if defined(GOOGLE_CHROME_BUILD)
// TODO(port): remove this warning before beta release when we have all the
@@ -149,6 +154,10 @@ void FirstRunDialog::OnDialogResponse(GtkWidget* widget, int response) {
}
}
+ // Set preference to show first run bubble and welcome page.
+ FirstRun::SetShowFirstRunBubblePref();
+ FirstRun::SetShowWelcomePagePref();
+
gtk_widget_destroy(dialog_);
MessageLoop::current()->Quit();
}
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
index 08eb6fc..38c2901 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/alternate_nav_url_fetcher.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
#include "chrome/browser/command_updater.h"
+#include "chrome/browser/gtk/first_run_bubble.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
@@ -36,6 +37,11 @@ const int kBottomMargin = 1;
// We draw a border on the top and bottom (but not on left or right).
const int kBorderThickness = 1;
+// Left margin of first run bubble.
+const int kFirstRunBubbleLeftMargin = 20;
+// Task delay (in milliseconds) to show first run bubble.
+const int kFirstRunBubbleTaskDelay = 30;
+
// Left and right padding/margin.
// no icon/text : 4px url_text 4px
// [4px|url text|4px] <hide ssl icon> <hide ev text>
@@ -103,7 +109,8 @@ LocationBarViewGtk::LocationBarViewGtk(CommandUpdater* command_updater,
toolbar_model_(toolbar_model),
popup_positioner_(popup_positioner),
disposition_(CURRENT_TAB),
- transition_(PageTransition::TYPED) {
+ transition_(PageTransition::TYPED),
+ first_run_bubble_(this) {
}
LocationBarViewGtk::~LocationBarViewGtk() {
@@ -308,7 +315,10 @@ std::wstring LocationBarViewGtk::GetTitle() const {
}
void LocationBarViewGtk::ShowFirstRunBubble(bool use_OEM_bubble) {
- NOTIMPLEMENTED();
+ Task* task = first_run_bubble_.NewRunnableMethod(
+ &LocationBarViewGtk::ShowFirstRunBubbleInternal, use_OEM_bubble);
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, task,
+ kFirstRunBubbleTaskDelay);
}
std::wstring LocationBarViewGtk::GetInputString() const {
@@ -491,3 +501,19 @@ void LocationBarViewGtk::SetKeywordHintLabel(const std::wstring& keyword) {
gtk_label_set_text(GTK_LABEL(tab_to_search_hint_trailing_label_),
trailing.c_str());
}
+
+void LocationBarViewGtk::ShowFirstRunBubbleInternal(bool use_OEM_bubble) {
+ if (!location_entry_.get() || !widget()->window)
+ return;
+
+ gint x, y;
+ gdk_window_get_origin(widget()->window, &x, &y);
+ // The bubble needs to be just below the Omnibox and slightly to the right
+ // of star button, so shift x and y co-ordinates.
+ x += widget()->allocation.x + kFirstRunBubbleLeftMargin;
+ y += widget()->allocation.y + widget()->allocation.height;
+
+ FirstRunBubble::Show(profile_,
+ GTK_WINDOW(gtk_widget_get_toplevel(widget())),
+ gfx::Rect(x, y, 0, 0), use_OEM_bubble);
+}
diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h
index 3ccbbb2..f3cafd2 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.h
+++ b/chrome/browser/gtk/location_bar_view_gtk.h
@@ -102,6 +102,8 @@ class LocationBarViewGtk : public AutocompleteEditController,
// Set the keyword text for the "Press tab to search BLAH" hint box.
void SetKeywordHintLabel(const std::wstring& keyword);
+ void ShowFirstRunBubbleInternal(bool use_OEM_bubble);
+
// The outermost widget we want to be hosted.
OwnedWidgetGtk hbox_;
@@ -141,6 +143,9 @@ class LocationBarViewGtk : public AutocompleteEditController,
// The transition type to use for the navigation.
PageTransition::Type transition_;
+ // Used schedule a task for the first run info bubble.
+ ScopedRunnableMethodFactory<LocationBarViewGtk> first_run_bubble_;
+
DISALLOW_COPY_AND_ASSIGN(LocationBarViewGtk);
};
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 5a62435..4a55ddd 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1026,6 +1026,8 @@
'browser/gtk/download_started_animation_gtk.cc',
'browser/gtk/edit_search_engine_dialog.cc',
'browser/gtk/edit_search_engine_dialog.h',
+ 'browser/gtk/first_run_bubble.cc',
+ 'browser/gtk/first_run_bubble.h',
'browser/gtk/first_run_dialog.cc',
'browser/gtk/first_run_dialog.h',
'browser/gtk/go_button_gtk.cc',
diff --git a/chrome/common/gtk_util.cc b/chrome/common/gtk_util.cc
index e985bf6..8b7dfd8 100644
--- a/chrome/common/gtk_util.cc
+++ b/chrome/common/gtk_util.cc
@@ -178,6 +178,27 @@ GtkWidget* CreateGtkBorderBin(GtkWidget* child, const GdkColor* color,
return ebox;
}
+bool GetWidgetSizeFromResources(GtkWidget* widget, int width_chars,
+ int height_lines, int* width, int* height) {
+ PangoContext* context = gtk_widget_create_pango_context(widget);
+ PangoFontMetrics* metrics = pango_context_get_metrics(context,
+ widget->style->font_desc, pango_context_get_language(context));
+ double chars = 0;
+ StringToDouble(l10n_util::GetStringUTF8(width_chars), &chars);
+ *width =
+ pango_font_metrics_get_approximate_char_width(metrics) *
+ static_cast<int>(chars) / PANGO_SCALE;
+ double lines = 0;
+ StringToDouble(l10n_util::GetStringUTF8(height_lines), &lines);
+ *height =
+ (pango_font_metrics_get_ascent(metrics) +
+ pango_font_metrics_get_descent(metrics)) *
+ static_cast<int>(lines) / PANGO_SCALE;
+ pango_font_metrics_unref(metrics);
+ g_object_unref(context);
+ return true;
+}
+
void RemoveAllChildren(GtkWidget* container) {
gtk_container_foreach(GTK_CONTAINER(container), RemoveWidget, container);
}
diff --git a/chrome/common/gtk_util.h b/chrome/common/gtk_util.h
index 983cf4a..85bcc4b 100644
--- a/chrome/common/gtk_util.h
+++ b/chrome/common/gtk_util.h
@@ -62,6 +62,12 @@ GtkWidget* CreateLabeledControlsGroup(const char* text, ...);
GtkWidget* CreateGtkBorderBin(GtkWidget* child, const GdkColor* color,
int top, int bottom, int left, int right);
+// Calculates the size of given widget based on the size specified in
+// number of characters/lines (in locale specific resource file) and
+// font metrics.
+bool GetWidgetSizeFromResources(GtkWidget* widget, int width_chars,
+ int height_lines, int* width, int* height);
+
// Remove all children from this container.
void RemoveAllChildren(GtkWidget* container);