2 Copyright (C) 2008 John Emmas
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <pbd/fallback_folders.h>
27 #ifdef PLATFORM_WINDOWS // Would not be relevant for Cygwin!!
31 //***************************************************************
33 // get_win_special_folder()
35 // Gets the full path name that corresponds of one of the Windows
36 // special folders, such as "My Documents" and the like. The input
37 // parameter must be one of the corresponding CSIDL values, such
38 // as CSIDL_SYSTEM etc.
42 // On Success: A pointer to a newly allocated string containing
43 // the name of the special folder (must later be freed).
47 get_win_special_folder (int csidl)
49 wchar_t path[PATH_MAX+1];
51 LPITEMIDLIST pidl = 0;
54 if (S_OK == (hr = SHGetSpecialFolderLocation (0, csidl, &pidl)))
56 if (SHGetPathFromIDListW (pidl, path))
57 retval = g_utf16_to_utf8 ((const gunichar2*)path, -1, 0, 0, 0);
63 #endif // PLATFORM_WINDOWS
67 static gchar **fallback_folders = 0;
69 //***************************************************************
71 // get_platform_fallback_folders()
73 // Returns an array of folders to fall back to if the folders
74 // weren't named at build time and subsequently couldn't be found
75 // in the user's environment. This might not be needed any more
76 // because the function 'fixup_bundle_environment()' (in the
77 // gtk2_ardour branch) now explicitly sets up any environment
78 // paths that the program will need at run time. However, having
79 // the folders here might help us to simplify the above function
80 // which would be useful (currently, there are different versions
81 // of 'fixup_bundle_environment()' for each supported platform).
82 // Twelve fallback folders are currently catered for, corresponding to:-
92 // CONTROL_SURFACES_DIR
94 // LADSPA_PATH - note that there's only one entry in the path
95 // VST_PATH - note that there may only be one entry in the path
99 // On Success: A pointer to an array containing the above dirs.
102 #ifdef PLATFORM_WINDOWS // Would not be relevant for Cygwin!!
105 get_platform_fallback_folders ()
107 gchar **fallback_dir_vector = 0;
108 const gchar *pUsrHome = 0; // Do not free !!
110 if (!fallback_folders)
112 GArray *pFallbackDirs;
114 gchar *pMyAppData = 0;
116 gchar *pPersonal = 0;
118 pFallbackDirs = g_array_new (TRUE, TRUE, sizeof (char *));
122 /* Get the path for the user's personal folder */
123 gchar *pPersonalTemp = get_win_special_folder (CSIDL_PERSONAL);
125 /* and the path for the user's personal application data */
126 gchar *pMyAppDataTemp = get_win_special_folder (CSIDL_LOCAL_APPDATA);
128 /* and the path for common application data ("Documents and Settings\All Users\Application Data") */
129 gchar *pAppDataTemp = get_win_special_folder (CSIDL_COMMON_APPDATA);
131 if (0 == pAppDataTemp)
132 pAppData = g_build_filename("C:\\", "Documents and Settings", "All Users", "Application Data", PROGRAM_NAME, "local", 0);
135 pAppData = g_build_filename(pAppDataTemp, PROGRAM_NAME, "local", 0);
136 g_free (pAppDataTemp);
139 if (0 == pMyAppDataTemp)
141 pMyAppData = g_build_filename(g_get_home_dir(), "Application Data", "local", 0);
145 pMyAppData = g_build_filename(pMyAppDataTemp, 0);
146 g_free (pMyAppDataTemp);
149 if (0 == pPersonalTemp)
150 pPersonal = g_build_filename(g_get_home_dir(), 0);
153 pPersonal = g_build_filename(pPersonalTemp, 0);
154 g_free (pPersonalTemp);
157 /* Get the path to the running application */
158 pExeRoot = g_win32_get_package_installation_directory_of_module (0);
162 pExeRoot = g_build_filename("C:\\", "Program Files", PROGRAM_NAME, 0);
165 if ((pExeRoot) && (pAppData) && (pMyAppData) && (pPersonal))
167 gchar tmp[PATH_MAX+1];
170 // Build our LOCALEDIR entry
171 if (0 != (p = g_build_filename(pAppData, "share", "locale", 0)))
173 g_array_append_val (pFallbackDirs, p);
175 // Build our GTK_DIR entry
176 if (0 != (p = g_build_filename(pPersonal, ".gtk-2.0", 0)))
178 g_array_append_val (pFallbackDirs, p);
180 // Build our CONFIG_DIR entry
181 if (0 != (p = g_build_filename(pAppData, "etc", 0)))
183 g_array_append_val (pFallbackDirs, p);
185 // Build our ARDOUR_DIR entry
186 p = g_build_filename(pMyAppData, PROGRAM_NAME, 0);
190 g_array_append_val (pFallbackDirs, p);
192 // Build our MODULE_DIR entry
193 strcpy(tmp, pExeRoot);
194 if (0 != (p = strrchr (tmp, G_DIR_SEPARATOR)))
198 if (0 != (p = g_build_filename(tmp, 0)))
200 g_array_append_val (pFallbackDirs, p);
202 // Build our DATA_DIR entry
203 if (0 != (p = g_build_filename(pAppData, "share", 0)))
205 g_array_append_val (pFallbackDirs, p);
207 // Build our ICONS_DIR entry
208 if (0 != (p = g_build_filename(pAppData, "share", "icons", 0)))
210 g_array_append_val (pFallbackDirs, p);
212 // Build our PIXMAPS_DIR entry
213 if (0 != (p = g_build_filename(pAppData, "share", "pixmaps", 0)))
215 g_array_append_val (pFallbackDirs, p);
217 // Build our CONTROL_SURFACES_DIR entry
218 if (0 != (p = g_build_filename(pExeRoot, "bin", "surfaces", 0)))
220 g_array_append_val (pFallbackDirs, p);
222 // Build our VAMP_DIR entry
223 p = g_build_filename(pExeRoot, "bin", "vamp", 0);
225 g_array_append_val (pFallbackDirs, p);
227 g_array_append_val (pFallbackDirs, "");
229 // Next, build our LADSPA_PATH entry
230 p = g_build_filename(pExeRoot, "bin", "plugins", 0);
232 g_array_append_val (pFallbackDirs, p);
234 g_array_append_val (pFallbackDirs, "");
236 // And finally, build our VST_PATH entry
237 DWORD dwType = REG_SZ; HKEY hKey;
238 DWORD dwSize = PATH_MAX; p = 0;
239 if (ERROR_SUCCESS == RegOpenKeyExA (HKEY_CURRENT_USER, "Software\\VST", 0, KEY_READ, &hKey))
241 // Look for the user's VST Registry entry
242 if (ERROR_SUCCESS == RegQueryValueExA (hKey, "VSTPluginsPath", 0, &dwType, (LPBYTE)tmp, &dwSize))
243 p = g_build_filename (Glib::locale_to_utf8(tmp).c_str(), 0);
249 if (ERROR_SUCCESS == RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\VST", 0, KEY_READ, &hKey))
251 // Look for a global VST Registry entry
252 if (ERROR_SUCCESS == RegQueryValueExA (hKey, "VSTPluginsPath", 0, &dwType, (LPBYTE)tmp, &dwSize))
253 p = g_build_filename (Glib::locale_to_utf8(tmp).c_str(), 0);
261 gchar *pProgFilesX86 = get_win_special_folder (CSIDL_PROGRAM_FILESX86);
265 // Look for a VST folder under C:\Program Files (x86)
266 if (pVSTx86 = g_build_filename (pProgFilesX86, "Steinberg", "VSTPlugins", 0))
268 if (Glib::file_test (pVSTx86, Glib::FILE_TEST_EXISTS))
269 if (Glib::file_test (pVSTx86, Glib::FILE_TEST_IS_DIR))
270 p = g_build_filename (pVSTx86, 0);
275 g_free (pProgFilesX86);
280 // Look for a VST folder under C:\Program Files
282 gchar *pProgFiles = get_win_special_folder (CSIDL_PROGRAM_FILES);
286 if (pVST = g_build_filename (pProgFiles, "Steinberg", "VSTPlugins", 0))
288 if (Glib::file_test (pVST, Glib::FILE_TEST_EXISTS))
289 if (Glib::file_test (pVST, Glib::FILE_TEST_IS_DIR))
290 p = g_build_filename (pVST, 0);
302 // If all else failed, assume the plugins are under "My Documents"
303 pUsrHome = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS);
305 p = g_build_filename (pUsrHome, "Plugins", "VST", 0);
308 pUsrHome = g_build_filename(g_get_home_dir(), "My Documents", 0);
310 p = g_build_filename (pUsrHome, "Plugins", "VST", 0);
317 // Concatenate the registry path with the user's personal path
318 pUsrHome = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS);
323 p = g_build_path (";", q, g_build_filename(pUsrHome, "Plugins", "VST", 0), 0);
327 pUsrHome = g_build_filename(g_get_home_dir(), "My Documents", 0);
331 p = g_build_path (";", q, g_build_filename (pUsrHome, "Plugins", "VST", 0), 0);
337 g_array_append_val (pFallbackDirs, p);
339 g_array_append_val (pFallbackDirs, "");
342 p = g_build_filename(pExeRoot, "bin", "lv2", 0);
344 g_array_append_val (pFallbackDirs, p);
346 g_array_append_val (pFallbackDirs, "");
364 fallback_dir_vector = fallback_folders = (gchar **) g_array_free (pFallbackDirs, FALSE);
368 fallback_dir_vector = fallback_folders;
370 return (fallback_dir_vector);
374 // Assume Linux, Cygwin or OS-X. Note that in all 3 cases we only
375 // need to cater for unbundled releases (those built by a user from
376 // source). Bundled releases of Ardour and Mixbus now specifically
377 // write their folders and paths to the user's environment at startup.
378 // See the function 'fixup_bundle_environment()'.
381 get_platform_fallback_folders ()
383 gchar **fallback_dir_vector = 0;
386 if (!fallback_folders)
388 GArray *pFallbackDirs;
391 gchar *pPersonal = 0;
393 pFallbackDirs = g_array_new (TRUE, TRUE, sizeof (char *));
397 pAppData = g_build_filename("/usr", "local", 0);
398 pExeRoot = g_build_filename("/usr", "local", "lib", "ardour2", 0);
399 pPersonal = g_build_filename(g_get_home_dir(), 0);
401 if ((pExeRoot) && (pAppData) && (pPersonal))
403 gchar tmp[PATH_MAX+1];
406 // Build our LOCALEDIR entry
407 if (0 != (p = g_build_filename(pAppData, "share", "locale", 0)))
409 g_array_append_val (pFallbackDirs, p);
411 // Build our GTK_DIR entry
412 if (0 != (p = g_build_filename(pPersonal, ".gtk-2.0", 0)))
414 g_array_append_val (pFallbackDirs, p);
416 // Build our CONFIG_DIR entry
417 if (0 != (p = g_build_filename(pAppData, "etc", 0)))
419 g_array_append_val (pFallbackDirs, p);
421 // Build our ARDOUR_DIR entry
422 p = ""; // Empty string (temporary)
425 g_array_append_val (pFallbackDirs, p);
427 // Build our MODULE_DIR entry
428 strcpy(tmp, pExeRoot);
429 if (0 != (p = strrchr (tmp, G_DIR_SEPARATOR)))
433 if (0 != (p = g_build_filename(tmp, 0)))
435 g_array_append_val (pFallbackDirs, p);
437 // Build our DATA_DIR entry
438 if (0 != (p = g_build_filename(pAppData, "share", 0)))
440 g_array_append_val (pFallbackDirs, p);
442 // Build our ICONS_DIR entry (re-use 'tmp')
443 strcpy(tmp, "/usr/local/share/ardour2");
444 if (0 != (p = g_build_filename(tmp, "icons", 0)))
446 g_array_append_val (pFallbackDirs, p);
448 // Build our PIXMAPS_DIR entry
449 if (0 != (p = g_build_filename(tmp, "pixmaps", 0)))
451 g_array_append_val (pFallbackDirs, p);
453 // Build our CONTROL_SURFACES_DIR entry
454 if (0 != (p = g_build_filename(pExeRoot, "surfaces", 0)))
456 g_array_append_val (pFallbackDirs, p);
458 // Build our VAMP_DIR entry
459 p = g_build_filename(pExeRoot, "vamp", 0);
461 g_array_append_val (pFallbackDirs, p);
463 // Next, build our LADSPA_PATH entry
464 p = g_build_filename(Glib::path_get_dirname(pExeRoot).c_str(), "plugins", 0);
466 g_array_append_val (pFallbackDirs, p);
468 // And finally, build our VST_PATH entry
469 if (g_getenv("HOME"))
470 p = g_build_filename(g_getenv("HOME"), "VST", "plugins", 0);
472 p = g_build_filename(g_get_home_dir(), "VST", "plugins", 0);
475 g_array_append_val (pFallbackDirs, p);
492 fallback_dir_vector = fallback_folders = (gchar **) g_array_free (pFallbackDirs, FALSE);
496 fallback_dir_vector = fallback_folders;
501 return (fallback_dir_vector);
506 //***************************************************************
508 // get_platform_fallback_folder()
510 // Returns a const gchar* which points to a string describing
511 // the full path to the Ardour fallback folder corresponding to
512 // the supplied index. See 'get_platform_fallback_folders()' for a
513 // complete list of the supported index enumerations. Calling this
514 // function will initialize the fallback folder array if it wasn't
515 // already initiaized. The array should then (eventually) be freed
516 // using 'free_platform_fallback_folders()'.
520 // On Success: A pointer to the path string contained at the
524 PBD_API G_CONST_RETURN gchar* PBD_APICALLTYPE
525 get_platform_fallback_folder (PBD::fallback_folder_t index)
527 if ((index >= 0) && (index < FALLBACK_FOLDER_MAX))
528 return ((G_CONST_RETURN gchar *)get_platform_fallback_folders ()[index]);
530 return (G_CONST_RETURN gchar *) 0;
534 //***************************************************************
536 // alloc_platform_fallback_folders()
538 // Calls 'get_platform_fallback_folders()' to ensure that memory
539 // for the fallback folder array is already allocated before the
540 // array gets used. It doesn't cause any problems if the array gets
541 // used prior to calling this function (since the memory will get
542 // allocated anyway, on fist usage). Either way however, the momory
543 // must later be freed using 'free_platform_fallback_folders()'.
547 // The value obtained from 'get_platform_fallback_folders()'
549 PBD_API G_CONST_RETURN gchar* G_CONST_RETURN * PBD_APICALLTYPE
550 alloc_platform_fallback_folders ()
552 return ((G_CONST_RETURN gchar* G_CONST_RETURN *)get_platform_fallback_folders ());
556 //***************************************************************
558 // free_platform_fallback_folders()
560 // Frees the memory that was previously allocated for the Ardour
561 // fallback folder array.
567 PBD_API void PBD_APICALLTYPE
568 free_platform_fallback_folders ()
570 int index = FOLDER_LOCALE;
572 if (fallback_folders)
574 gchar *p = get_platform_fallback_folders()[(fallback_folder_t)index++];
576 while (index < (FALLBACK_FOLDER_MAX+1)) {
580 if (index < FALLBACK_FOLDER_MAX)
581 p = get_platform_fallback_folders()[(fallback_folder_t)index++];
586 fallback_folders = 0;