#include "remoting/host/linux/ei_event_watcher_glib.h"
#include <unistd.h>
#include "base/check.h"
#include "base/memory/raw_ptr.h"
#include "third_party/libei/include/libei.h"
namespace remoting {
constexpr GSourceFuncs EiEventWatcherGlib::kWatchSourceFuncs;
EiEventWatcherGlib::EiEventWatcherGlib(
int fd,
ei* ei,
EiEventWatcherGlib::EiEventHandler* handler)
: fd_(fd), ei_(ei_ref(ei)), handler_(handler) {}
EiEventWatcherGlib::~EiEventWatcherGlib() {
StopProcessingEvents();
}
void EiEventWatcherGlib::StartProcessingEvents() {
DCHECK(!ei_source_);
ei_source_ = static_cast<GLibEiSource*>(g_source_new(
const_cast<GSourceFuncs*>(&kWatchSourceFuncs), sizeof(GLibEiSource)));
ei_source_->event_watcher = this;
ei_source_->poll_fd = {
.fd = fd_,
.events = G_IO_IN,
.revents = 0,
};
g_source_add_poll(ei_source_, &ei_source_->poll_fd);
g_source_set_can_recurse(ei_source_, TRUE);
auto* context = g_main_context_get_thread_default();
if (!context) {
context = g_main_context_default();
}
g_source_attach(ei_source_, context);
g_source_set_priority(ei_source_, kPriorityFdWatch);
}
void EiEventWatcherGlib::StopProcessingEvents() {
if (ei_source_) {
close(fd_);
g_source_destroy(ei_source_);
g_source_unref(ei_source_);
ei_source_ = nullptr;
}
if (ei_) {
ei_unref(ei_);
ei_ = nullptr;
}
}
gboolean EiEventWatcherGlib::WatchSourcePrepare(GSource* source,
gint* timeout_ms) {
*timeout_ms = -1;
auto* event_watcher_glib =
static_cast<GLibEiSource*>(source)->event_watcher.get();
return event_watcher_glib->Prepare();
}
gboolean EiEventWatcherGlib::WatchSourceCheck(GSource* source) {
auto* glib_ei_source = static_cast<GLibEiSource*>(source);
gushort flags = glib_ei_source->poll_fd.revents;
return flags & G_IO_IN;
}
gboolean EiEventWatcherGlib::WatchSourceDispatch(GSource* source,
GSourceFunc unused_func,
gpointer data) {
auto* event_watcher_glib =
static_cast<GLibEiSource*>(source)->event_watcher.get();
event_watcher_glib->Dispatch();
return TRUE;
}
bool EiEventWatcherGlib::Prepare() {
if (!ei_) {
return false;
}
struct ei_event* event = ei_peek_event(ei_.get());
if (event) {
ei_event_unref(event);
return true;
}
return false;
}
void EiEventWatcherGlib::Dispatch() {
ei_dispatch(ei_);
struct ei_event* event;
while ((event = ei_peek_event(ei_))) {
ei_event_unref(event);
event = ei_get_event(ei_);
if (handler_) {
handler_->HandleEiEvent(event);
}
bool should_stop = ei_event_get_type(event) == EI_EVENT_DISCONNECT;
ei_event_unref(event);
if (should_stop) {
StopProcessingEvents();
break;
}
}
}
}