Page 1 of 1

How to create a single instance app? (Solved)

Posted: Wed Feb 14, 2024 6:05 am
by torm

How to create a single instance app?

Must be more than one or two ways to do this.. I suspect. :)
Wrapper scripts are somewhat workarounds that I would like to leave out here.
Same with the temporary files on the disk.

Maybe use signal.h - before GUI creation?
And peek if another instance is already running, then send, say a signal or
ClientMessage, etc. that another instance knows and can monitor, to trigger some
predefined action?

Story 1, simple:
App A is clicked on the panel toolbar and runs.
App A is clicked again, the panel will not toggle or manage that.
Now A1 and A2 run both.
Question:
How A2 sends the signal S to A1 so that both quit?
Note:
Only the signal is sent and monitored.
A2 will not make it to GUI.

Story 2, tricky:
App A is set as a default handler for filetype C.
A uses child process B* to open file C.
When C is clicked in the filemanager, A runs Ba or Bb or B* to open the C,
depending on the C subtype.
Question:
When A1 runs B* with C1 - and C2 is clicked, how to hand over C2 to A1 from A2 ?
So that A1 would stop B* and start over with C2, while A2 quits.
Note:
Here we have at least a filename, with unknown lenght and size, aside the signal.
String buffer size used in main is 1024 before gtk_init

I hope it was readable :)
PS. Both apps are GTK2.


Re: How to create a single instance app?

Posted: Wed Feb 14, 2024 6:44 am
by user1234

In bash, we would just check if the process with that name is already running (using something like pidof). Not sure how you'll implement that in C?


The easiest will be to just call the command and read its output in your C code.


Re: How to create a single instance app?

Posted: Wed Feb 14, 2024 7:32 am
by dimkr

Use a lock file. flock() with LOCK_EX|LOCK_NB fails with EWOULDBLOCK in errno - that's how additional instances of the application can tell if the application is already running, or you can use just LOCK_EX to wait for the first instance to terminate.

If you create a lock file and lock it, then call fork() and exec() to run a different application, but the file descriptor is inherited, it remains locked. This is how application A can run application B and wait for B plus all children of B (unless B closes extra file descriptors before it starts them).

For communication between the processes, you can use D-Bus or Unix sockets (more work because the applications will need to "discover" each other somehow).


Re: How to create a single instance app?

Posted: Mon Feb 26, 2024 10:23 am
by torm

Thanks!

Ok, will report back if I get anywhere with this.
May take some time..

Some examples of wrapper scrips that I would like to replace.
With imaginary appname etc.
First example only switches the program on/off, nothing more.

Code: Select all

#!/bin/sh

## script for panel item toggle
## use as:  scriptname

appPID=$(pidof appname)

if [ "`pidof appname`" ]; then
	kill $appPID 2>/dev/null &
else
	appname -argument1 -argument2 &
fi

Second example gets the filename from ROX and writes in todo list,
then signals the running app about the new task. Else runs app with the
filename as an argument.
No polling, minimal c lines ;)
pkill is in BusyBox, just like pidof.
Note: If running appname as run-in-terminal client it may get killed.

Code: Select all

#!/bin/sh

## script for ROX-filer filetype shell command  
## use as:  scriptname "$1"

appPID=$(pidof appname)

if [ "`pidof appname`" ]; then
	echo "$1" > /path/.appfolder/todolist
	pkill -ALRM appname &
else
	appname -argument1 -argument2 "$1" &
fi