diff --git a/src/autorotate-iio.cpp b/src/autorotate-iio.cpp index 4f0ba11..7656698 100644 --- a/src/autorotate-iio.cpp +++ b/src/autorotate-iio.cpp @@ -22,6 +22,7 @@ extern "C" { #include #include +#include } using namespace Gio; @@ -105,6 +106,12 @@ class WayfireAutorotateIIO : public wf::per_output_plugin_instance_t /* Transform coming from the iio-sensors, -1 means not set */ int32_t sensor_transform = -1; + /* Debounce: pending transform waiting to be confirmed stable */ + int32_t pending_transform = -1; + guint debounce_timer_id = 0; + static constexpr guint DEBOUNCE_ROTATE_MS = 500; + static constexpr guint DEBOUNCE_NORMAL_MS = 1200; + bool on_rotate_binding(int32_t target_rotation) { if (!output->can_activate_plugin(&grab_interface)) @@ -154,10 +161,18 @@ class WayfireAutorotateIIO : public wf::per_output_plugin_instance_t return true; } - wf::effect_hook_t on_frame = [=] () + /* Wayland event loop timer — fires every 50ms to pump the GLib main context + * even when the display is idle and on_frame would not run. */ + wl_event_source *glib_timer = nullptr; + + static int glib_timer_cb(void *data) { + auto *self = static_cast(data); Glib::MainContext::get_default()->iteration(false); - }; + wl_event_source_timer_update(self->glib_timer, 50); + return 0; + } + Glib::RefPtr loop; public: @@ -185,7 +200,10 @@ class WayfireAutorotateIIO : public wf::per_output_plugin_instance_t Gio::init(); loop = Glib::MainLoop::create(true); - output->render->add_effect(&on_frame, wf::OUTPUT_EFFECT_PRE); + + auto *evloop = wl_display_get_event_loop(wf::get_core().display); + glib_timer = wl_event_loop_add_timer(evloop, glib_timer_cb, this); + wl_event_source_timer_update(glib_timer, 50); watch_id = DBus::watch_name(DBus::BUS_TYPE_SYSTEM, "net.hadess.SensorProxy", sigc::mem_fun(this, &WayfireAutorotateIIO::on_iio_appeared), @@ -210,6 +228,7 @@ class WayfireAutorotateIIO : public wf::per_output_plugin_instance_t iio_proxy->signal_properties_changed().connect_notify( sigc::mem_fun(this, &WayfireAutorotateIIO::on_properties_changed)); iio_proxy->call_sync("ClaimAccelerometer"); + update_orientation(); } void on_properties_changed( @@ -228,6 +247,11 @@ class WayfireAutorotateIIO : public wf::per_output_plugin_instance_t Glib::Variant orientation; iio_proxy->get_cached_property(orientation, "AccelerometerOrientation"); + if (!orientation) + { + return; + } + LOGI("IIO Accelerometer orientation: %s", orientation.get().c_str()); static const std::map transform_by_name = @@ -238,10 +262,55 @@ class WayfireAutorotateIIO : public wf::per_output_plugin_instance_t {"bottom-up", WL_OUTPUT_TRANSFORM_180}, }; - if (transform_by_name.count(orientation.get())) + if (!transform_by_name.count(orientation.get())) { - sensor_transform = transform_by_name.find(orientation.get())->second; - update_transform(); + return; + } + + int32_t new_transform = transform_by_name.find(orientation.get())->second; + + bool timer_running = (debounce_timer_id != 0); + bool new_is_normal = (new_transform == WL_OUTPUT_TRANSFORM_NORMAL); + bool pend_is_normal = (pending_transform == WL_OUTPUT_TRANSFORM_NORMAL); + + if (!timer_running) + { + if (new_transform == sensor_transform) + { + return; + } + + pending_transform = new_transform; + guint delay = new_is_normal ? DEBOUNCE_NORMAL_MS : DEBOUNCE_ROTATE_MS; + debounce_timer_id = g_timeout_add(delay, [] (gpointer data) -> gboolean + { + auto *self = static_cast(data); + self->debounce_timer_id = 0; + self->sensor_transform = self->pending_transform; + self->update_transform(); + return G_SOURCE_REMOVE; + }, this); + } else if (!pend_is_normal) + { + if (!new_is_normal) + { + pending_transform = new_transform; + } + } else + { + if (!new_is_normal) + { + g_source_remove(debounce_timer_id); + pending_transform = new_transform; + debounce_timer_id = g_timeout_add(DEBOUNCE_ROTATE_MS, [] (gpointer data) -> gboolean + { + auto *self = static_cast(data); + self->debounce_timer_id = 0; + self->sensor_transform = self->pending_transform; + self->update_transform(); + return G_SOURCE_REMOVE; + }, this); + } } } @@ -259,13 +328,20 @@ class WayfireAutorotateIIO : public wf::per_output_plugin_instance_t output->rem_binding(&on_rotate_up); output->rem_binding(&on_rotate_down); + if (debounce_timer_id) + { + g_source_remove(debounce_timer_id); + debounce_timer_id = 0; + } + /* If loop is NULL, autorotate was disabled for the current output */ if (loop) { iio_proxy.reset(); DBus::unwatch_name(watch_id); loop->quit(); - output->render->rem_effect(&on_frame); + wl_event_source_remove(glib_timer); + glib_timer = nullptr; } } };