diff --git a/Ide/LgiIdeProj.xml b/Ide/LgiIdeProj.xml
--- a/Ide/LgiIdeProj.xml
+++ b/Ide/LgiIdeProj.xml
@@ -1,288 +1,269 @@
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
.\buildHaiku.py
- ./Makefile.linux
+ ./linux/Makefile.linux
./MacCocoa/LgiIde.xcodeproj
Makefile.haiku
./lgiide
./lgiide
LgiIde.exe
LgiIde.exe
WINDOWS
WINNATIVE
WINDOWS
WINNATIVE
POSIX
POSIX
LIBPNG_VERSION=\"1.2\"
LIBPNG_VERSION=\"1.2\"
MingW
/home/matthew/Code/Lgi/trunk/Ide/Code/IdeProjectSettings.cpp
-
-
- ./Code
-./Resources
+ ./src
+./resources
../include
- ./Code
-./Resources
+ ./src
+./resources
../include
..\include\lgi\win
/local/include
..\include\lgi\win
/local/include
../include/lgi/linux
../include/lgi/linux/Gtk
../../../../codelib/openssl/include
../include/lgi/linux
../include/lgi/linux/Gtk
../../../../codelib/openssl/include
../include/lgi/haiku
../include/lgi/haiku
../include/lgi/mac/cocoa
../include/lgi/mac/cocoa
imm32
imm32
magic
pthread
`pkg-config --libs gtk+-3.0`
-static-libgcc
magic
pthread
`pkg-config --libs gtk+-3.0`
-static-libgcc
-static-libgcc
gnu
network
be
-static-libgcc
gnu
network
be
-
..\Debug
..\Release
-
Executable
lgiide
lgiide
LgiIde.exe
LgiIde.exe
lgiide
lgiide
C:\Data\CodeLib\Gtk\include\gtk-2.0\gtk
C:\Data\CodeLib\Gtk\include\gtk-2.0\gdk
C:\Data\CodeLib\Gtk\include\gtk-2.0\gtk
C:\Data\CodeLib\Gtk\include\gtk-2.0\gdk
`pkg-config --cflags gtk+-3.0`
`pkg-config --cflags gtk+-3.0`
-
POSIX
_GNU_SOURCE
POSIX
_GNU_SOURCE
-
-
4
4
0
1
-
-
SOME_TEST=testing
-
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
diff --git a/Ide/linux/Makefile.linux b/Ide/linux/Makefile.linux
--- a/Ide/linux/Makefile.linux
+++ b/Ide/linux/Makefile.linux
@@ -1,422 +1,422 @@
#!/usr/bin/make
#
# This makefile generated by LgiIde
# http://www.memecode.com/lgi.php
#
.SILENT :
CC = gcc
CPP = g++
Target = ./lgiide
ifndef Build
Build = Debug
endif
BuildDir = $(Build)
Flags = -fPIC -w -fno-inline -fpermissive
ifeq ($(Build),Debug)
Flags += -g -std=c++14
Tag = d
Defs = -D_DEBUG -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX
Libs = \
-L../Debug \
-lmagic \
-lpthread \
`pkg-config --libs gtk+-3.0` \
-static-libgcc \
-llgi-gtk3$(Tag) \
-L../$(BuildDir)
Inc = \
`pkg-config --cflags gtk+-3.0` \
- -I./Resources \
- -I./Code \
+ -I./src \
+ -I./resources \
-I../include/lgi/linux/Gtk \
-I../include/lgi/linux \
-I../include \
-I../../../../codelib/openssl/include
else
Flags += -s -Os -std=c++14
Defs = -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX
Libs = \
-L../Release \
-lmagic \
-lpthread \
`pkg-config --libs gtk+-3.0` \
-static-libgcc \
-llgi-gtk3$(Tag) \
-L../$(BuildDir)
Inc = \
`pkg-config --cflags gtk+-3.0` \
- -I./Resources \
- -I./Code \
+ -I./src \
+ -I./resources \
-I../include/lgi/linux/Gtk \
-I../include/lgi/linux \
-I../include \
-I../../../../codelib/openssl/include
endif
# Dependencies
-Source = Code/WebFldDlg.cpp \
- Code/SysCharSupport.cpp \
- Code/SpaceTabConv.cpp \
- Code/SimpleCppParser.cpp \
- Code/PythonParser.cpp \
- Code/ProjectNode.cpp \
- Code/NewProjectFromTemplate.cpp \
- Code/MissingFiles.cpp \
- Code/MemDumpViewer.cpp \
- Code/LgiUtils.cpp \
- Code/LgiIde.cpp \
- Code/levenshtein.c \
- Code/JavascriptParser.cpp \
- Code/IdeProjectSettings.cpp \
- Code/IdeProject.cpp \
- Code/IdeDoc.cpp \
- Code/IdeCommon.cpp \
- Code/History.cpp \
- Code/FtpThread.cpp \
- Code/FindSymbol.cpp \
- Code/FindInFiles.cpp \
- Code/DocEditStyling.cpp \
- Code/DocEdit.cpp \
- Code/Debugger.cpp \
- Code/DebugContext.cpp \
- Code/AddFtpFile.cpp \
+Source = src/WebFldDlg.cpp \
+ src/SysCharSupport.cpp \
+ src/SpaceTabConv.cpp \
+ src/SimpleCppParser.cpp \
+ src/PythonParser.cpp \
+ src/ProjectNode.cpp \
+ src/NewProjectFromTemplate.cpp \
+ src/MissingFiles.cpp \
+ src/MemDumpViewer.cpp \
+ src/LgiUtils.cpp \
+ src/LgiIde.cpp \
+ src/levenshtein.c \
+ src/JavascriptParser.cpp \
+ src/IdeProjectSettings.cpp \
+ src/IdeProject.cpp \
+ src/IdeDoc.cpp \
+ src/IdeCommon.cpp \
+ src/History.cpp \
+ src/FtpThread.cpp \
+ src/FindSymbol.cpp \
+ src/FindInFiles.cpp \
+ src/DocEditStyling.cpp \
+ src/DocEdit.cpp \
+ src/Debugger.cpp \
+ src/DebugContext.cpp \
+ src/AddFtpFile.cpp \
../src/common/Text/TextConvert.cpp \
../src/common/Text/HtmlParser.cpp \
../src/common/Text/HtmlCommon.cpp \
../src/common/Text/Html.cpp \
../src/common/Text/Homoglyphs/HomoglyphsTable.cpp \
../src/common/Text/Homoglyphs/Homoglyphs.cpp \
../src/common/Text/DocView.cpp \
../src/common/Net/OpenSSLSocket.cpp \
../src/common/Net/Http.cpp \
../src/common/Net/Ftp.cpp \
../src/common/Lgi/Mdi.cpp \
../src/common/Lgi/LgiMain.cpp \
../src/common/Lgi/About.cpp \
../src/common/Gdc2/Filters/Png.cpp \
../src/common/Coding/ParseCpp.cpp \
../src/common/Coding/LexCpp.cpp
SourceLst := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(Source)))
Objects := $(addprefix $(BuildDir)/,$(SourceLst))
Deps := $(patsubst %.o,%.d,$(Objects))
# Target
# Executable target
$(Target) : ../$(BuildDir)/liblgi-gtk3$(Tag).so $(Objects)
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
export Build=$(Build); \
$(MAKE) -C .. -f Makefile.linux
.SECONDEXPANSION:
$(Objects): $(BuildDir)/%.o: $$(wildcard %.c*)
mkdir -p $(@D)
@echo $(
#include "lgi/common/Lgi.h"
#include "lgi/common/DragAndDrop.h"
#include "lgi/common/Token.h"
#include "lgi/common/Popup.h"
#include "lgi/common/Panel.h"
#include "lgi/common/Notifications.h"
#include "lgi/common/Menu.h"
#include "ViewPriv.h"
using namespace Gtk;
#undef Status
#include "LgiWidget.h"
#define DEBUG_SETFOCUS 0
#define DEBUG_HANDLEVIEWKEY 0
extern Gtk::GdkDragAction EffectToDragAction(int Effect);
///////////////////////////////////////////////////////////////////////
class HookInfo
{
public:
LWindowHookType Flags;
LView *Target;
};
enum LAttachState
{
LUnattached,
LAttaching,
LAttached,
LDetaching,
};
class LWindowPrivate
{
public:
int Sx, Sy;
bool Dynamic;
LKey LastKey;
::LArray Hooks;
bool SnapToEdge;
::LString Icon;
LRect Decor;
gulong DestroySig;
LAutoPtr IconImg;
LAttachState AttachState;
bool ShowTitleBar = true;
bool WillFocus = true;
// State
GdkWindowState State;
bool HadCreateEvent;
// Focus stuff
OsView FirstFocus;
LViewI *Focus;
bool Active;
LWindowPrivate()
{
AttachState = LUnattached;
DestroySig = 0;
Decor.ZOff(-1, -1);
FirstFocus = NULL;
Focus = NULL;
Active = false;
State = (Gtk::GdkWindowState)0;
HadCreateEvent = false;
Sx = Sy = 0;
Dynamic = true;
SnapToEdge = false;
LastKey.vkey = 0;
LastKey.c16 = 0;
LastKey.Data = 0;
LastKey.IsChar = 0;
}
int GetHookIndex(LView *Target, bool Create = false)
{
for (int i=0; iTarget = Target;
n->Flags = LNoEvents;
return Hooks.Length() - 1;
}
}
return -1;
}
};
///////////////////////////////////////////////////////////////////////
#define GWND_CREATE 0x0010000
LWindow::LWindow(GtkWidget *w) : LView(0)
{
d = new LWindowPrivate;
_QuitOnClose = false;
Menu = NULL;
Wnd = GTK_WINDOW(w);
if (Wnd)
{
printf("gtk_window_set_decorated %i\n", d->ShowTitleBar);
gtk_window_set_decorated(Wnd, d->ShowTitleBar);
g_object_set_data(G_OBJECT(Wnd), "LViewI", (LViewI*)this);
}
_Root = NULL;
_MenuBar = NULL;
_VBox = NULL;
_Default = 0;
_Window = this;
WndFlags |= GWND_CREATE;
ClearFlag(WndFlags, GWF_VISIBLE);
_Lock = new ::LMutex("LWindow");
}
LWindow::~LWindow()
{
d->AttachState = LDetaching;
if (Wnd && d->DestroySig > 0)
{
// As we are already in the destructor, we don't want
// GtkWindowDestroy to try and delete the object again.
g_signal_handler_disconnect(Wnd, d->DestroySig);
}
if (LAppInst &&
LAppInst->AppWnd == this)
LAppInst->AppWnd = NULL;
if (_Root)
{
lgi_widget_detach(_Root);
_Root = NULL;
}
if (Wnd)
{
gtk_widget_destroy(GTK_WIDGET(Wnd));
Wnd = NULL;
}
d->AttachState = LUnattached;
DeleteObj(Menu);
DeleteObj(d);
DeleteObj(_Lock);
}
int LWindow::WaitThread()
{
return 0; // Nop for linux
}
bool LWindow::SetIcon(const char *FileName)
{
LString a;
if (Wnd)
{
if (!LFileExists(FileName))
{
if (a = LFindFile(FileName))
FileName = a;
}
if (!LFileExists(FileName))
{
LgiTrace("%s:%i - SetIcon failed to find '%s'\n", _FL, FileName);
return false;
}
else
{
#if defined(LINUX)
LAppInst->SetApplicationIcon(FileName);
#endif
#if _MSC_VER
GError *error = NULL;
if (gtk_window_set_icon_from_file(Wnd, FileName, &error))
return true;
#else
// On windows this is giving a red for blue channel swap error...
if (d->IconImg.Reset(GdcD->Load(a)))
gtk_window_set_icon(Wnd, d->IconImg->CreatePixBuf());
#endif
}
}
if (FileName != d->Icon.Get())
d->Icon = FileName;
return d->Icon != NULL;
}
bool LWindow::GetSnapToEdge()
{
return d->SnapToEdge;
}
void LWindow::SetSnapToEdge(bool s)
{
d->SnapToEdge = s;
}
bool LWindow::IsActive()
{
return d->Active;
}
bool LWindow::SetActive()
{
if (!Wnd)
return false;
gtk_window_present(Wnd);
return true;
}
bool LWindow::Visible()
{
return LView::Visible();
}
void LWindow::Visible(bool i)
{
ThreadCheck();
auto w = GTK_WIDGET(Wnd);
if (i)
gtk_widget_show(w);
else
gtk_widget_hide(w);
}
bool LWindow::Obscured()
{
return d->State == GDK_WINDOW_STATE_WITHDRAWN ||
d->State == GDK_WINDOW_STATE_ICONIFIED;
}
void LWindow::_SetDynamic(bool i)
{
d->Dynamic = i;
}
void LWindow::_OnViewDelete()
{
if (d->Dynamic)
{
delete this;
}
}
void LWindow::OnGtkRealize()
{
d->AttachState = LAttached;
LView::OnGtkRealize();
}
void LWindow::OnGtkDelete()
{
// Delete everything we own...
// DeleteObj(Menu);
#if 0
while (Children.Length())
{
LViewI *c = Children.First();
c->Detach();
}
#else
for (unsigned i=0; iGetGView();
if (v)
v->OnGtkDelete();
}
#endif
// These will be destroyed by GTK after returning from LWindowCallback
Wnd = NULL;
#ifndef __GTK_H__
_View = NULL;
#endif
}
LRect *LWindow::GetDecorSize()
{
return d->Decor.x2 >= 0 ? &d->Decor : NULL;
}
void LWindow::SetDecor(bool Visible)
{
if (Wnd)
gtk_window_set_decorated (Wnd, Visible);
else
LgiTrace("%s:%i - No window to set decor.\n", _FL);
}
LViewI *LWindow::WindowFromPoint(int x, int y, bool Debug)
{
if (!_Root)
return NULL;
auto rpos = GtkGetPos(_Root).ZeroTranslate();
if (!rpos.Overlap(x, y))
return NULL;
return LView::WindowFromPoint(x - rpos.x1, y - rpos.y1, Debug);
}
bool LWindow::TranslateMouse(LMouse &m)
{
m.Target = WindowFromPoint(m.x, m.y, false);
if (!m.Target)
return false;
LViewI *w = this;
for (auto p = m.Target; p; p = p->GetParent())
{
if (p == w)
{
auto ppos = GtkGetPos(GTK_WIDGET(WindowHandle()));
m.x -= ppos.x1;
m.y -= ppos.y1;
break;
}
else
{
auto pos = p->GetPos();
m.x -= pos.x1;
m.y -= pos.y1;
}
}
return true;
}
gboolean LWindow::OnGtkEvent(GtkWidget *widget, GdkEvent *event)
{
if (!event)
{
printf("%s:%i - No event.\n", _FL);
return FALSE;
}
#if 0
if (event->type != 28)
LgiTrace("%s::OnGtkEvent(%i) name=%s\n", GetClass(), event->type, Name());
#endif
switch (event->type)
{
case GDK_DELETE:
{
bool Close = OnRequestClose(false);
if (Close)
OnGtkDelete();
return !Close;
}
case GDK_DESTROY:
{
delete this;
return true;
}
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
{
auto ModFlags = LAppInst->GetKeyModFlags();
auto e = &event->key;
#define KEY(name) GDK_KEY_##name
LKey k;
k.Down(e->type == GDK_KEY_PRESS);
k.c16 = k.vkey = e->keyval;
k.Shift((e->state & ModFlags->Shift) != 0);
k.Ctrl((e->state & ModFlags->Ctrl) != 0);
k.Alt((e->state & ModFlags->Alt) != 0);
k.System((e->state & ModFlags->System) != 0);
#if 0//def _DEBUG
if (k.vkey == GDK_KEY_Meta_L ||
k.vkey == GDK_KEY_Meta_R)
break;
#endif
k.IsChar = !k.Ctrl() &&
!k.Alt() &&
!k.System() &&
(k.c16 >= ' ') &&
(k.c16 >> 8 != 0xff);
if (e->keyval > 0xff && e->string != NULL)
{
// Convert string to unicode char
auto *i = e->string;
ptrdiff_t len = strlen(i);
k.c16 = LgiUtf8To32((uint8_t *&) i, len);
}
switch (k.vkey)
{
case GDK_KEY_ISO_Left_Tab:
case KEY(Tab):
k.IsChar = true;
k.c16 = k.vkey = LK_TAB;
break;
case KEY(Return):
case KEY(KP_Enter):
k.IsChar = true;
k.c16 = k.vkey = LK_RETURN;
break;
case GDK_KEY_BackSpace:
k.c16 = k.vkey = LK_BACKSPACE;
k.IsChar = !k.Ctrl() && !k.Alt() && !k.System();
break;
case KEY(Left):
k.vkey = k.c16 = LK_LEFT;
break;
case KEY(Right):
k.vkey = k.c16 = LK_RIGHT;
break;
case KEY(Up):
k.vkey = k.c16 = LK_UP;
break;
case KEY(Down):
k.vkey = k.c16 = LK_DOWN;
break;
case KEY(Page_Up):
k.vkey = k.c16 = LK_PAGEUP;
break;
case KEY(Page_Down):
k.vkey = k.c16 = LK_PAGEDOWN;
break;
case KEY(Home):
k.vkey = k.c16 = LK_HOME;
break;
case KEY(End):
k.vkey = k.c16 = LK_END;
break;
case KEY(Delete):
k.vkey = k.c16 = LK_DELETE;
break;
#define KeyPadMap(gdksym, ch, is) \
case gdksym: k.c16 = ch; k.IsChar = is; break;
KeyPadMap(KEY(KP_0), '0', true)
KeyPadMap(KEY(KP_1), '1', true)
KeyPadMap(KEY(KP_2), '2', true)
KeyPadMap(KEY(KP_3), '3', true)
KeyPadMap(KEY(KP_4), '4', true)
KeyPadMap(KEY(KP_5), '5', true)
KeyPadMap(KEY(KP_6), '6', true)
KeyPadMap(KEY(KP_7), '7', true)
KeyPadMap(KEY(KP_8), '8', true)
KeyPadMap(KEY(KP_9), '9', true)
KeyPadMap(KEY(KP_Space), ' ', true)
KeyPadMap(KEY(KP_Tab), '\t', true)
KeyPadMap(KEY(KP_F1), LK_F1, false)
KeyPadMap(KEY(KP_F2), LK_F2, false)
KeyPadMap(KEY(KP_F3), LK_F3, false)
KeyPadMap(KEY(KP_F4), LK_F4, false)
KeyPadMap(KEY(KP_Home), LK_HOME, false)
KeyPadMap(KEY(KP_Left), LK_LEFT, false)
KeyPadMap(KEY(KP_Up), LK_UP, false)
KeyPadMap(KEY(KP_Right), LK_RIGHT, false)
KeyPadMap(KEY(KP_Down), LK_DOWN, false)
KeyPadMap(KEY(KP_Page_Up), LK_PAGEUP, false)
KeyPadMap(KEY(KP_Page_Down), LK_PAGEDOWN, false)
KeyPadMap(KEY(KP_End), LK_END, false)
KeyPadMap(KEY(KP_Begin), LK_HOME, false)
KeyPadMap(KEY(KP_Insert), LK_INSERT, false)
KeyPadMap(KEY(KP_Delete), LK_DELETE, false)
KeyPadMap(KEY(KP_Equal), '=', true)
KeyPadMap(KEY(KP_Multiply), '*', true)
KeyPadMap(KEY(KP_Add), '+', true)
KeyPadMap(KEY(KP_Separator), '|', true) // is this right?
KeyPadMap(KEY(KP_Subtract), '-', true)
KeyPadMap(KEY(KP_Decimal), '.', true)
KeyPadMap(KEY(KP_Divide), '/', true)
}
if (ModFlags->Debug)
{
:: LString Msg;
Msg.Printf("e->state=%x %s", e->state, ModFlags->FlagsToString(e->state).Get());
k.Trace(Msg);
}
auto v = d->Focus ? d->Focus : this;
if (!HandleViewKey(v->GetGView(), k))
{
if (!k.Down())
return false;
if (k.vkey == LK_TAB || k.vkey == KEY(ISO_Left_Tab))
{
// Do tab between controls
::LArray a;
BuildTabStops(this, a);
int idx = a.IndexOf((LViewI*)v);
if (idx >= 0)
{
idx += k.Shift() ? -1 : 1;
int next_idx = idx == 0 ? a.Length() -1 : idx % a.Length();
LViewI *next = a[next_idx];
if (next)
{
// LgiTrace("Setting focus to %i of %i: %s, %s, %i\n", next_idx, a.Length(), next->GetClass(), next->GetPos().GetStr(), next->GetId());
next->Focus(true);
}
}
}
else if (k.System())
{
if (ToLower(k.c16) == 'q')
{
auto AppWnd = LAppInst->AppWnd;
auto Wnd = AppWnd ? AppWnd : this;
if (Wnd->OnRequestClose(false))
{
Wnd->Quit();
return true;
}
}
}
else return false;
}
break;
}
case GDK_CONFIGURE:
{
GdkEventConfigure *c = &event->configure;
Pos.Set(c->x, c->y, c->x+c->width-1, c->y+c->height-1);
// printf("%s::GDK_CONFIGURE %s\n", GetClass(), Pos.GetStr());
OnPosChange();
return FALSE;
break;
}
case GDK_FOCUS_CHANGE:
{
d->Active = event->focus_change.in;
#if 0
printf("%s/%s::GDK_FOCUS_CHANGE(%i)\n",
GetClass(),
Name(),
event->focus_change.in);
#endif
break;
}
case GDK_WINDOW_STATE:
{
d->State = event->window_state.new_window_state;
break;
}
case GDK_PROPERTY_NOTIFY:
{
gchar *Name = gdk_atom_name (event->property.atom);
if (!Name)
break;
if (!_stricmp(Name, "_NET_FRAME_EXTENTS"))
{
// printf("PropChange: %i - %s\n", event->property.atom, Name);
unsigned long *extents = NULL;
if (gdk_property_get(event->property.window,
gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
gdk_atom_intern ("CARDINAL", FALSE),
0,
sizeof (unsigned long) * 4,
FALSE,
NULL,
NULL,
NULL,
(guchar **)&extents))
{
d->Decor.Set(extents[0], extents[2], extents[1], extents[3]);
g_free(extents);
}
else printf("%s:%i - Error: gdk_property_get failed.\n", _FL);
}
g_free(Name);
break;
}
case GDK_UNMAP:
{
// LgiTrace("%s:%i - Unmap %s\n", _FL, GetClass());
break;
}
case GDK_VISIBILITY_NOTIFY:
{
// LgiTrace("%s:%i - Visible %s\n", _FL, GetClass());
break;
}
case GDK_DRAG_ENTER:
{
LgiTrace("%s:%i - GDK_DRAG_ENTER\n", _FL);
break;
}
case GDK_DRAG_LEAVE:
{
LgiTrace("%s:%i - GDK_DRAG_LEAVE\n", _FL);
break;
}
case GDK_DRAG_MOTION:
{
LgiTrace("%s:%i - GDK_DRAG_MOTION\n", _FL);
break;
}
case GDK_DRAG_STATUS:
{
LgiTrace("%s:%i - GDK_DRAG_STATUS\n", _FL);
break;
}
case GDK_DROP_START:
{
LgiTrace("%s:%i - GDK_DROP_START\n", _FL);
break;
}
case GDK_DROP_FINISHED:
{
LgiTrace("%s:%i - GDK_DROP_FINISHED\n", _FL);
break;
}
default:
{
printf("%s:%i - Unknown event %i\n", _FL, event->type);
return false;
}
}
return true;
}
static
gboolean
GtkWindowDestroy(GtkWidget *widget, LWindow *This)
{
delete This;
return true;
}
static
void
GtkWindowRealize(GtkWidget *widget, LWindow *This)
{
#if 0
LgiTrace("GtkWindowRealize, This=%p(%s\"%s\")\n",
This, (NativeInt)This > 0x1000 ? This->GetClass() : 0, (NativeInt)This > 0x1000 ? This->Name() : 0);
#endif
This->OnGtkRealize();
}
static
void
GtkRootResize(GtkWidget *widget, GdkRectangle *alloc, LView *This)
{
LWindow *w = This->GetWindow();
if (w)
w->PourAll();
}
void
LWindowUnrealize(GtkWidget *widget, LWindow *wnd)
{
// printf("%s:%i - LWindowUnrealize %s\n", _FL, wnd->GetClass());
}
bool DndPointMap(LViewI *&v, LPoint &p, LDragDropTarget *&t, LWindow *Wnd, int x, int y)
{
LRect cli = Wnd->GetClient();
t = NULL;
v = Wnd->WindowFromPoint(x - cli.x1, y - cli.y1, false);
if (!v)
{
LgiTrace("%s:%i - @ %i,%i\n", _FL, x, y);
return false;
}
v->WindowVirtualOffset(&p);
p.x = x - p.x;
p.y = y - p.y;
for (LViewI *view = v; !t && view; view = view->GetParent())
t = view->DropTarget();
if (t)
return true;
LgiTrace("%s:%i - No target for %s\n", _FL, v->GetClass());
return false;
}
void
LWindowDragBegin(GtkWidget *widget, GdkDragContext *context, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
void
LWindowDragDataDelete(GtkWidget *widget, GdkDragContext *context, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
void
LWindowDragDataGet(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *data, guint info, guint time, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
void
LWindowDragDataReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, LWindow *Wnd)
{
LPoint p;
LViewI *v;
LDragDropTarget *t;
if (!DndPointMap(v, p, t, Wnd, x, y))
return;
for (auto &d: t->Data)
{
auto type = gdk_atom_name(gtk_selection_data_get_data_type(data));
if (d.Format.Equals(type))
{
gint length = 0;
auto ptr = gtk_selection_data_get_data_with_length(data, &length);
if (ptr)
{
d.Data[0].SetBinary(length, (void*)ptr, false);
}
break;
}
}
}
int GetAcceptFmts(::LString::Array &Formats, GdkDragContext *context, LDragDropTarget *t, LPoint &p)
{
int KeyState = 0;
LDragFormats Fmts(true);
int Flags = DROPEFFECT_NONE;
GList *targets = gdk_drag_context_list_targets(context);
Gtk::GList *i = targets;
while (i)
{
auto a = gdk_atom_name((GdkAtom)i->data);
if (a)
Fmts.Supports(a);
i = i->next;
}
Fmts.SetSource(false);
Flags = t->WillAccept(Fmts, p, KeyState);
auto Sup = Fmts.GetSupported();
for (auto &s: Sup)
Formats.New() = s;
return Flags;
}
gboolean
LWindowDragDataDrop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, LWindow *Wnd)
{
// Map the point to a view...
LPoint p;
LViewI *v;
LDragDropTarget *t;
if (!DndPointMap(v, p, t, Wnd, x, y))
return false;
t->Data.Length(0);
// Request the data...
::LArray Data;
::LString::Array Formats;
int KeyState = 0;
int Flags = GetAcceptFmts(Formats, context, t, p);
for (auto f: Formats)
{
t->Data.New().Format = f;
gtk_drag_get_data(widget, context, gdk_atom_intern(f, true), time);
}
// Wait for the data to arrive...
uint64_t Start = LCurrentTime();
while (LCurrentTime()-Start < 2000)
{
int HasData = 0;
for (auto d: t->Data)
if (d.Data.Length() > 0)
HasData++;
if (HasData >= Formats.Length())
break;
LYield();
}
auto Result = t->OnDrop(t->Data, p, KeyState);
if (Flags != DROPEFFECT_NONE)
gdk_drag_status(context, EffectToDragAction(Flags), time);
return Result != DROPEFFECT_NONE;
}
void
LWindowDragEnd(GtkWidget *widget, GdkDragContext *context, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
gboolean
LWindowDragFailed(GtkWidget *widget, GdkDragContext *context, GtkDragResult result, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
return false;
}
void
LWindowDragLeave(GtkWidget *widget, GdkDragContext *context, guint time, LWindow *Wnd)
{
LgiTrace("%s:%i - %s %s\n", _FL, Wnd->GetClass(), __func__);
}
gboolean
LWindowDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, LWindow *Wnd)
{
LPoint p;
LViewI *v;
LDragDropTarget *t;
if (!DndPointMap(v, p, t, Wnd, x, y))
return false;
::LString::Array Formats;
int Flags = GetAcceptFmts(Formats, context, t, p);
if (Flags != DROPEFFECT_NONE)
gdk_drag_status(context, EffectToDragAction(Flags), time);
return Flags != DROPEFFECT_NONE;
}
bool LWindow::Attach(LViewI *p)
{
bool Status = false;
ThreadCheck();
// Setup default button...
if (!_Default)
_Default = FindControl(IDOK);
// Create a window if needed..
if (!Wnd)
Wnd = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
if (Wnd)
{
SetTitleBar(d->ShowTitleBar);
SetWillFocus(d->WillFocus);
auto Widget = GTK_WIDGET(Wnd);
LView *i = this;
if (Pos.X() > 0 && Pos.Y() > 0)
gtk_window_resize(Wnd, Pos.X(), Pos.Y());
gtk_window_move(Wnd, Pos.x1, Pos.y1);
auto Obj = G_OBJECT(Wnd);
g_object_set_data(Obj, "LViewI", (LViewI*)this);
d->DestroySig = g_signal_connect(Obj, "destroy", G_CALLBACK(GtkWindowDestroy), this);
g_signal_connect(Obj, "delete_event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "key-press-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "key-release-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "focus-in-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "focus-out-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "window-state-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "property-notify-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "configure-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "unmap-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "visibility-notify-event",G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "realize", G_CALLBACK(GtkWindowRealize), i);
g_signal_connect(Obj, "unrealize", G_CALLBACK(LWindowUnrealize), i);
g_signal_connect(Obj, "drag-begin", G_CALLBACK(LWindowDragBegin), i);
g_signal_connect(Obj, "drag-data-delete", G_CALLBACK(LWindowDragDataDelete), i);
g_signal_connect(Obj, "drag-data-get", G_CALLBACK(LWindowDragDataGet), i);
g_signal_connect(Obj, "drag-data-received", G_CALLBACK(LWindowDragDataReceived), i);
g_signal_connect(Obj, "drag-drop", G_CALLBACK(LWindowDragDataDrop), i);
g_signal_connect(Obj, "drag-end", G_CALLBACK(LWindowDragEnd), i);
g_signal_connect(Obj, "drag-failed", G_CALLBACK(LWindowDragFailed), i);
g_signal_connect(Obj, "drag-leave", G_CALLBACK(LWindowDragLeave), i);
g_signal_connect(Obj, "drag-motion", G_CALLBACK(LWindowDragMotion), i);
#if 0
g_signal_connect(Obj, "button-press-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "button-release-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "motion-notify-event", G_CALLBACK(GtkViewCallback), i);
g_signal_connect(Obj, "scroll-event", G_CALLBACK(GtkViewCallback), i);
#endif
gtk_widget_add_events( Widget,
GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK |
GDK_FOCUS_CHANGE_MASK |
GDK_STRUCTURE_MASK |
GDK_VISIBILITY_NOTIFY_MASK);
gtk_window_set_title(Wnd, LBase::Name());
d->AttachState = LAttaching;
// g_action_map_add_action_entries (G_ACTION_MAP(Wnd), app_entries, G_N_ELEMENTS (app_entries), Wnd);
if ((_Root = lgi_widget_new(this, true)))
{
g_signal_connect(_Root, "size-allocate", G_CALLBACK(GtkRootResize), i);
GtkContainer *AttachPoint = NULL;
if (GTK_IS_DIALOG(Wnd))
{
auto content = gtk_dialog_get_content_area(GTK_DIALOG(Wnd));
if (!content)
{
LAssert(!"No content area");
return false;
}
AttachPoint = GTK_CONTAINER(content);
}
else
{
AttachPoint = GTK_CONTAINER(Wnd);
}
LAssert(AttachPoint != NULL);
gtk_container_add(AttachPoint, _Root);
// Check it actually worked... (would a return value kill you GTK? no it would not)
auto p = gtk_widget_get_parent(_Root);
if (!p)
{
LAssert(!"Add failed");
return false;
}
gtk_widget_show(_Root);
}
// This call sets up the GdkWindow handle
gtk_widget_realize(Widget);
// Do a rough layout of child windows
PourAll();
// Add icon
if (d->Icon)
{
SetIcon(d->Icon);
d->Icon.Empty();
}
auto p = GetParent();
if (p)
{
auto pHnd = p->WindowHandle();
if (!pHnd)
LgiTrace("%s:%i - SetParent() - no pHnd from %s.\n", _FL, p->GetClass());
else
gtk_window_set_transient_for(GTK_WINDOW(Wnd), pHnd);
}
Status = true;
}
return Status;
}
bool LWindow::OnRequestClose(bool OsShuttingDown)
{
if (GetQuitOnClose())
{
LCloseApp();
}
return LView::OnRequestClose(OsShuttingDown);
}
bool LWindow::HandleViewMouse(LView *v, LMouse &m)
{
if (m.Down() && !m.IsMove())
{
bool InPopup = false;
for (LViewI *p = v; p; p = p->GetParent())
{
if (dynamic_cast(p))
{
InPopup = true;
break;
}
}
if (!InPopup && LPopup::CurrentPopups.Length())
{
for (int i=0; iVisible())
p->Visible(false);
}
}
}
for (int i=0; iHooks.Length(); i++)
{
if (d->Hooks[i].Flags & LMouseEvents)
{
if (!d->Hooks[i].Target->OnViewMouse(v, m))
{
return false;
}
}
}
return true;
}
bool LWindow::HandleViewKey(LView *v, LKey &k)
{
bool Status = false;
LViewI *Ctrl = 0;
#if DEBUG_HANDLEVIEWKEY
bool Debug = 1; // k.vkey == LK_RETURN;
char SafePrint = k.c16 < ' ' ? ' ' : k.c16;
// if (Debug)
{
LgiTrace("%s/%p::HandleViewKey=%i ischar=%i %s%s%s%s (d->Focus=%s/%p)\n",
v->GetClass(), v,
k.c16,
k.IsChar,
(char*)(k.Down()?" Down":" Up"),
(char*)(k.Shift()?" Shift":""),
(char*)(k.Alt()?" Alt":""),
(char*)(k.Ctrl()?" Ctrl":""),
d->Focus?d->Focus->GetClass():0, d->Focus);
}
#endif
// Any window in a popup always gets the key...
LViewI *p;
for (p = v->GetParent(); p; p = p->GetParent())
{
if (dynamic_cast(p))
{
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tSending key to popup\n");
#endif
return v->OnKey(k);
}
}
// Give key to popups
if (LAppInst &&
LAppInst->GetMouseHook() &&
LAppInst->GetMouseHook()->OnViewKey(v, k))
{
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tMouseHook got key\n");
#endif
goto AllDone;
}
// Allow any hooks to see the key...
for (int i=0; iHooks.Length(); i++)
{
#if DEBUG_HANDLEVIEWKEY
// if (Debug) LgiTrace("\tHook[%i]\n", i);
#endif
if (d->Hooks[i].Flags & LKeyEvents)
{
LView *Target = d->Hooks[i].Target;
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tHook[%i].Target=%p %s\n", i, Target, Target->GetClass());
#endif
if (Target->OnViewKey(v, k))
{
Status = true;
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tHook[%i] ate '%c'(%i) down=%i alt=%i ctrl=%i sh=%i\n", i, SafePrint, k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
goto AllDone;
}
}
}
// Give the key to the window...
if (v->OnKey(k))
{
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tView ate '%c'(%i) down=%i alt=%i ctrl=%i sh=%i\n",
SafePrint, k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
Status = true;
goto AllDone;
}
#if DEBUG_HANDLEVIEWKEY
else if (Debug)
LgiTrace("\t%s didn't eat '%c'(%i) down=%i alt=%i ctrl=%i sh=%i\n",
v->GetClass(), SafePrint, k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
// Window didn't want the key...
switch (k.vkey)
{
case LK_RETURN:
#ifdef LK_KEYPADENTER
case LK_KEYPADENTER:
#endif
{
Ctrl = _Default;
break;
}
case LK_ESCAPE:
{
Ctrl = FindControl(IDCANCEL);
break;
}
}
// printf("Ctrl=%p\n", Ctrl);
if (Ctrl)
{
if (Ctrl->Enabled())
{
if (Ctrl->OnKey(k))
{
Status = true;
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tDefault Button ate '%c'(%i) down=%i alt=%i ctrl=%i sh=%i\n",
SafePrint, k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
goto AllDone;
}
// else printf("OnKey()=false\n");
}
// else printf("Ctrl=disabled\n");
}
#if DEBUG_HANDLEVIEWKEY
else if (Debug)
LgiTrace("\tNo default ctrl to handle key.\n");
#endif
if (Menu)
{
Status = Menu->OnKey(v, k);
if (Status)
{
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tMenu ate '%c' down=%i alt=%i ctrl=%i sh=%i\n", k.c16, k.Down(), k.Alt(), k.Ctrl(), k.Shift());
#endif
}
}
// Tab through controls
if (k.vkey == LK_TAB && k.Down() && !k.IsChar)
{
LViewI *Wnd = GetNextTabStop(v, k.Shift());
#if DEBUG_HANDLEVIEWKEY
if (Debug)
LgiTrace("\tTab moving focus shift=%i Wnd=%p\n", k.Shift(), Wnd);
#endif
if (Wnd)
Wnd->Focus(true);
}
// Control shortcut?
if (k.Down() && k.Alt() && k.c16 > ' ')
{
ShortcutMap Map;
BuildShortcuts(Map);
LViewI *c = Map.Find(ToUpper(k.c16));
if (c)
{
c->OnNotify(c, LNotifyActivate);
return true;
}
}
AllDone:
if (d)
d->LastKey = k;
return Status;
}
void LWindow::Raise()
{
if (Wnd)
gtk_window_present(Wnd);
}
LWindowZoom LWindow::GetZoom()
{
switch (d->State)
{
case GDK_WINDOW_STATE_ICONIFIED:
return LZoomMin;
case GDK_WINDOW_STATE_MAXIMIZED:
return LZoomMax;
default:
break;
}
return LZoomNormal;
}
void LWindow::SetZoom(LWindowZoom i)
{
if (!Wnd)
{
// LgiTrace("%s:%i - No window.\n", _FL);
return;
}
ThreadCheck();
switch (i)
{
case LZoomMin:
{
gtk_window_iconify(Wnd);
break;
}
case LZoomNormal:
{
gtk_window_deiconify(Wnd);
gtk_window_unmaximize(Wnd);
break;
}
case LZoomMax:
{
gtk_window_maximize(Wnd);
break;
}
default:
{
LgiTrace("%s:%i - Error: unsupported zoom.\n", _FL);
break;
}
}
}
LViewI *LWindow::GetDefault()
{
return _Default;
}
void LWindow::SetDefault(LViewI *v)
{
if (v &&
v->GetWindow() == this)
{
if (_Default != v)
{
LViewI *Old = _Default;
_Default = v;
if (Old) Old->Invalidate();
if (_Default) _Default->Invalidate();
}
}
else
{
_Default = 0;
}
}
bool LWindow::SetTitleBar(bool ShowTitleBar)
{
d->ShowTitleBar = ShowTitleBar;
if (Wnd)
{
ThreadCheck();
gtk_window_set_decorated(Wnd, ShowTitleBar);
}
return true;
}
bool LWindow::Name(const char *n)
{
if (Wnd)
{
ThreadCheck();
gtk_window_set_title(Wnd, n);
}
return LBase::Name(n);
}
const char *LWindow::Name()
{
return LBase::Name();
}
struct CallbackParams
{
LRect Menu;
int Depth;
CallbackParams()
{
Menu.ZOff(-1, -1);
Depth = 0;
}
};
void ClientCallback(GtkWidget *w, CallbackParams *p)
{
const char *Name = gtk_widget_get_name(w);
if (Name && !_stricmp(Name, "GtkMenuBar"))
{
GtkAllocation alloc = {0};
gtk_widget_get_allocation(w, &alloc);
p->Menu.ZOff(alloc.width-1, alloc.height-1);
// LgiTrace("GtkMenuBar = %s\n", p->Menu.GetStr());
}
if (!p->Menu.Valid())
{
p->Depth++;
if (GTK_IS_CONTAINER(w))
gtk_container_forall(GTK_CONTAINER(w), (GtkCallback)ClientCallback, p);
p->Depth--;
}
}
LPoint LWindow::GetDpi()
{
return LScreenDpi();
}
LPointF LWindow::GetDpiScale()
{
auto Dpi = GetDpi();
return LPointF((double)Dpi.x/96.0, (double)Dpi.y/96.0);
}
LRect &LWindow::GetClient(bool ClientSpace)
{
static LRect r;
r = LView::GetClient(ClientSpace);
if (Wnd)
{
CallbackParams p;
gtk_container_forall(GTK_CONTAINER(Wnd), (GtkCallback)ClientCallback, &p);
if (p.Menu.Valid())
{
if (ClientSpace)
r.y2 -= p.Menu.Y();
else
r.y1 += p.Menu.Y();
}
}
return r;
}
bool LWindow::SerializeState(LDom *Store, const char *FieldName, bool Load)
{
if (!Store || !FieldName)
return false;
if (Load)
{
::LVariant v;
if (Store->GetValue(FieldName, v) && v.Str())
{
LRect Position(0, 0, -1, -1);
LWindowZoom State = LZoomNormal;
// printf("SerializeState load %s\n", v.Str());
LToken t(v.Str(), ";");
for (int i=0; iSetValue(FieldName, v))
return false;
}
return true;
}
LRect &LWindow::GetPos()
{
return Pos;
}
bool LWindow::SetPos(LRect &p, bool Repaint)
{
Pos = p;
if (Wnd)
{
ThreadCheck();
gtk_window_resize(Wnd, MAX(1, Pos.X()), Pos.Y());
gtk_window_move(Wnd, Pos.x1, Pos.y1);
}
OnPosChange();
return true;
}
void LWindow::OnChildrenChanged(LViewI *Wnd, bool Attaching)
{
// Force repour
d->Sx = d->Sy = -1;
}
void LWindow::OnCreate()
{
AttachChildren();
}
void LWindow::OnPaint(LSurface *pDC)
{
pDC->Colour(L_MED);
pDC->Rectangle();
}
void LWindow::OnPosChange()
{
LView::OnPosChange();
if (d->Sx != X() || d->Sy != Y())
{
PourAll();
d->Sx = X();
d->Sy = Y();
}
}
#define IsTool(v) \
( \
dynamic_cast(v) \
&& \
dynamic_cast(v)->_IsToolBar \
)
void LWindow::PourAll()
{
LRect c;
if (_Root)
c = GtkGetPos(_Root).ZeroTranslate();
else
c = GetClient();
if (c.X() < 20 || c.Y() < 20)
return; // IDK, GTK is weird sometimes... filter out low sizes.
LRegion Client(c);
LViewI *MenuView = 0;
LRegion Update(Client);
bool HasTools = false;
LViewI *v;
List::I Lst = Children.begin();
{
LRegion Tools;
for (v = *Lst; v; v = *++Lst)
{
bool IsMenu = MenuView == v;
if (!IsMenu && IsTool(v))
{
LRect OldPos = v->GetPos();
if (OldPos.Valid())
Update.Union(&OldPos);
if (HasTools)
{
// 2nd and later toolbars
if (v->Pour(Tools))
{
if (!v->Visible())
{
v->Visible(true);
}
auto vpos = v->GetPos();
if (OldPos != vpos)
{
// position has changed update...
v->Invalidate();
}
// Has it increased the size of the toolbar area?
auto b = Tools.Bound();
if (vpos.y2 >= b.y2)
{
LRect Bar = Client;
Bar.y2 = vpos.y2;
Client.Subtract(&Bar);
// LgiTrace("IncreaseToolbar=%s\n", Bar.GetStr());
}
Tools.Subtract(&vpos);
Update.Subtract(&vpos);
// LgiTrace("vpos=%s\n", vpos.GetStr());
}
}
else
{
// First toolbar
if (v->Pour(Client))
{
HasTools = true;
if (!v->Visible())
{
v->Visible(true);
}
if (OldPos != v->GetPos())
{
v->Invalidate();
}
LRect Bar(v->GetPos());
// LgiTrace("%s = %s\n", v->GetClass(), Bar.GetStr());
Bar.x2 = GetClient().x2;
Tools = Bar;
Tools.Subtract(&v->GetPos());
Client.Subtract(&Bar);
Update.Subtract(&Bar);
}
}
}
}
}
Lst = Children.begin();
for (LViewI *v = *Lst; v; v = *++Lst)
{
bool IsMenu = MenuView == v;
if (!IsMenu && !IsTool(v))
{
LRect OldPos = v->GetPos();
if (OldPos.Valid())
Update.Union(&OldPos);
if (v->Pour(Client))
{
// LRect p = v->GetPos();
// LgiTrace("%s = %s\n", v->GetClass(), p.GetStr());
if (!v->Visible())
v->Visible(true);
v->Invalidate();
Client.Subtract(&v->GetPos());
Update.Subtract(&v->GetPos());
}
else
{
// non-pourable
}
}
}
for (int i=0; iMsg())
{
case M_CLOSE:
{
if (OnRequestClose(false))
{
Quit();
return 0;
}
break;
}
}
return LView::OnEvent(m);
}
bool LWindow::RegisterHook(LView *Target, LWindowHookType EventType, int Priority)
{
bool Status = false;
if (Target && EventType)
{
int i = d->GetHookIndex(Target, true);
if (i >= 0)
{
d->Hooks[i].Flags = EventType;
Status = true;
}
}
return Status;
}
bool LWindow::UnregisterHook(LView *Target)
{
int i = d->GetHookIndex(Target);
if (i >= 0)
{
d->Hooks.DeleteAt(i);
return true;
}
return false;
}
void LWindow::OnFrontSwitch(bool b)
{
}
LViewI *LWindow::GetFocus()
{
return d->Focus;
}
#if DEBUG_SETFOCUS
static LAutoString DescribeView(LViewI *v)
{
if (!v)
return LAutoString(NewStr("NULL"));
char s[512];
int ch = 0;
::LArray p;
for (LViewI *i = v; i; i = i->GetParent())
{
p.Add(i);
}
for (int n=MIN(3, p.Length()-1); n>=0; n--)
{
char Buf[256] = "";
if (!stricmp(v->GetClass(), "LMdiChild"))
sprintf(Buf, "'%s'", v->Name());
v = p[n];
ch += sprintf_s(s + ch, sizeof(s) - ch, "%s>%s", Buf, v->GetClass());
}
return LAutoString(NewStr(s));
}
#endif
void LWindow::SetFocus(LViewI *ctrl, FocusType type)
{
#if DEBUG_SETFOCUS
const char *TypeName = NULL;
switch (type)
{
case GainFocus: TypeName = "Gain"; break;
case LoseFocus: TypeName = "Lose"; break;
case ViewDelete: TypeName = "Delete"; break;
}
#endif
switch (type)
{
case GainFocus:
{
if (d->Focus == ctrl)
{
#if DEBUG_SETFOCUS
LAutoString _ctrl = DescribeView(ctrl);
LgiTrace("SetFocus(%s, %s) already has focus.\n", _ctrl.Get(), TypeName);
#endif
return;
}
if (d->Focus)
{
LView *gv = d->Focus->GetGView();
if (gv)
{
#if DEBUG_SETFOCUS
LAutoString _foc = DescribeView(d->Focus);
LgiTrace(".....defocus LView: %s\n", _foc.Get());
#endif
gv->_Focus(false);
}
else if (IsActive())
{
#if DEBUG_SETFOCUS
LAutoString _foc = DescribeView(d->Focus);
LgiTrace(".....defocus view: %s (active=%i)\n", _foc.Get(), IsActive());
#endif
d->Focus->OnFocus(false);
d->Focus->Invalidate();
}
}
d->Focus = ctrl;
if (d->Focus)
{
#if DEBUG_SETFOCUS
static int Count = 0;
#endif
LView *gv = d->Focus->GetGView();
if (gv)
{
#if DEBUG_SETFOCUS
LAutoString _set = DescribeView(d->Focus);
LgiTrace("LWindow::SetFocus(%s, %s) %i focusing LView\n",
_set.Get(),
TypeName,
Count++);
#endif
gv->_Focus(true);
}
else if (IsActive())
{
#if DEBUG_SETFOCUS
LAutoString _set = DescribeView(d->Focus);
LgiTrace("LWindow::SetFocus(%s, %s) %i focusing nonGView (active=%i)\n",
_set.Get(),
TypeName,
Count++,
IsActive());
#endif
d->Focus->OnFocus(true);
d->Focus->Invalidate();
}
}
break;
}
case LoseFocus:
{
#if DEBUG_SETFOCUS
LAutoString _Ctrl = DescribeView(d->Focus);
LAutoString _Focus = DescribeView(d->Focus);
LgiTrace("LWindow::SetFocus(%s, %s) d->Focus=%s\n",
_Ctrl.Get(),
TypeName,
_Focus.Get());
#endif
if (ctrl == d->Focus)
{
d->Focus = NULL;
}
break;
}
case ViewDelete:
{
if (ctrl == d->Focus)
{
#if DEBUG_SETFOCUS
LAutoString _Ctrl = DescribeView(d->Focus);
LgiTrace("LWindow::SetFocus(%s, %s) on delete\n",
_Ctrl.Get(),
TypeName);
#endif
d->Focus = NULL;
}
break;
}
}
}
-void LWindow::SetWillFocus(bool f)
+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)
{
}