1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <unx/gtk/gtkinst.hxx>
22 #include <unx/gtk/gtksys.hxx>
23 #include <unx/gtk/gtkbackend.hxx>
24 #include <osl/module.h>
26 GtkSalSystem
*GtkSalSystem::GetSingleton()
28 static GtkSalSystem
*pSingleton
= new GtkSalSystem();
32 SalSystem
*GtkInstance::CreateSalSystem()
34 return GtkSalSystem::GetSingleton();
37 GtkSalSystem::GtkSalSystem() : SalGenericSystem()
39 mpDisplay
= gdk_display_get_default();
40 countScreenMonitors();
41 // rhbz#1285356, native look will be gtk2, which crashes
42 // when gtk3 is already loaded. Until there is a solution
43 // java-side force look and feel to something that doesn't
44 // crash when we are using gtk3
45 setenv("STOC_FORCE_SYSTEM_LAF", "true", 1);
48 GtkSalSystem::~GtkSalSystem()
55 struct GdkRectangleCoincidentLess
57 // fdo#78799 - detect and elide overlaying monitors of different sizes
58 bool operator()(GdkRectangle
const& rLeft
, GdkRectangle
const& rRight
)
66 struct GdkRectangleCoincident
68 // fdo#78799 - detect and elide overlaying monitors of different sizes
69 bool operator()(GdkRectangle
const& rLeft
, GdkRectangle
const& rRight
)
73 && rLeft
.y
== rRight
.y
81 * GtkSalSystem::countScreenMonitors()
83 * This method builds the vector which allows us to map from VCL's
84 * idea of linear integer ScreenNumber to gtk+'s rather more
85 * complicated screen + monitor concept.
88 GtkSalSystem::countScreenMonitors()
90 maScreenMonitors
.clear();
91 for (gint i
= 0; i
< gdk_display_get_n_screens(mpDisplay
); i
++)
93 GdkScreen
* const pScreen(gdk_display_get_screen(mpDisplay
, i
));
94 gint
nMonitors(pScreen
? gdk_screen_get_n_monitors(pScreen
) : 0);
97 std::vector
<GdkRectangle
> aGeometries
;
98 aGeometries
.reserve(nMonitors
);
99 for (gint
j(0); j
!= nMonitors
; ++j
)
101 GdkRectangle aGeometry
;
102 gdk_screen_get_monitor_geometry(pScreen
, j
, &aGeometry
);
103 aGeometries
.push_back(aGeometry
);
105 std::sort(aGeometries
.begin(), aGeometries
.end(),
106 GdkRectangleCoincidentLess());
107 const std::vector
<GdkRectangle
>::iterator
aUniqueEnd(
108 std::unique(aGeometries
.begin(), aGeometries
.end(),
109 GdkRectangleCoincident()));
110 nMonitors
= std::distance(aGeometries
.begin(), aUniqueEnd
);
112 maScreenMonitors
.emplace_back(pScreen
, nMonitors
);
117 GtkSalSystem::getXScreenFromDisplayScreen(unsigned int nScreen
)
121 GdkScreen
*pScreen
= getScreenMonitorFromIdx (nScreen
, nMonitor
);
123 return SalX11Screen (0);
124 if (!DLSYM_GDK_IS_X11_DISPLAY(mpDisplay
))
125 return SalX11Screen (0);
126 return SalX11Screen (gdk_x11_screen_get_screen_number (pScreen
));
130 GtkSalSystem::getScreenMonitorFromIdx (int nIdx
, gint
&nMonitor
)
132 GdkScreen
*pScreen
= nullptr;
133 for (auto const& screenMonitor
: maScreenMonitors
)
135 pScreen
= screenMonitor
.first
;
138 if (nIdx
>= screenMonitor
.second
)
139 nIdx
-= screenMonitor
.second
;
145 // handle invalid monitor indexes as non-existent screens
146 if (nMonitor
< 0 || (pScreen
&& nMonitor
>= gdk_screen_get_n_monitors (pScreen
)))
153 GtkSalSystem::getScreenIdxFromPtr (GdkScreen
*pScreen
)
156 for (auto const& screenMonitor
: maScreenMonitors
)
158 if (screenMonitor
.first
== pScreen
)
160 nIdx
+= screenMonitor
.second
;
162 g_warning ("failed to find screen %p", pScreen
);
166 int GtkSalSystem::getScreenMonitorIdx (GdkScreen
*pScreen
,
169 // TODO: this will fail horribly for exotic combinations like two
170 // monitors in mirror mode and one extra. Hopefully such
171 // abominations are not used (or, even better, not possible) in
173 return getScreenIdxFromPtr (pScreen
) +
174 gdk_screen_get_monitor_at_point (pScreen
, nX
, nY
);
177 unsigned int GtkSalSystem::GetDisplayScreenCount()
180 (void)getScreenMonitorFromIdx (G_MAXINT
, nMonitor
);
181 return G_MAXINT
- nMonitor
;
184 bool GtkSalSystem::IsUnifiedDisplay()
186 return gdk_display_get_n_screens (mpDisplay
) == 1;
190 int _fallback_get_primary_monitor (GdkScreen
*pScreen
)
192 // Use monitor name as primacy heuristic
193 int max
= gdk_screen_get_n_monitors (pScreen
);
194 for (int i
= 0; i
< max
; ++i
)
196 char *name
= gdk_screen_get_monitor_plug_name (pScreen
, i
);
197 bool bLaptop
= (name
&& !g_ascii_strncasecmp (name
, "LVDS", 4));
205 int _get_primary_monitor (GdkScreen
*pScreen
)
207 static int (*get_fn
) (GdkScreen
*) = nullptr;
208 get_fn
= gdk_screen_get_primary_monitor
;
209 // Perhaps we have a newer gtk+ with this symbol:
212 get_fn
= reinterpret_cast<int(*)(GdkScreen
*)>(osl_getAsciiFunctionSymbol(nullptr,
213 "gdk_screen_get_primary_monitor"));
216 get_fn
= _fallback_get_primary_monitor
;
218 return get_fn (pScreen
);
222 } // end anonymous namespace
224 unsigned int GtkSalSystem::GetDisplayBuiltInScreen()
226 GdkScreen
*pDefault
= gdk_display_get_default_screen (mpDisplay
);
227 int idx
= getScreenIdxFromPtr (pDefault
);
228 return idx
+ _get_primary_monitor (pDefault
);
231 tools::Rectangle
GtkSalSystem::GetDisplayScreenPosSizePixel (unsigned int nScreen
)
236 pScreen
= getScreenMonitorFromIdx (nScreen
, nMonitor
);
238 return tools::Rectangle();
239 gdk_screen_get_monitor_geometry (pScreen
, nMonitor
, &aRect
);
240 return tools::Rectangle (Point(aRect
.x
, aRect
.y
), Size(aRect
.width
, aRect
.height
));
243 // convert ~ to indicate mnemonic to '_'
244 static OString
MapToGtkAccelerator(const OUString
&rStr
)
246 return OUStringToOString(rStr
.replaceFirst("~", "_"), RTL_TEXTENCODING_UTF8
);
249 int GtkSalSystem::ShowNativeDialog (const OUString
& rTitle
, const OUString
& rMessage
,
250 const std::vector
< OUString
>& rButtonNames
)
252 OString
aTitle (OUStringToOString (rTitle
, RTL_TEXTENCODING_UTF8
));
253 OString
aMessage (OUStringToOString (rMessage
, RTL_TEXTENCODING_UTF8
));
255 GtkDialog
*pDialog
= GTK_DIALOG (
256 g_object_new (GTK_TYPE_MESSAGE_DIALOG
,
257 "title", aTitle
.getStr(),
258 "message-type", int(GTK_MESSAGE_WARNING
),
259 "text", aMessage
.getStr(),
262 for (auto const& buttonName
: rButtonNames
)
263 gtk_dialog_add_button (pDialog
, MapToGtkAccelerator(buttonName
).getStr(), nButton
++);
264 gtk_dialog_set_default_response (pDialog
, 0/*nDefaultButton*/);
266 nButton
= gtk_dialog_run (pDialog
);
270 gtk_widget_destroy (GTK_WIDGET (pDialog
));
275 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */