Ghost: Support queries for special user directories (desktop, documents, etc.)

When we had to get special user directories, we'd usually do it in varying,
rather ad-hoc ways. It would be done with a bunch of `#ifdef`s for the
different operating systems. Also, some of the used Win32 functions were legacy
ones and the API docs recommend using newer ones.
Further, seems `BKE_appdir_folder_default()` used `XDG_DOCUMENTS_DIR` wrong.
It's not supposed to be an environment variable but a value inside a config
file.

This adds the platform dependent logic to Ghost, so we can abstract it away
nicely using the `GHOST_ISystemPaths` interface. Getting the desktop directory
for example can now easily be done with:
`GHOST_getUserSpecialDir(GHOST_kUserSpecialDirDesktop).`

For now I added the logic for desktop, documents, downloads, videos, images and
music directories, even though we only use the Documents one. We can extend/
change this as needed, it's easy to do now.
On Windows and macOS, it uses pretty much the same way to access the
directories as elsewhere already. On Linux, it uses the `xdg-user-dir` command
that seems to be available by default on most Linux systems.

No functional changes. The new queries are not actually used yet.

Differential Revision: https://developer.blender.org/D9800

Reviewed by: Brecht Van Lommel
This commit is contained in:
Julian Eisel 2020-12-11 15:36:29 +01:00
parent c8a3d1a1fa
commit 6de85a0cc0
10 changed files with 201 additions and 0 deletions

View File

@ -77,6 +77,12 @@ class GHOST_ISystemPaths {
*/
virtual const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const = 0;
/**
* Determine a special ("well known") and easy to reach user directory.
* \return Unsigned char string pointing to user dir (eg `~/Documents/`).
*/
virtual const GHOST_TUns8 *getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const = 0;
/**
* Determine the directory of the current binary
* \return Unsigned char string pointing to the binary dir

View File

@ -56,6 +56,12 @@ extern const GHOST_TUns8 *GHOST_getSystemDir(int version, const char *versionstr
*/
extern const GHOST_TUns8 *GHOST_getUserDir(int version, const char *versionstr);
/**
* Determine a special ("well known") and easy to reach user directory.
* \return Unsigned char string pointing to user dir (eg `~/Documents/`).
*/
extern const GHOST_TUns8 *GHOST_getUserSpecialDir(GHOST_TUserSpecialDirTypes type);
/**
* Determine the dir in which the binary file is found.
* \return Unsigned char string pointing to binary dir (eg ~/usr/local/bin/).

View File

@ -565,6 +565,16 @@ typedef struct {
char is_repeat;
} GHOST_TEventKeyData;
typedef enum {
GHOST_kUserSpecialDirDesktop,
GHOST_kUserSpecialDirDocuments,
GHOST_kUserSpecialDirDownloads,
GHOST_kUserSpecialDirMusic,
GHOST_kUserSpecialDirPictures,
GHOST_kUserSpecialDirVideos,
/* Can be extended as needed. */
} GHOST_TUserSpecialDirTypes;
typedef struct {
/** Number of pixels on a line. */
GHOST_TUns32 xPixels;

View File

@ -50,6 +50,12 @@ const GHOST_TUns8 *GHOST_getUserDir(int version, const char *versionstr)
return systemPaths ? systemPaths->getUserDir(version, versionstr) : NULL; /* shouldn't be NULL */
}
const GHOST_TUns8 *GHOST_getUserSpecialDir(GHOST_TUserSpecialDirTypes type)
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
return systemPaths ? systemPaths->getUserSpecialDir(type) : NULL; /* shouldn't be NULL */
}
const GHOST_TUns8 *GHOST_getBinaryDir()
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();

View File

@ -55,6 +55,12 @@ class GHOST_SystemPathsCocoa : public GHOST_SystemPaths {
*/
const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const;
/**
* Determine a special ("well known") and easy to reach user directory.
* \return Unsigned char string pointing to user dir (eg `~/Documents/`).
*/
const GHOST_TUns8 *getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const;
/**
* Determine the directory of the current binary
* \return Unsigned char string pointing to the binary dir

View File

@ -21,6 +21,7 @@
#import <Foundation/Foundation.h>
#include "GHOST_Debug.h"
#include "GHOST_SystemPathsCocoa.h"
#pragma mark initialization/finalization
@ -89,6 +90,57 @@ const GHOST_TUns8 *GHOST_SystemPathsCocoa::getUserDir(int, const char *versionst
return (GHOST_TUns8 *)tempPath;
}
const GHOST_TUns8 *GHOST_SystemPathsCocoa::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
{
static char tempPath[512] = "";
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *basePath;
NSArray *paths;
NSSearchPathDirectory ns_directory;
switch (type) {
case GHOST_kUserSpecialDirDesktop:
ns_directory = NSDesktopDirectory;
break;
case GHOST_kUserSpecialDirDocuments:
ns_directory = NSDocumentDirectory;
break;
case GHOST_kUserSpecialDirDownloads:
ns_directory = NSDownloadsDirectory;
break;
case GHOST_kUserSpecialDirMusic:
ns_directory = NSMusicDirectory;
break;
case GHOST_kUserSpecialDirPictures:
ns_directory = NSPicturesDirectory;
break;
case GHOST_kUserSpecialDirVideos:
ns_directory = NSMoviesDirectory;
break;
default:
GHOST_ASSERT(
false,
"GHOST_SystemPathsCocoa::getUserSpecialDir(): Invalid enum value for type parameter");
[pool drain];
return NULL;
}
paths = NSSearchPathForDirectoriesInDomains(ns_directory, NSUserDomainMask, YES);
if ([paths count] > 0)
basePath = [paths objectAtIndex:0];
else {
[pool drain];
return NULL;
}
strncpy(
(char *)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding], sizeof(tempPath));
[pool drain];
return (GHOST_TUns8 *)tempPath;
}
const GHOST_TUns8 *GHOST_SystemPathsCocoa::getBinaryDir() const
{
static GHOST_TUns8 tempPath[512] = "";

View File

@ -21,6 +21,9 @@
* \ingroup GHOST
*/
#include <cstdio>
#include <sstream>
#include "GHOST_SystemPathsUnix.h"
#include "GHOST_Debug.h"
@ -108,6 +111,61 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserDir(int version, const char *ve
}
}
const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
{
const char *type_str;
switch (type) {
case GHOST_kUserSpecialDirDesktop:
type_str = "DESKTOP";
break;
case GHOST_kUserSpecialDirDocuments:
type_str = "DOCUMENTS";
break;
case GHOST_kUserSpecialDirDownloads:
type_str = "DOWNLOAD";
break;
case GHOST_kUserSpecialDirMusic:
type_str = "MUSIC";
break;
case GHOST_kUserSpecialDirPictures:
type_str = "PICTURES";
break;
case GHOST_kUserSpecialDirVideos:
type_str = "VIDEOS";
break;
default:
GHOST_ASSERT(
false,
"GHOST_SystemPathsUnix::getUserSpecialDir(): Invalid enum value for type parameter");
return NULL;
}
static string path = "";
string command = string("xdg-user-dir ") + type_str;
FILE *fstream = popen(command.c_str(), "r");
if (fstream == NULL) {
return NULL;
}
std::stringstream path_stream;
while (!feof(fstream)) {
char c = fgetc(fstream);
/* xdg-user-dir ends the path with '\n'. */
if (c == '\n') {
break;
}
path_stream << c;
}
if (pclose(fstream) == -1) {
perror("GHOST_SystemPathsUnix::getUserSpecialDir failed at pclose()");
return NULL;
}
path = path_stream.str();
return (const GHOST_TUns8 *)path.c_str();
}
const GHOST_TUns8 *GHOST_SystemPathsUnix::getBinaryDir() const
{
return NULL;

View File

@ -53,6 +53,12 @@ class GHOST_SystemPathsUnix : public GHOST_SystemPaths {
*/
const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const;
/**
* Determine a special ("well known") and easy to reach user directory.
* \return Unsigned char string pointing to user dir (eg `~/Documents/`).
*/
const GHOST_TUns8 *getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const;
/**
* Determine the directory of the current binary
* \return Unsigned char string pointing to the binary dir

View File

@ -22,6 +22,7 @@
*/
#include "GHOST_SystemPathsWin32.h"
#include "GHOST_Debug.h"
#ifndef _WIN32_IE
# define _WIN32_IE 0x0501
@ -76,6 +77,50 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserDir(int, const char *versionst
return NULL;
}
const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
{
GUID folderid;
switch (type) {
case GHOST_kUserSpecialDirDesktop:
folderid = FOLDERID_Desktop;
break;
case GHOST_kUserSpecialDirDocuments:
folderid = FOLDERID_Documents;
break;
case GHOST_kUserSpecialDirDownloads:
folderid = FOLDERID_Downloads;
break;
case GHOST_kUserSpecialDirMusic:
folderid = FOLDERID_Music;
break;
case GHOST_kUserSpecialDirPictures:
folderid = FOLDERID_Pictures;
break;
case GHOST_kUserSpecialDirVideos:
folderid = FOLDERID_Videos;
break;
default:
GHOST_ASSERT(
false,
"GHOST_SystemPathsWin32::getUserSpecialDir(): Invalid enum value for type parameter");
return NULL;
}
static char knownpath[MAX_PATH * 3] = {0};
PWSTR knownpath_16 = NULL;
HRESULT hResult = SHGetKnownFolderPath(folderid, KF_FLAG_DEFAULT, NULL, &knownpath_16);
if (hResult == S_OK) {
conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3);
CoTaskMemFree(knownpath_16);
return (GHOST_TUns8 *)knownpath;
}
CoTaskMemFree(knownpath_16);
return NULL;
}
const GHOST_TUns8 *GHOST_SystemPathsWin32::getBinaryDir() const
{
static char fullname[MAX_PATH * 3] = {0};

View File

@ -62,6 +62,12 @@ class GHOST_SystemPathsWin32 : public GHOST_SystemPaths {
*/
const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const;
/**
* Determine a special ("well known") and easy to reach user directory.
* \return Unsigned char string pointing to user dir (eg `~/Documents/`).
*/
const GHOST_TUns8 *getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const;
/**
* Determine the directory of the current binary
* \return Unsigned char string pointing to the binary dir