diff --git a/Lvc/linux/Makefile.linux b/Lvc/linux/Makefile.linux --- a/Lvc/linux/Makefile.linux +++ b/Lvc/linux/Makefile.linux @@ -1,395 +1,396 @@ #!/usr/bin/make # # This makefile generated by LgiIde # http://www.memecode.com/lgi.php # .SILENT : CC = gcc CPP = g++ -Target = ../lvc +Target = ./lvc ifndef Build Build = Debug endif MakeDir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) BuildDir = $(Build) Flags = -fPIC -w -fno-inline -fpermissive ifeq ($(Build),Debug) Flags += -MMD -MP -g -std=c++14 Tag = d Defs = -D_DEBUG -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX Libs = \ -lssh \ -lmagic \ -static-libgcc \ `pkg-config --libs gtk+-3.0` \ -pthread \ -llgi-gtk3$(Tag) \ - -L../../$(BuildDir) + -L../$(BuildDir) Inc = \ - -I../src \ - -I../resources \ + -I./src \ + -I./resources \ `pkg-config --cflags gtk+-3.0` \ - -I../../../../../../../usr/include/gstreamer-1.0 \ - -I../../include/lgi/linux/Gtk \ - -I../../include/lgi/linux \ - -I../../include + -I../../../../../../usr/include/gstreamer-1.0 \ + -I../include/lgi/linux/Gtk \ + -I../include/lgi/linux \ + -I../include else Flags += -MMD -MP -s -Os -std=c++14 Defs = -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX Libs = \ -lssh \ -lmagic \ -static-libgcc \ `pkg-config --libs gtk+-3.0` \ -pthread \ -llgi-gtk3$(Tag) \ - -L../../$(BuildDir) + -L../$(BuildDir) Inc = \ - -I../src \ - -I../resources \ + -I./src \ + -I./resources \ `pkg-config --cflags gtk+-3.0` \ - -I../../../../../../../usr/include/gstreamer-1.0 \ - -I../../include/lgi/linux/Gtk \ - -I../../include/lgi/linux \ - -I../../include + -I../../../../../../usr/include/gstreamer-1.0 \ + -I../include/lgi/linux/Gtk \ + -I../include/lgi/linux \ + -I../include endif # Dependencies -Source = ../src/VcFolder.cpp \ - ../src/VcFile.cpp \ - ../src/VcCommit.cpp \ - ../src/SshConnection.cpp \ - ../src/PatchViewer.cpp \ - ../src/Main.cpp \ - ../src/DropDownBtn.cpp \ - ../src/BlameUi.cpp \ - ../../src/common/Widgets/ControlTree.cpp \ - ../../src/common/Text/XmlTreeUi.cpp \ - ../../src/common/Text/DeEscape.cpp \ - ../../src/common/Lgi/StructuredLog.cpp \ - ../../src/common/Lgi/LgiMain.cpp \ - ../../src/common/Gdc2/Filters/Png.cpp +Source = src/VcFolder.cpp \ + src/VcFile.cpp \ + src/VcCommit.cpp \ + src/SshConnection.cpp \ + src/PatchViewer.cpp \ + src/Main.cpp \ + src/DropDownBtn.cpp \ + src/BlameUi.cpp \ + ../src/common/Widgets/ControlTree.cpp \ + ../src/common/Text/XmlTreeUi.cpp \ + ../src/common/Text/DeEscape.cpp \ + ../src/common/Lgi/StructuredLog.cpp \ + ../src/common/Lgi/LgiMain.cpp \ + ../src/common/Gdc2/Filters/Png.cpp SourceC := $(filter %.c,$(Source)) ObjectsC := $(SourceC:.c=.o) SourceCpp := $(filter %.cpp,$(Source)) ObjectsCpp := $(SourceCpp:.cpp=.o) Objects := $(notdir $(ObjectsC) $(ObjectsCpp)) Objects := $(addprefix $(BuildDir)/,$(Objects)) Deps := $(patsubst %.o,%.d,$(Objects)) $(BuildDir)/%.o: %.c mkdir -p $(@D) echo $(notdir $<) [$(Build)] $(CC) $(Inc) $(Flags) $(Defs) -c $< -o $@ $(BuildDir)/%.o: %.cpp mkdir -p $(@D) echo $(notdir $<) [$(Build)] $(CPP) $(Inc) $(Flags) $(Defs) -c $< -o $@ # 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/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/Emoji.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 export Build=$(Build); \ - $(MAKE) -C ../../ -f Makefile.linux + $(MAKE) -C ../ -f Makefile.linux -include $(Objects:.o=.d) # Clean just this target clean : rm -rf $(BuildDir) $(Target) @echo Cleaned $(BuildDir) $(Target) # Clean all targets cleanall : rm -rf $(BuildDir) $(Target) @echo Cleaned $(BuildDir) $(Target) - +make -C "../../" -f "Makefile.linux" clean + +make -C "../" -f "Makefile.linux" clean VPATH=$(BuildDir) \ - ../../src/common/Widgets \ - ../../src/common/Text \ - ../../src/common/Lgi \ - ../../src/common/Gdc2/Filters \ - ../src + ../src/common/Widgets \ + ../src/common/Text \ + ../src/common/Lgi \ + ../src/common/Gdc2/Filters \ + ./src diff --git a/Lvc/src/Lvc.h b/Lvc/src/Lvc.h --- a/Lvc/src/Lvc.h +++ b/Lvc/src/Lvc.h @@ -1,235 +1,235 @@ #ifndef _Lvc_h_ #define _Lvc_h_ #include "lgi/common/Lgi.h" #include "lgi/common/List.h" #include "lgi/common/Box.h" #include "lgi/common/Tree.h" #include "lgi/common/OptionsFile.h" #include "lgi/common/TextView3.h" #include "lgi/common/TextLog.h" #include "lgi/common/TabView.h" #include "lgi/common/Edit.h" #include "lgi/common/Menu.h" #include "lgi/common/Ssh.h" #include "lgi/common/EventTargetThread.h" #include "lgi/common/StructuredLog.h" #define OPT_Folders "Folders" #define OPT_Folder "Folder" #define METHOD_GetContext "GetContext" #define APP_VERSION "0.8" extern const char *AppName; extern void OpenPatchViewer(LViewI *Parent, LOptionsFile *Opts); enum LvcIcon { IcoFolder, IcoCleanFolder, IcoDirtyFolder, IcoFile, IcoCleanFile, IcoDirtyFile, }; enum LvcNotify { LvcBase = LNotifyUserApp, LvcCommandStart, LvcCommandEnd }; enum FileColumns { COL_CHECKBOX, COL_STATE, COL_FILENAME, }; enum AppIds { IDC_TOOLS_BOX = 100, IDC_FOLDERS_BOX, IDC_COMMITS_BOX, IDC_FILES_BOX, IDC_TXT, IDC_LOG, IDC_MSG_BOX, IDC_TAB_VIEW, IDC_FOLDER_TBL, // Contains the following controls: IDC_TREE, IDC_FILTER_FOLDERS, IDC_CLEAR_FILTER_FOLDERS, IDC_COMMITS_TBL, // Contains the following controls: IDC_LIST, IDC_FILTER_COMMITS, IDC_CLEAR_FILTER_COMMITS, IDC_FILES_TBL, // Contains the following controls: IDC_FILES, IDC_FILTER_FILES, IDC_CLEAR_FILTER_FILES, IDM_ADD_LOCAL = 200, IDM_ADD_REMOTE, IDM_UPDATE, IDM_COPY_REV, IDM_COPY_INDEX, IDM_RENAME_BRANCH, IDM_REMOVE, IDM_CLEAN, IDM_REVERT, IDM_REVERT_TO_REV, IDM_BLAME, IDM_SAVE_AS, IDM_BROWSE, IDM_LOG, IDM_EOL_LF, IDM_EOL_CRLF, IDM_EOL_AUTO, IDM_ADD_FILE, IDM_ADD_BINARY_FILE, IDM_BROWSE_FOLDER, IDM_TERMINAL, IDM_RESOLVE_MARK, IDM_RESOLVE_UNMARK, IDM_RESOLVE_LOCAL, IDM_RESOLVE_INCOMING, IDM_RESOLVE_TOOL, IDM_MERGE, IDM_LOG_FILE, IDM_COPY_PATH, IDM_COPY_LEAF, IDM_EDIT, IDM_REMOTE_URL, }; enum AppMessages { M_DETECT_VCS = M_USER + 100, M_RUN_CMD, M_RESPONSE, M_HANDLE_CALLBACK, }; enum VersionCtrl { VcNone, VcCvs, VcSvn, VcGit, VcHg, VcPending, VcError, VcMax, }; class VcFolder; struct ParseParams { LString Str; LString AltInitPath; class VcLeaf *Leaf = NULL; bool IsWorking = false;; bool Debug = false; std::function Callback; ParseParams(const char *str = NULL) { Str = str; } }; typedef bool (VcFolder::*ParseFn)(int, LString, ParseParams*); class SshConnection; struct AppPriv { VcFolder *CurFolder = NULL; LTree *Tree = NULL; LList *Commits = NULL; LList *Files = NULL; LEdit *Msg = NULL; LTextLog *Diff = NULL; LTextLog *Log = NULL; LTabView *Tabs = NULL; VersionCtrl PrevType = VcNone; LOptionsFile Opts; LStructuredLog sLog; int Resort = -1; // Filtering LString FolderFilter, CommitFilter, FileFilter; LHashTbl,SshConnection*> Connections; AppPriv() : Opts(LOptionsFile::DesktopMode, AppName), sLog("Lvc.slog") - { - - } + { + } + ~AppPriv(); SshConnection *GetConnection(const char *Uri, bool Create = true); auto Wnd() { return Commits ? Commits->GetWindow() : LAppInst->AppWnd; } void ClearFiles() { if (Files) Files->Empty(); if (Diff) Diff->Name(NULL); } LArray GetRevs(LString::Array &Revs); LString::Array GetCommitRange(); bool IsMenuChecked(int Item) { LMenu *m = Tree->GetWindow()->GetMenu(); LMenuItem *i = m ? m->FindItem(Item) : NULL; return i ? i->Checked() : false; } VersionCtrl DetectVcs(VcFolder *Fld); class VcFile *FindFile(const char *Path); }; #include "SshConnection.h" class BlameUi : public LWindow { struct BlameUiPriv *d; public: BlameUi(AppPriv *priv, VersionCtrl Vc, LString Output); ~BlameUi(); }; class DropDownBtn : public LDropDown, public ResObject { struct DropDownBtnPriv *d; class DropLst *Pu; public: DropDownBtn(); ~DropDownBtn(); LString::Array GetList(); bool SetList(int EditCtrl, LString::Array a); bool OnLayout(LViewLayoutInfo &Inf); }; extern bool ConvertEol(const char *Path, bool Cr); extern int GetEol(const char *Path); extern LString::Array GetProgramsInPath(const char *Program); extern LColour GetPaletteColour(int i); #include "VcFile.h" #include "VcCommit.h" #include "VcFolder.h" #endif diff --git a/Lvc/src/Main.cpp b/Lvc/src/Main.cpp --- a/Lvc/src/Main.cpp +++ b/Lvc/src/Main.cpp @@ -1,1710 +1,1718 @@ #include "lgi/common/Lgi.h" #include "lgi/common/TableLayout.h" #include "lgi/common/TextLog.h" #include "lgi/common/Button.h" #include "lgi/common/XmlTreeUi.h" #include "lgi/common/Tree.h" #include "lgi/common/FileSelect.h" #include "lgi/common/StructuredLog.h" #include "Lvc.h" #include "resdefs.h" #ifdef WINDOWS #include "resource.h" #endif ////////////////////////////////////////////////////////////////// const char *AppName = "Lvc"; #define DEFAULT_BUILD_FIX_MSG "Build fix." #define OPT_Hosts "Hosts" #define OPT_Host "Host" +AppPriv::~AppPriv() +{ + if (CurFolder) + CurFolder->Empty(); +} + SshConnection *AppPriv::GetConnection(const char *Uri, bool Create) { LUri u(Uri); u.sPath.Empty(); auto s = u.ToString(); auto Conn = Connections.Find(s); if (!Conn && Create) Connections.Add(s, Conn = new SshConnection(Log, s, "matthew@*$ ")); return Conn; } VersionCtrl AppPriv::DetectVcs(VcFolder *Fld) { char p[MAX_PATH_LEN]; LUri u = Fld->GetUri(); if (!u.IsFile() || !u.sPath) { auto c = GetConnection(u.ToString()); if (!c) return VcNone; auto type = c->Types.Find(u.sPath); if (type) return type; c->DetectVcs(Fld); Fld->GetCss(true)->Color(LColour::Blue); Fld->Update(); return VcPending; } auto Path = u.sPath.Get(); #ifdef WINDOWS if (*Path == '/') Path++; #endif if (LMakePath(p, sizeof(p), Path, ".git") && LDirExists(p)) return VcGit; if (LMakePath(p, sizeof(p), Path, ".svn") && LDirExists(p)) return VcSvn; if (LMakePath(p, sizeof(p), Path, ".hg") && LDirExists(p)) return VcHg; if (LMakePath(p, sizeof(p), Path, "CVS") && LDirExists(p)) return VcCvs; return VcNone; } class DiffView : public LTextLog { public: DiffView(int id) : LTextLog(id) { } void PourStyle(size_t Start, ssize_t Length) { for (auto ln : LTextView3::Line) { if (!ln->c.IsValid()) { char16 *t = Text + ln->Start; if (*t == '+') { ln->c = LColour::Green; ln->Back.Rgb(245, 255, 245); } else if (*t == '-') { ln->c = LColour::Red; ln->Back.Rgb(255, 245, 245); } else if (*t == '@') { ln->c.Rgb(128, 128, 128); ln->Back.Rgb(235, 235, 235); } else ln->c = LColour(L_TEXT); } } } }; class ToolBar : public LLayout, public LResourceLoad { public: ToolBar() { LAutoString Name; LRect Pos; if (LoadFromResource(IDD_TOOLBAR, this, &Pos, &Name)) { OnPosChange(); } else LAssert(!"Missing toolbar resource"); } void OnCreate() { AttachChildren(); } void OnPosChange() { LRect Cli = GetClient(); LTableLayout *v; if (GetViewById(IDC_TABLE, v)) { v->SetPos(Cli); v->OnPosChange(); auto r = v->GetUsedArea(); if (r.Y() <= 1) r.Set(0, 0, 30, 30); // printf("Used = %s\n", r.GetStr()); LCss::Len NewSz(LCss::LenPx, (float)r.Y()+3); auto OldSz = GetCss(true)->Height(); if (OldSz != NewSz) { GetCss(true)->Height(NewSz); SendNotify(LNotifyTableLayoutRefresh); } } else LAssert(!"Missing table ctrl"); } void OnPaint(LSurface *pDC) { pDC->Colour(LColour(L_MED)); pDC->Rectangle(); } }; class CommitCtrls : public LLayout, public LResourceLoad { public: CommitCtrls() { LAutoString Name; LRect Pos; if (LoadFromResource(IDD_COMMIT, this, &Pos, &Name)) { LTableLayout *v; if (GetViewById(IDC_COMMIT_TABLE, v)) { v->GetCss(true)->PaddingRight("8px"); LRect r = v->GetPos(); r.Offset(-r.x1, -r.y1); r.x2++; v->SetPos(r); v->OnPosChange(); r = v->GetUsedArea(); if (r.Y() <= 1) r.Set(0, 0, 30, 30); GetCss(true)->Height(LCss::Len(LCss::LenPx, (float)r.Y())); } else LAssert(!"Missing table ctrl"); } else LAssert(!"Missing toolbar resource"); } void OnPosChange() { LTableLayout *v; if (GetViewById(IDC_COMMIT_TABLE, v)) v->SetPos(GetClient()); } void OnCreate() { AttachChildren(); } }; LString::Array GetProgramsInPath(const char *Program) { LString::Array Bin; LString Prog = Program; #ifdef WINDOWS Prog += LGI_EXECUTABLE_EXT; #endif LString::Array a = LGetPath(); for (auto p : a) { LFile::Path c(p, Prog); if (c.Exists()) Bin.New() = c.GetFull(); } return Bin; } class OptionsDlg : public LDialog, public LXmlTreeUi { LOptionsFile &Opts; public: OptionsDlg(LViewI *Parent, LOptionsFile &opts) : Opts(opts) { SetParent(Parent); Map("svn-path", IDC_SVN, GV_STRING); Map("svn-limit", IDC_SVN_LIMIT); Map("git-path", IDC_GIT, GV_STRING); Map("git-limit", IDC_GIT_LIMIT); Map("hg-path", IDC_HG, GV_STRING); Map("hg-limit", IDC_HG_LIMIT); Map("cvs-path", IDC_CVS, GV_STRING); Map("cvs-limit", IDC_CVS_LIMIT); if (LoadFromResource(IDD_OPTIONS)) { MoveSameScreen(Parent); Convert(&Opts, this, true); } } void Browse(int EditId) { auto s = new LFileSelect; s->Parent(this); s->Open([this, EditId](auto s, auto status) { if (status) SetCtrlName(EditId, s->Name()); delete s; }); } void BrowseFiles(LViewI *Ctrl, const char *Bin, int EditId) { LRect Pos = Ctrl->GetPos(); LPoint Pt(Pos.x1, Pos.y2 + 1); PointToScreen(Pt); LSubMenu s; LString::Array Bins = GetProgramsInPath(Bin); for (unsigned i=0; i= 1000) { LString Bin = Bins[Cmd - 1000]; if (Bin) SetCtrlName(EditId, Bin); } break; } } } int OnNotify(LViewI *Ctrl, LNotification n) { switch (Ctrl->GetId()) { case IDC_SVN_BROWSE: BrowseFiles(Ctrl, "svn", IDC_SVN); break; case IDC_GIT_BROWSE: BrowseFiles(Ctrl, "git", IDC_GIT); break; case IDC_HG_BROWSE: BrowseFiles(Ctrl, "hg", IDC_HG); break; case IDC_CVS_BROWSE: BrowseFiles(Ctrl, "cvs", IDC_CVS); break; case IDOK: Convert(&Opts, this, false); // fall case IDCANCEL: { EndModal(Ctrl->GetId() == IDOK); break; } } return LDialog::OnNotify(Ctrl, n); } }; int CommitDataCmp(VcCommit **_a, VcCommit **_b) { auto a = *_a; auto b = *_b; return a->GetTs().Compare(&b->GetTs()); } LString::Array AppPriv::GetCommitRange() { LString::Array r; if (Commits) { LArray Sel; Commits->GetSelection(Sel); if (Sel.Length() > 1) { Sel.Sort(CommitDataCmp); r.Add(Sel[0]->GetRev()); r.Add(Sel.Last()->GetRev()); } else { r.Add(Sel[0]->GetRev()); } } else LAssert(!"No commit list ptr"); return r; } LArray AppPriv::GetRevs(LString::Array &Revs) { LArray a; for (auto i = Commits->begin(); i != Commits->end(); i++) { VcCommit *c = dynamic_cast(*i); if (c) { for (auto r: Revs) { if (r.Equals(c->GetRev())) { a.Add(c); break; } } } } return a; } class CommitList : public LList { public: CommitList(int id) : LList(id, 0, 0, 200, 200) { } void SelectRevisions(LString::Array &Revs, const char *BranchHint = NULL) { VcCommit *Scroll = NULL; LArray Matches; for (auto i: *this) { VcCommit *item = dynamic_cast(i); if (!item) continue; bool IsMatch = false; for (auto r: Revs) { if (item->IsRev(r)) { IsMatch = true; break; } } if (IsMatch) Matches.Add(item); else if (i->Select()) i->Select(false); } for (auto item: Matches) { auto b = item->GetBranch(); if (BranchHint) { if (!b || Stricmp(b, BranchHint)) continue; } else if (b) { continue; } if (!Scroll) Scroll = item; item->Select(true); } if (!Scroll && Matches.Length() > 0) { Scroll = Matches[0]; Scroll->Select(true); } if (Scroll) Scroll->ScrollTo(); } bool OnKey(LKey &k) { switch (k.c16) { case 'p': case 'P': { if (k.Down()) { LArray Sel; GetSelection(Sel); if (Sel.Length()) { auto first = Sel[0]; auto branch = first->GetBranch(); auto p = first->GetParents(); if (p->Length() == 0) break; for (auto c:Sel) c->Select(false); SelectRevisions(*p, branch); } } return true; } case 'c': case 'C': { if (k.Down()) { LArray Sel; GetSelection(Sel); if (Sel.Length()) { LHashTbl,VcCommit*> Map; for (auto s:Sel) Map.Add(s->GetRev(), s); LString::Array n; for (auto it = begin(); it != end(); it++) { VcCommit *c = dynamic_cast(*it); if (c) { for (auto r:*c->GetParents()) { if (Map.Find(r)) { n.Add(c->GetRev()); break; } } } } for (auto c:Sel) c->Select(false); SelectRevisions(n, Sel[0]->GetBranch()); } } return true; } } return LList::OnKey(k); } }; int LstCmp(LListItem *a, LListItem *b, int Col) { VcCommit *A = dynamic_cast(a); VcCommit *B = dynamic_cast(b); if (A == NULL || B == NULL) { return (A ? 1 : -1) - (B ? 1 : -1); } auto f = A->GetFolder(); auto flds = f->GetFields(); if (!flds.Length()) { LgiTrace("%s:%i - No fields?\n", _FL); return 0; } auto fld = flds[Col]; switch (fld) { case LGraph: case LIndex: case LParents: case LRevision: default: return (int) (B->GetIndex() - A->GetIndex()); case LBranch: case LAuthor: case LMessageTxt: return Stricmp(A->GetFieldText(fld), B->GetFieldText(fld)); case LTimeStamp: return B->GetTs().Compare(&A->GetTs()); } return 0; } struct TestThread : public LThread { public: TestThread() : LThread("test") { Run(); } int Main() { auto Path = LGetPath(); LSubProcess p("python", "/Users/matthew/CodeLib/test.py"); auto t = LString(LGI_PATH_SEPARATOR).Join(Path); for (auto s: Path) printf("s: %s\n", s.Get()); p.SetEnvironment("PATH", t); if (p.Start()) { LStringPipe s; p.Communicate(&s); printf("Test: %s\n", s.NewLStr().Get()); } return 0; } }; class RemoteFolderDlg : public LDialog { class App *app; LTree *tree; struct SshHost *root, *newhost; LXmlTreeUi Ui; public: LString Uri; RemoteFolderDlg(App *application); ~RemoteFolderDlg(); int OnNotify(LViewI *Ctrl, LNotification n); }; class VcDiffFile : public LTreeItem { AppPriv *d; LString File; public: VcDiffFile(AppPriv *priv, LString file) : d(priv), File(file) { } const char *GetText(int i = 0) override { return i ? NULL : File; } LString StripFirst(LString s) { return s.Replace("\\","/").SplitDelimit("/", 1).Last(); } void Select(bool s) override { LTreeItem::Select(s); if (s) { d->Files->Empty(); d->Diff->Name(NULL); LFile in(File, O_READ); LString s = in.Read(); if (!s) return; LString NewLine("\n"); LString::Array a = s.Replace("\r").Split("\n"); LArray index; LString oldName, newName; LString::Array Diff; VcFile *f = NULL; bool InPreamble = false; bool InDiff = false; for (unsigned i=0; iSetDiff(NewLine.Join(Diff)); f->Select(false); } Diff.Empty(); oldName.Empty(); newName.Empty(); InDiff = false; InPreamble = true; } else if (!Strnicmp(Ln, "Index", 5)) { if (InPreamble) index = a[i].SplitDelimit(": ", 1).Slice(1); } else if (!strncmp(Ln, "--- ", 4)) { auto p = a[i].SplitDelimit(" \t", 1); if (p.Length() > 1) oldName = p[1]; } else if (!strncmp(Ln, "+++ ", 4)) { auto p = a[i].SplitDelimit(" \t", 1); if (p.Length() > 1) newName = p[1]; if (oldName && newName) { InDiff = true; InPreamble = false; f = d->FindFile(newName); if (!f) f = new VcFile(d, NULL, NULL, false); const char *nullFn = "dev/null"; if (newName.Find(nullFn) >= 0) { // Delete f->SetText(StripFirst(oldName), COL_FILENAME); f->SetText("D", COL_STATE); } else { f->SetText(StripFirst(newName), COL_FILENAME); if (oldName.Find(nullFn) >= 0) // Add f->SetText("A", COL_STATE); else // Modify f->SetText("M", COL_STATE); } f->GetStatus(); d->Files->Insert(f); } } else if (!_strnicmp(Ln, "------", 6)) { InPreamble = !InPreamble; } else if (!_strnicmp(Ln, "======", 6)) { InPreamble = false; InDiff = true; } else if (InDiff) { Diff.Add(a[i]); } } if (f && Diff.Length()) { f->SetDiff(NewLine.Join(Diff)); Diff.Empty(); } } } }; class App : public LWindow, public AppPriv { LAutoPtr ImgLst; LBox *FoldersBox = NULL; bool CallMethod(const char *MethodName, LVariant *ReturnValue, LArray &Args) { if (!Stricmp(MethodName, METHOD_GetContext)) { *ReturnValue = (AppPriv*)this; return true; } return false; } public: App() { LString AppRev; AppRev.Printf("%s v%s", AppName, APP_VERSION); Name(AppRev); LRect r(0, 0, 1400, 800); SetPos(r); MoveToCenter(); SetQuitOnClose(true); Opts.SerializeFile(false); SerializeState(&Opts, "WndPos", true); #ifdef WINDOWS SetIcon(MAKEINTRESOURCEA(IDI_ICON1)); #else SetIcon("icon32.png"); #endif ImgLst.Reset(LLoadImageList("image-list.png", 16, 16)); if (Attach(0)) { if ((Menu = new LMenu)) { Menu->SetPrefAndAboutItems(IDM_OPTIONS, IDM_ABOUT); Menu->Attach(this); Menu->Load(this, "IDM_MENU"); } LBox *ToolsBox = new LBox(IDC_TOOLS_BOX, true, "ToolsBox"); FoldersBox = new LBox(IDC_FOLDERS_BOX, false, "FoldersBox"); LBox *CommitsBox = new LBox(IDC_COMMITS_BOX, true, "CommitsBox"); ToolBar *Tools = new ToolBar; ToolsBox->Attach(this); Tools->Attach(ToolsBox); FoldersBox->Attach(ToolsBox); auto FolderLayout = new LTableLayout(IDC_FOLDER_TBL); auto c = FolderLayout->GetCell(0, 0, true, 2); Tree = new LTree(IDC_TREE, 0, 0, 320, 200); Tree->SetImageList(ImgLst, false); Tree->ShowColumnHeader(true); Tree->AddColumn("Folder", 250); Tree->AddColumn("Counts", 50); c->Add(Tree); c = FolderLayout->GetCell(0, 1); c->Add(new LEdit(IDC_FILTER_FOLDERS, 0, 0, -1, -1)); c = FolderLayout->GetCell(1, 1); c->Add(new LButton(IDC_CLEAR_FILTER_FOLDERS, 0, 0, -1, -1, "x")); FolderLayout->Attach(FoldersBox); CommitsBox->Attach(FoldersBox); auto CommitsLayout = new LTableLayout(IDC_COMMITS_TBL); c = CommitsLayout->GetCell(0, 0, true, 2); Commits = new CommitList(IDC_LIST); c->Add(Commits); c = CommitsLayout->GetCell(0, 1); c->Add(new LEdit(IDC_FILTER_COMMITS, 0, 0, -1, -1)); c = CommitsLayout->GetCell(1, 1); c->Add(new LButton(IDC_CLEAR_FILTER_COMMITS, 0, 0, -1, -1, "x")); CommitsLayout->Attach(CommitsBox); CommitsLayout->GetCss(true)->Height("40%"); LBox *FilesBox = new LBox(IDC_FILES_BOX, false); FilesBox->Attach(CommitsBox); auto FilesLayout = new LTableLayout(IDC_FILES_TBL); c = FilesLayout->GetCell(0, 0, true, 2); Files = new LList(IDC_FILES, 0, 0, 200, 200); Files->AddColumn("[ ]", 30); Files->AddColumn("State", 100); Files->AddColumn("Name", 400); c->Add(Files); c = FilesLayout->GetCell(0, 1); c->Add(new LEdit(IDC_FILTER_FILES, 0, 0, -1, -1)); c = FilesLayout->GetCell(1, 1); c->Add(new LButton(IDC_CLEAR_FILTER_FILES, 0, 0, -1, -1, "x")); FilesLayout->GetCss(true)->Width("35%"); FilesLayout->Attach(FilesBox); LBox *MsgBox = new LBox(IDC_MSG_BOX, true); MsgBox->Attach(FilesBox); CommitCtrls *Commit = new CommitCtrls; Commit->Attach(MsgBox); Commit->GetCss(true)->Height("25%"); if (Commit->GetViewById(IDC_MSG, Msg)) { LTextView3 *Tv = dynamic_cast(Msg); if (Tv) { Tv->Sunken(true); Tv->SetWrapType(TEXTED_WRAP_NONE); } } else LAssert(!"No ctrl?"); Tabs = new LTabView(IDC_TAB_VIEW); Tabs->Attach(MsgBox); const char *Style = "Padding: 0px 8px 8px 0px"; Tabs->GetCss(true)->Parse(Style); LTabPage *p = Tabs->Append("Diff"); p->Append(Diff = new DiffView(IDC_TXT)); // Diff->Sunken(true); Diff->SetWrapType(TEXTED_WRAP_NONE); p = Tabs->Append("Log"); p->Append(Log = new LTextLog(IDC_LOG)); // Log->Sunken(true); Log->SetWrapType(TEXTED_WRAP_NONE); SetCtrlValue(IDC_UPDATE, true); AttachChildren(); Visible(true); } LXmlTag *f = Opts.LockTag(OPT_Folders, _FL); if (!f) { Opts.CreateTag(OPT_Folders); f = Opts.LockTag(OPT_Folders, _FL); } if (f) { bool Req[VcMax] = {0}; for (auto c: f->Children) { if (c->IsTag(OPT_Folder)) { auto f = new VcFolder(this, c); Tree->Insert(f); if (!Req[f->GetType()]) { Req[f->GetType()] = true; f->GetVersion(); } } } Opts.Unlock(); LRect Large(0, 0, 2000, 200); Tree->SetPos(Large); Tree->ResizeColumnsToContent(); LItemColumn *c; int i = 0, px = 0; while ((c = Tree->ColumnAt(i++))) { px += c->Width(); } FoldersBox->Value(MAX(320, px + 20)); // new TestThread(); } SetPulse(200); DropTarget(true); } ~App() { SerializeState(&Opts, "WndPos", false); SaveFolders(); } void SaveFolders() { LXmlTag *f = Opts.LockTag(OPT_Folders, _FL); if (!f) return; f->EmptyChildren(); for (auto i: *Tree) { VcFolder *vcf = dynamic_cast(i); if (vcf) f->InsertTag(vcf->Save()); } Opts.Unlock(); Opts.SerializeFile(true); } LMessage::Result OnEvent(LMessage *Msg) { switch (Msg->Msg()) { case M_RESPONSE: { SshConnection::HandleMsg(Msg); break; } case M_HANDLE_CALLBACK: { LAutoPtr Pc((ProcessCallback*)Msg->A()); if (Pc) Pc->OnComplete(); break; } } return LWindow::OnEvent(Msg); } void OnReceiveFiles(LArray &Files) { for (auto f : Files) { if (LDirExists(f)) OpenLocalFolder(f); } } int OnCommand(int Cmd, int Event, OsView Wnd) { switch (Cmd) { case IDM_PATCH_VIEWER: { OpenPatchViewer(this, &Opts); break; } case IDM_OPEN_LOCAL: { OpenLocalFolder(); break; } case IDM_OPEN_REMOTE: { OpenRemoteFolder(); break; } case IDM_OPEN_DIFF: { auto s = new LFileSelect; s->Parent(this); s->Open([this](auto dlg, auto status) { if (status) OpenDiff(dlg->Name()); delete dlg; }); break; } case IDM_OPTIONS: { auto Dlg = new OptionsDlg(this, Opts); Dlg->DoModal([](auto dlg, auto ctrlId) { delete dlg; }); break; } case IDM_FIND: { auto i = new LInput(this, "", "Search string:"); i->DoModal([this, i](auto dlg, auto ctrlId) { if (ctrlId == IDOK) { LString::Array Revs; Revs.Add(i->GetStr()); CommitList *cl; if (GetViewById(IDC_LIST, cl)) cl->SelectRevisions(Revs); } delete dlg; }); break; } case IDM_UNTRACKED: { auto mi = GetMenu()->FindItem(IDM_UNTRACKED); if (!mi) break; mi->Checked(!mi->Checked()); LArray Flds; Tree->GetSelection(Flds); for (auto f : Flds) { f->Refresh(); } break; } case IDM_REFRESH: { LArray Flds; Tree->GetSelection(Flds); for (auto f: Flds) f->Refresh(); break; } case IDM_PULL: { LArray Flds; Tree->GetSelection(Flds); for (auto f: Flds) f->Pull(); break; } case IDM_PUSH: { LArray Flds; Tree->GetSelection(Flds); for (auto f: Flds) f->Push(); break; } case IDM_STATUS: { LArray Flds; Tree->GetSelection(Flds); for (auto f: Flds) f->FolderStatus(); break; } case IDM_UPDATE_SUBS: { LArray Flds; Tree->GetSelection(Flds); for (auto f: Flds) f->UpdateSubs(); break; break; } case IDM_EXIT: { LCloseApp(); break; } } return 0; } void OnPulse() { for (auto i:*Tree) { VcFolder *vcf = dynamic_cast(i); if (vcf) vcf->OnPulse(); } } void OpenLocalFolder(const char *Fld = NULL) { auto Load = [this](const char *Fld) { // Check the folder isn't already loaded... bool Has = false; LArray Folders; Tree->GetAll(Folders); for (auto f: Folders) { if (f->GetUri().IsFile() && !Stricmp(f->LocalPath(), Fld)) { Has = true; break; } } if (!Has) { LUri u; u.SetFile(Fld); auto f = new VcFolder(this, u.ToString()); if (f) { Tree->Insert(f); SaveFolders(); } } }; if (!Fld) { auto s = new LFileSelect; s->Parent(this); s->OpenFolder([this, Load](auto s, auto status) { if (status) Load(s->Name()); delete s; }); } else Load(Fld); } void OpenRemoteFolder() { auto Dlg = new RemoteFolderDlg(this); Dlg->DoModal([this, Dlg](auto dlg, auto status) { if (status) { Tree->Insert(new VcFolder(this, Dlg->Uri)); SaveFolders(); } delete dlg; }); } void OpenDiff(const char *File) { Tree->Insert(new VcDiffFile(this, File)); } void OnFilterFolders() { if (!Tree) return; for (auto i = Tree->GetChild(); i; i = i->GetNext()) { auto n = i->GetText(); bool vis = !FolderFilter || Stristr(n, FolderFilter.Get()) != NULL; i->GetCss(true)->Display(vis ? LCss::DispBlock : LCss::DispNone); } Tree->UpdateAllItems(); Tree->Invalidate(); } void OnFilterCommits() { if (!Commits) return; LArray a; if (!Commits->GetAll(a)) return; auto cols = Commits->GetColumns(); for (auto i: a) { bool vis = !CommitFilter; for (int c=1; !vis && cGetText(c); if (Stristr(txt, CommitFilter.Get())) vis = true; } i->GetCss(true)->Display(vis ? LCss::DispBlock : LCss::DispNone); } Commits->UpdateAllItems(); Commits->Invalidate(); } void OnFilterFiles() { VcFolder *f = dynamic_cast(Tree->Selection()); if (f) f->FilterCurrentFiles(); } int OnNotify(LViewI *c, LNotification n) { switch (c->GetId()) { case IDC_CLEAR_FILTER_FOLDERS: { SetCtrlName(IDC_FILTER_FOLDERS, NULL); // Fall through } case IDC_FILTER_FOLDERS: { if (n.Type == LNotifyEscapeKey) SetCtrlName(IDC_FILTER_FOLDERS, NULL); LString n = GetCtrlName(IDC_FILTER_FOLDERS); if (n != FolderFilter) { FolderFilter = n; OnFilterFolders(); } break; } case IDC_CLEAR_FILTER_COMMITS: { SetCtrlName(IDC_FILTER_COMMITS, NULL); // Fall through } case IDC_FILTER_COMMITS: { if (n.Type == LNotifyEscapeKey) SetCtrlName(IDC_FILTER_COMMITS, NULL); LString n = GetCtrlName(IDC_FILTER_COMMITS); if (n != CommitFilter) { CommitFilter = n; OnFilterCommits(); } break; } case IDC_CLEAR_FILTER_FILES: { SetCtrlName(IDC_FILTER_FILES, NULL); // Fall through } case IDC_FILTER_FILES: { if (n.Type == LNotifyEscapeKey) SetCtrlName(IDC_FILTER_FILES, NULL); LString n = GetCtrlName(IDC_FILTER_FILES); if (n != FileFilter) { FileFilter = n; OnFilterFiles(); } break; } case IDC_FILES: { switch (n.Type) { case LNotifyItemColumnClicked: { int Col = -1; LMouse m; if (Files->GetColumnClickInfo(Col, m)) { if (Col == 0) { // Select / deselect all check boxes.. List n; if (Files->GetAll(n)) { bool Checked = false; for (auto f: n) Checked |= f->Checked() > 0; for (auto f: n) f->Checked(Checked ? 0 : 1); } } } break; } default: break; } break; } case IDC_OPEN: { OpenLocalFolder(); break; } case IDC_TREE: { switch (n.Type) { case LNotifyContainerClick: { LMouse m; c->GetMouse(m); if (m.Right()) { LSubMenu s; s.AppendItem("Add Local", IDM_ADD_LOCAL); s.AppendItem("Add Remote", IDM_ADD_REMOTE); int Cmd = s.Float(c->GetGView(), m); switch (Cmd) { case IDM_ADD_LOCAL: { OpenLocalFolder(); break; } case IDM_ADD_REMOTE: { OpenRemoteFolder(); break; } } } break; } case (LNotifyType)LvcCommandStart: { SetCtrlEnabled(IDC_PUSH, false); SetCtrlEnabled(IDC_PULL, false); SetCtrlEnabled(IDC_PULL_ALL, false); break; } case (LNotifyType)LvcCommandEnd: { SetCtrlEnabled(IDC_PUSH, true); SetCtrlEnabled(IDC_PULL, true); SetCtrlEnabled(IDC_PULL_ALL, true); break; } default: break; } break; } case IDC_COMMIT_AND_PUSH: case IDC_COMMIT: { auto BuildFix = GetCtrlValue(IDC_BUILD_FIX); const char *Msg = GetCtrlName(IDC_MSG); if (BuildFix || ValidStr(Msg)) { auto Sel = Tree->Selection(); if (Sel) { VcFolder *f = dynamic_cast(Sel); if (!f) { for (auto p = Sel->GetParent(); p; p = p->GetParent()) { f = dynamic_cast(p); if (f) break; } } if (f) { auto Branch = GetCtrlName(IDC_BRANCH); bool AndPush = c->GetId() == IDC_COMMIT_AND_PUSH; f->Commit(BuildFix ? DEFAULT_BUILD_FIX_MSG : Msg, ValidStr(Branch) ? Branch : NULL, AndPush); } } } else LgiMsg(this, "No message for commit.", AppName); break; } case IDC_PUSH: { VcFolder *f = dynamic_cast(Tree->Selection()); if (f) f->Push(); break; } case IDC_PULL: { VcFolder *f = dynamic_cast(Tree->Selection()); if (f) f->Pull(); break; } case IDC_PULL_ALL: { LArray Folders; Tree->GetAll(Folders); bool AndUpdate = GetCtrlValue(IDC_UPDATE) != 0; for (auto f : Folders) { f->Pull(AndUpdate, LogSilo); } break; } case IDC_STATUS: { LArray Folders; Tree->GetAll(Folders); for (auto f : Folders) { f->FolderStatus(); } break; } case IDC_HEADS: { if (n.Type == LNotifyValueChanged) { auto Revs = LString(c->Name()).SplitDelimit(); CommitList *cl; if (GetViewById(IDC_LIST, cl)) cl->SelectRevisions(Revs); } break; } case IDC_LIST: { switch (n.Type) { case LNotifyItemColumnClicked: { int Col = -1; LMouse Ms; Commits->GetColumnClickInfo(Col, Ms); Commits->Sort(LstCmp, Col); break; } case LNotifyItemDoubleClick: { VcFolder *f = dynamic_cast(Tree->Selection()); if (!f) break; LArray s; if (Commits->GetSelection(s) && s.Length() == 1) f->OnUpdate(s[0]->GetRev()); break; } default: break; } break; } } return 0; } }; struct SshHost : public LTreeItem { LXmlTag *t; LString Host, User, Pass; SshHost(LXmlTag *tag = NULL) { t = tag; if (t) { Serialize(false); SetText(Host); } } void Serialize(bool WriteToTag) { if (WriteToTag) { LUri u; u.sProtocol = "ssh"; u.sHost = Host; u.sUser = User; u.sPass = Pass; t->SetContent(u.ToString()); } else { LUri u(t->GetContent()); if (!Stricmp(u.sProtocol.Get(), "ssh")) { Host = u.sHost; User = u.sUser; Pass = u.sPass; } } } }; RemoteFolderDlg::RemoteFolderDlg(App *application) : app(application), root(NULL), newhost(NULL), tree(NULL) { SetParent(app); LoadFromResource(IDD_REMOTE_FOLDER); if (GetViewById(IDC_HOSTS, tree)) { printf("tree=%p\n", tree); tree->Insert(root = new SshHost()); root->SetText("Ssh Hosts"); } else return; LViewI *v; if (GetViewById(IDC_HOSTNAME, v)) v->Focus(true); Ui.Map("Host", IDC_HOSTNAME); Ui.Map("User", IDC_USER); Ui.Map("Password", IDC_PASS); LXmlTag *hosts = app->Opts.LockTag(OPT_Hosts, _FL); if (hosts) { SshHost *h; for (auto c: hosts->Children) if (c->IsTag(OPT_Host) && (h = new SshHost(c))) root->Insert(h); app->Opts.Unlock(); } root->Insert(newhost = new SshHost()); newhost->SetText("New Host"); root->Expanded(true); newhost->Select(true); } RemoteFolderDlg::~RemoteFolderDlg() { } int RemoteFolderDlg::OnNotify(LViewI *Ctrl, LNotification n) { SshHost *cur = tree ? dynamic_cast(tree->Selection()) : NULL; #define CHECK_SPECIAL() \ if (cur == newhost) \ { \ root->Insert(cur = new SshHost()); \ cur->Select(true); \ } \ if (cur == root) \ break; switch (Ctrl->GetId()) { case IDC_HOSTS: { switch (n.Type) { case LNotifyItemSelect: { bool isRoot = cur == root; SetCtrlEnabled(IDC_HOSTNAME, !isRoot); SetCtrlEnabled(IDC_USER, !isRoot); SetCtrlEnabled(IDC_PASS, !isRoot); SetCtrlEnabled(IDC_DELETE, !isRoot && !(cur == newhost)); SetCtrlName(IDC_HOSTNAME, cur ? cur->Host : NULL); SetCtrlName(IDC_USER, cur ? cur->User : NULL); SetCtrlName(IDC_PASS, cur ? cur->Pass : NULL); break; } default: break; } break; } case IDC_HOSTNAME: { CHECK_SPECIAL() if (cur) { cur->Host = Ctrl->Name(); cur->SetText(cur->Host ? cur->Host : ""); } break; } case IDC_DELETE: { auto sel = tree ? dynamic_cast(tree->Selection()) : NULL; if (!sel) break; LXmlTag *hosts = app->Opts.LockTag(OPT_Hosts, _FL); if (!hosts) { LAssert(!"Couldn't lock tag."); break; } if (hosts->Children.HasItem(sel->t)) { sel->t->RemoveTag(); DeleteObj(sel->t); delete sel; } app->Opts.Unlock(); break; } case IDC_USER: { CHECK_SPECIAL() if (cur) cur->User = Ctrl->Name(); break; } case IDC_PASS: { CHECK_SPECIAL() if (cur) cur->Pass = Ctrl->Name(); break; } case IDOK: { LXmlTag *hosts; if (!(hosts = app->Opts.LockTag(OPT_Hosts, _FL))) { if (!(app->Opts.CreateTag(OPT_Hosts) && (hosts = app->Opts.LockTag(OPT_Hosts, _FL)))) break; } LAssert(hosts != NULL); for (auto i = root->GetChild(); i; i = i->GetNext()) { SshHost *h = dynamic_cast(i); if (!h || h == newhost) continue; if (h->t) ; else if ((h->t = new LXmlTag(OPT_Host))) hosts->InsertTag(cur->t); else return false; h->Serialize(true); } app->Opts.Unlock(); LUri u; u.sProtocol = "ssh"; u.sHost = GetCtrlName(IDC_HOSTNAME); u.sUser = GetCtrlName(IDC_USER); u.sPass = GetCtrlName(IDC_PASS); u.sPath = GetCtrlName(IDC_REMOTE_PATH); Uri = u.ToString(); // Fall through } case IDCANCEL: { EndModal(Ctrl->GetId() == IDOK); break; } } return 0; } ////////////////////////////////////////////////////////////////// int LgiMain(OsAppArguments &AppArgs) { LApp a(AppArgs, AppName); if (a.IsOk()) { // LStructuredLog::UnitTest(); a.AppWnd = new App; a.Run(); + + DeleteObj(a.AppWnd); } LAssert(VcCommit::Instances == 0); return 0; } diff --git a/Lvc/src/VcFolder.h b/Lvc/src/VcFolder.h --- a/Lvc/src/VcFolder.h +++ b/Lvc/src/VcFolder.h @@ -1,374 +1,374 @@ #ifndef _VcFolder_h_ #define _VcFolder_h_ #include "lgi/common/SubProcess.h" #include class VcLeaf; enum LoggingType { LogNone, // No output from cmd LogNormal, // Output appears as it's available LogSilo, // Output appears after cmd finished (keeps it non-interleaved with other log msgs) }; enum LvcError { ErrNone, ErrSubProcessFailed = GSUBPROCESS_ERROR, }; enum LvcStatus { StatusNone, StatusActive, StatusError, }; enum LvcResolve { ResolveNone, //--- ResolveMark, ResolveUnmark, //--- ResolveLocal, ResolveIncoming, ResolveTool, }; class ReaderThread : public LThread { VersionCtrl Vcs; LStream *Out; LAutoPtr Process; int FilterCount; int OnLine(char *s, ssize_t len); bool OnData(char *Buf, ssize_t &r); public: int Result; ReaderThread(VersionCtrl vcs, LAutoPtr p, LStream *out); ~ReaderThread(); int Main(); }; extern int Ver2Int(LString v); extern int ToolVersion[VcMax]; extern int LstCmp(LListItem *a, LListItem *b, int Col); struct Result { int Code; LString Out; }; struct ProcessCallback : public LThread, public LSubProcess { Result Ret; LView *View = NULL; LTextLog *Log = NULL; std::function Callback; public: ProcessCallback(LString exe, LString args, LString localPath, LTextLog *log, LView *view, std::function callback); int Main(); void OnComplete(); }; struct VcBranch : public LString { bool Default; LColour Colour; LString Hash; VcBranch(LString name, LString hash = NULL) { Default = name.Equals("default") || name.Equals("trunk") || name.Equals("main"); Set(name); if (hash) Hash = hash; } }; struct SshParams { SshConnection *c; VcFolder *f; LString Exe, Args, Path, Output; VersionCtrl Vcs; ParseFn Parser; ParseParams *Params; int ExitCode; SshParams(SshConnection *con) : c(con) { f = NULL; Parser = NULL; Params = NULL; Vcs = VcNone; ExitCode = -1; } }; class VcFolder : public LTreeItem { friend class VcCommit; class Cmd : public LStream { LString::Array Context; LStringPipe Buf; public: LoggingType Logging; LStream *Log; LAutoPtr Rd; ParseFn PostOp; LAutoPtr Params; LvcError Err; Cmd(LString::Array &context, LoggingType logging, LStream *log) { Context = context; Logging = logging; Log = log; Err = ErrNone; } ~Cmd() { } LString GetBuf() { LString s = Buf.NewLStr(); if (Log && Logging == LogSilo) { LString m; m.Printf("=== %s ===\n\t%s %s\n", Context[0].Get(), Context[1].Get(), Context[2].Get()); Log->Write(m.Get(), m.Length()); auto Lines = s.Split("\n"); for (auto Ln : Lines) Log->Print("\t%s\n", Ln.Get()); } return s; } ssize_t Write(const void *Ptr, ssize_t Size, int Flags = 0) { ssize_t Wr = Buf.Write(Ptr, Size, Flags); if (Log && Logging == LogNormal) Log->Write(Ptr, Size, Flags); if (Flags) Err = (LvcError) Flags; return Wr; } }; class UncommitedItem : public LListItem { AppPriv *d; public: UncommitedItem(AppPriv *priv) { d = priv; } void OnPaint(LItem::ItemPaintCtx &Ctx); void Select(bool b); }; AppPriv *d; VersionCtrl Type; LUri Uri; LString CurrentCommit, RepoUrl, VcCmd; int64 CurrentCommitIdx; LArray Log; LString CurrentBranch; LHashTbl,VcBranch*> Branches; LAutoPtr Uncommit; LString Cache, NewRev; bool CommitListDirty = false; int Unpushed = 0, Unpulled = 0; LString CountCache; LTreeItem *Tmp = NULL; int CmdErrors = 0; LArray Fields; // Git specific LHashTbl,LString> GitNames; void AddGitName(LString Hash, LString Name); LString GetGitNames(LString Hash); static int CmdMaxThreads; static int CmdActiveThreads; struct GitCommit { LString::Array Files; LString Msg, Branch; ParseParams *Param; GitCommit() { Param = NULL; } }; LAutoPtr PostAdd; void GitAdd(); LArray Cmds; bool IsLogging, IsUpdate, IsFilesCmd, IsWorkingFld, IsCommit, IsUpdatingCounts; LvcStatus IsBranches, IsIdent; void Init(AppPriv *priv); const char *GetVcName(); bool StartCmd(const char *Args, ParseFn Parser = NULL, ParseParams *Params = NULL, LoggingType Logging = LogNone); bool RunCmd(const char *Args, LoggingType Logging, std::function Callback); void OnBranchesChange(); void OnCmdError(LString Output, const char *Msg); void ClearError(); VcFile *FindFile(const char *Path); void LinkParents(); void CurrentRev(std::function Callback); LColour BranchColour(const char *Name); - void Empty(); bool ParseDiffs(LString s, LString Rev, bool IsWorking); bool ParseRevList(int Result, LString s, ParseParams *Params); bool ParseLog(int Result, LString s, ParseParams *Params); bool ParseInfo(int Result, LString s, ParseParams *Params); bool ParseFiles(int Result, LString s, ParseParams *Params); bool ParseWorking(int Result, LString s, ParseParams *Params); bool ParseUpdate(int Result, LString s, ParseParams *Params); bool ParseCommit(int Result, LString s, ParseParams *Params); bool ParseGitAdd(int Result, LString s, ParseParams *Params); bool ParsePush(int Result, LString s, ParseParams *Params); bool ParsePull(int Result, LString s, ParseParams *Params); bool ParseCounts(int Result, LString s, ParseParams *Params); bool ParseRevert(int Result, LString s, ParseParams *Params); bool ParseResolveList(int Result, LString s, ParseParams *Params); bool ParseResolve(int Result, LString s, ParseParams *Params); bool ParseBlame(int Result, LString s, ParseParams *Params); bool ParseSaveAs(int Result, LString s, ParseParams *Params); bool ParseBranches(int Result, LString s, ParseParams *Params); bool ParseStatus(int Result, LString s, ParseParams *Params); bool ParseAddFile(int Result, LString s, ParseParams *Params); bool ParseVersion(int Result, LString s, ParseParams *Params); bool ParseClean(int Result, LString s, ParseParams *Params); bool ParseDiff(int Result, LString s, ParseParams *Params); bool ParseMerge(int Result, LString s, ParseParams *Params); bool ParseCountToTip(int Result, LString s, ParseParams *Params); bool ParseUpdateSubs(int Result, LString s, ParseParams *Params); bool ParseRemoteFind(int Result, LString s, ParseParams *Params); bool ParseStartBranch(int Result, LString s, ParseParams *Params); void DoExpand(); public: VcFolder(AppPriv *priv, const char *uri); VcFolder(AppPriv *priv, LXmlTag *t); ~VcFolder(); VersionCtrl GetType(); AppPriv *GetPriv() { return d; } const char *LocalPath(); LUri GetUri() { return Uri; } VcLeaf *FindLeaf(const char *Path, bool OpenTree); void DefaultFields(); void UpdateColumns(); const char *GetText(int Col); LArray &GetFields() { return Fields; } bool Serialize(LXmlTag *t, bool Write); LXmlTag *Save(); + void Empty(); void Select(bool b); void ListCommit(VcCommit *c); void ListWorkingFolder(); void FolderStatus(const char *Path = NULL, VcLeaf *Notify = NULL); void Commit(const char *Msg, const char *Branch, bool AndPush); void StartBranch(const char *BranchName, const char *OnCreated = NULL); void Push(bool NewBranchOk = false); void Pull(int AndUpdate = -1, LoggingType Logging = LogNormal); void Clean(); bool Revert(LString::Array &uris, const char *Revision = NULL); bool Resolve(const char *Path, LvcResolve Type); bool AddFile(const char *Path, bool AsBinary = true); bool Blame(const char *Path); bool SaveFileAs(const char *Path, const char *Revision); void ReadDir(LTreeItem *Parent, const char *Uri); void SetEol(const char *Path, int Type); void GetVersion(); void Diff(VcFile *file); void DiffRange(const char *FromRev, const char *ToRev); void MergeToLocal(LString Rev); bool RenameBranch(LString NewName, LArray &Revs); void Refresh(); bool GetBranches(ParseParams *Params = NULL); void GetCurrentRevision(ParseParams *Params = NULL); void CountToTip(); bool UpdateSubs(); // Clone/checkout any sub-repositries. void LogFile(const char *Path); LString GetFilePart(const char *uri); void FilterCurrentFiles(); void GetRemoteUrl(std::function Callback); void OnPulse(); void OnUpdate(const char *Rev); void OnMouseClick(LMouse &m); void OnRemove(); void OnExpand(bool b); void OnVcsType(LString errorMsg); void OnSshCmd(SshParams *p); }; class VcLeaf : public LTreeItem { AppPriv *d; VcFolder *Parent; bool Folder; LUri Uri; LString Leaf; LTreeItem *Tmp; void DoExpand(); public: LArray Log; VcLeaf(VcFolder *parent, LTreeItem *Item, LString uri, LString leaf, bool folder); ~VcLeaf(); LString Full(); VcLeaf *FindLeaf(const char *Path, bool OpenTree); void OnBrowse(); void AfterBrowse(); void OnExpand(bool b); const char *GetText(int Col); int GetImage(int Flags); int Compare(VcLeaf *b); bool Select(); void Select(bool b); void OnMouseClick(LMouse &m); void ShowLog(); }; #endif 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,1918 +1,1922 @@ #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) { 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; } + + // This needs to be before the 'gtk_widget_destroy' because that will delete the menu's widgets. + DeleteObj(Menu); + 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; iName()); 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) { }