diff --git a/juci/CMakeLists.txt b/juci/CMakeLists.txt index 625d06a..64c2849 100644 --- a/juci/CMakeLists.txt +++ b/juci/CMakeLists.txt @@ -3,6 +3,7 @@ set(project_name juci) set(module juci_to_python_api) project (${project_name}) +add_definitions(-DBOOST_LOG_DYN_LINK) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake/Modules/") @@ -52,7 +53,7 @@ endif() #Boost_INCLUDE_DIRS - Boost include directories #Boost_LIBRARY_DIRS - Link directories for Boost libraries #Boost_LIBRARIES - Boost component libraries to be linked -find_package(Boost 1.5 REQUIRED COMPONENTS python timer system filesystem) +find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED) #If boost is not found if(${Boost_FOUND}) @@ -131,8 +132,8 @@ link_directories( ${LIBCLANG_LIBRARY_DIRS} ) #module: -set_target_properties(${module} PROPERTIES PREFIX "" - LIBRARY_OUTPUT_DIRECTORY "/usr/lib/python2.7/dist-packages/") +set_target_properties(${module} PROPERTIES PREFIX "") +# LIBRARY_OUTPUT_DIRECTORY "/usr/lib/python2.7/dist-packages/") target_link_libraries(${module} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) #executable: target_link_libraries(${project_name} ${LIVCLANG_LIBRARIES} ${LCL_LIBRARIES} ${GTKMM_LIBRARIES} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}) diff --git a/juci/api.cc b/juci/api.cc index ae7534a..989bd3e 100644 --- a/juci/api.cc +++ b/juci/api.cc @@ -1,10 +1,23 @@ #include "api.h" +#include "logging.h" Menu::Controller* PluginApi::menu_; Notebook::Controller* PluginApi::notebook_; ///////////////////////////// //// API ServiceProvider //// ///////////////////////////// +PluginApi::PluginApi(Menu::Controller& menu_ctl_, + Notebook::Controller& notebook_ctl_) { + menu_ = &menu_ctl_; + notebook_ = ¬ebook_ctl_; + InitPlugins(); +} + +PluginApi::~PluginApi() { + menu_ = NULL; + notebook_ = NULL; +} + std::string PluginApi::ProjectPath() { int MAXPATHLEN = 50; char temp[MAXPATHLEN]; @@ -107,7 +120,7 @@ void libjuci::ReplaceWord(const std::string word) { } void libjuci::ReplaceLine(const std::string line) { - std::cout << "unimplemented function: 'libjuci::ReplaceLine()' called" + std::cout << "unimplemented: " << __func__ << " called" << std::endl; } std::string libjuci::GetWord() { @@ -201,16 +214,7 @@ void libjuci::IterToWordEnd(Gtk::TextIter &iter) { } Glib::RefPtr libjuci::BufferFromNotebook() { - // finding focused view - // int i = 0; - // while (!PluginApi::notebook_->source_vec_.at(i)->view().has_focus()) { - // i++; - // while(!PluginApi::notebook_->CurrentTextView().has_focus()) { - // i++; - // } return Glib::RefPtr(PluginApi::notebook_ - // ->source_vec_.at(i) - // ->view().get_buffer()); ->CurrentTextView().get_buffer()); } diff --git a/juci/api.h b/juci/api.h index 46f3f98..900d206 100644 --- a/juci/api.h +++ b/juci/api.h @@ -12,6 +12,8 @@ //////////////////// class PluginApi { public: + PluginApi(Menu::Controller&, Notebook::Controller&); + ~PluginApi(); static Menu::Controller* menu_; static Notebook::Controller* notebook_; static void InitPlugins(); @@ -25,7 +27,6 @@ public: const std::string menu_func_name, const std::string plugin_path, const std::string menu_keybinding); - // text-buffer functions static void ReplaceWord(const std::string word); static void ReplaceLine(const std::string line); protected: @@ -64,11 +65,10 @@ namespace libjuci { namespace bp = boost::python; bp::api::object OpenPythonScript(const std::string path, bp::api::object python_name_space); - void LoadPlugin(const std::string& plugin_name); void LoadPluginFunction(const std::string &function_name, const std::string &plugin_path); void InitPlugin(const std::string& plugin_path); -} // libjuci +} // namespace libjuci #endif // JUCI_API_H_ diff --git a/juci/api_ext.cc b/juci/api_ext.cc index e04bc11..9b8b1ba 100644 --- a/juci/api_ext.cc +++ b/juci/api_ext.cc @@ -12,7 +12,4 @@ BOOST_PYTHON_MODULE(juci_to_python_api) { def("replaceLine", &libjuci::ReplaceLine); def("replaceWord", &libjuci::ReplaceWord); def("getWord", &libjuci::GetWord); - - - //something more - }// module::juci_to_python_api + } // module::juci_to_python_api diff --git a/juci/config.cc b/juci/config.cc index 689fd19..22dbffb 100644 --- a/juci/config.cc +++ b/juci/config.cc @@ -1,4 +1,5 @@ #include "config.h" +#include "logging.h" MainConfig::MainConfig() : keybindings_cfg_(), source_cfg_() { @@ -6,43 +7,45 @@ MainConfig::MainConfig() : GenerateSource(); GenerateKeybindings(); GenerateDirectoryFilter(); - // keybindings_cfg_ = cfg_.get_child("keybindings"); - // notebook_cfg_ = cfg_.get_child("notebook"); - // menu_cfg_ = cfg_.get_child("menu"); } void MainConfig::GenerateSource() { + INFO("Generating source cfg"); boost::property_tree::ptree source_json = cfg_.get_child("source"); boost::property_tree::ptree syntax_json = source_json.get_child("syntax"); boost::property_tree::ptree colors_json = source_json.get_child("colors"); - for ( auto &i : colors_json ) { + for (auto &i : colors_json) { source_cfg_.InsertTag(i.first, i.second.get_value()); } - for ( auto &i : syntax_json ) { - source_cfg_.InsertType(i.first, i.second.get_value()); + for (auto &i : syntax_json) { + source_cfg_.InsertType(i.first, i.second.get_value()); } + INFO("Source cfg generated"); } void MainConfig::GenerateKeybindings() { + INFO("Generating keybindings"); std::string line; std::ifstream menu_xml("menu.xml"); if (menu_xml.is_open()) { while (getline(menu_xml, line)) { keybindings_cfg_.AppendXml(line); } + } boost::property_tree::ptree keys_json = cfg_.get_child("keybindings"); for (auto &i : keys_json) keybindings_cfg_.key_map()[i.first] = i.second.get_value(); + INFO("Keybindings generated"); } void MainConfig::GenerateDirectoryFilter() { boost::property_tree::ptree dir_json = cfg_.get_child("directoryfilter"); boost::property_tree::ptree ignore_json = dir_json.get_child("ignore"); boost::property_tree::ptree except_json = dir_json.get_child("exceptions"); - for ( auto &i : except_json ) + for ( auto &i : except_json ) dir_cfg_.AddException(i.second.get_value()); - for ( auto &i : ignore_json ) + for ( auto &i : ignore_json ) dir_cfg_.AddIgnore(i.second.get_value()); } diff --git a/juci/config.json b/juci/config.json index 3305cf8..9344fbb 100644 --- a/juci/config.json +++ b/juci/config.json @@ -36,6 +36,7 @@ "#", "~", ".idea", + ".so", "in-lowercase.pls" ], "exceptions": [ diff --git a/juci/directories.cc b/juci/directories.cc index 3134d6f..73fb825 100644 --- a/juci/directories.cc +++ b/juci/directories.cc @@ -1,4 +1,5 @@ #include "directories.h" +#include "logging.h" Directories::Controller::Controller(Directories::Config& cfg) : config_(cfg) { @@ -8,6 +9,7 @@ Directories::Controller::Controller(Directories::Config& cfg) : void Directories::Controller:: open_folder(const boost::filesystem::path& dir_path) { + INFO("Open folder"); m_refTreeModel = Gtk::TreeStore::create(view()); m_TreeView.set_model(m_refTreeModel); m_TreeView.remove_all_columns(); @@ -17,6 +19,7 @@ open_folder(const boost::filesystem::path& dir_path) { Gtk::TreeModel::Row row; list_dirs(dir_path, row, row_id); m_refTreeModel->set_sort_column(0, Gtk::SortType::SORT_ASCENDING); + INFO("Folder opened"); } bool Directories::Controller::IsIgnored(std::string path) { @@ -80,6 +83,7 @@ int Directories::Controller::count(const std::string path) { std::string Directories::Controller:: GetCmakeVarValue(const boost::filesystem::path& dir_path, std::string command_name) { + INFO("fetches cmake variable value for: "+command_name); std::string project_name; std::string project_name_var; boost::filesystem::directory_iterator end_itr; @@ -92,42 +96,50 @@ int Directories::Controller::count(const std::string path) { while (std::getline(ifs, line)) { if (line.find(command_name+"(", 0) != std::string::npos || line.find(command_name+" (", 0) != std::string::npos ) { - size_t variabel_start = line.find("{", 0); - size_t variabel_end = line.find("}", variabel_start); - project_name_var = line.substr(variabel_start+1, - (variabel_end)-variabel_start-1); + size_t variable_start = line.find("{", 0); + size_t variable_end = line.find("}", variable_start); + project_name_var = line.substr(variable_start+1, + (variable_end)-variable_start-1); boost::algorithm::trim(project_name_var); - if (variabel_start == std::string::npos) { // not a variabel - variabel_start = line.find("(", 0); + if (variable_start == std::string::npos) { // not a variabel + variable_start = line.find("(", 0); - variabel_end = line.find(' ', variabel_start); - if(variabel_end != std::string::npos){ - return line.substr(variabel_start+1, - (variabel_end)-variabel_start-1); + variable_end = line.find(' ', variable_start); + if(variable_end != std::string::npos){ + return line.substr(variable_start+1, + (variable_end)-variable_start-1); } - variabel_end = line.find("#", variabel_start); - if(variabel_end != std::string::npos){ - return line.substr(variabel_start+1, - (variabel_end)-variabel_start-1); + variable_end = line.find("#", variable_start); + if(variable_end != std::string::npos){ + return line.substr(variable_start+1, + (variable_end)-variable_start-1); } - variabel_end = line.find(")", variabel_start); - return line.substr(variabel_start+1, - (variabel_end)-variabel_start-1); + variable_end = line.find(")", variable_start); + return line.substr(variable_start+1, + (variable_end)-variable_start-1); + if (variable_start == std::string::npos) { // not a variable + variable_start = line.find("(", 0); + variable_end = line.find(")", variable_start); + INFO("Wasn't a variable, returning value"); + return line.substr(variable_start+1, + (variable_end)-variable_start-1); } break; } } + } std::ifstream ifs2(itr->path().string()); while (std::getline(ifs2, line)) { if (line.find("set(", 0) != std::string::npos || line.find("set (", 0) != std::string::npos) { if( line.find(project_name_var, 0) != std::string::npos) { - size_t variabel_start = line.find(project_name_var, 0) + size_t variable_start = line.find(project_name_var, 0) +project_name_var.length(); - size_t variabel_end = line.find(")", variabel_start); - project_name = line.substr(variabel_start+1, - variabel_end-variabel_start-1); + size_t variable_end = line.find(")", variable_start); + project_name = line.substr(variable_start+1, + variable_end-variable_start-1); boost::algorithm::trim(project_name); + INFO("found variable, returning value"); return project_name; } } @@ -135,6 +147,7 @@ int Directories::Controller::count(const std::string path) { break; } } + INFO("Couldn't find value in CMakeLists.txt"); return "no project name"; } diff --git a/juci/juci.cc b/juci/juci.cc index b2afc98..199d97e 100644 --- a/juci/juci.cc +++ b/juci/juci.cc @@ -1,4 +1,5 @@ #include "window.h" +#include "logging.h" int main(int argc, char *argv[]) { Glib::RefPtr app = Gtk::Application::create( @@ -6,8 +7,8 @@ int main(int argc, char *argv[]) { argv, "no.sout.juci"); + add_file_log("juci.log"); + INFO("Logging initalized"); Window window; - - //api::LoadPlugin("juci_api_test"); return app->run(window); } diff --git a/juci/logging.h b/juci/logging.h new file mode 100644 index 0000000..f6cdc55 --- /dev/null +++ b/juci/logging.h @@ -0,0 +1,22 @@ +#ifndef JUCI_LOGGING_H_ +#define JUCI_LOGGING_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::log; + +#define TRACE(x) BOOST_LOG_TRIVIAL(trace) << __func__ << "(" << __LINE__ << "): " << #x << "=<" << x << ">"; +#define DEBUG(x) BOOST_LOG_TRIVIAL(debug) << __func__ << "(" << __LINE__ << "): " << #x << "=<" << x << ">"; +#define INFO(x) BOOST_LOG_TRIVIAL(info) << __func__ << "(" << __LINE__ << "): \"" x << "\""; +#define WARNING(x) BOOST_LOG_TRIVIAL(warning) << __func__ << "(" << __LINE__ << "): " << #x << "=<" << x << ">"; +#define ERROR(x) BOOST_LOG_TRIVIAL(error) << __func__ << "(" << __LINE__ << "): " << #x << "=<" << x << ">"; +#define FATAL(x) BOOST_LOG_TRIVIAL(fatal) << __func__ << "(" << __LINE__ << "): " << #x << "=<" << x << ">"; + +#endif // JUCI_LOGGING_H_ diff --git a/juci/plugins.py b/juci/plugins.py index 70bbf5b..f8faf6e 100644 --- a/juci/plugins.py +++ b/juci/plugins.py @@ -1,9 +1,11 @@ #!/usr/bin/python #plugin handler -import juci_to_python_api as juci, os, glob +import sys, os, glob +cwd = os.getcwd() +sys.path.append(cwd) +import juci_to_python_api as juci def loadplugins(): - cwd = os.getcwd() plugin_files = glob.glob(cwd+"/plugins/*.py") for current_file in plugin_files: juci.initPlugin(current_file) diff --git a/juci/source.cc b/juci/source.cc index 30b63ff..126ed38 100644 --- a/juci/source.cc +++ b/juci/source.cc @@ -5,9 +5,7 @@ #include #include #include "notebook.h" - -#define log( var ) \ - std::cout << "source.cc (" << __LINE__ << ") " << #var << std::endl +#include "logging.h" Source::Location:: Location(int line_number, int column_offset) : @@ -267,7 +265,9 @@ HighlightToken(clang::Token *token, // Constructor for Controller Source::Controller::Controller(const Source::Config &config, Notebook::Controller *notebook) : - model_(config), notebook_(notebook) { } + model_(config), notebook_(notebook) { + INFO("Source Controller with childs constructed"); +} // Source::Controller::view() // return shared_ptr to the view diff --git a/juci/terminal.cc b/juci/terminal.cc index 4b624e2..4e7a28e 100644 --- a/juci/terminal.cc +++ b/juci/terminal.cc @@ -33,7 +33,7 @@ void Terminal::Controller::Compile(){ void Terminal::Controller::Run(std::string executable) { PrintMessage("juCi++ execute: " + executable + "\n"); - ExecuteCommand("./"+executable, "w"); + ExecuteCommand("./"+executable, "r"); } void Terminal::Controller::PrintMessage(std::string message){ @@ -50,37 +50,17 @@ bool Terminal::Controller::ExistInConsole(std::string string) { } void Terminal::Controller::ExecuteCommand(std::string command, std::string mode) { - + command = folder_command_+command; std::cout << "EXECUTE COMMAND: "<< command << std::endl; - if(mode == "w"){ - command = path_ + " " +command + " > some_file.txt"; - system(command.c_str()); - }else{ - - FILE* p = popen(command.c_str(), mode.c_str()); - command = folder_command_+command; - if (p == NULL) { - PrintMessage("juCi++ ERROR: Failed to run command" + command + "\n"); - }else { - char buffer[1028]; - while (fgets(buffer, 1028, p) != NULL) { - PrintMessage(buffer); - } - pclose(p); + FILE* p = popen(command.c_str(), mode.c_str()); + + if (p == NULL) { + PrintMessage("juCi++ ERROR: Failed to run command" + command + "\n"); + }else { + char buffer[1028]; + while (fgets(buffer, 1028, p) != NULL) { + PrintMessage(buffer); } + pclose(p); } - - - - // // run a process and create a streambuf that reads its stdout and stderr - // redi::ipstream proc(command, redi::pstreams::pstderr); - // std::string line; - // // read child's stdout - // while (std::getline(proc.out(), line)) - // PrintMessage(line+ "\n"); - - // // read child's stderr - // while (std::getline(proc.err(), line)) - // PrintMessage(line+ "\n"); - } diff --git a/juci/window.cc b/juci/window.cc index a09ee86..3cc5b89 100644 --- a/juci/window.cc +++ b/juci/window.cc @@ -1,31 +1,36 @@ #include "window.h" +#include "logging.h" Window::Window() : window_box_(Gtk::ORIENTATION_VERTICAL), main_config_(), keybindings_(main_config_.keybindings_cfg()), - notebook_(this,keybindings(), main_config_.source_cfg(), main_config_.dir_cfg()), - menu_(keybindings()) { + notebook_(this,keybindings(), + main_config_.source_cfg(), + main_config_.dir_cfg()), + menu_(keybindings()), + api_(menu_, notebook_) { + INFO("Create Window"); set_title("juCi++"); set_default_size(600, 400); add(window_box_); keybindings_.action_group_menu()->add(Gtk::Action::create("FileQuit", - Gtk::Stock::QUIT), - [this]() { - OnWindowHide(); - }); + Gtk::Stock::QUIT), + [this]() { + OnWindowHide(); + }); keybindings_.action_group_menu()->add(Gtk::Action::create("FileOpenFile", - Gtk::Stock::OPEN), - [this]() { - OnOpenFile(); - }); + Gtk::Stock::OPEN), + [this]() { + OnOpenFile(); + }); keybindings_.action_group_menu()->add(Gtk::Action::create("FileOpenFolder", - "Open folder"), - Gtk::AccelKey(keybindings_.config_ - .key_map()["open_folder"]), - [this]() { - OnFileOpenFolder(); - }); + "Open folder"), + Gtk::AccelKey(keybindings_.config_ + .key_map()["open_folder"]), + [this]() { + OnFileOpenFolder(); + }); keybindings_.action_group_menu()->add(Gtk::Action::create("FileSaveAs", "Save as"), @@ -35,14 +40,14 @@ Window::Window() : notebook_.OnSaveFile(); }); - keybindings_.action_group_menu()->add(Gtk::Action::create("FileSave", + keybindings_.action_group_menu()->add(Gtk::Action::create("FileSave", "Save"), Gtk::AccelKey(keybindings_.config_ .key_map()["save"]), [this]() { notebook_.OnSaveFile(); }); - keybindings_. + keybindings_. action_group_menu()-> add(Gtk::Action::create("ProjectCompileAndRun", "Compile And Run"), @@ -95,10 +100,6 @@ Window::Window() : connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false); terminal_.Terminal().signal_button_release_event(). connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false); - - PluginApi::menu_ = &menu_; - PluginApi::notebook_ = ¬ebook_; - PluginApi::InitPlugins(); add_accel_group(keybindings_.ui_manager_menu()->get_accel_group()); add_accel_group(keybindings_.ui_manager_hidden()->get_accel_group()); @@ -112,15 +113,16 @@ Window::Window() : paned_.pack2(terminal_.view(), true, true); window_box_.pack_end(paned_); show_all_children(); - } // Window constructor + INFO("Window created"); +} // Window constructor void Window::OnWindowHide() { hide(); } void Window::OnFileOpenFolder() { Gtk::FileChooserDialog dialog("Please choose a folder", - Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); - + Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + dialog.set_transient_for(*this); //Add response buttons the the dialog: dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); @@ -130,79 +132,78 @@ void Window::OnFileOpenFolder() { //Handle the response: switch(result) - { - case(Gtk::RESPONSE_OK): { - std::cout << "Folder selected: " << dialog.get_filename() - << std::endl; - notebook_.directories().open_folder(dialog.get_filename()); - std::cout << dialog.get_filename()<< std::endl; - break; - } + case(Gtk::RESPONSE_OK): + { + std::cout << "Folder selected: " << dialog.get_filename() + << std::endl; + notebook_.directories().open_folder(dialog.get_filename()); + std::cout << dialog.get_filename()<< std::endl; + break; + } case(Gtk::RESPONSE_CANCEL): - { - std::cout << "Cancel clicked." << std::endl; - break; - } + { + std::cout << "Cancel clicked." << std::endl; + break; + } default: - { - std::cout << "Unexpected button clicked." << std::endl; - break; + { + std::cout << "Unexpected button clicked." << std::endl; + break; + } } - } } void Window::OnOpenFile() { Gtk::FileChooserDialog dialog("Please choose a file", - Gtk::FILE_CHOOSER_ACTION_OPEN); - dialog.set_transient_for(*this); - dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); - - //Add response buttons the the dialog: - dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("_Open", Gtk::RESPONSE_OK); - - //Add filters, so that only certain file types can be selected: - Glib::RefPtr filter_text = Gtk::FileFilter::create(); - filter_text->set_name("Text files"); - filter_text->add_mime_type("text/plain"); - dialog.add_filter(filter_text); - - Glib::RefPtr filter_cpp = Gtk::FileFilter::create(); - filter_cpp->set_name("C/C++ files"); - filter_cpp->add_mime_type("text/x-c"); - filter_cpp->add_mime_type("text/x-c++"); - filter_cpp->add_mime_type("text/x-c-header"); - dialog.add_filter(filter_cpp); - - Glib::RefPtr filter_any = Gtk::FileFilter::create(); - filter_any->set_name("Any files"); - filter_any->add_pattern("*"); - dialog.add_filter(filter_any); - - int result = dialog.run(); - - switch (result) { - case(Gtk::RESPONSE_OK): { - std::cout << "Open clicked." << std::endl; - std::string path = dialog.get_filename(); - - std::cout << "File selected: " << path << std::endl; - notebook_.OnOpenFile(path); - break; - } - case(Gtk::RESPONSE_CANCEL): { - std::cout << "Cancel clicked." << std::endl; - break; - } - default: { - std::cout << "Unexpected button clicked." << std::endl; - break; - } - } + Gtk::FILE_CHOOSER_ACTION_OPEN); + dialog.set_transient_for(*this); + dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); + + //Add response buttons the the dialog: + dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("_Open", Gtk::RESPONSE_OK); + + //Add filters, so that only certain file types can be selected: + Glib::RefPtr filter_text = Gtk::FileFilter::create(); + filter_text->set_name("Text files"); + filter_text->add_mime_type("text/plain"); + dialog.add_filter(filter_text); + + Glib::RefPtr filter_cpp = Gtk::FileFilter::create(); + filter_cpp->set_name("C/C++ files"); + filter_cpp->add_mime_type("text/x-c"); + filter_cpp->add_mime_type("text/x-c++"); + filter_cpp->add_mime_type("text/x-c-header"); + dialog.add_filter(filter_cpp); + + Glib::RefPtr filter_any = Gtk::FileFilter::create(); + filter_any->set_name("Any files"); + filter_any->add_pattern("*"); + dialog.add_filter(filter_any); + + int result = dialog.run(); + + switch (result) { + case(Gtk::RESPONSE_OK): { + std::cout << "Open clicked." << std::endl; + std::string path = dialog.get_filename(); + + std::cout << "File selected: " << path << std::endl; + notebook_.OnOpenFile(path); + break; + } + case(Gtk::RESPONSE_CANCEL): { + std::cout << "Cancel clicked." << std::endl; + break; + } + default: { + std::cout << "Unexpected button clicked." << std::endl; + break; + } + } } bool Window::OnMouseRelease(GdkEventButton *button){ return notebook_.OnMouseRelease(button); } - diff --git a/juci/window.h b/juci/window.h index 2166c35..7f2b3f7 100644 --- a/juci/window.h +++ b/juci/window.h @@ -22,6 +22,7 @@ public: Menu::Controller menu_; Notebook::Controller notebook_; Terminal::Controller terminal_; + PluginApi api_; Keybindings::Controller& keybindings() { return keybindings_; } private: