Gtk C Application - Set PWD so pictures work - c

I have a simple Gtk GUI application written in C. I want to be able to render external images within a frame in my main window. The code for this is as follows:
GtkWidget myImage;
myImage = gtk_image_new_from_file("assets/image.png");
gtk_fixed_put(FTK_FIXED(frame), myImage, 0, 0));
The image shows as expected, but only if I cd into the directory where it exists. ie:
cd /tmp/bin/
./gtktest
If I run it from another location, like so, the image is never found.
/tmp/bin/gtktest
Is there a way to have the application set the present working directory (PWD) to the location of the binary itself?
Thank you.

You are using a relative path to cwd but you need to use either a relative path based on the location of the program binary or an absolute path based on the filesystem's root like /usr/lib/yourprogram/assets.
If you want to build a relative path based on the location of the binary, which might be more flexible in some situations, then you should use dirname(). Like this:
char *my_location = dirname(argv[0]); // argv[0] contains the path to the binary
Check man 3 dirname for more info.

Put the assets inside a GResource and compile them directly into your program.

You could call chdir(2) from inside your Gtk program, or its Glib wrapper g_chdir

Related

Relative paths from binary file

I have the following folder structure:
bin/ <-binary-file is in here
include/
src/
data/
Makefile
In my code, I use relative paths to my data. So "../data/xml/xmlFile.xml". This is fine if I were executing the binary file from the bin/ folder:
brandonto#computer:~/PATH-TO-PROJECT/bin$ ./binary-file
argv[0] = ./binary-file
dirname(argv[0]) = .
But if I were executing the binary from the main folder (or any other folder that is not the bin/ folder):
brandonto#computer:~/PATH-TO-PROJECT$ bin/binary-file
argv[0] = bin/binary-file
dirname(argv[0]) = bin
The xml files would not be found because "../data" would now go up one directory from the main folder (or whatever folder you are in when executing the program).
How could I make it so that the binary file could be executed from any directory on my system?
To make the question a little more clear:
brandonto#brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter/bin$ ~/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
argv[0] = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
dirname(argv[0]) = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin
brandonto#brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter/bin$ cd ..
brandonto#brandonto-Aspire-S3-391:~/cpp-workspace/sdl-projects/sdl-space-shooter$ ~/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
argv[0] = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin/SpaceShooter
dirname(argv[0]) = /home/brandonto/cpp-workspace/sdl-projects/sdl-space-shooter/bin
Unable to load image ../data/graphics/background/darkPurple.png! SDL_image Error: Couldn't open ../data/graphics/background/darkPurple.png
Unable to load image ../data/graphics/sprites/meteorBrown_big1.png! SDL_image Error: Couldn't open ../data/graphics/sprites/meteorBrown_big1.png
Here, I executed the binary file once from inside the bin/ folder, then once from inside the main folder. The binary ran fine from inside the bin/ folder, but could not find the relative paths to the .png files from inside the main folder.
Probably you are asking a wrong question: the build system has nothing to do with program execution.
However, if you look for an answer, how to make my program to correctly use data, that is located relative to program installation, than here is an answer.
When you program main gets executed, it gets the binary path as the first parameter (index 0). That path can be relative or absolute, but in any case it allows you to find the base directory.
These are also useful links:
How do I find the location of the executable in C?
Finding current executable's path without /proc/self/exe
Here how you can use first argument:
#include <linux/limits.h>
#include <stdio.h>
#include <string.h>
#include <libgen.h>
int main(int argc, char *argv[])
{
char datadir[PATH_MAX];
strncpy(datadir, argv[0], sizeof(datadir));
dirname(datadir);
strncat(datadir, "/../data", sizeof(datadir));
printf("Data dir: %s\n", datadir);
return 0;
}
I believe that you can find your process id (pid) using the getpid command and perform functions to extract the directory in a manner similar to this question on Ask Ubuntu.
I would have the data associated in some way (organizationally) with the bin directory where the executable resides.
Then, when running the routine, if a complete path is provided (noted by checking arg[0]), then you can find the data directory. If a relative path is provided, then search the search path sequentially until you find the executable, and then you can therefore find the data directory.
No pids needed. (I think this is how Python finds its way, or at least how it used to do so.)
I usually solve this with a program setting. In the good old days I would have these settings in a .ini file which would accompany the executable. Some settings would be configurable from within the program, and all could be edited with a text editor. If the file was missing, or any setting missing, they would be created by default.
For the location of the program's data I would use its full absolute path name. For example it might be
Datapath = D:\os50k
and the program then appends individual file names to the path as necessary.
These days in Windows the System Registry is used for this purpose. However your question is tagged Linux which stores settings in various places, including the program directory.
This question, and this question describe the process more fully.
If your paths can be determined at build time, (i.e. your project will never need to be installed to another directory,) you can inject the path through the build system as a preprocessor definition. Here's an example with CMake:
file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/resources" RESOURCE_DIR) # Normalize Windows/Linux paths
add_custom_command(
TARGET my_target POST_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/resources ${RESOURCE_DIR}
)
target_compile_definitions(my_target PUBLIC RESOURCE_DIR=${RESOURCE_DIR})
.
#define VAL(x) #x
#define STR(x) VAL(x)
const char* my_resource = STR(RESOURCE_DIR) "/my_resource.abc";

Allegro load_bitmap not working

