calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / unx / gtk3 / gtksys.cxx
blob37e32b28b38e9679f50cdffe26c087c539bc32cd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <gtk/gtk.h>
21 #include <unx/gtk/gtkdata.hxx>
22 #include <unx/gtk/gtkinst.hxx>
23 #include <unx/gtk/gtksys.hxx>
24 #include <unx/gtk/gtkbackend.hxx>
25 #include <osl/module.h>
27 GtkSalSystem *GtkSalSystem::GetSingleton()
29 static GtkSalSystem *pSingleton = new GtkSalSystem();
30 return pSingleton;
33 SalSystem *GtkInstance::CreateSalSystem()
35 return GtkSalSystem::GetSingleton();
38 GtkSalSystem::GtkSalSystem()
40 mpDisplay = gdk_display_get_default();
41 #if !GTK_CHECK_VERSION(4, 0, 0)
42 countScreenMonitors();
43 #endif
44 // rhbz#1285356, native look will be gtk2, which crashes
45 // when gtk3 is already loaded. Until there is a solution
46 // java-side force look and feel to something that doesn't
47 // crash when we are using gtk3
48 setenv("STOC_FORCE_SYSTEM_LAF", "true", 1);
51 GtkSalSystem::~GtkSalSystem()
55 namespace
58 struct GdkRectangleCoincidentLess
60 // fdo#78799 - detect and elide overlaying monitors of different sizes
61 bool operator()(GdkRectangle const& rLeft, GdkRectangle const& rRight)
63 return
64 rLeft.x < rRight.x
65 || rLeft.y < rRight.y
69 struct GdkRectangleCoincident
71 // fdo#78799 - detect and elide overlaying monitors of different sizes
72 bool operator()(GdkRectangle const& rLeft, GdkRectangle const& rRight)
74 return
75 rLeft.x == rRight.x
76 && rLeft.y == rRight.y
83 #if !GTK_CHECK_VERSION(4, 0, 0)
84 /**
85 * GtkSalSystem::countScreenMonitors()
87 * This method builds the vector which allows us to map from VCL's
88 * idea of linear integer ScreenNumber to gtk+'s rather more
89 * complicated screen + monitor concept.
91 void
92 GtkSalSystem::countScreenMonitors()
94 maScreenMonitors.clear();
95 for (gint i = 0; i < gdk_display_get_n_screens(mpDisplay); i++)
97 GdkScreen* const pScreen(gdk_display_get_screen(mpDisplay, i));
98 gint nMonitors(pScreen ? gdk_screen_get_n_monitors(pScreen) : 0);
99 if (nMonitors > 1)
101 std::vector<GdkRectangle> aGeometries;
102 aGeometries.reserve(nMonitors);
103 for (gint j(0); j != nMonitors; ++j)
105 GdkRectangle aGeometry;
106 gdk_screen_get_monitor_geometry(pScreen, j, &aGeometry);
107 aGeometries.push_back(aGeometry);
109 std::sort(aGeometries.begin(), aGeometries.end(),
110 GdkRectangleCoincidentLess());
111 const std::vector<GdkRectangle>::iterator aUniqueEnd(
112 std::unique(aGeometries.begin(), aGeometries.end(),
113 GdkRectangleCoincident()));
114 nMonitors = std::distance(aGeometries.begin(), aUniqueEnd);
116 maScreenMonitors.emplace_back(pScreen, nMonitors);
119 #endif
121 SalX11Screen
122 GtkSalSystem::getXScreenFromDisplayScreen(unsigned int nScreen)
124 if (!DLSYM_GDK_IS_X11_DISPLAY(mpDisplay))
125 return SalX11Screen (0);
127 #if GTK_CHECK_VERSION(4, 0, 0)
128 GdkX11Screen *pScreen = gdk_x11_display_get_screen(mpDisplay);
129 (void)nScreen;
130 #else
131 gint nMonitor;
132 GdkScreen *pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
133 if (!pScreen)
134 return SalX11Screen (0);
135 #endif
136 return SalX11Screen(gdk_x11_screen_get_screen_number(pScreen));
139 #if !GTK_CHECK_VERSION(4, 0, 0)
140 GdkScreen *
141 GtkSalSystem::getScreenMonitorFromIdx (int nIdx, gint &nMonitor)
143 GdkScreen *pScreen = nullptr;
144 for (auto const& screenMonitor : maScreenMonitors)
146 pScreen = screenMonitor.first;
147 if (!pScreen)
148 break;
149 if (nIdx >= screenMonitor.second)
150 nIdx -= screenMonitor.second;
151 else
152 break;
154 nMonitor = nIdx;
156 // handle invalid monitor indexes as non-existent screens
157 if (nMonitor < 0 || (pScreen && nMonitor >= gdk_screen_get_n_monitors (pScreen)))
158 pScreen = nullptr;
160 return pScreen;
164 GtkSalSystem::getScreenIdxFromPtr (GdkScreen *pScreen)
166 int nIdx = 0;
167 for (auto const& screenMonitor : maScreenMonitors)
169 if (screenMonitor.first == pScreen)
170 return nIdx;
171 nIdx += screenMonitor.second;
173 g_warning ("failed to find screen %p", pScreen);
174 return 0;
177 int GtkSalSystem::getScreenMonitorIdx (GdkScreen *pScreen,
178 int nX, int nY)
180 // TODO: this will fail horribly for exotic combinations like two
181 // monitors in mirror mode and one extra. Hopefully such
182 // abominations are not used (or, even better, not possible) in
183 // practice .-)
184 return getScreenIdxFromPtr (pScreen) +
185 gdk_screen_get_monitor_at_point (pScreen, nX, nY);
187 #endif
189 unsigned int GtkSalSystem::GetDisplayScreenCount()
191 #if GTK_CHECK_VERSION(4, 0, 0)
192 return g_list_model_get_n_items(gdk_display_get_monitors(mpDisplay));
193 #else
194 gint nMonitor;
195 (void)getScreenMonitorFromIdx (G_MAXINT, nMonitor);
196 return G_MAXINT - nMonitor;
197 #endif
200 bool GtkSalSystem::IsUnifiedDisplay()
202 #if !GTK_CHECK_VERSION(4, 0, 0)
203 return gdk_display_get_n_screens (mpDisplay) == 1;
204 #else
205 return true;
206 #endif
209 unsigned int GtkSalSystem::GetDisplayBuiltInScreen()
211 #if GTK_CHECK_VERSION(4, 0, 0)
212 #if defined(GDK_WINDOWING_X11)
213 if (DLSYM_GDK_IS_X11_DISPLAY(mpDisplay))
215 GdkMonitor* pPrimary = gdk_x11_display_get_primary_monitor(mpDisplay);
216 GListModel* pList = gdk_display_get_monitors(mpDisplay);
217 int nIndex = 0;
218 while (gpointer pElem = g_list_model_get_item(pList, nIndex))
220 if (pElem == pPrimary)
221 return nIndex;
222 ++nIndex;
225 #endif
226 // nothing for wayland ?, hope for the best that its at index 0
227 return 0;
228 #else // !GTK_CHECK_VERSION(4, 0, 0)
229 GdkScreen *pDefault = gdk_display_get_default_screen (mpDisplay);
230 int idx = getScreenIdxFromPtr (pDefault);
231 return idx + gdk_screen_get_primary_monitor(pDefault);
232 #endif
235 tools::Rectangle GtkSalSystem::GetDisplayScreenPosSizePixel(unsigned int nScreen)
237 GdkRectangle aRect;
238 #if GTK_CHECK_VERSION(4, 0, 0)
239 GListModel* pList = gdk_display_get_monitors(mpDisplay);
240 GdkMonitor* pMonitor = static_cast<GdkMonitor*>(g_list_model_get_item(pList, nScreen));
241 if (!pMonitor)
242 return tools::Rectangle();
243 gdk_monitor_get_geometry(pMonitor, &aRect);
244 #else
245 gint nMonitor;
246 GdkScreen *pScreen;
247 pScreen = getScreenMonitorFromIdx (nScreen, nMonitor);
248 if (!pScreen)
249 return tools::Rectangle();
250 gdk_screen_get_monitor_geometry (pScreen, nMonitor, &aRect);
251 #endif
252 return tools::Rectangle (Point(aRect.x, aRect.y), Size(aRect.width, aRect.height));
255 // convert ~ to indicate mnemonic to '_'
256 static OString MapToGtkAccelerator(const OUString &rStr)
258 return OUStringToOString(rStr.replaceFirst("~", "_"), RTL_TEXTENCODING_UTF8);
261 #if GTK_CHECK_VERSION(4, 0, 0)
263 namespace
265 struct DialogLoop
267 GMainLoop* pLoop = nullptr;
268 gint nResponseId = GTK_RESPONSE_NONE;
269 gulong nSignalResponseId = 0;
270 gulong nSignalCloseRequestId= 0;
272 static gboolean DialogClose(GtkWindow* pDialog, gpointer /*data*/)
274 gtk_dialog_response(GTK_DIALOG(pDialog), GTK_RESPONSE_CANCEL);
275 return true;
278 static void DialogResponse(GtkDialog* pDialog, gint nResponseId, gpointer data)
280 DialogLoop* pDialogLoop = static_cast<DialogLoop*>(data);
281 g_signal_handler_disconnect(pDialog, pDialogLoop->nSignalResponseId);
282 g_signal_handler_disconnect(pDialog, pDialogLoop->nSignalCloseRequestId);
283 pDialogLoop->nResponseId = nResponseId;
284 g_main_loop_quit(pDialogLoop->pLoop);
287 int run(GtkDialog *pDialog)
289 nSignalResponseId = g_signal_connect(pDialog, "response", G_CALLBACK(DialogResponse), this);
290 nSignalCloseRequestId = g_signal_connect(pDialog, "close-request", G_CALLBACK(DialogClose), this);
291 gtk_window_present(GTK_WINDOW(pDialog));
292 pLoop = g_main_loop_new(nullptr, false);
293 main_loop_run(pLoop);
294 g_main_loop_unref(pLoop);
295 return nResponseId;
301 gint gtk_dialog_run(GtkDialog* pDialog)
303 DialogLoop aDialogLoop;
304 return aDialogLoop.run(pDialog);
307 #endif
309 int GtkSalSystem::ShowNativeDialog (const OUString& rTitle, const OUString& rMessage,
310 const std::vector< OUString >& rButtonNames)
312 OString aTitle (OUStringToOString (rTitle, RTL_TEXTENCODING_UTF8));
313 OString aMessage (OUStringToOString (rMessage, RTL_TEXTENCODING_UTF8));
315 GtkDialog *pDialog = GTK_DIALOG (
316 g_object_new (GTK_TYPE_MESSAGE_DIALOG,
317 "title", aTitle.getStr(),
318 "message-type", int(GTK_MESSAGE_WARNING),
319 "text", aMessage.getStr(),
320 nullptr));
321 int nButton = 0;
322 for (auto const& buttonName : rButtonNames)
323 gtk_dialog_add_button (pDialog, MapToGtkAccelerator(buttonName).getStr(), nButton++);
324 gtk_dialog_set_default_response (pDialog, 0/*nDefaultButton*/);
326 nButton = gtk_dialog_run (pDialog);
327 if (nButton < 0)
328 nButton = -1;
330 #if !GTK_CHECK_VERSION(4, 0, 0)
331 gtk_widget_destroy(GTK_WIDGET(pDialog));
332 #else
333 gtk_window_destroy(GTK_WINDOW(pDialog));
334 #endif
336 return nButton;
339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */