skui分为几个模块:
# skui itself
add_subdirectory(core)
add_subdirectory(css)
add_subdirectory(graphics)
add_subdirectory(gui)
add_subdirectory(opengl)
add_subdirectory(system)
目前example里面例程用到的只有core、graphics、gui三个模块。
基本功能,包括信号,属性,字符串,路径,应用程序,操作系统抽象
c++和h++后缀的文件作者是为了防止和其它文件重名,这几种后缀名没有区别,如果编译器支持的话,哪种后缀都是一样的,在C++ Primer上给出如下说明:
Unix uses: C, cc, cxx, c
GNU C++ uses: C, cc, cxx, cpp, c++
Digital Mars uses: cpp, cxx
Borland C++ uses: cpp
Watcom uses: cpp
Microsoft Visual C++ uses: cpp, cxx, cc
Metrowerks CodeWarrior uses: cpp, cp, cc, cxx, c++
在application构造函数中创建application实例
application::application(int argc, char* argv[], string name)
: commandline_arguments{argv+1, argv+argc}
, name{std::move(name)}
{
if(implementation::instance != nullptr)
{
std::cerr << "skui::core::application: creating a second application instance is not allowed.\n";
implementation::instance->quit();
}
implementation::instance = this;
}
提供方法获取实例
application& application::instance()
{
if(implementation::instance == nullptr)
{
std::cerr << "skui::core::application::instance: application instance not created.\n";
std::exit(EXIT_FAILURE);
}
return *implementation::instance;
}
呵,浓浓的C语言风格代码布局。
在application类中定义core::event_loop的实例event_loop
appcation的事件执行和退出
int application::execute()
{
return event_loop.execute();
}
void application::quit(int exit_code)
{
about_to_quit.emit();
event_loop.stop(exit_code);
}
用来处理事件循环
里面一共有这几个方法:execute、push、stop、interrupt
execute
int event_loop::execute()
{
while(!exit)
{
// wait on the queue to receive work
queue.wait();
auto commands = queue.take_commands();
if(filter)
filter(commands);
while(!commands.empty() && !exit)
{
commands.front()->execute();
commands.pop_front();
}
}
return exit_code;
}
push
void event_loop::push(command_queue::command_ptr&& command)
{
queue.push(std::move(command));
}
stop
void event_loop::stop(int return_code)
{
exit_code = return_code;
queue.push(std::make_unique([this] { exit = true; }));
}
interrupt
void event_loop::interrupt(int return_code)
{
exit_code = return_code;
queue.push_front(std::make_unique([this] { exit = true; }));
}
都是在对command_queue类操作
在看command_queue类之前先看command类
里面定义了一个模板和属性std::function
template
command(Callable callable, ArgTypes... args)
: function{[callable, args...] { return callable(args...); }}
{}
std::function function;
创建一个 std::function 类的对象去捕获 lambda 函数(有问题的可以看下匿名函数)
构造函数中把Callable传给function
command::command()
: function{[] {}}
{}
方法execute中执行function
void command::execute()
{
function();
}
用using实现别名,定义了一个双端队列commands_type,里面保存的是command类型的智能指针,用来储存渲染命令
using command_ptr = std::unique_ptr;
using commands_type = std::deque;
push:尾插新元素到deque
void command_queue::push(command_ptr&& command)
{
const std::lock_guard lock{queue_mutex};
queue.push_back(std::move(command));
condition_variable.notify_one();
}
呵,不得不吐槽一下这个csdn编辑器代码块不能取消格式,只能去清浏览器缓存
push_front:头插新元素到deque
void command_queue::push_front(command_queue::command_ptr&& command)
{
std::lock_guard lock{queue_mutex};
queue.push_front(std::move(command));
condition_variable.notify_one();
}
wait:通过条件变量和互斥锁等待
void command_queue::wait()
{
std::unique_lock lock{queue_mutex};
if(queue.empty())
condition_variable.wait(lock, [this] { return !queue.empty(); });
}
take_commands:获取queue并清空command_queue的属性queue
command_queue::commands_type command_queue::take_commands()
{
const std::lock_guard lock{queue_mutex};
commands_type result;
std::swap(result, queue);
return result;
}
定义了log打印,加上了时间
inline void debug_print(ArgTypes... args)
{
auto& stream = std::cerr;
core::ostream_format_keeper guard(stream);
const auto now = std::chrono::system_clock::now();
const auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000;
const auto time = std::chrono::system_clock::to_time_t(now);
const auto utc_time = std::gmtime(&time);
stream << std::put_time(utc_time, "%FT%T.")
<< std::setprecision(4) << std::setfill('0') << std::setw(3) << ms.count()
<< std::put_time(utc_time, "%z: ");
stream << std::boolalpha;
stream << std::setprecision(15);
((stream << args), ...);
}
使用dlopen加载动态库
load
bool library::load(path filename_to_load)
{
if(filename == filename_to_load)
{
if(native_handle)
return true;
}
else
{
if(!filename_to_load.empty())
filename = std::move(filename_to_load);
}
native_handle = implementation::load(filename.c_str());
return native_handle != nullptr;
}
unload
bool library::unload()
{
bool result = true;
if(native_handle != nullptr)
result = implementation::unload(native_handle);
native_handle = nullptr;
return result;
}
下面是有关C++实现信号(signal)和槽(slot)的部分
(╯°Д°)╯︵ ┻━┻
定义了一个基类tracker,定义了trackable的删除、拷贝、移动。
class tracker
{
public:
virtual void trackable_deleted(const trackable* object) = 0;
virtual void trackable_copied(const trackable* old_object, const trackable* new_object) = 0;
virtual void trackable_moved(const trackable* old_object, const trackable* new_object) = 0;
protected:
tracker() = default;
virtual ~tracker() = default;
};
下面是主角trackable
class trackable
{
public:
virtual ~trackable();
trackable(const trackable& other);
trackable(trackable&& other) noexcept;
trackable& operator=(trackable other);
void track(implementation::tracker* tracker) const;
void untrack(implementation::tracker* tracker) const;
protected:
trackable() = default;
private:
// mutable so you can be track const objects
mutable std::unordered_set trackers;
mutable std::mutex trackers_mutex;
};
unordered_set本质是使用hash散列的方式存储数据,是一种使用hash值作为key的容器.