Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * Version: MPL 1.1 / GPLv3+ / LGPLv3+
4 : : *
5 : : * The contents of this file are subject to the Mozilla Public License Version
6 : : * 1.1 (the "License"); you may not use this file except in compliance with
7 : : * the License or as specified alternatively below. You may obtain a copy of
8 : : * the License at http://www.mozilla.org/MPL/
9 : : *
10 : : * Software distributed under the License is distributed on an "AS IS" basis,
11 : : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : : * for the specific language governing rights and limitations under the
13 : : * License.
14 : : *
15 : : * The Initial Developer of the Original Code is
16 : : * Michael Meeks <michael.meeks@novell.com>
17 : : * Portions created by the Initial Developer are Copyright (C) 2010 the
18 : : * Initial Developer. All Rights Reserved.
19 : : *
20 : : * Major Contributor(s):
21 : : *
22 : : * For minor contributions see the git repository.
23 : : *
24 : : * Alternatively, the contents of this file may be used under the terms of
25 : : * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
26 : : * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
27 : : * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
28 : : * instead of those above.
29 : : */
30 : : #include <string.h>
31 : : #include <gmodule.h>
32 : : #include <gtk/gtk.h>
33 : : #include <unx/gtk/gtkinst.hxx>
34 : : #include <unx/gtk/gtksys.hxx>
35 : :
36 : 0 : GtkSalSystem *GtkSalSystem::GetSingleton()
37 : : {
38 : : static GtkSalSystem *pSingleton = NULL;
39 : 0 : if (!pSingleton)
40 : 0 : pSingleton = new GtkSalSystem();
41 : 0 : return pSingleton;
42 : : }
43 : :
44 : 0 : SalSystem *GtkInstance::CreateSalSystem()
45 : : {
46 : 0 : return GtkSalSystem::GetSingleton();
47 : : }
48 : :
49 : 0 : GtkSalSystem::GtkSalSystem() : SalGenericSystem()
50 : : {
51 : 0 : mpDisplay = gdk_display_get_default();
52 : 0 : countScreenMonitors();
53 : 0 : }
54 : :
55 : 0 : GtkSalSystem::~GtkSalSystem()
56 : : {
57 : 0 : }
58 : :
59 : : int
60 : 0 : GtkSalSystem::GetDisplayXScreenCount()
61 : : {
62 : 0 : return gdk_display_get_n_screens (mpDisplay);
63 : : }
64 : :
65 : : namespace
66 : : {
67 : :
68 : : struct GdkRectangleEqual
69 : : {
70 : 0 : bool operator()(GdkRectangle const& rLeft, GdkRectangle const& rRight)
71 : : {
72 : : return
73 : : rLeft.x == rRight.x
74 : : && rLeft.y == rRight.y
75 : : && rLeft.width == rRight.width
76 : 0 : && rLeft.height == rRight.height
77 : : ;
78 : : }
79 : : };
80 : :
81 : : }
82 : :
83 : : void
84 : 0 : GtkSalSystem::countScreenMonitors()
85 : : {
86 : 0 : maScreenMonitors.clear();
87 : 0 : for (gint i = 0; i < gdk_display_get_n_screens(mpDisplay); i++)
88 : : {
89 : 0 : GdkScreen* const pScreen(gdk_display_get_screen(mpDisplay, i));
90 : 0 : gint nMonitors(pScreen ? gdk_screen_get_n_monitors(pScreen) : 0);
91 : 0 : if (nMonitors > 1)
92 : : {
93 : 0 : std::vector<GdkRectangle> aGeometries;
94 : 0 : aGeometries.reserve(nMonitors);
95 : 0 : for (gint j(0); j != nMonitors; ++j)
96 : : {
97 : : GdkRectangle aGeometry;
98 : 0 : gdk_screen_get_monitor_geometry(pScreen, j, &aGeometry);
99 : 0 : aGeometries.push_back(aGeometry);
100 : : }
101 : : GdkRectangleEqual aCmp;
102 : 0 : std::sort(aGeometries.begin(), aGeometries.end(), aCmp);
103 : : const std::vector<GdkRectangle>::iterator aUniqueEnd(
104 : 0 : std::unique(aGeometries.begin(), aGeometries.end(), aCmp));
105 : 0 : nMonitors = std::distance(aGeometries.begin(), aUniqueEnd);
106 : : }
107 : 0 : maScreenMonitors.push_back(std::make_pair(pScreen, nMonitors));
108 : : }
109 : 0 : }
110 : :
111 : : // Including gdkx.h kills us with the Window / XWindow conflict
112 : : extern "C" {
113 : : GType gdk_x11_display_get_type (void);
114 : : int gdk_x11_screen_get_screen_number (GdkScreen *screen);
115 : : }
116 : :
117 : : SalX11Screen
118 : 0 : GtkSalSystem::getXScreenFromDisplayScreen(unsigned int nScreen)
119 : : {
120 : : gint nMonitor;
121 : 0 : GdkScreen *pScreen = NULL;
122 : :
123 : 0 : pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
124 : 0 : if (!pScreen)
125 : 0 : return SalX11Screen (0);
126 : : #if GTK_CHECK_VERSION(3,0,0)
127 : : if (!G_TYPE_CHECK_INSTANCE_TYPE (mpDisplay, gdk_x11_display_get_type ()))
128 : : return SalX11Screen (0);
129 : : #endif
130 : 0 : return SalX11Screen (gdk_x11_screen_get_screen_number (pScreen));
131 : : }
132 : :
133 : : GdkScreen *
134 : 0 : GtkSalSystem::getScreenMonitorFromIdx (int nIdx, gint &nMonitor)
135 : : {
136 : 0 : GdkScreen *pScreen = NULL;
137 : 0 : for (ScreenMonitors_t::const_iterator aIt(maScreenMonitors.begin()), aEnd(maScreenMonitors.end()); aIt != aEnd; ++aIt)
138 : : {
139 : 0 : pScreen = aIt->first;
140 : 0 : if (!pScreen)
141 : 0 : break;
142 : 0 : if (nIdx >= aIt->second)
143 : 0 : nIdx -= aIt->second;
144 : : else
145 : 0 : break;
146 : : }
147 : 0 : nMonitor = nIdx;
148 : 0 : return pScreen;
149 : : }
150 : :
151 : : int
152 : 0 : GtkSalSystem::getScreenIdxFromPtr (GdkScreen *pScreen)
153 : : {
154 : 0 : int nIdx = 0;
155 : 0 : for (ScreenMonitors_t::const_iterator aIt(maScreenMonitors.begin()), aEnd(maScreenMonitors.end()); aIt != aEnd; ++aIt)
156 : : {
157 : 0 : if (aIt->first == pScreen)
158 : 0 : return nIdx;
159 : 0 : nIdx += aIt->second;
160 : : }
161 : 0 : g_warning ("failed to find screen %p", pScreen);
162 : 0 : return 0;
163 : : }
164 : :
165 : 0 : int GtkSalSystem::getScreenMonitorIdx (GdkScreen *pScreen,
166 : : int nX, int nY)
167 : : {
168 : : // TODO: this will fail horribly for exotic combinations like two
169 : : // monitors in mirror mode and one extra. Hopefully such
170 : : // abominations are not used (or, even better, not possible) in
171 : : // practice .-)
172 : 0 : return getScreenIdxFromPtr (pScreen) +
173 : 0 : gdk_screen_get_monitor_at_point (pScreen, nX, nY);
174 : : }
175 : :
176 : 0 : unsigned int GtkSalSystem::GetDisplayScreenCount()
177 : : {
178 : : gint nMonitor;
179 : 0 : (void)getScreenMonitorFromIdx (G_MAXINT, nMonitor);
180 : 0 : return G_MAXINT - nMonitor;
181 : : }
182 : :
183 : 0 : bool GtkSalSystem::IsUnifiedDisplay()
184 : : {
185 : 0 : return gdk_display_get_n_screens (mpDisplay) == 1;
186 : : }
187 : :
188 : : namespace {
189 : : #if GTK_CHECK_VERSION(2,14,0)
190 : 0 : static int _fallback_get_primary_monitor (GdkScreen *pScreen)
191 : : {
192 : : // Use monitor name as primacy heuristic
193 : 0 : int ret = -1;
194 : 0 : int max = gdk_screen_get_n_monitors (pScreen);
195 : 0 : for (int i = 0; i < max && ret < 0; i++)
196 : : {
197 : 0 : char *name = gdk_screen_get_monitor_plug_name (pScreen, i);
198 : 0 : if (name && !g_ascii_strncasecmp (name, "LVDS", 4))
199 : 0 : ret = i;
200 : 0 : g_free (name);
201 : : }
202 : 0 : return 0;
203 : : }
204 : : #endif
205 : :
206 : 0 : static int _get_primary_monitor (GdkScreen *pScreen)
207 : : {
208 : : static int (*get_fn) (GdkScreen *) = NULL;
209 : : #if GTK_CHECK_VERSION(3,0,0)
210 : : get_fn = gdk_screen_get_primary_monitor;
211 : : #endif
212 : : // Perhaps we have a newer gtk+ with this symbol:
213 : 0 : if (!get_fn)
214 : : {
215 : 0 : GModule *module = g_module_open (NULL, (GModuleFlags) 0);
216 : 0 : if (!g_module_symbol (module, "gdk_screen_get_primary_monitor",
217 : 0 : (gpointer *)&get_fn))
218 : 0 : get_fn = NULL;
219 : 0 : g_module_close (module);
220 : : }
221 : : #if GTK_CHECK_VERSION(2,14,0)
222 : 0 : if (!get_fn)
223 : 0 : get_fn = _fallback_get_primary_monitor;
224 : : #endif
225 : 0 : if (get_fn)
226 : 0 : return get_fn (pScreen);
227 : : else
228 : 0 : return 0;
229 : : }
230 : : } // end anonymous namespace
231 : :
232 : 0 : unsigned int GtkSalSystem::GetDisplayBuiltInScreen()
233 : : {
234 : 0 : GdkScreen *pDefault = gdk_display_get_default_screen (mpDisplay);
235 : 0 : int idx = getScreenIdxFromPtr (pDefault);
236 : 0 : return idx + _get_primary_monitor (pDefault);
237 : : }
238 : :
239 : 0 : Rectangle GtkSalSystem::GetDisplayScreenPosSizePixel (unsigned int nScreen)
240 : : {
241 : : gint nMonitor;
242 : : GdkScreen *pScreen;
243 : : GdkRectangle aRect;
244 : 0 : pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
245 : 0 : if (!pScreen)
246 : 0 : return Rectangle();
247 : 0 : gdk_screen_get_monitor_geometry (pScreen, nMonitor, &aRect);
248 : 0 : return Rectangle (Point(aRect.x, aRect.y), Size(aRect.width, aRect.height));
249 : : }
250 : :
251 : 0 : Rectangle GtkSalSystem::GetDisplayScreenWorkAreaPosSizePixel (unsigned int nScreen)
252 : : {
253 : : // FIXME: in theory we need extra code here to collect
254 : : // the work area, ignoring fixed panels etc. on the screen.
255 : : // surely gtk+ should have API to get this for us (?)
256 : 0 : return GetDisplayScreenPosSizePixel( nScreen );
257 : : }
258 : :
259 : 0 : rtl::OUString GtkSalSystem::GetDisplayScreenName(unsigned int nScreen)
260 : : {
261 : : gchar *pStr;
262 : : gint nMonitor;
263 : : GdkScreen *pScreen;
264 : 0 : pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
265 : 0 : if (!pScreen)
266 : 0 : return rtl::OUString();
267 : :
268 : : #if GTK_CHECK_VERSION(3,0,0) || GTK_CHECK_VERSION(2,14,0)
269 : 0 : pStr = gdk_screen_get_monitor_plug_name (pScreen, nMonitor);
270 : : #else
271 : : static gchar * (*get_fn) (GdkScreen *, int) = NULL;
272 : :
273 : : GModule *module = g_module_open (NULL, (GModuleFlags) 0);
274 : : if (!g_module_symbol (module, "gdk_screen_get_monitor_plug_name",
275 : : (gpointer *)&get_fn))
276 : : get_fn = NULL;
277 : : g_module_close (module);
278 : :
279 : : if (get_fn)
280 : : pStr = get_fn (pScreen, nMonitor);
281 : : else
282 : : pStr = g_strdup_printf ("%d", nScreen);
283 : : #endif
284 : 0 : rtl::OUString aRet (pStr, strlen (pStr), RTL_TEXTENCODING_UTF8);
285 : 0 : g_free (pStr);
286 : 0 : return aRet;
287 : : }
288 : :
289 : : // convert ~ to indicate mnemonic to '_'
290 : 0 : static rtl::OString MapToGtkAccelerator(const rtl::OUString &rStr)
291 : : {
292 : 0 : return rtl::OUStringToOString(rStr.replaceFirst("~", "_"), RTL_TEXTENCODING_UTF8);
293 : : }
294 : :
295 : 0 : int GtkSalSystem::ShowNativeDialog (const rtl::OUString& rTitle, const rtl::OUString& rMessage,
296 : : const std::list< rtl::OUString >& rButtonNames,
297 : : int nDefaultButton)
298 : : {
299 : 0 : rtl::OString aTitle (rtl::OUStringToOString (rTitle, RTL_TEXTENCODING_UTF8));
300 : 0 : rtl::OString aMessage (rtl::OUStringToOString (rMessage, RTL_TEXTENCODING_UTF8));
301 : :
302 : 0 : GtkDialog *pDialog = GTK_DIALOG (
303 : : g_object_new (GTK_TYPE_MESSAGE_DIALOG,
304 : : "title", aTitle.getStr(),
305 : : "message-type", (int)GTK_MESSAGE_WARNING,
306 : : "text", aMessage.getStr(),
307 : : NULL));
308 : 0 : int nButton = 0;
309 : 0 : std::list< rtl::OUString >::const_iterator it;
310 : 0 : for (it = rButtonNames.begin(); it != rButtonNames.end(); ++it)
311 : 0 : gtk_dialog_add_button (pDialog, MapToGtkAccelerator(*it).getStr(), nButton++);
312 : 0 : gtk_dialog_set_default_response (pDialog, nDefaultButton);
313 : :
314 : 0 : nButton = gtk_dialog_run (pDialog);
315 : 0 : if (nButton < 0)
316 : 0 : nButton = -1;
317 : :
318 : 0 : gtk_widget_destroy (GTK_WIDGET (pDialog));
319 : :
320 : 0 : return nButton;
321 : : }
322 : :
323 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|