Index: ui/base/clipboard/clipboard_gtk.cc |
diff --git a/ui/base/clipboard/clipboard_gtk.cc b/ui/base/clipboard/clipboard_gtk.cc |
index f51ba8a1a996d0581135f148d3b7a781dbbf4b39..e9af2f330d8fd5d95480ffb031ea595b1610ea36 100644 |
--- a/ui/base/clipboard/clipboard_gtk.cc |
+++ b/ui/base/clipboard/clipboard_gtk.cc |
@@ -5,6 +5,8 @@ |
#include "ui/base/clipboard/clipboard.h" |
#include <gtk/gtk.h> |
+#include <X11/extensions/Xfixes.h> |
+#include <X11/Xatom.h> |
#include <map> |
#include <set> |
#include <string> |
@@ -12,9 +14,11 @@ |
#include "base/file_path.h" |
#include "base/logging.h" |
-#include "base/memory/scoped_ptr.h" |
+#include "base/memory/singleton.h" |
#include "base/utf_string_conversions.h" |
#include "third_party/skia/include/core/SkBitmap.h" |
+#include "ui/base/gtk/gtk_signal.h" |
+#include "ui/base/x/x11_util.h" |
#include "ui/gfx/canvas_skia.h" |
#include "ui/gfx/gtk_util.h" |
#include "ui/gfx/size.h" |
@@ -23,6 +27,82 @@ namespace ui { |
namespace { |
+class SelectionChangeObserver { |
+ public: |
+ static SelectionChangeObserver* GetInstance(); |
+ |
+ uint64 clipboard_sequence_number() const { |
+ return clipboard_sequence_number_; |
+ } |
+ uint64 primary_sequence_number() const { return primary_sequence_number_; } |
+ |
+ private: |
+ friend struct DefaultSingletonTraits<SelectionChangeObserver>; |
+ |
+ SelectionChangeObserver(); |
+ ~SelectionChangeObserver(); |
+ |
+ CHROMEG_CALLBACK_1(SelectionChangeObserver, GdkFilterReturn, OnXEvent, |
+ GdkXEvent*, GdkEvent*); |
+ |
+ int event_base_; |
+ Atom clipboard_atom_; |
+ uint64 clipboard_sequence_number_; |
+ uint64 primary_sequence_number_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver); |
+}; |
+ |
+SelectionChangeObserver::SelectionChangeObserver() |
+ : event_base_(-1), |
+ clipboard_atom_(None), |
+ clipboard_sequence_number_(0), |
+ primary_sequence_number_(0) { |
+ int ignored; |
+ if (XFixesQueryExtension(GetXDisplay(), &event_base_, &ignored)) { |
+ clipboard_atom_ = XInternAtom(GetXDisplay(), "CLIPBOARD", false); |
+ XFixesSelectSelectionInput(GetXDisplay(), GetX11RootWindow(), |
+ clipboard_atom_, |
+ XFixesSetSelectionOwnerNotifyMask | |
+ XFixesSelectionWindowDestroyNotifyMask | |
+ XFixesSelectionClientCloseNotifyMask); |
+ // This seems to be semi-optional. For some reason, registering for any |
+ // selection notify events seems to subscribe us to events for both the |
+ // primary and the clipboard buffers. Register anyway just to be safe. |
+ XFixesSelectSelectionInput(GetXDisplay(), GetX11RootWindow(), |
+ XA_PRIMARY, |
+ XFixesSetSelectionOwnerNotifyMask | |
+ XFixesSelectionWindowDestroyNotifyMask | |
+ XFixesSelectionClientCloseNotifyMask); |
+ gdk_window_add_filter(NULL, &SelectionChangeObserver::OnXEventThunk, this); |
+ } |
+} |
+ |
+SelectionChangeObserver::~SelectionChangeObserver() { |
+} |
+ |
+SelectionChangeObserver* SelectionChangeObserver::GetInstance() { |
+ return Singleton<SelectionChangeObserver>::get(); |
+} |
+ |
+GdkFilterReturn SelectionChangeObserver::OnXEvent(GdkXEvent* xevent, |
+ GdkEvent* event) { |
+ XEvent* xev = static_cast<XEvent*>(xevent); |
+ |
+ if (xev->type == event_base_ + XFixesSelectionNotify) { |
+ XFixesSelectionNotifyEvent* ev = |
+ reinterpret_cast<XFixesSelectionNotifyEvent*>(xev); |
+ if (ev->selection == clipboard_atom_) { |
+ clipboard_sequence_number_++; |
+ } else if (ev->selection == XA_PRIMARY) { |
+ primary_sequence_number_++; |
+ } else { |
+ DLOG(ERROR) << "Unexpected selection atom: " << ev->selection; |
+ } |
+ } |
+ return GDK_FILTER_CONTINUE; |
+} |
+ |
const char kMimeTypeBitmap[] = "image/bmp"; |
const char kMimeTypeMozillaURL[] = "text/x-moz-url"; |
const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; |
@@ -423,10 +503,10 @@ void Clipboard::ReadData(const std::string& format, std::string* result) { |
} |
uint64 Clipboard::GetSequenceNumber(Buffer buffer) { |
- // TODO(cdn): implement this. For now this interface will advertise |
- // that the Linux clipboard never changes. That's fine as long as we |
- // don't rely on this signal. |
- return 0; |
+ if (buffer == BUFFER_STANDARD) |
+ return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); |
+ else |
+ return SelectionChangeObserver::GetInstance()->primary_sequence_number(); |
} |
// static |