summaryrefslogtreecommitdiff
path: root/indra/newview/llappviewerlinux.cpp
diff options
context:
space:
mode:
authorJonathan "Geenz" Goodman <geenz@geenzo.com>2026-08-11 21:39:19 -0400
committerJonathan "Geenz" Goodman <geenz@geenzo.com>2026-08-11 21:39:19 -0400
commit8cabc33e960ca93fdc1a32c77cf611269d95d51b (patch)
tree931fcecac10bf73214efa07cc3d704ba2bd01272 /indra/newview/llappviewerlinux.cpp
parent9b7ab49575b54523128952af6686d17eb6696725 (diff)
parentd045f9aa32789a35628aced166145c182751acbf (diff)
Merge remote-tracking branch 'origin/develop-linux' into geenz/linux-to-develop
Diffstat (limited to 'indra/newview/llappviewerlinux.cpp')
-rw-r--r--indra/newview/llappviewerlinux.cpp789
1 files changed, 365 insertions, 424 deletions
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index fe0d6f6e7d..2fd0eebd44 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -34,27 +34,48 @@
#include "llurldispatcher.h" // SLURL from other app instance
#include "llviewernetwork.h"
#include "llviewercontrol.h"
-#include "llwindowsdl.h"
#include "llmd5.h"
#include "llfindlocale.h"
+#include "llversioninfo.h"
#include <exception>
-#if LL_DBUS_ENABLED
-# include "llappviewerlinux_api_dbus.h"
+#define SDL_MAIN_USE_CALLBACKS
+#include <SDL3/SDL_main.h>
+
+#include "SDL3/SDL.h"
+
+#include "llsdl.h"
+#include "llwindowsdl.h"
-// regrettable hacks to give us better runtime compatibility with older systems inside llappviewerlinux_api.h:
-#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0)
-#undef g_return_if_fail
-#define g_return_if_fail(COND) llg_return_if_fail(COND)
-// The generated API
-# include "llappviewerlinux_api.h"
+#ifdef LL_GLIB
+#include <gio/gio.h>
#endif
+#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService"
+#define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI"
+#define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI"
+
+static const char * DBUS_SERVER = "<node name=\"/com/secondlife/ViewerAppAPI\">\n"
+ " <interface name=\"com.secondlife.ViewerAppAPI\">\n"
+ " <annotation name=\"org.freedesktop.DBus.GLib.CSymbol\" value=\"viewer_app_api\"/>\n"
+ " <method name=\"GoSLURL\">\n"
+ " <annotation name=\"org.freedesktop.DBus.GLib.CSymbol\" value=\"dispatchSLURL\"/>\n"
+ " <arg type=\"s\" name=\"slurl\" direction=\"in\" />\n"
+ " </method>\n"
+ " </interface>\n"
+ "</node>";
+
+typedef struct
+{
+ GObject parent;
+} ViewerAppAPI;
+
namespace
{
int gArgC = 0;
char **gArgV = NULL;
+ LLAppViewerLinux* gViewerAppPtr = NULL;
void (*gOldTerminateHandler)() = NULL;
}
@@ -62,6 +83,97 @@ namespace
guint32 LLAppViewerLinux::sPowerInhibitCookie = 0;
bool LLAppViewerLinux::sPowerInhibitActive = false;
+void check_vm_bloat()
+{
+#if LL_LINUX
+ // watch our own VM and RSS sizes, warn if we bloated rapidly
+ static const std::string STATS_FILE = "/proc/self/stat";
+ FILE *fp = fopen(STATS_FILE.c_str(), "r");
+ if (fp)
+ {
+ static long long last_vm_size = 0;
+ static long long last_rss_size = 0;
+ const long long significant_vm_difference = 250 * 1024*1024;
+ const long long significant_rss_difference = 50 * 1024*1024;
+ long long this_vm_size = 0;
+ long long this_rss_size = 0;
+
+ ssize_t res;
+ size_t dummy;
+ char *ptr = nullptr;
+ for (int i=0; i<22; ++i) // parse past the values we don't want
+ {
+ res = getdelim(&ptr, &dummy, ' ', fp);
+ if (-1 == res)
+ {
+ LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL;
+ goto finally;
+ }
+ free(ptr);
+ ptr = nullptr;
+ }
+ // 23rd space-delimited entry is vsize
+ res = getdelim(&ptr, &dummy, ' ', fp);
+ llassert(ptr);
+ if (-1 == res)
+ {
+ LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL;
+ goto finally;
+ }
+ this_vm_size = atoll(ptr);
+ free(ptr);
+ ptr = nullptr;
+ // 24th space-delimited entry is RSS
+ res = getdelim(&ptr, &dummy, ' ', fp);
+ llassert(ptr);
+ if (-1 == res)
+ {
+ LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL;
+ goto finally;
+ }
+ this_rss_size = getpagesize() * atoll(ptr);
+ free(ptr);
+ ptr = nullptr;
+
+ LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL;
+
+ if (llabs(last_vm_size - this_vm_size) > significant_vm_difference)
+ {
+ if (this_vm_size > last_vm_size)
+ {
+ LL_WARNS() << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL;
+ }
+ }
+
+ if (llabs(last_rss_size - this_rss_size) > significant_rss_difference)
+ {
+ if (this_rss_size > last_rss_size)
+ {
+ LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL;
+ }
+ }
+
+ last_rss_size = this_rss_size;
+ last_vm_size = this_vm_size;
+
+finally:
+ if (ptr)
+ {
+ free(ptr);
+ ptr = nullptr;
+ }
+ fclose(fp);
+ }
+#endif // LL_LINUX
+}
static void exceptionTerminateHandler()
{
@@ -75,32 +187,85 @@ static void exceptionTerminateHandler()
gOldTerminateHandler(); // call old terminate() handler
}
-int main( int argc, char **argv )
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv)
{
// Call Tracy first thing to have it allocate memory
// https://github.com/wolfpld/tracy/issues/196
LL_PROFILER_FRAME_END;
LL_PROFILER_SET_THREAD_NAME("App");
+ gSDLMainHandled = true;
+
gArgC = argc;
gArgV = argv;
- LLAppViewer* viewer_app_ptr = new LLAppViewerLinux();
+ gViewerAppPtr = new LLAppViewerLinux();
// install unexpected exception handler
gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
- bool ok = viewer_app_ptr->init();
+ unsetenv( "LD_PRELOAD" ); // <FS:ND/> Get rid of any preloading, we do not want this to happen during startup of plugins.
+
+ // This needs to be set as early as possible
+ SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING, LLVersionInfo::getInstance()->getChannel().c_str());
+ SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_VERSION_STRING, LLVersionInfo::getInstance()->getVersion().c_str());
+ SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING, "com.secondlife.indra.viewer");
+ SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_CREATOR_STRING, "Linden Research Inc");
+ SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_COPYRIGHT_STRING, "Copyright (c) Linden Research, Inc. 2025");
+ SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_URL_STRING, "https://www.secondlife.com");
+ SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_TYPE_STRING, "game");
+
+ bool ok = gViewerAppPtr->init();
if(!ok)
{
LL_WARNS() << "Application init failed." << LL_ENDL;
- return -1;
+ return SDL_APP_FAILURE;
}
- // Run the application main loop
- while (! viewer_app_ptr->frame())
- {}
+ return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult SDL_AppIterate(void *appstate)
+{
+ // Run the application main loop
+ if (!gViewerAppPtr->frame())
+ {
+#if LL_GLIB
+ // Pump until we've nothing left to do or passed 1/15th of a
+ // second pumping for this frame.
+ static LLTimer pump_timer;
+ pump_timer.reset();
+ pump_timer.setTimerExpirySec(1.0f / 15.0f);
+ do
+ {
+ g_main_context_iteration(g_main_context_default(), false);
+ } while( g_main_context_pending(g_main_context_default()) && !pump_timer.hasExpired());
+#endif
+ // hack - doesn't belong here - but this is just for debugging
+ if (getenv("LL_DEBUG_BLOAT"))
+ {
+ check_vm_bloat();
+ }
+
+ return SDL_APP_CONTINUE;
+ }
+
+ if(LLApp::isError())
+ {
+ return SDL_APP_FAILURE;
+ }
+
+ return SDL_APP_SUCCESS;
+}
+
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
+{
+ return LLWindowSDL::handleEvents(*event);
+}
+
+void SDL_AppQuit(void *appstate, SDL_AppResult result)
+{
if (!LLApp::isError())
{
//
@@ -108,11 +273,11 @@ int main( int argc, char **argv )
// the assumption is that the error handler is responsible for doing
// app cleanup if there was a problem.
//
- viewer_app_ptr->cleanup();
+ gViewerAppPtr->cleanup();
}
- delete viewer_app_ptr;
- viewer_app_ptr = NULL;
- return 0;
+
+ delete gViewerAppPtr;
+ gViewerAppPtr = nullptr;
}
LLAppViewerLinux::LLAppViewerLinux()
@@ -130,12 +295,6 @@ LLAppViewerLinux::~LLAppViewerLinux()
bool LLAppViewerLinux::init()
{
- // g_thread_init() must be called before *any* use of glib, *and*
- // before any mutexes are held, *and* some of our third-party
- // libraries likes to use glib functions; in short, do this here
- // really early in app startup!
- if (!g_thread_supported ()) g_thread_init (NULL);
-
bool success = LLAppViewer::init();
#if LL_SEND_CRASH_REPORTS
@@ -157,7 +316,7 @@ bool LLAppViewerLinux::restoreErrorTrap()
}
/////////////////////////////////////////
-#if LL_DBUS_ENABLED
+#if LL_GLIB
typedef struct
{
@@ -167,101 +326,77 @@ typedef struct
static void viewerappapi_init(ViewerAppAPI *server);
static void viewerappapi_class_init(ViewerAppAPIClass *klass);
-///
-
-// regrettable hacks to give us better runtime compatibility with older systems in general
-static GType llg_type_register_static_simple_ONCE(GType parent_type,
- const gchar *type_name,
- guint class_size,
- GClassInitFunc class_init,
- guint instance_size,
- GInstanceInitFunc instance_init,
- GTypeFlags flags)
-{
- static GTypeInfo type_info;
- memset(&type_info, 0, sizeof(type_info));
-
- type_info.class_size = class_size;
- type_info.class_init = class_init;
- type_info.instance_size = instance_size;
- type_info.instance_init = instance_init;
-
- return g_type_register_static(parent_type, type_name, &type_info, flags);
-}
-#define llg_intern_static_string(S) (S)
-#define g_intern_static_string(S) llg_intern_static_string(S)
-#define g_type_register_static_simple(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) llg_type_register_static_simple_ONCE(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags)
-
G_DEFINE_TYPE(ViewerAppAPI, viewerappapi, G_TYPE_OBJECT);
void viewerappapi_class_init(ViewerAppAPIClass *klass)
{
}
-static bool dbus_server_init = false;
-
-void viewerappapi_init(ViewerAppAPI *server)
+static void dispatchSLURL(gchar const *slurl)
{
- // Connect to the default DBUS, register our service/API.
-
- if (!dbus_server_init)
- {
- GError *error = NULL;
-
- server->connection = lldbus_g_bus_get(DBUS_BUS_SESSION, &error);
- if (server->connection)
- {
- lldbus_g_object_type_install_info(viewerappapi_get_type(), &dbus_glib_viewerapp_object_info);
+ LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL;
- lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server));
+ std::string url = slurl;
+ LLMediaCtrl* web = NULL;
+ const bool trusted_browser = false;
+ LLURLDispatcher::dispatch(url, "", web, trusted_browser);
+}
- DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
+static void DoMethodeCall (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ LL_INFOS() << "DBUS message " << method_name << " from: " << sender << " interface: " << interface_name << LL_ENDL;
+ const gchar *slurl;
- guint request_name_ret_unused;
- // akin to org_freedesktop_DBus_request_name
- if (lldbus_g_proxy_call(serverproxy, "RequestName", &error, G_TYPE_STRING, VIEWERAPI_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_ret_unused, G_TYPE_INVALID))
- {
- // total success.
- dbus_server_init = true;
- }
- else
- {
- LL_WARNS() << "Unable to register service name: " << error->message << LL_ENDL;
- }
+ g_variant_get (parameters, "(&s)", &slurl);
+ dispatchSLURL(slurl);
+}
- g_object_unref(serverproxy);
- }
- else
+GDBusNodeInfo *gBusNodeInfo = nullptr;
+static const GDBusInterfaceVTable interface_vtable =
{
- g_warning("Unable to connect to dbus: %s", error->message);
- }
-
- if (error)
- g_error_free(error);
- }
+ DoMethodeCall
+ };
+static void busAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
+{
+ auto id = g_dbus_connection_register_object(connection,
+ VIEWERAPI_PATH,
+ gBusNodeInfo->interfaces[0],
+ &interface_vtable,
+ NULL, /* user_data */
+ NULL, /* user_data_free_func */
+ NULL); /* GError** */
+ g_assert (id > 0);
}
-gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error)
+static void nameAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
{
- bool success = false;
+}
- LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL;
+static void nameLost(GDBusConnection *connection, const gchar *name, gpointer user_data)
+{
- std::string url = slurl;
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- if (LLURLDispatcher::dispatch(url, "", web, trusted_browser))
- {
- // bring window to foreground, as it has just been "launched" from a URL
- // todo: hmm, how to get there from here?
- //xxx->mWindow->bringToFront();
- success = true;
- }
+}
+void viewerappapi_init(ViewerAppAPI *server)
+{
+ gBusNodeInfo = g_dbus_node_info_new_for_xml (DBUS_SERVER, NULL);
+ g_assert (gBusNodeInfo != NULL);
- *success_rtn = g_new (gboolean, 1);
- (*success_rtn)[0] = (gboolean)success;
+ g_bus_own_name(G_BUS_TYPE_SESSION,
+ VIEWERAPI_SERVICE,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ busAcquired,
+ nameAcquired,
+ nameLost,
+ NULL,
+ NULL);
- return TRUE; // the invokation succeeded, even if the actual dispatch didn't.
}
///
@@ -269,13 +404,6 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ
//virtual
bool LLAppViewerLinux::initSLURLHandler()
{
- if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
- {
- return false; // failed
- }
-
- g_type_init();
-
//ViewerAppAPI *api_server = (ViewerAppAPI*)
g_object_new(viewerappapi_get_type(), NULL);
@@ -285,49 +413,49 @@ bool LLAppViewerLinux::initSLURLHandler()
//virtual
bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
{
- if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
+ auto *pBus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, nullptr);
+
+ if( !pBus )
{
- return false; // failed
+ LL_WARNS() << "Getting dbus failed." << LL_ENDL;
+ return false;
}
- bool success = false;
- DBusGConnection *bus;
- GError *error = NULL;
-
- g_type_init();
+ auto pProxy = g_dbus_proxy_new_sync(pBus, G_DBUS_PROXY_FLAGS_NONE, nullptr,
+ VIEWERAPI_SERVICE, VIEWERAPI_PATH,
+ VIEWERAPI_INTERFACE, nullptr, nullptr);
- bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error);
- if (bus)
+ if( !pProxy )
{
- gboolean rtn = FALSE;
- DBusGProxy *remote_object =
- lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE);
-
- if (lldbus_g_proxy_call(remote_object, "GoSLURL", &error,
- G_TYPE_STRING, url.c_str(), G_TYPE_INVALID,
- G_TYPE_BOOLEAN, &rtn, G_TYPE_INVALID))
- {
- success = rtn;
- }
- else
- {
- LL_INFOS() << "Call-out to other instance failed (perhaps not running): " << error->message << LL_ENDL;
- }
-
- g_object_unref(G_OBJECT(remote_object));
+ LL_WARNS() << "Cannot create new dbus proxy." << LL_ENDL;
+ g_object_unref( pBus );
+ return false;
}
- else
+
+ auto *pArgs = g_variant_new( "(s)", url.c_str() );
+ if( !pArgs )
{
- LL_WARNS() << "Couldn't connect to session bus: " << error->message << LL_ENDL;
+ LL_WARNS() << "Cannot create new variant." << LL_ENDL;
+ g_object_unref( pBus );
+ return false;
}
- if (error)
- g_error_free(error);
+ auto pRes = g_dbus_proxy_call_sync(pProxy,
+ "GoSLURL",
+ pArgs,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, nullptr, nullptr);
- return success;
+
+
+ if( pRes )
+ g_variant_unref( pRes );
+ g_object_unref( pProxy );
+ g_object_unref( pBus );
+ return true;
}
-#else // LL_DBUS_ENABLED
+#else // LL_GLIB
bool LLAppViewerLinux::initSLURLHandler()
{
return false; // not implemented without dbus
@@ -336,8 +464,68 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
{
return false; // not implemented without dbus
}
-#endif // LL_DBUS_ENABLED
+#endif // LL_GLIB
+
+#if LL_GLIB
+
+namespace
+{
+ // Session-bus sleep inhibitors, tried in order; both hand back a uint cookie.
+ struct PowerInhibitor
+ {
+ const char* service;
+ const char* path;
+ const char* iface;
+ const char* uninhibit;
+ bool gnome_args;
+ };
+
+ const PowerInhibitor POWER_INHIBITORS[] =
+ {
+ { "org.freedesktop.PowerManagement", "/org/freedesktop/PowerManagement/Inhibit",
+ "org.freedesktop.PowerManagement.Inhibit", "UnInhibit", false },
+ { "org.gnome.SessionManager", "/org/gnome/SessionManager",
+ "org.gnome.SessionManager", "Uninhibit", true }
+ };
+
+ const PowerInhibitor* sActiveInhibitor = nullptr;
+
+ // Returns the reply, or null on failure. Takes ownership of args.
+ GVariant* call_power_manager(const PowerInhibitor& inhibitor, const char* method, GVariant* args,
+ const GVariantType* reply_type)
+ {
+ g_variant_ref_sink(args);
+
+ GDBusConnection* bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
+ if (!bus)
+ {
+ LL_WARNS("OS") << "Getting dbus failed." << LL_ENDL;
+ g_variant_unref(args);
+ return nullptr;
+ }
+
+ GError* error = nullptr;
+ GVariant* result = g_dbus_connection_call_sync(bus, inhibitor.service, inhibitor.path,
+ inhibitor.iface, method, args, reply_type,
+ G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error);
+ if (!result)
+ {
+ LL_DEBUGS("OS") << inhibitor.service << "." << method << " failed: "
+ << (error ? error->message : "unknown error") << LL_ENDL;
+ }
+ if (error)
+ {
+ g_error_free(error);
+ }
+
+ g_variant_unref(args);
+ g_object_unref(bus);
+ return result;
+ }
+}
+
+#endif // LL_GLIB
void LLAppViewerLinux::setOSHibernationMode(eHibernationMode mode)
{
@@ -391,302 +579,67 @@ void LLAppViewerLinux::setOSHibernationMode(eHibernationMode mode)
// TODO: This is AI Generated!!!, needs review and testing.
bool LLAppViewerLinux::inhibitPowerManagement(bool inhibit_display)
{
-#if LL_DBUS_ENABLED
- // Try to use D-Bus to inhibit power management via various desktop environment APIs
- // This works with GNOME, KDE, XFCE, and most modern Linux desktop environments
-
- if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
- {
- LL_WARNS("OS") << "Failed to load D-Bus symbols for power management" << LL_ENDL;
- return false;
- }
-
- GError* error = nullptr;
- DBusGConnection* bus = lldbus_g_bus_get(DBUS_BUS_SESSION, &error);
-
- if (!bus)
- {
- LL_WARNS("OS") << "Failed to connect to D-Bus session bus: "
- << (error ? error->message : "unknown error") << LL_ENDL;
- if (error)
- g_error_free(error);
- return false;
- }
-
- // Try multiple power management services in order of preference
- // 1. org.freedesktop.PowerManagement (older standard)
- // 2. org.gnome.SessionManager (GNOME)
- // 3. org.kde.Solid.PowerManagement (KDE)
-
- const char* services[] = {
- "org.freedesktop.PowerManagement",
- "org.gnome.SessionManager",
- "org.kde.Solid.PowerManagement"
- };
-
- const char* paths[] = {
- "/org/freedesktop/PowerManagement/Inhibit",
- "/org/gnome/SessionManager",
- "/org/kde/Solid/PowerManagement"
- };
+#if LL_GLIB
+ const char* reason = inhibit_display ?
+ "Viewer active - preventing system and display sleep" :
+ "Viewer active - preventing system sleep";
- const char* interfaces[] = {
- "org.freedesktop.PowerManagement.Inhibit",
- "org.gnome.SessionManager",
- "org.kde.Solid.PowerManagement"
- };
-
- const char* methods[] = {
- "Inhibit",
- "Inhibit",
- "inhibit"
- };
-
- bool success = false;
-
- for (int i = 0; i < 3 && !success; ++i)
+ for (const PowerInhibitor& inhibitor : POWER_INHIBITORS)
{
- DBusGProxy* proxy = lldbus_g_proxy_new_for_name(
- bus,
- services[i],
- paths[i],
- interfaces[i]
- );
-
- if (!proxy)
- continue;
-
- error = nullptr;
- guint32 cookie = 0;
+ // Inhibit(app: s, reason: s) -> u, or GNOME's Inhibit(app: s, xid: u, reason: s, flags: u) -> u
+ // GNOME flags: 4 = suspend, 8 = idle (display), 12 = both
+ GVariant* args = inhibitor.gnome_args ?
+ g_variant_new("(susu)", "SecondLifeViewer", (guint32)0, reason,
+ (guint32)(inhibit_display ? 12 : 4)) :
+ g_variant_new("(ss)", "Second Life Viewer", reason);
- if (i == 0) // freedesktop.PowerManagement
- {
- // Inhibit(application_name: s, reason: s) -> cookie: u
- success = lldbus_g_proxy_call(
- proxy,
- methods[i],
- &error,
- G_TYPE_STRING, "Second Life Viewer",
- G_TYPE_STRING, inhibit_display ?
- "Viewer active - preventing system and display sleep" :
- "Viewer active - preventing system sleep",
- G_TYPE_INVALID,
- G_TYPE_UINT, &cookie,
- G_TYPE_INVALID
- );
- }
- else if (i == 1) // GNOME SessionManager
- {
- // Inhibit(app_id: s, toplevel_xid: u, reason: s, flags: u) -> cookie: u
- // flags: 4 = suspend, 8 = idle (display), 12 = both
- guint32 flags = inhibit_display ? 12 : 4;
- success = lldbus_g_proxy_call(
- proxy,
- methods[i],
- &error,
- G_TYPE_STRING, "SecondLifeViewer",
- G_TYPE_UINT, 0, // toplevel_xid (0 = none)
- G_TYPE_STRING, inhibit_display ?
- "Viewer active - preventing system and display sleep" :
- "Viewer active - preventing system sleep",
- G_TYPE_UINT, flags,
- G_TYPE_INVALID,
- G_TYPE_UINT, &cookie,
- G_TYPE_INVALID
- );
- }
- else if (i == 2) // KDE Solid
+ GVariant* result = call_power_manager(inhibitor, "Inhibit", args, G_VARIANT_TYPE("(u)"));
+ if (!result)
{
- // Different method signature for KDE
- success = lldbus_g_proxy_call(
- proxy,
- methods[i],
- &error,
- G_TYPE_INVALID,
- G_TYPE_INT, &cookie,
- G_TYPE_INVALID
- );
+ continue;
}
- if (success)
- {
- sPowerInhibitCookie = cookie;
- sPowerInhibitActive = true;
- LL_INFOS("OS") << "Successfully inhibited power management using "
- << services[i] << LL_ENDL;
- }
- else if (error)
- {
- LL_DEBUGS("OS") << "Failed to inhibit via " << services[i]
- << ": " << error->message << LL_ENDL;
- g_error_free(error);
- error = nullptr;
- }
+ guint32 cookie = 0;
+ g_variant_get(result, "(u)", &cookie);
+ g_variant_unref(result);
- g_object_unref(proxy);
+ sPowerInhibitCookie = cookie;
+ sPowerInhibitActive = true;
+ sActiveInhibitor = &inhibitor;
+ LL_INFOS("OS") << "Successfully inhibited power management using "
+ << inhibitor.service << LL_ENDL;
+ return true;
}
+#endif // LL_GLIB
- return success;
-
-#else // !LL_DBUS_ENABLED
- LL_WARNS("OS") << "Power management control not available - D-Bus support not enabled" << LL_ENDL;
return false;
-#endif
}
void LLAppViewerLinux::uninhibitPowerManagement()
{
-#if LL_DBUS_ENABLED
- if (!sPowerInhibitActive || sPowerInhibitCookie == 0)
+#if LL_GLIB
+ if (sPowerInhibitActive && sActiveInhibitor)
{
- return;
- }
-
- if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME))
- {
- LL_WARNS("OS") << "Failed to load D-Bus symbols for power management uninhibit" << LL_ENDL;
- return;
- }
-
- GError* error = nullptr;
- DBusGConnection* bus = lldbus_g_bus_get(DBUS_BUS_SESSION, &error);
-
- if (!bus)
- {
- if (error)
- g_error_free(error);
- return;
- }
-
- // Try to uninhibit using all services that might have been used
- const char* services[] = {
- "org.freedesktop.PowerManagement",
- "org.gnome.SessionManager",
- "org.kde.Solid.PowerManagement"
- };
-
- const char* paths[] = {
- "/org/freedesktop/PowerManagement/Inhibit",
- "/org/gnome/SessionManager",
- "/org/kde/Solid/PowerManagement"
- };
-
- const char* interfaces[] = {
- "org.freedesktop.PowerManagement.Inhibit",
- "org.gnome.SessionManager",
- "org.kde.Solid.PowerManagement"
- };
-
- const char* methods[] = {
- "UnInhibit",
- "Uninhibit",
- "uninhibit"
- };
-
- bool success = false;
-
- for (int i = 0; i < 3; ++i)
- {
- DBusGProxy* proxy = lldbus_g_proxy_new_for_name(
- bus,
- services[i],
- paths[i],
- interfaces[i]
- );
-
- if (!proxy)
- continue;
-
- error = nullptr;
-
- if (lldbus_g_proxy_call(
- proxy,
- methods[i],
- &error,
- G_TYPE_UINT, sPowerInhibitCookie,
- G_TYPE_INVALID,
- G_TYPE_INVALID))
+ GVariant* result = call_power_manager(*sActiveInhibitor, sActiveInhibitor->uninhibit,
+ g_variant_new("(u)", (guint32)sPowerInhibitCookie),
+ nullptr);
+ if (result)
{
- success = true;
+ g_variant_unref(result);
LL_INFOS("OS") << "Successfully uninhibited power management using "
- << services[i] << LL_ENDL;
- }
- else if (error)
- {
- LL_DEBUGS("OS") << "Failed to uninhibit via " << services[i]
- << ": " << error->message << LL_ENDL;
- g_error_free(error);
- error = nullptr;
+ << sActiveInhibitor->service << LL_ENDL;
}
- g_object_unref(proxy);
-
- if (success)
- break;
+ sActiveInhibitor = nullptr;
}
+#endif // LL_GLIB
sPowerInhibitCookie = 0;
sPowerInhibitActive = false;
-
-#endif // LL_DBUS_ENABLED
}
void LLAppViewerLinux::initCrashReporting(bool reportFreeze)
{
- std::string cmd =gDirUtilp->getExecutableDir();
- cmd += gDirUtilp->getDirDelimiter();
-#if LL_LINUX
- cmd += "linux-crash-logger.bin";
-#else
-# error Unknown platform
-#endif
-
- std::stringstream pid_str;
- pid_str << LLApp::getPid();
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
- std::string appname = gDirUtilp->getExecutableFilename();
- // launch the actual crash logger
- const char * cmdargv[] =
- {cmd.c_str(),
- "-user",
- (char*)LLGridManager::getInstance()->getGridId().c_str(),
- "-name",
- LLAppViewer::instance()->getSecondLifeTitle().c_str(),
- "-pid",
- pid_str.str().c_str(),
- "-dumpdir",
- logdir.c_str(),
- "-procname",
- appname.c_str(),
- NULL};
- fflush(NULL);
-
- pid_t pid = fork();
- if (pid == 0)
- { // child
- execv(cmd.c_str(), (char* const*) cmdargv); /* Flawfinder: ignore */
- LL_WARNS() << "execv failure when trying to start " << cmd << LL_ENDL;
- _exit(1); // avoid atexit()
- }
- else
- {
- if (pid > 0)
- {
- // DO NOT wait for child proc to die; we want
- // the logger to outlive us while we quit to
- // free up the screen/keyboard/etc.
- ////int childExitStatus;
- ////waitpid(pid, &childExitStatus, 0);
- }
- else
- {
- LL_WARNS() << "fork failure." << LL_ENDL;
- }
- }
- // Sometimes signals don't seem to quit the viewer. Also, we may
- // have been called explicitly instead of from a signal handler.
- // Make sure we exit so as to not totally confuse the user.
- //_exit(1); // avoid atexit(), else we may re-crash in dtors.
}
bool LLAppViewerLinux::beingDebugged()
@@ -717,7 +670,7 @@ bool LLAppViewerLinux::beingDebugged()
base += 1;
}
- if (strcmp(base, "gdb") == 0)
+ if (strcmp(base, "gdb") == 0 || strcmp(base, "lldb") == 0)
{
debugged = yes;
}
@@ -729,18 +682,6 @@ bool LLAppViewerLinux::beingDebugged()
return debugged == yes;
}
-void LLAppViewerLinux::initLoggingAndGetLastDuration()
-{
- // Remove the last stack trace, if any
- // This file is no longer created, since the move to Google Breakpad
- // The code is left here to clean out any old state in the log dir
- std::string old_stack_file =
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
- LLFile::remove(old_stack_file);
-
- LLAppViewer::initLoggingAndGetLastDuration();
-}
-
bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp)
{
if (!clp.parseCommandLine(gArgC, gArgV))