Browse Source

Can now cancel all applications started in Juci with escape. Also some cleanup and fixes.

merge-requests/365/head
eidheim 10 years ago
parent
commit
10c5c5fb1b
  1. 6
      src/cmake.cc
  2. 6
      src/directories.cc
  3. 1
      src/directories.h
  4. 110
      src/terminal.cc
  5. 7
      src/terminal.h
  6. 52
      src/window.cc
  7. 2
      src/window.h

6
src/cmake.cc

@ -162,7 +162,7 @@ void CMake::parse_variable_parameters(std::string &data) {
pos++;
}
for(auto &var: variables) {
auto pos=data.find("${"+var.first+'}'); //TODO: check if there is a slash in front of $
auto pos=data.find("${"+var.first+'}');
while(pos!=std::string::npos) {
data.replace(pos, var.first.size()+3, var.second);
pos=data.find("${"+var.first+'}');
@ -170,7 +170,7 @@ void CMake::parse_variable_parameters(std::string &data) {
}
//Remove variables we do not know:
pos=data.find("${"); //TODO: check if there is a slash in front of $
pos=data.find("${");
auto pos_end=data.find("}", pos+2);
while(pos!=std::string::npos && pos_end!=std::string::npos) {
data.erase(pos, pos_end-pos+1);
@ -221,7 +221,7 @@ std::vector<std::string> CMake::get_function_parameters(std::string &data) {
parameters.emplace_back(data.substr(parameter_pos));
for(auto &var: variables) {
for(auto &parameter: parameters) {
auto pos=parameter.find("${"+var.first+'}'); //TODO: check if there is a slash in front of $
auto pos=parameter.find("${"+var.first+'}');
while(pos!=std::string::npos) {
parameter.replace(pos, var.first.size()+3, var.second);
pos=parameter.find("${"+var.first+'}');

6
src/directories.cc

@ -58,7 +58,7 @@ void Directories::open_folder(const boost::filesystem::path& dir_path) {
tree_store->clear();
if(current_path!=new_path)
if(dir_path!="")
cmake=std::unique_ptr<CMake>(new CMake(new_path));
auto project=cmake->get_functions_parameters("project");
if(project.size()>0 && project[0].second.size()>0)
@ -71,6 +71,9 @@ void Directories::open_folder(const boost::filesystem::path& dir_path) {
tree_view.expand_row(path, false);
current_path=new_path;
if(selected_path.size()>0)
select_path(selected_path);
DEBUG("Folder opened");
}
@ -80,6 +83,7 @@ void Directories::select_path(const std::string &path) {
auto tree_path=Gtk::TreePath(iter);
tree_view.expand_to_path(tree_path);
tree_view.set_cursor(tree_path);
selected_path=path;
return true;
}
return false;

1
src/directories.h

@ -41,6 +41,7 @@ private:
Gtk::TreeView tree_view;
Glib::RefPtr<Gtk::TreeStore> tree_store;
ColumnRecord column_record;
std::string selected_path;
};
#endif // JUCI_DIRECTORIES_H_

110
src/terminal.cc

@ -2,6 +2,67 @@
#include <iostream>
#include "logging.h"
#include "singletons.h"
#include <unistd.h>
#include <sys/wait.h>
#include <iostream> //TODO: remove
using namespace std; //TODO: remove
#define READ 0
#define WRITE 1
//TODO: Windows...
//Coppied partially from http://www.linuxprogrammingblog.com/code-examples/sigaction
void signal_execl_exit(int sig, siginfo_t *siginfo, void *context) {
int status;
while (waitpid(siginfo->si_pid, &status, WNOHANG) > 0) {}
Singleton::terminal()->async_pid_mutex.lock();
if(Singleton::terminal()->async_pid_descriptors.find(siginfo->si_pid)!=Singleton::terminal()->async_pid_descriptors.end()) {
Singleton::terminal()->async_pid_status[siginfo->si_pid]=status;
close(Singleton::terminal()->async_pid_descriptors.at(siginfo->si_pid).first);
close(Singleton::terminal()->async_pid_descriptors.at(siginfo->si_pid).second);
Singleton::terminal()->async_pid_descriptors.erase(siginfo->si_pid);
}
Singleton::terminal()->async_pid_mutex.unlock();
}
//TODO: Windows...
//Copied from http://stackoverflow.com/questions/12778672/killing-process-that-has-been-created-with-popen2
pid_t popen2(const char *command, int *input_descriptor, int *output_descriptor) {
pid_t pid;
int p_stdin[2], p_stdout[2];
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0) {
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execl("/bin/sh", "sh", "-c", command, NULL);
perror("execl");
exit(1);
}
if (input_descriptor == NULL)
close(p_stdin[WRITE]);
else
*input_descriptor = p_stdin[WRITE];
if (output_descriptor == NULL)
close(p_stdout[READ]);
else
*output_descriptor = p_stdout[READ];
return pid;
}
Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) {
waiting_print.connect([this](){
@ -55,9 +116,20 @@ Terminal::Terminal() {
});
async_execute_print.connect([this](){
print(async_execute_print_string);
async_execute_print_finished=true;
async_execute_print_string_mutex.lock();
if(async_execute_print_string.size()>0) {
print(async_execute_print_string);
async_execute_print_string="";
}
async_execute_print_string_mutex.unlock();
});
//Coppied from http://www.linuxprogrammingblog.com/code-examples/sigaction
struct sigaction act;
memset (&act, '\0', sizeof(act));
act.sa_sigaction = &signal_execl_exit;
act.sa_flags = SA_SIGINFO;
sigaction(SIGCHLD, &act, NULL);
}
bool Terminal::execute(const std::string &command, const std::string &path) {
@ -97,28 +169,36 @@ void Terminal::async_execute(const std::string &command, const std::string &path
boost_path=boost::filesystem::path(path);
//TODO: Windows...
cd_path_and_command="cd "+boost_path.string()+" 2>&1 && "+command;
cd_path_and_command="cd "+boost_path.string()+" 2>&1 && exec "+command;
}
else
cd_path_and_command=command;
FILE* p;
p = popen(cd_path_and_command.c_str(), "r");
if (p == NULL) {
async_execute_print_string="Error: Failed to run command" + command + "\n";
async_execute_print_finished=false;
int input_descriptor, output_descriptor;
async_pid_mutex.lock();
auto pid=popen2(cd_path_and_command.c_str(), &input_descriptor, &output_descriptor);
async_pid_descriptors[pid]={input_descriptor, output_descriptor};
async_pid_mutex.unlock();
if (pid<=0) {
async_execute_print_string_mutex.lock();
async_execute_print_string+="Error: Failed to run command" + command + "\n";
async_execute_print_string_mutex.unlock();
async_execute_print();
}
else {
char buffer[1024];
while (fgets(buffer, 1024, p) != NULL) {
async_execute_print_string=buffer;
async_execute_print_finished=false;
ssize_t n;
while ((n=read(output_descriptor, buffer, 1024)) > 0) {
async_execute_print_string_mutex.lock();
for(int c=0;c<n;c++)
async_execute_print_string+=buffer[c];
async_execute_print_string_mutex.unlock();
async_execute_print();
while(!async_execute_print_finished)
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
int exit_code=pclose(p);
async_pid_mutex.lock();
int exit_code=async_pid_status.at(pid);
async_pid_status.erase(pid);
async_pid_mutex.unlock();
if(callback)
callback(exit_code==0);
}
@ -128,7 +208,7 @@ void Terminal::async_execute(const std::string &command, const std::string &path
int Terminal::print(std::string message){
INFO("Terminal: PrintMessage");
text_view.get_buffer()->insert(text_view.get_buffer()->end(), "> "+message);
text_view.get_buffer()->insert(text_view.get_buffer()->end(), message);
return text_view.get_buffer()->end().get_line();
}

7
src/terminal.h

@ -7,6 +7,7 @@
#include <boost/filesystem.hpp>
#include <thread>
#include <atomic>
#include <unordered_map>
class Terminal : public Gtk::HBox {
public:
@ -27,6 +28,10 @@ public:
Terminal();
bool execute(const std::string &command, const std::string &path="");
void async_execute(const std::string &command, const std::string &path="", std::function<void(bool success)> callback=nullptr);
std::unordered_map<pid_t, std::pair<int, int> > async_pid_descriptors;
std::unordered_map<pid_t, int> async_pid_status;
std::mutex async_pid_mutex;
int print(std::string message);
void print(int line_nr, std::string message);
std::shared_ptr<InProgress> print_in_progress(std::string start_msg);
@ -36,7 +41,7 @@ private:
Glib::Dispatcher async_execute_print;
std::string async_execute_print_string;
std::atomic<bool> async_execute_print_finished;
std::mutex async_execute_print_string_mutex;
};
#endif // JUCI_TERMINAL_H_

52
src/window.cc

@ -88,6 +88,17 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil
notebook.signal_page_removed().connect([this](Gtk::Widget* page, guint page_num) {
entry_box.hide();
});
compile_success.connect([this](){
directories.open_folder();
});
run_success.connect([this](){
Singleton::terminal()->print("Execution returned: success\n");
});
run_error.connect([this](){
Singleton::terminal()->print("Execution returned: error\n");
});
INFO("Window created");
} // Window constructor
@ -197,6 +208,7 @@ void Window::create_menu() {
if(notebook.get_current_page()==-1 || compiling)
return;
CMake cmake(notebook.get_current_view()->file_path);
directories.open_folder();
auto executables = cmake.get_functions_parameters("add_executable");
std::string executable;
boost::filesystem::path path;
@ -207,29 +219,40 @@ void Window::create_menu() {
}
if(cmake.project_path!="") {
compiling=true;
if(path!="")
if(path!="") {
Singleton::terminal()->print("Compiling and executing "+path.string()+"\n");
//TODO: Windows...
Singleton::terminal()->async_execute("make 2>&1", cmake.project_path.string(), [this, path](bool success){
compiling=false;
if(success) {
compile_success();
//TODO: Windows...
Singleton::terminal()->async_execute(path.string()+" 2>&1", path.parent_path().string(), [this](bool success){
if(success)
run_success();
else
run_error();
});
}
});
}
else
Singleton::terminal()->print("Could not find an executable, please use add_executable in CMakeLists.txt\n");
//TODO: Windows...
Singleton::terminal()->async_execute("make 2>&1", cmake.project_path.string(), [this, path](int exit_code){
compiling=false;
if(path!="")
//TODO: Windows...
Singleton::terminal()->async_execute(path.string()+" 2>&1", path.parent_path().string());
});
}
});
menu.action_group->add(Gtk::Action::create("ProjectCompile", "Compile"), Gtk::AccelKey(menu.key_map["compile"]), [this]() {
if(notebook.get_current_page()==-1 || compiling)
return;
CMake cmake(notebook.get_current_view()->file_path);
directories.open_folder();
if(cmake.project_path!="") {
compiling=true;
Singleton::terminal()->print("Compiling project "+cmake.project_path.string()+"\n");
//TODO: Windows...
Singleton::terminal()->async_execute("make 2>&1", cmake.project_path.string(), [this](int exit_code){
Singleton::terminal()->async_execute("make 2>&1", cmake.project_path.string(), [this](bool success){
compiling=false;
if(success)
compile_success();
});
}
});
@ -243,8 +266,15 @@ void Window::create_menu() {
}
bool Window::on_key_press_event(GdkEventKey *event) {
if(event->keyval==GDK_KEY_Escape)
if(event->keyval==GDK_KEY_Escape) {
if(entry_box.entries.size()==0) {
Singleton::terminal()->async_pid_mutex.lock();
for(auto &pid: Singleton::terminal()->async_pid_descriptors)
kill(pid.first, SIGTERM);
Singleton::terminal()->async_pid_mutex.unlock();
}
entry_box.hide();
}
#ifdef __APPLE__ //For Apple's Command-left, right, up, down keys
else if((event->state & GDK_META_MASK)>0) {
if(event->keyval==GDK_KEY_Left) {
@ -336,8 +366,6 @@ void Window::open_folder_dialog() {
if(result==Gtk::RESPONSE_OK) {
std::string project_path=dialog.get_filename();
directories.open_folder(project_path);
if(notebook.get_current_page()!=-1)
directories.select_path(notebook.get_current_view()->file_path);
}
}

2
src/window.h

@ -26,6 +26,8 @@ private:
EntryBox entry_box;
Menu menu;
std::atomic<bool> compiling;
Glib::Dispatcher compile_success;
Glib::Dispatcher run_success, run_error;
void create_menu();
void hide();

Loading…
Cancel
Save