Index: chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk2.cc |
diff --git a/chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk.cc b/chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk2.cc |
similarity index 88% |
rename from chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk.cc |
rename to chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk2.cc |
index 3fa18cb9ee36abb349919aee36c759825076292e..7768b22c10df4702a8b54ed82957b57b52d76a3c 100644 |
--- a/chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk.cc |
+++ b/chrome/browser/ui/libgtk2ui/select_file_dialog_impl_gtk2.cc |
@@ -2,11 +2,16 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <gdk/gdk.h> |
+#include <gdk/gdkx.h> |
#include <gtk/gtk.h> |
#include <map> |
#include <set> |
#include <vector> |
+// Xlib defines RootWindow |
+#undef RootWindow |
+ |
#include "base/file_util.h" |
#include "base/logging.h" |
#include "base/message_loop.h" |
@@ -15,15 +20,43 @@ |
#include "base/threading/thread.h" |
#include "base/threading/thread_restrictions.h" |
#include "base/utf_string_conversions.h" |
-//#include "chrome/browser/ui/gtk/select_file_dialog_impl.h" |
-#include "chrome/browser/ui/select_file_dialog.h" |
-#include "grit/generated_resources.h" |
-//#include "ui/base/gtk/gtk_signal.h" |
+#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" |
+#include "chrome/browser/ui/libgtk2ui/select_file_dialog_impl.h" |
+#include "grit/ui_strings.h" |
+#include "ui/aura/root_window.h" |
+#include "ui/aura/window_observer.h" |
+#include "ui/base/dialogs/select_file_dialog.h" |
#include "ui/base/l10n/l10n_util.h" |
+namespace { |
+ |
+const char kAuraTransientParent[] = "aura-transient-parent"; |
+ |
+// Set |dialog| as transient for |parent|, which will keep it on top and center |
+// it above |parent|. |
+void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) { |
+ gtk_widget_realize(dialog); |
+ GdkWindow* gdk_window = gtk_widget_get_window(dialog); |
+ |
+ // TODO(erg): Check to make sure we're using X11 if wayland or some other |
+ // display server ever happens. Otherwise, this will crash. |
+ XSetTransientForHint(GDK_WINDOW_XDISPLAY(gdk_window), |
+ GDK_WINDOW_XID(gdk_window), |
+ parent->GetRootWindow()->GetAcceleratedWidget()); |
+ |
+ // We also set the |parent| as a property of |dialog|, so that we can unlink |
+ // the two later. |
+ g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, parent); |
+} |
+ |
+} // namespace |
+ |
+namespace libgtk2ui { |
+ |
// Implementation of SelectFileDialog that shows a Gtk common dialog for |
// choosing a file or folder. This acts as a modal dialog. |
-class SelectFileDialogImplGTK : public SelectFileDialogImpl { |
+class SelectFileDialogImplGTK : public SelectFileDialogImpl, |
+ public aura::WindowObserver { |
public: |
explicit SelectFileDialogImplGTK(Listener* listener, |
ui::SelectFilePolicy* policy); |
@@ -45,6 +78,9 @@ class SelectFileDialogImplGTK : public SelectFileDialogImpl { |
private: |
virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE; |
+ // Overridden from aura::WindowObserver: |
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE; |
+ |
// Add the filters from |file_types_| to |chooser|. |
void AddFilters(GtkFileChooser* chooser); |
@@ -153,6 +189,14 @@ bool SelectFileDialogImplGTK::HasMultipleFileTypeChoicesImpl() { |
return file_types_.extensions.size() > 1; |
} |
+void SelectFileDialogImplGTK::OnWindowDestroying(aura::Window* window) { |
+ std::set<aura::Window*>::iterator iter = parents_.find(window); |
+ if (iter != parents_.end()) { |
+ (*iter)->RemoveObserver(this); |
+ parents_.erase(iter); |
+ } |
+} |
+ |
// We ignore |default_extension|. |
void SelectFileDialogImplGTK::SelectFileImpl( |
Type type, |
@@ -167,8 +211,10 @@ void SelectFileDialogImplGTK::SelectFileImpl( |
// |owning_window| can be null when user right-clicks on a downloadable item |
// and chooses 'Open Link in New Tab' when 'Ask where to save each file |
// before downloading.' preference is turned on. (http://crbug.com/29213) |
- if (owning_window) |
+ if (owning_window) { |
+ owning_window->AddObserver(this); |
parents_.insert(owning_window); |
+ } |
std::string title_string = UTF16ToUTF8(title); |
@@ -211,10 +257,8 @@ void SelectFileDialogImplGTK::SelectFileImpl( |
params_map_[dialog] = params; |
- // Set window-to-parent modality by adding the dialog to the same window |
- // group as the parent. |
- gtk_window_group_add_window(gtk_window_get_group(owning_window), |
- GTK_WINDOW(dialog)); |
+ // TODO(erg): Figure out how to fake GTK window-to-parent modality without |
+ // having the parent be a real GtkWindow. |
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); |
gtk_widget_show_all(dialog); |
@@ -310,11 +354,12 @@ GtkWidget* SelectFileDialogImplGTK::CreateFileOpenHelper( |
const FilePath& default_path, |
gfx::NativeWindow parent) { |
GtkWidget* dialog = |
- gtk_file_chooser_dialog_new(title.c_str(), parent, |
+ gtk_file_chooser_dialog_new(title.c_str(), NULL, |
GTK_FILE_CHOOSER_ACTION_OPEN, |
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, |
NULL); |
+ SetGtkTransientForAura(dialog, parent); |
AddFilters(GTK_FILE_CHOOSER(dialog)); |
if (!default_path.empty()) { |
@@ -342,11 +387,12 @@ GtkWidget* SelectFileDialogImplGTK::CreateSelectFolderDialog( |
l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE); |
GtkWidget* dialog = |
- gtk_file_chooser_dialog_new(title_string.c_str(), parent, |
+ gtk_file_chooser_dialog_new(title_string.c_str(), NULL, |
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, |
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, |
NULL); |
+ SetGtkTransientForAura(dialog, parent); |
if (!default_path.empty()) { |
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), |
@@ -395,11 +441,12 @@ GtkWidget* SelectFileDialogImplGTK::CreateSaveAsDialog(const std::string& title, |
l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE); |
GtkWidget* dialog = |
- gtk_file_chooser_dialog_new(title_string.c_str(), parent, |
+ gtk_file_chooser_dialog_new(title_string.c_str(), NULL, |
GTK_FILE_CHOOSER_ACTION_SAVE, |
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, |
NULL); |
+ SetGtkTransientForAura(dialog, parent); |
AddFilters(GTK_FILE_CHOOSER(dialog)); |
if (!default_path.empty()) { |
@@ -438,14 +485,17 @@ void SelectFileDialogImplGTK::FileDialogDestroyed(GtkWidget* dialog) { |
// windows got destroyed, or 2) when the parent tab has been opened by |
// 'Open Link in New Tab' context menu on a downloadable item and |
// the tab has no content (see the comment in SelectFile as well). |
- GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(dialog)); |
+ aura::Window* parent = reinterpret_cast<aura::Window*>( |
+ g_object_get_data(G_OBJECT(dialog), kAuraTransientParent)); |
if (!parent) |
return; |
- std::set<GtkWindow*>::iterator iter = parents_.find(parent); |
- if (iter != parents_.end()) |
+ std::set<aura::Window*>::iterator iter = parents_.find(parent); |
+ if (iter != parents_.end()) { |
+ (*iter)->RemoveObserver(this); |
parents_.erase(iter); |
- else |
+ } else { |
NOTREACHED(); |
+ } |
} |
bool SelectFileDialogImplGTK::IsCancelResponse(gint response_id) { |
@@ -546,3 +596,5 @@ void SelectFileDialogImplGTK::OnUpdatePreview(GtkWidget* chooser) { |
gtk_file_chooser_set_preview_widget_active(GTK_FILE_CHOOSER(chooser), |
pixbuf ? TRUE : FALSE); |
} |
+ |
+} // namespace libgtk2ui |