diff --git a/Lgi.xml b/Lgi.xml
--- a/Lgi.xml
+++ b/Lgi.xml
@@ -1,597 +1,596 @@
Makefile.linux
Makefile.win64
Makefile.macosx
- Makefile.unknown
gcc
0
./include
./private/common
./include
./private/common
./include/lgi/linux
./include/lgi/linux/Gtk
./private/linux
./include/lgi/linux
./include/lgi/linux/Gtk
./private/linux
./include/lgi/win
./private/win
./include/lgi/win
./private/win
./include/lgi/haiku
./private/haiku
./include/lgi/haiku
./private/haiku
/usr/include/libappindicator3-0.1
`pkg-config --cflags gtk+-3.0`
`pkg-config --cflags gstreamer-1.0`
/usr/include/libappindicator3-0.1
`pkg-config --cflags gtk+-3.0`
`pkg-config --cflags gstreamer-1.0`
magic
appindicator3
crypt
-static-libgcc
`pkg-config --libs gtk+-3.0`
magic
appindicator3
crypt
-static-libgcc
`pkg-config --libs gtk+-3.0`
- -static-gcc
+ -static-libgcc
gnu
network
be
- -static-gcc
+ -static-libgcc
gnu
network
be
lgi-gtk3
lgi-gtk3
DynamicLibrary
LGI_LIBRARY
LGI_LIBRARY
POSIX
_GNU_SOURCE
POSIX
_GNU_SOURCE
diff --git a/Makefile.haiku b/Makefile.haiku
--- a/Makefile.haiku
+++ b/Makefile.haiku
@@ -1,204 +1,209 @@
#!/usr/bin/make
#
# This makefile generated by LgiIde
# http://www.memecode.com/lgi.php
#
.SILENT :
CC = gcc
CPP = g++
Target = lgi
ifndef Build
Build = Debug
endif
BuildDir = $(Build)
Flags = -fPIC -w -fno-inline -fpermissive
ifeq ($(Build),Debug)
Flags += -g -std=c++14
Tag = d
Defs = -D_DEBUG -DHAIKU -D_REENTRANT -DLGI_LIBRARY -DPOSIX -D_GNU_SOURCE
- Libs = -static-libgcc \
+ Libs = \
+ -static-libgcc \
-lgnu \
-lnetwork \
-lbe
Inc = \
-I./private/haiku \
-I./private/common \
-I./include/lgi/haiku \
-I./include
else
Flags += -s -Os -std=c++14
Defs = -DHAIKU -D_REENTRANT -DLGI_LIBRARY -DPOSIX -D_GNU_SOURCE
- Libs = -static-libgcc \
+ Libs = \
+ -static-libgcc \
-lgnu \
-lnetwork \
-lbe
Inc = \
-I./private/haiku \
-I./private/common \
-I./include/lgi/haiku \
-I./include
endif
# Dependencies
Source = src/haiku/Window.cpp \
src/haiku/Widgets.cpp \
src/haiku/View.cpp \
src/haiku/Thread.cpp \
+ src/haiku/ShowFileProp_Haiku.cpp \
src/haiku/ScreenDC.cpp \
src/haiku/Printer.cpp \
src/haiku/PrintDC.cpp \
src/haiku/Menu.cpp \
src/haiku/MemDC.cpp \
src/haiku/Mem.cpp \
src/haiku/Layout.cpp \
src/haiku/General.cpp \
src/haiku/Gdc2.cpp \
src/haiku/File.cpp \
src/haiku/DragAndDrop.cpp \
src/haiku/ClipBoard.cpp \
src/haiku/App.cpp \
- src/haiku/ShowFileProp_Haiku.cpp \
src/common/Widgets/Tree.cpp \
src/common/Widgets/ToolBar.cpp \
src/common/Widgets/TextLabel.cpp \
src/common/Widgets/TabView.cpp \
src/common/Widgets/TableLayout.cpp \
src/common/Widgets/StatusBar.cpp \
src/common/Widgets/Splitter.cpp \
src/common/Widgets/Slider.cpp \
src/common/Widgets/ScrollBar.cpp \
src/common/Widgets/RadioGroup.cpp \
src/common/Widgets/ProgressDlg.cpp \
src/common/Widgets/Progress.cpp \
src/common/Widgets/Popup.cpp \
src/common/Widgets/Panel.cpp \
src/common/Widgets/List.cpp \
src/common/Widgets/ItemContainer.cpp \
src/common/Widgets/Edit.cpp \
src/common/Widgets/Combo.cpp \
src/common/Widgets/CheckBox.cpp \
src/common/Widgets/Button.cpp \
src/common/Widgets/Box.cpp \
src/common/Widgets/Bitmap.cpp \
src/common/Text/XmlTree.cpp \
src/common/Text/Utf8.cpp \
src/common/Text/Unicode.cpp \
src/common/Text/Token.cpp \
src/common/Text/TextView3.cpp \
src/common/Text/String.cpp \
src/common/Text/DocView.cpp \
src/common/Skins/Gel/Gel.cpp \
src/common/Resource/Res.cpp \
src/common/Resource/LgiRes.cpp \
src/common/Net/Uri.cpp \
src/common/Net/NetTools.cpp \
src/common/Net/Net.cpp \
src/common/Net/MDStringToDigest.cpp \
src/common/Net/Base64.cpp \
src/common/Lgi/WindowCommon.cpp \
src/common/Lgi/ViewCommon.cpp \
src/common/Lgi/Variant.cpp \
src/common/Lgi/TrayIcon.cpp \
src/common/Lgi/ToolTip.cpp \
src/common/Lgi/ThreadEvent.cpp \
src/common/Lgi/ThreadCommon.cpp \
src/common/Lgi/SubProcess.cpp \
src/common/Lgi/Stream.cpp \
src/common/Lgi/Rand.cpp \
src/common/Lgi/OptionsFile.cpp \
src/common/Lgi/Object.cpp \
src/common/Lgi/Mutex.cpp \
src/common/Lgi/Mru.cpp \
src/common/Lgi/MenuCommon.cpp \
src/common/Lgi/MemStream.cpp \
src/common/Lgi/LMsg.cpp \
src/common/Lgi/Library.cpp \
src/common/Lgi/LgiCommon.cpp \
src/common/Lgi/Input.cpp \
src/common/Lgi/GuiUtils.cpp \
src/common/Lgi/FontSelect.cpp \
src/common/Lgi/FindReplace.cpp \
src/common/Lgi/FileSelect.cpp \
src/common/Lgi/DragAndDropCommon.cpp \
src/common/Lgi/DataDlg.cpp \
src/common/Lgi/CssTools.cpp \
src/common/Lgi/Css.cpp \
src/common/Lgi/AppCommon.cpp \
src/common/Lgi/Alert.cpp \
src/common/Hash/sha1/sha1.c \
src/common/Hash/md5/md5.c \
src/common/General/Properties.cpp \
src/common/General/Password.cpp \
src/common/General/FileCommon.cpp \
src/common/General/ExeCheck.cpp \
src/common/General/DateTime.cpp \
src/common/General/Containers.cpp \
src/common/Gdc2/Tools/GdcTools.cpp \
src/common/Gdc2/Tools/ColourReduce.cpp \
src/common/Gdc2/Surface.cpp \
src/common/Gdc2/Rect.cpp \
src/common/Gdc2/Path/Path.cpp \
src/common/Gdc2/GdcCommon.cpp \
src/common/Gdc2/Font/TypeFace.cpp \
src/common/Gdc2/Font/StringLayout.cpp \
src/common/Gdc2/Font/FontType.cpp \
src/common/Gdc2/Font/FontSystem.cpp \
src/common/Gdc2/Font/Font.cpp \
src/common/Gdc2/Font/DisplayString.cpp \
src/common/Gdc2/Font/Charset.cpp \
src/common/Gdc2/Filters/Filter.cpp \
src/common/Gdc2/Colour.cpp \
src/common/Gdc2/Alpha.cpp \
src/common/Gdc2/8Bit.cpp \
src/common/Gdc2/32Bit.cpp \
src/common/Gdc2/24Bit.cpp \
src/common/Gdc2/16Bit.cpp \
src/common/Gdc2/15Bit.cpp
SourceLst := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(Source)))
Objects := $(addprefix $(BuildDir)/,$(SourceLst))
# Target
TargetFile = lib$(Target)$(Tag).so
-
$(TargetFile) : $(Objects)
mkdir -p $(BuildDir)
@echo Linking $(TargetFile) [$(Build)]...
$(CPP)$s -shared \
+ \
-o $(BuildDir)/$(TargetFile) \
$(Objects) \
$(Libs)
@echo Done.
.SECONDEXPANSION:
$(Objects): $(BuildDir)/%.o: $$(wildcard %.c*)
mkdir -p $(@D)
@echo $(
#endif
#define _WIN32_WINNT 0x501
#include
#include
#include
#include
#ifdef WINDOWS
#include
#include "lgi/common/RegKey.h"
#include
#include
#else
#include
#define _getcwd getcwd
#endif
#include "lgi/common/Lgi.h"
#include "lgi/common/Capabilities.h"
#if defined(LINUX) && !defined(LGI_SDL)
#include "LgiWinManGlue.h"
#elif defined(WINDOWS)
#include "lgi/common/RegKey.h"
#endif
#if defined POSIX
#include
#include
#include
#include
#include "lgi/common/SubProcess.h"
#endif
#ifdef HAIKU
#include
#include
#else
#include "SymLookup.h"
#endif
#include "lgi/common/Library.h"
#include "lgi/common/Net.h"
#if defined(__GTK_H__)
namespace Gtk {
#include "LgiWidget.h"
}
#endif
//////////////////////////////////////////////////////////////////////////
// Misc stuff
#if LGI_COCOA || defined(__GTK_H__)
LString LgiArgsAppPath;
#endif
#if defined MAC
#import
#if defined LGI_CARBON
bool _get_path_FSRef(FSRef &fs, LStringPipe &a)
{
HFSUniStr255 Name;
ZeroObj(Name);
FSRef Parent;
FSCatalogInfo Cat;
ZeroObj(Cat);
OSErr e = FSGetCatalogInfo(&fs,
kFSCatInfoVolume|kFSCatInfoNodeID,
&Cat,
&Name,
NULL,
&Parent);
if (!e)
{
if (_get_path_FSRef(Parent, a))
{
LAutoString u((char*)LNewConvertCp("utf-8", Name.unicode, "utf-16", Name.length * sizeof(Name.unicode[0]) ));
// printf("CatInfo = '%s' %x %x\n", u.Get(), Cat.nodeID, Cat.volume);
if (u && Cat.nodeID > 2)
{
a.Print("%s%s", DIR_STR, u.Get());
}
}
return true;
}
return false;
}
LAutoString FSRefPath(FSRef &fs)
{
LStringPipe a;
if (_get_path_FSRef(fs, a))
{
return LAutoString(a.NewStr());
}
return LAutoString();
}
#endif
#endif
bool LPostEvent(OsView Wnd, int Event, LMessage::Param a, LMessage::Param b)
{
#if LGI_SDL
SDL_Event e;
e.type = SDL_USEREVENT;
e.user.code = Event;
e.user.data1 = Wnd;
e.user.data2 = a || b ? new LMessage::EventParams(a, b) : NULL;
/*
printf("LPostEvent Wnd=%p, Event=%i, a/b: %i/%i\n",
Wnd, Event, (int)a, (int)b);
*/
return SDL_PushEvent(&e) == 0;
#elif WINNATIVE
return PostMessage(Wnd, Event, a, b) != 0;
#elif defined(__GTK_H__)
LAssert(Wnd);
LViewI *View = (LViewI*) g_object_get_data(GtkCast(Wnd, g_object, GObject), "LViewI");
if (View)
{
LMessage m(0);
m.Set(Event, a, b);
return m.Send(View);
}
else printf("%s:%i - Error: LPostEvent can't cast OsView to LViewI\n", _FL);
#elif defined(MAC) && !LGI_COCOA
#if 0
int64 Now = LCurrentTime();
static int64 Last = 0;
static int Count = 0;
Count++;
if (Now > Last + 1000)
{
printf("Sent %i events in the last %ims\n", Count, (int)(Now-Last));
Last = Now;
Count = 0;
}
#endif
EventRef Ev;
OSStatus e = CreateEvent(NULL,
kEventClassUser,
kEventUser,
0, // EventTime
kEventAttributeNone,
&Ev);
if (e)
{
printf("%s:%i - CreateEvent failed with %i\n", _FL, (int)e);
}
else
{
EventTargetRef t = GetControlEventTarget(Wnd);
e = SetEventParameter(Ev, kEventParamLgiEvent, typeUInt32, sizeof(Event), &Event);
if (e) printf("%s:%i - error %i\n", _FL, (int)e);
e = SetEventParameter(Ev, kEventParamLgiA, typeUInt32, sizeof(a), &a);
if (e) printf("%s:%i - error %i\n", _FL, (int)e);
e = SetEventParameter(Ev, kEventParamLgiB, typeUInt32, sizeof(b), &b);
if (e) printf("%s:%i - error %i\n", _FL, (int)e);
bool Status = false;
EventQueueRef q = GetMainEventQueue();
e = SetEventParameter(Ev, kEventParamPostTarget, typeEventTargetRef, sizeof(t), &t);
if (e) printf("%s:%i - error %i\n", _FL, (int)e);
e = PostEventToQueue(q, Ev, kEventPriorityStandard);
if (e) printf("%s:%i - error %i\n", _FL, (int)e);
else Status = true;
// printf("PostEventToQueue %i,%i,%i -> %p\n", Event, a, b, q);
ReleaseEvent(Ev);
return Status;
}
#else
LAssert(!"Not impl.");
#endif
return false;
}
void LExitApp()
{
exit(0);
}
//////////////////////////////////////////////////////////////////////////
#ifdef WIN32
bool RegisterActiveXControl(char *Dll)
{
LLibrary Lib(Dll);
if (Lib.IsLoaded())
{
#ifdef _MSC_VER
typedef HRESULT (STDAPICALLTYPE *p_DllRegisterServer)(void);
p_DllRegisterServer DllRegisterServer = (p_DllRegisterServer)Lib.GetAddress("DllRegisterServer");
if (DllRegisterServer)
{
return DllRegisterServer() == S_OK;
}
#else
LAssert(!"Not impl.");
#endif
}
return false;
}
#endif
//////////////////////////////////////////////////////////////////////////
#ifdef WINDOWS
#include
#pragma comment(lib, "netapi32.lib")
#endif
/// \brief Returns the operating system that Lgi is running on.
/// \sa Returns one of the defines starting with LGI_OS_UNKNOWN in LgiDefs.h
int LGetOs
(
/// Returns the version of the OS or NULL if you don't care
LArray *Ver
)
{
#if defined(WIN32) || defined(WIN64)
- static int Os = LGI_OS_UNKNOWN;
- static int Version = 0, Revision = 0;
+ static int Os = LGI_OS_UNKNOWN;
+ static int Version = 0, Revision = 0;
- if (Os == LGI_OS_UNKNOWN)
- {
- #if defined(WIN64)
- BOOL IsWow64 = TRUE;
- #elif defined(WIN32)
- BOOL IsWow64 = FALSE;
- IsWow64Process(GetCurrentProcess(), &IsWow64);
- #endif
-
- SERVER_INFO_101 *v = NULL;
- auto r = NetServerGetInfo(NULL, 101, (LPBYTE*)&v);
- if (r == NERR_Success)
+ if (Os == LGI_OS_UNKNOWN)
{
- Version = v->sv101_version_major;
- Revision = v->sv101_version_minor;
- Os = (v->sv101_version_major >= 6)
- ?
- #ifdef WIN32
- (IsWow64 ? LGI_OS_WIN64 : LGI_OS_WIN32)
- #else
- LGI_OS_WIN64
- #endif
- :
- LGI_OS_WIN9X;
+ #if defined(WIN64)
+ BOOL IsWow64 = TRUE;
+ #elif defined(WIN32)
+ BOOL IsWow64 = FALSE;
+ IsWow64Process(GetCurrentProcess(), &IsWow64);
+ #endif
- NetApiBufferFree(v);
- }
- else LAssert(0);
- }
+ SERVER_INFO_101 *v = NULL;
+ auto r = NetServerGetInfo(NULL, 101, (LPBYTE*)&v);
+ if (r == NERR_Success)
+ {
+ Version = v->sv101_version_major;
+ Revision = v->sv101_version_minor;
+ Os = (v->sv101_version_major >= 6)
+ ?
+ #ifdef WIN32
+ (IsWow64 ? LGI_OS_WIN64 : LGI_OS_WIN32)
+ #else
+ LGI_OS_WIN64
+ #endif
+ :
+ LGI_OS_WIN9X;
- if (Ver)
- {
- Ver->Add(Version);
- Ver->Add(Revision);
- }
+ NetApiBufferFree(v);
+ }
+ else LAssert(0);
+ }
- return Os;
+ if (Ver)
+ {
+ Ver->Add(Version);
+ Ver->Add(Revision);
+ }
+
+ return Os;
#elif defined LINUX
- if (Ver)
- {
- utsname Buf;
- if (!uname(&Buf))
+ if (Ver)
{
- auto t = LString(Buf.release).SplitDelimit(".");
- for (int i=0; iAdd(atoi(t[i]));
+ auto t = LString(Buf.release).SplitDelimit(".");
+ for (int i=0; iAdd(atoi(t[i]));
+ }
}
}
- }
- return LGI_OS_LINUX;
+ return LGI_OS_LINUX;
#elif defined MAC
- #if !defined(__GTK_H__)
- if (Ver)
- {
- NSOperatingSystemVersion v = [[NSProcessInfo processInfo] operatingSystemVersion];
- Ver->Add((int)v.majorVersion);
- Ver->Add((int)v.minorVersion);
- Ver->Add((int)v.patchVersion);
- }
- #endif
+ #if !defined(__GTK_H__)
+ if (Ver)
+ {
+ NSOperatingSystemVersion v = [[NSProcessInfo processInfo] operatingSystemVersion];
+ Ver->Add((int)v.majorVersion);
+ Ver->Add((int)v.minorVersion);
+ Ver->Add((int)v.patchVersion);
+ }
+ #endif
+
+ return LGI_OS_MAC_OS_X;
+
+ #elif defined HAIKU
- return LGI_OS_MAC_OS_X;
+ return LGI_OS_HAIKU;
#else
- return LGI_OS_UNKNOWN;
+ #error "Impl Me"
+ return LGI_OS_UNKNOWN;
#endif
}
const char *LGetOsName()
{
const char *Str[LGI_OS_MAX] =
{
"Unknown",
"Win9x",
"Win32",
"Win64",
"Haiku",
"Linux",
"MacOSX",
};
- return Str[LGetOs()];
+ auto Os = LGetOs();
+ if (Os > 0 && Os < CountOf(Str))
+ return Str[Os];
+
+ LAssert(!"Invalid OS index.");
+ return "error";
}
#ifdef WIN32
#define RecursiveFileSearch_Wildcard "*.*"
#else // unix'ish OS
#define RecursiveFileSearch_Wildcard "*"
#endif
bool LRecursiveFileSearch(const char *Root,
LArray *Ext,
LArray *Files,
uint64 *Size,
uint64 *Count,
std::function Callback,
LCancel *Cancel)
{
// validate args
if (!Root) return false;
// get directory enumerator
LDirectory Dir;
bool Status = true;
// enumerate the directory contents
for (auto Found = Dir.First(Root); Found && (!Cancel || !Cancel->IsCancelled()); Found = Dir.Next())
{
char Name[300];
if (!Dir.Path(Name, sizeof(Name)))
continue;
if (Callback && !Callback(Name, &Dir))
continue;
if (Dir.IsDir())
{
// dir
LRecursiveFileSearch( Name,
Ext,
Files,
Size,
Count,
Callback,
Cancel);
}
else
{
// process file
bool Match = true; // if no Ext's then default to match
if (Ext)
{
for (int i=0; iLength(); i++)
{
const char *e = (*Ext)[i];
char *RawFile = strrchr(Name, DIR_CHAR);
if (RawFile &&
(Match = MatchStr(e, RawFile+1)))
{
break;
}
}
}
if (Match)
{
// file matched... process:
if (Files)
Files->Add(NewStr(Name));
if (Size)
*Size += Dir.GetSize();
if (Count)
(*Count)++;
Status = true;
}
}
}
return Status;
}
#define LGI_TRACE_TO_FILE
// #include
#ifndef WIN32
#define _vsnprintf vsnprintf
#endif
static LStreamI *_LgiTraceStream = NULL;
void LgiTraceSetStream(LStreamI *stream)
{
_LgiTraceStream = stream;
}
bool LgiTraceGetFilePath(char *LogPath, int BufLen)
{
if (!LogPath)
return false;
auto Exe = LGetExeFile();
if (Exe)
{
#ifdef MAC
char *Dir = strrchr(Exe, DIR_CHAR);
if (Dir)
{
char Part[256];
strcpy_s(Part, sizeof(Part), Dir+1);
LMakePath(LogPath, BufLen, "~/Library/Logs", Dir+1);
strcat_s(LogPath, BufLen, ".txt");
}
else
#endif
{
char *Dot = strrchr(Exe, '.');
if (Dot && !strchr(Dot, DIR_CHAR))
sprintf_s(LogPath, BufLen, "%.*s.txt", (int)(Dot - Exe.Get()), Exe.Get());
else
sprintf_s(LogPath, BufLen, "%s.txt", Exe.Get());
}
LFile f;
if (f.Open(LogPath, O_WRITE))
{
f.Close();
}
else
{
char Leaf[64];
char *Dir = strrchr(LogPath, DIR_CHAR);
if (Dir)
{
strcpy_s(Leaf, sizeof(Leaf), Dir + 1);
LGetSystemPath(LSP_APP_ROOT, LogPath, BufLen);
if (!LDirExists(LogPath))
FileDev->CreateFolder(LogPath);
LMakePath(LogPath, BufLen, LogPath, Leaf);
}
else goto OnError;
}
#if 0
LFile tmp;
if (tmp.Open("c:\\temp\\log.txt", O_WRITE))
{
tmp.SetSize(0);
tmp.Write(LogPath, strlen(LogPath));
}
#endif
}
else
{
// Well what to do now? I give up
OnError:
strcpy_s(LogPath, BufLen, "trace.txt");
return false;
}
return true;
}
void LgiTrace(const char *Msg, ...)
{
#if defined _INC_MALLOC && WINNATIVE
if (_heapchk() != _HEAPOK)
return;
#endif
if (!Msg)
return;
#ifdef WIN32
static LMutex Sem("LgiTrace");
Sem.Lock(_FL, true);
#endif
char Buffer[2049] = "";
#ifdef LGI_TRACE_TO_FILE
static LFile f;
static char LogPath[MAX_PATH_LEN] = "";
if (!_LgiTraceStream && LogPath[0] == 0)
LgiTraceGetFilePath(LogPath, sizeof(LogPath));
#endif
va_list Arg;
va_start(Arg, Msg);
#ifdef LGI_TRACE_TO_FILE
int Ch =
#endif
vsnprintf(Buffer, sizeof(Buffer)-1, Msg, Arg);
va_end(Arg);
#ifdef LGI_TRACE_TO_FILE
LStreamI *Output = NULL;
if (_LgiTraceStream)
Output = _LgiTraceStream;
else
{
if (!f.IsOpen() &&
f.Open(LogPath, O_WRITE))
f.Seek(0, SEEK_END);
Output = &f;
}
if (Output && Ch > 0)
{
Output->ChangeThread();
Output->Write(Buffer, Ch);
}
if (!_LgiTraceStream)
{
#ifdef WINDOWS
// Windows can take AGES to close a file when there is anti-virus on, like 100ms.
// We can't afford to wait here so just keep the file open but flush the
// buffers if we can.
FlushFileBuffers(f.Handle());
#else
f.Close();
#endif
}
#endif
#if defined WIN32
OutputDebugStringA(Buffer);
Sem.Unlock();
#else
printf("%s", Buffer);
#endif
}
#ifndef LGI_STATIC
#define STACK_SIZE 12
void LStackTrace(const char *Msg, ...)
{
#ifndef HAIKU
LSymLookup::Addr Stack[STACK_SIZE];
ZeroObj(Stack);
LSymLookup *Lu = LAppInst ? LAppInst->GetSymLookup() : NULL;
if (!Lu)
{
printf("%s:%i - Failed to get sym lookup object.\n", _FL);
return;
}
int Frames = Lu ? Lu->BackTrace(0, 0, Stack, STACK_SIZE) : 0;
if (Msg)
{
#ifdef LGI_TRACE_TO_FILE
static LFile f;
static char LogPath[MAX_PATH_LEN] = "";
if (!_LgiTraceStream)
{
if (LogPath[0] == 0)
LgiTraceGetFilePath(LogPath, sizeof(LogPath));
f.Open(LogPath, O_WRITE);
}
#endif
va_list Arg;
va_start(Arg, Msg);
char Buffer[2049] = "";
int Len = vsnprintf(Buffer, sizeof(Buffer)-1, Msg, Arg);
va_end(Arg);
Lu->Lookup(Buffer+Len, sizeof(Buffer)-Len-1, Stack, Frames);
#ifdef LGI_TRACE_TO_FILE
if (f.IsOpen())
{
f.Seek(0, SEEK_END);
f.Write(Buffer, (int)strlen(Buffer));
f.Close();
}
#endif
#if defined WIN32
OutputDebugStringA(Buffer);
#else
printf("Trace: %s", Buffer);
#endif
}
#endif
}
#endif
bool LTrimDir(char *Path)
{
if (!Path)
return false;
char *p = strrchr(Path, DIR_CHAR);
if (!p)
return false;
if (p[1] == 0) // Trailing DIR_CHAR doesn't count... do it again.
{
*p = 0;
p = strrchr(Path, DIR_CHAR);
if (!p)
return false;
}
*p = 0;
return true;
}
LString LMakeRelativePath(const char *Base, const char *Path)
{
LStringPipe Status;
if (Base && Path)
{
#ifdef WIN32
bool SameNs = strnicmp(Base, Path, 3) == 0;
#else
bool SameNs = true;
#endif
if (SameNs)
{
auto b = LString(Base + 1).SplitDelimit(":\\/");
auto p = LString(Path + 1).SplitDelimit(":\\/");
int Same = 0;
while (Same < b.Length() && Same < p.Length() && stricmp(b[Same], p[Same]) == 0)
{
Same++;
}
for (int i = Same; i= b.Length())
{
Status.Print(".%s", DIR_STR);
}
for (int n = Same; n Same)
{
Status.Push(DIR_STR);
}
Status.Push(p[n]);
}
}
}
return Status.NewGStr();
}
bool LIsRelativePath(const char *Path)
{
if (!Path)
return false;
if (*Path == '.')
return true;
#ifdef WIN32
if (IsAlpha(Path[0]) && Path[1] == ':') // Drive letter path
return false;
#endif
if (*Path == DIR_CHAR)
return false;
if (strstr(Path, "://")) // Protocol def
return false;
return true; // Correct or not???
}
bool LMakePath(char *Str, int StrSize, const char *Path, const char *File)
{
if (!Str || StrSize <= 0 || !Path || !File)
{
printf("%s:%i - Invalid LMakePath(%p,%i,%s,%s) param\n", _FL, Str, StrSize, Path, File);
return false;
}
if (StrSize <= 4)
{
printf("%s:%i - LgiMakeFile buf size=%i?\n", _FL, StrSize);
}
if (Str && Path && File)
{
char Dir[] = { '/', '\\', 0 };
if (Path[0] == '~')
{
auto Parts = LString(Path).SplitDelimit(Dir, 2);
char *s = Str, *e = Str + StrSize;
for (auto p: Parts)
{
if (p.Equals("~"))
{
LGetSystemPath(LSP_HOME, s, e - s);
s += strlen(s);
}
else
s += sprintf_s(s, e - s, "%s%s", DIR_STR, p.Get());
}
}
else if (Str != Path)
{
strcpy_s(Str, StrSize, Path);
}
#define EndStr() Str[strlen(Str)-1]
#define EndDir() if (!strchr(Dir, EndStr())) strcat(Str, DIR_STR);
size_t Len = strlen(Str);
char *End = Str + (Len ? Len - 1 : 0);
if (strchr(Dir, *End) && End > Str)
{
*End = 0;
}
auto T = LString(File).SplitDelimit(Dir);
for (int i=0; i= StrSize - 1)
return false;
Str[Len++] = DIR_CHAR;
Str[Len] = 0;
}
size_t SegLen = strlen(T[i]);
if (Len + SegLen + 1 > StrSize)
{
return false;
}
strcpy_s(Str + Len, StrSize - Len, T[i]);
}
}
}
return true;
}
bool LgiGetTempPath(char *Dst, int DstSize)
{
return LGetSystemPath(LSP_TEMP, Dst, DstSize);
}
bool LGetSystemPath(LSystemPath Which, char *Dst, ssize_t DstSize)
{
if (!Dst || DstSize <= 0)
return false;
LFile::Path p;
LString s = p.GetSystem(Which, 0);
if (!s)
return false;
strcpy_s(Dst, DstSize, s);
return true;
}
LString LGetSystemPath(LSystemPath Which, int WordSize)
{
LFile::Path p;
return p.GetSystem(Which, WordSize);
}
LFile::Path::State LFile::Path::Exists()
{
if (Length() == 0)
return TypeNone;
#ifdef WINDOWS
struct _stat64 s;
int r = _stat64(GetFull(), &s);
if (r)
return TypeNone;
if (s.st_mode & _S_IFDIR)
return TypeFolder;
if (s.st_mode & _S_IFREG)
return TypeFile;
#else
struct stat s;
int r = stat(GetFull(), &s);
if (r)
return TypeNone;
if (S_ISDIR(s.st_mode))
return TypeFolder;
if (S_ISREG(s.st_mode))
return TypeFile;
#endif
return TypeNone;
}
LString LFile::Path::PrintAll()
{
LStringPipe p;
#define _(name) \
p.Print(#name ": '%s'\n", GetSystem(name).Get());
_(LSP_OS)
_(LSP_OS_LIB)
_(LSP_TEMP)
_(LSP_COMMON_APP_DATA)
_(LSP_USER_APP_DATA)
_(LSP_LOCAL_APP_DATA)
_(LSP_DESKTOP)
_(LSP_HOME)
_(LSP_USER_APPS)
_(LSP_EXE)
_(LSP_TRASH)
_(LSP_APP_INSTALL)
_(LSP_APP_ROOT)
_(LSP_USER_DOCUMENTS)
_(LSP_USER_MUSIC)
_(LSP_USER_VIDEO)
_(LSP_USER_DOWNLOADS)
_(LSP_USER_LINKS)
_(LSP_USER_PICTURES)
#undef _
#if LGI_COCOA
int Domains[] = {NSUserDomainMask, NSSystemDomainMask};
const char *DomainName[] = {"User", "System"};
for (int i=0; i 0) \
{ \
LString s = [paths objectAtIndex:0]; \
p.Print("%s." #name ": '%s'\n", DomainName[i], s.Get()); \
} \
else p.Print("%s." #name ": null\n", DomainName[i]); \
} \
}
_(NSApplicationDirectory)
_(NSDemoApplicationDirectory)
_(NSDeveloperApplicationDirectory)
_(NSAdminApplicationDirectory)
_(NSLibraryDirectory)
_(NSDeveloperDirectory)
_(NSUserDirectory)
_(NSDocumentationDirectory)
_(NSDocumentDirectory)
_(NSCoreServiceDirectory)
_(NSAutosavedInformationDirectory)
_(NSDesktopDirectory)
_(NSCachesDirectory)
_(NSApplicationSupportDirectory)
_(NSDownloadsDirectory)
_(NSInputMethodsDirectory)
_(NSMoviesDirectory)
_(NSMusicDirectory)
_(NSPicturesDirectory)
_(NSPrinterDescriptionDirectory)
_(NSSharedPublicDirectory)
_(NSPreferencePanesDirectory)
_(NSApplicationScriptsDirectory)
_(NSItemReplacementDirectory)
_(NSAllApplicationsDirectory)
_(NSAllLibrariesDirectory)
_(NSTrashDirectory)
#undef _
}
#endif
return p.NewGStr();
}
LString LFile::Path::GetSystem(LSystemPath Which, int WordSize)
{
LString Path;
#if defined(WIN32)
#ifndef CSIDL_PROFILE
#define CSIDL_PROFILE 0x0028
#endif
#if !defined(CSIDL_MYDOCUMENTS)
#define CSIDL_MYDOCUMENTS 0x0005
#endif
#if !defined(CSIDL_MYMUSIC)
#define CSIDL_MYMUSIC 0x000d
#endif
#if !defined(CSIDL_MYVIDEO)
#define CSIDL_MYVIDEO 0x000e
#endif
#if !defined(CSIDL_LOCAL_APPDATA)
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
#if !defined(CSIDL_COMMON_APPDATA)
#define CSIDL_COMMON_APPDATA 0x0023
#endif
#if !defined(CSIDL_APPDATA)
#define CSIDL_APPDATA 0x001a
#endif
#endif
/*
#if defined(LINUX) && !defined(LGI_SDL)
// Ask our window manager add-on if it knows the path
LLibrary *WmLib = LAppInst ? LAppInst->GetWindowManagerLib() : NULL;
if (WmLib)
{
Proc_LgiWmGetPath WmGetPath = (Proc_LgiWmGetPath) WmLib->GetAddress("LgiWmGetPath");
char Buf[MAX_PATH_LEN];
if (WmGetPath && WmGetPath(Which, Buf, sizeof(Buf)))
{
Path = Buf;
return Path;
}
}
#endif
*/
switch (Which)
{
default:
break;
case LSP_USER_DOWNLOADS:
{
#if defined(__GTK_H__)
auto p = Gtk::g_get_user_special_dir(Gtk::G_USER_DIRECTORY_DOWNLOAD);
Path = p;
#elif defined(WIN32) && defined(_MSC_VER)
// OMG!!!! Really?
#ifndef REFKNOWNFOLDERID
typedef GUID KNOWNFOLDERID;
#define REFKNOWNFOLDERID const KNOWNFOLDERID &
GUID FOLDERID_Downloads = {0x374DE290,0x123F,0x4565,{0x91,0x64,0x39,0xC4,0x92,0x5E,0x46,0x7B}};
#endif
LLibrary Shell("Shell32.dll");
typedef HRESULT (STDAPICALLTYPE *pSHGetKnownFolderPath)(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
pSHGetKnownFolderPath SHGetKnownFolderPath = (pSHGetKnownFolderPath)Shell.GetAddress("SHGetKnownFolderPath");
if (SHGetKnownFolderPath)
{
PWSTR ptr = NULL;
HRESULT r = SHGetKnownFolderPath(FOLDERID_Downloads, 0, NULL, &ptr);
if (SUCCEEDED(r))
{
LAutoString u8(WideToUtf8(ptr));
if (u8)
Path = u8;
CoTaskMemFree(ptr);
}
}
if (!Path.Get())
{
LRegKey k(false, "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
char *p = k.GetStr("{374DE290-123F-4565-9164-39C4925E467B}");
if (LDirExists(p))
Path = p;
}
if (!Path.Get())
{
LString MyDoc = WinGetSpecialFolderPath(CSIDL_MYDOCUMENTS);
if (MyDoc)
{
char Buf[MAX_PATH_LEN];
LMakePath(Buf, sizeof(Buf), MyDoc, "Downloads");
if (LDirExists(Buf))
Path = Buf;
}
}
if (!Path.Get())
{
LString Profile = WinGetSpecialFolderPath(CSIDL_PROFILE);
if (Profile)
{
char Buf[MAX_PATH_LEN];
LMakePath(Buf, sizeof(Buf), Profile, "Downloads");
if (LDirExists(Buf))
Path = Buf;
}
}
#elif LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDownloadsDirectory, NSUserDomainMask, YES);
if (paths)
{
if ([paths count])
Path = [paths objectAtIndex:0];
}
#elif defined(HAIKU)
#else
LAssert(!"Not implemented");
#endif
break;
}
case LSP_USER_LINKS:
{
LString Home = LGetSystemPath(LSP_HOME);
#if defined(WIN32)
char p[MAX_PATH_LEN];
if (LMakePath(p, sizeof(p), Home, "Links"))
Path = p;
#elif defined(LINUX)
char p[MAX_PATH_LEN];
if (LMakePath(p, sizeof(p), Home, ".config/gtk-3.0"))
Path = p;
#endif
break;
}
case LSP_USER_PICTURES:
{
#if defined(__GTK_H__)
auto p = Gtk::g_get_user_special_dir(Gtk::G_USER_DIRECTORY_DOCUMENTS);
Path = p;
#elif defined(WIN32)
Path = WinGetSpecialFolderPath(CSIDL_MYPICTURES);
if (Path)
return Path;
#elif defined LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSPicturesDirectory, NSUserDomainMask, YES);
if (paths)
{
if ([paths count])
Path = [paths objectAtIndex:0];
}
#endif
// Default to ~/Pictures
char hm[MAX_PATH_LEN];
LString Home = LGetSystemPath(LSP_HOME);
if (LMakePath(hm, sizeof(hm), Home, "Pictures"))
Path = hm;
break;
}
case LSP_USER_DOCUMENTS:
{
#if defined(__GTK_H__)
auto p = Gtk::g_get_user_special_dir(Gtk::G_USER_DIRECTORY_DOCUMENTS);
Path = p;
#elif defined(WIN32) && defined(_MSC_VER)
Path = WinGetSpecialFolderPath(CSIDL_MYDOCUMENTS);
if (Path)
return Path;
#elif defined LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
if (paths)
{
if ([paths count])
Path = [paths objectAtIndex:0];
}
#endif
// Default to ~/Documents
char hm[MAX_PATH_LEN];
LString Home = LGetSystemPath(LSP_HOME);
if (LMakePath(hm, sizeof(hm), Home, "Documents"))
Path = hm;
break;
}
case LSP_USER_MUSIC:
{
#if defined WIN32
Path = WinGetSpecialFolderPath(CSIDL_MYMUSIC);
#elif defined(__GTK_H__)
auto p = Gtk::g_get_user_special_dir(Gtk::G_USER_DIRECTORY_MUSIC);
Path = p;
#elif defined LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kMusicDocumentsFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
else
{
LAutoString a = FSRefPath(Ref);
if (a)
Path = a.Get();
}
#elif LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSMusicDirectory, NSUserDomainMask, YES);
if (paths)
{
if ([paths count])
Path = [paths objectAtIndex:0];
}
#endif
if (!Path)
{
// Default to ~/Music
char p[MAX_PATH_LEN];
LString Home = LGetSystemPath(LSP_HOME);
if (LMakePath(p, sizeof(p), Home, "Music"))
Path = p;
}
break;
}
case LSP_USER_VIDEO:
{
#if defined WIN32
Path = WinGetSpecialFolderPath(CSIDL_MYVIDEO);
#elif defined(__GTK_H__)
auto p = Gtk::g_get_user_special_dir(Gtk::G_USER_DIRECTORY_VIDEOS);
Path = p;
#elif defined LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kMovieDocumentsFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
else
{
LAutoString a = FSRefPath(Ref);
if (a)
Path = a.Get();
}
#elif LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSMoviesDirectory, NSUserDomainMask, YES);
if (paths)
{
if ([paths count])
Path = [paths objectAtIndex:0];
}
#endif
if (!Path)
{
// Default to ~/Video
char p[MAX_PATH_LEN];
LString Home = LGetSystemPath(LSP_HOME);
if (LMakePath(p, sizeof(p), Home, "Video"))
Path = p;
}
break;
}
case LSP_USER_APPS:
{
#if defined WIN32
int Id =
#ifdef WIN64
CSIDL_PROGRAM_FILES
#else
CSIDL_PROGRAM_FILESX86
#endif
;
if (WordSize == 32)
Id = CSIDL_PROGRAM_FILESX86;
else if (WordSize == 64)
Id = CSIDL_PROGRAM_FILES;
Path = WinGetSpecialFolderPath(Id);
#elif defined(HAIKU)
dev_t volume = dev_for_path("/boot");
char path[MAX_PATH_LEN] = "";
if (find_directory(B_SYSTEM_APPS_DIRECTORY, volume, true, path, sizeof(path)) == B_OK)
Path = path;
#elif LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationDirectory, NSSystemDomainMask, YES);
if (paths)
{
if ([paths count])
Path = [paths objectAtIndex:0];
}
#elif defined MAC
Path = "/Applications";
#elif defined LINUX
Path = "/usr/bin";
#else
LAssert(!"Impl me.");
#endif
break;
}
case LSP_APP_INSTALL:
{
Path = LGetSystemPath(LSP_EXE);
if (Path)
{
size_t Last = Path.RFind(DIR_STR);
if (Last > 0)
{
LString s = Path(Last, -1);
if
(
stristr(s,
#ifdef _DEBUG
"Debug"
#else
"Release"
#endif
)
)
Path = Path(0, Last);
}
}
break;
}
case LSP_APP_ROOT:
{
#ifndef LGI_STATIC
const char *Name = NULL;
// Try and get the configured app name:
if (LAppInst)
Name = LAppInst->LBase::Name();
if (!Name)
{
// Use the exe name?
LString Exe = LGetExeFile();
char *l = LGetLeaf(Exe);
if (l)
{
#ifdef WIN32
char *d = strrchr(l, '.');
*d = NULL;
#endif
Name = l;
// printf("%s:%i - name '%s'\n", _FL, Name);
}
}
if (!Name)
{
LAssert(0);
break;
}
#if defined MAC
#if LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
if (paths)
Path = [[paths objectAtIndex:0] UTF8String];
#elif LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kDomainLibraryFolderType, kDontCreateFolder, &Ref);
if (e)
{
printf("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
LAssert(0);
}
else
{
LAutoString Base = FSRefPath(Ref);
Path = Base.Get();
}
#else
struct passwd *pw = getpwuid(getuid());
if (!pw)
return false;
Path.Printf("%s/Library", pw->pw_dir);
#endif
#elif defined WIN32
Path = WinGetSpecialFolderPath(CSIDL_APPDATA);
#elif defined LINUX
char Dot[128];
snprintf(Dot, sizeof(Dot), ".%s", Name);
Name = Dot;
struct passwd *pw = getpwuid(getuid());
if (pw)
Path = pw->pw_dir;
else
LAssert(0);
#elif defined(HAIKU)
dev_t volume = dev_for_path("/boot");
char path[MAX_PATH_LEN] = "";
if (find_directory(B_USER_DIRECTORY , volume, true, path, sizeof(path)) == B_OK)
Path = path;
#else
LAssert(0);
#endif
if (Path)
{
Path += DIR_STR;
Path += Name;
}
#endif
break;
}
case LSP_OS:
{
#if defined WIN32
char16 p[MAX_PATH_LEN];
if (GetWindowsDirectoryW(p, CountOf(p)) > 0)
Path = p;
#elif defined(HAIKU)
dev_t volume = dev_for_path("/boot");
char path[MAX_PATH_LEN] = "";
if (find_directory(B_SYSTEM_DIRECTORY, volume, true, path, sizeof(path)) == B_OK)
Path = path;
#elif defined LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kOnAppropriateDisk, kSystemFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", __FILE__, __LINE__, e);
else
{
LAutoString u = FSRefPath(Ref);
if (u)
Path = u.Get();
}
#elif defined LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, NSSystemDomainMask, YES);
if (paths)
{
Path = [paths objectAtIndex:0];
LTrimDir(Path);
}
#elif defined LINUX
Path = "/boot"; // it'll do for now...
#endif
break;
}
case LSP_OS_LIB:
{
#if defined WIN32
char16 p[MAX_PATH_LEN];
if (GetSystemDirectoryW(p, CountOf(p)) > 0)
Path = p;
#elif defined(HAIKU)
dev_t volume = dev_for_path("/boot");
char path[MAX_PATH_LEN] = "";
if (find_directory(B_SYSTEM_LIB_DIRECTORY, volume, true, path, sizeof(path)) == B_OK)
Path = path;
#elif defined MAC
Path = "/Library";
#elif defined LINUX
Path = "/lib"; // it'll do for now...
#endif
break;
}
case LSP_TEMP:
{
#if defined WIN32
char16 t[MAX_PATH_LEN];
if (GetTempPathW(CountOf(t), t) > 0)
{
LAutoString utf(WideToUtf8(t));
if (utf)
Path = utf;
}
#elif defined LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kTemporaryFolderType, kCreateFolder, &Ref);
if (e) LgiTrace("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
else
{
LAutoString u = FSRefPath(Ref);
if (u)
{
Path = u.Get();
}
else LgiTrace("%s:%i - FSRefPath failed.\n", _FL);
}
#elif defined LGI_COCOA
NSString *tempDir = NSTemporaryDirectory();
if (tempDir)
Path = tempDir;
else
LAssert(!"No tmp folder?");
#elif defined LINUX
Path = "/tmp"; // it'll do for now...
#else
LAssert(!"Impl me.");
#endif
break;
}
case LSP_COMMON_APP_DATA:
{
#if defined WIN32
Path = WinGetSpecialFolderPath(CSIDL_COMMON_APPDATA);
#elif defined LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kOnSystemDisk, kDomainLibraryFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
else
{
auto u = FSRefPath(Ref);
if (u)
Path = u.Get();
}
#elif defined LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, NSSystemDomainMask, YES);
if (paths)
{
Path = [paths objectAtIndex:0];
}
#elif defined LINUX
Path = "/usr";
#else
LAssert(!"Impl me.");
#endif
break;
}
case LSP_USER_APP_DATA:
{
#if defined WIN32
Path = WinGetSpecialFolderPath(CSIDL_APPDATA);
#elif defined LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kDomainLibraryFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", __FILE__, __LINE__, e);
else
{
auto u = FSRefPath(Ref);
if (u)
Path = u.Get();
}
#elif defined LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, NSUserDomainMask, YES);
if (paths)
{
Path = [paths objectAtIndex:0];
}
#elif defined LINUX
Path = "/usr";
#elif defined HAIKU
dev_t volume = dev_for_path("/boot");
char path[MAX_PATH_LEN] = "";
if (find_directory(B_USER_SETTINGS_DIRECTORY, volume, true, path, sizeof(path)) == B_OK)
Path = path;
#else
LAssert(!"Impl me.");
#endif
break;
}
case LSP_LOCAL_APP_DATA:
{
#if defined WIN32
Path = WinGetSpecialFolderPath(CSIDL_LOCAL_APPDATA);
#elif defined LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, NSUserDomainMask, YES);
if (paths)
{
Path = [paths objectAtIndex:0];
}
#else
LAssert(!"Impl me.");
#endif
break;
}
case LSP_DESKTOP:
{
#if defined(WINDOWS) && defined(_MSC_VER)
Path = WinGetSpecialFolderPath(CSIDL_DESKTOPDIRECTORY);
#elif defined(HAIKU)
dev_t volume = dev_for_path("/boot");
char path[MAX_PATH_LEN] = "";
if (find_directory(B_DESKTOP_DIRECTORY, volume, true, path, sizeof(path)) == B_OK)
Path = path;
#elif defined(__GTK_H__)
auto p = Gtk::g_get_user_special_dir(Gtk::G_USER_DIRECTORY_DESKTOP);
Path = p;
#elif defined LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDesktopDirectory, NSUserDomainMask, YES);
if (paths)
{
Path = [paths objectAtIndex:0];
}
#elif defined LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kOnAppropriateDisk, kDesktopFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", __FILE__, __LINE__, e);
else
{
LAutoString u = FSRefPath(Ref);
if (u)
Path = u.Get();
}
#elif defined POSIX
struct passwd *pw = getpwuid(getuid());
if (pw)
{
#ifdef LINUX
WindowManager wm = LGetWindowManager();
if (wm == WM_Gnome)
{
Path.Printf("%s/.gnome-desktop", pw->pw_dir);
}
#endif
if (!LDirExists(Path))
{
Path.Printf("%s/Desktop", pw->pw_dir);
}
}
#else
#error "Impl me."
#endif
break;
}
case LSP_HOME:
{
#if defined WIN32
Path = WinGetSpecialFolderPath(CSIDL_PROFILE);
#elif defined(HAIKU)
dev_t volume = dev_for_path("/boot");
char path[MAX_PATH_LEN] = "";
if (find_directory(B_USER_DIRECTORY, volume, true, path, sizeof(path)) == B_OK)
Path = path;
#elif defined LGI_COCOA
NSString *home = NSHomeDirectory();
if (home)
Path = home;
else
LAssert(!"No home path?");
#elif defined POSIX
struct passwd *pw = getpwuid(getuid());
if (pw)
Path = pw->pw_dir;
#else
#error "Impl me."
#endif
break;
}
case LSP_EXE:
{
Path = LGetExeFile();
if (!Path)
break;
auto p = Path.RFind(DIR_STR);
if (p > 0)
Path.Length(p);
break;
}
case LSP_TRASH:
{
#if defined LINUX
switch (LGetWindowManager())
{
case WM_Kde:
{
static char KdeTrash[256] = "";
if (!ValidStr(KdeTrash))
{
// Ask KDE where the current trash is...
LStringPipe o;
LSubProcess p("kde-config", "--userpath trash");
if (p.Start())
{
p.Communicate(&o);
char *s = o.NewStr();
if (s)
{
// Store it..
strcpy_s(KdeTrash, sizeof(KdeTrash), s);
DeleteArray(s);
// Clear out any crap at the end...
char *e = KdeTrash + strlen(KdeTrash) - 1;
while (e > KdeTrash && strchr(" \r\n\t/", *e))
{
*e-- = 0;
}
}
else
{
printf("%s:%i - No output from 'kde-config'.\n", _FL);
}
}
else
{
printf("%s:%i - Run 'kde-config' failed.\n", _FL);
}
}
if (ValidStr(KdeTrash))
Path = KdeTrash;
break;
}
default:
{
LString Home = LGetSystemPath(LSP_HOME);
if (!Home)
{
LgiTrace("%s:%i - Can't get LSP_HOME.\n", _FL);
break;
}
char p[MAX_PATH_LEN];
if (!LMakePath(p, sizeof(p), Home, ".local/share/Trash/files") ||
!LDirExists(p))
{
LgiTrace("%s:%i - '%s' doesn't exist.\n", _FL, p);
break;
}
Path = p;
break;
}
}
#elif defined(HAIKU)
dev_t volume = dev_for_path("/boot");
char path[MAX_PATH_LEN] = "";
if (find_directory(B_TRASH_DIRECTORY, volume, true, path, sizeof(path)) == B_OK)
Path = path;
#elif defined LGI_CARBON
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kTrashFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
else
{
LAutoString u = FSRefPath(Ref);
if (u)
Path = u.Get();
}
#elif defined LGI_COCOA
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSTrashDirectory, NSUserDomainMask, YES);
if (paths)
{
Path = [paths objectAtIndex:0];
}
#elif defined(WIN32)
LAssert(0);
#endif
break;
}
}
return Path;
}
LString LGetExeFile()
{
#if defined WIN32
char16 Exe[MAX_PATH_LEN];
if (GetModuleFileNameW(NULL, Exe, CountOf(Exe)) > 0)
{
LString e = Exe;
if (e)
{
return e;
}
else
{
LgiMsg(0, "LgiFromNativeCp returned 0, ANSI CodePage=%i (%s)", "LgiGetExeFile Error", MB_OK, GetACP(), LAnsiToLgiCp());
return LString();
}
}
LString m;
m.Printf("GetModuleFileName failed err: %08.8X", GetLastError());
MessageBoxA(0, m, "LgiGetExeFile Error", MB_OK);
LExitApp();
#elif defined HAIKU
// Copy the string so as to not allow callers to change it
return LgiArgsAppPath.Get();
#elif defined LINUX
static char ExePathCache[MAX_PATH_LEN] = "";
bool Status = false;
// this is _REALLY_ lame way to do it... but hey there aren't any
// other better ways to get the full path of the running executable
if (!ExePathCache[0])
{
// First try the self method
int Len = readlink("/proc/self/exe", ExePathCache, sizeof(ExePathCache));
Status = LFileExists(ExePathCache);
// printf("readlink=%i Status=%i Exe='%s'\n", Len, Status, ExePathCache);
if (!Status)
{
ExePathCache[0] = 0;
// Next try the map file method
char ProcFile[256];
sprintf_s(ProcFile, sizeof(ProcFile), "/proc/%i/maps", getpid());
int fd = open(ProcFile, O_RDONLY);
if (fd >= 0)
{
int Len = 16 << 10; // is this enough?
// no better way of determining the length of proc info?
char *Buf = new char[Len+1];
if (Buf)
{
int r = read(fd, Buf, Len);
Buf[r] = 0;
char *s = strchr(Buf, '/');
if (s)
{
char *e = strchr(s, '\n');
if (e)
{
*e = 0;
strcpy_s(ExePathCache, sizeof(ExePathCache), s);
Status = true;
}
}
DeleteArray(Buf);
}
close(fd);
}
else
{
// Non proc system (like cygwin for example)
// char Cmd[256];
// sprintf_s(Cmd, sizeof(Cmd), "ps | grep \"%i\"", getpid());
LStringPipe Ps;
LSubProcess p("ps");
if (p.Start())
{
p.Communicate(&Ps);
char *PsOutput = Ps.NewStr();
if (PsOutput)
{
auto n = LString(PsOutput).SplitDelimit("\r\n");
for (int i=0; !Status && i 7)
{
int LinePid = 0;
for (int i=0; iReset(NewStr(Path));
return;
}
#ifdef WIN32
if (PathLen < sizeof(Path) - 4)
{
strcat(Path, ".lnk");
if (LResolveShortcut(Path, Path, sizeof(Path)))
{
if (GStr)
*GStr = Path;
else if (AStr)
AStr->Reset(NewStr(Path));
return;
}
}
#endif
}
// General search fall back...
LArray Ext;
LArray Files;
Ext.Add((char*)Name);
if (LRecursiveFileSearch(Exe, &Ext, &Files) &&
Files.Length())
{
if (GStr)
*GStr = Files[0];
else
{
AStr->Reset(Files[0]);
Files.DeleteAt(0);
}
}
Files.DeleteArrays();
}
LString LFindFile(const char *Name)
{
LString s;
_LFindFile(Name, &s, NULL);
return s;
}
#if defined WIN32
static LARGE_INTEGER Freq = {0};
static bool CurTimeInit = false;
#endif
uint64_t LCurrentTime()
{
#if defined WIN32
if (!CurTimeInit)
{
CurTimeInit = true;
if (!QueryPerformanceFrequency(&Freq))
Freq.QuadPart = 0;
}
if (Freq.QuadPart)
{
// Return performance counter in ms
LARGE_INTEGER i;
if (QueryPerformanceCounter(&i))
{
return i.QuadPart * 1000 / Freq.QuadPart;
}
// Now what?? Give up and go back to tick count I guess.
Freq.QuadPart = 0;
}
// Fall back for systems without a performance counter.
return GetTickCount();
#elif defined LGI_CARBON
UnsignedWide t;
Microseconds(&t);
uint64 i = ((uint64)t.hi << 32) | t.lo;
return i / 1000;
#else
timeval tv;
gettimeofday(&tv, 0);
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
#endif
}
uint64_t LgiMicroTime()
{
#if defined WIN32
if (!CurTimeInit)
{
CurTimeInit = true;
if (!QueryPerformanceFrequency(&Freq))
Freq.QuadPart = 0;
}
if (Freq.QuadPart)
{
// Return performance counter in ms
LARGE_INTEGER i;
if (QueryPerformanceCounter(&i))
{
return i.QuadPart * 1000000 / Freq.QuadPart;
}
}
return 0;
#elif defined LGI_CARBON
UnsignedWide t;
Microseconds(&t);
return ((uint64)t.hi << 32) | t.lo;
#else
timeval tv;
gettimeofday(&tv, 0);
return (tv.tv_sec * 1000000) + tv.tv_usec;
#endif
}
int LIsReleaseBuild()
{
#ifdef _DEBUG
return 0;
#else
return 1;
#endif
}
bool LIsVolumeRoot(const char *Path)
{
if (!Path)
return false;
#ifdef WIN32
if
(
IsAlpha(Path[0])
&&
Path[1] == ':'
&&
(
(Path[2] == 0)
||
(Path[2] == '\\' && Path[3] == 0)
)
)
{
return true;
}
#else
auto t = LString(Path).SplitDelimit(DIR_STR);
if (t.Length() == 0)
return true;
#ifdef MAC
if (!stricmp(t[0], "Volumes") &&
t.Length() == 2)
return true;
#else
if (!stricmp(t[0], "mnt") &&
t.Length() == 2)
return true;
#endif
#endif
return false;
}
LString LFormatSize(int64_t Size)
{
char Buf[64];
LFormatSize(Buf, sizeof(Buf), Size);
return Buf;
}
void LFormatSize(char *Str, int SLen, int64_t Size)
{
int64_t K = 1024;
int64_t M = K * K;
int64_t G = K * M;
int64_t T = K * G;
if (Size == 1)
{
strcpy_s(Str, SLen, "1 byte");
}
else if (Size < K)
{
sprintf_s(Str, SLen, "%u bytes", (int)Size);
}
else if (Size < 10 * K)
{
double d = (double)Size;
sprintf_s(Str, SLen, "%.2f KiB", d / K);
}
else if (Size < M)
{
sprintf_s(Str, SLen, "%u KiB", (int) (Size / K));
}
else if (Size < G)
{
double d = (double)Size;
sprintf_s(Str, SLen, "%.2f MiB", d / M);
}
else if (Size < T)
{
double d = (double)Size;
sprintf_s(Str, SLen, "%.2f GiB", d / G);
}
else
{
double d = (double)Size;
sprintf_s(Str, SLen, "%.2f TiB", d / T);
}
}
char *LTokStr(const char *&s)
{
char *Status = 0;
if (s && *s)
{
// Skip whitespace
static char Delim[] = ", \t\r\n";
while (*s && strchr(Delim, *s)) s++;
if (*s)
{
if (strchr("\'\"", *s))
{
char Delim = *s++;
const char *e = strchr(s, Delim);
if (!e)
{
// error, no end delimiter
e = s;
while (*e) e++;
}
Status = NewStr(s, e - s);
s = *e ? e + 1 : e;
}
else
{
const char *e = s;
while (*e && !strchr(Delim, *e)) e++;
Status = NewStr(s, e - s);
s = e;
}
}
}
return Status;
}
LString LGetEnv(const char *Var)
{
#ifdef _MSC_VER
char *s = NULL;
size_t sz;
errno_t err = _dupenv_s(&s, &sz, Var);
if (err)
return LString();
LString ret(s);
free(s);
return ret;
#else
return getenv("PATH");
#endif
}
LString::Array LGetPath()
{
LString::Array Paths;
#ifdef MAC
// OMG, WHY?! Seriously?
//
// The GUI application path is NOT the same as what is configured for the terminal.
// At least in 10.12. And I don't know how to make them the same. This works around
// that for the time being.
#if 1
LFile EctPaths("/etc/paths", O_READ);
Paths = EctPaths.Read().Split("\n");
#else
LFile::Path Home(LSP_HOME);
Home += ".profile";
if (!Home.Exists())
{
Home--;
Home += ".zprofile";
}
auto Profile = LFile(Home, O_READ).Read().Split("\n");
for (auto Ln : Profile)
{
auto p = Ln.SplitDelimit(" =", 2);
if (p.Length() == 3 &&
p[0].Equals("export") &&
p[1].Equals("PATH"))
{
Paths = p[2].Strip("\"").SplitDelimit(LGI_PATH_SEPARATOR);
Paths.SetFixedLength(false);
for (auto &p : Paths)
{
if (p.Equals("$PATH"))
{
auto SysPath = LGetEnv("PATH").SplitDelimit(LGI_PATH_SEPARATOR);
for (unsigned i=0; i 0)
{
Period = p;
}
}
bool DoEvery::DoNow()
{
int64 Now = LCurrentTime();
if (LastTime + Period < Now)
{
LastTime = Now;
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////
bool LCapabilityClient::NeedsCapability(const char *Name, const char *Param)
{
for (int i=0; iNeedsCapability(Name, Param);
return Targets.Length() > 0;
}
LCapabilityClient::~LCapabilityClient()
{
for (int i=0; iClients.Delete(this);
}
void LCapabilityClient::Register(LCapabilityTarget *t)
{
if (t && !Targets.HasItem(t))
{
Targets.Add(t);
t->Clients.Add(this);
}
}
LCapabilityTarget::~LCapabilityTarget()
{
for (int i=0; iTargets.Delete(this);
}
/////////////////////////////////////////////////////////////////////
#define BUF_SIZE (4 << 10)
#define PROFILE_MICRO 1
LProfile::LProfile(const char *Name, int HideMs)
{
MinMs = HideMs;
Used = 0;
Buf = NULL;
Add(Name);
}
LProfile::~LProfile()
{
Add("End");
uint64 TotalMs = s.Last().Time - s[0].Time;
if (MinMs > 0)
{
if (TotalMs < MinMs
#if PROFILE_MICRO
* 1000
#endif
)
{
return;
}
}
uint64 accum = 0;
for (int i=0; i BUF_SIZE - 64)
{
LAssert(0);
return;
}
char *Name = Buf + Used;
Used += sprintf_s(Name, BUF_SIZE - Used, "%s:%i", File, Line) + 1;
s.Add(Sample(
#if PROFILE_MICRO
LgiMicroTime(),
#else
LCurrentTime(),
#endif
Name));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool LIsValidEmail(LString Email)
{
// Local part
char buf[321];
char *o = buf;
char *e = Email;
if (!Email || *e == '.')
return false;
#define OutputChar() \
if (o - buf >= sizeof(buf) - 1) \
return false; \
*o++ = *e++
// Local part
while (*e)
{
if (strchr("!#$%&\'*+-/=?^_`.{|}~", *e) ||
IsAlpha((uchar)*e) ||
IsDigit((uchar)*e))
{
OutputChar();
}
else if (*e == '\"')
{
// Quoted string
OutputChar();
bool quote = false;
while (*e && !quote)
{
quote = *e == '\"';
OutputChar();
}
}
else if (*e == '\\')
{
// Quoted character
e++;
if (*e < ' ' || *e >= 0x7f)
return false;
OutputChar();
}
else if (*e == '@')
{
break;
}
else
{
// Illegal character
return false;
}
}
// Process the '@'
if (*e != '@' || o - buf > 64)
return false;
OutputChar();
// Domain part...
if (*e == '[')
{
// IP addr
OutputChar();
// Initial char must by a number
if (!IsDigit(*e))
return false;
// Check the rest...
char *Start = e;
while (*e)
{
if (IsDigit(*e) ||
*e == '.')
{
OutputChar();
}
else
{
return false;
}
}
// Not a valid IP
if (e - Start > 15)
return false;
if (*e != ']')
return false;
OutputChar();
}
else
{
// Hostname, check initial char
if (!IsAlpha(*e) && !IsDigit(*e))
return false;
// Check the rest.
while (*e)
{
if (IsAlpha(*e) ||
IsDigit(*e) ||
strchr(".-", *e))
{
OutputChar();
}
else
{
return false;
}
}
}
// Remove any trailing dot/dash
while (strchr(".-", o[-1]))
o--;
// Output
*o = 0;
LAssert(o - buf <= sizeof(buf));
if (strcmp(Email, buf))
Email.Set(buf, o - buf);
return true;
}
//////////////////////////////////////////////////////////////////////////
LString LGetAppForProtocol(const char *Protocol)
{
LString App;
if (!Protocol)
return App;
#ifdef WINDOWS
LRegKey k(false, "HKEY_CLASSES_ROOT\\%s\\shell\\open\\command", Protocol);
if (k.IsOk())
{
const char *p = k.GetStr();
if (p)
{
LAutoString a(LTokStr(p));
App = a.Get();
}
}
#elif defined(LINUX)
const char *p = NULL;
if (stricmp(Protocol, "mailto"))
p = "xdg-email";
else
p = "xdg-open";
LString Path = LGetEnv("PATH");
LString::Array a = Path.SplitDelimit(LGI_PATH_SEPARATOR);
for (auto i : a)
{
LFile::Path t(i);
t += p;
if (t.Exists())
{
App = t.GetFull();
break;
}
}
#elif defined(__GTK_H__)
LAssert(!"What to do?");
#elif defined(MAC)
// Get the handler type
LString s;
s.Printf("%s://domain/path", Protocol);
auto str = s.NsStr();
auto type = [NSURL URLWithString:str];
[str release];
auto handlerUrl = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:type];
[type release];
if (handlerUrl)
{
// Convert to app path
s = [handlerUrl absoluteString];
LUri uri(s);
if (uri.sProtocol.Equals("file"))
App = uri.sPath.RStrip("/");
else
LgiTrace("%s:%i - Error: unknown protocol '%s'\n", _FL, uri.sProtocol.Get());
}
[handlerUrl release];
#else
#warning "Impl me."
#endif
return App;
}
diff --git a/src/haiku/ClipBoard.cpp b/src/haiku/ClipBoard.cpp
--- a/src/haiku/ClipBoard.cpp
+++ b/src/haiku/ClipBoard.cpp
@@ -1,169 +1,183 @@
// Clipboard Implementation
#include "lgi/common/Lgi.h"
#include "lgi/common/Variant.h"
#include "lgi/common/ClipBoard.h"
#include
#define DEBUG_CLIPBOARD 0
#define LGI_CLIP_BINARY "lgi.binary"
class LClipBoardPriv : public BClipboard
{
public:
LString Txt;
LAutoWString WTxt;
LClipBoardPriv() : BClipboard(NULL)
{
}
};
///////////////////////////////////////////////////////////////////////////////////////////////
LClipBoard::LClipBoard(LView *o)
{
d = new LClipBoardPriv;
Owner = o;
Open = false;
}
LClipBoard::~LClipBoard()
{
DeleteObj(d);
}
bool LClipBoard::Empty()
{
if (!d->Lock())
{
LgiTrace("%s:%i - Can't lock BClipboard.\n", _FL);
return false;
}
- d->Clear();
+ auto result = d->Clear();
+ if (result)
+ printf("%s:%i - clear=%i %s\n", _FL, result, strerror(result));
+ result = d->Commit();
+ if (result)
+ printf("%s:%i - commit=%i %s\n", _FL, result, strerror(result));
+
d->Unlock();
return true;
}
bool LClipBoard::EnumFormats(::LArray &Formats)
{
return false;
}
bool LClipBoard::Html(const char *doc, bool AutoEmpty)
{
return false;
}
::LString LClipBoard::Html()
{
return ::LString();
}
bool LClipBoard::Text(const char *Str, bool AutoEmpty)
{
- bool Status = false;
-
if (AutoEmpty)
{
Empty();
}
if (!d->Lock())
{
LgiTrace("%s:%i - Can't lock BClipboard.\n", _FL);
return false;
}
auto clip = d->Data();
+ if (!clip)
+ {
+ d->Unlock();
+ LgiTrace("%s:%i - No clipboard data.\n", _FL);
+ return false;
+ }
- clip->AddData("text/plain", B_MIME_TYPE, Str, strlen(Str));
+ auto result = clip->AddString("text/plain", BString(Str));
+ if (result)
+ printf("%s:%i - AddString=%i %s\n", _FL, result, strerror(result));
- Status = d->Commit() == B_OK;
- if (!Status)
- LgiTrace("%s:%i - Could not commit data to clipboard.\n", _FL);
-
+ result = d->Commit();
+ if (result)
+ printf("%s:%i - Commit=%i %s\n", _FL, result, strerror(result));
+
d->Unlock();
- return Status;
+ return result == B_OK;
}
char *LClipBoard::Text()
{
if (!d->Lock())
{
LgiTrace("%s:%i - Can't lock BClipboard.\n", _FL);
return NULL;
}
auto clip = d->Data();
- const char *string = NULL;
- ssize_t stringLen = 0;
- clip->FindData("text/plain", B_MIME_TYPE, (const void **)&string, &stringLen);
- d->Txt.Set(string, stringLen);
+ BString s;
+ auto result = clip->FindString("text/plain", &s);
+ if (result)
+ printf("%s:%i - FindString=%i %s\n", _FL, result, strerror(result));
+
+ d->Txt = s;
d->Unlock();
return d->Txt;
}
// Wide char versions for plain text
bool LClipBoard::TextW(const char16 *Str, bool AutoEmpty)
{
LAutoString u(WideToUtf8(Str));
return Text(u, AutoEmpty);
}
char16 *LClipBoard::TextW()
{
auto u = Text();
d->WTxt.Reset(Utf8ToWide(u));
return d->WTxt;
}
bool LClipBoard::Bitmap(LSurface *pDC, bool AutoEmpty)
{
bool Status = false;
return Status;
}
LAutoPtr LClipBoard::Bitmap()
{
LAutoPtr img;
return img;
}
bool LClipBoard::Binary(FormatType Format, uchar *Ptr, ssize_t Len, bool AutoEmpty)
{
if (!Ptr || Len <= 0)
return false;
return false;
}
::LString::Array LClipBoard::Files()
{
::LString::Array a;
return a;
}
bool LClipBoard::Files(::LString::Array &a, bool AutoEmpty)
{
return false;
}
struct ReceiveData
{
LAutoPtr *Ptr;
ssize_t *Len;
};
bool LClipBoard::Binary(FormatType Format, LAutoPtr &Ptr, ssize_t *Len)
{
return false;
}