aboutsummaryrefslogtreecommitdiffstats
path: root/cmake/src/base/UPlatformMacOSX.pas
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cmake/src/base/UPlatformMacOSX.pas331
1 files changed, 331 insertions, 0 deletions
diff --git a/cmake/src/base/UPlatformMacOSX.pas b/cmake/src/base/UPlatformMacOSX.pas
new file mode 100644
index 00000000..96e4bc63
--- /dev/null
+++ b/cmake/src/base/UPlatformMacOSX.pas
@@ -0,0 +1,331 @@
+{* UltraStar Deluxe - Karaoke Game
+ *
+ * UltraStar Deluxe is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *}
+
+unit UPlatformMacOSX;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ Classes,
+ ULog,
+ UPlatform;
+
+type
+ {**
+ * @abstract(Provides Mac OS X specific details.)
+ * @lastmod(August 1, 2008)
+ * The UPlatformMacOSX unit takes care of setting paths to resource folders.
+ *
+ * (Note for non-Maccies: "folder" is the Mac name for directory.)
+ *
+ * Note on the resource folders:
+ * 1. Installation of an application on the mac works as follows: Extract and
+ * copy an application and if you don't like or need the application
+ * anymore you move the folder to the trash - and you're done.
+ * 2. The use of folders in the user's home directory is against Apple's
+ * guidelines and strange to an average user.
+ * 3. Even worse is using /usr/local/... since all lowercase folders in / are
+ * not visible to an average user in the Finder, at least not without some
+ * "tricks".
+ *
+ * The best way would be to store everything within the application bundle.
+ * However, this requires USDX to offer the handling of the resources. Until
+ * this is implemented, the second best solution is as follows:
+ *
+ * According to Aple guidelines handling of resources and folders should follow
+ * these lines:
+ *
+ * Acceptable places for files are folders named UltraStarDeluxe either in
+ * /Library/Application Support/
+ * or
+ * ~/Library/Application Support/
+ *
+ * So
+ * GetGameSharedPath could return
+ * /Library/Application Support/UltraStarDeluxe/.
+ * GetGameUserPath could return
+ * ~/Library/Application Support/UltraStarDeluxe/.
+ *
+ * Right now, only $HOME/Library/Application Support/UltraStarDeluxe
+ * is used. So every user needs the complete set of files and folders.
+ * Future versions may also use shared resources in
+ * /Library/Application Support/UltraStarDeluxe. However, this is
+ * not treated yet in the code outside this unit.
+ *
+ * USDX checks, whether GetGameUserPath exists. If not, USDX creates it.
+ * The existence of needed files is then checked and if a file is missing
+ * it is copied to there from within the folder Contents in the Application
+ * bundle, which contains the default files. USDX should not delete files or
+ * folders in Application Support/UltraStarDeluxe automatically or without
+ * user confirmation.
+ *}
+ TPlatformMacOSX = class(TPlatform)
+ private
+ {**
+ * GetBundlePath returns the path to the application bundle
+ * UltraStarDeluxe.app.
+ *}
+ function GetBundlePath: WideString;
+
+ {**
+ * GetApplicationSupportPath returns the path to
+ * $HOME/Library/Application Support/UltraStarDeluxe.
+ *}
+ function GetApplicationSupportPath: WideString;
+
+ {**
+ * see the description of @link(Init).
+ *}
+ procedure CreateUserFolders();
+
+ public
+ {**
+ * Init simply calls @link(CreateUserFolders), which in turn scans the
+ * folder UltraStarDeluxe.app/Contents for all files and
+ * folders. $HOME/Library/Application Support/UltraStarDeluxe
+ * is then checked for their presence and missing ones are copied.
+ *}
+ procedure Init; override;
+
+ {**
+ * DirectoryFindFiles returns all entries of a folder with names and
+ * booleans about their type, i.e. file or directory.
+ *}
+ function DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: boolean): TDirectoryEntryArray; override;
+
+ {**
+ * GetLogPath returns the path for log messages. Currently it is set to
+ * $HOME/Library/Application Support/UltraStarDeluxe/Log.
+ *}
+ function GetLogPath : WideString; override;
+
+ {**
+ * GetGameSharedPath returns the path for shared resources. Currently it
+ * is set to /Library/Application Support/UltraStarDeluxe.
+ * However it is not used.
+ *}
+ function GetGameSharedPath : WideString; override;
+
+ {**
+ * GetGameUserPath returns the path for user resources. Currently it is
+ * set to $HOME/Library/Application Support/UltraStarDeluxe.
+ * This is where a user can add songs, themes, ....
+ *}
+ function GetGameUserPath : WideString; override;
+ end;
+
+implementation
+
+uses
+ SysUtils,
+ BaseUnix;
+
+procedure TPlatformMacOSX.Init;
+begin
+ CreateUserFolders();
+end;
+
+procedure TPlatformMacOSX.CreateUserFolders();
+const
+ // used to construct the @link(UserPathName)
+ PathName: string = '/Library/Application Support/UltraStarDeluxe';
+var
+ RelativePath: string;
+ // BaseDir contains the path to the folder, where a search is performed.
+ // It is set to the entries in @link(DirectoryList) one after the other.
+ BaseDir: string;
+ // OldBaseDir contains the path to the folder, where the search started.
+ // It is used to return to it, when the search is completed in all folders.
+ OldBaseDir: string;
+ // This record contains the result of a file search with FindFirst or FindNext
+ SearchInfo: TSearchRec;
+ // These two lists contain all folder and file names found
+ // within the folder @link(BaseDir).
+ DirectoryList, FileList: TStringList;
+ // DirectoryIsFinished contains the index of the folder in @link(DirectoryList),
+ // which is the last one completely searched. Later folders are still to be
+ // searched for additional files and folders.
+ DirectoryIsFinished: longint;
+ Counter: longint;
+ // These three are for creating directories, due to possible symlinks
+ CreatedDirectory: boolean;
+ FileAttrs: integer;
+ DirectoryPath: string;
+
+ UserPathName: string;
+begin
+ // Get the current folder and save it in OldBaseDir for returning to it, when
+ // finished.
+ GetDir(0, OldBaseDir);
+
+ // UltraStarDeluxe.app/Contents contains all the default files and
+ // folders.
+ BaseDir := OldBaseDir + '/UltraStarDeluxe.app/Contents';
+ ChDir(BaseDir);
+
+ // Right now, only $HOME/Library/Application Support/UltraStarDeluxe
+ // is used.
+ UserPathName := GetEnvironmentVariable('HOME') + PathName;
+
+ DirectoryIsFinished := 0;
+ DirectoryList := TStringList.Create();
+ FileList := TStringList.Create();
+ DirectoryList.Add('.');
+
+ // create the folder and file lists
+ repeat
+
+ RelativePath := DirectoryList[DirectoryIsFinished];
+ ChDir(BaseDir + '/' + RelativePath);
+ if (FindFirst('*', faAnyFile, SearchInfo) = 0) then
+ begin
+ repeat
+ if DirectoryExists(SearchInfo.Name) then
+ begin
+ if (SearchInfo.Name <> '.') and (SearchInfo.Name <> '..') then
+ DirectoryList.Add(RelativePath + '/' + SearchInfo.Name);
+ end
+ else
+ Filelist.Add(RelativePath + '/' + SearchInfo.Name);
+ until (FindNext(SearchInfo) <> 0);
+ end;
+ FindClose(SearchInfo);
+ Inc(DirectoryIsFinished);
+ until (DirectoryIsFinished = DirectoryList.Count);
+
+ // create missing folders
+ ForceDirectories(UserPathName); // should not be necessary since (UserPathName+'/.') is created.
+ for Counter := 0 to DirectoryList.Count-1 do
+ begin
+ DirectoryPath := UserPathName + '/' + DirectoryList[Counter];
+ CreatedDirectory := ForceDirectories(DirectoryPath);
+ FileAttrs := FileGetAttr(DirectoryPath);
+ // Don't know how to analyse the target of the link.
+ // Let's assume the symlink is pointing to an existing directory.
+ if (not CreatedDirectory) and (FileAttrs and faSymLink > 0) then
+ Log.LogError('Failed to create the folder "'+ UserPathName + '/' + DirectoryList[Counter] +'"',
+ 'TPlatformMacOSX.CreateUserFolders');
+ end;
+ DirectoryList.Free();
+
+ // copy missing files
+ for Counter := 0 to Filelist.Count-1 do
+ begin
+ CopyFile(BaseDir + '/' + Filelist[Counter],
+ UserPathName + '/' + Filelist[Counter], true);
+ end;
+ FileList.Free();
+
+ // go back to the initial folder
+ ChDir(OldBaseDir);
+end;
+
+function TPlatformMacOSX.GetBundlePath: WideString;
+var
+ i, pos : integer;
+begin
+ // Mac applications are packaged in folders.
+ // Cutting the last two folders yields the application folder.
+
+ Result := GetExecutionDir();
+ for i := 1 to 2 do
+ begin
+ pos := Length(Result);
+ repeat
+ Delete(Result, pos, 1);
+ pos := Length(Result);
+ until (pos = 0) or (Result[pos] = '/');
+ end;
+end;
+
+function TPlatformMacOSX.GetApplicationSupportPath: WideString;
+const
+ PathName : string = '/Library/Application Support/UltraStarDeluxe';
+begin
+ Result := GetEnvironmentVariable('HOME') + PathName + '/';
+end;
+
+function TPlatformMacOSX.GetLogPath: WideString;
+begin
+ Result := GetApplicationSupportPath + 'Logs';
+end;
+
+function TPlatformMacOSX.GetGameSharedPath: WideString;
+begin
+ Result := GetApplicationSupportPath;
+end;
+
+function TPlatformMacOSX.GetGameUserPath: WideString;
+begin
+ Result := GetApplicationSupportPath;
+end;
+
+function TPlatformMacOSX.DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: boolean): TDirectoryEntryArray;
+var
+ i : integer;
+ TheDir : pdir;
+ ADirent : pDirent;
+ lAttrib : integer;
+begin
+ i := 0;
+ Filter := LowerCase(Filter);
+
+ TheDir := FPOpenDir(Dir);
+ if Assigned(TheDir) then
+ repeat
+ ADirent := FPReadDir(TheDir);
+
+ if Assigned(ADirent) and (ADirent^.d_name <> '.') and (ADirent^.d_name <> '..') then
+ begin
+ lAttrib := FileGetAttr(Dir + ADirent^.d_name);
+ if ReturnAllSubDirs and ((lAttrib and faDirectory) <> 0) then
+ begin
+ SetLength(Result, i + 1);
+ Result[i].Name := ADirent^.d_name;
+ Result[i].IsDirectory := true;
+ Result[i].IsFile := false;
+ i := i + 1;
+ end
+ else if (Length(Filter) = 0) or (Pos( Filter, LowerCase(ADirent^.d_name)) > 0) then
+ begin
+ SetLength(Result, i + 1);
+ Result[i].Name := ADirent^.d_name;
+ Result[i].IsDirectory := false;
+ Result[i].IsFile := true;
+ i := i + 1;
+ end;
+ end;
+ until ADirent = nil;
+
+ FPCloseDir(TheDir);
+end;
+
+end.