ac2f84c2ef8866c03c06f16dc2159ffea997cdc8
[WebKit-https.git] / Source / WebCore / platform / gtk / GtkVersioning.c
1 /*
2  * Copyright (C) 2010 Collabora Ltd.
3  * Copyright (C) 2010 Igalia, S.L.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public License
16  *  along with this library; see the file COPYING.LIB.  If not, write to
17  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  *  Boston, MA 02110-1301, USA.
19  */
20
21 #include "GtkVersioning.h"
22
23 #include <gtk/gtk.h>
24
25 #ifdef GDK_WINDOWING_X11
26 #include <X11/Xatom.h>
27 #include <gdk/gdkx.h>
28 #endif
29
30 #if !GTK_CHECK_VERSION(2, 14, 0)
31 void gtk_adjustment_set_value(GtkAdjustment* adjusment, gdouble value)
32 {
33         m_adjustment->value = m_currentPos;
34         gtk_adjustment_value_changed(m_adjustment);
35 }
36
37 void gtk_adjustment_configure(GtkAdjustment* adjustment, gdouble value, gdouble lower, gdouble upper,
38                               gdouble stepIncrement, gdouble pageIncrement, gdouble pageSize)
39 {
40     g_object_freeze_notify(G_OBJECT(adjustment));
41
42     g_object_set(adjustment,
43                  "lower", lower,
44                  "upper", upper,
45                  "step-increment", stepIncrement,
46                  "page-increment", pageIncrement,
47                  "page-size", pageSize,
48                  NULL);
49
50     g_object_thaw_notify(G_OBJECT(adjustment));
51
52     gtk_adjustment_changed(adjustment);
53     gtk_adjustment_value_changed(adjustment);
54 }
55 #endif
56
57 GdkDevice *getDefaultGDKPointerDevice(GdkWindow* window)
58 {
59 #ifndef GTK_API_VERSION_2
60     GdkDeviceManager *manager =  gdk_display_get_device_manager(gdk_window_get_display(window));
61     return gdk_device_manager_get_client_pointer(manager);
62 #else
63     return gdk_device_get_core_pointer();
64 #endif // GTK_API_VERSION_2
65 }
66
67 #if !GTK_CHECK_VERSION(2, 17, 3)
68 void gdk_window_get_root_coords(GdkWindow* window, gint x, gint y, gint* rootX, gint* rootY)
69 {
70     gdk_window_get_root_origin(window, rootX, rootY);
71     *rootX = *rootX + x;
72     *rootY = *rootY + y;
73 }
74 #endif
75
76 GdkCursor * blankCursor()
77 {
78 #if GTK_CHECK_VERSION(2, 16, 0)
79     return gdk_cursor_new(GDK_BLANK_CURSOR);
80 #else
81     GdkCursor * cursor;
82     GdkPixmap * source;
83     GdkPixmap * mask;
84     GdkColor foreground = { 0, 65535, 0, 0 }; // Red.
85     GdkColor background = { 0, 0, 0, 65535 }; // Blue.
86     static gchar cursorBits[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
87
88     source = gdk_bitmap_create_from_data(0, cursorBits, 8, 8);
89     mask = gdk_bitmap_create_from_data(0, cursorBits, 8, 8);
90     cursor = gdk_cursor_new_from_pixmap(source, mask, &foreground, &background, 8, 8);
91     gdk_pixmap_unref(source);
92     gdk_pixmap_unref(mask);
93     return cursor;
94 #endif // GTK_CHECK_VERSION(2, 16, 0)
95 }
96
97 #if !GTK_CHECK_VERSION(2, 16, 0)
98 const gchar* gtk_menu_item_get_label(GtkMenuItem* menuItem)
99 {
100     GtkWidget * label = gtk_bin_get_child(GTK_BIN(menuItem));
101     if (GTK_IS_LABEL(label))
102         return gtk_label_get_text(GTK_LABEL(label));
103     return 0;
104 }
105 #endif // GTK_CHECK_VERSION(2, 16, 0)
106
107 #ifdef GTK_API_VERSION_2
108 static cairo_format_t
109 gdk_cairo_format_for_content(cairo_content_t content)
110 {
111     switch (content) {
112     case CAIRO_CONTENT_COLOR:
113         return CAIRO_FORMAT_RGB24;
114     case CAIRO_CONTENT_ALPHA:
115         return CAIRO_FORMAT_A8;
116     case CAIRO_CONTENT_COLOR_ALPHA:
117     default:
118         return CAIRO_FORMAT_ARGB32;
119     }
120 }
121
122 static cairo_surface_t*
123 gdk_cairo_surface_coerce_to_image(cairo_surface_t* surface,
124                                   cairo_content_t content,
125                                   int width,
126                                   int height)
127 {
128     cairo_surface_t * copy;
129     cairo_t * cr;
130
131     if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE
132         && cairo_surface_get_content(surface) == content
133         && cairo_image_surface_get_width(surface) >= width
134         && cairo_image_surface_get_height(surface) >= height)
135         return cairo_surface_reference(surface);
136
137     copy = cairo_image_surface_create(gdk_cairo_format_for_content(content),
138                                       width,
139                                       height);
140
141     cr = cairo_create(copy);
142     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
143     cairo_set_source_surface(cr, surface, 0, 0);
144     cairo_paint(cr);
145     cairo_destroy(cr);
146
147     return copy;
148 }
149
150 static void
151 convert_alpha(guchar * destData, int destStride,
152               guchar * srcData, int srcStride,
153               int srcX, int srcY, int width, int height)
154 {
155     int x, y;
156
157     srcData += srcStride * srcY + srcY * 4;
158
159     for (y = 0; y < height; y++) {
160         guint32 * src = (guint32 *) srcData;
161
162         for (x = 0; x < width; x++) {
163             guint alpha = src[x] >> 24;
164
165             if (!alpha) {
166                 destData[x * 4 + 0] = 0;
167                 destData[x * 4 + 1] = 0;
168                 destData[x * 4 + 2] = 0;
169             } else {
170                 destData[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
171                 destData[x * 4 + 1] = (((src[x] & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
172                 destData[x * 4 + 2] = (((src[x] & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
173             }
174             destData[x * 4 + 3] = alpha;
175         }
176
177         srcData += srcStride;
178         destData += destStride;
179     }
180 }
181
182 static void
183 convert_no_alpha(guchar * destData, int destStride, guchar * srcData,
184                  int srcStride, int srcX, int srcY,
185                  int width, int height)
186 {
187     int x, y;
188
189     srcData += srcStride * srcY + srcX * 4;
190
191     for (y = 0; y < height; y++) {
192         guint32 * src = (guint32 *) srcData;
193
194         for (x = 0; x < width; x++) {
195             destData[x * 3 + 0] = src[x] >> 16;
196             destData[x * 3 + 1] = src[x] >>  8;
197             destData[x * 3 + 2] = src[x];
198         }
199
200         srcData += srcStride;
201         destData += destStride;
202     }
203 }
204
205 /**
206  * gdk_pixbuf_get_from_surface:
207  * @surface: surface to copy from
208  * @src_x: Source X coordinate within @surface
209  * @src_y: Source Y coordinate within @surface
210  * @width: Width in pixels of region to get
211  * @height: Height in pixels of region to get
212  *
213  * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
214  * representation inside a #GdkPixbuf. This allows you to efficiently read
215  * individual pixels from cairo surfaces. For #GdkWindows, use
216  * gdk_pixbuf_get_from_window() instead.
217  *
218  * This function will create an RGB pixbuf with 8 bits per channel. The pixbuf
219  * will contain an alpha channel if the @surface contains one.
220  *
221  * Return value: (transfer full): A newly-created pixbuf with a reference count
222  * of 1, or %NULL on error
223  **/
224 GdkPixbuf*
225 gdk_pixbuf_get_from_surface(cairo_surface_t * surface,
226                             int srcX, int srcY,
227                             int width, int height)
228 {
229     cairo_content_t content;
230     GdkPixbuf * dest;
231
232     /* General sanity checks */
233     g_return_val_if_fail(surface, NULL);
234     g_return_val_if_fail(srcX >= 0 && srcY >= 0, NULL);
235     g_return_val_if_fail(width > 0 && height > 0, NULL);
236
237     content = cairo_surface_get_content(surface) | CAIRO_CONTENT_COLOR;
238     dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
239                           !!(content & CAIRO_CONTENT_ALPHA),
240                           8,
241                           width, height);
242
243     surface = gdk_cairo_surface_coerce_to_image(surface, content, srcX + width, srcY + height);
244     cairo_surface_flush(surface);
245     if (cairo_surface_status(surface) || !dest) {
246         cairo_surface_destroy(surface);
247         return NULL;
248     }
249
250     if (gdk_pixbuf_get_has_alpha(dest))
251         convert_alpha(gdk_pixbuf_get_pixels(dest),
252                        gdk_pixbuf_get_rowstride(dest),
253                        cairo_image_surface_get_data(surface),
254                        cairo_image_surface_get_stride(surface),
255                        srcX, srcY,
256                        width, height);
257     else
258         convert_no_alpha(gdk_pixbuf_get_pixels(dest),
259                           gdk_pixbuf_get_rowstride(dest),
260                           cairo_image_surface_get_data(surface),
261                           cairo_image_surface_get_stride(surface),
262                           srcX, srcY,
263                           width, height);
264
265     cairo_surface_destroy(surface);
266     return dest;
267 }
268
269 #if GTK_CHECK_VERSION(2, 24, 0)
270 void getGdkDrawableSize(GdkDrawable *drawable, int *width, int *height)
271 {
272     g_return_if_fail(GDK_IS_PIXMAP(drawable) || GDK_IS_WINDOW(drawable));
273
274     if (GDK_IS_PIXMAP(drawable)) {
275         gdk_pixmap_get_size(GDK_PIXMAP(drawable), width, height);
276         return;
277     }
278
279     GdkWindow *window = GDK_WINDOW(drawable);
280     *width = gdk_window_get_width(window);
281     *height = gdk_window_get_height(window);
282 }
283 #else
284 void getGdkDrawableSize(GdkDrawable *drawable, int *width, int *height)
285 {
286     gdk_drawable_get_size(drawable, width, height);
287 }
288 #endif // GTK_CHECK_VERSION(2, 24, 0)
289
290 #endif // GTK_API_VERSION_2
291
292 #if !GLIB_CHECK_VERSION(2, 27, 1)
293 gboolean g_signal_accumulator_first_wins(GSignalInvocationHint *invocationHint, GValue *returnAccumulator, const GValue *handlerReturn, gpointer data)
294 {
295     g_value_copy(handlerReturn, returnAccumulator);
296     return FALSE;
297 }
298 #endif
299
300 #if !GTK_CHECK_VERSION(2, 22, 0)
301 cairo_surface_t *gdk_window_create_similar_surface(GdkWindow *window, cairo_content_t content, int width, int height)
302 {
303     cairo_t *cairoContext = gdk_cairo_create(window);
304     cairo_surface_t *cairoSurface = cairo_get_target(cairoContext);
305     cairo_surface_t *newSurface = cairo_surface_create_similar(cairoSurface, content, width, height);
306     cairo_destroy(cairoContext);
307     return newSurface;
308 }
309 #endif // GTK_CHECK_VERSION(2, 22, 0)
310
311 #if !GTK_CHECK_VERSION(3, 3, 6)
312 #ifdef GDK_WINDOWING_X11
313 static int getScreenCurrentDesktop(GdkScreen *screen)
314 {
315     Display *display = GDK_DISPLAY_XDISPLAY(gdk_screen_get_display(screen));
316     Window rootWindow = XRootWindow(display, GDK_SCREEN_XNUMBER(screen));
317     Atom currentDesktop = XInternAtom(display, "_NET_CURRENT_DESKTOP", True);
318
319     Atom type;
320     int format;
321     unsigned long itemsCount, bytesAfter;
322     unsigned char *returnedData = NULL;
323     XGetWindowProperty(display, rootWindow, currentDesktop, 0, G_MAXLONG, False, XA_CARDINAL,
324                        &type, &format, &itemsCount, &bytesAfter, &returnedData);
325
326     int workspace = 0;
327     if (type == XA_CARDINAL && format == 32 && itemsCount > 0)
328         workspace = (int)returnedData[0];
329
330     if (returnedData)
331         XFree(returnedData);
332
333     return workspace;
334 }
335
336 static void getScreenWorkArea(GdkScreen *screen, GdkRectangle *area)
337 {
338     Display *display = GDK_DISPLAY_XDISPLAY(gdk_screen_get_display(screen));
339     Atom workArea = XInternAtom(display, "_NET_WORKAREA", True);
340
341     /* Defaults in case of error. */
342     area->x = 0;
343     area->y = 0;
344     area->width = gdk_screen_get_width(screen);
345     area->height = gdk_screen_get_height(screen);
346
347     if (workArea == None)
348         return;
349
350     Window rootWindow = XRootWindow(display, GDK_SCREEN_XNUMBER(screen));
351     Atom type;
352     int format;
353     unsigned long itemsCount, bytesAfter;
354     unsigned char *returnedData = 0;
355     int result = XGetWindowProperty(display, rootWindow, workArea, 0, 4 * 32 /* Max length */, False, AnyPropertyType,
356                                     &type, &format, &itemsCount, &bytesAfter, &returnedData);
357     if (result != Success || type == None || !format || bytesAfter || itemsCount % 4)
358         return;
359
360     int desktop = getScreenCurrentDesktop(screen);
361     long *workAreas = (long *)returnedData;
362     area->x = workAreas[desktop * 4];
363     area->y = workAreas[desktop * 4 + 1];
364     area->width = workAreas[desktop * 4 + 2];
365     area->height = workAreas[desktop * 4 + 3];
366
367     XFree(returnedData);
368 }
369 #endif // GDK_WINDOWING_X11
370
371 void gdk_screen_get_monitor_workarea(GdkScreen *screen, int monitor, GdkRectangle *area)
372 {
373     gdk_screen_get_monitor_geometry(screen, monitor, area);
374
375 #ifdef GDK_WINDOWING_X11
376     GdkRectangle workArea;
377     getScreenWorkArea(screen, &workArea);
378     gdk_rectangle_intersect(&workArea, area, area);
379 #endif
380 }
381 #endif // GTK_CHECK_VERSION(3, 3, 6)