1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4 
5 #include "../../application.h"
6 #include "../../../include/iappdelegate.h"
7 #include "../../../include/iapplication.h"
8 #include "../../../../lib/vstkeycode.h"
9 #include "../../../../lib/platform/linux/x11frame.h"
10 #include "../../../../lib/platform/common/fileresourceinputstream.h"
11 #include "gdkcommondirectories.h"
12 #include "gdkpreference.h"
13 #include "gdkwindow.h"
14 #include "gdkrunloop.h"
15 #include <gtkmm.h>
16 #include <libgen.h>
17 #include <unordered_map>
18 
19 //------------------------------------------------------------------------
20 namespace std {
21 
22 //------------------------------------------------------------------------
23 template<>
24 struct hash<VstKeyCode>
25 {
operator ()std::hash26 	std::size_t operator() (const VstKeyCode& k) const
27 	{
28 		return ((hash<int32_t> () (k.character) ^ (hash<unsigned char> () (k.modifier) << 1)) >>
29 				1) ^
30 			   (hash<unsigned char> () (k.virt) << 1);
31 	}
32 };
33 
34 //------------------------------------------------------------------------
35 } // std
36 
37 //------------------------------------------------------------------------
operator ==(const VstKeyCode & k1,const VstKeyCode & k2)38 bool operator== (const VstKeyCode& k1, const VstKeyCode& k2)
39 {
40 	return k1.virt == k2.virt && k1.modifier == k2.modifier && k1.character == k2.character;
41 }
42 
43 //------------------------------------------------------------------------
44 namespace VSTGUI {
45 void* soHandle = nullptr;
46 
47 namespace Standalone {
48 namespace Platform {
49 namespace GDK {
50 
51 using namespace VSTGUI::Standalone::Detail;
52 
53 //------------------------------------------------------------------------
54 Glib::RefPtr<Gtk::Application> app;
55 
56 //------------------------------------------------------------------------
gtkApp()57 Glib::RefPtr<Gtk::Application> gtkApp ()
58 {
59 	return app;
60 }
61 
62 //------------------------------------------------------------------------
63 class Application
64 {
65 public:
66 	bool init (int argc, char* argv[]);
67 	int run ();
68 
69 	void quit ();
70 
71 private:
72 	void doCommandUpdate ();
73 	void handleCommand (const CommandWithKey& command);
74 
75 	CommonDirectories commonDirectories;
76 	Preference prefs;
77 
78 	bool isInitialized{false};
79 };
80 
81 //------------------------------------------------------------------------
init(int argc,char * argv[])82 bool Application::init (int argc, char* argv[])
83 {
84 	const auto& appInfo = IApplication::instance ().getDelegate ().getInfo ();
85 	app = Gtk::Application::create (argc, argv, appInfo.uri.data ());
86 	Glib::set_application_name (appInfo.name.getString ());
87 
88 	IApplication::CommandLineArguments cmdArgs;
89 	for (auto i = 0; i < argc; ++i)
90 		cmdArgs.push_back (argv[i]);
91 
92 	app->signal_startup ().connect ([cmdArgs = std::move (cmdArgs), this]() mutable {
93 		char result[PATH_MAX];
94 		ssize_t count = readlink ("/proc/self/exe", result, PATH_MAX);
95 		if (count == -1)
96 			exit (-1);
97 		std::string execPath = dirname (result);
98 		VSTGUI::X11::Frame::createResourceInputStreamFunc =
99 			[execPath](const CResourceDescription& desc) {
100 				if (desc.type == CResourceDescription::kIntegerType)
101 					return IPlatformResourceInputStream::Ptr ();
102 				std::string path (execPath);
103 				path += "/Resources/";
104 				path += desc.u.name;
105 				return FileResourceInputStream::create (path);
106 			};
107 
108 		PlatformCallbacks callbacks;
109 		callbacks.quit = [this]() { quit (); };
110 		callbacks.onCommandUpdate = [this]() { doCommandUpdate (); };
111 		callbacks.showAlert = [](const AlertBoxConfig& config) { return AlertResult::Error; };
112 		callbacks.showAlertForWindow = [](const AlertBoxForWindowConfig& config) {
113 			if (config.callback)
114 				config.callback (AlertResult::Error);
115 		};
116 
117 		auto appAccess = Detail::getApplicationPlatformAccess ();
118 		vstgui_assert (appAccess);
119 		IPlatformApplication::OpenFilesList openFilesList;
120 		/* TODO: fill openFilesList */
121 		appAccess->init ({prefs, commonDirectories, std::move (cmdArgs), std::move (callbacks),
122 						  std::move (openFilesList)});
123 		isInitialized = true;
124 		doCommandUpdate ();
125 	});
126 	return true;
127 }
128 
129 //------------------------------------------------------------------------
run()130 int Application::run ()
131 {
132 	return app->run ();
133 }
134 
135 //------------------------------------------------------------------------
quit()136 void Application::quit ()
137 {
138 	app->quit ();
139 }
140 
141 //------------------------------------------------------------------------
handleCommand(const CommandWithKey & command)142 void Application::handleCommand (const CommandWithKey& command) {}
143 
144 //------------------------------------------------------------------------
doCommandUpdate()145 void Application::doCommandUpdate ()
146 {
147 	if (!isInitialized)
148 		return;
149 	auto mainMenu = Gio::Menu::create ();
150 	auto commandList = Detail::getApplicationPlatformAccess ()->getCommandList ();
151 	for (auto& e : commandList)
152 	{
153 		auto subMenu = Gio::Menu::create ();
154 		for (auto& command : e.second)
155 		{
156 			if (command.name == CommandName::MenuSeparator)
157 			{
158 				continue;
159 			}
160 			auto actionName = command.group.getString () + "." + command.name.getString ();
161 			std::replace (actionName.begin (), actionName.end (), ' ', '_');
162 			auto item = Gio::MenuItem::create (command.name.getString (), actionName);
163 			if (command.defaultKey)
164 			{
165 				std::string accelKey ("<Primary>");
166 				accelKey += command.defaultKey;
167 				// TODO: map virtual characters
168 				item->set_attribute_value ("accel",
169 										   Glib::Variant<Glib::ustring>::create (accelKey));
170 			}
171 			subMenu->append_item (item);
172 
173 			if (!app->has_action (actionName))
174 			{
175 				if (auto action = app->add_action (actionName,
176 												   [this, command]() { handleCommand (command); }))
177 				{
178 				}
179 			}
180 		}
181 		mainMenu->append_submenu (e.first.getString (), subMenu);
182 	}
183 	app->set_menubar (mainMenu);
184 }
185 
186 //------------------------------------------------------------------------
187 } // GDK
188 } // Platform
189 } // Standalone
190 } // VSTGUI
191 
192 //------------------------------------------------------------------------
main(int argc,char * argv[])193 int main (int argc, char* argv[])
194 {
195 	VSTGUI::Standalone::Platform::GDK::Application app;
196 	if (app.init (argc, argv))
197 		return app.run ();
198 	return -1;
199 }