Before turning to the static properties Desktop.ConfigDir, Desktop.DataDir, Desktop.RuntimeDir and Desktop.CacheDir of the Desktop (gb.desktop) class, you should read the information at https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html [1] carefully. The chapter in [1] gives a good introduction to the concept of base directories defined by environment variables such as $XDG_CONFIG_HOME or $XDG_DATA_HOME, to name two.
In a console, for selected environment variables, these values were read out for the user 'hans' (that is the author):
hans@mint-183 ~ $ echo $XDG_CONFIG_HOME (blank or not set) hans@mint-183 ~ $ echo $XDG_DATA_HOME (blank or not set) hans@mint-183 ~ $ echo $XDG_RUNTIME_DIR /run/user/1000 hans@mint-183 ~ $ echo $XDG_CACHE_HOME (blank or not set)
With this source code snippet you can query the current paths on your system as Gambas has read them out and defined them in case they are empty or not set:
Print "ConfigDir = "; Desktop.ConfigDir ' $XDG_CONFIG_HOME Print "DataDir = "; Desktop.DataDir ' $XDG_DATA_HOME Print "RuntimeDir = "; Desktop.RuntimeDir ' $XDG_RUNTIME_DIR Print "CacheDir = "; Desktop.CacheDir ' $XDG_CACHE_HOME
In the Gambas IDE console, the author produced the following output (B):
ConfigDir = /home/hans/.config DataDir = /home/hans/.local/share RuntimeDir = /run/user/1000 CacheDir = /home/hans/.cache
The difference between the two outputs (A) and (B) is quickly explained: If one of the above environment variables is empty or not set, Gambas will fall back on standard directories according to the specification in [1].
In addition, if the environment variable $XDG_RUNTIME_DIR is empty or not set, then applications should fall back on a substitute directory such as /tmp with similar functionality. In the file in the Gambas source code gambas_source_code/comp/src/gb.desktop/.src/Desktop.class, the Desktop.ConfigDir, Desktop.DataDir, Desktop.RuntimeDir and Desktop.CacheDir properties of the Desktop (gb.desktop) class are defined as function values like this:
Static Private Function ConfigDir_Read() As String Return GetDir("XDG_CONFIG_HOME", User.Home &/ ".config") End Static Private Function DataDir_Read() As String Return GetDir("XDG_DATA_HOME", User.Home &/ ".local/share") End Static Private Function CacheDir_Read() As String Return GetDir("XDG_CACHE_HOME", User.Home &/ ".cache") End Static Private Function RuntimeDir_Read() As String Dim sPath As String = Env["XDG_RUNTIME_DIR"] If Not sPath Then sPath = File.Dir(Temp$()) Error "gb.desktop: warning: XDG_RUNTIME_DIR is not set default to "; sPath Endif Return sPath End
Static Property Read ConfigDir As String
Returns the base directory where user-specific configuration files should be stored.
Examples:
Public sConfigDir As String Public Sub _new() ... sGlobalConfigDir = Desktop.ConfigDir &/ sVendor &/ Lower(sAppName) ' ~/.config/gambasbook/pathproject If Not Exist(sGlobalConfigDir) Then Shell.MkDir(sGlobalConfigDir) ... hSettings = New Settings(sGlobalConfigDir &/ File.SetExt(Lower(sAppName), "conf")) ' ~/.config/gambasbook/pathproject/pathproject.conf ... End Public Sub Form_Open() ... If hSettings["First/Value", 0] < 2 Then ' The 'About' window is displayed exactly 2 times i = hSettings["First/Value", 0] Inc i hSettings["First/Value"] = i hSettings.Save() FAbout.ShowModal() Endif End
Some Gambas programs store scripts - for example in shell, Perl, Python or Gambas - as `hooks` that are executed by the Gambas program on certain events. In this way, the script intervenes in the configuration of the programme. These scripts or the agreed directory that is searched by your programme should then be located in the base directory Desktop.ConfigDir.In programming, according to https://de.wikipedia.org/wiki/Hook_(computer science), `hook` refers to an interface with which programme source code of other languages can be integrated into a programme in order to extend it, to change their flow or to intercept certain events.
Static Property Read DataDir As String
Returns the base directory where user-specific data files are to be (permanently) stored.
In this base directory, among other things, the projects from the Gambas software farm are stored, which have been selected and installed in the start window of the IDE under 'Software farm …' in the dialogue. Example: /home/hans/.local/share/gambas3/src/ajmsoftware/gbAutoMount or Desktop.DataDir &/ “gambas3/src/ajmsoftware/gbAutoMount”.
The `ajmsoftware` stands for the developer name (vendor) and `gbAutoMount` for the project name.
Scripts (shell scripts and scripts in other languages such as Gambas or Python or Perl or PHP) that you have copied into the project directory or newly created there can be executed in the IDE without any problems if the script file has the necessary permissions, which are set for the case of a new script file with `rw-rw-r–'. Therefore, you must change these rights so that at least the owner has the right to execute the script file.
Case 1 - Script Test in the Gambas IDE
While the statement
txaResult.Insert(File.Load(sScriptPath))
with the path sScriptPath = “…/scripts/test_script.sh” displays the contents of the script file in the project directory in the TextArea txaResult, the following statement generates an error:
CHMOD sScriptPath To "..x......"
The reason is that the CHMOD instruction - just like the SHELL instruction - requires an absolute path! Therefore, the following two instructions work without problems:
CHMOD SetFullPath(sScriptPath) To "..x......" SHELL SetFullPath(sScriptPath) To sStore
This is the source code for the function SetFullPath(sPath As String):
Public Function SetFullPath(sPath As String) As String Dim sFullPath As String If Left(sPath, 1) = "~" Then sFullPath = User.Home & Mid(sPath, 1 + 1) Else If Exist(sPath) And Left(sPath, 1) <> "/" Then sFullPath = Application.Path &/ sPath Else sFullPath = sPath Endif Return sFullPath End
Case 2 - Script test in the project directory.
You have to take a completely different approach if you create an executable file *.gambas, open it in the project directory and start the programme there.
hans@mint-183 ~/Schreibtisch/RunScriptCHMOD $ gbr3 ./runscript.gambas
The reason is that files in a Gambas archive can only be read - execution fails! The following approach has proven successful for this case:
Source code:
Public Sub btnRunScript_Click() Dim sStore As String sRelativeScriptPath = ".../scripts/test_script.sh" sAbsoluteScriptPath = Desktop.DataDir &/ File.BaseName(sRelativeScriptPath) & ".sh" Copy sRelativeScriptPath To sAbsoluteScriptPath ' Chmod sAbsoluteScriptPath To "r-xr-xr-x" ' All rights are explicitly reset Chmod sAbsoluteScriptPath To "..x......" ' Only the "Execute" right is set for the owner - all others are retained! txaResult.Clear() Shell sAbsoluteScriptPath To sStore If sStore Then txaResult.Text = sStore txaResult.Pos = 0 Else Message.Error(Error.Text & "!") Endif If Exist(sAbsoluteScriptPath) Then Kill sAbsoluteScriptPath End
Or you can decide to copy the script file into a temporary file and choose /tmp as the base directory. Since the script is only needed temporarily, the above source text changes:
Public Sub btnRunScript_Click() Dim sStore As String sRelativeScriptPath = "scripts/test_script.sh" sTempScriptPath = Temp(File.BaseName(sRelativeScriptPath)) & ".sh" ' Absolute Path: /tmp/gambas.1000/4979/test_script.tmp.sh If Not Exist(sTempScriptPath) Then Copy sRelativeScriptPath To sTempScriptPath ' Chmod sTempScriptPath To "r-xr-xr-x" ' All rights are explicitly reset Chmod sTempScriptPath To "..x......" ' Only the "Execute" right is set for the owner - all others are retained txaResult.Clear() Shell sTempScriptPath To sStore If sStore Then txaResult.Text = sStore txaResult.Pos = 0 Else Message.Error(Error.Text & "!") Endif End
Good to know: The file with the path sTempScriptPath is automatically deleted when the Gambas programme is terminated.
Example 3
If you take a look at the source code (app/src/gambas3/.src/Project/Farm/CSoftware.class) regarding the software to maintain the database of installed software from the software farm:
Public Sub GetInstalledDir() As String Return Desktop.DataDir &/ "gambas3/src" &/ LCase(Vendor) &/ Name End
you will see that Desktop.DataDir is selected as the installation directory. The name of the developer can be specified via the 'Vendor' entry in the project properties.
Static Property Read CacheDir As String
Returns the base directory where user-specific, non-essential files should be stored. It is defined by the environment variable $XDG_CACHE_HOME. If $XDG_CACHE_HOME is not set or is empty, the default ~/.cache is used.
Static Property Read RuntimeDir As String
Returns the (base) directory /run/user/User-ID such as /run/user/1000 where user-specific, runtime-only files and other file objects such as local Unix sockets or named pipes are to be (temporarily) stored. The directory must belong to the user. He must be the only one who has read and write access to it. His Unix access mode must be 0700. The directory is defined by the environment variable $XDG_RUNTIME_DIR:
hans@mint-183 ~ $ echo $XDG_RUNTIME_DIR /run/user/1000
The /run directory a virtual, temporary file system. It exists in the main memory and is automatically emptied when the computer is restarted.
Example
Public Sub _new() ... sGlobalRuntimeDir = Desktop.RuntimeDir &/ sVendor &/ Lower(sAppName) ' /run/user/1000/gambasbook/pathproject If Not Exist(sGlobalRuntimeDir) Then Shell.MkDir(sGlobalRuntimeDir) ... sGlobalScriptsDir = sGlobalRuntimeDir &/ GetDirPath(sLocalScriptsDir) ' /run/user/1000/gambasbook/pathproject/scripts If Not Exist(sGlobalScriptsDir) Then Shell.MkDir(sGlobalScriptsDir) Endif For Each sFile In Dir(sLocalScriptsDir, "*.{sh,sql,pl,py,gbs}") If Not Exist(sGlobalScriptsDir &/ sFile) Then Copy sLocalScriptsDir &/ sFile To sGlobalScriptsDir &/ sFile Chmod sGlobalScriptsDir &/ sFile To "..x......" Endif Next ... End
First, all scripts with the appropriate filter for the extension are temporarily stored in the base directory sGlobalScriptsDir: /run/user/user_id/gambasbook/pathproject/scripts).For each copied script file, the right to execute (user) is set.
This is how the script dump.sh is called in an EXEC instruction:
Private Sub GetDBDumpExec() Dim aExecCommand As String[] ' The file extension .sql is automatically supplemented with the Dump command! aExecCommand = [sTempScriptPath, sGlobalDBHostDir &/ sDBName, sGlobalDBHostDir &/ "dump." & sDBTableName] Exec aExecCommand Wait End
In the directory ~/.local/share/gambasbook/pathproject/data/databases the file contacts.sql is saved.
Using base directories for permanent storage of selected files may require three different base directories to be used for a project. This certainly promotes the idea of always using the base paths for certain files in the same way.
In my opinion, however, there is nothing to be said against permanently storing all relevant files for a project in a base directory such as Desktop.DataDir with a trailing NameSpace/ProjectName.
Using the Application.Name, Application.Path and Application.Dir properties of the Application (gb) class holds some surprises. If you want to use these properties in your projects, then you should read the following sections carefully. The considerations presented also apply to the project type 'Library' and 'Component'.
The documentation says: 'Return the application name, as defined in the IDE project properties dialog.' This text is inaccurate and should be changed to:
'Returns the name of the application to run.'
If the application is executed in the IDE, it is the project name - as defined in the 'New Project' dialog.The project name is also the name of the automatically created project directory.If the application is executed outside the IDE directly or with `gbr3 path2project/archive_name.gambas`, it is the name of the executable file archive_name.gambas.If the application is executed outside the IDE with `gbx3 path2project_directory`, it is the name of the project directory.'
The following 4 cases demonstrate the use of the Application.Name property in a project.
Case 1: Running the application in the IDE - project name 'GetAppName'.
Figure 6.1.2.5.1: Start in the IDE
Case 2: Execution in the project directory GetAppName.
$ gbx3 ~/GB3BUCH/6K_Stream/6.1_Pfade/BuchProgramm/GetAppName
Figure 6.1.2.5.2: Start in the project directory
Case 3: Execution in the project directory GetAppName.
The name of the executable file has been changed from the (default) name GetAppName.gambas to get.app.name.gambas
$ gbr3 ~/GB3BUCH/6K_Stream/6.1_Pfade/BuchProgramm/GetAppName/get.app.name.gambas
Figure 6.1.2.5.3: Start in the project directory
Case 4 - Running a copy of the project directory.
The original project directory ../GetAppName was copied to ../GetAppNameCopy and the programme was started there.
hans@mint-183 ~ $ gbx3 ~/GB3BUCH/6K_Stream/6.1_Pfade/BuchProgramm/GetAppNameCopy
Figure 6.1.2.5.4: Start in a copy of the project directory
Conclusion: you should refrain from renaming a project directory or the existing Gambas archive *.gambas - without necessity - if you want to safely use the Application.Name property as an implementation detail in your project.
For the Application.Dir property, the documentation states:
'Returns the application directory. It is the current working directory defined at application startup.' 'Returns the programme directory. It is the current working directory defined at application startup'.
Here is a suggestion for an extended definition:
A) Returns the application directory as default working directory if in Gambas execution mode.
B) Returns the user home directory as default working directory if in development mode (inside the IDE).
The Application.Dir property returns the CWD (current working directory) - as it is set at the time the programme is started.
The Gambas process inherits its CWD from the IDE. If you start the IDE from your “Programs” menu, the CWD is the home directory.In all other cases, it is the directory from which you started the program. Do this experiment: Open a terminal. Type 'cd /tmp'. Start the Gambas IDE with 'gambas3'. Now you are in the IDE. In a project, 'Print Application.Dir' returns /tmp!
Gambas has no concept of relative file system paths. Any relative path you pass to, for example, OPEN, File.Load(…) or similar is interpreted as relative to the files in the project directory. To get into the computer's file system, you must use absolute paths. In this case, the use of the Application.Dir property can become useful.
Example:
Assume that you have created a program myprogram.gambas that needs to be passed a file 'myfile' for processing with a command line argument. For example, in order for the File.Load(absolutepath2myfile) or Picture.Load(absolutepath2myfile) methods to load the file, the file path must be absolute, which is user-unfriendly. As a user, instead of
$ gbr3 ./myprogram.gambas absolutepath2myfile
$ gbr3 ./myprogram.gambas myfile
instead of <code_b_14>, as you are used to from programmes in other programming languages with relative paths. You can use Application.Dir for exactly this case:
Source code excerpt for the ShowImageD project.
' Gambas class file Public Sub Form_Open() Dim sImagePath As String ' Assumption: The image path is relative to the CWD - as in all other languages. ' The image is located in the project directory. sImagePath = Application.Args[1] If sImagePath Not Begins "/" Then sImagePath = Application.Dir &/ sImagePath piboxImage.Picture = Picture.Load(sImagePath) End
Program start in two variants:
hans@mint-183 ~/Schreibtisch/ShowImageD $ gbr3 ./ShowImageD.gambas hgb.png hans@mint-183 ~/Schreibtisch/ShowImageD $ gbx3 /home/hans/Schreibtisch/ShowImageD -- hgb.png
Figure 6.1.2.5.5: Start with the image hgb.png
Conclusion: You can also use the Application.Env[“PWD”] property for Application.Dir. It uses the appropriate environment variable to display the CWD if it is set correctly. Taking up this idea, using the $PWD environment variable directly in Bash or in another shell could be a mediating approach:
$ gbr3 ./myprogram.gambas $PWD/myfile
Source code excerpt ShowImageP
' Gambas class file Public Sub Form_Open() Dim sImagePath As String sImagePath = Application.Args[1] piboxImage.Picture = Picture.Load(sImagePath) End
Programme start:
hans@mint-183 ~/Schreibtisch/ShowImageP $ gbr3 ./ShowImageP.gambas $PWD/hgb.png hans@mint-183 ~/Schreibtisch/ShowImageP $ gbx3 /home/hans/Schreibtisch/ShowImageP -- $PWD/hgb.png
Conclusion: the current working directory [CWD] is only interesting for command line programs and in Gambas one writes GUI programs much more often. The latter resort to file selection dialogues and these dialogues return absolute paths. The Application.Dir property is therefore used quite little.
The `Application.Path` property always returns the project directory where the source code of the project is located.
This gives rise to the following considerations:
(1) The Application.Path property is at most to be used for debugging or for phases of program development in the IDE, for example to store files created by the program in a special developer mode in the project directory.
(2) The Application.Path property should not be used as an implementation detail of a project because otherwise the program will not work if a user decides to create an executable archive file *.gambas from the project and open it. In this case all project files are stored in an archive and Application.Path makes no sense!
Example project 'Intro':
When the program is started, an image is displayed as an intro. The image hgb.png is in the project folder in the (sub-)folder 'images'. The executable archive file is named show.intro.gambas. The source code is short:
' Gambas class file Public Sub Form_Open() Dim sImagePath As String FMain.Icon = Picture.Load(".../symbols/form_icon.png") sImagePath = Application.Path &/ "images/hgb.png" piboxImage.Picture = Picture.Load(sImagePath) End
(a) Start in the IDE with F5 or via the button in the toolbar with the symbol ► → ok
(b) The program is started directly in the project directory → ok
(c) Start console: hans@mint-183 ~/Desk $ gbr3 Intro/show.intro.gambas → ok
(d) Start console: hans@mint-183 ~/desk $ gbx3 Intro → ok
Finally, copy only the executable archive file show.intro.gambas to the home directory and start it directly there:
Figure 6.1.2.5.6: Start in the home directory
The error is understandable because the Application.Path property no longer points to the /home/hans/Desk/Intro directory but to /home/hans and therefore the image file cannot be loaded. What now - what to do? Here is a suggestion:
Replace the line
sImagePath = Application.Path &/ "images/hgb.png"
with
sImagePath = ".../images/hgb.png"
and the error is eliminated because the resolution of the relative path is now always correct!