Backed out 3 changesets (bug 1870106, bug 1845276) for causing doc generate failures...
[gecko.git] / widget / gtk / nsClipboardX11.cpp
blobfc82e0dd8d05179f1c39b4d663bf6e73f3dcafaf
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/ArrayUtils.h"
10 #include "AsyncGtkClipboardRequest.h"
11 #include "nsClipboardX11.h"
12 #include "mozilla/RefPtr.h"
13 #include "mozilla/TimeStamp.h"
14 #include "mozilla/WidgetUtilsGtk.h"
16 #include <gtk/gtk.h>
18 // For manipulation of the X event queue
19 #include <X11/Xlib.h>
20 #include <poll.h>
21 #include <gdk/gdkx.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include "X11UndefineNone.h"
28 using namespace mozilla;
30 nsRetrievalContextX11::nsRetrievalContextX11() = default;
32 static void DispatchSelectionNotifyEvent(GtkWidget* widget, XEvent* xevent) {
33 GdkEvent event = {};
34 event.selection.type = GDK_SELECTION_NOTIFY;
35 event.selection.window = gtk_widget_get_window(widget);
36 event.selection.selection =
37 gdk_x11_xatom_to_atom(xevent->xselection.selection);
38 event.selection.target = gdk_x11_xatom_to_atom(xevent->xselection.target);
39 event.selection.property = gdk_x11_xatom_to_atom(xevent->xselection.property);
40 event.selection.time = xevent->xselection.time;
42 gtk_widget_event(widget, &event);
45 static void DispatchPropertyNotifyEvent(GtkWidget* widget, XEvent* xevent) {
46 GdkWindow* window = gtk_widget_get_window(widget);
47 if ((gdk_window_get_events(window)) & GDK_PROPERTY_CHANGE_MASK) {
48 GdkEvent event = {};
49 event.property.type = GDK_PROPERTY_NOTIFY;
50 event.property.window = window;
51 event.property.atom = gdk_x11_xatom_to_atom(xevent->xproperty.atom);
52 event.property.time = xevent->xproperty.time;
53 event.property.state = xevent->xproperty.state;
55 gtk_widget_event(widget, &event);
59 struct checkEventContext {
60 GtkWidget* cbWidget;
61 Atom selAtom;
64 static Bool checkEventProc(Display* display, XEvent* event, XPointer arg) {
65 checkEventContext* context = (checkEventContext*)arg;
67 if (event->xany.type == SelectionNotify ||
68 (event->xany.type == PropertyNotify &&
69 event->xproperty.atom == context->selAtom)) {
70 GdkWindow* cbWindow = gdk_x11_window_lookup_for_display(
71 gdk_x11_lookup_xdisplay(display), event->xany.window);
72 if (cbWindow) {
73 GtkWidget* cbWidget = nullptr;
74 gdk_window_get_user_data(cbWindow, (gpointer*)&cbWidget);
75 if (cbWidget && GTK_IS_WIDGET(cbWidget)) {
76 context->cbWidget = cbWidget;
77 return X11True;
82 return X11False;
85 ClipboardData nsRetrievalContextX11::WaitForClipboardData(
86 ClipboardDataType aDataType, int32_t aWhichClipboard,
87 const char* aMimeType) {
88 AsyncGtkClipboardRequest request(aDataType, aWhichClipboard, aMimeType);
89 if (request.HasCompleted()) {
90 // the request completed synchronously
91 return request.TakeResult();
94 GdkDisplay* gdkDisplay = gdk_display_get_default();
95 // gdk_display_get_default() returns null on headless
96 if (widget::GdkIsX11Display(gdkDisplay)) {
97 Display* xDisplay = GDK_DISPLAY_XDISPLAY(gdkDisplay);
98 checkEventContext context;
99 context.cbWidget = nullptr;
100 context.selAtom =
101 gdk_x11_atom_to_xatom(gdk_atom_intern("GDK_SELECTION", FALSE));
103 // Send X events which are relevant to the ongoing selection retrieval
104 // to the clipboard widget. Wait until either the operation completes, or
105 // we hit our timeout. All other X events remain queued.
107 int poll_result;
109 struct pollfd pfd;
110 pfd.fd = ConnectionNumber(xDisplay);
111 pfd.events = POLLIN;
112 TimeStamp start = TimeStamp::Now();
114 do {
115 XEvent xevent;
117 while (XCheckIfEvent(xDisplay, &xevent, checkEventProc,
118 (XPointer)&context)) {
119 if (xevent.xany.type == SelectionNotify)
120 DispatchSelectionNotifyEvent(context.cbWidget, &xevent);
121 else
122 DispatchPropertyNotifyEvent(context.cbWidget, &xevent);
124 if (request.HasCompleted()) {
125 return request.TakeResult();
129 TimeStamp now = TimeStamp::Now();
130 int timeout = std::max<int>(
131 0, kClipboardTimeout / 1000 - (now - start).ToMilliseconds());
132 poll_result = poll(&pfd, 1, timeout);
133 } while ((poll_result == 1 && (pfd.revents & (POLLHUP | POLLERR)) == 0) ||
134 (poll_result == -1 && errno == EINTR));
137 LOGCLIP("exceeded clipboard timeout");
138 return {};
141 ClipboardTargets nsRetrievalContextX11::GetTargetsImpl(
142 int32_t aWhichClipboard) {
143 LOGCLIP("nsRetrievalContextX11::GetTargetsImpl(%s)\n",
144 aWhichClipboard == nsClipboard::kSelectionClipboard ? "primary"
145 : "clipboard");
146 return WaitForClipboardData(ClipboardDataType::Targets, aWhichClipboard)
147 .ExtractTargets();
150 ClipboardData nsRetrievalContextX11::GetClipboardData(const char* aMimeType,
151 int32_t aWhichClipboard) {
152 LOGCLIP("nsRetrievalContextX11::GetClipboardData(%s) MIME %s\n",
153 aWhichClipboard == nsClipboard::kSelectionClipboard ? "primary"
154 : "clipboard",
155 aMimeType);
157 return WaitForClipboardData(ClipboardDataType::Data, aWhichClipboard,
158 aMimeType);
161 GUniquePtr<char> nsRetrievalContextX11::GetClipboardText(
162 int32_t aWhichClipboard) {
163 LOGCLIP("nsRetrievalContextX11::GetClipboardText(%s)\n",
164 aWhichClipboard == nsClipboard::kSelectionClipboard ? "primary"
165 : "clipboard");
167 return WaitForClipboardData(ClipboardDataType::Text, aWhichClipboard)
168 .ExtractText();