diff --git a/include/common/LgiClasses.h b/include/common/LgiClasses.h
--- a/include/common/LgiClasses.h
+++ b/include/common/LgiClasses.h
@@ -1,1846 +1,1849 @@
/**
\file
\author Matthew Allen
\date 19/12/1997
\brief Gui class definitions
Copyright (C) 1997-2004, Matthew Allen
*/
/////////////////////////////////////////////////////////////////////////////////////
// Includes
#ifndef __GUI_H
#define __GUI_H
#if defined BEOS
#include
#endif
#include "GMutex.h"
#include "LgiOsClasses.h"
#include "GMem.h"
#include "GArray.h"
#include "LgiCommon.h"
#include "GXmlTree.h"
#ifndef WIN32
#include "GDragAndDrop.h"
#endif
/////////////////////////////////////////////////////////////////////////////////////
// Externs
extern long MouseWatcher(void *Ptr);
extern bool LgiCheckFile(char *Path, int PathSize);
LgiFunc bool LgiPostEvent(OsView Wnd, int Event, GMessage::Param a = 0, GMessage::Param b = 0);
LgiFunc GViewI *GetNextTabStop(GViewI *v, bool Back);
/// Converts an OS error code into a text string
LgiClass GAutoString LgiErrorCodeToString(uint32 ErrorCode);
#if defined(MAC) && !defined(COCOA)
LgiFunc void DumpHnd(HIViewRef v, int depth = 0);
#endif
/// Virtual base class for receiving events
class LgiClass GTarget
{
public:
virtual GMessage::Result OnEvent(GMessage *Msg) { return 0; }
};
#if 0
/// Fill colour definition
class LgiClass GViewFill
{
public:
enum FillType
{
None,
Solid,
RefBitmap,
OwnBitmap,
};
protected:
FillType Type;
GColour Col;
GSurface *pDC;
#ifdef WIN32
HBRUSH hBrush;
#endif
public:
GViewFill(GColour c);
GViewFill(COLOUR c, int Bits = -1);
GViewFill(GSurface *dc, bool Copy = true);
GViewFill(const GViewFill &f);
virtual ~GViewFill();
void Empty();
GViewFill &operator =(GColour col)
{
Empty();
Type = Solid;
Col = col;
return *this;
}
void SetRgba32(int r, int g, int b, int a = 0xff)
{
Empty();
Type = Solid;
Col.Rgb(r, g, b, a);
}
GColour GetFlat() const
{
return Col;
}
bool IsTransparent()
{
return Type == Solid && Col.a() == 0;
}
void Fill(GSurface *pDC, GRect *r = 0, GdcPt2 *Origin = 0);
};
#endif
/////////////////////////////////////////////////////////////////////////////////
#if WIN32NATIVE
typedef DWORD OsProcessId;
#else
typedef int OsProcessId;
#endif
/// Returns the current process ID
#define LgiProcessId() (LgiApp->GetProcessId())
/// Returns a pointer to the GApp object.
///
/// \warning Don't use this before you have created your GApp object. i.e. in a constructor
/// of a global static class which is initialized before the main begins executing.
#define LgiApp (GApp::ObjInstance())
/// Returns a system font pointer.
///
/// \warning Don't use this before you have created your GApp object. i.e. in a constructor
/// of a global static class which is initialized before the main begins executing.
#define SysFont (LgiApp->SystemNormal)
/// Returns a bold system font pointer.
///
/// \warning Don't use this before you have created your GApp object. i.e. in a constructor
/// of a global static class which is initialized before the main begins executing.
#define SysBold (LgiApp->SystemBold)
/// Exits the application right now!
///
/// \warning This will cause data loss if you have any unsaved data. Equivilant to exit(0).
LgiFunc void LgiExitApp();
/// Closes the application gracefully.
///
/// This actually causes GApp::Run() to stop processing message and return.
#define LgiCloseApp() LgiApp->Exit(false)
#ifdef LINUX
#define ThreadCheck() LgiAssert(InThread())
#else
#define ThreadCheck()
#endif
/// Optional arguments to the GApp object
struct GAppArguments
{
/// Don't initialize the skinning engine.
bool NoSkin;
};
/// \brief Singleton class for handling application wide settings and methods
///
/// This should be the first class you create, passing in the arguments from the
/// operating system. And once your initialization is complete the 'Run' method
/// is called to enter the main application loop that processes messages for the
/// life time of the application.
class LgiClass GApp : virtual public GAppI,
public GBase,
public OsApplication
{
friend class GView;
protected:
// private member vars
class GAppPrivate *d;
#if defined WIN32
CRITICAL_SECTION StackTraceSync;
friend LONG __stdcall _ExceptionFilter_Redir(LPEXCEPTION_POINTERS e);
LONG __stdcall _ExceptionFilter(LPEXCEPTION_POINTERS e, char *ProductId);
friend class GWin32Class;
List *GetClasses();
#elif defined ATHEOS
char *_AppFile;
#elif defined BEOS
void RefsReceived(BMessage *Msg);
#elif defined LINUX
friend class GClipBoard;
virtual void OnEvents();
void DeleteMeLater(GViewI *v);
void SetClipBoardContent(OsView Hnd, GVariant &v);
bool GetClipBoardContent(OsView Hnd, GVariant &v, GArray &Types);
#endif
friend class GMouseHook;
static GMouseHook *MouseHook;
public:
// Static publics
/// Use 'LgiApp' to return a pointer to the GApp object
static GApp *ObjInstance();
static class GSkinEngine *SkinEngine;
// public member vars
/// The system font
GFont *SystemNormal;
/// The system font in bold
GFont *SystemBold;
/// Pointer to the applications main window
GWindow *AppWnd;
/// Returns true if the GApp object initialized correctly
bool IsOk();
/// Returns this processes ID
OsProcessId GetProcessId();
/// Returns the thread currently running the active message loop
OsThreadId GetGuiThread();
/// Returns the number of CPU cores the machine has
int GetCpuCount();
/// Construct the object
GApp
(
/// The arguments passed in by the OS.
OsAppArguments &AppArgs,
/// The application's name.
const char *AppName,
/// Optional args
GAppArguments *ObjArgs = 0
);
/// Destroys the object
virtual ~GApp();
/// Returns the version of Lgi used. String returned is in the form '#.#.#'
const char *GetLgiVersion() { return LGI_VER; }
/// Resets the arguments
void SetAppArgs(OsAppArguments &AppArgs);
/// Returns the arguemnts
OsAppArguments *GetAppArgs();
/// Returns the n'th argument as a heap string. Free with DeleteArray(...).
char *GetArgumentAt(int n);
/// Enters the message loop.
bool Run
(
/// If true this function will return when the application exits (with LgiCloseApp()).
/// Otherwise if false only pending events will be processed and then the function returns.
bool Loop = true,
/// Idle callback
OnIdleProc IdleCallback = NULL,
/// Param for IdleCallback
void *IdleParam = NULL
);
/// Event called to process the command line
void OnCommandLine();
/// Event called to process files dropped on the application
void OnReceiveFiles(GArray &Files);
/// Event called to process URLs given to the application
void OnUrl(const char *Url);
/// Exits the event loop with the code specified
void Exit
(
/// The application exit code.
int Code = 0
);
/// \brief Parses the command line for a switch
/// \return true if the option exists.
bool GetOption
(
/// The option to look for.
const char *Option,
/// The buffer to receive the value.
GAutoString &Buf
);
/// \brief Parses the command line for a switch
/// \return true if the option exists.
bool GetOption
(
/// The option to look for.
const char *Option,
/// The buffer to receive the value of the command line parameter or NULL if you don't care.
char *Dst = 0,
/// The buffer size in bytes
int DstSize = 0
);
/// Gets the application conf stored in lgi.conf
GXmlTag *GetConfig(const char *Tag);
/// Sets a single tag in the config. (Not written to disk)
void SetConfig(GXmlTag *Tag);
/// Gets the control with the keyboard focus
GViewI *GetFocus();
/// Gets the MIME type of a file
/// \returns the mime type or NULL if unknown.
GAutoString GetFileMimeType
(
/// The file to identify
const char *File
);
/// Gets the applications that can handle a file of a certain mime type
bool GetAppsForMimeType(char *Mime, GArray &Apps);
/// Get a system metric
int32 GetMetric
(
/// One of #LGI_MET_DECOR_X, #LGI_MET_DECOR_Y
LgiSystemMetric Metric
);
/// Get the mouse hook instance
GMouseHook *GetMouseHook();
/// Gets the singleton symbol lookup class
class GSymLookup *GetSymLookup();
+ /// \returns true if the process is running with elevated permissions
+ bool IsElevated();
+
// OS Specific
#if defined WIN32
static bool IsWin9x;
HINSTANCE GetInstance();
int GetShow();
/// \returns true if the application is running under Wine on Linux. This is useful to know
/// if you need to work around missing functionality in the Wine implementation.
bool IsWine();
#endif
#ifdef LINUX
class GLibrary *GetWindowManagerLib();
void RegisterHandle(GView *v);
void UnregisterHandle(GView *v);
bool InThread();
#endif
};
/// \brief The base class for all windows in the GUI.
///
/// This is the core object that all on screen windows inherit from. It encapsulates
/// a HWND on Win32, a BView on BeOS, a Window on X11 + Mac OS X. Used by itself it's not a
/// top level window, for that see the GWindow class.
///
/// To create a top level window see GWindow or GDialog.
///
/// For a GView with scroll bars use GLayout.
///
class LgiClass GView : virtual public GViewI, virtual public GBase
{
friend class GWindow;
friend class GLayout;
friend class GControl;
friend class GMenu;
friend class GSubMenu;
friend class GWnd;
friend class GScrollBar;
friend class GFileTarget;
friend class GDialog;
friend class GDragDropTarget;
friend class GPopup;
friend bool SysOnKey(GView *w, GMessage *m);
#if defined(__GTK_H__)
friend Gtk::gboolean lgi_widget_expose(Gtk::GtkWidget *widget, Gtk::GdkEventExpose *e);
friend Gtk::gboolean lgi_widget_click(Gtk::GtkWidget *widget, Gtk::GdkEventButton *ev);
friend Gtk::gboolean lgi_widget_motion(Gtk::GtkWidget *widget, Gtk::GdkEventMotion *ev);
friend Gtk::gboolean GViewCallback(Gtk::GtkWidget *widget, Gtk::GdkEvent *event, GView *view);
friend Gtk::gboolean PopupEvent(Gtk::GtkWidget *widget, Gtk::GdkEvent *event, class GPopup *This);
friend Gtk::gboolean GtkViewCallback(Gtk::GtkWidget *widget, Gtk::GdkEvent *event, GView *This);
virtual Gtk::gboolean OnGtkEvent(Gtk::GtkWidget *widget, Gtk::GdkEvent *event);
#elif defined WIN32
friend class GWin32Class;
friend LRESULT CALLBACK DlgRedir(OsView hWnd, UINT m, WPARAM a, LPARAM b);
static void CALLBACK TimerProc(OsView hwnd, UINT uMsg, UINT_PTR idEvent, uint32 dwTime);
#elif defined MAC
#if defined(COCOA)
#else
friend OSStatus LgiWindowProc(EventHandlerCallRef, EventRef, void *);
friend OSStatus LgiRootCtrlProc(EventHandlerCallRef, EventRef, void *);
friend OSStatus CarbonControlProc(EventHandlerCallRef, EventRef, void *);
friend OSStatus GViewProc(EventHandlerCallRef, EventRef, void *);
#endif
#elif defined BEOS
friend class GButtonRedir;
friend class _OsEditFrame;
friend class BViewRedir;
friend long _lgi_pulse_thread(void *ptr);
friend GView *_lgi_search_children(GView *v, int &x, int &y);
#endif
GRect Pos;
int _InLock;
protected:
class GViewPrivate *d;
class GDragDropTarget *&DropTargetPtr();
OsView _View; // OS specific handle to view object
GView *_Window;
GMutex *_Lock;
uint16 _BorderSize;
uint16 _IsToolBar;
int WndFlags;
static GViewI *_Capturing;
static GViewI *_Over;
#if defined WIN32
uint32 GetStyle();
void SetStyle(uint32 i);
uint32 GetExStyle();
void SetExStyle(uint32 i);
uint32 GetDlgCode();
void SetDlgCode(uint32 i);
/// \brief Gets the win32 class passed to CreateWindowEx()
const char *GetClassW32();
/// \brief Sets the win32 class passed to CreateWindowEx()
void SetClassW32(const char *s);
/// \brief Creates a class to pass to CreateWindowEx(). If this methed is not
/// explicitly called then the string from GetClass() is used to create a class,
/// which is usually the name of the object.
GWin32Class *CreateClassW32(const char *Class = 0, HICON Icon = 0, int AddStyles = 0);
virtual int SysOnNotify(int Code) { return 0; }
#elif defined BEOS
struct OsMouseInfo;
friend long _lgi_mouse_thread(OsMouseInfo *Info);
OsMouseInfo *_MouseInfo;
OsThread _CaptureThread;
OsThread _PulseThread;
int _PulseRate;
BWindow *_QuitMe;
void _Key(const char *bytes, int32 numBytes, bool down);
virtual bool QuitRequested() {}
#elif defined MAC
OsView _CreateCustomView();
bool _Attach(GViewI *parent);
#if defined(COCOA)
#else
virtual bool _OnGetInfo(HISize &size, HISize &line, HIRect &bounds, HIPoint &origin) { return false; }
virtual void _OnScroll(HIPoint &origin) {}
#endif
#endif
// Complex Region searches
/// Finds the largest rectangle in the region
GRect *FindLargest(GRegion &r);
/// Finds the smallest rectangle that would fit a window 'Sx' by 'Sy'
GRect *FindSmallestFit(GRegion &r, int Sx, int Sy);
/// Finds the largest rectangle on the specified
GRect *FindLargestEdge
(
/// The region to search
GRegion &r,
/// The edge to look at:
/// \sa GV_EDGE_TOP, GV_EDGE_RIGHT, GV_EDGE_BOTTOM or GV_EDGE_LEFT
int Edge
);
void _Delete();
GViewI *FindReal(GdcPt2 *Offset = 0);
bool HandleCapture(GView *Wnd, bool c);
virtual void _Paint(GSurface *pDC = 0, int Ox = 0, int Oy = 0);
#if !WIN32NATIVE
GView *&PopupChild();
virtual bool _Mouse(GMouse &m, bool Move);
void _Focus(bool f);
#endif
virtual bool OnViewMouse(GView *v, GMouse &m) { return true; }
virtual bool OnViewKey(GView *v, GKey &k) { return false; }
virtual void OnNcPaint(GSurface *pDC, GRect &r);
/// List of children views.
friend class GViewIter;
List Children;
public:
/// \brief Creates a view/window.
///
/// On non-Win32 platforms the default argument is the class that redirects the
/// C++ virtual event handlers to the GView handlers. Which is usually the
/// 'DefaultOsView' class. If you pass NULL in a DefaultOsView will be created to
/// do the job. On BeOS you can subclass the native controls by passing in an
/// instance of the BView based class.
GView
(
/// The handle that the OS knows the window by
OsView wnd = 0
);
/// Destructor
virtual ~GView();
/// Returns the OS handle of the view
OsView Handle() { return _View; }
/// Returns the ptr to a GView
GView *GetGView() { return this; }
/// Returns the OS handle of the top level window
virtual OsWindow WindowHandle();
// Attaching windows / heirarchy
bool AddView(GViewI *v, int Where = -1);
bool DelView(GViewI *v);
bool HasView(GViewI *v);
GViewIterator *IterateViews();
/// \brief Attaches the view to a parent view.
///
/// Each GView starts in an un-attached state. When you attach it to a Parent GView
/// the view gains a OS-specific handle and becomes visible on the screen (if the
/// Visible() property is TRUE). However if a view is inserted into the Children list
/// of a GView and it's parent pointer is set correctly it will still paint on the
/// screen without the OS knowing about it. This is known in Lgi as a "virtual window"
/// and is primarily used to cut down on windowing resources. Mouse clicks are handled
/// by the parent window and passed down to the virtual children. Virtual children
/// are somewhat limited. They can't receive focus, or participate in drag and drop
/// operations. If you want to see an example have a look at the GToolBar code.
virtual bool Attach
(
/// The parent view or NULL for a top level window
GViewI *p
);
/// Attachs all the views in the Children list if not already attached.
virtual bool AttachChildren();
/// Detachs a window from it's parent.
virtual bool Detach();
/// Returns true if the window is attached
virtual bool IsAttached();
/// Destroys the window async
virtual void Quit(bool DontDelete = false);
// Properties
/// Gets the top level window that this view belongs to
GWindow *GetWindow();
/// Gets the parent view.
GViewI *GetParent();
/// \brief Sets the parent view.
///
/// This doesn't attach the window so that it will display. You should use GView::Attach for that.
virtual void SetParent(GViewI *p);
/// Script handler to receive UI events.
GEventsI *Script;
bool OnScriptEvent(GViewI *Ctrl) { return false; }
/// Sends a notification to the notify target or the parent chain
void SendNotify(int Data = 0);
/// Gets the window that receives event notifications
GViewI *GetNotify();
/// \brief Sets the view to receive event notifications.
///
/// The notify window will receive events when this view changes. By
/// default the parent view receives the events.
virtual void SetNotify(GViewI *n);
/// \brief Each top level window (GWindow) has a lock. By calling this function
/// you lock the whole GWindow and all it's children.
bool Lock
(
/// The file name of the caller
const char *file,
/// The line number of the caller
int line,
/// The timeout in milli-seconds or -1 to block until locked.
int TimeOut = -1
);
/// Unlocks the GWindow and that this view belongs to.
void Unlock();
/// Called to process every message received by this window.
GMessage::Result OnEvent(GMessage *Msg);
/// true if the view is enabled
bool Enabled();
/// Sets the enabled state
void Enabled(bool e);
/// true if the view is visible
bool Visible();
/// Hides/Shows the view
void Visible
(
/// True if you want to show the view, False to hide the view/
bool v
);
/// true if the view has keyboard focus
bool Focus();
/// Sets the keyboard focus state on the view.
void Focus(bool f);
/// true if this view is a drop target
bool DropTarget();
/// Sets the drop target state of this view
bool DropTarget(bool t);
/// \brief Gives this view a 1 or 2 px sunken border.
///
/// The size is set by the _BorderSize member variable. This border is
/// not considered part of the client area. Mouse and drawing coordinates
/// do not take it into account.
bool Sunken();
/// Sets a sunken border around the control
void Sunken(bool i);
/// true if the view has a flat border
bool Flat();
/// Sets the flat border state
void Flat(bool i);
/// \brief true if the view has a raised border
///
/// The size is set by the _BorderSize member variable. This border is
/// not considered part of the client area. Mouse and drawing coordinates
/// do not take it into account.
bool Raised();
/// Sets the raised border state
void Raised(bool i);
/// Draws an OS themed border
void DrawThemeBorder(GSurface *pDC, GRect &r);
/// \brief true if the control is currently executing in the GUI thread
///
/// Some OS functions are not thread safe, and can only be called in the GUI
/// thread. In the Linux implementation the GUI thread can change from time
/// to time. On Win32 it stays the same. In any case if this function returns
/// true it's safe to do just about anything.
bool InThread();
/// \brief Asyncronously posts an event to be received by this window
///
/// This calls PostMessage on Win32 and XSendEvent on X11. XSendEvent is called
/// with a ClientMessage with the a and b parameters in the data section.
bool PostEvent
(
/// The command ID.
/// \sa Should be M_USER or higher for custom events.
int Cmd,
/// The first 32-bits of data. Equivilent to wParam on Win32.
GMessage::Param a = 0,
/// The second 32-bits of data. Equivilent to lParam on Win32.
GMessage::Param b = 0
);
/// \brief Sets the utf-8 text associated with this view
///
/// Name and NameW are interchangable. Using them in any order will convert the
/// text between utf-8 and wide to satify any requirement. Generally once the opposing
/// version of the string is required both the utf-8 and wide copies of the string
/// remain cached in RAM until the Name is changed.
bool Name(const char *n);
/// Returns the utf-8 text associated with this view
char *Name();
/// Sets the wide char text associated with this view
virtual bool NameW(const char16 *n);
/// \brief Returns the wide char text associated with this view
///
/// On Win32 the wide characters are 16 bits, on unix systems they are 32-bit
/// characters.
virtual char16 *NameW();
/// \brief Gets the font this control should draw with.
///
/// The default font is the system font, owned by the GApp object.
virtual GFont *GetFont();
/// \brief Sets the font for this control
///
/// The lifetime of the font passed in is the responsibility of the caller.
/// The GView object assumes the pointer will be valid at all times.
virtual void SetFont(GFont *Fnt, bool OwnIt = false);
/// Returns the cursor that should be displayed for the given location
/// \returns a cursor type. i.e. LCUR_Normal from LgiDefs.h
LgiCursor GetCursor(int x, int y);
/*
/// \brief Sets the mouse cursor to display when the mouse is over this control.
///
/// This currently only works on Win32, as I can't get the X11 cursor functions to
/// work. They seem horribly broken. (Surprise surprise)
bool SetCursor
(
/// The cursor to change to.
/// \sa the defines starting with LCUR_Normal from LgiDefs.h
LgiCursor Cursor
);
*/
/// \brief Get the position of the view relitive to it's parent.
virtual GRect &GetPos() { return Pos; }
/// Get the client region of the window relitive to itself (ie always 0,0-x,y)
virtual GRect &GetClient(bool InClientSpace = true);
/// Set the position of the view in terms of it's parent
virtual bool SetPos(GRect &p, bool Repaint = false);
/// Gets the width of the view in pixels
int X() { return Pos.X(); }
/// Gets the height of the view in pixels.
int Y() { return Pos.Y(); }
/// Gets the minimum size of the view
GdcPt2 GetMinimumSize();
/// \brief Set the minimum size of the view.
///
/// Only works for top level windows.
void SetMinimumSize(GdcPt2 Size);
/// Sets the style of the control
bool SetCssStyle(const char *CssStyle);
/// Gets the style of the control
class GCss *GetCss(bool Create = false);
/// Sets the CSS foreground or background colour
bool SetColour(GColour &c, bool Fore);
/// Moves a top level window on screen.
void MoveOnScreen();
/// Moves a top level to the center of the screen
void MoveToCenter();
/// Moves a top level window to where the mouse is
void MoveToMouse();
/// The class' name. Should be overriden in child classes to return the
/// right class name. Mostly used for debugging, but in the win32 port it
/// is also the default WIN32 class name passed to RegisterClass() in
/// GView::CreateClass().
///
/// \returns the Class' name for debugging
const char *GetClass() { return "GView"; }
/// \brief Captures all mouse events to this view
///
/// Once you have mouse capture all mouse events will be passed to this
/// view. i.e. during a mouse click.
bool Capture(bool c);
/// true if this view is capturing mouse events.
bool IsCapturing();
/// \brief Gets the current mouse location
/// \return true on success
bool GetMouse
(
/// The mouse location information returned
GMouse &m,
/// Get the location in screen coordinates
bool ScreenCoords = false
);
/// \brief Gets the ID associated with the view
///
/// The ID of a view is designed to associate controls defined in resource
/// files with a object at runtime via a C header file define.
int GetId();
/// Sets the view's ID.
void SetId(int i);
/// true if this control is a tab stop.
bool GetTabStop();
/// \brief Sets whether this control is a tab stop.
///
/// A top stop is a control that receives focus if the user scrolls through the controls
/// with the tab key.
void SetTabStop(bool b);
/// Gets the integer representation of the view's contents
virtual int64 Value() { return 0; }
/// Sets the integer representation of the view's contents
virtual void Value(int64 i) {}
/// Find a view by it's os handle
virtual GViewI *FindControl(OsView hnd);
/// Returns the view by it's ID
virtual GViewI *FindControl
(
// The ID to look for
int Id
);
/// Gets the value of the control identified by the ID
int64 GetCtrlValue(int Id);
/// Sets the value of the control identified by the ID
void SetCtrlValue(int Id, int64 i);
/// Gets the name (text) of the control identified by the ID
char *GetCtrlName(int Id);
/// Sets the name (text) of the control identified by the ID
void SetCtrlName(int Id, const char *s);
/// Gets the enabled state of the control identified by the ID
bool GetCtrlEnabled(int Id);
/// Sets the enabled state of the control identified by the ID
void SetCtrlEnabled(int Id, bool Enabled);
/// Gets the visible state of the control identified by the ID
bool GetCtrlVisible(int Id);
/// Sets the visible state of the control identified by the ID
void SetCtrlVisible(int Id, bool Visible);
/// Causes the given area of the view to be repainted to update the screen
bool Invalidate
(
/// The rectangle of the view to repaint, or NULL for the entire view
GRect *r = NULL,
/// true if you want to wait for the update to happen
bool Repaint = false,
/// false to update in client coordinates, true to update the non client region
bool NonClient = false
);
/// Causes the given area of the view to be repainted to update the screen
bool Invalidate
(
/// The region of the view to repaint
GRegion *r,
/// true if you want to wait for the update to happen
bool Repaint = false,
/// false to update in client coordinates, true to update the non client region
bool NonClient = false
);
/// true if the mouse event is over the view
bool IsOver(GMouse &m);
/// returns the sub window located at the point x,y
GViewI *WindowFromPoint(int x, int y, bool Debug = false);
/// Sets a timer to call the OnPulse() event
void SetPulse
(
/// The milliseconds between calls to OnPulse() or -1 to disable
int Ms = -1
);
/// Convert a point form view coordinates to screen coordinates
void PointToScreen(GdcPt2 &p);
/// Convert a point form screen coordinates to view coordinates
void PointToView(GdcPt2 &p);
/// Get the x,y offset from the virtual window to the first real view in the parent chain
bool WindowVirtualOffset(GdcPt2 *Offset);
/// Get the size of the window borders
GdcPt2 &GetWindowBorderSize();
/// Layout all the child views
virtual bool Pour
(
/// The available space to lay out the views into
GRegion &r
) { return false; }
/// The mouse was clicked over this view
void OnMouseClick
(
/// The event parameters
GMouse &m
);
/// Mouse moves into the area over the control
void OnMouseEnter
(
/// The event parameters
GMouse &m
);
/// Mouse leaves the area over the control
void OnMouseExit
(
/// The event parameters
GMouse &m
);
/// The mouse moves over the control
void OnMouseMove
(
/// The event parameters
GMouse &m
);
/// The mouse wheel was scrolled.
bool OnMouseWheel
(
/// The amount scrolled
double Lines
);
/// A key was pressed while this view has focus
bool OnKey(GKey &k);
/// The view is attached
void OnCreate();
/// The view is detached
void OnDestroy();
/// The view gains or loses the keyboard focus
void OnFocus
(
/// True if the control is receiving focus
bool f
);
/// \brief Called every so often by the timer system.
/// \sa SetPulse()
void OnPulse();
/// Called when the view position changes
void OnPosChange();
/// Called on a top level window when something requests to close the window
bool OnRequestClose
(
/// True if the operating system is shutting down.
bool OsShuttingDown
);
/// Return the type of cursor that should be visible when the mouse is at x,y
/// e.g. #LCUR_Normal
int OnHitTest
(
/// The x coordinate in view coordinates
int x,
/// The y coordinate in view coordinates
int y
);
/// Called when the contents of the Children list have changed.
void OnChildrenChanged(GViewI *Wnd, bool Attaching);
/// Called to paint the onscreen representation of the view
void OnPaint(GSurface *pDC);
/// \brief Called when a child view or view with it's SetNotify() set to this window changes.
///
/// The event by default will bubble up to the GWindow at the top of the window heirarchy visiting
/// each GView on the way. If it reaches a GView that processes it then the event stops propergating
/// up the heirarchy.
int OnNotify(GViewI *Ctrl, int Flags);
/// Called when a menu command is activated by the user.
int OnCommand(int Cmd, int Event, OsView Wnd);
/// Called after the view is attached to a new parent
void OnAttach();
/// Called to get layout information for the control
bool OnLayout(GViewLayoutInfo &Inf) { return false; }
#if defined(_DEBUG)
bool _Debug;
void Debug();
void _Dump(int Depth = 0);
#endif
};
///////////////////////////////////////////////////////////////////////////////////////////////
// Control or View window
/// FindLargestEdge parameter
/// \sa GView::FindLargest(GRegion &, int)
#define GV_EDGE_TOP 0x0001
/// FindLargestEdge parameter
/// \sa GView::FindLargest(GRegion &, int)
#define GV_EDGE_RIGHT 0x0002
/// FindLargestEdge parameter
/// \sa GView::FindLargest(GRegion &, int)
#define GV_EDGE_BOTTOM 0x0004
/// FindLargestEdge parameter
/// \sa GView::FindLargest(GRegion &, int)
#define GV_EDGE_LEFT 0x0008
/// Id of the vertical scroll bar in a GLayout control
#define IDC_VSCROLL 14000
/// Id of the horizontal scroll bar in a GLayout control
#define IDC_HSCROLL 14001
#ifdef MAC
#define XPLATFORM_GLAYOUT 1
#else
#define XPLATFORM_GLAYOUT 0
#endif
/// \brief A GView with scroll bars
///
/// This class adds scroll bars to the standard GView base class. The scroll bars can be
/// directly accessed using the VScroll and HScroll member variables. Although you should
/// always do a NULL check on the pointer before using, if the scroll bar is not activated
/// using GLayout::SetScrollBars then VScroll and/or HScroll will by NULL. When the scroll
/// bar is used to scroll the GLayout control you will receive an event on GView::OnNotify
/// with the control ID of the scrollbar, which is either #IDC_VSCROLL or #IDC_HSCROLL.
class LgiClass GLayout : public GView
{
friend class GScroll;
friend class GView;
// Private variables
bool _SettingScrollBars;
bool _PourLargest;
protected:
/// The vertical scroll bar
GScrollBar *VScroll;
/// The horizontal scroll bar
GScrollBar *HScroll;
/// Sets which of the scroll bars is visible
virtual bool SetScrollBars
(
/// Make the horizontal scroll bar visible
bool x,
/// Make the vertical scroll bar visible
bool y
);
#if defined(XPLATFORM_GLAYOUT)
void AttachScrollBars();
bool _SetScrollBars(bool x, bool y);
#endif
#if defined(MAC) && !XPLATFORM_GLAYOUT
friend class GLayoutScrollBar;
HISize Line;
OsView RealWnd;
bool _OnGetInfo(HISize &size, HISize &line, HIRect &bounds, HIPoint &origin);
void _OnScroll(HIPoint &origin);
void OnScrollConfigure();
#endif
public:
GLayout();
~GLayout();
const char *GetClass() { return "GLayout"; }
/// Gets the current scroll bar values.
virtual void GetScrollPos(int &x, int &y);
/// Sets the current scroll bar values
virtual void SetScrollPos(int x, int y);
/// Gets the "pour largest" setting
bool GetPourLargest();
/// \brief Sets the "pour largest" setting
///
/// When "pour largest" is switched on the pour function automatically
/// lays the control into the largest rectangle available. This is useful
/// for putting a single GView into a splitter pane or a tab view and having
/// it just take up all the space.
void SetPourLargest(bool i);
/// Handles the incoming events.
GMessage::Result OnEvent(GMessage *Msg);
/// Lay out all the children views into the client area according to their
/// own internal rules. Space is given in a first come first served basis.
bool Pour(GRegion &r);
// Impl
#if defined(__GTK_H__) || defined(MAC) || defined(BEOS)
bool Attach(GViewI *p);
bool Detach();
GRect &GetClient(bool InClientSpace = true);
#if defined(MAC) && !XPLATFORM_GLAYOUT
bool Invalidate(GRect *r = NULL, bool Repaint = false, bool NonClient = false);
bool Focus();
void Focus(bool f);
bool SetPos(GRect &p, bool Repaint = false);
#else
void OnPosChange();
int OnNotify(GViewI *c, int f);
void OnNcPaint(GSurface *pDC, GRect &r);
#endif
#endif
GViewI *FindControl(int Id);
};
/// Client draws the content.
#define GIC_OWNER_DRAW 0x01
/// Column header is text.
#define GIC_ASK_TEXT 0x02
/// Column header is an image.
#define GIC_ASK_IMAGE 0x04
/// Not used.
#define GIC_OWN_LIST 0x08
/// Drag is over the control
#define GIC_IN_DRAG_OP 0x10
class LgiClass GItemContainer
{
protected:
int Flags;
GImageList *ImageList;
public:
GItemContainer();
virtual ~GItemContainer();
// Props
bool OwnerDraw() { return TestFlag(Flags, GIC_OWNER_DRAW); }
void OwnerDraw(bool b) { if (b) SetFlag(Flags, GIC_OWNER_DRAW); else ClearFlag(Flags, GIC_OWNER_DRAW); }
bool AskText() { return TestFlag(Flags, GIC_ASK_TEXT); }
void AskText(bool b) { if (b) SetFlag(Flags, GIC_ASK_TEXT); else ClearFlag(Flags, GIC_ASK_TEXT); }
bool AskImage() { return TestFlag(Flags, GIC_ASK_IMAGE); }
void AskImage(bool b) { if (b) SetFlag(Flags, GIC_ASK_IMAGE); else ClearFlag(Flags, GIC_ASK_IMAGE); }
bool InsideDragOp() { return TestFlag(Flags, GIC_IN_DRAG_OP); }
void InsideDragOp(bool b) { if (b) SetFlag(Flags, GIC_IN_DRAG_OP); else ClearFlag(Flags, GIC_IN_DRAG_OP); }
// Image List
GImageList *GetImageList() { return ImageList; }
bool SetImageList(GImageList *List, bool Own = true);
bool LoadImageList(char *File, int x, int y);
bool OwnList() { return TestFlag(Flags, GIC_OWN_LIST); }
void OwnList(bool b) { if (b) SetFlag(Flags, GIC_OWN_LIST); else ClearFlag(Flags, GIC_OWN_LIST); }
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// Menus
#include "GMenu.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
/// The available states for a top level window
enum GWindowZoom
{
/// Minimized
GZoomMin,
/// Restored/Normal
GZoomNormal,
/// Maximized
GZoomMax
};
enum GWindowHookType
{
GNoEvents = 0,
/// \sa GWindow::RegisterHook()
GMouseEvents = 1,
/// \sa GWindow::RegisterHook()
GKeyEvents = 2,
/// \sa GWindow::RegisterHook()
GKeyAndMouseEvents = GMouseEvents | GKeyEvents,
};
/// A top level window.
class LgiClass GWindow :
public GView
#ifndef WIN32
, public GDragDropTarget
#endif
{
friend class BViewRedir;
friend class GView;
friend class GButton;
friend class XWindow;
friend class GDialog;
#if defined(MAC) && !defined(COCOA)
friend pascal OSStatus LgiWindowProc(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData);
#endif
bool _QuitOnClose;
protected:
#if WIN32NATIVE
GRect OldPos;
GWindow *_Dialog;
#else
OsWindow Wnd;
void _OnViewDelete();
void _SetDynamic(bool i);
#endif
#if defined BEOS
friend class GMenu;
friend class GView;
#elif defined __GTK_H__
friend class GMenu;
Gtk::GtkWidget *_Root, *_VBox, *_MenuBar;
void _Paint(GSurface *pDC = 0, int Ox = 0, int Oy = 0);
void OnGtkDelete();
Gtk::gboolean OnGtkEvent(Gtk::GtkWidget *widget, Gtk::GdkEvent *event);
#endif
/// The default button
GViewI *_Default;
/// The menu on the window
GMenu *Menu;
class GWindowPrivate *d;
void SetChildDialog(GDialog *Dlg);
void SetDragHandlers(bool On);
public:
#ifdef __GTK_H__
GWindow(Gtk::GtkWidget *w = 0);
#else
GWindow();
#endif
~GWindow();
const char *GetClass() { return "GWindow"; }
/// Lays out the child views into the client area.
virtual void Pour();
/// Returns the current menu object
GMenu *GetMenu() { return Menu; }
/// Set the menu object.
void SetMenu(GMenu *m) { Menu = m; }
/// Gets the "quit on close" setting.
bool GetQuitOnClose() { return _QuitOnClose; }
/// \brief Sets the "quit on close" setting.
///
/// When this is switched on the application will quit the main message
/// loop when this GWindow is closed. This is really useful for your
/// main application window. Otherwise the UI will disappear but the
/// application is still running.
void SetQuitOnClose(bool i) { _QuitOnClose = i; }
bool GetSnapToEdge();
void SetSnapToEdge(bool b);
/// Gets the current zoom setting
GWindowZoom GetZoom();
/// Sets the current zoom
void SetZoom(GWindowZoom i);
/// Raises the window to the top of the stack.
void Raise();
void OnPosChange();
GMessage::Result OnEvent(GMessage *Msg);
void OnPaint(GSurface *pDC);
bool HandleViewMouse(GView *v, GMouse &m);
bool HandleViewKey(GView *v, GKey &k);
bool OnRequestClose(bool OsShuttingDown);
bool Obscured();
bool Visible();
void Visible(bool i);
bool IsActive();
GRect &GetPos();
// Focus setting
GViewI *GetFocus();
enum FocusType
{
GainFocus,
LoseFocus,
ViewDelete
};
void SetFocus(GViewI *ctrl, FocusType type);
/// Registers a watcher to receive OnView... messages before they
/// are passed through to the intended recipient.
bool RegisterHook
(
/// The target view.
GView *Target,
/// Combination of #GMouseEvents and #GKeyEvents OR'd together.
GWindowHookType EventType,
/// Not implemented
int Priority = 0
);
/// Unregisters a hook target
bool UnregisterHook(GView *Target);
/// Called when the window zoom state changes.
virtual void OnZoom(GWindowZoom Action) {}
/// Called when the tray icon is clicked. (if present)
virtual void OnTrayClick(GMouse &m);
/// Called when the tray icon menu is about to be displayed.
virtual void OnTrayMenu(GSubMenu &m) {}
/// Called when the tray icon menu item has been selected.
virtual void OnTrayMenuResult(int MenuId) {}
/// Called when files are dropped on the window.
virtual void OnReceiveFiles(GArray &Files) {}
/// Called when a URL is sent to the window
virtual void OnUrl(const char *Url) {};
#if !WIN32NATIVE
bool Attach(GViewI *p);
// Props
OsWindow WindowHandle() { return Wnd; }
bool Name(const char *n);
char *Name();
bool SetPos(GRect &p, bool Repaint = false);
GRect &GetClient(bool InClientSpace = true);
// D'n'd
int WillAccept(List &Formats, GdcPt2 Pt, int KeyState);
int OnDrop(char *Format, GVariant *Data, GdcPt2 Pt, int KeyState);
// Events
void OnChildrenChanged(GViewI *Wnd, bool Attaching);
void OnCreate();
#endif
#if defined MAC
bool &CloseRequestDone();
bool PostEvent(int Cmd, GMessage::Param a = 0, GMessage::Param b = 0);
void Quit(bool DontDelete = false);
#ifndef COCOA
OSErr HandlerCallback(DragTrackingMessage *tracking, DragRef theDrag);
#endif
int OnCommand(int Cmd, int Event, OsView Wnd);
GViewI *WindowFromPoint(int x, int y, bool Debug = false);
virtual void OnFrontSwitch(bool b);
#elif defined __GTK_H__
void OnMap(bool m);
#endif
/// Gets the default view
GViewI *GetDefault();
/// Sets the default view
void SetDefault(GViewI *v);
/// Saves/loads the window's state, e.g. position, minimized/maximized etc
bool SerializeState
(
/// The data store for reading/writing
GDom *Store,
/// The field name to use for storing settings under
const char *FieldName,
/// TRUE if loading the settings into the window, FALSE if saving to the store.
bool Load
);
};
////////////////////////////////////////////////////////////////////////////
/// Puts a tool tip on screen when the mouse wanders over a region.
class LgiClass GToolTip : public GView
{
class GToolTipPrivate *d;
public:
GToolTip();
~GToolTip();
/// Create a tip
int NewTip
(
/// The text to display
char *Name,
/// The region the mouse has to be in to trigger the tip
GRect &Pos
);
/// Delete the tip.
void DeleteTip(int Id);
bool Attach(GViewI *p);
};
////////////////////////////////////////////////////////////////////////////
// Dialog stuff
#include "LgiWidgets.h"
////////////////////////////////////////////////////////////////////////////
// Progress meters stuff
#include "Progress.h"
#include "GProgress.h"
////////////////////////////////////////////////////////////////////////
#include "GFileSelect.h"
#include "GFindReplaceDlg.h"
#include "GToolBar.h"
#include "GThread.h"
////////////////////////////////////////////////////////////////////////////////////////////////
/// Displays 2 views side by side
class LgiClass GSplitter : public GLayout
{
class GSplitterPrivate *d;
void CalcRegions(bool Follow = false);
bool OverSplit(int x, int y);
public:
GSplitter();
~GSplitter();
const char *GetClass() { return "GSplitter"; }
/// Get the position of the split in px
int64 Value(); // Use to set/get the split position
/// Sets the position of the split
void Value(int64 i);
/// True if the split is vertical
bool IsVertical();
/// Sets the split to horizontal or vertical
void IsVertical(bool v);
/// True if the split follows the opposite
bool DoesSplitFollow();
/// Sets the split to follow the opposite
void DoesSplitFollow(bool i);
/// Return the left/top view
GView *GetViewA();
/// Detach the left/top view
void DetachViewA();
/// Sets the left/top view
void SetViewA(GView *a, bool Border = true);
/// Return the right/bottom view
GView *GetViewB();
/// Detach the right/bottom view
void DetachViewB();
/// Sets the right/bottom view
void SetViewB(GView *b, bool Border = true);
/// Get the size of the bar that splits the views
int BarSize();
/// Set the bar size
void BarSize(int i);
bool Border();
void Border(bool i);
GViewI *FindControl(OsView hCtrl);
bool Attach(GViewI *p);
bool Pour(GRegion &r);
void OnPaint(GSurface *pDC);
void OnPosChange();
void OnMouseClick(GMouse &m);
void OnMouseMove(GMouse &m);
void OnMouseExit(GMouse &m);
int OnHitTest(int x, int y);
void OnChildrenChanged(GViewI *Wnd, bool Attaching);
LgiCursor GetCursor(int x, int y);
};
////////////////////////////////////////////////////////////////////////////////////////////////
#define STATUSBAR_SEPARATOR 4
#define GSP_SUNKEN 0x0001
class LgiClass GStatusBar : public GLayout
{
friend class GStatusPane;
protected:
void RePour();
public:
GStatusBar();
~GStatusBar();
const char *GetClass() { return "GStatusBar"; }
bool Pour(GRegion &r);
void OnPaint(GSurface *pDC);
GStatusPane *AppendPane(const char *Text, int Width);
bool AppendPane(GStatusPane *Pane);
};
class LgiClass GStatusPane :
public GView
{
friend class GStatusBar;
protected:
int Flags;
int Width;
GSurface *pDC;
public:
GStatusPane();
~GStatusPane();
const char *GetClass() { return "GStatusPane"; }
char *Name() { return GBase::Name(); }
bool Name(const char *n);
void OnPaint(GSurface *pDC);
int GetWidth();
void SetWidth(int x);
bool Sunken();
void Sunken(bool i);
GSurface *Bitmap();
void Bitmap(GSurface *pdc);
};
/////////////////////////////////////////////////////////////////////////////////////////////
class LgiClass GCommand : public GBase //, public GFlags
{
int Flags;
bool PrevValue;
public:
int Id;
GToolButton *ToolButton;
GMenuItem *MenuItem;
GKey *Accelerator;
char *TipHelp;
GCommand();
~GCommand();
bool Enabled();
void Enabled(bool e);
bool Value();
void Value(bool v);
};
/////////////////////////////////////////////////////////////////////////
/// Put an icon in the system tray
class LgiClass GTrayIcon :
public GBase
// public GFlags
{
friend class GTrayWnd;
class GTrayIconPrivate *d;
public:
/// Constructor
GTrayIcon
(
/// The owner GWindow
GWindow *p
);
~GTrayIcon();
/// Add an icon to the list
bool Load(const TCHAR *Str);
/// Is it visible?
bool Visible();
/// Show / Hide the tray icon
void Visible(bool v);
/// The index of the icon visible
int64 Value();
/// Set the index of the icon you want visible
void Value(int64 v);
/// Call this in your window's OnEvent handler
virtual GMessage::Result OnEvent(GMessage *Msg);
};
//////////////////////////////////////////////////////////////////
#include "GInput.h"
#include "GPrinter.h"
//////////////////////////////////////////////////////////////////
/// \brief A BeOS style alert window, kinda like a Win32 MessageBox
///
/// The best thing about this class is you can name the buttons very specifically.
/// It's always non-intuitive to word a question to the user in such a way so thats
/// it's obvious to answer with "Ok" or "Cancel". But if the user gets a question
/// with customised "actions" as buttons they'll love you.
///
/// The button pressed is returned as a index from the DoModal() function. Starting
/// at '1'. i.e. Btn2 -> returns 2.
class LgiClass GAlert : public GDialog
{
public:
/// Constructor
GAlert
(
/// The parent view
GViewI *parent,
/// The dialog title
const char *Title,
/// The body of the message
const char *Text,
/// The first button text
const char *Btn1,
/// The [optional] 2nd buttons text
const char *Btn2 = 0,
/// The [optional] 3rd buttons text
const char *Btn3 = 0
);
void SetAppModal();
int OnNotify(GViewI *Ctrl, int Flags);
};
/// Timer class to help do something every so often
class LgiClass DoEvery
{
int64 LastTime;
int64 Period;
public:
/// Constructor
DoEvery
(
/// Timeout in ms
int p = 1000
);
/// Reset the timer
void Init
(
/// Timeout in ms
int p = -1
);
/// Returns true when the time has expired. Resets automatically.
bool DoNow();
};
/// \brief Factory for creating view's by name.
///
/// Inherit from this to add a new factory to create objects. Override
/// NewView() to create your control.
class LgiClass GViewFactory
{
/** \brief Create a view by name
\code
if (strcmp(Class, "MyControl") == 0)
{
return new MyControl;
}
\endcode
*/
virtual GView *NewView
(
/// The name of the class to create
const char *Class,
/// The initial position of the view
GRect *Pos,
/// The initial text of the view
const char *Text
) = 0;
public:
GViewFactory();
virtual ~GViewFactory();
/// Create a view by name.
static GView *Create(const char *Class, GRect *Pos = 0, const char *Text = 0);
};
//////////////////////////////////////////////////////////
// Colour
LgiFunc void LgiInitColours();
LgiFunc COLOUR LgiColour(int Colour);
// Graphics
LgiFunc void LgiDrawBox(GSurface *pDC, GRect &r, bool Sunken, bool Fill);
LgiFunc void LgiWideBorder(GSurface *pDC, GRect &r, int Type);
LgiFunc void LgiThinBorder(GSurface *pDC, GRect &r, int Type);
LgiFunc void LgiFlatBorder(GSurface *pDC, GRect &r, int Width = -1);
// Helpers
#ifdef __GTK_H__
extern Gtk::gboolean GtkViewCallback(Gtk::GtkWidget *widget, Gtk::GdkEvent *event, GView *This);
#endif
#ifdef LINUX
/// Ends a x windows startup session
LgiFunc void LgiFinishXWindowsStartup(class GViewI *Wnd);
#endif
/// \brief Displays a message box
/// \returns The button clicked. The return value is one of #IDOK, #IDCANCEL, #IDYES or #IDNO.
LgiFunc int LgiMsg
(
/// The parent view or NULL if none available
GViewI *Parent,
/// The message's text. This is a printf format string that you can pass arguments to
const char *Msg,
/// The title of the message box window
const char *Title = 0,
/// The type of buttons below the message. Can be one of:
/// #MB_OK, #MB_OKCANCEL, #MB_YESNO or #MB_YESNOCANCEL.
int Type = MB_OK,
...
);
/// Contains all the infomation about a display/monitor attached to the system.
/// \sa LgiGetDisplays
struct GDisplayInfo
{
/// The position and dimensions of the display. On windows the left/upper
/// most display will be positioned at 0,0 and each furthur display will have
/// co-ordinates that join to one edge of that initial rectangle.
GRect r;
/// The number of bits per pixel
int BitDepth;
/// The refreash rate
int Refresh;
/// The device's path, system specific
char *Device;
/// A descriptive name of the device, usually the video card
char *Name;
/// The name of any attached monitor
char *Monitor;
GDisplayInfo()
{
r.ZOff(-1, -1);
BitDepth = 0;
Refresh = 0;
Device = 0;
Name = 0;
Monitor = 0;
}
~GDisplayInfo()
{
DeleteArray(Device);
DeleteArray(Name);
DeleteArray(Monitor);
}
};
/// Returns infomation about the displays attached to the system.
/// \returns non-zero on success.
LgiFunc bool LgiGetDisplays
(
/// [out] The array of display info structures. The caller should free these
/// objects using Displays.DeleteObjects().
GArray &Displays,
/// [out] Optional bounding rectangle of all displays. Can be NULL if your don't
/// need that information.
GRect *AllDisplays = 0
);
/// This class makes it easy to profile a function and write out timings at the end
class LgiClass GProfile
{
struct Sample
{
uint64 Time;
const char *Name;
Sample(uint64 t = 0, const char *n = 0)
{
Time = t;
Name = n;
}
};
GArray s;
int MinMs;
public:
GProfile(const char *Name);
virtual ~GProfile();
void HideResultsIfBelow(int Ms);
virtual void Add(const char *Name);
};
#endif
diff --git a/include/common/LgiDefs.h b/include/common/LgiDefs.h
--- a/include/common/LgiDefs.h
+++ b/include/common/LgiDefs.h
@@ -1,559 +1,580 @@
/**
\file
\author Matthew Allen
\date 24/9/1999
\brief Defines and types
Copyright (C) 1999-2004, Matthew Allen
*/
#ifndef _LGIDEFS_H_
#define _LGIDEFS_H_
#include "LgiInc.h"
// Unsafe typedefs, for backward compatibility
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
// Length safe typedesf, use these in new code
#ifndef BEOS
/// 8-bit signed int type (size safe, garenteed to be 8 bits)
typedef char int8;
/// 8-bit unsigned int type (size safe, garenteed to be 8 bits)
typedef unsigned char uint8;
#else
#include
#endif
/// 16-bit signed int type (size safe, garenteed to be 16 bits)
typedef short int16;
/// 16-bit unsigned int type (size safe, garenteed to be 16 bits)
typedef unsigned short uint16;
#ifndef BEOS
/// 32-bit signed int type (size safe, garenteed to be 32 bits)
typedef int int32;
/// 32-bit unsigned int type (size safe, garenteed to be 32 bits)
typedef unsigned int uint32;
#endif
#ifdef _MSC_VER
/// 64-bit signed int type (size safe, garenteed to be 64 bits)
typedef signed __int64 int64;
/// 64-bit unsigned int type (size safe, garenteed to be 64 bits)
typedef unsigned __int64 uint64;
#else
/// 64-bit signed int type (size safe, garenteed to be 64 bits)
typedef signed long long int64;
/// 64-bit unsigned int type (size safe, garenteed to be 64 bits)
typedef unsigned long long uint64;
#endif
#if !defined(LINUX)
/// \brief Wide unicode char
///
/// This is 16 bits on Win32 and Mac, but 32 bits on unix platforms. There are a number
/// of wide character string function available for manipulating wide char strings.
///
/// Firstly to convert to and from utf-8 there is:
///
/// - LgiNewUtf8To16()
///
- LgiNewUtf16To8()
///
///
/// Wide versions of standard library functions are available:
///
/// - StrchrW()
///
- StrrchrW()
///
- StrnchrW()
///
- StrstrW()
///
- StristrW()
///
- StrnstrW()
///
- StrnistrW()
///
- StrcmpW()
///
- StricmpW()
///
- StrncmpW()
///
- StrnicmpW()
///
- StrcpyW()
///
- StrncpyW()
///
- StrlenW()
///
- StrcatW()
///
- HtoiW()
///
- NewStrW()
///
- TrimStrW()
///
- ValidStrW()
///
- MatchStrW()
///
#if defined(__MINGW32__) || defined(BEOS)
typedef wchar_t char16;
#else
#if _MSC_VER > 1300
typedef wchar_t char16;
#else
typedef unsigned short char16;
#endif
#endif
#else // LINUX
typedef unsigned int char16;
#endif
#if !WIN32NATIVE
#ifdef UNICODE
typedef char16 TCHAR;
#ifndef _T
#define _T(arg) L##arg
#endif
#else
typedef char TCHAR;
#ifndef _T
#define _T(arg) arg
#endif
#endif
#endif
#if defined(_MSC_VER)
#if _MSC_VER >= 1400
#ifdef _WIN64
typedef __int64 NativeInt;
typedef unsigned __int64 UNativeInt;
#else
typedef _W64 int NativeInt;
typedef _W64 unsigned int UNativeInt;
#endif
#else
typedef int NativeInt;
typedef unsigned int UNativeInt;
#endif
#else
#if __LP64__
typedef int64 NativeInt;
typedef uint64 UNativeInt;
#else
typedef int NativeInt;
typedef unsigned int UNativeInt;
#endif
#endif
/// Generic pointer to any base type. Used when addressing continuous data of
/// different types.
typedef union
{
int8 *s8;
uint8 *u8;
int16 *s16;
uint16 *u16;
int32 *s32;
uint32 *u32;
int64 *s64;
uint64 *u64;
NativeInt *ni;
UNativeInt *uni;
char *c;
char16 *w;
float *f;
double *d;
#ifdef __cplusplus
bool *b;
#else
unsigned char *b;
#endif
void **vp;
int i;
} GPointer;
// Basic macros
// #define abs(a) (((a) > 0) ? (a) : -(a))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define limit(i,l,u) (((i)<(l)) ? (l) : (((i)>(u)) ? (u) : (i)))
#define makelong(a, b) ((a)<<16 | (b&0xFFFF))
#define loword(a) (a&0xFFFF)
#define hiword(a) (a>>16)
#define LgiSwap(a, b) { int n = a; a = b; b = n; }
/// Returns true if 'c' is an ascii character
#define IsAlpha(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
/// Returns true if 'c' is a digit (number)
#define IsDigit(c) ((c) >= '0' && (c) <= '9')
// Byte swapping
#define LgiSwap16(a) ( (((a) & 0xff00) >> 8) | \
(((a) & 0x00ff) << 8) )
#define LgiSwap32(a) ( (((a) & 0xff000000) >> 24) | \
(((a) & 0x00ff0000) >> 8) | \
(((a) & 0x0000ff00) << 8) | \
(((a) & 0x000000ff) << 24) )
#ifdef __GNUC__
#define LgiSwap64(a) ( (((a) & 0xff00000000000000LLU) >> 56) | \
(((a) & 0x00ff000000000000LLU) >> 40) | \
(((a) & 0x0000ff0000000000LLU) >> 24) | \
(((a) & 0x000000ff00000000LLU) >> 8) | \
(((a) & 0x00000000ff000000LLU) << 8) | \
(((a) & 0x0000000000ff0000LLU) << 24) | \
(((a) & 0x000000000000ff00LLU) << 40) | \
(((a) & 0x00000000000000ffLLU) << 56) )
#else
#define LgiSwap64(a) ( (((a) & 0xff00000000000000) >> 56) | \
(((a) & 0x00ff000000000000) >> 40) | \
(((a) & 0x0000ff0000000000) >> 24) | \
(((a) & 0x000000ff00000000) >> 8) | \
(((a) & 0x00000000ff000000) << 8) | \
(((a) & 0x0000000000ff0000) << 24) | \
(((a) & 0x000000000000ff00) << 40) | \
(((a) & 0x00000000000000ff) << 56) )
#endif
// Good ol NULLy
#ifndef NULL
#define NULL 0
#endif
// Slashes and quotes
#define IsSlash(c) (((c)=='/')||((c)=='\\'))
#define IsQuote(c) (((c)=='\"')||((c)=='\''))
// Some objectish ones
#define ZeroObj(obj) memset(&obj, 0, sizeof(obj))
#ifndef CountOf
#define CountOf(array) (sizeof(array)/sizeof(array[0]))
#endif
#ifndef MEMORY_DEBUG
#define DeleteObj(obj) if (obj) { delete obj; obj = 0; }
#define DeleteArray(obj) if (obj) { delete [] obj; obj = 0; }
#endif
// Asserts
LgiFunc void _lgi_assert(bool b, const char *test, const char *file, int line);
#define LgiAssert(b) _lgi_assert(b, #b, __FILE__, __LINE__)
// Flags
#define SetFlag(i, f) (i) |= (f)
#define ClearFlag(i, f) (i) &= ~(f)
#define TestFlag(i, f) (((i) & (f)) != 0)
// Defines
/// Enum of all the operating systems we might be running on.
enum LgiOs
{
/// \brief Unknown OS
/// \sa LgiGetOs
LGI_OS_UNKNOWN = 0,
/// \brief Windows 95, 98[se] or ME. (Not supported)
/// \sa LgiGetOs
LGI_OS_WIN9X,
/// \brief 32bit NT, 2k, XP, Vista, 7, 8 or later. (XP and later supported)
/// \sa LgiGetOs
LGI_OS_WIN32,
/// \brief 64bit NT, 2k, XP, Vista, 7, 8 or later. (XP and later supported)
/// \sa LgiGetOs
LGI_OS_WIN64,
/// \brief BeOS/Haiku. (Somewhat supported)
/// \sa LgiGetOs
LGI_OS_HAIKU,
/// \brief Linux. (Kernels v2.4 and up supported)
/// \sa LgiGetOs
LGI_OS_LINUX,
/// \brief There was an Atheos port at one point. (Not supported)
/// \sa LgiGetOs
LGI_OS_MAC_OS_X,
/// One higher than the maximum OS define
LGI_OS_MAX,
};
// System Colours
/// Black
#define LC_BLACK LgiColour(0)
/// Dark grey
#define LC_DKGREY LgiColour(1)
/// Medium grey
#define LC_MIDGREY LgiColour(2)
/// Light grey
#define LC_LTGREY LgiColour(3)
/// White
#define LC_WHITE LgiColour(4)
/// 3d dark shadow
#define LC_SHADOW LgiColour(5)
/// 3d light shadow
#define LC_LOW LgiColour(6)
/// Flat colour for dialogs, windows and buttons
#define LC_MED LgiColour(7)
/// 3d dark hilight
#define LC_HIGH LgiColour(8)
/// 3d light hilight
#define LC_LIGHT LgiColour(9)
/// Dialog colour
#define LC_DIALOG LgiColour(10)
/// Workspace area
#define LC_WORKSPACE LgiColour(11)
/// Default text colour
#define LC_TEXT LgiColour(12)
/// Selection background colour when in focus
#define LC_FOCUS_SEL_BACK LgiColour(13)
/// Selection foreground colour when in focus
#define LC_FOCUS_SEL_FORE LgiColour(14)
#define LC_ACTIVE_TITLE LgiColour(15)
#define LC_ACTIVE_TITLE_TEXT LgiColour(16)
#define LC_INACTIVE_TITLE LgiColour(17)
#define LC_INACTIVE_TITLE_TEXT LgiColour(18)
#define LC_MENU_BACKGROUND LgiColour(19)
#define LC_MENU_TEXT LgiColour(20)
/// Selection background colour when not in focus
#define LC_NON_FOCUS_SEL_BACK LgiColour(21)
/// Selection forground colour when not in focus
#define LC_NON_FOCUS_SEL_FORE LgiColour(22)
#define LC_MAXIMUM 23
// Cursors
enum LgiCursor
{
/// Blank/invisible cursor
LCUR_Blank,
/// Normal arrow
LCUR_Normal,
/// Upwards arrow
LCUR_UpArrow,
/// Downwards arrow
LCUR_DownArrow,
/// Left arrow
LCUR_LeftArrow,
/// Right arrow
LCUR_RightArrow,
/// Crosshair
LCUR_Cross,
/// Hourglass/watch
LCUR_Wait,
/// Ibeam/text entry
LCUR_Ibeam,
/// Vertical resize (|)
LCUR_SizeVer,
/// Horizontal resize (-)
LCUR_SizeHor,
/// Diagonal resize (/)
LCUR_SizeBDiag,
/// Diagonal resize (\)
LCUR_SizeFDiag,
/// All directions resize
LCUR_SizeAll,
/// Vertical splitting
LCUR_SplitV,
/// Horziontal splitting
LCUR_SplitH,
/// A pointing hand
LCUR_PointingHand,
/// A slashed circle
LCUR_Forbidden,
/// Copy Drop
LCUR_DropCopy,
/// Copy Move
LCUR_DropMove,
};
// General Event Flags
#define LGI_EF_LCTRL 0x00000001
#define LGI_EF_RCTRL 0x00000002
#define LGI_EF_CTRL (LGI_EF_LCTRL | LGI_EF_RCTRL)
#define LGI_EF_LALT 0x00000004
#define LGI_EF_RALT 0x00000008
#define LGI_EF_ALT (LGI_EF_LALT | LGI_EF_RALT)
#define LGI_EF_LSHIFT 0x00000010
#define LGI_EF_RSHIFT 0x00000020
#define LGI_EF_SHIFT (LGI_EF_LSHIFT | LGI_EF_RSHIFT)
#define LGI_EF_DOWN 0x00000040
#define LGI_EF_DOUBLE 0x00000080
#define LGI_EF_CAPS_LOCK 0x00000100
#define LGI_EF_IS_CHAR 0x00000200
#define LGI_EF_IS_NOT_CHAR 0x00000400
#define LGI_EF_SYSTEM 0x00000800 // Windows key/Apple key etc
// Mouse Event Flags
#define LGI_EF_LEFT 0x00001000
#define LGI_EF_MIDDLE 0x00002000
#define LGI_EF_RIGHT 0x00004000
#define LGI_EF_MOVE 0x00008000
// Emit compiler warnings
#define __STR2__(x) #x
#define __STR1__(x) __STR2__(x)
#define __LOC__ __FILE__ "("__STR1__(__LINE__)") : Warning: "
// To use just do #pragma message(__LOC__"My warning message")
// Simple definition of breakable unicode characters
#define LGI_BreakableChar(c) ( \
(c) == '\n' || \
(c) == ' ' || \
(c) == '\t' || \
( (c) >= 0x3040 && (c) <= 0x30FF ) || \
( (c) >= 0x3300 && (c) <= 0x9FAF ) \
)
// Os metrics
enum LgiSystemMetric
{
/// Get the standard window horizontal border size
/// \sa GApp::GetMetric()
LGI_MET_DECOR_X = 1,
/// Get the standard window vertical border size including caption bar.
/// \sa GApp::GetMetric()
LGI_MET_DECOR_Y,
/// Get the standard window vertical border size including caption bar.
/// \sa GApp::GetMetric()
LGI_MET_DECOR_CAPTION,
/// Get the height of a single line menu bar
/// \sa GApp::GetMetric()
LGI_MET_MENU,
/// This is non-zero if the system is theme aware
LGI_MET_THEME_AWARE
};
/// \brief Types of system paths available for querying
/// \sa LgiGetSystemPath
enum LgiSystemPath
{
/// The location of the operating system folder
/// [Win32] = e.g. C:\Windows
/// [Mac] = /System
/// [Linux] /boot
LSP_OS,
+
/// The system library folder
/// [Win32] = e.g. C:\Windows\System32
/// [Mac] = /Library
/// [Linux] = /usr/lib
LSP_OS_LIB,
+
/// A folder for storing temporary files. These files are usually
/// deleted automatically later by the system.
/// [Win32] = ~\Local Settings\Temp
/// [Mac] = ~/Library/Caches/TemporaryItems
/// [Linux] = /tmp
LSP_TEMP,
+
/// System wide application data
/// [Win32] = ~\..\All Users\Application Data
/// [Mac] = /System/Library
/// [Linux] = /usr
LSP_COMMON_APP_DATA,
+
/// User specific application data
/// [Win32] = ~\Application Data
/// [Mac] = ~/Library
/// [Linux] = /usr
LSP_USER_APP_DATA,
+
/// Machine + user specific application data (probably should not use)
/// [Win32] = ~\Local Settings\Application Data
/// [Mac] = ~/Library
/// [Linux] = /usr/local
LSP_LOCAL_APP_DATA,
+
/// Desktop dir
/// i.e. ~/Desktop
LSP_DESKTOP,
+
/// Home dir
/// i.e. ~
LSP_HOME,
+
+ /// Application install folder:
+ /// [Win] c:\Program Files
+ /// [Mac] /Applications
+ /// [Linux] /usr/bin
+ LSP_USER_APPS,
+
/// The running application's path.
/// [Mac] This doesn't include the "Contents/MacOS" part of the path inside the bundle.
LSP_EXE,
+
/// The system trash folder.
LSP_TRASH,
+
/// The app's install folder.
/// [Win32] = $ExePath (sans '\Release' or '\Debug')
/// [Mac/Linux] = $ExePath
/// Where $ExePath is the folder the application is running from
LSP_APP_INSTALL,
+
/// The app's root folder (Where config and data should be stored)
/// GOptionsFile uses LSP_APP_ROOT as the default location.
/// [Win32] = ~\Application Data\$AppName
/// [Mac] = ~/Library/$AppName
/// [Linux] = ~/.$AppName
/// Where $AppName = GApp::GetName.
/// If the given folder doesn't exist it will be created.
LSP_APP_ROOT,
+
/// This is the user's documents folder
/// [Win32] ~\My Documents
/// [Mac] ~\Documents
LSP_USER_DOCUMENTS,
+
/// This is the user's music folder
/// [Win32] ~\My Music
/// [Mac] ~\Music
LSP_USER_MUSIC,
+
/// This is the user's video folder
/// [Win32] ~\My Videos
/// [Mac] ~\Movies
LSP_USER_VIDEO,
+
/// This is the user's download folder
/// ~\Downloads
LSP_USER_DOWNLOADS,
};
// Deprecated method defines
#ifdef __GNUC__
#define DEPRECATED_PRE
#define DEPRECATED_POST __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED_PRE __declspec(deprecated)
#define DEPRECATED_POST
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED_PRE
#define DEPRECATED_POST
#endif
//
#ifdef _DEBUG
#define DeclDebugArgs , const char *_file, int _line
#define PassDebugArgs , __FILE__, __LINE__
#else
#define DeclDebugArgs
#define PassDebugArgs
#endif
#define _FL __FILE__, __LINE__
#define CALL_MEMBER_FN(obj, memFn) ((obj).*(memFn))
#include "GAutoPtr.h"
#endif
diff --git a/src/common/Lgi/Lgi.cpp b/src/common/Lgi/Lgi.cpp
--- a/src/common/Lgi/Lgi.cpp
+++ b/src/common/Lgi/Lgi.cpp
@@ -1,2172 +1,2196 @@
//
// Cross platform LGI functions
//
#include
#include
#include
#include
#ifdef _WINDOWS
#include
#include
#else
#include
#endif
#include "Lgi.h"
#include "GToken.h"
#include "GCapabilities.h"
#if defined(LINUX)
#include "LgiWinManGlue.h"
#elif defined(_WINDOWS)
#include "GRegKey.h"
#endif
#if defined POSIX
#include
#include
#include
#include
#include "GProcess.h"
#elif defined BEOS
#include
#endif
#if defined(WIN32) && defined(__GTK_H__)
#include "../win32/GSymLookup.h"
#else
#include "GSymLookup.h"
#endif
#include "GLibrary.h"
//////////////////////////////////////////////////////////////////////////
// Misc stuff
#if defined MAC && !defined COCOA
bool _get_path_FSRef(FSRef &fs, GStringPipe &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))
{
GAutoString u(LgiNewUtf16To8((char16*)Name.unicode, Name.length * sizeof(char16)));
// 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;
}
GAutoString FSRefPath(FSRef &fs)
{
GStringPipe a;
if (_get_path_FSRef(fs, a))
{
return GAutoString(a.NewStr());
}
return GAutoString();
}
#endif
bool LgiPostEvent(OsView Wnd, int Event, GMessage::Param a, GMessage::Param b)
{
#if WIN32NATIVE
return PostMessage(Wnd, Event, a, b);
#elif defined(__GTK_H__)
if (Wnd)
{
GMessage m(0);
m.Set(Event, a, b);
return m.Send(Wnd);
}
else
{
printf("%s:%i - Warning: LgiPostEvent failed because View=0\n", _FL);
}
#elif defined(BEOS)
if (Wnd)
{
BMessage Msg(Event);
Msg.AddInt32("a", a);
Msg.AddInt32("b", b);
BMessenger m(Wnd);
return m.SendMessage(&Msg) == B_OK;
}
#elif defined(MAC) && !defined COCOA
#if 0
int64 Now = LgiCurrentTime();
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", __FILE__, __LINE__, (int)e);
}
else
{
EventTargetRef t = GetControlEventTarget(Wnd);
e = SetEventParameter(Ev, kEventParamLgiEvent, typeUInt32, sizeof(Event), &Event);
if (e) printf("%s:%i - error %i\n", __FILE__, __LINE__, (int)e);
e = SetEventParameter(Ev, kEventParamLgiA, typeUInt32, sizeof(a), &a);
if (e) printf("%s:%i - error %i\n", __FILE__, __LINE__, (int)e);
e = SetEventParameter(Ev, kEventParamLgiB, typeUInt32, sizeof(b), &b);
if (e) printf("%s:%i - error %i\n", __FILE__, __LINE__, (int)e);
// printf("Sent event %x,%x,%x\n", Event, a, b);
bool Status = false;
#if 1
e = SetEventParameter(Ev, kEventParamPostTarget, typeEventTargetRef, sizeof(t), &t);
if (e) printf("%s:%i - error %i\n", __FILE__, __LINE__, (int)e);
e = PostEventToQueue(GetMainEventQueue(), Ev, kEventPriorityStandard);
if (e) printf("%s:%i - error %i\n", __FILE__, __LINE__, (int)e);
else Status = true;
#else
e = SendEventToEventTarget(Ev, GetControlEventTarget(Wnd));
if (e) printf("%s:%i - error %i\n", __FILE__, __LINE__, e);
else Status = true;
#endif
ReleaseEvent(Ev);
return Status;
}
#endif
return false;
}
void LgiExitApp()
{
exit(0);
}
//////////////////////////////////////////////////////////////////////////
#ifdef WIN32
bool RegisterActiveXControl(char *Dll)
{
GLibrary 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
LgiAssert(!"Not impl.");
#endif
}
return false;
}
#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 LgiGetOs
(
/// Returns the version of the OS or NULL if you don't care
GArray *Ver
)
{
#if defined(WIN32) || defined(WIN64)
static int Os = LGI_OS_UNKNOWN;
static int Version = 0, Revision = 0;
if (Os == LGI_OS_UNKNOWN)
{
OSVERSIONINFO v;
v.dwOSVersionInfoSize=sizeof(v);
GetVersionEx(&v);
Version = v.dwMajorVersion;
Revision = v.dwMinorVersion;
#ifdef WIN32
BOOL IsWow64 = FALSE;
IsWow64Process(GetCurrentProcess(), &IsWow64);
#endif
Os = (v.dwPlatformId == VER_PLATFORM_WIN32_NT)
?
#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);
}
return Os;
#elif defined BEOS
if (Ver)
{
Ver->Add(5);
Ver->Add(0);
}
return LGI_OS_BEOS;
#elif defined LINUX
if (Ver)
{
utsname Buf;
if (!uname(&Buf))
{
GToken t(Buf.release, ".");
for (int i=0; iAdd(atoi(t[i]));
}
}
}
return LGI_OS_LINUX;
#elif defined MAC && !defined COCOA
if (Ver)
{
SInt32 i;
if (Gestalt(gestaltSystemVersionMajor, &i) == noErr)
{
Ver->Add(i);
if (Gestalt(gestaltSystemVersionMinor, &i) == noErr)
{
Ver->Add(i);
if (Gestalt(gestaltSystemVersionBugFix, &i) == noErr)
{
Ver->Add(i);
}
}
}
else if (Gestalt(gestaltSystemVersion, &i) == noErr)
{
char s[10];
sprintf_s(s, sizeof(s), "%x", (int)i);
char *e = s + strlen(s) - 1;
char a[3] = { e[-1], 0 };
char b[3] = { e[0], 0 };
e[-1] = 0;
Ver->Add(atoi(s));
Ver->Add(htoi(a));
Ver->Add(htoi(b));
}
}
return LGI_OS_MAC_OS_X;
#else
return LGI_OS_UNKNOWN;
#endif
}
const char *LgiGetOsName()
{
const char *Str[LGI_OS_MAX] =
{
"Unknown",
"Win9x",
"Win32",
"Win64",
"Haiku",
"Linux",
"MacOSX",
};
return Str[LgiGetOs()];
}
#ifdef WIN32
#define RecursiveFileSearch_Wildcard "*.*"
#else // unix'ish OS
#define RecursiveFileSearch_Wildcard "*"
#endif
bool LgiRecursiveFileSearch(const char *Root,
GArray *Ext,
GArray *Files,
uint64 *Size,
uint64 *Count,
RecursiveFileSearch_Callback Callback,
void *UserData)
{
bool Status = false;
// validate args
if (!Root) return 0;
// get directory enumerator
GDirectory Dir;
Status = true;
// enumerate the directory contents
for (bool Found = Dir.First(Root); Found; Found = Dir.Next())
{
char Name[256];
if (!Dir.Path(Name, sizeof(Name)))
continue;
if (Callback)
{
if (!Callback(UserData, Name, &Dir))
{
continue;
}
}
if (Dir.IsDir())
{
// dir
LgiRecursiveFileSearch( Name,
Ext,
Files,
Size,
Count,
Callback,
UserData);
}
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
void LgiTrace(const char *Msg, ...)
{
#if defined _INC_MALLOC && WIN32NATIVE
if (_heapchk() != _HEAPOK)
{
return;
}
#endif
if (Msg)
{
#ifdef WIN32
static GMutex Sem;
Sem.Lock(_FL);
#endif
char Buffer[2049] = "";
#ifdef LGI_TRACE_TO_FILE
GFile f;
static char LogPath[MAX_PATH] = "";
if (LogPath[0] == 0)
{
if (LgiGetExeFile(LogPath, sizeof(LogPath)))
{
#ifdef MAC
char *Dir = strrchr(LogPath, DIR_CHAR);
if (Dir)
{
char Part[256];
strcpy_s(Part, sizeof(Part), Dir+1);
LogPath[0] = 0;
LgiMakePath(LogPath, sizeof(LogPath), LogPath, "~/Library/Logs");
LgiMakePath(LogPath, sizeof(LogPath), LogPath, Dir+1);
strcat_s(LogPath, sizeof(LogPath), ".txt");
}
else
#endif
{
char *Dot = strrchr(LogPath, '.');
if (Dot && !strchr(Dot, DIR_CHAR))
strcpy(Dot+1, "txt");
else
strcat(LogPath, ".txt");
}
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);
LgiGetSystemPath(LSP_APP_ROOT, LogPath, sizeof(LogPath));
if (!DirExists(LogPath))
FileDev->CreateFolder(LogPath);
LgiMakePath(LogPath, sizeof(LogPath), LogPath, Leaf);
}
else goto OnError;
}
}
else
{
// Well what to do now? I give up
OnError:
strcpy_s(LogPath, sizeof(LogPath), "trace.txt");
}
}
#endif
va_list Arg;
va_start(Arg, Msg);
_vsnprintf(Buffer, sizeof(Buffer)-1, Msg, Arg);
va_end(Arg);
#ifdef LGI_TRACE_TO_FILE
if (f.Open(LogPath, O_WRITE))
{
f.Seek(0, SEEK_END);
f.Write(Buffer, strlen(Buffer));
f.Close();
}
#endif
#if defined WIN32
OutputDebugString(Buffer);
Sem.Unlock();
#else
printf("%s", Buffer);
#endif
}
}
#ifndef LGI_STATIC
#define STACK_SIZE 12
void LgiStackTrace(const char *Msg, ...)
{
GSymLookup::Addr Stack[STACK_SIZE];
ZeroObj(Stack);
GSymLookup *Lu = LgiApp->GetSymLookup();
int Frames = Lu ? Lu->BackTrace(0, 0, Stack, STACK_SIZE) : 0;
if (Msg)
{
char Buffer[2049] = "";
#ifdef LGI_TRACE_TO_FILE
GFile f;
if (LgiGetExeFile(Buffer, sizeof(Buffer)))
{
char *Dot = strrchr(Buffer, '.');
if (Dot && !strchr(Dot, DIR_CHAR))
{
strcpy(Dot+1, "txt");
}
else
{
strcat(Buffer, ".txt");
}
f.Open(Buffer, O_WRITE);
}
#endif
va_list Arg;
va_start(Arg, Msg);
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, strlen(Buffer));
f.Close();
}
#endif
#if defined WIN32
OutputDebugString(Buffer);
#else
printf("Trace: %s", Buffer);
#endif
}
}
#endif
bool LgiTrimDir(char *Path)
{
if (Path)
{
char *p = strrchr(Path, DIR_CHAR);
if (p)
{
*p = 0;
return true;
}
}
return false;
}
GAutoString LgiMakeRelativePath(const char *Base, const char *Path)
{
GStringPipe Status;
if (Base && Path)
{
#ifdef WIN32
bool SameNs = strnicmp(Base, Path, 3) == 0;
#else
bool SameNs = true;
#endif
if (SameNs)
{
GToken b(Base + 1, ":" DIR_STR);
GToken p(Path + 1, ":" DIR_STR);
int Same = 0;
while (b[Same] && p[Same] && 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 GAutoString(Status.NewStr());
}
bool LgiIsRelativePath(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 LgiMakePath(char *Str, int StrSize, const char *Path, const char *File)
{
LgiAssert(Str != 0 &&
StrSize > 0 &&
Path != 0 &&
File != 0);
if (StrSize <= 4)
{
printf("%s:%i - LgiMakeFile buf size=%i?\n", _FL, StrSize);
}
if (Str && Path && File)
{
if (Str != Path)
{
strcpy_s(Str, StrSize, Path);
}
char Dir[] = { '/', '\\', 0 };
#define EndStr() Str[strlen(Str)-1]
#define EndDir() if (!strchr(Dir, EndStr())) strcat(Str, DIR_STR);
int Len = strlen(Str);
char *End = Str + (Len ? Len - 1 : 0);
if (strchr(Dir, *End) && End > Str)
{
*End = 0;
}
GToken T(File, Dir);
for (int i=0; i= StrSize - 1)
return false;
Str[Len++] = DIR_CHAR;
Str[Len] = 0;
}
int SegLen = strlen(T[i]);
if (Len + SegLen + 1 > StrSize)
{
return false;
}
strcpy(Str + Len, T[i]);
}
}
}
return true;
}
bool LgiGetTempPath(char *Dst, int DstSize)
{
return LgiGetSystemPath(LSP_TEMP, Dst, DstSize);
}
bool LgiGetSystemPath(LgiSystemPath Which, char *Dst, int DstSize)
{
bool Status = false;
#if defined(WIN32)
#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 (Dst)
{
#ifdef LINUX
// Ask our window manager add-on if it knows the path
GLibrary *WmLib = LgiApp ? LgiApp->GetWindowManagerLib() : NULL;
if (WmLib)
{
Proc_LgiWmGetPath WmGetPath = (Proc_LgiWmGetPath) WmLib->GetAddress("LgiWmGetPath");
if (WmGetPath && WmGetPath(Which, Dst, DstSize))
{
return true;
}
}
#endif
switch (Which)
{
case LSP_USER_DOWNLOADS:
{
#if 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
GLibrary 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))
{
GAutoString u8(LgiNewUtf16To8(ptr));
if (u8)
{
strcpy_s(Dst, DstSize, u8);
Status = true;
}
CoTaskMemFree(ptr);
}
}
if (!Status)
{
GRegKey k(false, "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
char *p = k.GetStr("{374DE290-123F-4565-9164-39C4925E467B}");
if (DirExists(p))
{
strcpy_s(Dst, DstSize, p);
Status = true;
}
}
if (!Status)
{
GAutoString MyDoc(GetWindowsFolder(CSIDL_MYDOCUMENTS));
if (MyDoc)
{
LgiMakePath(Dst, DstSize, MyDoc, "Downloads");
Status = DirExists(Dst);
}
}
if (!Status)
{
GAutoString MyDoc(GetWindowsFolder(CSIDL_PROFILE));
if (MyDoc)
{
LgiMakePath(Dst, DstSize, MyDoc, "Downloads");
Status = DirExists(Dst);
}
}
#else
LgiAssert(!"Not implemented");
#endif
break;
}
case LSP_USER_DOCUMENTS:
{
#if defined(WIN32) && defined(_MSC_VER)
GAutoString f(GetWindowsFolder(CSIDL_PERSONAL));
if (f)
{
strcpy_s(Dst, DstSize, f);
Status = true;
}
#else
LgiAssert(!"Not implemented");
#endif
break;
}
case LSP_USER_MUSIC:
{
#if defined WIN32
GAutoString f(GetWindowsFolder(CSIDL_MYMUSIC));
if (f)
{
strcpy_s(Dst, DstSize, f);
Status = true;
}
#elif defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kMusicDocumentsFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
else
{
GAutoString a = FSRefPath(Ref);
if (a)
{
strcpy_s(Dst, DstSize, a);
return true;
}
}
#else
LgiAssert(!"Not implemented");
#endif
break;
}
case LSP_USER_VIDEO:
{
#if defined WIN32
GAutoString f(GetWindowsFolder(CSIDL_MYVIDEO));
if (f)
{
strcpy_s(Dst, DstSize, f);
Status = true;
}
#elif defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kMovieDocumentsFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
else
{
GAutoString a = FSRefPath(Ref);
if (a)
{
strcpy_s(Dst, DstSize, a);
return true;
}
}
#else
LgiAssert(!"Not implemented");
#endif
break;
}
+ case LSP_USER_APPS:
+ {
+ #if defined WINDOWS
+ GAutoString f(GetWindowsFolder(
+ #ifdef WIN64
+ CSIDL_PROGRAM_FILES
+ #else
+ CSIDL_PROGRAM_FILESX86
+ #endif
+ ));
+ if (!f) return false;
+ strcpy_s(Dst, DstSize, f);
+ Status = true;
+ #elif defined MAC
+ strcpy_s(Dst, DstSize, "/Applications");
+ Status = true;
+ #elif defined LINUX
+ strcpy_s(Dst, DstSize, "/usr/bin");
+ Status = true;
+ #elif defined BEOS
+ LgiAssert(!"Impl me.");
+ #endif
+ break;
+ }
case LSP_APP_INSTALL:
{
if (LgiGetExePath(Dst, DstSize))
{
#if defined WIN32
char *Last = strrchr(Dst, DIR_CHAR);
if (Last)
{
if (stristr(Last,
#ifdef _DEBUG
"Debug"
#else
"Release"
#endif
))
*Last = 0;
}
#elif defined MAC
char *Last = strrchr(Dst, DIR_CHAR);
if (Last)
{
if (!stricmp(Last,
#ifdef _DEBUG
"/Debug"
#else
"/Release"
#endif
))
*Last = 0;
}
if ((Last = strrchr(Dst, DIR_CHAR)))
{
if (!stricmp(Last, "/build"))
*Last = 0;
}
#endif
return true;
}
break;
}
case LSP_APP_ROOT:
{
#ifndef LGI_STATIC
if (!LgiApp)
{
LgiAssert(0);
break;
}
char *Name = LgiApp->Name();
if (!Name)
{
LgiAssert(0);
break;
}
GAutoString Base;
#if defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kDomainLibraryFolderType, kDontCreateFolder, &Ref);
if (e)
{
printf("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
LgiAssert(0);
}
else
{
Base = FSRefPath(Ref);
}
#elif defined WIN32
Base.Reset(GetWindowsFolder(CSIDL_APPDATA));
#elif defined LINUX
char Dot[128];
snprintf(Dot, sizeof(Dot), ".%s", Name);
Name = Dot;
struct passwd *pw = getpwuid(getuid());
if (pw)
{
Base.Reset(NewStr(pw->pw_dir));
}
else LgiAssert(0);
#else
LgiAssert(0);
#endif
if (Base)
{
LgiMakePath(Dst, DstSize, Base, Name);
Status = true;
}
else
#endif
{
LgiAssert(0);
}
break;
}
case LSP_OS:
{
#if defined WIN32
char p[MAX_PATH];
if (GetWindowsDirectory(p, sizeof(p)) > 0)
{
strcpy_s(Dst, DstSize, p);
Status = true;
}
#elif defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kOnAppropriateDisk, kSystemFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", __FILE__, __LINE__, e);
else
{
GAutoString u = FSRefPath(Ref);
if (u)
{
strcpy_s(Dst, DstSize, u);
Status = true;
}
}
#else
strcpy_s(Dst, DstSize, "/boot"); // it'll do for now...
Status = true;
#endif
break;
}
case LSP_OS_LIB:
{
#if defined WIN32
char p[MAX_PATH];
if (GetSystemDirectory(p, sizeof(p)) > 0)
{
strcpy_s(Dst, DstSize, p);
Status = true;
}
#elif defined MAC
strcpy_s(Dst, DstSize, "/Library");
Status = true;
#else
strcpy_s(Dst, DstSize, "/lib"); // it'll do for now...
Status = true;
#endif
break;
}
case LSP_TEMP:
{
#if defined WIN32
if (LgiGetOs() == LGI_OS_WIN9X)
{
char t[256];
if (GetTempPath(sizeof(t), t) > 0)
{
char *utf = LgiToNativeCp(t);
if (utf)
{
strcpy_s(Dst, DstSize, utf);
DeleteArray(utf);
Status = true;
}
}
}
else
{
char16 t[256];
if (GetTempPathW(CountOf(t), t) > 0)
{
char *utf = LgiNewUtf16To8(t);
if (utf)
{
strcpy_s(Dst, DstSize, utf);
DeleteArray(utf);
Status = true;
}
}
}
#elif defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kTemporaryFolderType, kCreateFolder, &Ref);
if (e) LgiTrace("%s:%i - FSFindFolder failed e=%i\n", _FL, e);
else
{
GAutoString u = FSRefPath(Ref);
if (u)
{
strcpy_s(Dst, DstSize, u);
Status = true;
}
else LgiTrace("%s:%i - FSRefPath failed.\n", _FL);
}
#else
strcpy_s(Dst, DstSize, "/tmp"); // it'll do for now...
Status = true;
#endif
break;
}
case LSP_COMMON_APP_DATA:
{
#if defined WIN32
GAutoString f(GetWindowsFolder(CSIDL_COMMON_APPDATA));
if (f)
{
strcpy_s(Dst, DstSize, f);
Status = true;
}
#elif defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kOnSystemDisk, kDomainLibraryFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", __FILE__, __LINE__, e);
else
{
GAutoString u = FSRefPath(Ref);
if (u)
{
strcpy_s(Dst, DstSize, u);
Status = true;
}
}
#elif defined LINUX
strcpy_s(Dst, DstSize, "/usr");
Status = true;
#elif defined BEOS
strcpy_s(Dst, DstSize, "/boot/apps");
Status = true;
#endif
break;
}
case LSP_USER_APP_DATA:
{
#if defined WIN32
GAutoString f(GetWindowsFolder(CSIDL_APPDATA));
if (f)
{
strcpy_s(Dst, DstSize, f);
Status = true;
}
#elif defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kDomainLibraryFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", __FILE__, __LINE__, e);
else
{
GAutoString u = FSRefPath(Ref);
if (u)
{
strcpy_s(Dst, DstSize, u);
Status = true;
}
}
#elif defined LINUX
strcpy_s(Dst, DstSize, "/usr");
Status = true;
#endif
break;
}
case LSP_LOCAL_APP_DATA:
{
#if defined WIN32
GAutoString f(GetWindowsFolder(CSIDL_LOCAL_APPDATA));
if (f)
{
strcpy_s(Dst, DstSize, f);
Status = true;
}
#else
LgiAssert(!"Impl me.");
#endif
break;
}
case LSP_DESKTOP:
{
#if defined(_WINDOWS) && defined(_MSC_VER)
GAutoString f(GetWindowsFolder(CSIDL_DESKTOPDIRECTORY));
if (f)
{
strcpy_s(Dst, DstSize, f);
Status = true;
}
#elif defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kOnAppropriateDisk, kDesktopFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", __FILE__, __LINE__, e);
else
{
GAutoString u = FSRefPath(Ref);
if (u)
{
strcpy_s(Dst, DstSize, u);
Status = true;
}
}
#elif defined POSIX
struct passwd *pw = getpwuid(getuid());
if (pw)
{
#ifdef LINUX
WindowManager wm = LgiGetWindowManager();
if (wm == WM_Gnome)
sprintf_s(Dst, sizeof(Dst), "%s/.gnome-desktop", pw->pw_dir);
else
#endif
sprintf_s(Dst, sizeof(Dst), "%s/Desktop", pw->pw_dir);
Status = true;
}
#elif defined BEOS
strcpy_s(Dst, DstSize, "/boot/home/Desktop");
Status = true;
#endif
break;
}
case LSP_HOME:
{
#if defined WIN32
#ifndef CSIDL_PROFILE
#define CSIDL_PROFILE 0x0028
#endif
GAutoString f(GetWindowsFolder(CSIDL_PROFILE));
if (f)
{
strcpy_s(Dst, DstSize, f);
Status = true;
}
#elif defined POSIX
struct passwd *pw = getpwuid(getuid());
if (pw)
{
strcpy_s(Dst, DstSize, pw->pw_dir);
Status = true;
}
#elif defined BEOS
strcpy_s(Dst, DstSize, "/boot/home");
Status = true;
#endif
break;
}
case LSP_EXE:
{
if (LgiGetExeFile(Dst, DstSize))
{
LgiTrimDir(Dst);
Status = true;
}
break;
}
case LSP_TRASH:
{
#if defined LINUX
switch (LgiGetWindowManager())
{
case WM_Kde:
{
static char KdeTrash[256] = "";
if (!ValidStr(KdeTrash))
{
// Ask KDE where the current trash is...
GProcess p;
GStringPipe o;
if (p.Run("kde-config", "--userpath trash", 0, true, 0, &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", __FILE__, __LINE__);
}
}
else
{
printf("%s:%i - Run 'kde-config' failed.\n", __FILE__, __LINE__);
}
}
if (ValidStr(KdeTrash))
{
strcpy_s(Dst, DstSize, KdeTrash);
Status = true;
}
break;
}
default:
{
printf("%s:%i - Unknown window manager.\n", __FILE__, __LINE__);
break;
}
}
#elif defined MAC && !defined COCOA
FSRef Ref;
OSErr e = FSFindFolder(kUserDomain, kTrashFolderType, kDontCreateFolder, &Ref);
if (e) printf("%s:%i - FSFindFolder failed e=%i\n", __FILE__, __LINE__, e);
else
{
GAutoString u = FSRefPath(Ref);
if (u)
{
strcpy_s(Dst, DstSize, u);
Status = true;
}
}
#elif defined WIN32
// This should work but doesn't... *shrug*
// char *f = GetWin32Folder(CSIDL_BITBUCKET);
#else
#endif
break;
}
}
}
return Status;
}
bool LgiGetExeFile(char *Dst, int DstSize)
{
if (Dst)
{
#if defined WIN32
if (LgiGetOs() == LGI_OS_WIN9X)
{
char Exe[256];
if (GetModuleFileName(NULL, Exe, sizeof(Exe)) > 0)
{
char *e = LgiFromNativeCp(Exe);
if (e)
{
strlwr(e);
strcpy_s(Dst, DstSize, e);
DeleteArray(e);
return true;
}
else
{
LgiMsg(0, "LgiFromNativeCp returned 0, ANSI CodePage=%i (%s)", "LgiGetExeFile Error", MB_OK, GetACP(), LgiAnsiToLgiCp());
}
}
char m[256];
sprintf_s(m, sizeof(m), "GetModuleFileName failed err: %08.8X", GetLastError());
MessageBox(0, m, "LgiGetExeFile Error", MB_OK);
LgiExitApp();
}
else
{
char16 Exe[256];
if (GetModuleFileNameW(NULL, Exe, sizeof(Exe)) > 0)
{
char *e = LgiNewUtf16To8(Exe);
if (e)
{
strcpy_s(Dst, DstSize, e);
DeleteArray(e);
return true;
}
}
}
#elif defined BEOS
app_info Info;
if (LgiApp->GetAppInfo(&Info) == B_OK)
{
BEntry e(&Info.ref);
BPath p;
if (e.GetPath(&p) == B_OK)
{
strcpy_s(Dst, DstSize, p.Path());
return true;
}
}
#elif defined ATHEOS
os::Directory AppPath;
if (AppPath.SetTo("^/.") == 0)
{
std::string p;
if (AppPath.GetPath(&p) == 0)
{
sprintf_s(Dst, DstSize, "%s%s%s", p.c_str(), DIR_STR, LgiApp->_AppFile);
return true;
}
}
#elif defined LINUX
static char ExePathCache[256] = "";
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 = FileExists(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());
GStringPipe Ps;
GProcess p;
if (p.Run("ps", 0, 0, true, 0, &Ps))
{
char *PsOutput = Ps.NewStr();
if (PsOutput)
{
GToken n(PsOutput, "\r\n");
for (int i=0; !Status && i 7)
{
int LinePid = 0;
for (int i=0; i Ext;
GArray Files;
Ext.Add((char*)Name);
#if DEBUG_FIND_FILE
printf("%s:%i - Exe='%s'\n", __FILE__, __LINE__, Exe);
#endif
if (LgiRecursiveFileSearch(Exe, &Ext, &Files) &&
Files.Length())
{
Result = Files[0];
Files.DeleteAt(0);
}
Files.DeleteArrays();
}
return Result;
}
#if defined WIN32
static LARGE_INTEGER Freq = {0};
static bool CurTimeInit = false;
#endif
uint64 LgiCurrentTime()
{
#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 BEOS
return system_time() / 1000;
#elif defined MAC && !defined COCOA
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 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 BEOS
LgiAssert(!"Not impl.");
return 0;
#elif defined MAC && !defined COCOA
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 LgiIsReleaseBuild()
{
#ifdef _DEBUG
return 0;
#else
return 1;
#endif
}
void LgiFormatSize(char *Str, int SLen, uint64 Size)
{
int64 K = 1024;
int64 M = K * K;
int64 G = K * M;
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)(int64)Size;
sprintf_s(Str, SLen, "%.2f K", d / K);
}
else if (Size < M)
{
sprintf_s(Str, SLen, "%u K", (int) (Size / K));
}
else if (Size < G)
{
double d = (double)(int64)Size;
sprintf_s(Str, SLen, "%.2f M", d / M);
}
else
{
double d = (double)(int64)Size;
sprintf_s(Str, SLen, "%.2f G", d / G);
}
}
char *LgiTokStr(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;
}
//////////////////////////////////////////////////////////////////////////////
DoEvery::DoEvery(int p) // p = timeout in ms
{
Init(p);
}
void DoEvery::Init(int p) // p = timeout in ms
{
LastTime = LgiCurrentTime();
if (p > 0)
{
Period = p;
}
}
bool DoEvery::DoNow()
{
int64 Now = LgiCurrentTime();
if (LastTime + Period < Now)
{
LastTime = Now;
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////
#if 0
GViewFill::GViewFill(GColour c)
{
Type = Solid;
Col = c;
#ifdef WIN32
hBrush = NULL;
#endif
}
GViewFill::GViewFill(COLOUR c, int Bits)
{
Type = Solid;
Col.c32(CBit(32, c, Bits));
#ifdef WIN32
hBrush = NULL;
#endif
}
GViewFill::GViewFill(GSurface *dc, bool Copy)
{
Col.c32(0);
Type = Copy ? OwnBitmap : RefBitmap;
#ifndef LGI_STATIC
if (Copy)
pDC = new GMemDC(dc);
else
pDC = dc;
#endif
#ifdef WIN32
hBrush = NULL;
#endif
}
GViewFill::GViewFill(const GViewFill &f)
{
Col = f.GetFlat();
Type = f.Type;
if (Type == OwnBitmap)
{
#ifndef LGI_STATIC
pDC = new GMemDC(f.pDC);
#endif
}
else if (Type == RefBitmap)
{
pDC = f.pDC;
}
#ifdef WIN32
hBrush = NULL;
#endif
}
GViewFill::~GViewFill()
{
Empty();
}
void GViewFill::Empty()
{
if (Type == OwnBitmap)
DeleteObj(pDC);
Type = None;
pDC = 0;
Col.c32(0);
#ifdef WIN32
if (hBrush)
{
DeleteObject(hBrush);
hBrush = NULL;
}
#endif
}
void GViewFill::Fill(GSurface *pDC, GRect *r, GdcPt2 *Origin)
{
#ifndef LGI_STATIC
if (Type == Solid)
{
pDC->Colour(Col);
pDC->Rectangle(r);
}
else if (Type == OwnBitmap || Type == RefBitmap)
{
if (pDC)
{
GRect a;
if (!r)
{
a.ZOff(pDC->X()-1, pDC->Y()-1);
r = &a;
}
for (int y = Origin ? (Origin->y % pDC->Y()) - pDC->Y() : 0; y < r->Y(); y += pDC->Y())
{
for (int x = Origin ? (Origin->x % pDC->X()) - pDC->X() : 0; xX(); x += pDC->X())
{
pDC->Blt(r->x1 + x, r->y1 + y, pDC);
}
}
}
else
{
LgiAssert(0);
}
}
#endif
}
#ifdef WIN32
/*
HBRUSH GViewFill::GetBrush()
{
if (!hBrush)
{
LOGBRUSH LogBrush;
LogBrush.lbStyle = BS_SOLID;
LogBrush.lbColor = GetFlat().c24();
LogBrush.lbHatch = 0;
hBrush = CreateBrushIndirect(&LogBrush);
}
return hBrush;
}
*/
#endif
#endif
//////////////////////////////////////////////////////////////////////
bool GCapabilityClient::NeedsCapability(const char *Name, const char *Param)
{
for (int i=0; iNeedsCapability(Name, Param);
return Targets.Length() > 0;
}
GCapabilityClient::~GCapabilityClient()
{
for (int i=0; iClients.Delete(this);
}
void GCapabilityClient::Register(GCapabilityTarget *t)
{
if (t)
{
Targets.Add(t);
t->Clients.Add(this);
}
}
GCapabilityTarget::~GCapabilityTarget()
{
for (int i=0; iTargets.Delete(this);
}
/////////////////////////////////////////////////////////////////////
GProfile::GProfile(const char *Name)
{
MinMs = -1;
Add(Name);
}
GProfile::~GProfile()
{
Add("End");
if (MinMs > 0)
{
uint64 TotalMs = s.Last().Time - s[0].Time;
if (TotalMs < MinMs)
{
return;
}
}
for (int i=0; i
#include
#include
#include "GSkinEngine.h"
#include "GSymLookup.h"
#include "GDocView.h"
#include "GToken.h"
#include
HINSTANCE _lgi_app_instance = 0;
extern LPTOP_LEVEL_EXCEPTION_FILTER _PrevExceptionHandler;
OsAppArguments::OsAppArguments()
{
_Default();
}
OsAppArguments::OsAppArguments(int Args, char **Arg)
{
_Default();
Set(Args, Arg);
}
OsAppArguments &OsAppArguments::operator =(OsAppArguments &p)
{
hInstance = p.hInstance;
Pid = p.Pid;
nCmdShow = p.nCmdShow;
lpCmdLine = 0;
CmdLine.Reset(NewStrW(p.lpCmdLine));
lpCmdLine = CmdLine;
return *this;
}
void OsAppArguments::_Default()
{
hInstance = 0;
lpCmdLine = 0;
Pid = GetCurrentProcessId();
nCmdShow = SW_RESTORE;
}
void OsAppArguments::Set(int Args, char **Arg)
{
GStringPipe p;
for (int i=0; i Classes;
GSymLookup *SymLookup;
GAppPrivate()
{
LinuxWine = -1;
SymLookup = 0;
QuitReceived = false;
SkinLib = 0;
ThemeAware = true;
GuiThread = LgiGetCurrentThread();
}
~GAppPrivate()
{
DeleteObj(SkinLib);
DeleteObj(SymLookup);
}
};
/////////////////////////////////////////////////////////////////////////////
LONG __stdcall _ExceptionFilter_Redir(LPEXCEPTION_POINTERS e)
{
if (LgiApp)
return LgiApp->_ExceptionFilter(e, LgiApp->d->ProductId);
else
LgiTrace("_ExceptionFilter_Redir error: No application ptr.\n");
return 0;
}
/////////////////////////////////////////////////////////////////////////////
GSkinEngine *GApp::SkinEngine = 0;
GMouseHook *GApp::MouseHook = 0;
GMouseHook *GApp::GetMouseHook()
{
return MouseHook;
}
static GAutoString ParseStr(GPointer &p, bool Pad = true)
{
char16 *Key = p.w;
// Skip 'key' string
while (*p.w)
p.w++;
// Skip NULL
p.w++;
if (Pad)
{
// Align to 32-bit boundry
while ((NativeInt)p.u8 & 3)
p.u8++;
}
return GAutoString(LgiNewUtf16To8(Key));
}
static GAutoString ParseVer(void *Resource, char *Part)
{
GToken Parts(Part, ".");
if (Parts.Length() == 3)
{
GPointer p;
p.u8 = (uint8*)Resource;
uint16 Len = *p.u16++;
uint16 ValueLen = *p.u16++;
uint16 Type = *p.u16++;
GAutoString Key = ParseStr(p);
// Read VS_FIXEDFILEINFO structure
DWORD dwSig = *p.u32++;
DWORD dwStrucVersion = *p.u32++;
DWORD dwFileVersionMS = *p.u32++;
DWORD dwFileVersionLS = *p.u32++;
DWORD dwProductVersionMS = *p.u32++;
DWORD dwProductVersionLS = *p.u32++;
DWORD dwFileFlagsMask = *p.u32++;
DWORD dwFileFlags = *p.u32++;
DWORD dwFileOS = *p.u32++;
DWORD dwFileType = *p.u32++;
DWORD dwFileSubtype = *p.u32++;
DWORD dwFileDateMS = *p.u32++;
DWORD dwFileDateLS = *p.u32++;
// Align to 32-bit boundry
while ((NativeInt)p.u8 & 3)
p.u8++;
// Children
while (p.u8 < (uint8*)Resource + Len)
{
// Read StringFileInfo structures...
uint8 *fStart = p.u8;
uint16 fLength = *p.u16++;
uint16 fValueLength = *p.u16++;
uint16 fType = *p.u16++;
GAutoString fKey = ParseStr(p);
if (strcmp(fKey, "StringFileInfo"))
break;
while (p.u8 < fStart + fLength)
{
// Read StringTable entries
uint8 *tStart = p.u8;
uint16 tLength = *p.u16++;
uint16 tValueLength = *p.u16++;
uint16 tType = *p.u16++;
GAutoString tKey = ParseStr(p);
while (p.u8 < tStart + tLength)
{
// Read String entries
uint8 *sStart = p.u8;
uint16 sLength = *p.u16++;
uint16 sValueLength = *p.u16++;
uint16 sType = *p.u16++;
GAutoString sKey = ParseStr(p);
GAutoString sValue;
if (p.u8 < sStart + sLength)
sValue = ParseStr(p);
if (!stricmp(Parts[0], fKey) &&
!stricmp(Parts[1], tKey) &&
!stricmp(Parts[2], sKey))
{
return sValue;
}
}
}
}
}
return GAutoString();
}
/////////////////////////////////////////////////////////////////////////////
#include
#include
extern int MouseRollMsg;
typedef HRESULT (CALLBACK *fDllGetVersion)(DLLVERSIONINFO *);
bool GApp::Win9x = LgiGetOs() == LGI_OS_WIN9X;
GApp::GApp(OsAppArguments &AppArgs, const char *AppName, GAppArguments *ObjArgs)
{
// GApp instance
LgiAssert(TheApp == 0);
TheApp = this;
LgiAssert(AppName);
Name(AppName);
int64 Time = LgiCurrentTime();
#define DumpTime(str) /* \
{ int64 n = LgiCurrentTime(); \
LgiTrace("%s=%ims\n", str, (int)(n-Time)); \
Time = n; } */
// Sanity Checks
LgiAssert(sizeof(int8) == 1);
LgiAssert(sizeof(uint8) == 1);
LgiAssert(sizeof(int16) == 2);
LgiAssert(sizeof(uint16) == 2);
LgiAssert(sizeof(int32) == 4);
LgiAssert(sizeof(uint32) == 4);
LgiAssert(sizeof(int64) == 8);
LgiAssert(sizeof(uint64) == 8);
LgiAssert(sizeof(char16) == 2);
DumpTime("start");
// Private data
d = new GAppPrivate;
char Mime[256];
sprintf_s(Mime, sizeof(Mime), "application/x-%s", AppName);
d->Mime.Reset(NewStr(Mime));
DumpTime("priv");
// Setup exception handler
HRSRC hRsrc = ::FindResource(NULL, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
HGLOBAL hGlobal = ::LoadResource(NULL, hRsrc);
LPVOID pVersionResource = ::LockResource(hGlobal);
GAutoString ProductName, ProductVer;
// replace "040904e4" with the language ID of your resources
if (pVersionResource)
{
ProductName = ParseVer(pVersionResource, "StringFileInfo.0c0904b0.ProductName");
ProductVer = ParseVer(pVersionResource, "StringFileInfo.0c0904b0.ProductVersion");
}
if (ProductName && ProductVer)
{
char s[256];
sprintf_s(s, sizeof(s), "%s-%s", ProductName.Get(), ProductVer.Get());
d->ProductId.Reset(NewStr(s));
}
InitializeCriticalSection(&StackTraceSync);
#if !defined(_DEBUG)
_PrevExceptionHandler = SetUnhandledExceptionFilter(_ExceptionFilter_Redir);
#endif
DumpTime("exception handler");
// Initialize windows dll's
OleInitialize(NULL);
CoInitialize(NULL);
InitCommonControls();
{
/*
GLibrary ComCtl32("ComCtl32.dll");
DLLVERSIONINFO info;
ZeroObj(info);
info.cbSize = sizeof(info);
fDllGetVersion DllGetVersion = (fDllGetVersion)ComCtl32.GetAddress("DllGetVersion");
if (DllGetVersion)
{
HRESULT ret = DllGetVersion(&info);
d->ThemeAware = info.dwMajorVersion >= 6;
LgiTrace("ComCtl32.dll v%i.%i found (ret=%x)\n", info.dwMajorVersion, info.dwMinorVersion, ret);
)
*/
GArray Ver;
LgiGetOs(&Ver);
if (Ver.Length() > 1)
{
// LgiTrace("Windows v%i.%i\n", Ver[0], Ver[1]);
if (Ver[0] < 6)
{
d->ThemeAware = false;
}
}
#ifdef _MSC_VER
if (!d->ThemeAware)
{
SetThemeAppProperties(0);
}
#endif
}
DumpTime("init common ctrls");
// Setup LGI Sub-systems
GFontSystem::Inst();
DumpTime("font sys");
d->FileSystem = new GFileSystem;
DumpTime("file sys");
d->GdcSystem = new GdcDevice;
DumpTime("gdc");
// Vars...
d->Config = 0;
AppWnd = 0;
SetAppArgs(AppArgs);
DumpTime("vars");
// System font
SystemNormal = 0;
SystemBold = 0;
GFontType SysFontType;
if (SysFontType.GetSystemFont("System"))
{
SystemNormal = SysFontType.Create();
if (SystemNormal)
{
// Force load
SystemNormal->Create();
}
SystemBold = SysFontType.Create();
if (SystemBold)
{
SystemBold->Bold(true);
SystemBold->Create();
}
}
if (!SystemNormal)
{
LgiMsg(0, "Error: Couldn't create system font.", "Lgi Error");
LgiExitApp();
}
DumpTime("fonts");
// Other vars and init
hNormalCursor = LoadCursor(NULL, IDC_ARROW);
LgiRandomize(LgiCurrentTime()*LgiGetCurrentThread());
MouseRollMsg = RegisterWindowMessage("MSWHEEL_ROLLMSG");
DumpTime("cursor/rand/msg");
LgiInitColours();
DumpTime("colours");
// Setup mouse hook
MouseHook = new GMouseHook;
DumpTime("ms hook");
if
(
#if 0 // defined(LGI_STATIC) && _MSC_VER < 1600
0
#else
(
!ObjArgs
||
!ObjArgs->NoSkin
)
&&
!GetOption("noskin")
#endif
)
{
// Load library
char SkinLibName[] =
#ifdef __GNUC__
"lib"
#endif
"lgiskin"
#if _MSC_VER == 1300
"7"
#endif
#if _MSC_VER == 1400
"8"
#endif
#if _MSC_VER == 1500
"9"
#endif
#if _MSC_VER == 1600
"10"
#endif
#ifdef _DEBUG
"d"
#endif
;
#if HAS_SHARED_OBJECT_SKIN
d->SkinLib = new GLibrary(SkinLibName);
if (d->SkinLib)
{
if (d->SkinLib->IsLoaded())
{
Proc_CreateSkinEngine CreateSkinEngine =
(Proc_CreateSkinEngine)d->SkinLib->GetAddress(LgiSkinEntryPoint);
if (CreateSkinEngine)
{
SkinEngine = CreateSkinEngine(this);
}
}
else
{
DeleteObj(d->SkinLib);
printf("Failed to load '%s'\n", SkinLibName);
}
}
#else
extern GSkinEngine *CreateSkinEngine(GApp *App);
SkinEngine = CreateSkinEngine(this);
#endif
}
DumpTime("skin");
}
GApp::~GApp()
{
DeleteObj(AppWnd);
DeleteObj(SystemNormal);
DeleteObj(SystemBold);
DeleteObj(MouseHook);
TheApp = 0;
DeleteObj(SkinEngine);
DeleteObj(GFontSystem::Me);
DeleteObj(d->FileSystem);
DeleteObj(d->GdcSystem);
DeleteObj(d->Config);
d->Classes.DeleteObjects();
CoUninitialize();
OleUninitialize();
DeleteObj(d);
DeleteCriticalSection(&StackTraceSync);
}
bool GApp::IsOk()
{
bool Status = (this != 0) &&
(d != 0) &&
(d->FileSystem != 0) &&
(d->GdcSystem != 0);
if (!Status)
LgiAssert(!"Hash table error");
return Status;
}
int GApp::GetCpuCount()
{
SYSTEM_INFO si;
ZeroObj(si);
GetSystemInfo(&si);
return si.dwNumberOfProcessors;
}
OsThreadId GApp::GetGuiThread()
{
return d->GuiThread;
}
List *GApp::GetClasses()
{
return IsOk() ? &d->Classes : 0;
}
OsAppArguments *GApp::GetAppArgs()
{
return IsOk() ? &d->Args : 0;
}
GXmlTag *GApp::GetConfig(const char *Tag)
{
if (IsOk() && !d->Config)
{
const char File[] = "lgi.conf";
char Path[256];
if (LgiGetExePath(Path, sizeof(Path)))
{
if (Path[strlen(Path)-1] != DIR_CHAR) strcat(Path, DIR_STR);
strcat(Path, File);
if (FileExists(Path))
{
d->Config = new GXmlTag("Config");
if (d->Config)
{
GFile f;
if (f.Open(Path, O_READ))
{
GXmlTree t;
t.Read(d->Config, &f, 0);
}
}
}
}
if (!d->Config)
{
d->Config = new GXmlTag("Options");
}
}
if (Tag && d->Config)
{
return d->Config->GetTag(Tag);
}
return 0;
}
void GApp::SetConfig(GXmlTag *Tag)
{
if (IsOk() && Tag)
{
GXmlTag *Old = GetConfig(Tag->Tag);
if (Old)
{
Old->RemoveTag();
DeleteObj(Old);
}
if (!d->Config)
{
GetConfig(0);
}
if (d->Config)
{
d->Config->InsertTag(Tag);
}
}
}
char *GApp::GetArgumentAt(int n)
{
if (d->Args.lpCmdLine)
{
char16 *s = d->Args.lpCmdLine;
for (int i=0; i<=n; i++)
{
char16 *e = 0;
while (*s && strchr(WhiteSpace, *s)) s++;
if (*s == '\'' || *s == '\"')
{
char16 Delim = *s++;
e = StrchrW(s, Delim);
}
else
{
for (e = s; *e && !strchr(WhiteSpace, *e); e++)
;
}
if (i == n)
{
return LgiNewUtf16To8(s, (e - s) * sizeof(char16));
}
s = *e ? e + 1 : e;
}
}
return 0;
}
bool GApp::GetOption(const char *Option, GAutoString &Buf)
{
if (!ValidStr(Option))
{
return false;
}
char16 *c = d->Args.lpCmdLine;
char16 *Opt = LgiNewUtf8To16(Option);
int OptLen = StrlenW(Opt);
while (c && *c)
{
if (*c == '/' || *c == '-')
{
c++;
char16 *e = c;
while (*e && (IsAlpha(*e)) || StrchrW(L"_-", *e))
e++;
if (e - c == OptLen &&
!StrnicmpW(c, Opt, OptLen))
{
c += OptLen;
if (*c)
{
// skip leading whitespace
while (*c && strchr(WhiteSpace, *c))
{
c++;
}
// write str out if they want it
char16 End = (*c == '\'' || *c == '\"') ? *c++ : ' ';
char16 *e = StrchrW(c, End);
if (!e) e = c + StrlenW(c);
Buf.Reset(LgiNewUtf16To8(c, (NativeInt)e-(NativeInt)c));
}
// yeah we got the option
DeleteArray(Opt);
return true;
}
}
c = StrchrW(c, ' ');
if (c) c++;
}
DeleteArray(Opt);
return false;
}
bool GApp::GetOption(const char *Option, char *Dest, int DestLen)
{
GAutoString Buf;
if (GetOption(Option, Buf))
{
if (Dest)
strcpy_s(Dest, DestLen, &Buf[0]);
return true;
}
return false;
}
// #include "GInput.h"
void GApp::SetAppArgs(OsAppArguments &AppArgs)
{
d->Args = AppArgs;
}
void GApp::OnCommandLine()
{
char WhiteSpace[] = " \r\n\t";
char *CmdLine = LgiNewUtf16To8(d->Args.lpCmdLine);
if (ValidStr(CmdLine))
{
// LgiTrace("CmdLine='%s'\n", CmdLine);
GArray Files;
char *Delim = "\'\"";
char *s;
for (s = CmdLine; *s; )
{
// skip ws
while (*s && strchr(WhiteSpace, *s)) s++;
// read to end of token
char *e = s;
if (strchr(Delim, *s))
{
char Delim = *s++;
e = strchr(s, Delim);
if (!e)
e = s + strlen(s);
}
else
{
for (; *e && !strchr(WhiteSpace, *e); e++)
;
}
char *Arg = NewStr(s, e - s);
if (Arg)
{
if (FileExists(Arg))
{
Files.Add(Arg);
}
else
{
DeleteArray(Arg);
}
}
// next
s = (*e) ? e + 1 : e;
}
// call app
if (Files.Length() > 0)
{
OnReceiveFiles(Files);
}
// clear up
Files.DeleteArrays();
}
DeleteArray(CmdLine);
}
void GApp::OnUrl(const char *Url)
{
if (AppWnd)
AppWnd->OnUrl(Url);
}
void GApp::OnReceiveFiles(GArray &Files)
{
if (AppWnd)
AppWnd->OnReceiveFiles(Files);
}
int32 GApp::GetMetric(LgiSystemMetric Metric)
{
int32 Status = 0;
switch (Metric)
{
case LGI_MET_DECOR_X:
{
Status = GetSystemMetrics(SM_CXFRAME) * 2;
break;
}
case LGI_MET_DECOR_Y:
{
Status = GetSystemMetrics(SM_CYFRAME) * 2;
Status += GetSystemMetrics(SM_CYCAPTION);
break;
}
case LGI_MET_DECOR_CAPTION:
{
Status = GetSystemMetrics(SM_CYCAPTION);
break;
}
case LGI_MET_MENU:
{
Status = GetSystemMetrics(SM_CYMENU);
break;
}
case LGI_MET_THEME_AWARE:
{
Status = d->ThemeAware;
break;
}
}
return Status;
}
GViewI *GApp::GetFocus()
{
HWND h = ::GetFocus();
if (h)
{
return GWindowFromHandle(h);
}
return 0;
}
HINSTANCE GApp::GetInstance()
{
if (this && IsOk())
{
return d->Args.hInstance;
}
return (HINSTANCE)GetCurrentProcess();
}
OsProcessId GApp::GetProcessId()
{
if (this)
{
return IsOk() ? d->Args.Pid : 0;
}
return GetCurrentProcessId();
}
int GApp::GetShow()
{
return IsOk() ? d->Args.nCmdShow : 0;
}
class GWnd
{
public:
GMutex *GetLock(GWindow *w)
{
return w->_Lock;
}
};
bool GApp::Run(bool Loop, OnIdleProc IdleCallback, void *IdleParam)
{
MSG Msg;
bool status = true;
ZeroObj(Msg);
if (Loop)
{
OnCommandLine();
if (IdleCallback)
{
bool DontWait = true;
while (!d->QuitReceived)
{
while (1)
{
bool Status;
if (DontWait)
{
Status = PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE);
}
else
{
Status = GetMessage(&Msg, NULL, 0, 0) > 0;
DontWait = true;
}
#if 0
char m[256];
sprintf_s(m, sizeof(m), "Msg=%i hwnd=%p %i,%i\n", Msg.message, Msg.hwnd, Msg.wParam, Msg.lParam);
OutputDebugStringA(m);
#endif
if (!Status || Msg.message == WM_QUIT)
break;
#ifdef _DEBUG
int64 Last = LgiCurrentTime();
#endif
TranslateMessage(&Msg);
DispatchMessage(&Msg);
#ifdef _DEBUG
int64 Now = LgiCurrentTime();
if (Now - Last > 1000)
{
LgiTrace("%s:%i - Msg Loop Blocked: %i ms (Msg: 0x%.4x)\n",
_FL, (int) (Now - Last), Msg.message);
}
#endif
}
if (Msg.message == WM_QUIT)
{
d->QuitReceived = true;
}
else
{
DontWait = IdleCallback(IdleParam);
}
}
}
else
{
while (!d->QuitReceived && GetMessage(&Msg, NULL, 0, 0) > 0)
{
#ifdef _DEBUG
int64 Last = LgiCurrentTime();
#endif
TranslateMessage(&Msg);
DispatchMessage(&Msg);
#ifdef _DEBUG
int64 Now = LgiCurrentTime();
if (Now - Last > 1000)
{
LgiTrace("%s:%i - Msg Loop Blocked: %i ms (Msg: %i)\n",
__FILE__, __LINE__,
(int) (Now - Last), Msg.message);
}
#endif
}
}
}
else
{
while ( PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) &&
Msg.message != WM_QUIT)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
if (Msg.message == WM_QUIT)
{
d->QuitReceived = true;
}
}
return Msg.message != WM_QUIT;
}
void GApp::Exit(int Code)
{
if (Code)
{
exit(0);
}
else
{
PostQuitMessage(Code);
}
}
GAutoString GApp::GetFileMimeType(const char *File)
{
GAutoString r;
char m[128];
if (LgiGetFileMimeType(File, m, sizeof(m)))
r.Reset(NewStr(m));
return r;
}
bool GApp::GetAppsForMimeType(char *Mime, GArray &Apps)
{
LgiAssert(!"Not impl.");
return false;
}
GSymLookup *GApp::GetSymLookup()
{
if (!this)
return 0;
if (!d->SymLookup)
d->SymLookup = new GSymLookup;
return d->SymLookup;
}
bool GApp::IsWine()
{
if (d->LinuxWine < 0)
{
HMODULE hntdll = GetModuleHandle("ntdll.dll");
if (hntdll)
{
typedef const char * (CDECL *pwine_get_version)(void);
pwine_get_version wine_get_version = (pwine_get_version)GetProcAddress(hntdll, "wine_get_version");
d->LinuxWine = wine_get_version != 0;
}
}
return d->LinuxWine > 0;
}
+
+bool GApp::IsElevated()
+{
+ bool fRet = false;
+ HANDLE hToken = NULL;
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken ))
+ {
+ TOKEN_ELEVATION Elevation;
+ DWORD cbSize = sizeof(TOKEN_ELEVATION);
+ if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize))
+ fRet = Elevation.TokenIsElevated;
+ }
+ if (hToken)
+ CloseHandle(hToken);
+ return fRet;
+}
\ No newline at end of file