Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Andrea Weikert (c) 2008 Blender Foundation. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <stdlib.h> 00034 #include <string.h> 00035 #include <stdio.h> 00036 #include <math.h> 00037 00038 #include "MEM_guardedalloc.h" 00039 00040 #include "DNA_space_types.h" /* FILE_MAX */ 00041 00042 #include "BLI_blenlib.h" 00043 #include "BLI_linklist.h" 00044 #include "BLI_dynstr.h" 00045 00046 #ifdef WIN32 00047 #include <windows.h> /* need to include windows.h so _WIN32_IE is defined */ 00048 #ifndef _WIN32_IE 00049 #define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */ 00050 #endif 00051 #include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */ 00052 #include "BLI_winstuff.h" 00053 #endif 00054 00055 #ifdef __APPLE__ 00056 /* XXX BIG WARNING: carbon.h can not be included in blender code, it conflicts with struct ID */ 00057 #define ID ID_ 00058 #include <CoreServices/CoreServices.h> 00059 00060 #endif 00061 00062 #ifdef __linux__ 00063 #include <mntent.h> 00064 #endif 00065 00066 #include "fsmenu.h" /* include ourselves */ 00067 00068 00069 /* FSMENU HANDLING */ 00070 00071 /* FSMenuEntry's without paths indicate seperators */ 00072 typedef struct _FSMenuEntry FSMenuEntry; 00073 struct _FSMenuEntry { 00074 FSMenuEntry *next; 00075 00076 char *path; 00077 short save; 00078 }; 00079 00080 typedef struct FSMenu 00081 { 00082 FSMenuEntry *fsmenu_system; 00083 FSMenuEntry *fsmenu_bookmarks; 00084 FSMenuEntry *fsmenu_recent; 00085 00086 } FSMenu; 00087 00088 static FSMenu *g_fsmenu = NULL; 00089 00090 struct FSMenu* fsmenu_get(void) 00091 { 00092 if (!g_fsmenu) { 00093 g_fsmenu=MEM_callocN(sizeof(struct FSMenu), "fsmenu"); 00094 } 00095 return g_fsmenu; 00096 } 00097 00098 static FSMenuEntry *fsmenu_get_category(struct FSMenu* fsmenu, FSMenuCategory category) 00099 { 00100 FSMenuEntry *fsms = NULL; 00101 00102 switch(category) { 00103 case FS_CATEGORY_SYSTEM: 00104 fsms = fsmenu->fsmenu_system; 00105 break; 00106 case FS_CATEGORY_BOOKMARKS: 00107 fsms = fsmenu->fsmenu_bookmarks; 00108 break; 00109 case FS_CATEGORY_RECENT: 00110 fsms = fsmenu->fsmenu_recent; 00111 break; 00112 } 00113 return fsms; 00114 } 00115 00116 static void fsmenu_set_category(struct FSMenu* fsmenu, FSMenuCategory category, FSMenuEntry *fsms) 00117 { 00118 switch(category) { 00119 case FS_CATEGORY_SYSTEM: 00120 fsmenu->fsmenu_system = fsms; 00121 break; 00122 case FS_CATEGORY_BOOKMARKS: 00123 fsmenu->fsmenu_bookmarks = fsms; 00124 break; 00125 case FS_CATEGORY_RECENT: 00126 fsmenu->fsmenu_recent = fsms; 00127 break; 00128 } 00129 } 00130 00131 int fsmenu_get_nentries(struct FSMenu* fsmenu, FSMenuCategory category) 00132 { 00133 FSMenuEntry *fsme; 00134 int count= 0; 00135 00136 for (fsme= fsmenu_get_category(fsmenu, category); fsme; fsme= fsme->next) 00137 count++; 00138 00139 return count; 00140 } 00141 00142 char *fsmenu_get_entry(struct FSMenu* fsmenu, FSMenuCategory category, int idx) 00143 { 00144 FSMenuEntry *fsme; 00145 00146 for (fsme= fsmenu_get_category(fsmenu, category); fsme && idx; fsme= fsme->next) 00147 idx--; 00148 00149 return fsme?fsme->path:NULL; 00150 } 00151 00152 short fsmenu_can_save (struct FSMenu* fsmenu, FSMenuCategory category, int idx) 00153 { 00154 FSMenuEntry *fsme; 00155 00156 for (fsme= fsmenu_get_category(fsmenu, category); fsme && idx; fsme= fsme->next) 00157 idx--; 00158 00159 return fsme?fsme->save:0; 00160 } 00161 00162 void fsmenu_insert_entry(struct FSMenu* fsmenu, FSMenuCategory category, const char *path, int sorted, short save) 00163 { 00164 FSMenuEntry *prev; 00165 FSMenuEntry *fsme; 00166 FSMenuEntry *fsms; 00167 00168 fsms = fsmenu_get_category(fsmenu, category); 00169 prev= fsme= fsms; 00170 00171 for (; fsme; prev= fsme, fsme= fsme->next) { 00172 if (fsme->path) { 00173 const int cmp_ret= BLI_path_cmp(path, fsme->path); 00174 if (cmp_ret == 0) { 00175 return; 00176 } 00177 else if (sorted && cmp_ret < 0) { 00178 break; 00179 } 00180 } else { 00181 // if we're bookmarking this, file should come 00182 // before the last separator, only automatically added 00183 // current dir go after the last sep. 00184 if (save) { 00185 break; 00186 } 00187 } 00188 } 00189 00190 fsme= MEM_mallocN(sizeof(*fsme), "fsme"); 00191 fsme->path= BLI_strdup(path); 00192 fsme->save = save; 00193 00194 if (prev) { 00195 fsme->next= prev->next; 00196 prev->next= fsme; 00197 } else { 00198 fsme->next= fsms; 00199 fsmenu_set_category(fsmenu, category, fsme); 00200 } 00201 } 00202 00203 void fsmenu_remove_entry(struct FSMenu* fsmenu, FSMenuCategory category, int idx) 00204 { 00205 FSMenuEntry *prev= NULL, *fsme= NULL; 00206 FSMenuEntry *fsms = fsmenu_get_category(fsmenu, category); 00207 00208 for (fsme= fsms; fsme && idx; prev= fsme, fsme= fsme->next) 00209 idx--; 00210 00211 if (fsme) { 00212 /* you should only be able to remove entries that were 00213 not added by default, like windows drives. 00214 also separators (where path == NULL) shouldn't be removed */ 00215 if (fsme->save && fsme->path) { 00216 00217 /* remove fsme from list */ 00218 if (prev) { 00219 prev->next= fsme->next; 00220 } else { 00221 fsms= fsme->next; 00222 fsmenu_set_category(fsmenu, category, fsms); 00223 } 00224 /* free entry */ 00225 MEM_freeN(fsme->path); 00226 MEM_freeN(fsme); 00227 } 00228 } 00229 } 00230 00231 void fsmenu_write_file(struct FSMenu* fsmenu, const char *filename) 00232 { 00233 FSMenuEntry *fsme= NULL; 00234 int nskip= 0; 00235 00236 FILE *fp = fopen(filename, "w"); 00237 if (!fp) return; 00238 00239 fprintf(fp, "[Bookmarks]\n"); 00240 for (fsme= fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); fsme; fsme= fsme->next) { 00241 if (fsme->path && fsme->save) { 00242 fprintf(fp, "%s\n", fsme->path); 00243 } 00244 } 00245 fprintf(fp, "[Recent]\n"); 00246 nskip = fsmenu_get_nentries(fsmenu, FS_CATEGORY_RECENT) - FSMENU_RECENT_MAX; 00247 // skip first entries if list too long 00248 for (fsme= fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT); fsme && (nskip>0); fsme= fsme->next, --nskip) 00249 ; 00250 for (; fsme; fsme= fsme->next) { 00251 if (fsme->path && fsme->save) { 00252 fprintf(fp, "%s\n", fsme->path); 00253 } 00254 } 00255 fclose(fp); 00256 } 00257 00258 void fsmenu_read_bookmarks(struct FSMenu* fsmenu, const char *filename) 00259 { 00260 char line[256]; 00261 FSMenuCategory category = FS_CATEGORY_BOOKMARKS; 00262 FILE *fp; 00263 00264 fp = fopen(filename, "r"); 00265 if (!fp) return; 00266 00267 while ( fgets ( line, 256, fp ) != NULL ) /* read a line */ 00268 { 00269 if (strncmp(line, "[Bookmarks]", 11)==0){ 00270 category = FS_CATEGORY_BOOKMARKS; 00271 } else if (strncmp(line, "[Recent]", 8)==0){ 00272 category = FS_CATEGORY_RECENT; 00273 } else { 00274 int len = strlen(line); 00275 if (len>0) { 00276 if (line[len-1] == '\n') { 00277 line[len-1] = '\0'; 00278 } 00279 if (BLI_exists(line)) { 00280 fsmenu_insert_entry(fsmenu, category, line, 0, 1); 00281 } 00282 } 00283 } 00284 } 00285 fclose(fp); 00286 } 00287 00288 void fsmenu_read_system(struct FSMenu* fsmenu) 00289 { 00290 char line[256]; 00291 #ifdef WIN32 00292 /* Add the drive names to the listing */ 00293 { 00294 __int64 tmp; 00295 char tmps[4]; 00296 int i; 00297 00298 tmp= GetLogicalDrives(); 00299 00300 for (i=0; i < 26; i++) { 00301 if ((tmp>>i) & 1) { 00302 tmps[0]='A'+i; 00303 tmps[1]=':'; 00304 tmps[2]='\\'; 00305 tmps[3]=0; 00306 00307 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, 1, 0); 00308 } 00309 } 00310 00311 /* Adding Desktop and My Documents */ 00312 SHGetSpecialFolderPath(0, line, CSIDL_PERSONAL, 0); 00313 fsmenu_insert_entry(fsmenu,FS_CATEGORY_BOOKMARKS, line, 1, 0); 00314 SHGetSpecialFolderPath(0, line, CSIDL_DESKTOPDIRECTORY, 0); 00315 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00316 } 00317 #else 00318 #ifdef __APPLE__ 00319 { 00320 #if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4) 00321 OSErr err=noErr; 00322 int i; 00323 const char *home; 00324 00325 /* loop through all the OS X Volumes, and add them to the SYSTEM section */ 00326 for (i=1; err!=nsvErr; i++) 00327 { 00328 FSRef dir; 00329 unsigned char path[FILE_MAX]; 00330 00331 err = FSGetVolumeInfo(kFSInvalidVolumeRefNum, i, NULL, kFSVolInfoNone, NULL, NULL, &dir); 00332 if (err != noErr) 00333 continue; 00334 00335 FSRefMakePath(&dir, path, FILE_MAX); 00336 if (strcmp((char*)path, "/home") && strcmp((char*)path, "/net")) 00337 { /* /net and /home are meaningless on OSX, home folders are stored in /Users */ 00338 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)path, 1, 0); 00339 } 00340 } 00341 00342 /* As 10.4 doesn't provide proper API to retrieve the favorite places, 00343 assume they are the standard ones 00344 TODO : replace hardcoded paths with proper BLI_get_folder calls */ 00345 home = getenv("HOME"); 00346 if(home) { 00347 BLI_snprintf(line, 256, "%s/", home); 00348 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00349 BLI_snprintf(line, 256, "%s/Desktop/", home); 00350 if (BLI_exists(line)) { 00351 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00352 } 00353 BLI_snprintf(line, 256, "%s/Documents/", home); 00354 if (BLI_exists(line)) { 00355 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00356 } 00357 BLI_snprintf(line, 256, "%s/Pictures/", home); 00358 if (BLI_exists(line)) { 00359 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00360 } 00361 BLI_snprintf(line, 256, "%s/Music/", home); 00362 if (BLI_exists(line)) { 00363 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00364 } 00365 BLI_snprintf(line, 256, "%s/Movies/", home); 00366 if (BLI_exists(line)) { 00367 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00368 } 00369 } 00370 #else 00371 /* 10.5 provides ability to retrieve Finder favorite places */ 00372 UInt32 seed; 00373 OSErr err = noErr; 00374 CFArrayRef pathesArray; 00375 LSSharedFileListRef list; 00376 LSSharedFileListItemRef itemRef; 00377 CFIndex i, pathesCount; 00378 CFURLRef cfURL = NULL; 00379 CFStringRef pathString = NULL; 00380 00381 /* First get local mounted volumes */ 00382 list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteVolumes, NULL); 00383 pathesArray = LSSharedFileListCopySnapshot(list, &seed); 00384 pathesCount = CFArrayGetCount(pathesArray); 00385 00386 for (i=0; i<pathesCount; i++) 00387 { 00388 itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(pathesArray, i); 00389 00390 err = LSSharedFileListItemResolve(itemRef, 00391 kLSSharedFileListNoUserInteraction 00392 | kLSSharedFileListDoNotMountVolumes, 00393 &cfURL, NULL); 00394 if (err != noErr) 00395 continue; 00396 00397 pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle); 00398 00399 if (!CFStringGetCString(pathString,line,256,kCFStringEncodingASCII)) 00400 continue; 00401 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, 1, 0); 00402 00403 CFRelease(pathString); 00404 CFRelease(cfURL); 00405 } 00406 00407 CFRelease(pathesArray); 00408 CFRelease(list); 00409 00410 /* Then get network volumes */ 00411 err = noErr; 00412 for (i=1; err!=nsvErr; i++) 00413 { 00414 FSRef dir; 00415 FSVolumeRefNum volRefNum; 00416 struct GetVolParmsInfoBuffer volParmsBuffer; 00417 unsigned char path[FILE_MAX]; 00418 00419 err = FSGetVolumeInfo(kFSInvalidVolumeRefNum, i, &volRefNum, kFSVolInfoNone, NULL, NULL, &dir); 00420 if (err != noErr) 00421 continue; 00422 00423 err = FSGetVolumeParms(volRefNum, &volParmsBuffer, sizeof(volParmsBuffer)); 00424 if ((err != noErr) || (volParmsBuffer.vMServerAdr == 0)) /* Exclude local devices */ 00425 continue; 00426 00427 00428 FSRefMakePath(&dir, path, FILE_MAX); 00429 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)path, 1, 0); 00430 } 00431 00432 /* Finally get user favorite places */ 00433 list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL); 00434 pathesArray = LSSharedFileListCopySnapshot(list, &seed); 00435 pathesCount = CFArrayGetCount(pathesArray); 00436 00437 for (i=0; i<pathesCount; i++) 00438 { 00439 itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(pathesArray, i); 00440 00441 err = LSSharedFileListItemResolve(itemRef, 00442 kLSSharedFileListNoUserInteraction 00443 | kLSSharedFileListDoNotMountVolumes, 00444 &cfURL, NULL); 00445 if (err != noErr) 00446 continue; 00447 00448 pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle); 00449 00450 if (!CFStringGetCString(pathString,line,256,kCFStringEncodingASCII)) 00451 continue; 00452 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00453 00454 CFRelease(pathString); 00455 CFRelease(cfURL); 00456 } 00457 00458 CFRelease(pathesArray); 00459 CFRelease(list); 00460 #endif /* OSX 10.5+ */ 00461 } 00462 #else 00463 /* unix */ 00464 { 00465 const char *home= getenv("HOME"); 00466 00467 if(home) { 00468 BLI_snprintf(line, FILE_MAXDIR, "%s/", home); 00469 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00470 BLI_snprintf(line, FILE_MAXDIR, "%s/Desktop/", home); 00471 if (BLI_exists(line)) { 00472 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, line, 1, 0); 00473 } 00474 } 00475 00476 { 00477 int found= 0; 00478 #ifdef __linux__ 00479 /* loop over mount points */ 00480 struct mntent *mnt; 00481 int len; 00482 FILE *fp; 00483 00484 fp = setmntent (MOUNTED, "r"); 00485 if (fp == NULL) { 00486 fprintf(stderr, "could not get a list of mounted filesystemts\n"); 00487 } 00488 else { 00489 while ((mnt = getmntent (fp))) { 00490 /* not sure if this is right, but seems to give the relevant mnts */ 00491 if(strncmp(mnt->mnt_fsname, "/dev", 4)) 00492 continue; 00493 00494 len= strlen(mnt->mnt_dir); 00495 if(len && mnt->mnt_dir[len-1] != '/') { 00496 BLI_snprintf(line, FILE_MAXDIR, "%s/", mnt->mnt_dir); 00497 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, 1, 0); 00498 } 00499 else 00500 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, 1, 0); 00501 00502 found= 1; 00503 } 00504 if (endmntent (fp) == 0) { 00505 fprintf(stderr, "could not close the list of mounted filesystemts\n"); 00506 } 00507 } 00508 #endif 00509 00510 /* fallback */ 00511 if(!found) 00512 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, "/", 1, 0); 00513 } 00514 } 00515 #endif 00516 #endif 00517 } 00518 00519 00520 static void fsmenu_free_category(struct FSMenu* fsmenu, FSMenuCategory category) 00521 { 00522 FSMenuEntry *fsme= fsmenu_get_category(fsmenu, category); 00523 00524 while (fsme) { 00525 FSMenuEntry *n= fsme->next; 00526 00527 if (fsme->path) MEM_freeN(fsme->path); 00528 MEM_freeN(fsme); 00529 00530 fsme= n; 00531 } 00532 } 00533 00534 void fsmenu_free(struct FSMenu* fsmenu) 00535 { 00536 fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM); 00537 fsmenu_free_category(fsmenu, FS_CATEGORY_BOOKMARKS); 00538 fsmenu_free_category(fsmenu, FS_CATEGORY_RECENT); 00539 MEM_freeN(fsmenu); 00540 } 00541