From ce482b52c5e8167af427bae0744ea3d5ff8b11f7 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Wed, 24 Jul 2013 19:16:31 +0000 Subject: [PATCH] [mapplauncherd] Remove X11 dependency from single-instance. Instead of using windowsystem-specific functionality, ask the system compositor to activate the given binary for us. --- rpm/mapplauncherd.spec | 1 + rpm/mapplauncherd.yaml | 1 + src/launcherlib/booster.cpp | 10 -- src/single-instance/CMakeLists.txt | 8 +- src/single-instance/main.cpp | 235 +++++------------------------ 5 files changed, 45 insertions(+), 210 deletions(-) diff --git a/rpm/mapplauncherd.spec b/rpm/mapplauncherd.spec index 4bed8c1..380c923 100644 --- a/rpm/mapplauncherd.spec +++ b/rpm/mapplauncherd.spec @@ -27,6 +27,7 @@ BuildRequires: pkgconfig(xext) BuildRequires: pkgconfig(systemd) BuildRequires: pkgconfig(QtCore) BuildRequires: pkgconfig(QtTest) +BuildRequires: pkgconfig(dbus-1) BuildRequires: cmake BuildRequires: python Provides: meegotouch-applauncherd > 3.0.3 diff --git a/rpm/mapplauncherd.yaml b/rpm/mapplauncherd.yaml index af6b36d..944d806 100644 --- a/rpm/mapplauncherd.yaml +++ b/rpm/mapplauncherd.yaml @@ -21,6 +21,7 @@ PkgConfigBR: # For tests only - QtCore - QtTest + - dbus-1 PkgBR: - cmake - python diff --git a/src/launcherlib/booster.cpp b/src/launcherlib/booster.cpp index e21941e..93cbff2 100644 --- a/src/launcherlib/booster.cpp +++ b/src/launcherlib/booster.cpp @@ -124,11 +124,6 @@ void Booster::initialize(int initialArgc, char ** initialArgv, int newBoosterLau { if (!pluginEntry->lockFunc(m_appData->appName().c_str())) { -#ifdef USE_X11 - // Set XErrorHandler to handle possible errors from X - XErrorHandler oldHandler = XSetErrorHandler(Booster::handleXError); -#endif - // Try to activate the window of the existing instance if (!pluginEntry->activateExistingInstanceFunc(m_appData->appName().c_str())) { @@ -140,11 +135,6 @@ void Booster::initialize(int initialArgc, char ** initialArgv, int newBoosterLau m_connection->sendExitValue(EXIT_SUCCESS); } m_connection->close(); - -#ifdef USE_X11 - // Return original XErrorHandler - XSetErrorHandler(oldHandler); -#endif // invoker requested to start an application that is already running // booster is not needed this time, let's wait for the next connection from invoker diff --git a/src/single-instance/CMakeLists.txt b/src/single-instance/CMakeLists.txt index 5707385..cc04ba2 100644 --- a/src/single-instance/CMakeLists.txt +++ b/src/single-instance/CMakeLists.txt @@ -3,12 +3,12 @@ set(COMMON "${CMAKE_HOME_DIRECTORY}/src/common") # Set sources set(SRC main.cpp ${COMMON}/report.c) -# Find X11 +# Find dbus include(FindPkgConfig) -pkg_check_modules(X11 x11 REQUIRED) +pkg_check_modules(DBUS dbus-1 REQUIRED) # Set include dirs -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${X11_INCLUDE_DIRS} ${COMMON}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${DBUS_INCLUDE_DIRS} ${COMMON}) # Hide all symbols except the ones explicitly exported in the code (like main()) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fPIC") @@ -20,7 +20,7 @@ set(CMAKE_EXE_LINKER_FLAGS "-pie -rdynamic") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fPIC") # Set link libraries -link_libraries(${X11_LDFLAGS}) +link_libraries(${DBUS_LDFLAGS}) # Set target add_executable(single-instance ${SRC}) diff --git a/src/single-instance/main.cpp b/src/single-instance/main.cpp index 71ca653..598c88a 100644 --- a/src/single-instance/main.cpp +++ b/src/single-instance/main.cpp @@ -17,8 +17,8 @@ ** ****************************************************************************/ -#include -#include +#include + #include #include #include @@ -69,14 +69,6 @@ static bool mkpath(const std::string & path) return true; } -int handleXError(Display *dpy, XErrorEvent *e) -{ - char errorText[1024]; - XGetErrorText( dpy, e->error_code, errorText, sizeof(errorText) ); - report(report_error, "Xerror: %s\n", errorText ); - return 0; -} - //! Print help. static void printHelp() { @@ -90,172 +82,6 @@ static void printHelp() PROG_NAME_SINGLE_INSTANCE, PROG_NAME_SINGLE_INSTANCE); } -//! Activate a window. -static int clientMsg(Display *disp, Window win, const char *msg, - unsigned long data0, unsigned long data1, - unsigned long data2, unsigned long data3, - unsigned long data4) -{ - XEvent event; - long mask = SubstructureRedirectMask | SubstructureNotifyMask; - - event.xclient.type = ClientMessage; - event.xclient.serial = 0; - event.xclient.send_event = True; - event.xclient.message_type = XInternAtom(disp, msg, True); - event.xclient.window = win; - event.xclient.format = 32; - event.xclient.data.l[0] = data0; - event.xclient.data.l[1] = data1; - event.xclient.data.l[2] = data2; - event.xclient.data.l[3] = data3; - event.xclient.data.l[4] = data4; - - // XInternAtom will return None if atom does not exists - if (event.xclient.message_type && XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) - { - return EXIT_SUCCESS; - } - else - { - report(report_error, "Cannot send %s event.\n", msg); - return EXIT_FAILURE; - } -} - -/*! - * \brief Return binary name assigned to a process id. - * - * Source for the binary name is /proc/[pid]/cmdline. - * - * \param pid The process id. - * \return Full path to the command on success, empty string on failure. - */ -static std::string binaryNameForPid(int pid) -{ - std::string cmdLine; - - std::stringstream ss; - ss << "/proc/" << pid << "/cmdline"; - - std::ifstream procFile; - procFile.open(ss.str().c_str()); - if (procFile.is_open()) - { - procFile >> cmdLine; - - size_t nul = cmdLine.find_first_of('\0'); - if (nul != std::string::npos) - { - cmdLine = cmdLine.substr(0, nul); - } - } - - return cmdLine; -} - -/*! - * \brief Return pid assigned to a window id. - * - * \param dpy The X11 display. - * \param window The window id. - * \return Pid on success, -1 on failure. - */ -static int windowPid(Display * dpy, Window window) -{ - if (dpy) - { - static Atom pidAtom = XInternAtom(dpy, "_NET_WM_PID", False); - Atom type; - int format; - unsigned long nItems; - unsigned long bytesAfter; - unsigned char *propPID = 0; - - // Get the PID of the window - if(XGetWindowProperty(dpy, window, pidAtom, 0, 1, False, XA_CARDINAL, - &type, &format, &nItems, &bytesAfter, &propPID) == Success) - { - if(propPID != 0) - { - // If the PID matches, add this window to the result set. - int pid = *(reinterpret_cast(propPID)); - XFree(propPID); - return pid; - } - } - } - - return -1; -} - -//! Raise given window of the given display -void raiseWindow(Display *dpy, Window window) -{ - clientMsg(dpy, window, "_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); - XSync(dpy, False); -} - -/*! - * \brief Return window id for the given binary. - * - * This method first fetches _NET_CLIENT_LIST for window candidates, - * and then finds the matching binary using /proc/[pid]/cmdline. - * Proc fs is primarily used, because we cannot trust WM_COMMAND window property - * in all cases. Anyhow we check also WM_COMMAND because proc fs does not work - * with scripts (python etc.). - * - * \param dpy The X11 display. - * \param binaryName Full path to the binary. - * \return Window id on success, 0 on failure. - */ -Window windowIdForBinary(Display *dpy, const char *binaryName) -{ - Window retValue = 0; - if (dpy) - { - Atom netClientListAtom = XInternAtom(dpy, "_NET_CLIENT_LIST", False); - Atom type; - int format; - unsigned long nItems = 0; - unsigned long bytesAfter; - unsigned char *prop = 0; - - // Get the client list of the root window - int status = XGetWindowProperty(dpy, XDefaultRootWindow(dpy), netClientListAtom, - 0, 0x7fffffff, False, XA_WINDOW, - &type, &format, &nItems, &bytesAfter, &prop); - - if ((status == Success) && (prop != NULL)) - { - Window * clients = reinterpret_cast(prop); - for (unsigned long i = 0; i < nItems; i++) - { - char **wmCommand = NULL; - int wmCommandCount = 0; - - if (binaryNameForPid(windowPid(dpy, clients[i])) == binaryName || - (XGetCommand (dpy, clients[i], &wmCommand, &wmCommandCount) != 0 && - wmCommandCount > 0 && strcmp(wmCommand[0], binaryName) == 0)) - { - retValue = clients[i]; - } - - if (wmCommand) { - XFreeStringList(wmCommand); - } - - if (retValue) - break; - } - - XFree(prop); - } - } - - return retValue; -} - // **** Export these functions when used as a library **** extern "C" @@ -317,26 +143,45 @@ extern "C" //! Activate existing application DECL_EXPORT bool activateExistingInstance(const char * binaryName) { - if (Display * dpy = XOpenDisplay(NULL)) - { - if (Window winId = windowIdForBinary(dpy, binaryName)) - { - raiseWindow(dpy, winId); - XCloseDisplay(dpy); - return true; - } - else - { - report(report_error, "Lock reserved but no window id for binary name found.\n"); - XCloseDisplay(dpy); - return false; - } + DBusError error; + + dbus_error_init(&error); + DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error); + if (!bus) { + report(report_error, "Can't get session bus connection"); + goto err; } - else - { - report(report_error, "Failed to open display!\n"); - return false; + + DBusMessage *msg; + DBusMessageIter args; + + msg = dbus_message_new_method_call("org.nemomobile.lipstick", + "/WindowModel", + "local.Lipstick.WindowModel", + "launchProcess"); + if (!msg) { + report(report_error, "Can't allocate bus message"); + goto err; } + + dbus_message_iter_init_append(msg, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &binaryName)) { + report(report_error, "Can't allocate bus message"); + goto err; + } + + if (!dbus_connection_send(bus, msg, NULL)) { + report(report_error, "Can't send message"); + goto err; + } + + /* as we don't have a guarenteed mainloop, we must flush */ + dbus_connection_flush(bus); + return true; + +err: + dbus_error_free(&error); + return false; } } @@ -357,9 +202,7 @@ int main(int argc, char **argv) { if (!lock(argv[1])) { - XErrorHandler oldHandler = XSetErrorHandler(handleXError); bool success = activateExistingInstance(argv[1]); - XSetErrorHandler(oldHandler); if (!success) { return EXIT_FAILURE;