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 | |
46 | namespace WebCore { |
47 | |
48 | static GtkWidget* getToplevel(GtkWidget* widget) |
49 | { |
50 | GtkWidget* toplevel = gtk_widget_get_toplevel(widget); |
51 | return gtk_widget_is_toplevel(toplevel) ? toplevel : 0; |
52 | } |
53 | |
54 | static 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 | |
67 | int screenDepth(Widget* widget) |
68 | { |
69 | GdkVisual* visual = getVisual(widget); |
70 | if (!visual) |
71 | return 24; |
72 | return gdk_visual_get_depth(visual); |
73 | } |
74 | |
75 | int 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 | |
84 | bool screenIsMonochrome(Widget* widget) |
85 | { |
86 | return screenDepth(widget) < 2; |
87 | } |
88 | |
89 | bool screenHasInvertedColors() |
90 | { |
91 | return false; |
92 | } |
93 | |
94 | double 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 | |
117 | static WTF::HashMap<void*, Function<void()>>& screenDPIObserverHandlersMap() |
118 | { |
119 | static WTF::NeverDestroyed<WTF::HashMap<void*, Function<void()>>> handlersMap; |
120 | return handlersMap; |
121 | } |
122 | |
123 | static void gtkXftDPIChangedCallback() |
124 | { |
125 | for (const auto& keyValuePair : screenDPIObserverHandlersMap()) |
126 | keyValuePair.value(); |
127 | } |
128 | |
129 | void 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 | |
151 | static GdkScreen* getScreen(GtkWidget* widget) |
152 | { |
153 | return gtk_widget_has_screen(widget) ? gtk_widget_get_screen(widget) : gdk_screen_get_default(); |
154 | } |
155 | |
156 | FloatRect 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 | |
174 | FloatRect 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 | |
193 | bool screenSupportsExtendedColor(Widget*) |
194 | { |
195 | return false; |
196 | } |
197 | |
198 | } // namespace WebCore |
199 | |