diff --git a/Ide/LgiIdeProj.xml b/Ide/LgiIdeProj.xml
--- a/Ide/LgiIdeProj.xml
+++ b/Ide/LgiIdeProj.xml
@@ -1,284 +1,280 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
+
.\win\Makefile.windows
./linux/Makefile.linux
./MacCocoa/LgiIde.xcodeproj
Makefile.haiku
./lgiide
./lgiide
LgiIde.exe
LgiIde.exe
WINDOWS
WINNATIVE
WINDOWS
WINNATIVE
POSIX
POSIX
LIBPNG_VERSION=\"1.2\"
LIBPNG_VERSION=\"1.2\"
MingW
/home/matthew/Code/Lgi/trunk/Ide/Code/IdeProjectSettings.cpp
./src
./resources
../include
./src
./resources
../include
..\include\lgi\win
..\include\lgi\win
../include/lgi/linux
../include/lgi/linux/Gtk
../../../../codelib/openssl/include
../include/lgi/linux
../include/lgi/linux/Gtk
../../../../codelib/openssl/include
../include/lgi/haiku
../include/lgi/haiku
../include/lgi/mac/cocoa
../include/lgi/mac/cocoa
imm32
imm32
magic
pthread
`pkg-config --libs gtk+-3.0`
-static-libgcc
magic
pthread
`pkg-config --libs gtk+-3.0`
-static-libgcc
-static-libgcc
gnu
network
be
-static-libgcc
gnu
network
be
-
- ..\x64Debug19
- ..\x64Release19
-
-
+
+
Executable
lgiide
lgiide
LgiIde.exe
LgiIde.exe
lgiide
lgiide
-
`pkg-config --cflags gtk+-3.0`
`pkg-config --cflags gtk+-3.0`
POSIX
_GNU_SOURCE
POSIX
_GNU_SOURCE
-
+
4
4
0
1
SOME_TEST=testing
-
+
diff --git a/Ide/linux/Makefile.linux b/Ide/linux/Makefile.linux
--- a/Ide/linux/Makefile.linux
+++ b/Ide/linux/Makefile.linux
@@ -1,422 +1,403 @@
#!/usr/bin/make
#
# This makefile generated by LgiIde
# http://www.memecode.com/lgi.php
#
-.SILENT :
+# .SILENT :
CC = gcc
CPP = g++
-Target = ./lgiide
+Target = ../lgiide
ifndef Build
Build = Debug
endif
BuildDir = $(Build)
+MakeDir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
Flags = -fPIC -w -fno-inline -fpermissive
ifeq ($(Build),Debug)
Flags += -g -std=c++14
Tag = d
Defs = -D_DEBUG -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX
Libs = \
- -L../Debug \
-lmagic \
-lpthread \
`pkg-config --libs gtk+-3.0` \
-static-libgcc \
-llgi-gtk3$(Tag) \
- -L../$(BuildDir)
+ -L../../$(BuildDir)
Inc = \
`pkg-config --cflags gtk+-3.0` \
- -I./src \
- -I./resources \
- -I../include/lgi/linux/Gtk \
- -I../include/lgi/linux \
- -I../include \
- -I../../../../codelib/openssl/include
+ -I$(MakeDir)/../src \
+ -I$(MakeDir)/../resources \
+ -I$(MakeDir)/../../include/lgi/linux/Gtk \
+ -I$(MakeDir)/../../include/lgi/linux \
+ -I$(MakeDir)/../../include \
+ -I$(MakeDir)/../../../../../codelib/openssl/include
else
Flags += -s -Os -std=c++14
Defs = -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX
Libs = \
- -L../Release \
-lmagic \
-lpthread \
`pkg-config --libs gtk+-3.0` \
-static-libgcc \
-llgi-gtk3$(Tag) \
-L../$(BuildDir)
Inc = \
`pkg-config --cflags gtk+-3.0` \
-I./src \
-I./resources \
-I../include/lgi/linux/Gtk \
-I../include/lgi/linux \
-I../include \
-I../../../../codelib/openssl/include
endif
# Dependencies
-Source = src/WebFldDlg.cpp \
- src/SysCharSupport.cpp \
- src/SpaceTabConv.cpp \
- src/SimpleCppParser.cpp \
- src/PythonParser.cpp \
- src/ProjectNode.cpp \
- src/NewProjectFromTemplate.cpp \
- src/MissingFiles.cpp \
- src/MemDumpViewer.cpp \
- src/LgiUtils.cpp \
- src/LgiIde.cpp \
- src/levenshtein.c \
- src/JavascriptParser.cpp \
- src/IdeProjectSettings.cpp \
- src/IdeProject.cpp \
- src/IdeDoc.cpp \
- src/IdeCommon.cpp \
- src/History.cpp \
- src/FtpThread.cpp \
- src/FindSymbol.cpp \
- src/FindInFiles.cpp \
- src/DocEditStyling.cpp \
- src/DocEdit.cpp \
- src/Debugger.cpp \
- src/DebugContext.cpp \
- src/AddFtpFile.cpp \
- ../src/common/Text/TextConvert.cpp \
- ../src/common/Text/HtmlParser.cpp \
- ../src/common/Text/HtmlCommon.cpp \
- ../src/common/Text/Html.cpp \
- ../src/common/Text/Homoglyphs/HomoglyphsTable.cpp \
- ../src/common/Text/Homoglyphs/Homoglyphs.cpp \
- ../src/common/Text/DocView.cpp \
- ../src/common/Net/OpenSSLSocket.cpp \
- ../src/common/Net/Http.cpp \
- ../src/common/Net/Ftp.cpp \
- ../src/common/Lgi/Mdi.cpp \
- ../src/common/Lgi/LgiMain.cpp \
- ../src/common/Lgi/About.cpp \
- ../src/common/Gdc2/Filters/Png.cpp \
- ../src/common/Coding/ParseCpp.cpp \
- ../src/common/Coding/LexCpp.cpp
+Source = ../src/WebFldDlg.cpp \
+ ../src/SysCharSupport.cpp \
+ ../src/SpaceTabConv.cpp \
+ ../src/SimpleCppParser.cpp \
+ ../src/PythonParser.cpp \
+ ../src/ProjectNode.cpp \
+ ../src/NewProjectFromTemplate.cpp \
+ ../src/MissingFiles.cpp \
+ ../src/MemDumpViewer.cpp \
+ ../src/LgiUtils.cpp \
+ ../src/LgiIde.cpp \
+ ../src/levenshtein.c \
+ ../src/JavascriptParser.cpp \
+ ../src/IdeProjectSettings.cpp \
+ ../src/IdeProject.cpp \
+ ../src/IdeDoc.cpp \
+ ../src/IdeCommon.cpp \
+ ../src/History.cpp \
+ ../src/FtpThread.cpp \
+ ../src/FindSymbol.cpp \
+ ../src/FindInFiles.cpp \
+ ../src/DocEditStyling.cpp \
+ ../src/DocEdit.cpp \
+ ../src/Debugger.cpp \
+ ../src/DebugContext.cpp \
+ ../src/AddFtpFile.cpp \
+ ../../src/common/Text/TextConvert.cpp \
+ ../../src/common/Text/HtmlParser.cpp \
+ ../../src/common/Text/HtmlCommon.cpp \
+ ../../src/common/Text/Html.cpp \
+ ../../src/common/Text/Homoglyphs/HomoglyphsTable.cpp \
+ ../../src/common/Text/Homoglyphs/Homoglyphs.cpp \
+ ../../src/common/Text/DocView.cpp \
+ ../../src/common/Net/OpenSSLSocket.cpp \
+ ../../src/common/Net/Http.cpp \
+ ../../src/common/Net/Ftp.cpp \
+ ../../src/common/Lgi/Mdi.cpp \
+ ../../src/common/Lgi/LgiMain.cpp \
+ ../../src/common/Lgi/About.cpp \
+ ../../src/common/Gdc2/Filters/Png.cpp \
+ ../../src/common/Coding/ParseCpp.cpp \
+ ../../src/common/Coding/LexCpp.cpp
SourceLst := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(Source)))
Objects := $(addprefix $(BuildDir)/,$(SourceLst))
Deps := $(patsubst %.o,%.d,$(Objects))
# Target
# Executable target
-$(Target) : ../$(BuildDir)/liblgi-gtk3$(Tag).so $(Objects)
+$(Target) : ../../$(BuildDir)/liblgi-gtk3$(Tag).so $(Objects)
mkdir -p $(BuildDir)
@echo Linking $(Target) [$(Build)]...
$(CPP) -Wl,-export-dynamic,-R. -o \
$(Target) $(Objects) $(Libs)
@echo Done.
-../$(BuildDir)/liblgi-gtk3$(Tag).so : ../include/lgi/common/App.h \
- ../include/lgi/common/Array.h \
- ../include/lgi/common/AutoPtr.h \
- ../include/lgi/common/Base64.h \
- ../include/lgi/common/Bitmap.h \
- ../include/lgi/common/Box.h \
- ../include/lgi/common/Button.h \
- ../include/lgi/common/CairoSurface.h \
- ../include/lgi/common/Cancel.h \
- ../include/lgi/common/Capabilities.h \
- ../include/lgi/common/Charset.h \
- ../include/lgi/common/CheckBox.h \
- ../include/lgi/common/ClipBoard.h \
- ../include/lgi/common/Colour.h \
- ../include/lgi/common/ColourSpace.h \
- ../include/lgi/common/Com.h \
- ../include/lgi/common/Combo.h \
- ../include/lgi/common/Containers.h \
- ../include/lgi/common/Core.h \
- ../include/lgi/common/Css.h \
- ../include/lgi/common/CssTools.h \
- ../include/lgi/common/CurrentTime.h \
- ../include/lgi/common/DataDlg.h \
- ../include/lgi/common/DateTime.h \
- ../include/lgi/common/Dialog.h \
- ../include/lgi/common/DisplayString.h \
- ../include/lgi/common/DocView.h \
- ../include/lgi/common/Dom.h \
- ../include/lgi/common/DomFields.h \
- ../include/lgi/common/DragAndDrop.h \
- ../include/lgi/common/DropFiles.h \
- ../include/lgi/common/Edit.h \
- ../include/lgi/common/Error.h \
- ../include/lgi/common/EventTargetThread.h \
- ../include/lgi/common/File.h \
- ../include/lgi/common/FileSelect.h \
- ../include/lgi/common/Filter.h \
- ../include/lgi/common/FindReplaceDlg.h \
- ../include/lgi/common/Font.h \
- ../include/lgi/common/FontCache.h \
- ../include/lgi/common/FontSelect.h \
- ../include/lgi/common/Gdc2.h \
- ../include/lgi/common/GdcTools.h \
- ../include/lgi/common/GdiLeak.h \
- ../include/lgi/common/HashTable.h \
- ../include/lgi/common/ImageList.h \
- ../include/lgi/common/Input.h \
- ../include/lgi/common/ItemContainer.h \
- ../include/lgi/common/Json.h \
- ../include/lgi/common/Layout.h \
- ../include/lgi/common/Lgi.h \
- ../include/lgi/common/LgiClasses.h \
- ../include/lgi/common/LgiCommon.h \
- ../include/lgi/common/LgiDefs.h \
- ../include/lgi/common/LgiInc.h \
- ../include/lgi/common/LgiInterfaces.h \
- ../include/lgi/common/LgiMsgs.h \
- ../include/lgi/common/LgiNetInc.h \
- ../include/lgi/common/LgiRes.h \
- ../include/lgi/common/LgiString.h \
- ../include/lgi/common/LgiUiBase.h \
- ../include/lgi/common/Library.h \
- ../include/lgi/common/LibraryUtils.h \
- ../include/lgi/common/List.h \
- ../include/lgi/common/ListItemCheckBox.h \
- ../include/lgi/common/ListItemRadioBtn.h \
- ../include/lgi/common/LMallocArray.h \
- ../include/lgi/common/Mail.h \
- ../include/lgi/common/Matrix.h \
- ../include/lgi/common/Mem.h \
- ../include/lgi/common/Menu.h \
- ../include/lgi/common/Message.h \
- ../include/lgi/common/Mime.h \
- ../include/lgi/common/Mru.h \
- ../include/lgi/common/Mutex.h \
- ../include/lgi/common/Net.h \
- ../include/lgi/common/NetTools.h \
- ../include/lgi/common/Notifications.h \
- ../include/lgi/common/OAuth2.h \
- ../include/lgi/common/OptionsFile.h \
- ../include/lgi/common/Palette.h \
- ../include/lgi/common/Panel.h \
- ../include/lgi/common/Password.h \
- ../include/lgi/common/Path.h \
- ../include/lgi/common/PixelRops.h \
- ../include/lgi/common/Point.h \
- ../include/lgi/common/Popup.h \
- ../include/lgi/common/PopupList.h \
- ../include/lgi/common/PopupNotification.h \
- ../include/lgi/common/Printer.h \
- ../include/lgi/common/Profile.h \
- ../include/lgi/common/Progress.h \
- ../include/lgi/common/ProgressDlg.h \
- ../include/lgi/common/ProgressView.h \
- ../include/lgi/common/Properties.h \
- ../include/lgi/common/RadioGroup.h \
- ../include/lgi/common/Range.h \
- ../include/lgi/common/Rect.h \
- ../include/lgi/common/RectF.h \
- ../include/lgi/common/RefCount.h \
- ../include/lgi/common/RegKey.h \
- ../include/lgi/common/Res.h \
- ../include/lgi/common/Rops.h \
- ../include/lgi/common/ScrollBar.h \
- ../include/lgi/common/SkinEngine.h \
- ../include/lgi/common/Slider.h \
- ../include/lgi/common/Splitter.h \
- ../include/lgi/common/StatusBar.h \
- ../include/lgi/common/Store3Defs.h \
- ../include/lgi/common/Stream.h \
- ../include/lgi/common/StringClass.h \
- ../include/lgi/common/StringLayout.h \
- ../include/lgi/common/StructuredIo.h \
- ../include/lgi/common/StructuredLog.h \
- ../include/lgi/common/SubProcess.h \
- ../include/lgi/common/TableLayout.h \
- ../include/lgi/common/TabView.h \
- ../include/lgi/common/TextFile.h \
- ../include/lgi/common/TextLabel.h \
- ../include/lgi/common/TextLog.h \
- ../include/lgi/common/TextView3.h \
- ../include/lgi/common/Thread.h \
- ../include/lgi/common/ThreadEvent.h \
- ../include/lgi/common/Token.h \
- ../include/lgi/common/ToolBar.h \
- ../include/lgi/common/ToolTip.h \
- ../include/lgi/common/TrayIcon.h \
- ../include/lgi/common/Tree.h \
- ../include/lgi/common/Undo.h \
- ../include/lgi/common/Unicode.h \
- ../include/lgi/common/UnicodeString.h \
- ../include/lgi/common/UnrolledList.h \
- ../include/lgi/common/Variant.h \
- ../include/lgi/common/View.h \
- ../include/lgi/common/Widgets.h \
- ../include/lgi/common/Window.h \
- ../include/lgi/common/XmlTree.h \
- ../include/lgi/linux/Gtk/LgiOsClasses.h \
- ../include/lgi/linux/Gtk/LgiOsDefs.h \
- ../include/lgi/linux/Gtk/LgiWidget.h \
- ../include/lgi/linux/Gtk/LgiWinManGlue.h \
- ../include/lgi/linux/SymLookup.h \
- ../include/lgi/mac/cocoa/LCocoaView.h \
- ../include/lgi/mac/cocoa/LgiMac.h \
- ../include/lgi/mac/cocoa/LgiOs.h \
- ../include/lgi/mac/cocoa/LgiOsClasses.h \
- ../include/lgi/mac/cocoa/LgiOsDefs.h \
- ../include/lgi/mac/cocoa/ObjCWrapper.h \
- ../include/lgi/mac/cocoa/SymLookup.h \
- ../private/common/FontPriv.h \
- ../private/common/ViewPriv.h \
- ../private/linux/AppPriv.h \
- ../src/common/Gdc2/15Bit.cpp \
- ../src/common/Gdc2/16Bit.cpp \
- ../src/common/Gdc2/24Bit.cpp \
- ../src/common/Gdc2/32Bit.cpp \
- ../src/common/Gdc2/8Bit.cpp \
- ../src/common/Gdc2/Alpha.cpp \
- ../src/common/Gdc2/Colour.cpp \
- ../src/common/Gdc2/Filters/Filter.cpp \
- ../src/common/Gdc2/Font/Charset.cpp \
- ../src/common/Gdc2/Font/DisplayString.cpp \
- ../src/common/Gdc2/Font/Font.cpp \
- ../src/common/Gdc2/Font/FontSystem.cpp \
- ../src/common/Gdc2/Font/FontType.cpp \
- ../src/common/Gdc2/Font/StringLayout.cpp \
- ../src/common/Gdc2/Font/TypeFace.cpp \
- ../src/common/Gdc2/GdcCommon.cpp \
- ../src/common/Gdc2/Path/Path.cpp \
- ../src/common/Gdc2/Rect.cpp \
- ../src/common/Gdc2/RopsCases.cpp \
- ../src/common/Gdc2/Surface.cpp \
- ../src/common/Gdc2/Tools/ColourReduce.cpp \
- ../src/common/Gdc2/Tools/GdcTools.cpp \
- ../src/common/General/Containers.cpp \
- ../src/common/General/DateTime.cpp \
- ../src/common/General/ExeCheck.cpp \
- ../src/common/General/FileCommon.cpp \
- ../src/common/General/Password.cpp \
- ../src/common/General/Properties.cpp \
- ../src/common/Hash/md5/md5.c \
- ../src/common/Hash/md5/md5.h \
- ../src/common/Hash/sha1/sha1.c \
- ../src/common/Hash/sha1/sha1.h \
- ../src/common/Lgi/Alert.cpp \
- ../src/common/Lgi/AppCommon.cpp \
- ../src/common/Lgi/Css.cpp \
- ../src/common/Lgi/CssTools.cpp \
- ../src/common/Lgi/DataDlg.cpp \
- ../src/common/Lgi/DragAndDropCommon.cpp \
- ../src/common/Lgi/FileSelect.cpp \
- ../src/common/Lgi/FindReplace.cpp \
- ../src/common/Lgi/FontSelect.cpp \
- ../src/common/Lgi/GuiUtils.cpp \
- ../src/common/Lgi/Input.cpp \
- ../src/common/Lgi/LgiCommon.cpp \
- ../src/common/Lgi/Library.cpp \
- ../src/common/Lgi/LMsg.cpp \
- ../src/common/Lgi/MemStream.cpp \
- ../src/common/Lgi/MenuCommon.cpp \
- ../src/common/Lgi/Mru.cpp \
- ../src/common/Lgi/Mutex.cpp \
- ../src/common/Lgi/Object.cpp \
- ../src/common/Lgi/OptionsFile.cpp \
- ../src/common/Lgi/Rand.cpp \
- ../src/common/Lgi/Stream.cpp \
- ../src/common/Lgi/SubProcess.cpp \
- ../src/common/Lgi/ThreadCommon.cpp \
- ../src/common/Lgi/ThreadEvent.cpp \
- ../src/common/Lgi/ToolTip.cpp \
- ../src/common/Lgi/TrayIcon.cpp \
- ../src/common/Lgi/Variant.cpp \
- ../src/common/Lgi/ViewCommon.cpp \
- ../src/common/Lgi/WindowCommon.cpp \
- ../src/common/Net/Base64.cpp \
- ../src/common/Net/MDStringToDigest.cpp \
- ../src/common/Net/Net.cpp \
- ../src/common/Net/NetTools.cpp \
- ../src/common/Net/Uri.cpp \
- ../src/common/Resource/LgiRes.cpp \
- ../src/common/Resource/Res.cpp \
- ../src/common/Skins/Gel/Gel.cpp \
- ../src/common/Text/DocView.cpp \
- ../src/common/Text/String.cpp \
- ../src/common/Text/TextView3.cpp \
- ../src/common/Text/Token.cpp \
- ../src/common/Text/Unicode.cpp \
- ../src/common/Text/Utf8.cpp \
- ../src/common/Text/XmlTree.cpp \
- ../src/common/Widgets/Bitmap.cpp \
- ../src/common/Widgets/Box.cpp \
- ../src/common/Widgets/Button.cpp \
- ../src/common/Widgets/CheckBox.cpp \
- ../src/common/Widgets/Combo.cpp \
- ../src/common/Widgets/Edit.cpp \
- ../src/common/Widgets/ItemContainer.cpp \
- ../src/common/Widgets/List.cpp \
- ../src/common/Widgets/Panel.cpp \
- ../src/common/Widgets/Popup.cpp \
- ../src/common/Widgets/Progress.cpp \
- ../src/common/Widgets/ProgressDlg.cpp \
- ../src/common/Widgets/RadioGroup.cpp \
- ../src/common/Widgets/ScrollBar.cpp \
- ../src/common/Widgets/Slider.cpp \
- ../src/common/Widgets/Splitter.cpp \
- ../src/common/Widgets/StatusBar.cpp \
- ../src/common/Widgets/TableLayout.cpp \
- ../src/common/Widgets/TabView.cpp \
- ../src/common/Widgets/TextLabel.cpp \
- ../src/common/Widgets/ToolBar.cpp \
- ../src/common/Widgets/Tree.cpp \
- ../src/linux/General/File.cpp \
- ../src/linux/General/Mem.cpp \
- ../src/linux/General/ShowFileProp_Linux.cpp \
- ../src/linux/Gtk/Gdc2.cpp \
- ../src/linux/Gtk/LgiWidget.cpp \
- ../src/linux/Gtk/MemDC.cpp \
- ../src/linux/Gtk/PrintDC.cpp \
- ../src/linux/Gtk/ScreenDC.cpp \
- ../src/linux/Lgi/App.cpp \
- ../src/linux/Lgi/ClipBoard.cpp \
- ../src/linux/Lgi/DragAndDrop.cpp \
- ../src/linux/Lgi/General.cpp \
- ../src/linux/Lgi/Layout.cpp \
- ../src/linux/Lgi/Menu.cpp \
- ../src/linux/Lgi/Printer.cpp \
- ../src/linux/Lgi/Thread.cpp \
- ../src/linux/Lgi/View.cpp \
- ../src/linux/Lgi/Widgets.cpp \
- ../src/linux/Lgi/Window.cpp
+../../$(BuildDir)/liblgi-gtk3$(Tag).so : ../../include/lgi/common/App.h \
+ ../../include/lgi/common/Array.h \
+ ../../include/lgi/common/AutoPtr.h \
+ ../../include/lgi/common/Box.h \
+ ../../include/lgi/common/Button.h \
+ ../../include/lgi/common/Cancel.h \
+ ../../include/lgi/common/CheckBox.h \
+ ../../include/lgi/common/ClipBoard.h \
+ ../../include/lgi/common/Colour.h \
+ ../../include/lgi/common/ColourSpace.h \
+ ../../include/lgi/common/Com.h \
+ ../../include/lgi/common/Combo.h \
+ ../../include/lgi/common/Containers.h \
+ ../../include/lgi/common/Css.h \
+ ../../include/lgi/common/CssTools.h \
+ ../../include/lgi/common/DataDlg.h \
+ ../../include/lgi/common/DateTime.h \
+ ../../include/lgi/common/Dialog.h \
+ ../../include/lgi/common/DisplayString.h \
+ ../../include/lgi/common/DocView.h \
+ ../../include/lgi/common/Dom.h \
+ ../../include/lgi/common/DragAndDrop.h \
+ ../../include/lgi/common/DropFiles.h \
+ ../../include/lgi/common/Edit.h \
+ ../../include/lgi/common/Error.h \
+ ../../include/lgi/common/EventTargetThread.h \
+ ../../include/lgi/common/File.h \
+ ../../include/lgi/common/FileSelect.h \
+ ../../include/lgi/common/Filter.h \
+ ../../include/lgi/common/FindReplaceDlg.h \
+ ../../include/lgi/common/Font.h \
+ ../../include/lgi/common/FontCache.h \
+ ../../include/lgi/common/FontSelect.h \
+ ../../include/lgi/common/Gdc2.h \
+ ../../include/lgi/common/GdcTools.h \
+ ../../include/lgi/common/GdiLeak.h \
+ ../../include/lgi/common/HashTable.h \
+ ../../include/lgi/common/Input.h \
+ ../../include/lgi/common/ItemContainer.h \
+ ../../include/lgi/common/Json.h \
+ ../../include/lgi/common/Layout.h \
+ ../../include/lgi/common/Lgi.h \
+ ../../include/lgi/common/LgiClasses.h \
+ ../../include/lgi/common/LgiCommon.h \
+ ../../include/lgi/common/LgiDefs.h \
+ ../../include/lgi/common/LgiInc.h \
+ ../../include/lgi/common/LgiInterfaces.h \
+ ../../include/lgi/common/LgiMsgs.h \
+ ../../include/lgi/common/LgiNetInc.h \
+ ../../include/lgi/common/LgiRes.h \
+ ../../include/lgi/common/LgiString.h \
+ ../../include/lgi/common/LgiUiBase.h \
+ ../../include/lgi/common/Library.h \
+ ../../include/lgi/common/List.h \
+ ../../include/lgi/common/ListItemCheckBox.h \
+ ../../include/lgi/common/ListItemRadioBtn.h \
+ ../../include/lgi/common/Mem.h \
+ ../../include/lgi/common/Menu.h \
+ ../../include/lgi/common/Message.h \
+ ../../include/lgi/common/Mime.h \
+ ../../include/lgi/common/Mru.h \
+ ../../include/lgi/common/Mutex.h \
+ ../../include/lgi/common/Net.h \
+ ../../include/lgi/common/NetTools.h \
+ ../../include/lgi/common/Notifications.h \
+ ../../include/lgi/common/OptionsFile.h \
+ ../../include/lgi/common/Password.h \
+ ../../include/lgi/common/PixelRops.h \
+ ../../include/lgi/common/Point.h \
+ ../../include/lgi/common/Popup.h \
+ ../../include/lgi/common/PopupList.h \
+ ../../include/lgi/common/PopupNotification.h \
+ ../../include/lgi/common/Printer.h \
+ ../../include/lgi/common/Progress.h \
+ ../../include/lgi/common/ProgressDlg.h \
+ ../../include/lgi/common/ProgressView.h \
+ ../../include/lgi/common/Properties.h \
+ ../../include/lgi/common/RadioGroup.h \
+ ../../include/lgi/common/Rect.h \
+ ../../include/lgi/common/RefCount.h \
+ ../../include/lgi/common/Res.h \
+ ../../include/lgi/common/ScrollBar.h \
+ ../../include/lgi/common/Slider.h \
+ ../../include/lgi/common/Stream.h \
+ ../../include/lgi/common/StringClass.h \
+ ../../include/lgi/common/StringLayout.h \
+ ../../include/lgi/common/StructuredIo.h \
+ ../../include/lgi/common/StructuredLog.h \
+ ../../include/lgi/common/SubProcess.h \
+ ../../include/lgi/common/TableLayout.h \
+ ../../include/lgi/common/TabView.h \
+ ../../include/lgi/common/TextFile.h \
+ ../../include/lgi/common/TextLabel.h \
+ ../../include/lgi/common/TextLog.h \
+ ../../include/lgi/common/TextView3.h \
+ ../../include/lgi/common/Thread.h \
+ ../../include/lgi/common/ThreadEvent.h \
+ ../../include/lgi/common/Token.h \
+ ../../include/lgi/common/ToolBar.h \
+ ../../include/lgi/common/ToolTip.h \
+ ../../include/lgi/common/Tree.h \
+ ../../include/lgi/common/Unicode.h \
+ ../../include/lgi/common/UnrolledList.h \
+ ../../include/lgi/common/Variant.h \
+ ../../include/lgi/common/View.h \
+ ../../include/lgi/common/Widgets.h \
+ ../../include/lgi/common/Window.h \
+ ../../include/lgi/common/XmlTree.h \
+ ../../include/lgi/linux/Gtk/LgiOsClasses.h \
+ ../../include/lgi/linux/Gtk/LgiOsDefs.h \
+ ../../include/lgi/linux/Gtk/LgiWidget.h \
+ ../../include/lgi/linux/Gtk/LgiWinManGlue.h \
+ ../../include/lgi/linux/SymLookup.h \
+ ../../include/lgi/mac/cocoa/LCocoaView.h \
+ ../../include/lgi/mac/cocoa/LgiMac.h \
+ ../../include/lgi/mac/cocoa/LgiOs.h \
+ ../../include/lgi/mac/cocoa/LgiOsClasses.h \
+ ../../include/lgi/mac/cocoa/LgiOsDefs.h \
+ ../../include/lgi/mac/cocoa/ObjCWrapper.h \
+ ../../include/lgi/mac/cocoa/SymLookup.h \
+ ../../private/common/FontPriv.h \
+ ../../private/common/ViewPriv.h \
+ ../../private/linux/AppPriv.h \
+ ../../src/common/Gdc2/15Bit.cpp \
+ ../../src/common/Gdc2/16Bit.cpp \
+ ../../src/common/Gdc2/24Bit.cpp \
+ ../../src/common/Gdc2/32Bit.cpp \
+ ../../src/common/Gdc2/8Bit.cpp \
+ ../../src/common/Gdc2/Alpha.cpp \
+ ../../src/common/Gdc2/Colour.cpp \
+ ../../src/common/Gdc2/Filters/Filter.cpp \
+ ../../src/common/Gdc2/Font/Charset.cpp \
+ ../../src/common/Gdc2/Font/DisplayString.cpp \
+ ../../src/common/Gdc2/Font/Font.cpp \
+ ../../src/common/Gdc2/Font/FontSystem.cpp \
+ ../../src/common/Gdc2/Font/FontType.cpp \
+ ../../src/common/Gdc2/Font/StringLayout.cpp \
+ ../../src/common/Gdc2/Font/TypeFace.cpp \
+ ../../src/common/Gdc2/GdcCommon.cpp \
+ ../../src/common/Gdc2/Path/Path.cpp \
+ ../../src/common/Gdc2/Rect.cpp \
+ ../../src/common/Gdc2/RopsCases.cpp \
+ ../../src/common/Gdc2/Surface.cpp \
+ ../../src/common/Gdc2/Tools/ColourReduce.cpp \
+ ../../src/common/Gdc2/Tools/GdcTools.cpp \
+ ../../src/common/General/Containers.cpp \
+ ../../src/common/General/DateTime.cpp \
+ ../../src/common/General/ExeCheck.cpp \
+ ../../src/common/General/FileCommon.cpp \
+ ../../src/common/General/Password.cpp \
+ ../../src/common/General/Properties.cpp \
+ ../../src/common/Hash/md5/md5.c \
+ ../../src/common/Hash/md5/md5.h \
+ ../../src/common/Hash/sha1/sha1.c \
+ ../../src/common/Hash/sha1/sha1.h \
+ ../../src/common/Lgi/Alert.cpp \
+ ../../src/common/Lgi/AppCommon.cpp \
+ ../../src/common/Lgi/Css.cpp \
+ ../../src/common/Lgi/CssTools.cpp \
+ ../../src/common/Lgi/DataDlg.cpp \
+ ../../src/common/Lgi/DragAndDropCommon.cpp \
+ ../../src/common/Lgi/FileSelect.cpp \
+ ../../src/common/Lgi/FindReplace.cpp \
+ ../../src/common/Lgi/FontSelect.cpp \
+ ../../src/common/Lgi/GuiUtils.cpp \
+ ../../src/common/Lgi/Input.cpp \
+ ../../src/common/Lgi/LgiCommon.cpp \
+ ../../src/common/Lgi/Library.cpp \
+ ../../src/common/Lgi/LMsg.cpp \
+ ../../src/common/Lgi/MemStream.cpp \
+ ../../src/common/Lgi/MenuCommon.cpp \
+ ../../src/common/Lgi/Mru.cpp \
+ ../../src/common/Lgi/Mutex.cpp \
+ ../../src/common/Lgi/Object.cpp \
+ ../../src/common/Lgi/OptionsFile.cpp \
+ ../../src/common/Lgi/Rand.cpp \
+ ../../src/common/Lgi/Stream.cpp \
+ ../../src/common/Lgi/SubProcess.cpp \
+ ../../src/common/Lgi/ThreadCommon.cpp \
+ ../../src/common/Lgi/ThreadEvent.cpp \
+ ../../src/common/Lgi/ToolTip.cpp \
+ ../../src/common/Lgi/TrayIcon.cpp \
+ ../../src/common/Lgi/Variant.cpp \
+ ../../src/common/Lgi/ViewCommon.cpp \
+ ../../src/common/Lgi/WindowCommon.cpp \
+ ../../src/common/Net/Base64.cpp \
+ ../../src/common/Net/MDStringToDigest.cpp \
+ ../../src/common/Net/Net.cpp \
+ ../../src/common/Net/NetTools.cpp \
+ ../../src/common/Net/Uri.cpp \
+ ../../src/common/Resource/LgiRes.cpp \
+ ../../src/common/Resource/Res.cpp \
+ ../../src/common/Skins/Gel/Gel.cpp \
+ ../../src/common/Text/DocView.cpp \
+ ../../src/common/Text/String.cpp \
+ ../../src/common/Text/TextView3.cpp \
+ ../../src/common/Text/Token.cpp \
+ ../../src/common/Text/Unicode.cpp \
+ ../../src/common/Text/Utf8.cpp \
+ ../../src/common/Text/XmlTree.cpp \
+ ../../src/common/Widgets/Bitmap.cpp \
+ ../../src/common/Widgets/Box.cpp \
+ ../../src/common/Widgets/Button.cpp \
+ ../../src/common/Widgets/CheckBox.cpp \
+ ../../src/common/Widgets/Combo.cpp \
+ ../../src/common/Widgets/Edit.cpp \
+ ../../src/common/Widgets/ItemContainer.cpp \
+ ../../src/common/Widgets/List.cpp \
+ ../../src/common/Widgets/Panel.cpp \
+ ../../src/common/Widgets/Popup.cpp \
+ ../../src/common/Widgets/Progress.cpp \
+ ../../src/common/Widgets/ProgressDlg.cpp \
+ ../../src/common/Widgets/RadioGroup.cpp \
+ ../../src/common/Widgets/ScrollBar.cpp \
+ ../../src/common/Widgets/Slider.cpp \
+ ../../src/common/Widgets/Splitter.cpp \
+ ../../src/common/Widgets/StatusBar.cpp \
+ ../../src/common/Widgets/TableLayout.cpp \
+ ../../src/common/Widgets/TabView.cpp \
+ ../../src/common/Widgets/TextLabel.cpp \
+ ../../src/common/Widgets/ToolBar.cpp \
+ ../../src/common/Widgets/Tree.cpp \
+ ../../src/linux/General/File.cpp \
+ ../../src/linux/General/Mem.cpp \
+ ../../src/linux/General/ShowFileProp_Linux.cpp \
+ ../../src/linux/Gtk/Gdc2.cpp \
+ ../../src/linux/Gtk/LgiWidget.cpp \
+ ../../src/linux/Gtk/MemDC.cpp \
+ ../../src/linux/Gtk/PrintDC.cpp \
+ ../../src/linux/Gtk/ScreenDC.cpp \
+ ../../src/linux/Lgi/App.cpp \
+ ../../src/linux/Lgi/ClipBoard.cpp \
+ ../../src/linux/Lgi/DragAndDrop.cpp \
+ ../../src/linux/Lgi/General.cpp \
+ ../../src/linux/Lgi/Layout.cpp \
+ ../../src/linux/Lgi/Menu.cpp \
+ ../../src/linux/Lgi/Printer.cpp \
+ ../../src/linux/Lgi/Thread.cpp \
+ ../../src/linux/Lgi/View.cpp \
+ ../../src/linux/Lgi/Widgets.cpp \
+ ../../src/linux/Lgi/Window.cpp
export Build=$(Build); \
- $(MAKE) -C .. -f Makefile.linux
+ $(MAKE) -C ../../ -f Makefile.linux
.SECONDEXPANSION:
-$(Objects): $(BuildDir)/%.o: $$(wildcard %.c*)
+$(Objects): $(BuildDir)/%.o: $$(Source)
mkdir -p $(@D)
- @echo $(
#else
#include
#endif
#include
#include "lgi/common/Lgi.h"
#include "lgi/common/DragAndDrop.h"
#include "lgi/common/Token.h"
#include "lgi/common/Combo.h"
#include "lgi/common/Net.h"
#include "lgi/common/ListItemCheckBox.h"
#include "lgi/common/ClipBoard.h"
#include "lgi/common/DropFiles.h"
#include "lgi/common/SubProcess.h"
#include "lgi/common/Css.h"
#include "lgi/common/TableLayout.h"
#include "lgi/common/TextLabel.h"
#include "lgi/common/Button.h"
#include "lgi/common/RegKey.h"
#include "lgi/common/FileSelect.h"
#include "lgi/common/Menu.h"
#include "LgiIde.h"
#include "resdefs.h"
#include "FtpThread.h"
#include "ProjectNode.h"
#include "WebFldDlg.h"
extern const char *Untitled;
const char SourcePatterns[] = "*.c;*.h;*.cpp;*.cc;*.java;*.d;*.php;*.html;*.css;*.js";
const char *AddFilesProgress::DefaultExt = "c,cpp,cc,cxx,h,hpp,hxx,html,css,json,js,jsx,txt,png,jpg,jpeg,rc,xml,mk,paths,makefile,py,java,php";
const char *VsBinaries[] = {"devenv.com", "WDExpress.exe"};
#define USE_OPEN_PROGRESS 1
#define STOP_BUILD_TIMEOUT 2000
#ifdef WINDOWS
#define LGI_STATIC_LIBRARY_EXT "lib"
#else
#define LGI_STATIC_LIBRARY_EXT "a"
#endif
const char *PlatformNames[] =
{
"Windows",
"Linux",
"Mac",
"Haiku",
0
};
int PlatformCtrlId[] =
{
IDC_WIN32,
IDC_LINUX,
IDC_MAC,
IDC_HAIKU,
0
};
const char *PlatformDynamicLibraryExt(IdePlatform Platform)
{
if (Platform == PlatformWin)
return "dll";
if (Platform == PlatformMac)
return "dylib";
return "so";
}
const char *PlatformSharedLibraryExt(IdePlatform Platform)
{
if (Platform == PlatformWin)
return "lib";
return "a";
}
const char *PlatformExecutableExt(IdePlatform Platform)
{
if (Platform == PlatformWin)
return ".exe";
return "";
}
char *ToUnixPath(char *s)
{
if (s)
{
char *c;
while ((c = strchr(s, '\\')))
*c = '/';
}
return s;
}
const char *CastEmpty(char *s)
{
return s ? s : "";
}
bool FindInPath(LString &Exe)
{
LString::Array Path = LString(getenv("PATH")).Split(LGI_PATH_SEPARATOR);
for (unsigned i=0; i SubProc;
LString::Array BuildConfigs;
LString::Array PostBuild;
int AppHnd;
enum CompilerType
{
DefaultCompiler,
VisualStudio,
MingW,
Gcc,
CrossCompiler,
PythonScript,
IAR,
Nmake,
Cygwin,
Xcode,
}
Compiler;
enum ArchType
{
DefaultArch,
ArchX32,
ArchX64,
ArchArm6,
ArchArm7,
}
Arch;
public:
BuildThread(IdeProject *proj, char *makefile, bool clean, BuildConfig config, bool all, int wordsize);
~BuildThread();
ssize_t Write(const void *Buffer, ssize_t Size, int Flags = 0) override;
LString FindExe();
LAutoString WinToMingWPath(const char *path);
int Main() override;
};
class IdeProjectPrivate
{
public:
AppWnd *App;
IdeProject *Project;
bool Dirty, UserFileDirty;
LString FileName;
IdeProject *ParentProject;
IdeProjectSettings Settings;
LAutoPtr Thread;
LHashTbl, ProjectNode*> Nodes;
int NextNodeId;
// Threads
LAutoPtr CreateMakefile;
// User info file
LString UserFile;
LHashTbl,int> UserNodeFlags;
IdeProjectPrivate(AppWnd *a, IdeProject *project) :
Project(project),
Settings(project)
{
App = a;
Dirty = false;
UserFileDirty = false;
ParentProject = 0;
NextNodeId = 1;
}
void CollectAllFiles(LTreeNode *Base, LArray &Files, bool SubProjects, int Platform);
};
LString ToPlatformPath(const char *s, IdePlatform platform)
{
LString p = s;
if (platform == PlatformWin)
return p.Replace("/", "\\");
else
return p.Replace("\\", "/");
}
class MakefileThread : public LThread, public LCancel
{
IdeProjectPrivate *d;
IdeProject *Proj;
IdePlatform Platform;
LStream *Log;
bool BuildAfterwards;
bool HasError;
public:
static int Instances;
MakefileThread(IdeProjectPrivate *priv, IdePlatform platform, bool Build) : LThread("MakefileThread")
{
Instances++;
d = priv;
Proj = d->Project;
Platform = platform;
BuildAfterwards = Build;
HasError = false;
Log = d->App->GetBuildLog();
Run();
}
~MakefileThread()
{
Cancel();
while (!IsExited())
LSleep(1);
Instances--;
}
void OnError(const char *Fmt, ...)
{
va_list Arg;
va_start(Arg, Fmt);
LStreamPrintf(Log, 0, Fmt, Arg);
va_end(Arg);
HasError = true;
}
int Main()
{
const char *PlatformName = PlatformNames[Platform];
const char *PlatformLibraryExt = NULL;
const char *PlatformStaticLibExt = NULL;
const char *PlatformExeExt = "";
LString LinkerFlags;
const char *TargetType = d->Settings.GetStr(ProjTargetType, NULL, Platform);
const char *CompilerName = d->Settings.GetStr(ProjCompiler);
LString CCompilerBinary = "gcc";
LString CppCompilerBinary = "g++";
LStream *Log = d->App->GetBuildLog();
bool IsExecutableTarget = TargetType && !stricmp(TargetType, "Executable");
bool IsDynamicLibrary = TargetType && !stricmp(TargetType, "DynamicLibrary");
LAssert(Log);
if (!Log)
return false;
Log->Print("CreateMakefile for '%s'...\n", PlatformName);
if (Platform == PlatformWin)
{
LinkerFlags = ",--enable-auto-import";
}
else
{
if (IsDynamicLibrary)
{
LinkerFlags = ",-soname,$(TargetFile)";
}
LinkerFlags += ",-export-dynamic,-R.";
}
+ Log->Print("Log %s:%i\n", _FL);
+
auto Base = Proj->GetBasePath();
auto MakeFile = Proj->GetMakefile(Platform);
LString MakeFilePath;
Proj->CheckExists(MakeFile);
if (!MakeFile)
{
MakeFilePath = Base.Get();
LFile::Path p(MakeFilePath, "makefile");
MakeFile = p.GetFull();
}
else if (LIsRelativePath(MakeFile))
{
LFile::Path p(Base);
p += MakeFile;
MakeFile = p.GetFull();
p--;
MakeFilePath = p.GetFull();
}
else
{
LFile::Path p(MakeFile);
p--;
MakeFilePath = p.GetFull();
}
+ Log->Print("Log %s:%i\n", _FL);
+
// LGI_LIBRARY_EXT
switch (Platform)
{
case PlatformWin:
PlatformLibraryExt = "dll";
PlatformStaticLibExt = "lib";
PlatformExeExt = ".exe";
break;
case PlatformLinux:
case PlatformHaiku:
PlatformLibraryExt = "so";
PlatformStaticLibExt = "a";
break;
case PlatformMac:
PlatformLibraryExt = "dylib";
PlatformStaticLibExt = "a";
break;
default:
LAssert(0);
break;
}
+ Log->Print("Log %s:%i\n", _FL);
+
if (CompilerName)
{
if (!stricmp(CompilerName, "cross"))
{
LString CBin = d->Settings.GetStr(ProjCCrossCompiler, NULL, Platform);
if (CBin && !LFileExists(CBin))
FindInPath(CBin);
if (CBin && LFileExists(CBin))
CCompilerBinary = CBin;
else
Log->Print("%s:%i - Error: C cross compiler '%s' not found.\n", _FL, CBin.Get());
LString CppBin = d->Settings.GetStr(ProjCppCrossCompiler, NULL, Platform);
if (CppBin && !LFileExists(CppBin))
FindInPath(CppBin);
if (CppBin && LFileExists(CppBin))
CppCompilerBinary = CppBin;
else
Log->Print("%s:%i - Error: C++ cross compiler '%s' not found.\n", _FL, CppBin.Get());
}
}
LFile m;
if (!m.Open(MakeFile, O_WRITE))
{
Log->Print("Error: Failed to open '%s' for writing.\n", MakeFile.Get());
return false;
}
+ Log->Print("Log %s:%i\n", _FL);
+
m.SetSize(0);
m.Print("#!/usr/bin/make\n"
"#\n"
"# This makefile generated by LgiIde\n"
"# http://www.memecode.com/lgi.php\n"
"#\n"
"\n"
".SILENT :\n"
"\n"
"CC = %s\n"
"CPP = %s\n",
CCompilerBinary.Get(),
CppCompilerBinary.Get());
// Collect all files that require building
LArray Files;
d->CollectAllFiles
(
Proj,
Files,
false,
1 << Platform
);
+ Log->Print("Log %s:%i\n", _FL);
+
if (IsExecutableTarget)
{
LString Exe = Proj->GetExecutable(Platform);
if (Exe)
{
if (LIsRelativePath(Exe))
m.Print("Target = %s\n", ToPlatformPath(Exe, Platform).Get());
else
{
- auto RelExe = LMakeRelativePath(Base, Exe);
+ auto RelExe = LMakeRelativePath(MakeFilePath, Exe);
if (Base && RelExe)
{
m.Print("Target = %s\n", ToPlatformPath(RelExe, Platform).Get());
}
else
{
Log->Print("%s:%i - Error: Missing path (%s, %s).\n", _FL, Base.Get(), RelExe.Get());
return false;
}
}
}
else
{
Log->Print("%s:%i - Error: No executable name specified (%s, %s).\n", _FL, TargetType, d->FileName.Get());
return false;
}
}
else
{
LString Target = Proj->GetTargetName(Platform);
if (Target)
m.Print("Target = %s\n", ToPlatformPath(Target, Platform).Get());
else
{
Log->Print("%s:%i - Error: No target name specified.\n", _FL);
return false;
}
}
+ Log->Print("Log %s:%i\n", _FL);
+
// Output the build mode, flags and some paths
auto BuildMode = d->App->GetBuildMode();
auto BuildModeName = toString(BuildMode);
m.Print("ifndef Build\n"
" Build = %s\n"
"endif\n",
BuildModeName);
+ m.Print("MakeDir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n");
LString sDefines[BuildMax];
LString sLibs[BuildMax];
LString sIncludes[BuildMax];
const char *ExtraLinkFlags = NULL;
const char *ExeFlags = NULL;
if (Platform == PlatformWin)
{
ExtraLinkFlags = "";
ExeFlags = " -mwindows";
m.Print("BuildDir = $(Build)\n"
"\n"
"Flags = -fPIC -w -fno-inline -fpermissive\n");
const char *DefDefs = "-DWIN32 -D_REENTRANT";
sDefines[BuildDebug] = DefDefs;
sDefines[BuildRelease] = DefDefs;
}
else
{
LString PlatformCap = PlatformName;
ExtraLinkFlags = "";
ExeFlags = "";
m.Print("BuildDir = $(Build)\n"
"\n"
"Flags = -fPIC -w -fno-inline -fpermissive\n" // -fexceptions
);
sDefines[0].Printf("-D%s -D_REENTRANT", PlatformCap.Upper().Get());
#ifdef LINUX
sDefines[BuildDebug] += " -D_FILE_OFFSET_BITS=64"; // >:-(
sDefines[BuildDebug] += " -DPOSIX";
#endif
sDefines[BuildRelease] = sDefines[BuildDebug];
}
+ Log->Print("Log %s:%i\n", _FL);
+
List Deps;
Proj->GetChildProjects(Deps);
+ Log->Print("Log %s:%i\n", _FL);
for (int Cfg = BuildDebug; Cfg < BuildMax; Cfg++)
{
// Set the config
auto cfgName = toString((BuildConfig)Cfg);
d->Settings.SetCurrentConfig(cfgName);
// Get the defines setup
auto PDefs = d->Settings.GetStr(ProjDefines, NULL, Platform);
if (ValidStr(PDefs))
{
LToken Defs(PDefs, " ;,\r\n");
for (int i=0; iSettings.GetStr(ProjLibraryPaths, NULL, Platform);
if (ValidStr(PLibPaths))
{
LString::Array LibPaths = PLibPaths.Split("\n");
for (auto i: LibPaths)
{
LString s, in = i.Strip();
if (!in.Length())
continue;
if (strchr("`-", in(0)))
{
s.Printf(" \\\n\t\t%s", in.Get());
}
else
{
LString Rel;
if (!LIsRelativePath(in))
- Rel = LMakeRelativePath(Base, in);
+ Rel = LMakeRelativePath(MakeFilePath, in);
+
+ printf("Rel='%s' ('%s' + '%s')\n", Rel.Get(), MakeFilePath.Get(), in.Get());
LString Final = Rel ? Rel.Get() : in.Get();
if (!Proj->CheckExists(Final))
OnError("%s:%i - Library path '%s' doesn't exist (from %s).\n",
_FL, Final.Get(),
Proj->GetFileName());
s.Printf(" \\\n\t\t-L%s", ToUnixPath(Final));
}
sLibs[Cfg] += s;
}
}
const char *PLibs = d->Settings.GetStr(ProjLibraries, NULL, Platform);
if (ValidStr(PLibs))
{
LToken Libs(PLibs, "\r\n");
for (int i=0; iCheckExists(l);
s.Printf(" \\\n\t\t-l%s", ToUnixPath(l));
}
sLibs[Cfg] += s;
}
}
for (auto dep: Deps)
{
LString Target = dep->GetTargetName(Platform);
if (Target)
{
char t[MAX_PATH_LEN];
strcpy_s(t, sizeof(t), Target);
if (!strnicmp(t, "lib", 3))
memmove(t, t + 3, strlen(t + 3) + 1);
char *dot = strrchr(t, '.');
if (dot)
*dot = 0;
LString s, sTarget = t;
Proj->CheckExists(sTarget);
s.Printf(" \\\n\t\t-l%s$(Tag)", ToUnixPath(sTarget));
sLibs[Cfg] += s;
auto DepBase = dep->GetBasePath();
if (DepBase)
{
LString DepPath = DepBase.Get();
- auto Rel = LMakeRelativePath(Base, DepPath);
+ auto Rel = LMakeRelativePath(MakeFilePath, DepPath);
+ printf("Rel=%s (%s + %s)\n", Rel.Get(), MakeFilePath.Get(), DepPath.Get());
LString Final = Rel ? Rel.Get() : DepPath.Get();
Proj->CheckExists(Final);
s.Printf(" \\\n\t\t-L%s/$(BuildDir)", ToUnixPath(Final.RStrip("/\\")));
sLibs[Cfg] += s;
}
}
}
// Includes
// Do include paths
LHashTbl,bool> Inc;
auto ProjIncludes = d->Settings.GetStr(ProjIncludePaths, NULL, Platform);
if (ValidStr(ProjIncludes))
{
// Add settings include paths.
LToken Paths(ProjIncludes, "\r\n");
for (int i=0; iCheckExists(pn))
OnError("%s:%i - Include path '%s' doesn't exist.\n", _FL, pn.Get());
else if (!Inc.Find(pn))
Inc.Add(pn, true);
}
}
const char *SysIncludes = d->Settings.GetStr(ProjSystemIncludes, NULL, Platform);
if (ValidStr(SysIncludes))
{
// Add settings include paths.
LToken Paths(SysIncludes, "\r\n");
for (int i=0; iCheckExists(pn))
OnError("%s:%i - System include path '%s' doesn't exist (from %s).\n",
_FL, pn.Get(),
Proj->GetFileName());
else if (!Inc.Find(pn))
Inc.Add(pn, true);
}
}
#if 0
/*
Currently this code is adding extra paths that are covered by the official 'IncludePaths'
in addition to relative paths in the actual #include parameter. e.g.
#include "lgi/common/SomeHeader.h"
Hence disabling it for the time being.
*/
// Add paths of headers
for (int i=0; iGetFileName())
{
char *e = LGetExtension(n->GetFileName());
if (e && stricmp(e, "h") == 0)
{
LString Fn = n->GetFileName();
for (char *Dir = Fn; *Dir; Dir++)
{
if (*Dir == '/' || *Dir == '\\')
{
*Dir = DIR_CHAR;
}
}
char Path[MAX_PATH_LEN];
strcpy_s(Path, sizeof(Path), Fn);
LTrimDir(Path);
- LString Rel;
- if (!Proj->RelativePath(Rel, Path))
+ LString Rel = LMakeRelativePath(MakeFilePath, Path);
+ if (!Rel)
Rel = Path;
if (stricmp(Rel, ".") != 0)
{
LAutoString RelN = ToNativePath(Rel);
if (!Proj->CheckExists(RelN))
OnError("Header include path '%s' doesn't exist.\n", RelN.Get());
else if (!Inc.Find(RelN))
Inc.Add(RelN, true);
}
}
}
}
#endif
LString::Array Incs;
for (auto i: Inc)
Incs.New() = i.key;
Incs.Sort();
for (auto i: Incs)
{
LString s;
if (*i == '`')
s.Printf(" \\\n\t\t%s", i.Get());
else
s.Printf(" \\\n\t\t-I%s", ToUnixPath(i));
sIncludes[Cfg] += s;
}
}
// Output the defs section for Debug and Release
// Debug specific
m.Print("\n"
"ifeq ($(Build),Debug)\n"
" Flags += -g -std=c++14\n"
" Tag = d\n"
" Defs = -D_DEBUG %s\n"
" Libs = %s\n"
" Inc = %s\n",
CastEmpty(sDefines[0].Get()),
CastEmpty(sLibs[0].Get()),
CastEmpty(sIncludes[0].Get()));
// Release specific
m.Print("else\n"
" Flags += -s -Os -std=c++14\n"
" Defs = %s\n"
" Libs = %s\n"
" Inc = %s\n"
"endif\n"
"\n",
CastEmpty(sDefines[1].Get()),
CastEmpty(sLibs[1].Get()),
CastEmpty(sIncludes[1].Get()));
if (Files.Length())
{
LArray IncPaths;
if (Proj->BuildIncludePaths(IncPaths, false, false, Platform))
{
// Do source code list...
m.Print("# Dependencies\n"
"Source =\t");
LString::Array SourceFiles;
for (auto &n: Files)
{
if (n->GetType() == NodeSrc)
{
auto f = n->GetFileName();
auto path = ToPlatformPath(f, Platform);
if (path.Find("./") == 0)
path = path(2,-1);
SourceFiles.Add(path);
}
}
SourceFiles.Sort();
int c = 0;
for (auto &src: SourceFiles)
{
if (c++) m.Print(" \\\n\t\t\t");
m.Print("%s", src.Get());
}
m.Print("\n"
"\n"
"SourceLst := $(patsubst %%.c,%%.o,$(patsubst %%.cpp,%%.o,$(Source)))\n"
"Objects := $(addprefix $(BuildDir)/,$(SourceLst))\n"
"Deps := $(patsubst %%.o,%%.d,$(Objects))\n"
"\n");
// Write out the target stuff
m.Print("# Target\n");
LHashTbl,bool> DepFiles;
if (TargetType)
{
if (IsExecutableTarget)
{
m.Print("# Executable target\n"
"$(Target) :");
LStringPipe Rules;
IdeProject *Dep;
uint64 Last = LCurrentTime();
int Count = 0;
auto It = Deps.begin();
for (Dep=*It; Dep && !IsCancelled(); Dep=*(++It), Count++)
{
// Get dependency to create it's own makefile...
Dep->CreateMakefile(Platform, false);
// Build a rule to make the dependency if any of the source changes...
auto DepBase = Dep->GetBasePath();
- auto Base = MakeFilePath;
auto TargetFile = Dep->GetTargetFile(Platform);
if (DepBase && Base && TargetFile)
{
- LString Rel = LMakeRelativePath(Base, DepBase);
+ LString Rel = LMakeRelativePath(MakeFilePath, DepBase);
ToNativePath(Rel);
// Add tag to target name
auto Parts = TargetFile.SplitDelimit(".");
if (Parts.Length() == 2)
TargetFile.Printf("lib%s$(Tag).%s", Parts[0].Get(), Parts[1].Get());
LFile::Path Buf(Rel);
Buf += "$(BuildDir)";
Buf += TargetFile;
m.Print(" %s", Buf.GetFull().Get());
LArray AllDeps;
Dep->GetAllDependencies(AllDeps, Platform);
LAssert(AllDeps.Length() > 0);
AllDeps.Sort(StrSort);
Rules.Print("%s : ", Buf.GetFull().Get());
for (int i=0; iGetMakefile(Platform);
// RenameMakefileForPlatform(Mk, Platform);
if (Mk)
{
char *DepMakefile = strrchr(Mk, DIR_CHAR);
if (DepMakefile)
Rules.Print(" -f %s", DepMakefile + 1);
}
else
{
Mk = Dep->GetMakefile(Platform);
OnError("%s:%i - No makefile for '%s'\n", _FL, Dep->GetFullPath().Get());
}
Rules.Print("\n\n");
}
uint64 Now = LCurrentTime();
if (Now - Last > 1000)
{
Last = Now;
Log->Print("Building deps %i%%...\n", (int) (((int64)Count+1)*100/Deps.Length()));
}
}
m.Print(" $(Objects)\n"
" mkdir -p $(BuildDir)\n"
" @echo Linking $(Target) [$(Build)]...\n"
" $(CPP)%s%s %s%s -o \\\n"
" $(Target) $(Objects) $(Libs)\n",
ExtraLinkFlags,
ExeFlags,
ValidStr(LinkerFlags) ? "-Wl" : "", LinkerFlags.Get());
if (Platform == PlatformHaiku)
{
// Is there an application icon configured?
const char *AppIcon = d->Settings.GetStr(ProjApplicationIcon, NULL, Platform);
if (AppIcon)
{
m.Print(" addattr -f %s -t \"'VICN'\" \"BEOS:ICON\" $(Target)\n", AppIcon);
}
}
LString PostBuildCmds = d->Settings.GetStr(ProjPostBuildCommands, NULL, Platform);
if (ValidStr(PostBuildCmds))
{
LString::Array a = PostBuildCmds.Split("\n");
for (unsigned i=0; iGetMakefile(Platform);
if (mk)
{
- LAutoString my_base = Proj->GetBasePath();
LAutoString dep_base = d->GetBasePath();
d->CheckExists(dep_base);
- auto rel_dir = LMakeRelativePath(my_base, dep_base);
+ auto rel_dir = LMakeRelativePath(MakeFilePath, dep_base);
d->CheckExists(rel_dir);
char *mk_leaf = strrchr(mk, DIR_CHAR);
m.Print(" +make -C \"%s\" -f \"%s\" clean\n",
ToUnixPath(rel_dir ? rel_dir.Get() : dep_base.Get()),
ToUnixPath(mk_leaf ? mk_leaf + 1 : mk.Get()));
}
}
m.Print("\n");
}
// Shared library
else if (!stricmp(TargetType, "DynamicLibrary"))
{
m.Print("TargetFile = lib$(Target)$(Tag).%s\n"
"$(TargetFile) : $(Objects)\n"
" mkdir -p $(BuildDir)\n"
" @echo Linking $(TargetFile) [$(Build)]...\n"
" $(CPP)$s -shared \\\n"
" %s%s \\\n"
" -o $(BuildDir)/$(TargetFile) \\\n"
" $(Objects) \\\n"
" $(Libs)\n",
PlatformLibraryExt,
ValidStr(ExtraLinkFlags) ? "-Wl" : "", ExtraLinkFlags,
LinkerFlags.Get());
LString PostBuildCmds = d->Settings.GetStr(ProjPostBuildCommands, NULL, Platform);
if (ValidStr(PostBuildCmds))
{
LString::Array a = PostBuildCmds.Split("\n");
for (unsigned i=0; iSettings.GetStr(ProjPostBuildCommands, NULL, Platform);
if (ValidStr(PostBuildCmds))
{
LString::Array a = PostBuildCmds.Split("\n");
for (unsigned i=0; iCheckExists(p);
if (p && !strchr(p, '`'))
{
if (!LIsRelativePath(p))
{
- auto a = LMakeRelativePath(Base, p);
+ auto a = LMakeRelativePath(MakeFilePath, p);
m.Print("\t%s \\\n", ToPlatformPath(a ? a.Get() : p.Get(), Platform).Get());
}
else
{
m.Print("\t%s \\\n", ToPlatformPath(p, Platform).Get());
}
}
}
m.Print("\t$(BuildDir)\n\n");
const char *OtherMakefileRules = d->Settings.GetStr(ProjMakefileRules, NULL, Platform);
if (ValidStr(OtherMakefileRules))
{
m.Print("\n%s\n", OtherMakefileRules);
}
}
}
else
{
m.Print("# No files require building.\n");
}
Log->Print("...Done: '%s'\n", MakeFile.Get());
if (BuildAfterwards)
{
if (!Proj->GetApp()->PostEvent(M_START_BUILD))
printf("%s:%i - PostEvent(M_START_BUILD) failed.\n", _FL);
}
return HasError;
}
void OnAfterMain()
{
Proj->GetApp()->PostEvent(M_MAKEFILES_CREATED, (LMessage::Param)Proj);
}
};
/////////////////////////////////////////////////////////////////////////////////////
NodeSource::~NodeSource()
{
if (nView)
{
nView->nSrc = 0;
}
}
NodeView::~NodeView()
{
if (nSrc)
{
nSrc->nView = 0;
}
}
//////////////////////////////////////////////////////////////////////////////////
int NodeSort(LTreeItem *a, LTreeItem *b, NativeInt d)
{
ProjectNode *A = dynamic_cast(a);
ProjectNode *B = dynamic_cast(b);
if (A && B)
{
if
(
(A->GetType() == NodeDir)
^
(B->GetType() == NodeDir)
)
{
return A->GetType() == NodeDir ? -1 : 1;
}
else
{
return Stricmp(a->GetText(0), b->GetText(0));
}
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool ReadVsProjFile(LString File, LString &Ver, LString::Array &Configs)
{
const char *Ext = LGetExtension(File);
if (!Ext || _stricmp(Ext, "vcxproj"))
return false;
LFile f;
if (!f.Open(File, O_READ))
return false;
LXmlTree Io;
LXmlTag r;
if (Io.Read(&r, &f) &&
r.IsTag("Project"))
{
Ver = r.GetAttr("ToolsVersion");
LXmlTag *ItemGroup = r.GetChildTag("ItemGroup");
if (ItemGroup)
for (auto c: ItemGroup->Children)
{
if (c->IsTag("ProjectConfiguration"))
{
char *s = c->GetAttr("Include");
if (s)
Configs.New() = s;
}
}
}
else return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
BuildThread::BuildThread(IdeProject *proj, char *makefile, bool clean, BuildConfig config, bool all, int wordsize) : LThread("BuildThread")
{
Proj = proj;
Makefile = makefile;
Clean = clean;
Config = config;
All = all;
WordSize = wordsize;
Arch = DefaultArch;
Compiler = DefaultCompiler;
AppHnd = Proj->GetApp()->AddDispatch();
LString Cmds = proj->d->Settings.GetStr(ProjPostBuildCommands, NULL);
if (ValidStr(Cmds))
PostBuild = Cmds.SplitDelimit("\r\n");
auto Ext = LGetExtension(Makefile);
if (Ext && !_stricmp(Ext, "py"))
Compiler = PythonScript;
else if (Ext && !_stricmp(Ext, "sln"))
Compiler = VisualStudio;
else if (Ext && !Stricmp(Ext, "xcodeproj"))
Compiler = Xcode;
else
{
auto Comp = Proj->GetSettings()->GetStr(ProjCompiler);
if (Comp)
{
// Use the specified compiler...
if (!stricmp(Comp, "VisualStudio"))
Compiler = VisualStudio;
else if (!stricmp(Comp, "MingW"))
Compiler = MingW;
else if (!stricmp(Comp, "gcc"))
Compiler = Gcc;
else if (!stricmp(Comp, "cross"))
Compiler = CrossCompiler;
else if (!stricmp(Comp, "IAR"))
Compiler = IAR;
else if (!stricmp(Comp, "Cygwin"))
Compiler = Cygwin;
else
LAssert(!"Unknown compiler.");
}
}
if (Compiler == DefaultCompiler)
{
// Use default compiler for platform...
#ifdef WIN32
Compiler = VisualStudio;
#else
Compiler = Gcc;
#endif
}
Run();
}
BuildThread::~BuildThread()
{
if (SubProc)
{
bool b = SubProc->Interrupt();
LgiTrace("%s:%i - Sub process interrupt = %i.\n", _FL, b);
}
else LgiTrace("%s:%i - No sub process to interrupt.\n", _FL);
uint64 Start = LCurrentTime();
bool Killed = false;
while (!IsExited())
{
LSleep(10);
if (LCurrentTime() - Start > STOP_BUILD_TIMEOUT &&
SubProc)
{
if (Killed)
{
// Thread is stuck as well... ok kill that too!!! Argh - kill all the things!!!!
Terminate();
LgiTrace("%s:%i - Thread killed.\n", _FL);
Proj->GetApp()->PostEvent(M_BUILD_DONE);
break;
}
else
{
// Kill the sub-process...
bool b = SubProc->Kill();
Killed = true;
LgiTrace("%s:%i - Sub process killed.\n", _FL, b);
Start = LCurrentTime();
}
}
}
}
ssize_t BuildThread::Write(const void *Buffer, ssize_t Size, int Flags)
{
if (Proj->GetApp())
{
Proj->GetApp()->PostEvent(M_APPEND_TEXT, (LMessage::Param)NewStr((char*)Buffer, Size), AppWnd::BuildTab);
}
return Size;
}
#pragma comment(lib, "version.lib")
struct ProjInfo
{
LString Guid, Name, File;
LHashTbl,ssize_t> Configs;
};
LString BuildThread::FindExe()
{
LString::Array p = LGetPath();
if (Compiler == PythonScript)
{
#if defined(WINDOWS)
uint32_t BestVer = 0;
#else
LString BestVer;
#endif
static LString Best;
if (!Best)
{
const char *binName[] = {"python3", "python"};
for (int i=0; idwProductVersionMS > BestVer)
{
BestVer = v->dwProductVersionMS;
Best = Path;
}
}
}
else if (!Best)
{
Best = Path;
}
free(Buf);
#else
LSubProcess p(Path, "--version");
LStringPipe o;
if (p.Start())
p.Communicate(&o);
auto Out = o.NewLStr();
auto Ver = Out.SplitDelimit().Last();
printf("Ver=%s\n", Ver.Get());
if (!BestVer || Stricmp(Ver.Get(), BestVer.Get()) > 0)
{
Best = Path;
BestVer = Ver;
}
break;
#endif
}
}
}
}
return Best;
}
else if (Compiler == VisualStudio)
{
// Find the version we need:
double fVer = 0.0;
ProjInfo *First = NULL;
LHashTbl, ProjInfo*> Projects;
const char *Ext = LGetExtension(Makefile);
if (Ext && !_stricmp(Ext, "sln"))
{
LFile f;
if (f.Open(Makefile, O_READ))
{
LString ProjKey = "Project(";
LString StartSection = "GlobalSection(";
LString EndSection = "EndGlobalSection";
LString Section;
ssize_t Pos;
LString::Array Ln = f.Read().SplitDelimit("\r\n");
for (size_t i = 0; i < Ln.Length(); i++)
{
LString s = Ln[i].Strip();
if ((Pos = s.Find(ProjKey)) >= 0)
{
LString::Array p = s.SplitDelimit("(),=");
if (p.Length() > 5)
{
ProjInfo *i = new ProjInfo;
i->Name = p[3].Strip(" \t\"");
i->File = p[4].Strip(" \t\'\"");
i->Guid = p[5].Strip(" \t\"");
if (LIsRelativePath(i->File))
{
char f[MAX_PATH_LEN];
LMakePath(f, sizeof(f), Makefile, "..");
LMakePath(f, sizeof(f), f, i->File);
if (LFileExists(f))
i->File = f;
/*
else
LAssert(0);
*/
}
if (!First)
First = i;
Projects.Add(i->Guid, i);
}
}
else if (s.Find(StartSection) >= 0)
{
auto p = s.SplitDelimit("() \t");
Section = p[1];
}
else if (s.Find(EndSection) >= 0)
{
Section.Empty();
}
else if (Section == "ProjectConfigurationPlatforms")
{
auto p = s.SplitDelimit(". \t");
auto i = Projects.Find(p[0]);
if (i)
{
if (!i->Configs.Find(p[1]))
{
auto Idx = i->Configs.Length() + 1;
i->Configs.Add(p[1], Idx);
}
}
}
else if (Section == "SolutionConfigurationPlatforms")
{
auto p = s.SplitDelimit();
auto config = p[0];
for (auto &it: Projects)
{
auto proj = it.value;
if (!proj->Configs.Find(config))
proj->Configs.Add(config, proj->Configs.Length()+1);
}
}
}
}
}
else if (Ext && !_stricmp(Ext, "vcxproj"))
{
// ProjFile = Makefile;
}
else
{
if (Arch == DefaultArch)
{
if (sizeof(size_t) == 4)
Arch = ArchX32;
else
Arch = ArchX64;
}
#ifdef _MSC_VER
// Nmake file..
LString NmakePath;
switch (_MSC_VER)
{
#ifdef _MSC_VER_VS2013
case _MSC_VER_VS2013:
{
if (Arch == ArchX32)
NmakePath = "c:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\nmake.exe";
else
NmakePath = "c:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\nmake.exe";
break;
}
#endif
#ifdef _MSC_VER_VS2015
case _MSC_VER_VS2015:
{
if (Arch == ArchX32)
NmakePath = "c:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\nmake.exe";
else
NmakePath = "c:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\nmake.exe";
break;
}
#endif
default:
{
LAssert(!"Impl me.");
break;
}
}
if (LFileExists(NmakePath))
{
Compiler = Nmake;
return NmakePath;
}
#endif
}
/*
if (ProjFile && LFileExists(ProjFile))
{
LString sVer;
if (ReadVsProjFile(ProjFile, sVer, BuildConfigs))
{
fVer = sVer.Float();
}
}
*/
if (First)
{
for (auto i: First->Configs)
{
BuildConfigs[i.value - 1] = i.key;
LFile f(First->File, O_READ);
LXmlTree t;
LXmlTag r;
if (t.Read(&r, &f))
{
if (r.IsTag("Project"))
{
auto ToolsVersion = r.GetAttr("ToolsVersion");
if (ToolsVersion)
{
fVer = atof(ToolsVersion);
}
}
}
}
}
if (fVer > 0.0)
{
for (int i=0; i LatestVer)
{
LatestVer = p[2].Float();
Latest = n;
}
}
}
if (Latest &&
LMakePath(p, sizeof(p), p, Latest) &&
LMakePath(p, sizeof(p), p, "common\\bin\\IarBuild.exe"))
{
if (LFileExists(p))
return p;
}
}
else if (Compiler == Xcode)
{
return "/usr/bin/xcodebuild";
}
else if (Compiler == Cygwin)
{
#ifdef WINDOWS
LRegKey k(false, "HKEY_CURRENT_USER\\Software\\Cygwin\\Installations");
List n;
k.GetValueNames(n);
LString s;
for (auto i:n)
{
s = k.GetStr(i);
if (s.Find("\\??\\") == 0)
s = s(4,-1);
if (LDirExists(s))
{
CygwinPath = s;
break;
}
}
n.DeleteArrays();
LFile::Path p(s, "bin\\make.exe");
if (p.Exists())
return p.GetFull();
#endif
}
else
{
if (Compiler == MingW)
{
// Have a look in the default spot first...
const char *Def = "C:\\MinGW\\msys\\1.0\\bin\\make.exe";
if (LFileExists(Def))
{
return Def;
}
}
for (int i=0; iGetApp()->GetOptions()->GetValue(OPT_Jobs, Jobs) || Jobs.CastInt32() < 1)
Jobs = 2;
auto Pos = InitDir.RFind(DIR_STR);
if (Pos)
InitDir.Length(Pos);
LString TmpArgs, Include, Lib, LibPath, Path;
if (Compiler == VisualStudio)
{
// TmpArgs.Printf("\"%s\" /make \"All - Win32 Debug\"", Makefile.Get());
LString BuildConf = "All - Win32 Debug";
if (BuildConfigs.Length())
{
auto Key = toString(Config);
for (size_t i=0; i= 0)
{
if (!BuildConf || (c.Find("x64") >= 0 && BuildConf.Find("x64") < 0))
BuildConf = c;
}
}
}
TmpArgs.Printf("\"%s\" %s \"%s\"", Makefile.Get(), Clean ? "/Clean" : "/Build", BuildConf.Get());
}
else if (Compiler == Nmake)
{
const char *DefInc[] = {
"C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\INCLUDE",
"C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\ATLMFC\\INCLUDE",
"C:\\Program Files (x86)\\Windows Kits\\8.1\\include\\shared",
"C:\\Program Files (x86)\\Windows Kits\\8.1\\include\\um",
"C:\\Program Files (x86)\\Windows Kits\\8.1\\include\\winrt"
};
LString f;
#define ADD_PATHS(out, in) \
for (unsigned i=0; iGetChildTag("name") : NULL;
if (c)
Conf = c->GetContent();
}
}
TmpArgs.Printf("\"%s\" %s %s -log warnings", Makefile.Get(), Clean ? "-clean" : "-make", Conf.Get());
}
else if (Compiler == Xcode)
{
LString::Array Configs;
Configs.SetFixedLength(false);
LString a;
a.Printf("-list -project \"%s\"", Makefile.Get());
LSubProcess Ls(Exe, a);
if (Ls.Start())
{
LStringPipe o;
Ls.Communicate(&o);
auto key = "Build Configurations:";
auto lines = o.NewLStr().SplitDelimit("\n");
int inKey = -1;
for (auto l: lines)
{
int ws = 0;
for (int i=0; i=0)
inKey = ws;
else if (inKey>=0)
{
if (ws>inKey) { Configs.New() = l.Strip(); }
else { inKey = -1; }
}
// printf("%s\n", l.Get());
}
}
auto Config = Configs.Length() > 0 ? Configs[0] : LString("Debug");
TmpArgs.Printf("-project \"%s\" -configuration %s", Makefile.Get(), Config.Get());
}
else
{
if (Compiler == Cygwin)
{
LFile::Path p(CygwinPath, "bin");
Path = p.GetFull();
}
if (Compiler == MingW)
{
LString a;
char *Dir = strrchr(MakePath, DIR_CHAR);
#if 1
TmpArgs.Printf("/C \"%s\"", Exe.Get());
/* As of MSYS v1.0.18 the support for multiple jobs causes make to hang:
http://sourceforge.net/p/mingw/bugs/1950/
http://mingw-users.1079350.n2.nabble.com/MSYS-make-freezes-td7579038.html
Apparently it'll be "fixed" in v1.0.19. We'll see. >:-(
if (Jobs.CastInt32() > 1)
a.Print(" -j %i", Jobs.CastInt32());
*/
a.Printf(" -f \"%s\"", Dir ? Dir + 1 : MakePath.Get());
TmpArgs += a;
#else
TmpArgs.Printf("/C set");
#endif
Exe = "C:\\Windows\\System32\\cmd.exe";
}
else
{
if (Jobs.CastInt32())
TmpArgs.Printf("-j %i -f \"%s\"", Jobs.CastInt32(), MakePath.Get());
else
TmpArgs.Printf("-f \"%s\"", MakePath.Get());
}
if (Clean)
{
if (All)
TmpArgs += " cleanall";
else
TmpArgs += " clean";
}
if (Config == BuildRelease)
TmpArgs += " Build=Release";
}
PostThreadEvent(AppHnd, M_SELECT_TAB, AppWnd::BuildTab);
LString Msg;
Msg.Printf("Making: %s\n", MakePath.Get());
Proj->GetApp()->PostEvent(M_APPEND_TEXT, (LMessage::Param)NewStr(Msg), AppWnd::BuildTab);
LgiTrace("%s %s\n", Exe.Get(), TmpArgs.Get());
if (SubProc.Reset(new LSubProcess(Exe, TmpArgs)))
{
SubProc->SetNewGroup(false);
SubProc->SetInitFolder(InitDir);
if (Include)
SubProc->SetEnvironment("INCLUDE", Include);
if (Lib)
SubProc->SetEnvironment("LIB", Lib);
if (LibPath)
SubProc->SetEnvironment("LIBPATHS", LibPath);
if (Path)
{
LString Cur = getenv("PATH");
LString New = Cur + LGI_PATH_SEPARATOR + Path;
SubProc->SetEnvironment("PATH", New);
}
// SubProc->SetEnvironment("DLL", "1");
if (Compiler == MingW)
SubProc->SetEnvironment("PATH", "c:\\MingW\\bin;C:\\MinGW\\msys\\1.0\\bin;%PATH%");
if ((Status = SubProc->Start(true, false)))
{
// Read all the output
char Buf[256];
ssize_t rd;
while ( (rd = SubProc->Read(Buf, sizeof(Buf))) > 0 )
{
Write(Buf, rd);
}
uint32_t ex = SubProc->Wait();
Print("Make exited with %i (0x%x)\n", ex, ex);
if (Compiler == IAR &&
ex == 0 &&
PostBuild.Length())
{
for (auto Cmd : PostBuild)
{
auto p = Cmd.Split(" ", 1);
if (p[0].Equals("cd"))
{
if (p.Length() > 1)
FileDev->SetCurrentFolder(p[1]);
else
LAssert(!"No folder for cd?");
}
else
{
LSubProcess PostCmd(p[0], p.Length() > 1 ? p[1] : LString());
if (PostCmd.Start(true, false))
{
char Buf[256];
ssize_t rd;
while ( (rd = PostCmd.Read(Buf, sizeof(Buf))) > 0 )
{
Write(Buf, rd);
}
}
}
}
}
}
else
{
// Create a nice error message.
LString ErrStr = LErrorCodeToString(SubProc->GetErrorCode());
if (ErrStr)
{
char *e = ErrStr.Get() + ErrStr.Length();
while (e > ErrStr && strchr(" \t\r\n.", e[-1]))
*(--e) = 0;
}
sprintf_s(ErrBuf, sizeof(ErrBuf), "Running make failed with %i (%s)\n",
SubProc->GetErrorCode(),
ErrStr.Get());
Err = ErrBuf;
}
}
}
else
{
Err = "Couldn't find program to build makefile.";
LgiTrace("%s,%i - %s.\n", _FL, Err);
}
AppWnd *w = Proj->GetApp();
if (w)
{
w->PostEvent(M_BUILD_DONE);
if (Err)
Proj->GetApp()->PostEvent(M_BUILD_ERR, 0, (LMessage::Param)NewStr(Err));
}
else LAssert(0);
return 0;
}
//////////////////////////////////////////////////////////////////////////////////
IdeProject::IdeProject(AppWnd *App) : IdeCommon(NULL)
{
Project = this;
d = new IdeProjectPrivate(App, this);
Tag = NewStr("Project");
}
IdeProject::~IdeProject()
{
d->App->OnProjectDestroy(this);
LXmlTag::Empty(true);
DeleteObj(d);
}
bool IdeProject::OnNode(const char *Path, ProjectNode *Node, bool Add)
{
if (!Path || !Node)
{
LAssert(0);
return false;
}
char Full[MAX_PATH_LEN];
if (LIsRelativePath(Path))
{
LAutoString Base = GetBasePath();
if (LMakePath(Full, sizeof(Full), Base, Path))
{
Path = Full;
}
}
bool Status = false;
if (Add)
Status = d->Nodes.Add(Path, Node);
else
Status = d->Nodes.Delete(Path);
LString p = Path;
if (Status && CheckExists(p))
d->App->OnNode(p, Node, Add ? FindSymbolSystem::FileAdd : FindSymbolSystem::FileRemove);
return Status;
}
void IdeProject::ShowFileProperties(const char *File)
{
ProjectNode *Node = NULL;
// char *fp = FindFullPath(File, &Node);
if (Node)
{
Node->OnProperties();
}
}
const char *IdeProject::GetFileComment()
{
return d->Settings.GetStr(ProjCommentFile);
}
const char *IdeProject::GetFunctionComment()
{
return d->Settings.GetStr(ProjCommentFunction);
}
IdeProject *IdeProject::GetParentProject()
{
return d->ParentProject;
}
void IdeProject::SetParentProject(IdeProject *p)
{
d->ParentProject = p;
}
bool IdeProject::GetChildProjects(List &c)
{
CollectAllSubProjects(c);
return c.Length() > 0;
}
bool IdeProject::RelativePath(LString &Out, const char *In, bool Debug)
{
if (!In)
return false;
auto Base = GetBasePath();
if (!Base)
return false;
CheckExists(Base);
if (Debug) LgiTrace("XmlBase='%s'\n In='%s'\n", Base.Get(), In);
LToken b(Base, DIR_STR);
LToken i(In, DIR_STR);
char out[MAX_PATH_LEN] = "";
if (Debug) LgiTrace("Len %i-%i\n", b.Length(), i.Length());
auto ILen = i.Length() + (LDirExists(In) ? 0 : 1);
auto Max = MIN(b.Length(), ILen);
int Common = 0;
for (; Common < Max; Common++)
{
#ifdef WIN32
#define StrCompare stricmp
#else
#define StrCompare strcmp
#endif
if (Debug) LgiTrace("Cmd '%s'-'%s'\n", b[Common], i[Common]);
if (StrCompare(b[Common], i[Common]) != 0)
{
break;
}
}
if (Debug) LgiTrace("Common=%i\n", Common);
if (Common > 0)
{
if (Common < b.Length())
{
out[0] = 0;
auto Back = b.Length() - Common;
if (Debug) LgiTrace("Back=%i\n", (int)Back);
for (int n=0; nSettings.GetStr(ProjExe);
LString Exe;
if (!PExe)
{
// Use the default exe name?
Exe = GetExecutable(GetCurrentPlatform());
if (Exe)
{
printf("Exe='%s'\n", Exe.Get());
PExe = Exe;
}
}
if (!PExe)
return false;
if (LIsRelativePath(PExe))
{
auto Base = GetBasePath();
if (Base)
LMakePath(Path, Len, Base, PExe);
else
return false;
}
else
{
strcpy_s(Path, Len, PExe);
}
return true;
}
LString IdeProject::GetMakefile(IdePlatform Platform)
{
const char *PMakefile = d->Settings.GetStr(ProjMakefile, NULL, Platform);
if (!PMakefile)
return LString();
LString Path;
if (LIsRelativePath(PMakefile))
{
auto Base = GetBasePath();
if (Base)
{
char p[MAX_PATH_LEN];
LMakePath(p, sizeof(p), Base, PMakefile);
Path = p;
}
}
else
{
Path = PMakefile;
}
return Path;
}
void IdeProject::Clean(bool All, BuildConfig Config)
{
if (!d->Thread &&
d->Settings.GetStr(ProjMakefile))
{
auto m = GetMakefile(PlatformCurrent);
if (m)
{
CheckExists(m);
d->Thread.Reset(new BuildThread(this, m, true, Config, All, sizeof(ssize_t)*8));
}
}
}
char *QuoteStr(char *s)
{
LStringPipe p(256);
while (s && *s)
{
if (*s == ' ')
{
p.Push("\\ ", 2);
}
else p.Push(s, 1);
s++;
}
return p.NewStr();
}
class ExecuteThread : public LThread, public LStream, public LCancel
{
IdeProject *Proj;
LString Exe, Args, Path;
int Len;
ExeAction Act;
int AppHnd;
public:
ExecuteThread(IdeProject *proj, const char *exe, const char *args, char *path, ExeAction act) : LThread("ExecuteThread")
{
Len = 32 << 10;
Proj = proj;
Act = act;
Exe = exe;
Args = args;
Path = path;
DeleteOnExit = true;
AppHnd = proj->GetApp()->AddDispatch();
Run();
}
~ExecuteThread()
{
Cancel();
while (!IsExited())
LSleep(1);
}
int Main() override
{
PostThreadEvent(AppHnd, M_SELECT_TAB, AppWnd::OutputTab);
PostThreadEvent(AppHnd, M_APPEND_TEXT, 0, AppWnd::OutputTab);
if (Exe)
{
if (Act == ExeDebug)
{
LSubProcess sub("kdbg", Exe);
if (Path)
sub.SetInitFolder(Path);
if (sub.Start())
sub.Communicate(this, NULL, this);
}
else if (Act == ExeValgrind)
{
#ifdef LINUX
LString ExePath = Proj->GetExecutable(GetCurrentPlatform());
if (ExePath)
{
char Path[MAX_PATH_LEN];
char *ExeLeaf = LGetLeaf(Exe);
strcpy_s(Path, sizeof(Path), ExeLeaf ? ExeLeaf : Exe.Get());
LTrimDir(Path);
char *Term = 0;
char *WorkDir = 0;
char *Execute = 0;
switch (LGetWindowManager())
{
case WM_Kde:
Term = "konsole";
WorkDir = "--workdir ";
Execute = "-e";
break;
case WM_Gnome:
Term = "gnome-terminal";
WorkDir = "--working-directory=";
Execute = "-x";
break;
}
if (Term && WorkDir && Execute)
{
char *e = QuoteStr(ExePath);
char *p = QuoteStr(Path);
char *a = Proj->GetExeArgs() ? Proj->GetExeArgs() : (char*)"";
char Args[512];
sprintf(Args,
"%s%s "
"--noclose "
"%s valgrind --tool=memcheck --num-callers=20 %s %s",
WorkDir,
p,
Execute,
e, a);
LExecute(Term, Args);
}
}
#endif
}
else
{
LSubProcess sub(Exe, Args);
if (Path)
sub.SetInitFolder(Path);
if (sub.Start())
sub.Communicate(this, NULL, this);
}
}
return 0;
}
ssize_t Write(const void *Buffer, ssize_t Size, int Flags = 0) override
{
if (Len <= 0)
return 0;
PostThreadEvent(AppHnd, M_APPEND_TEXT, (LMessage::Param)NewStr((char*)Buffer, Size), AppWnd::OutputTab);
Len -= Size;
return Size;
}
};
LDebugContext *IdeProject::Execute(ExeAction Act, LString *ErrMsg)
{
auto Base = GetBasePath();
if (!Base)
{
if (ErrMsg) *ErrMsg = "No base path for project.";
return NULL;
}
char e[MAX_PATH_LEN];
if (!GetExePath(e, sizeof(e)))
{
if (ErrMsg) *ErrMsg = "GetExePath failed.";
return NULL;
}
if (!LFileExists(e))
{
if (ErrMsg) ErrMsg->Printf("Executable '%s' doesn't exist.\n", e);
return NULL;
}
const char *Args = d->Settings.GetStr(ProjArgs);
const char *Env = d->Settings.GetStr(ProjEnv);
LString InitDir = d->Settings.GetStr(ProjInitDir);
int RunAsAdmin = d->Settings.GetInt(ProjDebugAdmin);
#ifndef HAIKU
if (Act == ExeDebug)
{
if (InitDir && LIsRelativePath(InitDir))
{
LFile::Path p(Base);
p += InitDir;
InitDir = p.GetFull();
}
return new LDebugContext(d->App, this, e, Args, RunAsAdmin != 0, Env, InitDir);
}
#endif
new ExecuteThread( this,
e,
Args,
Base,
#if defined(HAIKU) || defined(WINDOWS)
ExeRun // No gdb or valgrind
#else
Act
#endif
);
return NULL;
}
bool IdeProject::IsMakefileAScript()
{
auto m = GetMakefile(PlatformCurrent);
if (m)
{
auto Ext = LGetExtension(m);
if (!Stricmp(Ext, "py"))
{
// Not a makefile but a build script... can't update.
return true;
}
}
return false;
}
bool IdeProject::IsMakefileUpToDate()
{
if (IsMakefileAScript())
return true; // We can't know if it's up to date...
List Proj;
GetChildProjects(Proj);
Proj.Insert(this);
for (auto p: Proj)
{
// Is the project file modified after the makefile?
auto Proj = p->GetFullPath();
uint64 ProjModTime = 0, MakeModTime = 0;
LDirectory dir;
if (dir.First(Proj))
{
ProjModTime = dir.GetLastWriteTime();
dir.Close();
}
auto m = p->GetMakefile(PlatformCurrent);
if (!m)
{
d->App->GetBuildLog()->Print("Error: no makefile? (%s:%i)\n", _FL);
break;
}
auto Ext = LGetExtension(m);
if (!Stricmp(Ext, "py"))
{
// Not a makefile but a build script... can't update.
return true;
}
if (dir.First(m))
{
MakeModTime = dir.GetLastWriteTime();
dir.Close();
}
// printf("Proj=%s - Timestamps " LGI_PrintfInt64 " - " LGI_PrintfInt64 "\n", Proj.Get(), ProjModTime, MakeModTime);
if (ProjModTime != 0 &&
MakeModTime != 0 &&
ProjModTime > MakeModTime)
{
// Need to rebuild the makefile...
return false;
}
}
return true;
}
bool IdeProject::FindDuplicateSymbols()
{
LStream *Log = d->App->GetBuildLog();
Log->Print("FindDuplicateSymbols starting...\n");
List Proj;
CollectAllSubProjects(Proj);
Proj.Insert(this);
int Lines = 0;
LHashTbl,int64> Map(200000);
int Found = 0;
for (auto p: Proj)
{
LString s = p->GetExecutable(GetCurrentPlatform());
if (s)
{
LString Args;
Args.Printf("--print-size --defined-only -C %s", s.Get());
LSubProcess Nm("nm", Args);
if (Nm.Start(true, false))
{
char Buf[256];
LStringPipe q;
for (ssize_t Rd = 0; (Rd = Nm.Read(Buf, sizeof(Buf))); )
q.Write(Buf, Rd);
LString::Array a = q.NewLStr().SplitDelimit("\r\n");
LHashTbl,bool> Local(200000);
for (auto &Ln: a)
{
LString::Array p = Ln.SplitDelimit(" \t", 3);
if (!Local.Find(p.Last()))
{
Local.Add(p.Last(), true);
// const char *Sz = p[1];
int64 Ours = p[1].Int(16);
int64 Theirs = Map.Find(p.Last());
if (Theirs >= 0)
{
if (Ours != Theirs)
{
if (Found++ < 100)
Log->Print(" %s (" LPrintfInt64 " -> " LPrintfInt64 ")\n",
p.Last().Get(),
Ours, Theirs);
}
}
else if (Ours >= 0)
{
Map.Add(p.Last(), Ours);
}
else
{
printf("Bad line: %s\n", Ln.Get());
}
}
Lines++;
}
}
}
else printf("%s:%i - GetExecutable failed.\n", _FL);
}
/*
char *Sym;
for (int Count = Map.First(&Sym); Count; Count = Map.Next(&Sym))
{
if (Count > 1)
Log->Print(" %i: %s\n", Count, Sym);
}
*/
Log->Print("FindDuplicateSymbols finished (%i lines)\n", Lines);
return false;
}
bool IdeProject::FixMissingFiles()
{
FixMissingFilesDlg(this);
return true;
}
void IdeProject::Build(bool All, BuildConfig Config)
{
if (d->Thread)
{
d->App->GetBuildLog()->Print("Error: Already building (%s:%i)\n", _FL);
return;
}
auto m = GetMakefile(PlatformCurrent);
CheckExists(m);
if (!m)
{
d->App->GetBuildLog()->Print("Error: no makefile? (%s:%i)\n", _FL);
return;
}
if (GetApp())
GetApp()->PostEvent(M_APPEND_TEXT, 0, 0);
SetClean([&](bool ok)
{
if (!ok)
return;
if (!IsMakefileUpToDate())
CreateMakefile(GetCurrentPlatform(), true);
else
// Start the build thread...
d->Thread.Reset
(
new BuildThread
(
this,
m,
false,
Config,
All,
sizeof(size_t)*8
)
);
});
}
void IdeProject::StopBuild()
{
d->Thread.Reset();
}
bool IdeProject::Serialize(bool Write)
{
return true;
}
AppWnd *IdeProject::GetApp()
{
return d->App;
}
const char *IdeProject::GetIncludePaths()
{
return d->Settings.GetStr(ProjIncludePaths);
}
const char *IdeProject::GetPreDefinedValues()
{
return d->Settings.GetStr(ProjDefines);
}
const char *IdeProject::GetExeArgs()
{
return d->Settings.GetStr(ProjArgs);
}
LString IdeProject::GetExecutable(IdePlatform Platform)
{
LString Bin = d->Settings.GetStr(ProjExe, NULL, Platform);
auto TargetType = d->Settings.GetStr(ProjTargetType, NULL, Platform);
auto Base = GetBasePath();
if (Bin)
{
if (LIsRelativePath(Bin) && Base)
{
char p[MAX_PATH_LEN];
if (LMakePath(p, sizeof(p), Base, Bin))
Bin = p;
}
return Bin;
}
// Create binary name from target:
auto Target = GetTargetName(Platform);
if (Target)
{
bool IsLibrary = Stristr(TargetType, "library");
int BuildMode = d->App->GetBuildMode();
const char *Name = BuildMode ? "Release" : "Debug";
const char *Postfix = BuildMode ? "" : "d";
switch (Platform)
{
case PlatformWin:
{
if (IsLibrary)
Bin.Printf("%s%s.dll", Target.Get(), Postfix);
else
Bin = Target;
break;
}
case PlatformMac:
{
if (IsLibrary)
Bin.Printf("lib%s%s.dylib", Target.Get(), Postfix);
else
Bin = Target;
break;
}
case PlatformLinux:
case PlatformHaiku:
{
if (IsLibrary)
Bin.Printf("lib%s%s.so", Target.Get(), Postfix);
else
Bin = Target;
break;
}
default:
{
LAssert(0);
printf("%s:%i - Unknown platform.\n", _FL);
return LString();
}
}
// Find the actual file...
if (!Base)
{
printf("%s:%i - GetBasePath failed.\n", _FL);
return LString();
}
char Path[MAX_PATH_LEN];
LMakePath(Path, sizeof(Path), Base, Name);
LMakePath(Path, sizeof(Path), Path, Bin);
if (LFileExists(Path))
Bin = Path;
else
printf("%s:%i - '%s' doesn't exist.\n", _FL, Path);
return Bin;
}
return LString();
}
const char *IdeProject::GetFileName()
{
return d->FileName;
}
int IdeProject::GetPlatforms()
{
return PLATFORM_ALL;
}
LAutoString IdeProject::GetFullPath()
{
LAutoString Status;
if (!d->FileName)
{
// LAssert(!"No path.");
return Status;
}
LArray sections;
IdeProject *proj = this;
while ( proj &&
proj->GetFileName() &&
LIsRelativePath(proj->GetFileName()))
{
sections.AddAt(0, proj->GetFileName());
proj = proj->GetParentProject();
}
if (!proj)
{
// LAssert(!"All projects have a relative path?");
return Status; // No absolute path in the parent projects?
}
char p[MAX_PATH_LEN];
strcpy_s(p, sizeof(p), proj->GetFileName()); // Copy the base path
if (sections.Length() > 0)
LTrimDir(p); // Trim off the filename
for (int i=0; iFileName.Empty();
d->UserFile.Empty();
d->App->GetTree()->Insert(this);
ProjectNode *f = new ProjectNode(this);
if (f)
{
f->SetName("Source");
f->SetType(NodeDir);
InsertTag(f);
}
f = new ProjectNode(this);
if (f)
{
f->SetName("Headers");
f->SetType(NodeDir);
InsertTag(f);
}
d->Settings.Set(ProjEditorTabSize, 4);
d->Settings.Set(ProjEditorIndentSize, 4);
d->Settings.Set(ProjEditorUseHardTabs, true);
d->Dirty = true;
Expanded(true);
}
ProjectStatus IdeProject::OpenFile(const char *FileName)
{
auto Log = d->App->GetBuildLog();
LProfile Prof("IdeProject::OpenFile");
Prof.HideResultsIfBelow(1000);
Empty();
Prof.Add("Init");
d->UserNodeFlags.Empty();
if (LIsRelativePath(FileName))
{
char p[MAX_PATH_LEN];
getcwd(p, sizeof(p));
LMakePath(p, sizeof(p), p, FileName);
d->FileName = p;
}
else
{
d->FileName = FileName;
}
d->UserFile = d->FileName + "." + LCurrentUserName();
if (!d->FileName)
{
Log->Print("%s:%i - No filename.\n", _FL);
return OpenError;
}
Prof.Add("FileOpen");
LFile f;
LString FullPath = d->FileName.Get();
if (!CheckExists(FullPath) ||
!f.Open(FullPath, O_READWRITE))
{
Log->Print("%s:%i - Error: Can't open '%s'.\n", _FL, FullPath.Get());
return OpenError;
}
Prof.Add("Xml");
LXmlTree x;
LXmlTag r;
if (!x.Read(&r, &f))
{
Log->Print("%s:%i - Error: Can't read XML: %s\n", _FL, x.GetErrorMsg());
return OpenError;
}
Prof.Add("Progress Setup");
#if DEBUG_OPEN_PROGRESS
int64 Nodes = r.CountTags();
LProgressDlg Prog(d->App, 1000);
Prog.SetDescription("Loading project...");
Prog.SetLimits(0, Nodes);
Prog.SetYieldTime(1000);
Prog.SetAlwaysOnTop(true);
#endif
Prof.Add("UserFile");
if (LFileExists(d->UserFile))
{
LFile Uf;
if (Uf.Open(d->UserFile, O_READ))
{
LString::Array Ln = Uf.Read().SplitDelimit("\n");
for (unsigned i=0; iUserNodeFlags.Add((int)p[0].Int(), (int)p[1].Int(16));
}
}
}
if (!r.IsTag("Project"))
{
Log->Print("%s:%i - No 'Project' tag.\n", _FL);
return OpenError;
}
Prof.Add("OnOpen");
bool Ok = OnOpen(
#if DEBUG_OPEN_PROGRESS
&Prog,
#else
NULL,
#endif
&r);
#if DEBUG_OPEN_PROGRESS
if (Prog.IsCancelled())
return OpenCancel;
else
#endif
if (!Ok)
return OpenError;
Prof.Add("Insert");
d->App->GetTree()->Insert(this);
Expanded(true);
Prof.Add("Serialize");
d->Settings.Serialize(&r, false /* read */);
return OpenOk;
}
bool IdeProject::SaveFile()
{
auto Full = GetFullPath();
if (ValidStr(Full) && d->Dirty)
{
LFile f;
if (f.Open(Full, O_WRITE))
{
f.SetSize(0);
LXmlTree x;
d->Settings.Serialize(this, true /* write */);
if (x.Write(this, &f))
d->Dirty = false;
else
LgiTrace("%s:%i - Failed to write XML.\n", _FL);
}
else LgiTrace("%s:%i - Couldn't open '%s' for writing.\n", _FL, Full.Get());
}
if (d->UserFileDirty)
{
LFile f;
LAssert(d->UserFile.Get());
if (f.Open(d->UserFile, O_WRITE))
{
f.SetSize(0);
// Save user file details..
// int Id;
// for (int Flags = d->UserNodeFlags.First(&Id); Flags >= 0; Flags = d->UserNodeFlags.Next(&Id))
for (auto i : d->UserNodeFlags)
{
f.Print("%i,%x\n", i.key, i.value);
}
d->UserFileDirty = false;
}
}
printf("\tIdeProject::SaveFile %i %i\n", d->Dirty, d->UserFileDirty);
return !d->Dirty &&
!d->UserFileDirty;
}
void IdeProject::SetDirty()
{
d->Dirty = true;
d->App->OnProjectChange();
}
void IdeProject::SetUserFileDirty()
{
d->UserFileDirty = true;
}
bool IdeProject::GetExpanded(int Id)
{
int f = d->UserNodeFlags.Find(Id);
return f >= 0 ? f : false;
}
void IdeProject::SetExpanded(int Id, bool Exp)
{
if (d->UserNodeFlags.Find(Id) != (int)Exp)
{
d->UserNodeFlags.Add(Id, Exp);
SetUserFileDirty();
}
}
int IdeProject::AllocateId()
{
return d->NextNodeId++;
}
template
bool CheckExists(LAutoString Base, T &p, Fn Setter, bool Debug)
{
LFile::Path Full;
bool WasRel = LIsRelativePath(p);
if (WasRel)
{
Full = Base.Get();
Full += p.Get();
}
else Full = p.Get();
bool Ret = Full.Exists();
if (!Ret)
{
// Is the case wrong?
for (int i=1; i%s\n", i, Leaf.Get(), dir.GetName());
Leaf = dir.GetName();
Matched = true;
break;
}
}
if (!Matched)
break;
}
}
if ((Ret = Full.Exists()))
{
LString Old = p.Get();
if (WasRel)
{
auto r = LMakeRelativePath(Base, Full);
Setter(p, r);
}
else
{
Setter(p, Full.GetFull());
}
if (Debug)
printf("%s -> %s\n", Old.Get(), p.Get());
}
}
if (Debug)
printf("CheckExists '%s' = %i\n", Full.GetFull().Get(), Ret);
return Ret;
}
bool IdeProject::CheckExists(LString &p, bool Debug)
{
return ::CheckExists(GetBasePath(), p, [](LString &o, const char *i) {
o = i;
}, Debug);
}
bool IdeProject::CheckExists(LAutoString &p, bool Debug)
{
return ::CheckExists(GetBasePath(), p, [](LAutoString &o, const char *i) {
o.Reset(NewStr(i));
}, Debug);
}
bool IdeProject::GetClean()
{
for (auto i: *this)
{
ProjectNode *p = dynamic_cast(i);
if (p && !p->GetClean())
return false;
}
return !d->Dirty && !d->UserFileDirty;
}
void IdeProject::SetClean(std::function OnDone)
{
auto CleanNodes = [this, OnDone]()
{
printf("IdeProject.SetClean.CleanNodes\n");
for (auto i: *this)
{
ProjectNode *p = dynamic_cast(i);
if (!p) break;
p->SetClean();
}
if (OnDone)
OnDone(true);
};
printf("IdeProject.SetClean dirty=%i,%i validfile=%i\n", d->Dirty, d->UserFileDirty, ValidStr(d->FileName));
if (d->Dirty || d->UserFileDirty)
{
if (ValidStr(d->FileName))
SaveFile();
else
{
auto s = new LFileSelect;
s->Parent(Tree);
s->Name("Project.xml");
s->Save([this, OnDone, CleanNodes](auto s, auto ok)
{
printf("IdeProject.SetClean.FileSelect ok=%i\n", ok);
if (ok)
{
d->FileName = s->Name();
d->UserFile = d->FileName + "." + LCurrentUserName();
d->App->OnFile(d->FileName, true);
Update();
CleanNodes();
}
else
{
if (OnDone)
OnDone(false);
}
delete s;
});
return;
}
}
CleanNodes();
}
const char *IdeProject::GetText(int Col)
{
if (d->FileName)
{
char *s = strrchr(d->FileName, DIR_CHAR);
return s ? s + 1 : d->FileName.Get();
}
return Untitled;
}
int IdeProject::GetImage(int Flags)
{
return 0;
}
void IdeProject::Empty()
{
LXmlTag *t;
while (Children.Length() > 0 &&
(t = Children[0]))
{
ProjectNode *n = dynamic_cast(t);
if (n)
{
n->Remove();
}
DeleteObj(t);
}
}
LXmlTag *IdeProject::Create(char *Tag)
{
if (!stricmp(Tag, TagSettings))
return NULL;
return new ProjectNode(this);
}
void IdeProject::OnMouseClick(LMouse &m)
{
if (m.IsContextMenu())
{
LSubMenu Sub;
Sub.AppendItem("New Folder", IDM_NEW_FOLDER);
Sub.AppendItem("New Web Folder", IDM_WEB_FOLDER);
Sub.AppendSeparator();
Sub.AppendItem("Build", IDM_BUILD);
Sub.AppendItem("Clean Project", IDM_CLEAN_PROJECT);
Sub.AppendItem("Clean All", IDM_CLEAN_ALL);
Sub.AppendItem("Rebuild Project", IDM_REBUILD_PROJECT);
Sub.AppendItem("Rebuild All", IDM_REBUILD_ALL);
Sub.AppendSeparator();
Sub.AppendItem("Sort Children", IDM_SORT_CHILDREN);
Sub.AppendSeparator();
Sub.AppendItem("Settings", IDM_SETTINGS, true);
Sub.AppendItem("Insert Dependency", IDM_INSERT_DEP);
m.ToScreen();
auto c = _ScrollPos();
m.x -= c.x;
m.y -= c.y;
switch (Sub.Float(Tree, m.x, m.y))
{
case IDM_NEW_FOLDER:
{
auto Name = new LInput(Tree, "", "Name:", AppName);
Name->DoModal([this, Name](auto d, auto code)
{
if (code)
GetSubFolder(this, Name->GetStr(), true);
delete d;
});
break;
}
case IDM_WEB_FOLDER:
{
WebFldDlg *Dlg = new WebFldDlg(Tree, 0, 0, 0);
Dlg->DoModal([&](auto d, auto code)
{
if (Dlg->Ftp && Dlg->Www)
{
IdeCommon *f = GetSubFolder(this, Dlg->Name, true);
if (f)
{
f->SetAttr(OPT_Ftp, Dlg->Ftp);
f->SetAttr(OPT_Www, Dlg->Www);
}
}
delete Dlg;
});
break;
}
case IDM_BUILD:
{
StopBuild();
Build(true, d->App->GetBuildMode());
break;
}
case IDM_CLEAN_PROJECT:
{
Clean(false, d->App->GetBuildMode());
break;
}
case IDM_CLEAN_ALL:
{
Clean(true, d->App->GetBuildMode());
break;
}
case IDM_REBUILD_PROJECT:
{
StopBuild();
Clean(false, d->App->GetBuildMode());
Build(false, d->App->GetBuildMode());
break;
}
case IDM_REBUILD_ALL:
{
StopBuild();
Clean(true, d->App->GetBuildMode());
Build(true, d->App->GetBuildMode());
break;
}
case IDM_SORT_CHILDREN:
{
SortChildren();
Project->SetDirty();
break;
}
case IDM_SETTINGS:
{
d->Settings.Edit(Tree, [&]()
{
SetDirty();
});
break;
}
case IDM_INSERT_DEP:
{
LFileSelect *s = new LFileSelect;
s->Parent(Tree);
s->Type("Project", "*.xml");
s->Open([&](auto s, bool ok)
{
if (!ok)
return;
ProjectNode *New = new ProjectNode(this);
if (New)
{
New->SetFileName(s->Name());
New->SetType(NodeDependancy);
InsertTag(New);
SetDirty();
}
delete s;
});
break;
}
}
}
}
char *IdeProject::FindFullPath(const char *File, ProjectNode **Node)
{
char *Full = 0;
for (auto i:*this)
{
ProjectNode *c = dynamic_cast(i);
if (!c) break;
ProjectNode *n = c->FindFile(File, &Full);
if (n)
{
if (Node)
*Node = n;
break;
}
}
return Full;
}
bool IdeProject::HasNode(ProjectNode *Node)
{
for (auto i:*this)
{
ProjectNode *c = dynamic_cast(i);
if (!c) break;
if (c->HasNode(Node))
return true;
}
return false;
}
bool IdeProject::GetAllNodes(LArray &Nodes)
{
for (auto i:*this)
{
ProjectNode *c = dynamic_cast(i);
if (!c) break;
c->AddNodes(Nodes);
}
return true;
}
bool IdeProject::InProject(bool FuzzyMatch, const char *Path, bool Open, IdeDoc **Doc)
{
if (!Path)
return false;
// Search complete path first...
ProjectNode *n = d->Nodes.Find(Path);
if (!n && FuzzyMatch)
{
// No match, do partial matching.
const char *Leaf = LGetLeaf(Path);
auto PathLen = strlen(Path);
auto LeafLen = strlen(Leaf);
uint32_t MatchingScore = 0;
// Traverse all nodes and try and find the best fit.
// const char *p;
// for (ProjectNode *Cur = d->Nodes.First(&p); Cur; Cur = d->Nodes.Next(&p))
for (auto Cur : d->Nodes)
{
int CurPlatform = Cur.value->GetPlatforms();
uint32_t Score = 0;
if (stristr(Cur.key, Path))
{
Score += PathLen;
}
else if (stristr(Cur.key, Leaf))
{
Score += LeafLen;
}
const char *pLeaf = LGetLeaf(Cur.key);
if (pLeaf && !stricmp(pLeaf, Leaf))
{
Score |= 0x40000000;
}
if (Score && (CurPlatform & PLATFORM_CURRENT) != 0)
{
Score |= 0x80000000;
}
if (Score > MatchingScore)
{
MatchingScore = Score;
n = Cur.value;
}
}
}
if (n && Doc)
{
*Doc = n->Open();
}
return n != 0;
}
char *GetQuotedStr(char *Str)
{
char *s = strchr(Str, '\"');
if (s)
{
s++;
char *e = strchr(s, '\"');
if (e)
{
return NewStr(s, e - s);
}
}
return 0;
}
void IdeProject::ImportDsp(const char *File)
{
if (File && LFileExists(File))
{
char Base[256];
strcpy(Base, File);
LTrimDir(Base);
char *Dsp = LReadTextFile(File);
if (Dsp)
{
LToken Lines(Dsp, "\r\n");
IdeCommon *Current = this;
bool IsSource = false;
for (int i=0; iGetSubFolder(this, Folder, true);
if (Sub)
{
Current = Sub;
}
DeleteArray(Folder);
}
}
else if (strnicmp(L, "# End Group", 11) == 0)
{
IdeCommon *Parent = dynamic_cast(Current->GetParent());
if (Parent)
{
Current = Parent;
}
}
else if (strnicmp(L, "# Begin Source", 14) == 0)
{
IsSource = true;
}
else if (strnicmp(L, "# End Source", 12) == 0)
{
IsSource = false;
}
else if (Current && IsSource && strncmp(L, "SOURCE=", 7) == 0)
{
ProjectNode *New = new ProjectNode(this);
if (New)
{
char *Src = 0;
if (strchr(L, '\"'))
{
Src = GetQuotedStr(L);
}
else
{
Src = NewStr(L + 7);
}
if (Src)
{
// Make absolute path
char Abs[256];
LMakePath(Abs, sizeof(Abs), Base, ToUnixPath(Src));
// Make relitive path
New->SetFileName(Src);
DeleteArray(Src);
}
Current->InsertTag(New);
SetDirty();
}
}
}
DeleteArray(Dsp);
}
}
}
IdeProjectSettings *IdeProject::GetSettings()
{
return &d->Settings;
}
bool IdeProject::BuildIncludePaths(LArray &Paths, bool Recurse, bool IncludeSystem, IdePlatform Platform)
{
List Projects;
if (Recurse)
GetChildProjects(Projects);
Projects.Insert(this, 0);
LHashTbl, bool> Map;
for (auto p: Projects)
{
LString ProjInclude = d->Settings.GetStr(ProjIncludePaths, NULL, Platform);
LAutoString Base = p->GetBasePath();
const char *Delim = ",;\r\n";
LString::Array In, Out;
LString::Array a = ProjInclude.SplitDelimit(Delim);
In = a;
if (IncludeSystem)
{
LString SysInclude = d->Settings.GetStr(ProjSystemIncludes, NULL, Platform);
a = SysInclude.SplitDelimit(Delim);
In.SetFixedLength(false);
In.Add(a);
}
for (unsigned i=0; i 1 ? a[1].Get() : NULL);
LStringPipe Buf;
if (Proc.Start())
{
Proc.Communicate(&Buf);
LString result = Buf.NewLStr();
a = result.Split(" \t\r\n");
for (int i=0; i Nodes;
if (p->GetAllNodes(Nodes))
{
auto Base = p->GetFullPath();
if (Base)
{
LTrimDir(Base);
for (auto &n: Nodes)
{
if (n->GetType() == NodeHeader && // Only look at headers.
(n->GetPlatforms() & (1 << Platform)) != 0) // Exclude files not on this platform.
{
auto f = n->GetFileName();
char p[MAX_PATH_LEN];
if (f &&
LMakePath(p, sizeof(p), Base, f))
{
char *l = strrchr(p, DIR_CHAR);
if (l)
*l = 0;
if (!Map.Find(p))
{
Map.Add(p, true);
}
}
}
}
}
}
}
// char *p;
// for (bool b = Map.First(&p); b; b = Map.Next(&p))
for (auto p : Map)
Paths.Add(p.key);
return true;
}
void IdeProjectPrivate::CollectAllFiles(LTreeNode *Base, LArray &Files, bool SubProjects, int Platform)
{
for (auto i:*Base)
{
IdeProject *Proj = dynamic_cast(i);
if (Proj)
{
if (Proj->GetParentProject() && !SubProjects)
{
continue;
}
}
else
{
ProjectNode *p = dynamic_cast(i);
if (p)
{
if (p->GetType() == NodeSrc ||
p->GetType() == NodeHeader)
{
if (p->GetPlatforms() & Platform)
{
Files.Add(p);
}
}
}
}
CollectAllFiles(i, Files, SubProjects, Platform);
}
}
LString IdeProject::GetTargetName(IdePlatform Platform)
{
LString Status;
const char *t = d->Settings.GetStr(ProjTargetName, NULL, Platform);
if (ValidStr(t))
{
// Take target name from the settings
Status = t;
}
else
{
char *s = strrchr(d->FileName, DIR_CHAR);
if (s)
{
// Generate the target executable name
char Target[MAX_PATH_LEN];
strcpy_s(Target, sizeof(Target), s + 1);
s = strrchr(Target, '.');
if (s) *s = 0;
strlwr(Target);
s = Target;
for (char *i = Target; *i; i++)
{
if (*i != '.' && *i != ' ')
{
*s++ = *i;
}
}
*s = 0;
Status = Target;
}
}
return Status;
}
LString IdeProject::GetTargetFile(IdePlatform Platform)
{
LString Target = GetTargetName(PlatformCurrent);
if (!Target)
{
LAssert(!"No target?");
return LString();
}
const char *TargetType = d->Settings.GetStr(ProjTargetType);
if (!TargetType)
{
LAssert(!"Needs a target type.");
return LString();
}
if (!stricmp(TargetType, "Executable"))
{
return Target;
}
else if (!stricmp(TargetType, "DynamicLibrary"))
{
char t[MAX_PATH_LEN];
auto DefExt = PlatformDynamicLibraryExt(Platform);
strcpy_s(t, sizeof(t), Target);
char *ext = LGetExtension(t);
if (!ext)
sprintf(t + strlen(t), ".%s", DefExt);
else if (stricmp(ext, DefExt))
strcpy(ext, DefExt);
return t;
}
else if (!stricmp(TargetType, "StaticLibrary"))
{
LString Ret;
Ret.Printf("%s.%s", Target.Get(), PlatformSharedLibraryExt(Platform));
return Ret;
}
return LString();
}
struct ProjDependency
{
bool Scanned;
LAutoString File;
ProjDependency(const char *f)
{
Scanned = false;
File.Reset(NewStr(f));
}
};
bool IdeProject::GetAllDependencies(LArray &Files, IdePlatform Platform)
{
if (!GetTree()->Lock(_FL))
return false;
LHashTbl, ProjDependency*> Deps;
LAutoString Base = GetBasePath();
// Build list of all the source files...
LArray Src;
CollectAllSource(Src, Platform);
// Get all include paths
LArray IncPaths;
BuildIncludePaths(IncPaths, false, false, Platform);
// Add all source to dependencies
for (int i=0; i Unscanned;
do
{
// Find all the unscanned dependencies
Unscanned.Length(0);
// for (ProjDependency *d = Deps.First(); d; d = Deps.Next())
for (auto d : Deps)
{
if (!d.value->Scanned)
Unscanned.Add(d.value);
}
for (int i=0; iScanned = true;
char *Src = d->File;
char Full[MAX_PATH_LEN];
if (LIsRelativePath(d->File))
{
LMakePath(Full, sizeof(Full), Base, d->File);
Src = Full;
}
LArray SrcDeps;
if (GetDependencies(Src, IncPaths, SrcDeps, Platform))
{
for (int n=0; n 0);
// for (ProjDependency *d = Deps.First(); d; d = Deps.Next())
for (auto d : Deps)
{
Files.Add(d.value->File.Release());
}
Deps.DeleteObjects();
GetTree()->Unlock();
return true;
}
bool IdeProject::GetDependencies(const char *InSourceFile, LArray &IncPaths, LArray &Files, IdePlatform Platform)
{
LString SourceFile = InSourceFile;
if (!CheckExists(SourceFile))
{
LgiTrace("%s:%i - can't read '%s'\n", _FL, SourceFile.Get());
return false;
}
LAutoString c8(LReadTextFile(SourceFile));
if (!c8)
return false;
LArray Headers;
if (!BuildHeaderList(c8, Headers, IncPaths, false))
return false;
for (int n=0; nCreateMakefile)
{
if (d->CreateMakefile->IsExited())
d->CreateMakefile.Reset();
else
{
d->App->GetBuildLog()->Print("%s:%i - Makefile thread still running.\n", _FL);
return false;
}
}
if (Platform == PlatformCurrent)
Platform = GetCurrentPlatform();
return d->CreateMakefile.Reset(new MakefileThread(d, Platform, BuildAfterwards));
}
void IdeProject::OnMakefileCreated()
{
if (d->CreateMakefile)
{
d->CreateMakefile.Reset();
if (MakefileThread::Instances == 0)
GetApp()->PostEvent(M_LAST_MAKEFILE_CREATED);
}
}
////////////////////////////////////////////////////////////////////////////////////////////
IdeTree::IdeTree() : LTree(IDC_PROJECT_TREE, 0, 0, 100, 100)
{
Hit = 0;
MultiSelect(true);
}
void IdeTree::OnCreate()
{
SetWindow(this);
}
void IdeTree::OnDragExit()
{
SelectDropTarget(0);
}
int IdeTree::WillAccept(LDragFormats &Formats, LPoint p, int KeyState)
{
static bool First = true;
Formats.SupportsFileDrops();
Formats.Supports(NODE_DROP_FORMAT);
First = false;
if (Formats.Length() == 0)
{
LgiTrace("%s:%i - No valid drop formats.\n", _FL);
return DROPEFFECT_NONE;
}
Hit = ItemAtPoint(p.x, p.y);
if (!Hit)
{
SelectDropTarget(NULL);
return DROPEFFECT_NONE;
}
if (Formats.HasFormat(LGI_FileDropFormat))
{
SelectDropTarget(Hit);
return DROPEFFECT_LINK;
}
IdeCommon *Src = dynamic_cast(Selection());
IdeCommon *Dst = dynamic_cast(Hit);
if (Src && Dst)
{
// Check this folder is not a child of the src
for (IdeCommon *n=Dst; n; n=dynamic_cast(n->GetParent()))
{
if (n == Src)
return DROPEFFECT_NONE;
}
}
// Valid target
SelectDropTarget(Hit);
return DROPEFFECT_MOVE;
}
int IdeTree::OnDrop(LArray &Data, LPoint p, int KeyState)
{
int Ret = DROPEFFECT_NONE;
SelectDropTarget(NULL);
if (!(Hit = ItemAtPoint(p.x, p.y)))
return Ret;
for (unsigned n=0; nType == GV_BINARY && Data->Value.Binary.Length == sizeof(ProjectNode*))
{
ProjectNode *Src = ((ProjectNode**)Data->Value.Binary.Data)[0];
if (Src)
{
ProjectNode *Folder = dynamic_cast(Hit);
while (Folder && Folder->GetType() != NodeDir)
Folder = dynamic_cast(Folder->GetParent());
IdeCommon *Dst = dynamic_cast(Folder?Folder:Hit);
if (Dst)
{
// Check this folder is not a child of the src
for (IdeCommon *n=Dst; n; n=dynamic_cast(n->GetParent()))
{
if (n == Src)
return DROPEFFECT_NONE;
}
// Detach
LTreeItem *i = dynamic_cast(Src);
i->Detach();
if (Src->LXmlTag::Parent)
{
LAssert(Src->LXmlTag::Parent->Children.HasItem(Src));
Src->LXmlTag::Parent->Children.Delete(Src);
}
// Attach
Src->LXmlTag::Parent = Dst;
Dst->Children.SetFixedLength(false);
Dst->Children.Add(Src);
Dst->Children.SetFixedLength(true);
Dst->Insert(Src);
// Dirty
Src->GetProject()->SetDirty();
}
Ret = DROPEFFECT_MOVE;
}
}
}
else if (dd.IsFileDrop())
{
ProjectNode *Folder = dynamic_cast(Hit);
while (Folder && Folder->GetType() > NodeDir)
Folder = dynamic_cast(Folder->GetParent());
IdeCommon *Dst = dynamic_cast(Folder?Folder:Hit);
if (Dst)
{
AddFilesProgress Prog(this);
LDropFiles Df(dd);
for (int i=0; iAddFiles(&Prog, Df[i]))
Ret = DROPEFFECT_LINK;
}
}
}
else LgiTrace("%s:%i - Unknown drop format: %s.\n", _FL, dd.Format.Get());
}
return Ret;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
AddFilesProgress::AddFilesProgress(LViewI *par)
{
v = 0;
Cancel = false;
Msg = NULL;
SetParent(par);
Ts = LCurrentTime();
LRect r(0, 0, 140, 100);
SetPos(r);
MoveSameScreen(par);
Name("Importing files...");
LString::Array a = LString(DefaultExt).SplitDelimit(",");
for (unsigned i=0; iGetCell(0, 0);
c->Add(new LTextLabel(-1, 0, 0, -1, -1, "Loaded:"));
c = t->GetCell(1, 0);
c->Add(Msg = new LTextLabel(-1, 0, 0, -1, -1, "..."));
c = t->GetCell(0, 1, true, 2);
c->TextAlign(LCss::Len(LCss::AlignRight));
c->Add(new LButton(IDCANCEL, 0, 0, -1, -1, "Cancel"));
}
int64 AddFilesProgress::Value()
{
return v;
}
void AddFilesProgress::Value(int64 val)
{
v = val;
uint64 Now = LCurrentTime();
if (Visible())
{
if (Now - Ts > 200)
{
if (Msg)
{
Msg->Value(v);
Msg->SendNotify(LNotifyTableLayoutRefresh);
}
Ts = Now;
}
}
else if (Now - Ts > 1000)
{
DoModeless();
SetAlwaysOnTop(true);
}
}
int AddFilesProgress::OnNotify(LViewI *c, LNotification n)
{
if (c->GetId() == IDCANCEL)
Cancel = true;
return 0;
}
diff --git a/src/linux/Lgi/Widgets.cpp b/src/linux/Lgi/Widgets.cpp
--- a/src/linux/Lgi/Widgets.cpp
+++ b/src/linux/Lgi/Widgets.cpp
@@ -1,270 +1,270 @@
/*hdr
** FILE: GuiDlg.cpp
** AUTHOR: Matthew Allen
** DATE: 8/9/1998
** DESCRIPTION: Dialog components
**
** Copyright (C) 1998 Matthew Allen
** fret@memecode.com
*/
#include
#include
#include "lgi/common/Lgi.h"
#include "lgi/common/Slider.h"
#include "lgi/common/Bitmap.h"
#include "lgi/common/TableLayout.h"
#include "lgi/common/DisplayString.h"
#include "lgi/common/Button.h"
using namespace Gtk;
#include "LgiWidget.h"
///////////////////////////////////////////////////////////////////////////////////////////
#define GreyBackground()
struct LDialogPriv
{
int ModalStatus;
int BtnId;
bool IsModal, IsModeless;
bool Resizable;
LDialogPriv()
{
IsModal = false;
IsModeless = false;
Resizable = true;
ModalStatus = 0;
BtnId = -1;
}
};
///////////////////////////////////////////////////////////////////////////////////////////
LDialog::LDialog(LViewI *parent)
:
#ifdef __GTK_H__
// , LWindow(gtk_dialog_new())
LWindow(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
#endif
ResObject(Res_Dialog)
{
d = new LDialogPriv();
Name("Dialog");
_SetDynamic(false);
if (parent)
SetParent(parent);
}
LDialog::~LDialog()
{
DeleteObj(d);
}
bool LDialog::IsModal()
{
return d->IsModal;
}
int LDialog::GetButtonId()
{
return d->BtnId;
}
int LDialog::OnNotify(LViewI *Ctrl, LNotification n)
{
LButton *b = dynamic_cast(Ctrl);
if (b)
{
d->BtnId = b->GetId();
if (d->IsModal)
EndModal();
else if (d->IsModeless)
EndModeless();
}
return 0;
}
void LDialog::Quit(bool DontDelete)
{
if (d->IsModal)
EndModal(0);
else
LView::Quit(DontDelete);
}
void LDialog::OnPosChange()
{
LWindow::OnPosChange();
if (Children.Length() == 1)
{
List::I it = Children.begin();
LTableLayout *t = dynamic_cast((LViewI*)it);
if (t)
{
LRect r = GetClient();
r.Inset(LTableLayout::CellSpacing, LTableLayout::CellSpacing);
t->SetPos(r);
// _Dump();
}
}
}
bool LDialog::LoadFromResource(int Resource, char *TagList)
{
LAutoString n;
LRect p;
- LProfile Prof("LDialog::LoadFromResource");
+ // LProfile Prof("LDialog::LoadFromResource");
bool Status = LResourceLoad::LoadFromResource(Resource, this, &p, &n, TagList);
if (Status)
{
- Prof.Add("Name.");
+ // Prof.Add("Name.");
Name(n);
SetPos(p);
}
return Status;
}
bool LDialog::OnRequestClose(bool OsClose)
{
if (d->IsModal)
{
EndModal(0);
return false;
}
return true;
}
bool LDialog::IsResizeable()
{
return d->Resizable;
}
void LDialog::IsResizeable(bool r)
{
d->Resizable = r;
}
bool LDialog::SetupDialog(bool Modal)
{
if (IsResizeable())
{
gtk_window_set_default_size(Wnd, Pos.X(), Pos.Y());
}
else
{
gtk_widget_set_size_request(GTK_WIDGET(Wnd), Pos.X(), Pos.Y());
gtk_window_set_resizable(Wnd, FALSE);
}
auto p = GetParent();
if (!Attach(p))
return false;
LWindow::Visible(true);
return true;
}
void LDialog::DoModal(OnClose Callback, OsView OverrideParent)
{
d->ModalStatus = -1;
auto Parent = GetParent();
if (Parent)
{
gtk_window_set_transient_for(GTK_WINDOW(Wnd), Parent->WindowHandle());
MoveSameScreen(Parent);
}
d->IsModal = true;
d->IsModeless = false;
SetupDialog(true);
LAppInst->Run();
if (Callback)
Callback(this, d->ModalStatus);
else
delete this;
}
void LDialog::EndModal(int Code)
{
if (d->IsModal)
{
d->IsModal = false;
d->ModalStatus = Code;
LAppInst->Exit();
}
else
{
// LAssert(0);
}
}
int LDialog::DoModeless()
{
d->IsModal = false;
d->IsModeless = true;
SetupDialog(false);
return 0;
}
void LDialog::EndModeless(int Code)
{
Quit(Code);
}
extern LButton *FindDefault(LView *w);
LMessage::Param LDialog::OnEvent(LMessage *Msg)
{
return LView::OnEvent(Msg);
}
///////////////////////////////////////////////////////////////////////////////////////////
LControl::LControl(OsView view) : LView(view)
{
Pos.ZOff(10, 10);
}
LControl::~LControl()
{
}
LMessage::Param LControl::OnEvent(LMessage *Msg)
{
return 0;
}
LPoint LControl::SizeOfStr(const char *Str)
{
int y = LSysFont->GetHeight();
LPoint Pt(0, 0);
if (Str)
{
const char *e = 0;
for (const char *s = Str; s && *s; s = e?e+1:0)
{
e = strchr(s, '\n');
auto Len = e ? e - s : strlen(s);
LDisplayString ds(LSysFont, s, Len);
Pt.x = MAX(Pt.x, ds.X());
Pt.y += y;
}
}
return Pt;
}
diff --git a/src/linux/Lgi/Window.cpp b/src/linux/Lgi/Window.cpp
--- a/src/linux/Lgi/Window.cpp
+++ b/src/linux/Lgi/Window.cpp
@@ -1,1919 +1,1918 @@
#include
#include "lgi/common/Lgi.h"
#include "lgi/common/DragAndDrop.h"
#include "lgi/common/Token.h"
#include "lgi/common/Popup.h"
#include "lgi/common/Panel.h"
#include "lgi/common/Notifications.h"
#include "lgi/common/Menu.h"
#include "ViewPriv.h"
using namespace Gtk;
#undef Status
#include "LgiWidget.h"
#define DEBUG_SETFOCUS 0
#define DEBUG_HANDLEVIEWKEY 0
extern Gtk::GdkDragAction EffectToDragAction(int Effect);
///////////////////////////////////////////////////////////////////////
class HookInfo
{
public:
LWindowHookType Flags;
LView *Target;
};
enum LAttachState
{
LUnattached,
LAttaching,
LAttached,
LDetaching,
};
class LWindowPrivate
{
public:
int Sx, Sy;
bool Dynamic;
LKey LastKey;
::LArray Hooks;
bool SnapToEdge;
::LString Icon;
LRect Decor;
gulong DestroySig;
LAutoPtr IconImg;
LAttachState AttachState;
bool ShowTitleBar = true;
bool WillFocus = true;
// State
GdkWindowState State;
bool HadCreateEvent;
// Focus stuff
OsView FirstFocus;
LViewI *Focus;
bool Active;
LWindowPrivate()
{
AttachState = LUnattached;
DestroySig = 0;
Decor.ZOff(-1, -1);
FirstFocus = NULL;
Focus = NULL;
Active = false;
State = (Gtk::GdkWindowState)0;
HadCreateEvent = false;
Sx = Sy = 0;
Dynamic = true;
SnapToEdge = false;
LastKey.vkey = 0;
LastKey.c16 = 0;
LastKey.Data = 0;
LastKey.IsChar = 0;
}
int GetHookIndex(LView *Target, bool Create = false)
{
for (int i=0; iTarget = Target;
n->Flags = LNoEvents;
return Hooks.Length() - 1;
}
}
return -1;
}
};
///////////////////////////////////////////////////////////////////////
#define GWND_CREATE 0x0010000
LWindow::LWindow(GtkWidget *w) : LView(0)
{
d = new LWindowPrivate;
_QuitOnClose = false;
Menu = NULL;
Wnd = GTK_WINDOW(w);
if (Wnd)
{
- printf("gtk_window_set_decorated %i\n", d->ShowTitleBar);
gtk_window_set_decorated(Wnd, d->ShowTitleBar);
g_object_set_data(G_OBJECT(Wnd), "LViewI", (LViewI*)this);
}
_Root = NULL;
_MenuBar = NULL;
_VBox = NULL;
_Default = 0;
_Window = this;
WndFlags |= GWND_CREATE;
ClearFlag(WndFlags, GWF_VISIBLE);
_Lock = new ::LMutex("LWindow");
}
LWindow::~LWindow()
{
d->AttachState = LDetaching;
if (Wnd && d->DestroySig > 0)
{
// As we are already in the destructor, we don't want
// GtkWindowDestroy to try and delete the object again.
g_signal_handler_disconnect(Wnd, d->DestroySig);
}
if (LAppInst &&
LAppInst->AppWnd == this)
LAppInst->AppWnd = NULL;
if (_Root)
{
lgi_widget_detach(_Root);
_Root = NULL;
}
if (Wnd)
{
gtk_widget_destroy(GTK_WIDGET(Wnd));
Wnd = NULL;
}
d->AttachState = LUnattached;
DeleteObj(Menu);
DeleteObj(d);
DeleteObj(_Lock);
}
int LWindow::WaitThread()
{
return 0; // Nop for linux
}
bool LWindow::SetIcon(const char *FileName)
{
LString a;
if (Wnd)
{
if (!LFileExists(FileName))
{
if (a = LFindFile(FileName))
FileName = a;
}
if (!LFileExists(FileName))
{
LgiTrace("%s:%i - SetIcon failed to find '%s'\n", _FL, FileName);
return false;
}
else
{
#if defined(LINUX)
LAppInst->SetApplicationIcon(FileName);
#endif
#if _MSC_VER
GError *error = NULL;
if (gtk_window_set_icon_from_file(Wnd, FileName, &error))
return true;
#else
// On windows this is giving a red for blue channel swap error...
if (d->IconImg.Reset(GdcD->Load(a)))
gtk_window_set_icon(Wnd, d->IconImg->CreatePixBuf());
#endif
}
}
if (FileName != d->Icon.Get())
d->Icon = FileName;
return d->Icon != NULL;
}
bool LWindow::GetSnapToEdge()
{
return d->SnapToEdge;
}
void LWindow::SetSnapToEdge(bool s)
{
d->SnapToEdge = s;
}
bool LWindow::IsActive()
{
return d->Active;
}
bool LWindow::SetActive()
{
if (!Wnd)
return false;
gtk_window_present(Wnd);
return true;
}
bool LWindow::Visible()
{
return LView::Visible();
}
void LWindow::Visible(bool i)
{
ThreadCheck();
auto w = GTK_WIDGET(Wnd);
if (i)
gtk_widget_show(w);
else
gtk_widget_hide(w);
}
bool LWindow::Obscured()
{
return d->State == GDK_WINDOW_STATE_WITHDRAWN ||
d->State == GDK_WINDOW_STATE_ICONIFIED;
}
void LWindow::_SetDynamic(bool i)
{
d->Dynamic = i;
}
void LWindow::_OnViewDelete()
{
if (d->Dynamic)
{
delete this;
}
}
void LWindow::OnGtkRealize()
{
d->AttachState = LAttached;
LView::OnGtkRealize();
}
void LWindow::OnGtkDelete()
{
// Delete everything we own...
// DeleteObj(Menu);
#if 0
while (Children.Length())
{
LViewI *c = Children.First();
c->Detach();
}
#else
for (unsigned i=0; iGetGView();
if (v)
v->OnGtkDelete();
}
#endif
// These will be destroyed by GTK after returning from LWindowCallback
Wnd = NULL;
#ifndef __GTK_H__
_View = NULL;
#endif
}
LRect *LWindow::GetDecorSize()
{
return d->Decor.x2 >= 0 ? &d->Decor : NULL;
}
void LWindow::SetDecor(bool Visible)
{
if (Wnd)
gtk_window_set_decorated (Wnd, Visible);
else
LgiTrace("%s:%i - No window to set decor.\n", _FL);
}
LViewI *LWindow::WindowFromPoint(int x, int y, bool Debug)
{
if (!_Root)
return NULL;
auto rpos = GtkGetPos(_Root).ZeroTranslate();
if (!rpos.Overlap(x, y))
return NULL;
return LView::WindowFromPoint(x - rpos.x1, y - rpos.y1, Debug);
}
bool LWindow::TranslateMouse(LMouse &m)
{
m.Target = WindowFromPoint(m.x, m.y, false);
if (!m.Target)
return false;
LViewI *w = this;
for (auto p = m.Target; p; p = p->GetParent())
{
if (p == w)
{
auto ppos = GtkGetPos(GTK_WIDGET(WindowHandle()));
m.x -= ppos.x1;
m.y -= ppos.y1;
break;
}
else
{
auto pos = p->GetPos();
m.x -= pos.x1;
m.y -= pos.y1;
}
}
return true;
}
gboolean LWindow::OnGtkEvent(GtkWidget *widget, GdkEvent *event)
{
if (!event)
{
printf("%s:%i - No event.\n", _FL);
return FALSE;
}
#if 0
if (event->type != 28)
LgiTrace("%s::OnGtkEvent(%i) name=%s\n", GetClass(), event->type, Name());
#endif
switch (event->type)
{
case GDK_DELETE:
{
bool Close = OnRequestClose(false);
if (Close)
OnGtkDelete();
return !Close;
}
case GDK_DESTROY:
{
delete this;
return true;
}
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
{
auto ModFlags = LAppInst->GetKeyModFlags();
auto e = &event->key;
#define KEY(name) GDK_KEY_##name
LKey k;
k.Down(e->type == GDK_KEY_PRESS);
k.c16 = k.vkey = e->keyval;
k.Shift((e->state & ModFlags->Shift) != 0);
k.Ctrl((e->state & ModFlags->Ctrl) != 0);
k.Alt((e->state & ModFlags->Alt) != 0);
k.System((e->state & ModFlags->System) != 0);
#if 0//def _DEBUG
if (k.vkey == GDK_KEY_Meta_L ||
k.vkey == GDK_KEY_Meta_R)
break;
#endif
k.IsChar = !k.Ctrl() &&
!k.Alt() &&
!k.System() &&
(k.c16 >= ' ') &&
(k.c16 >> 8 != 0xff);
if (e->keyval > 0xff && e->string != NULL)
{
// Convert string to unicode char
auto *i = e->string;
ptrdiff_t len = strlen(i);
k.c16 = LgiUtf8To32((uint8_t *&) i, len);
}
switch (k.vkey)
{
case GDK_KEY_ISO_Left_Tab:
case KEY(Tab):
k.IsChar = true;
k.c16 = k.vkey = LK_TAB;
break;
case KEY(Return):
case KEY(KP_Enter):
k.IsChar = true;
k.c16 = k.vkey = LK_RETURN;
break;
case GDK_KEY_BackSpace:
k.c16 = k.vkey = LK_BACKSPACE;
k.IsChar = !k.Ctrl() && !k.Alt() && !k.System();
break;
case KEY(Left):
k.vkey = k.c16 = LK_LEFT;
break;
case KEY(Right):
k.vkey = k.c16 = LK_RIGHT;
break;
case KEY(Up):
k.vkey = k.c16 = LK_UP;
break;
case KEY(Down):
k.vkey = k.c16 = LK_DOWN;
break;
case KEY(Page_Up):
k.vkey = k.c16 = LK_PAGEUP;
break;
case KEY(Page_Down):
k.vkey = k.c16 = LK_PAGEDOWN;
break;
case KEY(Home):
k.vkey = k.c16 = LK_HOME;
break;
case KEY(End):
k.vkey = k.c16 = LK_END;
break;
case KEY(Delete):
k.vkey = k.c16 = LK_DELETE;
break;
#define KeyPadMap(gdksym, ch, is) \
case gdksym: k.c16 = ch; k.IsChar = is; break;
KeyPadMap(KEY(KP_0), '0', true)
KeyPadMap(KEY(KP_1), '1', true)
KeyPadMap(KEY(KP_2), '2', true)
KeyPadMap(KEY(KP_3), '3', true)
KeyPadMap(KEY(KP_4), '4', true)
KeyPadMap(KEY(KP_5), '5', true)
KeyPadMap(KEY(KP_6), '6', true)
KeyPadMap(KEY(KP_7), '7', true)
KeyPadMap(KEY(KP_8), '8', true)
KeyPadMap(KEY(KP_9), '9', true)
KeyPadMap(KEY(KP_Space), ' ', true)
KeyPadMap(KEY(KP_Tab), '\t', true)
KeyPadMap(KEY(KP_F1), LK_F1, false)
KeyPadMap(KEY(KP_F2), LK_F2, false)
KeyPadMap(KEY(KP_F3), LK_F3, false)
KeyPadMap(KEY(KP_F4), LK_F4, false)
KeyPadMap(KEY(KP_Home), LK_HOME, false)
KeyPadMap(KEY(KP_Left), LK_LEFT, false)
KeyPadMap(KEY(KP_Up), LK_UP, false)
KeyPadMap(KEY(KP_Right), LK_RIGHT, false)
KeyPadMap(KEY(KP_Down), LK_DOWN, false)
KeyPadMap(KEY(KP_Page_Up), LK_PAGEUP, false)
KeyPadMap(KEY(KP_Page_Down), LK_PAGEDOWN, false)
KeyPadMap(KEY(KP_End), LK_END, false)
KeyPadMap(KEY(KP_Begin), LK_HOME, false)
KeyPadMap(KEY(KP_Insert), LK_INSERT, false)
KeyPadMap(KEY(KP_Delete), LK_DELETE, false)
KeyPadMap(KEY(KP_Equal), '=', true)
KeyPadMap(KEY(KP_Multiply), '*', true)
KeyPadMap(KEY(KP_Add), '+', true)
KeyPadMap(KEY(KP_Separator), '|', true) // is this right?
KeyPadMap(KEY(KP_Subtract), '-', true)
KeyPadMap(KEY(KP_Decimal), '.', true)
KeyPadMap(KEY(KP_Divide), '/', true)
}
if (ModFlags->Debug)
{
:: LString Msg;
Msg.Printf("e->state=%x %s", e->state, ModFlags->FlagsToString(e->state).Get());
k.Trace(Msg);
}
auto v = d->Focus ? d->Focus : this;
if (!HandleViewKey(v->GetGView(), k))
{
if (!k.Down())
return false;
if (k.vkey == LK_TAB || k.vkey == KEY(ISO_Left_Tab))
{
// Do tab between controls
::LArray a;
BuildTabStops(this, a);
int idx = a.IndexOf((LViewI*)v);
if (idx >= 0)
{
idx += k.Shift() ? -1 : 1;
int next_idx = idx == 0 ? a.Length() -1 : idx % a.Length();
LViewI *next = a[next_idx];
if (next)
{
// LgiTrace("Setting focus to %i of %i: %s, %s, %i\n", next_idx, a.Length(), next->GetClass(), next->GetPos().GetStr(), next->GetId());
next->Focus(true);
}
}
}
else if (k.System())
{
if (ToLower(k.c16) == 'q')
{
auto AppWnd = LAppInst->AppWnd;
auto Wnd = AppWnd ? AppWnd : this;
if (Wnd->OnRequestClose(false))
{
Wnd->Quit();
return true;
}
}
}
else return false;
}
break;
}
case GDK_CONFIGURE:
{
GdkEventConfigure *c = &event->configure;
Pos.Set(c->x, c->y, c->x+c->width-1, c->y+c->height-1);
// printf("%s::GDK_CONFIGURE %s\n", GetClass(), Pos.GetStr());
OnPosChange();
return FALSE;
break;
}
case GDK_FOCUS_CHANGE:
{
d->Active = event->focus_change.in;
#if 0
printf("%s/%s::GDK_FOCUS_CHANGE(%i)\n",
GetClass(),
Name(),
event->focus_change.in);
#endif
break;
}
case GDK_WINDOW_STATE:
{
d->State = event->window_state.new_window_state;
break;
}
case GDK_PROPERTY_NOTIFY:
{
gchar *Name = gdk_atom_name (event->property.atom);
if (!Name)
break;
if (!_stricmp(Name, "_NET_FRAME_EXTENTS"))
{
// printf("PropChange: %i - %s\n", event->property.atom, Name);
unsigned long *extents = NULL;
if (gdk_property_get(event->property.window,
gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
gdk_atom_intern ("CARDINAL", FALSE),
0,
sizeof (unsigned long) * 4,
FALSE,
NULL,
NULL,
NULL,
(guchar **)&extents))
{
d->Decor.Set(extents[0], extents[2], extents[1], extents[3]);
g_free(extents);
}
else printf("%s:%i - Error: gdk_property_get failed.\n", _FL);
}
g_free(Name);
break;
}
case GDK_UNMAP:
{
// LgiTrace("%s:%i - Unmap %s\n", _FL, GetClass());
break;
}
case GDK_VISIBILITY_NOTIFY:
{
// LgiTrace("%s:%i - Visible %s\n", _FL, GetClass());
break;
}
case GDK_DRAG_ENTER:
{
LgiTrace("%s:%i - GDK_DRAG_ENTER\n", _FL);
break;
}
case GDK_DRAG_LEAVE:
{
LgiTrace("%s:%i - GDK_DRAG_LEAVE\n", _FL);
break;
}
case GDK_DRAG_MOTION:
{
LgiTrace("%s:%i - GDK_DRAG_MOTION\n", _FL);
break;
}
case GDK_DRAG_STATUS:
{
LgiTrace("%s:%i - GDK_DRAG_STATUS\n", _FL);
break;
}
case GDK_DROP_START:
{
LgiTrace("%s:%i - GDK_DROP_START\n", _FL);
break;
}
case GDK_DROP_FINISHED:
{
LgiTrace("%s:%i - GDK_DROP_FINISHED\n", _FL);
break;
}
default:
{
printf("%s:%i - Unknown event %i\n", _FL, event->type);
return false;
}
}
return true;
}
static
gboolean
GtkWindowDestroy(GtkWidget *widget, LWindow *This)
{
delete This;
return true;
}
static
void
GtkWindowRealize(GtkWidget *widget, LWindow *This)
{
#if 0
LgiTrace("GtkWindowRealize, This=%p(%s\"%s\")\n",
This, (NativeInt)This > 0x1000 ? This->GetClass() : 0, (NativeInt)This > 0x1000 ? This->Name() : 0);
#endif
This->OnGtkRealize();
}
static
void
GtkRootResize(GtkWidget *widget, GdkRectangle *alloc, LView *This)
{
LWindow *w = This->GetWindow();
if (w)
w->PourAll();
}
void
LWindowUnrealize(GtkWidget *widget, LWindow *wnd)
{
// printf("%s:%i - LWindowUnrealize %s\n", _FL, wnd->GetClass());
}
bool DndPointMap(LViewI *&v, LPoint &p, LDragDropTarget *&t, LWindow *Wnd, int x, int y)
{
LRect cli = Wnd->GetClient();
t = NULL;
v = Wnd->WindowFromPoint(x - cli.x1, y - cli.y1, false);
if (!v)
{
LgiTrace("%s:%i - @ %i,%i\n", _FL, x, y);
return false;
}
v->WindowVirtualOffset(&p);
p.x = x - p.x;
p.y = y - p.y;
for (LViewI *view = v; !t && view; view = view->GetParent())
t = view->DropTarget();
if (t)
return true;
LgiTrace("%s:%i - No target for %s\n", _FL, v->GetClass());
return false;
}
void
LWindowDragBegin(GtkWidget *widget, GdkDragContext *context, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
void
LWindowDragDataDelete(GtkWidget *widget, GdkDragContext *context, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
void
LWindowDragDataGet(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *data, guint info, guint time, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
void
LWindowDragDataReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, LWindow *Wnd)
{
LPoint p;
LViewI *v;
LDragDropTarget *t;
if (!DndPointMap(v, p, t, Wnd, x, y))
return;
for (auto &d: t->Data)
{
auto type = gdk_atom_name(gtk_selection_data_get_data_type(data));
if (d.Format.Equals(type))
{
gint length = 0;
auto ptr = gtk_selection_data_get_data_with_length(data, &length);
if (ptr)
{
d.Data[0].SetBinary(length, (void*)ptr, false);
}
break;
}
}
}
int GetAcceptFmts(::LString::Array &Formats, GdkDragContext *context, LDragDropTarget *t, LPoint &p)
{
int KeyState = 0;
LDragFormats Fmts(true);
int Flags = DROPEFFECT_NONE;
GList *targets = gdk_drag_context_list_targets(context);
Gtk::GList *i = targets;
while (i)
{
auto a = gdk_atom_name((GdkAtom)i->data);
if (a)
Fmts.Supports(a);
i = i->next;
}
Fmts.SetSource(false);
Flags = t->WillAccept(Fmts, p, KeyState);
auto Sup = Fmts.GetSupported();
for (auto &s: Sup)
Formats.New() = s;
return Flags;
}
gboolean
LWindowDragDataDrop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, LWindow *Wnd)
{
// Map the point to a view...
LPoint p;
LViewI *v;
LDragDropTarget *t;
if (!DndPointMap(v, p, t, Wnd, x, y))
return false;
t->Data.Length(0);
// Request the data...
::LArray Data;
::LString::Array Formats;
int KeyState = 0;
int Flags = GetAcceptFmts(Formats, context, t, p);
for (auto f: Formats)
{
t->Data.New().Format = f;
gtk_drag_get_data(widget, context, gdk_atom_intern(f, true), time);
}
// Wait for the data to arrive...
uint64_t Start = LCurrentTime();
while (LCurrentTime()-Start < 2000)
{
int HasData = 0;
for (auto d: t->Data)
if (d.Data.Length() > 0)
HasData++;
if (HasData >= Formats.Length())
break;
LYield();
}
auto Result = t->OnDrop(t->Data, p, KeyState);
if (Flags != DROPEFFECT_NONE)
gdk_drag_status(context, EffectToDragAction(Flags), time);
return Result != DROPEFFECT_NONE;
}
void
LWindowDragEnd(GtkWidget *widget, GdkDragContext *context, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
gboolean
LWindowDragFailed(GtkWidget *widget, GdkDragContext *context, GtkDragResult result, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
return false;
}
void
LWindowDragLeave(GtkWidget *widget, GdkDragContext *context, guint time, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
gboolean
LWindowDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, LWindow *Wnd)
{
LPoint p;
LViewI *v;
LDragDropTarget *t;
if (!DndPointMap(v, p, t, Wnd, x, y))
return false;
::LString::Array Formats;
int Flags = GetAcceptFmts(Formats, context, t, p);
if (Flags != DROPEFFECT_NONE)
gdk_drag_status(context, EffectToDragAction(Flags), time);
return Flags != DROPEFFECT_NONE;
}
bool LWindow::Attach(LViewI *p)
{
bool Status = false;
ThreadCheck();
// Setup default button...
if (!_Default)
_Default = FindControl(IDOK);
// Create a window if needed..
if (!Wnd)
Wnd = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
if (Wnd)
{
SetTitleBar(d->ShowTitleBar);
SetWillFocus(d->WillFocus);
auto Widget = GTK_WIDGET(Wnd);
LView *i = this;
if (Pos.X() > 0 && Pos.Y() > 0)
gtk_window_resize(Wnd, Pos.X(), Pos.Y());
gtk_window_move(Wnd, Pos.x1, Pos.y1);
auto Obj = G_OBJECT(Wnd);
g_object_set_data(Obj, "LViewI", (LViewI*)this);
d->DestroySig = g_signal_connect(Obj, "destroy", G_CALLBACK(GtkWindowDestroy), this);
g_signal_connect(Obj, "delete_event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "key-press-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "key-release-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "focus-in-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "focus-out-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "window-state-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "property-notify-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "configure-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "unmap-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "visibility-notify-event",G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "realize", G_CALLBACK(GtkWindowRealize), i);
g_signal_connect(Obj, "unrealize", G_CALLBACK(LWindowUnrealize), i);
g_signal_connect(Obj, "drag-begin", G_CALLBACK(LWindowDragBegin), i);
g_signal_connect(Obj, "drag-data-delete", G_CALLBACK(LWindowDragDataDelete), i);
g_signal_connect(Obj, "drag-data-get", G_CALLBACK(LWindowDragDataGet), i);
g_signal_connect(Obj, "drag-data-received", G_CALLBACK(LWindowDragDataReceived), i);
g_signal_connect(Obj, "drag-drop", G_CALLBACK(LWindowDragDataDrop), i);
g_signal_connect(Obj, "drag-end", G_CALLBACK(LWindowDragEnd), i);
g_signal_connect(Obj, "drag-failed", G_CALLBACK(LWindowDragFailed), i);
g_signal_connect(Obj, "drag-leave", G_CALLBACK(LWindowDragLeave), i);
g_signal_connect(Obj, "drag-motion", G_CALLBACK(LWindowDragMotion), i);
#if 0
g_signal_connect(Obj, "button-press-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "button-release-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "motion-notify-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "scroll-event", G_CALLBACK(GtkViewCallback), i);
#endif
gtk_widget_add_events( Widget,
GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK |
GDK_FOCUS_CHANGE_MASK |
GDK_STRUCTURE_MASK |
GDK_VISIBILITY_NOTIFY_MASK);
gtk_window_set_title(Wnd, LBase::Name());
d->AttachState = LAttaching;
// g_action_map_add_action_entries (G_ACTION_MAP(Wnd), app_entries, G_N_ELEMENTS (app_entries), Wnd);
if ((_Root = lgi_widget_new(this, true)))
{
g_signal_connect(_Root, "size-allocate", G_CALLBACK(GtkRootResize), i);
GtkContainer *AttachPoint = NULL;
if (GTK_IS_DIALOG(Wnd))
{
auto content = gtk_dialog_get_content_area(GTK_DIALOG(Wnd));
if (!content)
{
LAssert(!"No content area");
return false;
}
AttachPoint = GTK_CONTAINER(content);
}
else
{
AttachPoint = GTK_CONTAINER(Wnd);
}
LAssert(AttachPoint != NULL);
gtk_container_add(AttachPoint, _Root);
// Check it actually worked... (would a return value kill you GTK? no it would not)
auto p = gtk_widget_get_parent(_Root);
if (!p)
{
LAssert(!"Add failed");
return false;
}
gtk_widget_show(_Root);
}
// This call sets up the GdkWindow handle
gtk_widget_realize(Widget);
// Do a rough layout of child windows
PourAll();
// Add icon
if (d->Icon)
{
SetIcon(d->Icon);
d->Icon.Empty();
}
auto p = GetParent();
if (p)
{
auto pHnd = p->WindowHandle();
if (!pHnd)
LgiTrace("%s:%i - SetParent() - no pHnd from %s.\n", _FL, p->GetClass());
else
gtk_window_set_transient_for(GTK_WINDOW(Wnd), pHnd);
}
Status = true;
}
return Status;
}
bool LWindow::OnRequestClose(bool OsShuttingDown)
{
if (GetQuitOnClose())
{
LCloseApp();
}
return LView::OnRequestClose(OsShuttingDown);
}
bool LWindow::HandleViewMouse(LView *v, LMouse &m)
{
if (m.Down() && !m.IsMove())
{
bool InPopup = false;
for (LViewI *p = v; p; p = p->GetParent())
{
if (dynamic_cast(p))
{
InPopup = true;
break;
}
}
if (!InPopup && LPopup::CurrentPopups.Length())
{
for (int i=0; iVisible())
p->Visible(false);
}
}
}
for (int i=0; iHooks.Length(); i++)
{
if (d->Hooks[i].Flags & LMouseEvents)
{
if (!d->Hooks[i].Target->OnViewMouse(v, m))
{
return false;
}
}
}
return true;
}
bool LWindow::HandleViewKey(LView *v, LKey &k)
{
bool Status = false;
LViewI *Ctrl = 0;
#if DEBUG_HANDLEVIEWKEY
bool Debug = 1; // k.vkey == LK_RETURN;
char SafePrint = k.c16 < ' ' ? ' ' : k.c16;
// if (Debug)
{
LgiTrace("%s/%p::HandleViewKey=%i ischar=%i %s%s%s%s (d->Focus=%s/%p)\n",
v->GetClass(), v,
k.c16,
k.IsChar,
(char*)(k.Down()?" Down":" Up"),
(char*)(k.Shift()?" Shift":""),
(char*)(k.Alt()?" Alt":""),
(char*)(k.Ctrl()?" Ctrl":""),
d->Focus?d->Focus->GetClass():0, d->Focus);
}
#endif
// Any window in a popup always gets the key...
LViewI *p;
for (p = v->GetParent(); p; p = p->GetParent())
{
if (dynamic_cast(p))
{
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tSending key to popup\n");
#endif
return v->OnKey(k);
}
}
// Give key to popups
if (LAppInst &&
LAppInst->GetMouseHook() &&
LAppInst->GetMouseHook()->OnViewKey(v, k))
{
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tMouseHook got key\n");
#endif
goto AllDone;
}
// Allow any hooks to see the key...
for (int i=0; iHooks.Length(); i++)
{
#if DEBUG_HANDLEVIEWKEY
// if (Debug) LgiTrace("\tHook[%i]\n", i);
#endif
if (d->Hooks[i].Flags & LKeyEvents)
{
LView *Target = d->Hooks[i].Target;
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tHook[%i].Target=%p %s\n", i, Target, Target->GetClass());
#endif
if (Target->OnViewKey(v, k))
{
Status = true;
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tHook[%i] ate '%c'(%i) down=%i alt=%i ctrl=%i sh=%i\n", i, SafePrint, k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
goto AllDone;
}
}
}
// Give the key to the window...
if (v->OnKey(k))
{
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tView ate '%c'(%i) down=%i alt=%i ctrl=%i sh=%i\n",
SafePrint, k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
Status = true;
goto AllDone;
}
#if DEBUG_HANDLEVIEWKEY
else if (Debug)
LgiTrace("\t%s didn't eat '%c'(%i) down=%i alt=%i ctrl=%i sh=%i\n",
v->GetClass(), SafePrint, k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
// Window didn't want the key...
switch (k.vkey)
{
case LK_RETURN:
#ifdef LK_KEYPADENTER
case LK_KEYPADENTER:
#endif
{
Ctrl = _Default;
break;
}
case LK_ESCAPE:
{
Ctrl = FindControl(IDCANCEL);
break;
}
}
// printf("Ctrl=%p\n", Ctrl);
if (Ctrl)
{
if (Ctrl->Enabled())
{
if (Ctrl->OnKey(k))
{
Status = true;
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tDefault Button ate '%c'(%i) down=%i alt=%i ctrl=%i sh=%i\n",
SafePrint, k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
goto AllDone;
}
// else printf("OnKey()=false\n");
}
// else printf("Ctrl=disabled\n");
}
#if DEBUG_HANDLEVIEWKEY
else if (Debug)
LgiTrace("\tNo default ctrl to handle key.\n");
#endif
if (Menu)
{
Status = Menu->OnKey(v, k);
if (Status)
{
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tMenu ate '%c' down=%i alt=%i ctrl=%i sh=%i\n", k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
}
}
// Tab through controls
if (k.vkey == LK_TAB && k.Down() && !k.IsChar)
{
LViewI *Wnd = GetNextTabStop(v, k.Shift());
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tTab moving focus shift=%i Wnd=%p\n", k.Shift(), Wnd);
#endif
if (Wnd)
Wnd->Focus(true);
}
// Control shortcut?
if (k.Down() && k.Alt() && k.c16 > ' ')
{
ShortcutMap Map;
BuildShortcuts(Map);
LViewI *c = Map.Find(ToUpper(k.c16));
if (c)
{
c->OnNotify(c, LNotifyActivate);
return true;
}
}
AllDone:
if (d)
d->LastKey = k;
return Status;
}
void LWindow::Raise()
{
if (Wnd)
gtk_window_present(Wnd);
}
LWindowZoom LWindow::GetZoom()
{
switch (d->State)
{
case GDK_WINDOW_STATE_ICONIFIED:
return LZoomMin;
case GDK_WINDOW_STATE_MAXIMIZED:
return LZoomMax;
default:
break;
}
return LZoomNormal;
}
void LWindow::SetZoom(LWindowZoom i)
{
if (!Wnd)
{
// LgiTrace("%s:%i - No window.\n", _FL);
return;
}
ThreadCheck();
switch (i)
{
case LZoomMin:
{
gtk_window_iconify(Wnd);
break;
}
case LZoomNormal:
{
gtk_window_deiconify(Wnd);
gtk_window_unmaximize(Wnd);
break;
}
case LZoomMax:
{
gtk_window_maximize(Wnd);
break;
}
default:
{
LgiTrace("%s:%i - Error: unsupported zoom.\n", _FL);
break;
}
}
}
LViewI *LWindow::GetDefault()
{
return _Default;
}
void LWindow::SetDefault(LViewI *v)
{
if (v &&
v->GetWindow() == this)
{
if (_Default != v)
{
LViewI *Old = _Default;
_Default = v;
if (Old) Old->Invalidate();
if (_Default) _Default->Invalidate();
}
}
else
{
_Default = 0;
}
}
bool LWindow::SetTitleBar(bool ShowTitleBar)
{
d->ShowTitleBar = ShowTitleBar;
if (Wnd)
{
ThreadCheck();
gtk_window_set_decorated(Wnd, ShowTitleBar);
}
return true;
}
bool LWindow::Name(const char *n)
{
if (Wnd)
{
ThreadCheck();
gtk_window_set_title(Wnd, n);
}
return LBase::Name(n);
}
const char *LWindow::Name()
{
return LBase::Name();
}
struct CallbackParams
{
LRect Menu;
int Depth;
CallbackParams()
{
Menu.ZOff(-1, -1);
Depth = 0;
}
};
void ClientCallback(GtkWidget *w, CallbackParams *p)
{
const char *Name = gtk_widget_get_name(w);
if (Name && !_stricmp(Name, "GtkMenuBar"))
{
GtkAllocation alloc = {0};
gtk_widget_get_allocation(w, &alloc);
p->Menu.ZOff(alloc.width-1, alloc.height-1);
// LgiTrace("GtkMenuBar = %s\n", p->Menu.GetStr());
}
if (!p->Menu.Valid())
{
p->Depth++;
if (GTK_IS_CONTAINER(w))
gtk_container_forall(GTK_CONTAINER(w), (GtkCallback)ClientCallback, p);
p->Depth--;
}
}
LPoint LWindow::GetDpi()
{
return LScreenDpi();
}
LPointF LWindow::GetDpiScale()
{
auto Dpi = GetDpi();
return LPointF((double)Dpi.x/96.0, (double)Dpi.y/96.0);
}
LRect &LWindow::GetClient(bool ClientSpace)
{
static LRect r;
r = LView::GetClient(ClientSpace);
if (Wnd)
{
CallbackParams p;
gtk_container_forall(GTK_CONTAINER(Wnd), (GtkCallback)ClientCallback, &p);
if (p.Menu.Valid())
{
if (ClientSpace)
r.y2 -= p.Menu.Y();
else
r.y1 += p.Menu.Y();
}
}
return r;
}
bool LWindow::SerializeState(LDom *Store, const char *FieldName, bool Load)
{
if (!Store || !FieldName)
return false;
if (Load)
{
::LVariant v;
if (Store->GetValue(FieldName, v) && v.Str())
{
LRect Position(0, 0, -1, -1);
LWindowZoom State = LZoomNormal;
// printf("SerializeState load %s\n", v.Str());
LToken t(v.Str(), ";");
for (int i=0; iSetValue(FieldName, v))
return false;
}
return true;
}
LRect &LWindow::GetPos()
{
return Pos;
}
bool LWindow::SetPos(LRect &p, bool Repaint)
{
Pos = p;
if (Wnd)
{
ThreadCheck();
gtk_window_resize(Wnd, MAX(1, Pos.X()), Pos.Y());
gtk_window_move(Wnd, Pos.x1, Pos.y1);
}
OnPosChange();
return true;
}
void LWindow::OnChildrenChanged(LViewI *Wnd, bool Attaching)
{
// Force repour
d->Sx = d->Sy = -1;
}
void LWindow::OnCreate()
{
AttachChildren();
}
void LWindow::OnPaint(LSurface *pDC)
{
pDC->Colour(L_MED);
pDC->Rectangle();
}
void LWindow::OnPosChange()
{
LView::OnPosChange();
if (d->Sx != X() || d->Sy != Y())
{
PourAll();
d->Sx = X();
d->Sy = Y();
}
}
#define IsTool(v) \
( \
dynamic_cast(v) \
&& \
dynamic_cast(v)->_IsToolBar \
)
void LWindow::PourAll()
{
LRect c;
if (_Root)
c = GtkGetPos(_Root).ZeroTranslate();
else
c = GetClient();
if (c.X() < 20 || c.Y() < 20)
return; // IDK, GTK is weird sometimes... filter out low sizes.
LRegion Client(c);
LViewI *MenuView = 0;
LRegion Update(Client);
bool HasTools = false;
LViewI *v;
List::I Lst = Children.begin();
{
LRegion Tools;
for (v = *Lst; v; v = *++Lst)
{
bool IsMenu = MenuView == v;
if (!IsMenu && IsTool(v))
{
LRect OldPos = v->GetPos();
if (OldPos.Valid())
Update.Union(&OldPos);
if (HasTools)
{
// 2nd and later toolbars
if (v->Pour(Tools))
{
if (!v->Visible())
{
v->Visible(true);
}
auto vpos = v->GetPos();
if (OldPos != vpos)
{
// position has changed update...
v->Invalidate();
}
// Has it increased the size of the toolbar area?
auto b = Tools.Bound();
if (vpos.y2 >= b.y2)
{
LRect Bar = Client;
Bar.y2 = vpos.y2;
Client.Subtract(&Bar);
// LgiTrace("IncreaseToolbar=%s\n", Bar.GetStr());
}
Tools.Subtract(&vpos);
Update.Subtract(&vpos);
// LgiTrace("vpos=%s\n", vpos.GetStr());
}
}
else
{
// First toolbar
if (v->Pour(Client))
{
HasTools = true;
if (!v->Visible())
{
v->Visible(true);
}
if (OldPos != v->GetPos())
{
v->Invalidate();
}
LRect Bar(v->GetPos());
// LgiTrace("%s = %s\n", v->GetClass(), Bar.GetStr());
Bar.x2 = GetClient().x2;
Tools = Bar;
Tools.Subtract(&v->GetPos());
Client.Subtract(&Bar);
Update.Subtract(&Bar);
}
}
}
}
}
Lst = Children.begin();
for (LViewI *v = *Lst; v; v = *++Lst)
{
bool IsMenu = MenuView == v;
if (!IsMenu && !IsTool(v))
{
LRect OldPos = v->GetPos();
if (OldPos.Valid())
Update.Union(&OldPos);
if (v->Pour(Client))
{
// LRect p = v->GetPos();
// LgiTrace("%s = %s\n", v->GetClass(), p.GetStr());
if (!v->Visible())
v->Visible(true);
v->Invalidate();
Client.Subtract(&v->GetPos());
Update.Subtract(&v->GetPos());
}
else
{
// non-pourable
}
}
}
for (int i=0; iMsg())
{
case M_CLOSE:
{
if (OnRequestClose(false))
{
Quit();
return 0;
}
break;
}
}
return LView::OnEvent(m);
}
bool LWindow::RegisterHook(LView *Target, LWindowHookType EventType, int Priority)
{
bool Status = false;
if (Target && EventType)
{
int i = d->GetHookIndex(Target, true);
if (i >= 0)
{
d->Hooks[i].Flags = EventType;
Status = true;
}
}
return Status;
}
bool LWindow::UnregisterHook(LView *Target)
{
int i = d->GetHookIndex(Target);
if (i >= 0)
{
d->Hooks.DeleteAt(i);
return true;
}
return false;
}
void LWindow::OnFrontSwitch(bool b)
{
}
LViewI *LWindow::GetFocus()
{
return d->Focus;
}
#if DEBUG_SETFOCUS
static LAutoString DescribeView(LViewI *v)
{
if (!v)
return LAutoString(NewStr("NULL"));
char s[512];
int ch = 0;
::LArray p;
for (LViewI *i = v; i; i = i->GetParent())
{
p.Add(i);
}
for (int n=MIN(3, p.Length()-1); n>=0; n--)
{
char Buf[256] = "";
if (!stricmp(v->GetClass(), "LMdiChild"))
sprintf(Buf, "'%s'", v->Name());
v = p[n];
ch += sprintf_s(s + ch, sizeof(s) - ch, "%s>%s", Buf, v->GetClass());
}
return LAutoString(NewStr(s));
}
#endif
void LWindow::SetFocus(LViewI *ctrl, FocusType type)
{
#if DEBUG_SETFOCUS
const char *TypeName = NULL;
switch (type)
{
case GainFocus: TypeName = "Gain"; break;
case LoseFocus: TypeName = "Lose"; break;
case ViewDelete: TypeName = "Delete"; break;
}
#endif
switch (type)
{
case GainFocus:
{
if (d->Focus == ctrl)
{
#if DEBUG_SETFOCUS
LAutoString _ctrl = DescribeView(ctrl);
LgiTrace("SetFocus(%s, %s) already has focus.\n", _ctrl.Get(), TypeName);
#endif
return;
}
if (d->Focus)
{
LView *gv = d->Focus->GetGView();
if (gv)
{
#if DEBUG_SETFOCUS
LAutoString _foc = DescribeView(d->Focus);
LgiTrace(".....defocus LView: %s\n", _foc.Get());
#endif
gv->_Focus(false);
}
else if (IsActive())
{
#if DEBUG_SETFOCUS
LAutoString _foc = DescribeView(d->Focus);
LgiTrace(".....defocus view: %s (active=%i)\n", _foc.Get(), IsActive());
#endif
d->Focus->OnFocus(false);
d->Focus->Invalidate();
}
}
d->Focus = ctrl;
if (d->Focus)
{
#if DEBUG_SETFOCUS
static int Count = 0;
#endif
LView *gv = d->Focus->GetGView();
if (gv)
{
#if DEBUG_SETFOCUS
LAutoString _set = DescribeView(d->Focus);
LgiTrace("LWindow::SetFocus(%s, %s) %i focusing LView\n",
_set.Get(),
TypeName,
Count++);
#endif
gv->_Focus(true);
}
else if (IsActive())
{
#if DEBUG_SETFOCUS
LAutoString _set = DescribeView(d->Focus);
LgiTrace("LWindow::SetFocus(%s, %s) %i focusing nonGView (active=%i)\n",
_set.Get(),
TypeName,
Count++,
IsActive());
#endif
d->Focus->OnFocus(true);
d->Focus->Invalidate();
}
}
break;
}
case LoseFocus:
{
#if DEBUG_SETFOCUS
LAutoString _Ctrl = DescribeView(d->Focus);
LAutoString _Focus = DescribeView(d->Focus);
LgiTrace("LWindow::SetFocus(%s, %s) d->Focus=%s\n",
_Ctrl.Get(),
TypeName,
_Focus.Get());
#endif
if (ctrl == d->Focus)
{
d->Focus = NULL;
}
break;
}
case ViewDelete:
{
if (ctrl == d->Focus)
{
#if DEBUG_SETFOCUS
LAutoString _Ctrl = DescribeView(d->Focus);
LgiTrace("LWindow::SetFocus(%s, %s) on delete\n",
_Ctrl.Get(),
TypeName);
#endif
d->Focus = NULL;
}
break;
}
}
}
bool LWindow::SetWillFocus(bool f)
{
d->WillFocus = f;
if (Wnd)
{
if (f)
{
}
else
{
gtk_window_set_type_hint(Wnd, GDK_WINDOW_TYPE_HINT_POPUP_MENU);
// printf("%s:%i - gtk_window_set_type_hint=GDK_WINDOW_TYPE_HINT_POPUP_MENU.\n", _FL);
}
}
return true;
}
void LWindow::SetDragHandlers(bool On)
{
}
void LWindow::SetParent(LViewI *p)
{
LView::SetParent(p);
if (p && Wnd)
{
auto pHnd = p->WindowHandle();
if (!pHnd)
LgiTrace("%s:%i - SetParent() - no pHnd from %s.\n", _FL, p->GetClass());
else if (!GTK_IS_WINDOW(Wnd))
LgiTrace("%s:%i - SetParent() - GTK_IS_WINDOW failed.\n", _FL);
else
gtk_window_set_transient_for(GTK_WINDOW(Wnd), pHnd);
}
}
bool LWindow::IsAttached()
{
return d->AttachState == LAttaching ||
d->AttachState == LAttached;
}
void LWindow::OnTrayClick(LMouse &m)
{
if (m.Down() || m.IsContextMenu())
{
LSubMenu RClick;
OnTrayMenu(RClick);
if (GetMouse(m, true))
{
#if WINNATIVE
SetForegroundWindow(Handle());
#endif
int Result = RClick.Float(this, m.x, m.y);
#if WINNATIVE
PostMessage(Handle(), WM_NULL, 0, 0);
#endif
OnTrayMenuResult(Result);
}
}
}
void LWindow::Quit(bool DontDelete)
{
ThreadCheck();
if (Wnd)
{
d->AttachState = LDetaching;
auto wnd = Wnd;
Wnd = NULL;
gtk_widget_destroy(GTK_WIDGET(wnd));
}
}
void LWindow::SetAlwaysOnTop(bool b)
{
}