i'm trying to load bitmap like this:
BITMAP *image = load_bitmap("picture.bmp", NULL);
when I test it:
if (image == NULL)
printf("No image loaded\n");
it prints No image loaded so load_bitmap doesn't work ... i have also tried absolute path but still nothing.
Im using Ubuntu and allegro 4.2
Some suggestions?
Did you try placing the image on the same location as the executable? After that is solved check this things also if still getting the error:
Is really a *.bmp file? A file of a different type can not be converted by just renaming it.
Is the file you are trying to read actually called like that? Check for spelling both in code and in the file explorer.
Does the program run correctly if executed from the file explorer or command-line but not from the IDE? If that is the case, then you should change the configuration of the workspace or project you are currently using so that the execution directory is the same as the one where the image file is located.
If all else fails then try following the steps of the tutorial again, perhaps you made something wrong. By the way, if this is your first C++ project I recommend you that instead go to more basic stuff and stick to the command-line for a while until you get the hang of the facilities the language and its libraries have to offer.

Add files with target using CMake

I am working using CMake on a little C project using OpenGL. To be able to run, my executable needs to access some resources files such as 3D meshes, textures or shader program sources.
When I run the generated executable, the current folder is the directory where it is created. This directory may differ depending on the binary tree location (out of source ? insource ? anywhere in the coputer). But my resources are located near my source tree.
I would like my CMakeLists.txt to copy the resource folder in my executable output directory but I have not a good idea of the way to do that. Besides, I am not sure this is a "best practice" of CMake.
Thank you for reading :)
You have 2 useful variable to do so: CMAKE_CURRENT_BINARY_DIR and CMAKE_BINARY_DIR, the former refers to the current CMakeLists.txt output directory, the latter refers to the top level project output directory.
Most of the time, you handle resources near the executable depending on it, then you'll certainly want to refer to CMAKE_CURRENT_BINARY_DIR.
configure_file(
"MyResourceDir/myresource"
"${CMAKE_CURRENT_BINARY_DIR}/" COPYONLY
)
This command will copy resource of the CURRENT_CMAKE_SOURCE_DIR/MyResourceDir named myresource in the directory matching the current CMakeLists.txt.
You can glob files of your MyResourceDir and loop on it (maybe there is also some function to copy directory instead of list of files).

How to define relative paths in Visual Studio Project?

I have a library and a console application that uses a library. The library has a folder with source and header files.
My project is in a child/inner directory but that library directory that I want to include is in a parent/upper directory.
My project directory:
H:\Gmail_04\gsasl-1.0\lib\libgsaslMain
Includes files are here:
H:\Gmail_04\gsasl-1.0\src
How can I use paths relative to the project directory, to include folders that are in a parent/upper directory?
Instead of using relative paths, you could also use the predefined macros of VS to achieve this.
$(ProjectDir) points to the directory of your .vcproj file, $(SolutionDir) is the directory of the .sln file.
You get a list of available macros when opening a project, go to
Properties → Configuration Properties → C/C++ → General
and hit the three dots:
In the upcoming dialog, hit Macros to see the macros that are predefined by the Studio (consult MSDN for their meaning):
You can use the Macros by typing $(MACRO_NAME) (note the $ and the round brackets).
If I get you right, you need ..\..\src
I have used a syntax like this before:
$(ProjectDir)..\headers
or
..\headers
As other have pointed out, the starting directory is the one your project file is in(vcproj or vcxproj), not where your main code is located.
By default, all paths you define will be relative. The question is: relative to what? There are several options:
Specifying a file or a path with nothing before it. For example: "mylib.lib". In that case, the file will be searched at the Output Directory.
If you add "..\", the path will be calculated from the actual path where the .sln file resides.
Please note that following a macro such as $(SolutionDir) there is no need to add a backward slash "\". Just use $(SolutionDir)mylibdir\mylib.lib.
In case you just can't get it to work, open the project file externally from Notepad and check it.
There are a couple of hints you need to know.
consider your app is running under c:\MyRepository\MyApp
a single dot on your path means the folder where your app runs. So if you like to reach some folder or file under MyApp folder (imagine c:\MyRepository\MyApp\Resources\someText.txt) you can do it like var bla = File.Exists(./Resources/someText.txt)
and you can go one level up with double dots (..) think about a folder under c:\MyRepository\SomeFolder\sometext.txt
for MyApp, it will be like
var bla = File.Exists(../SomeFolder/someText.txt)
and it is possible to go 2,3,4.. levels up like
../../SomeFolder (2 levels up)
../../../SomeFolder (3 levels up)
and path starting with no dots means the drive root. var bla = File.Exists(/SomeFolder/someText.txt) will look for the c:\SomeFolder\someText.txt in our scenario.

shellexec and c:\program files - x86 and x64 portability

I'm modifying an open-source GUI (written in c) to add a new menu item to the tray app. The new menu entry executes a file (update.exe) in the program root in c:\program files directory. Im using shellexec() and it works fine on x86, but since the path is different on x64 - c:\program files (x86), it fails to load. I'd like to use something to the effect of an environment variable like %programfiles%. What is an elegant solution to this?
Alternatively, I do have the ability to change where the update.exe file is stored. Putting it in 'program files' just seemed the most logical. For the problem above, should it go outside of program files? If so where?
You can use GetModuleFileName() to retrieve the full path to the executable. Then you'll just have to cut the filename from the end, and you'll have the complete directory path.
Something like this should to the trick:
TCHAR szPath[MAX_PATH];
LPTSTR szFileName;
GetModuleFileName(g_hInstance, szPath, sizeof(szPath)/sizeof(TCHAR));
szFileName = _tcsrchr(szPath, TEXT("\\"));
*szFileName = TEXT('\0');
// szPath now contains the path
(Warning! Untested!)

Resources