VirtualBox

source: vbox/trunk/src/VBox/GuestHost/DisplayServerType.cpp

Last change on this file was 101673, checked in by vboxsync, 7 months ago

GuestHost: DisplayServerType: Add runtime detection if Gtk library is present in the system, bugref:10194.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.8 KB
Line 
1/* $Id: DisplayServerType.cpp 101673 2023-10-31 09:57:18Z vboxsync $ */
2/** @file
3 * Guest / Host common code - Session type detection + handling.
4 */
5
6/*
7 * Copyright (C) 2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/assert.h>
33#include <iprt/env.h>
34#include <iprt/string.h>
35#include <iprt/ldr.h>
36#include <iprt/log.h>
37
38#include <VBox/GuestHost/DisplayServerType.h>
39
40
41/*********************************************************************************************************************************
42* Implementation *
43*********************************************************************************************************************************/
44
45/**
46 * Returns the VBGHDISPLAYSERVERTYPE as a string.
47 *
48 * @returns VBGHDISPLAYSERVERTYPE as a string.
49 * @param enmType VBGHDISPLAYSERVERTYPE to return as a string.
50 */
51const char *VBGHDisplayServerTypeToStr(VBGHDISPLAYSERVERTYPE enmType)
52{
53 switch (enmType)
54 {
55 RT_CASE_RET_STR(VBGHDISPLAYSERVERTYPE_NONE);
56 RT_CASE_RET_STR(VBGHDISPLAYSERVERTYPE_AUTO);
57 RT_CASE_RET_STR(VBGHDISPLAYSERVERTYPE_X11);
58 RT_CASE_RET_STR(VBGHDISPLAYSERVERTYPE_PURE_WAYLAND);
59 RT_CASE_RET_STR(VBGHDISPLAYSERVERTYPE_XWAYLAND);
60 default: break;
61 }
62
63 AssertFailedReturn("<invalid>");
64}
65
66/**
67 * Tries to load a (system) library via a set of different names / versions.
68 *
69 * @returns VBox status code.
70 * @returns VERR_NOT_FOUND if the library was not found.
71 *
72 * @param apszLibs Array of library (version) names to search for.
73 * Descending order (e.g. "libfoo.so", "libfoo.so.2", "libfoo.so.2.6").
74 * @param cLibs Number of library names in \a apszLibs.
75 * @param phLdrMod Where to return the library handle on success.
76 *
77 * @note Will print loading statuses to verbose release log.
78 */
79static int vbghDisplayServerTryLoadLib(const char **apszLibs, size_t cLibs, PRTLDRMOD phLdrMod)
80{
81 for (size_t i = 0; i < cLibs; i++)
82 {
83 const char *pszLib = apszLibs[i];
84 int rc2 = RTLdrLoadSystem(pszLib, /* fNoUnload = */ true, phLdrMod);
85 if (RT_SUCCESS(rc2))
86 {
87 LogRel2(("Loaded display server system library '%s'\n", pszLib));
88 return VINF_SUCCESS;
89 }
90 else
91 LogRel2(("Unable to load display server system library '%s': %Rrc\n", pszLib, rc2));
92 }
93
94 return VERR_NOT_FOUND;
95}
96
97
98#define GET_SYMBOL(a_Mod, a_Name, a_Fn) \
99 if (RT_SUCCESS(rc)) \
100 rc = RTLdrGetSymbol(a_Mod, a_Name, (void **)&a_Fn); \
101 if (RT_FAILURE(rc)) \
102 LogRel2(("Symbol '%s' unable to load, rc=%Rrc\n", a_Name, rc));
103
104/**
105 * Tries to detect the desktop display server type the process is running in.
106 *
107 * @returns A value of VBGHDISPLAYSERVERTYPE, or VBGHDISPLAYSERVERTYPE_NONE if detection was not successful.
108 *
109 * @note Precedence is:
110 * - Connecting to Wayland (via libwayland-client.so) and/or X11 (via libX11.so).
111 * - VBGH_ENV_WAYLAND_DISPLAY
112 * - VBGH_ENV_XDG_SESSION_TYPE
113 * - VBGH_ENV_XDG_CURRENT_DESKTOP.
114 *
115 * Will print a warning to the release log if configuration mismatches.
116 */
117VBGHDISPLAYSERVERTYPE VBGHDisplayServerTypeDetect(void)
118{
119 LogRel2(("Detecting display server ...\n"));
120
121 /* Try to connect to the wayland display, assuming it succeeds only when a wayland compositor is active: */
122 bool fHasWayland = false;
123 RTLDRMOD hWaylandClient = NIL_RTLDRMOD;
124
125 /* Array of libwayland-client.so versions to search for.
126 * Descending precedence. */
127 const char* aLibsWayland[] =
128 {
129 "libwayland-client.so",
130 "libwayland-client.so.0" /* Needed for Ubuntu */
131 };
132
133 int rc = vbghDisplayServerTryLoadLib(aLibsWayland, RT_ELEMENTS(aLibsWayland), &hWaylandClient);
134 if (RT_SUCCESS(rc))
135 {
136 void * (*pWaylandDisplayConnect)(const char *) = NULL;
137 GET_SYMBOL(hWaylandClient, "wl_display_connect", pWaylandDisplayConnect);
138 void (*pWaylandDisplayDisconnect)(void *) = NULL;
139 GET_SYMBOL(hWaylandClient, "wl_display_disconnect", pWaylandDisplayDisconnect);
140 if (RT_SUCCESS(rc))
141 {
142 AssertPtrReturn(pWaylandDisplayConnect, VBGHDISPLAYSERVERTYPE_NONE);
143 AssertPtrReturn(pWaylandDisplayDisconnect, VBGHDISPLAYSERVERTYPE_NONE);
144 void *pDisplay = pWaylandDisplayConnect(NULL);
145 if (pDisplay)
146 {
147 fHasWayland = true;
148 pWaylandDisplayDisconnect(pDisplay);
149 }
150 else
151 LogRel2(("Connecting to Wayland display failed\n"));
152 }
153 RTLdrClose(hWaylandClient);
154 }
155
156 /* Array of libX11.so versions to search for.
157 * Descending precedence. */
158 const char* aLibsX11[] =
159 {
160 "libX11.so",
161 "libX11.so.6"
162 };
163
164 /* Also try to connect to the default X11 display to determine if Xserver is running: */
165 bool fHasX = false;
166 RTLDRMOD hX11 = NIL_RTLDRMOD;
167 rc = vbghDisplayServerTryLoadLib(aLibsX11, RT_ELEMENTS(aLibsX11), &hX11);
168 if (RT_SUCCESS(rc))
169 {
170 void * (*pfnOpenDisplay)(const char *) = NULL;
171 GET_SYMBOL(hX11, "XOpenDisplay", pfnOpenDisplay);
172 int (*pfnCloseDisplay)(void *) = NULL;
173 GET_SYMBOL(hX11, "XCloseDisplay", pfnCloseDisplay);
174 if (RT_SUCCESS(rc))
175 {
176 AssertPtrReturn(pfnOpenDisplay, VBGHDISPLAYSERVERTYPE_NONE);
177 AssertPtrReturn(pfnCloseDisplay, VBGHDISPLAYSERVERTYPE_NONE);
178 void *pDisplay = pfnOpenDisplay(NULL);
179 if (pDisplay)
180 {
181 fHasX = true;
182 pfnCloseDisplay(pDisplay);
183 }
184 else
185 LogRel2(("Opening X display failed\n"));
186 }
187
188 RTLdrClose(hX11);
189 }
190
191 /* If both wayland and X11 display can be connected then we should have XWayland: */
192 VBGHDISPLAYSERVERTYPE retSessionType = VBGHDISPLAYSERVERTYPE_NONE;
193 if (fHasWayland && fHasX)
194 retSessionType = VBGHDISPLAYSERVERTYPE_XWAYLAND;
195 else if (fHasWayland)
196 retSessionType = VBGHDISPLAYSERVERTYPE_PURE_WAYLAND;
197 else if (fHasX)
198 retSessionType = VBGHDISPLAYSERVERTYPE_X11;
199
200 LogRel2(("Detected via connection: %s\n", VBGHDisplayServerTypeToStr(retSessionType)));
201
202 return retSessionType;
203}
204
205/**
206 * Detect GTK library.
207 *
208 * @returns \c true if GTK library is available in the system.
209 */
210bool VBGHDisplayServerTypeIsGtkAvailable(void)
211{
212 int rc;
213
214 /* Array of libGtk.so versions to search for.
215 * Descending precedence. */
216 const char* aLibsGtk[] =
217 {
218 "libgtk-3.so",
219 "libgtk-3.so.0"
220 };
221
222 RTLDRMOD hGtk = NIL_RTLDRMOD;
223 void * (*pfnGtkInit)(const char *) = NULL;
224
225 rc = vbghDisplayServerTryLoadLib(aLibsGtk, RT_ELEMENTS(aLibsGtk), &hGtk);
226 if (RT_SUCCESS(rc))
227 {
228 GET_SYMBOL(hGtk, "gtk_init", pfnGtkInit);
229 RTLdrClose(hGtk);
230 }
231
232 return RT_SUCCESS(rc) && RT_VALID_PTR(pfnGtkInit);
233}
234
235#undef GET_SYMBOL
236
237/**
238 * Returns true if @a enmType is indicating running X.
239 *
240 * @returns \c true if @a enmType is running X, \c false if not.
241 * @param enmType Type to check.
242 */
243bool VBGHDisplayServerTypeIsXAvailable(VBGHDISPLAYSERVERTYPE enmType)
244{
245 return enmType == VBGHDISPLAYSERVERTYPE_XWAYLAND
246 || enmType == VBGHDISPLAYSERVERTYPE_X11;
247}
248
249/**
250 * Returns true if @a enmType is indicating running Wayland.
251 *
252 * @returns \c true if @a enmType is running Wayland, \c false if not.
253 * @param enmType Type to check.
254 */
255bool VBGHDisplayServerTypeIsWaylandAvailable(VBGHDISPLAYSERVERTYPE enmType)
256{
257 return enmType == VBGHDISPLAYSERVERTYPE_XWAYLAND
258 || enmType == VBGHDISPLAYSERVERTYPE_PURE_WAYLAND;
259}
260
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use