[Gambas-user] 'Single instance' app cannot reuse DBus.Name

T Lee Davidson t.lee.davidson at ...626...
Sat Feb 20 13:32:29 CET 2016


A single instance application is one in which only one instance is allowed to be running at the same time. Checking for an 
existing instance is quite regularly done simply with some sort of lock file or socket. If a lock is found, then just quit the 
app. But suppose you want to pass the current command line arguments along to the existing instance.

DBus is handy for that. We can check to see if our DBus.Name, "org.gambas.[Application.Name]" by default, is already registered 
on the bus and behave accordingly. The pseudo-logic is:

If DBusName.IsRegistered.With.DbusSessionDaemon  ' There is already an instance running
   Send the command line args, via message, to the existing (primary) instance and quit out of the transient instance
Else
   Go ahead and start a 'primary' instance and register our DBus.Name on the bus
End


In Gambas, we would send the message to the existing instance using the general format 
"DBus[DBus.Name][/Path/To/MyDBusObject].inMethod()".  But, apparently, this particular format invisibly tries to register a 
connection on the bus using DBus.Name. This causes a problem, because you cannot register the same name on the bus more than once.

In other words, even if you don't explicitly connect and register a name on the bus, simply trying to send a message on the bus 
causes an intrinsic registration; and, an exception.  And you cannot use a random, guaranteed-unique name for DBus.Name or else 
you wouldn't know what it is and would have no way of knowing 'who' to send the message to.

The solution is to change Dbus.Name in the transient instance just prior to passing along the command line data. Here is my 
original, error-producing code:

------
' DBusInterface class file

Inherits DBusObject
Create Static

Public Sub Receiver(myString As String)
   Print "Received: " & myString
End

---

' Gambas module file

Public Sub Main()
   If DBus["org.freedesktop.DBus"]["/"].NameHasOwner(DBus.Name)
     Print DBus.Name & " already has an owner."  ' Only one instance allowed
     ' ' Send command line args to existing instance
     DBus[DBus.Name]["/DBusInterface"].Receiver("command line arguments")  ' *[1] *[2]
     Quit
   Else
     DBus.Session.Register(DBusInterface, "/DBusInterface")
     Print "Press Ctrl+C to quit."
     While True
       Wait 0.1
     Wend
     DBus.Session.Unregister(DBusInterface)
   Endif
End
------

*[1]:	That line caused "org.freedesktop.DBus.Error.Failed: No return value",
	and a Segmentation Fault; even though no return value should have been expected.


The fix was to do some name swapping:

     ' ' Send command line args to existing instance
     ReceiverDbusName = DBus.Name 'Preserve receiver name
     DBus.Name = "org.gambas.Transient" & Application.Name  ' Set different name for transient relay of args.
     DBus[ReceiverDbusName]["/DBusInterface"].Receiver("command line arguments")


Problem solved! :-)



-- 
Lee
__________

"Artificial Intelligence is no match for natural stupidity."




More information about the User mailing list