1212#include " i18n/Engine.hpp"
1313
1414#include < iostream>
15+ #include < chrono>
16+ #include < cstdlib>
17+ #include < thread>
1518
19+ #include < hyprutils/os/ProcLock.hpp>
1620#include < hyprutils/string/ConstVarList.hpp>
1721
1822using namespace Hyprutils ::String;
23+ using namespace Hyprutils ::OS ;
1924
2025static void printHelp () {
2126 std::cout << " Hyprlauncher usage: hyprlauncher [arg [...]].\n\n Arguments:\n "
@@ -45,6 +50,18 @@ static std::vector<std::string> parseExplicitFromStdin() {
4550 return result;
4651}
4752
53+ static const char * procLockErrorString (CProcLock::eProcLockObtainingError error) {
54+ switch (error) {
55+ case CProcLock::eProcLockObtainingError::ALREADY_TAKEN : return " lock already taken by this process" ;
56+ case CProcLock::eProcLockObtainingError::NO_ENVIRONMENT : return " XDG_RUNTIME_DIR is unset" ;
57+ case CProcLock::eProcLockObtainingError::ALREADY_RUNNING : return " another instance is running" ;
58+ case CProcLock::eProcLockObtainingError::PERMISSIONS_INSUFFICIENT : return " insufficient permissions for runtime lock" ;
59+ case CProcLock::eProcLockObtainingError::UNKNOWN : return " unknown error" ;
60+ }
61+
62+ return " unknown error" ;
63+ }
64+
4865int main (int argc, char ** argv, char ** envp) {
4966
5067 bool openByDefault = true , dmenuMode = false , toggle = false ;
@@ -89,12 +106,28 @@ int main(int argc, char** argv, char** envp) {
89106 }
90107 }
91108
92- auto socket = makeShared<CClientIPCSocket>();
93-
94109 if (dmenuMode)
95110 explicitOptions = parseExplicitFromStdin ();
96111
97- if (socket->m_connected ) {
112+ const auto WAYLAND_DISPLAY_ENV = getenv (" WAYLAND_DISPLAY" );
113+ const auto WAYLAND_DISPLAY = WAYLAND_DISPLAY_ENV ? std::string{WAYLAND_DISPLAY_ENV } : std::string{};
114+
115+ CProcLock procLock{" hyprlauncher" , {{" WAYLAND_DISPLAY" , WAYLAND_DISPLAY }}};
116+ const auto lockResult = procLock.obtain (CProcLock::eProcLockFlags::EXCLUSIVE );
117+
118+ if (!lockResult) {
119+ if (lockResult.error () != CProcLock::eProcLockObtainingError::ALREADY_RUNNING ) {
120+ Debug::log (ERR , " Failed to obtain process lock: {}" , procLockErrorString (lockResult.error ()));
121+ return 1 ;
122+ }
123+
124+ SP <CClientIPCSocket> socket = makeShared<CClientIPCSocket>(WAYLAND_DISPLAY );
125+
126+ if (!socket->m_connected ) {
127+ Debug::log (ERR , " Another instance is running, but its IPC socket is unavailable (probably starting up)" );
128+ return 1 ;
129+ }
130+
98131 Debug::log (TRACE , " Active instance already, opening launcher." );
99132 if (!explicitOptions.empty ())
100133 socket->sendOpenWithOptions (explicitOptions);
@@ -103,7 +136,11 @@ int main(int argc, char** argv, char** envp) {
103136 return 0 ;
104137 }
105138
106- g_serverIPCSocket = makeUnique<CServerIPCSocket>();
139+ g_serverIPCSocket = makeUnique<CServerIPCSocket>(WAYLAND_DISPLAY );
140+ if (!g_serverIPCSocket->valid ()) {
141+ Debug::log (ERR , " Failed to open IPC server socket" );
142+ return 1 ;
143+ }
107144
108145 g_desktopFinder = makeUnique<CDesktopFinder>();
109146 g_unicodeFinder = makeUnique<CUnicodeFinder>();
@@ -117,8 +154,6 @@ int main(int argc, char** argv, char** envp) {
117154 g_ipcFinder->init ();
118155 g_fontFinder->init ();
119156
120- socket.reset ();
121-
122157 I18n::initEngine ();
123158
124159 if (!explicitOptions.empty ()) {
0 commit comments