1/*
2 * Copyright (C) 2006 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
4 * Copyright (C) 2008 Christian Dywan <christian@imendio.com>
5 * Copyright (C) 2008 Collabora Ltd.
6 * Copyright (C) 2009 Holger Hans Peter Freyther
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "PlatformScreen.h"
33
34#include "FloatRect.h"
35#include "FrameView.h"
36#include "GtkVersioning.h"
37#include "HostWindow.h"
38#include "NotImplemented.h"
39#include "Widget.h"
40
41#include <cmath>
42#include <gtk/gtk.h>
43#include <wtf/HashMap.h>
44#include <wtf/NeverDestroyed.h>
45
46namespace WebCore {
47
48static GtkWidget* getToplevel(GtkWidget* widget)
49{
50 GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
51 return gtk_widget_is_toplevel(toplevel) ? toplevel : 0;
52}
53
54static GdkVisual* getVisual(Widget* widget)
55{
56 GtkWidget* container = widget ? GTK_WIDGET(widget->root()->hostWindow()->platformPageClient()) : 0;
57 if (!container) {
58 GdkScreen* screen = gdk_screen_get_default();
59 return screen ? gdk_screen_get_system_visual(screen) : 0;
60 }
61
62 if (!gtk_widget_get_realized(container))
63 container = getToplevel(container);
64 return container ? gdk_window_get_visual(gtk_widget_get_window(container)) : 0;
65}
66
67int screenDepth(Widget* widget)
68{
69 GdkVisual* visual = getVisual(widget);
70 if (!visual)
71 return 24;
72 return gdk_visual_get_depth(visual);
73}
74
75int screenDepthPerComponent(Widget* widget)
76{
77 GdkVisual* visual = getVisual(widget);
78 if (!visual)
79 return 8;
80
81 return gdk_visual_get_bits_per_rgb(visual);
82}
83
84bool screenIsMonochrome(Widget* widget)
85{
86 return screenDepth(widget) < 2;
87}
88
89bool screenHasInvertedColors()
90{
91 return false;
92}
93
94double screenDPI()
95{
96 static const double defaultDpi = 96;
97 GdkScreen* screen = gdk_screen_get_default();
98 if (!screen)
99 return defaultDpi;
100
101 double dpi = gdk_screen_get_resolution(screen);
102 if (dpi != -1)
103 return dpi;
104
105 static double cachedDpi = 0;
106 if (cachedDpi)
107 return cachedDpi;
108
109 static const double millimetresPerInch = 25.4;
110 double diagonalInPixels = std::hypot(gdk_screen_get_width(screen), gdk_screen_get_height(screen));
111 double diagonalInInches = std::hypot(gdk_screen_get_width_mm(screen), gdk_screen_get_height_mm(screen)) / millimetresPerInch;
112 cachedDpi = diagonalInPixels / diagonalInInches;
113
114 return cachedDpi;
115}
116
117static WTF::HashMap<void*, Function<void()>>& screenDPIObserverHandlersMap()
118{
119 static WTF::NeverDestroyed<WTF::HashMap<void*, Function<void()>>> handlersMap;
120 return handlersMap;
121}
122
123static void gtkXftDPIChangedCallback()
124{
125 for (const auto& keyValuePair : screenDPIObserverHandlersMap())
126 keyValuePair.value();
127}
128
129void setScreenDPIObserverHandler(Function<void()>&& handler, void* context)
130{
131 static GtkSettings* gtkSettings = gtk_settings_get_default();
132 static unsigned long gtkXftDpiChangedHandlerID = 0;
133
134 if (!gtkSettings)
135 return;
136
137 if (handler)
138 screenDPIObserverHandlersMap().set(context, WTFMove(handler));
139 else
140 screenDPIObserverHandlersMap().remove(context);
141
142 if (!screenDPIObserverHandlersMap().isEmpty()) {
143 if (!gtkXftDpiChangedHandlerID)
144 gtkXftDpiChangedHandlerID = g_signal_connect(gtkSettings, "notify::gtk-xft-dpi", G_CALLBACK(gtkXftDPIChangedCallback), nullptr);
145 } else if (gtkXftDpiChangedHandlerID) {
146 g_signal_handler_disconnect(gtkSettings, gtkXftDpiChangedHandlerID);
147 gtkXftDpiChangedHandlerID = 0;
148 }
149}
150
151static GdkScreen* getScreen(GtkWidget* widget)
152{
153 return gtk_widget_has_screen(widget) ? gtk_widget_get_screen(widget) : gdk_screen_get_default();
154}
155
156FloatRect screenRect(Widget* widget)
157{
158 GtkWidget* container = widget ? GTK_WIDGET(widget->root()->hostWindow()->platformPageClient()) : 0;
159 if (container)
160 container = getToplevel(container);
161
162 GdkScreen* screen = container ? getScreen(container) : gdk_screen_get_default();
163 if (!screen)
164 return FloatRect();
165
166 gint monitor = container ? gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(container)) : 0;
167
168 GdkRectangle geometry;
169 gdk_screen_get_monitor_geometry(screen, monitor, &geometry);
170
171 return FloatRect(geometry.x, geometry.y, geometry.width, geometry.height);
172}
173
174FloatRect screenAvailableRect(Widget* widget)
175{
176 GtkWidget* container = widget ? GTK_WIDGET(widget->root()->hostWindow()->platformPageClient()) : 0;
177 if (container && !gtk_widget_get_realized(container))
178 return screenRect(widget);
179
180 GdkScreen* screen = container ? getScreen(container) : gdk_screen_get_default();
181 if (!screen)
182 return FloatRect();
183
184 gint monitor = container ? gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(container)) : 0;
185
186 GdkRectangle workArea;
187 gdk_screen_get_monitor_workarea(screen, monitor, &workArea);
188
189 return FloatRect(workArea.x, workArea.y, workArea.width, workArea.height);
190
191}
192
193bool screenSupportsExtendedColor(Widget*)
194{
195 return false;
196}
197
198} // namespace WebCore
199