diff --git a/plugins/animate/fire/fire.cpp b/plugins/animate/fire/fire.cpp index 647e80ac6..d8996cc17 100644 --- a/plugins/animate/fire/fire.cpp +++ b/plugins/animate/fire/fire.cpp @@ -139,7 +139,7 @@ class fire_render_instance_t : public wf::scene::render_instance_t wf::output_t *output) { this->self = std::dynamic_pointer_cast(self->shared_from_this()); - auto child_damage = [=] (const wf::region_t& damage) + auto child_damage = [=] (const wf::regionf_t& damage) { push_damage(damage | self->get_bounding_box()); }; @@ -155,7 +155,7 @@ class fire_render_instance_t : public wf::scene::render_instance_t void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { if (children.empty()) { @@ -191,7 +191,7 @@ class fire_render_instance_t : public wf::scene::render_instance_t { for (auto box : data.damage) { - wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box)); + wf::gles::render_target_logic_scissor(data.target, box); self->ps->render(wf::gles::render_target_orthographic_projection(data.target) * translate); } }); @@ -205,7 +205,7 @@ class fire_render_instance_t : public wf::scene::render_instance_t } } - void compute_visibility(wf::output_t *output, wf::region_t& visible) override + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { for (auto& ch : this->children) { diff --git a/plugins/animate/squeezimize.hpp b/plugins/animate/squeezimize.hpp index 630293c28..3573fd2a2 100644 --- a/plugins/animate/squeezimize.hpp +++ b/plugins/animate/squeezimize.hpp @@ -209,7 +209,7 @@ class squeezimize_transformer : public wf::scene::view_2d_transformer_t void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { instructions.push_back(render_instruction_t{ .instance = this, @@ -218,9 +218,9 @@ class squeezimize_transformer : public wf::scene::view_2d_transformer_t }); } - void transform_damage_region(wf::region_t& damage) override + void transform_damage_region(wf::regionf_t& damage) override { - damage |= wf::region_t{self->animation_geometry}; + damage |= self->animation_geometry; } void render(const render_instruction_t& data) override @@ -247,14 +247,19 @@ class squeezimize_transformer : public wf::scene::view_2d_transformer_t (self->minimize_target.y + self->minimize_target.height) - src_box.y), (src_box.y + src_box.height) - self->minimize_target.y); + const float geometry_x = (float)self->animation_geometry.x; + const float geometry_y = (float)self->animation_geometry.y; + const float geometry_width = (float)self->animation_geometry.width; + const float geometry_height = (float)self->animation_geometry.height; + const float vertex_data_pos[] = { - 1.0f * self->animation_geometry.x, - 1.0f * self->animation_geometry.y + self->animation_geometry.height, - 1.0f * self->animation_geometry.x + self->animation_geometry.width, - 1.0f * self->animation_geometry.y + self->animation_geometry.height, - 1.0f * self->animation_geometry.x + self->animation_geometry.width, - 1.0f * self->animation_geometry.y, - 1.0f * self->animation_geometry.x, 1.0f * self->animation_geometry.y, + geometry_x, + geometry_y + geometry_height, + geometry_x + geometry_width, + geometry_y + geometry_height, + geometry_x + geometry_width, + geometry_y, + geometry_x, geometry_y, }; const glm::vec4 src_box_pos{ @@ -290,7 +295,7 @@ class squeezimize_transformer : public wf::scene::view_2d_transformer_t self->program.set_active_texture(src_tex); for (auto box : data.damage) { - gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box)); + gles::render_target_logic_scissor(data.target, box); GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4)); } }); @@ -418,7 +423,8 @@ class squeezimize_animation : public animate::animation_base_t wf::dassert(toplevel != nullptr, "We cannot minimize non-toplevel views!"); auto hint = toplevel->get_minimize_hint(); auto tmgr = view->get_transformed_node(); - auto node = std::make_shared(view, dur, hint, bbox); + auto node = std::make_shared(view, dur, + wf::from_framebuffer_box(hint), bbox); tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, squeezimize_transformer_name); node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION); } diff --git a/plugins/blur/blur-base.cpp b/plugins/blur/blur-base.cpp index df15bc016..76f93fbc2 100644 --- a/plugins/blur/blur-base.cpp +++ b/plugins/blur/blur-base.cpp @@ -128,10 +128,9 @@ static int round_up(int x, int mod) * Calculate the smallest box which contains @box and whose x, y, width, height * are divisible by @degrade, and clamp that box to @bounds. */ -static wf::geometry_t sanitize(wf::geometry_t box, int degrade, - wf::geometry_t bounds) +static wlr_box sanitize(wlr_box box, int degrade, wlr_box bounds) { - wf::geometry_t out_box; + wlr_box out_box; out_box.x = degrade * int(box.x / degrade); out_box.y = degrade * int(box.y / degrade); out_box.width = round_up(box.width, degrade); @@ -147,7 +146,8 @@ static wf::geometry_t sanitize(wf::geometry_t box, int degrade, out_box.height += degrade; } - return wf::clamp(out_box, bounds); + return wlr_box(wf::to_framebuffer_box(wf::clamp(wf::from_framebuffer_box(out_box), + wf::from_framebuffer_box(bounds)))); } wlr_box wf_blur_base::copy_region(wf::auxilliary_buffer_t& result, @@ -212,7 +212,7 @@ void wf_blur_base::prepare_blur(const wf::render_target_t& target_fb, const wf:: std::swap(fb[0], fb[1]); } - prepared_geometry = damage_box; + prepared_geometry = wf::from_framebuffer_box(damage_box); } static wf::pointf_t get_center(wf::geometry_t g) @@ -264,7 +264,7 @@ void wf_blur_base::render(wf::gles_texture_t src_tex, wlr_box src_box, const wf: const auto scale_y = 1.0 * view_box.height / blurred_box.height; glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3{scale_x, scale_y, 1.0}); - const wf::pointf_t center_view = get_center(view_box); + const wf::pointf_t center_view = get_center(wf::from_framebuffer_box(view_box)); const wf::pointf_t center_prepared = get_center(blurred_box); const auto translate_x = 1.0 * (center_view.x - center_prepared.x) / view_box.width; const auto translate_y = 1.0 * (center_view.y - center_prepared.y) / view_box.height; @@ -287,7 +287,8 @@ void wf_blur_base::render(wf::gles_texture_t src_tex, wlr_box src_box, const wf: for (const auto& box : damage) { - wf::gles::render_target_logic_scissor(target_fb, wlr_box_from_pixman_box(box)); + wf::gles::render_target_logic_scissor(target_fb, + wf::from_framebuffer_box(wlr_box_from_pixman_box(box))); GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4)); } diff --git a/plugins/blur/blur.cpp b/plugins/blur/blur.cpp index e55284947..18d115cd7 100644 --- a/plugins/blur/blur.cpp +++ b/plugins/blur/blur.cpp @@ -96,7 +96,7 @@ class blur_render_instance_t : public transformer_render_instance_t public: using transformer_render_instance_t::transformer_render_instance_t; - bool is_fully_opaque(wf::region_t damage) + bool is_fully_opaque(wf::regionf_t damage) { if (self->get_children().size() == 1) { @@ -109,7 +109,7 @@ class blur_render_instance_t : public transformer_render_instance_t return false; } - wf::region_t calculate_translucent_damage(const wf::render_target_t& target, wf::region_t damage) + wf::regionf_t calculate_translucent_damage(const wf::render_target_t& target, wf::regionf_t damage) { if (self->get_children().size() == 1) { @@ -120,7 +120,7 @@ class blur_render_instance_t : public transformer_render_instance_t auto opaque_region = opaque->get_opaque_region(); opaque_region.expand_edges(-padding); - wf::region_t translucent_region = damage ^ opaque_region; + wf::regionf_t translucent_region = damage ^ opaque_region; return translucent_region; } } @@ -129,7 +129,7 @@ class blur_render_instance_t : public transformer_render_instance_t } void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { const int padding = calculate_damage_padding(target, self->provider()->calculate_blur_radius()); auto bbox = self->get_bounding_box(); @@ -164,7 +164,7 @@ class blur_render_instance_t : public transformer_render_instance_t padded_region &= target.geometry; // Actual region which will be repainted by this render instance. - wf::region_t we_repaint = padded_region; + wf::regionf_t we_repaint = padded_region; this->saved_pixels = self->acquire_saved_pixel_buffer(); saved_pixels->region = @@ -204,15 +204,18 @@ class blur_render_instance_t : public transformer_render_instance_t void render(const wf::scene::render_instruction_t& data) override { - auto bounding_box = self->get_bounding_box(); + auto bounding_box = wf::to_framebuffer_box(self->get_bounding_box()); data.pass->custom_gles_subpass([&] { auto tex = wf::gles_texture_t{get_texture(data.target.scale)}; if (!data.damage.empty()) { - auto translucent_damage = calculate_translucent_damage(data.target, data.damage); - self->provider()->prepare_blur(data.target, translucent_damage); - self->provider()->render(tex, bounding_box, data.damage, data.target, data.target); + auto translucent_damage = calculate_translucent_damage(data.target, data.damage); + auto translucent_damage_fb = + data.target.framebuffer_region_from_geometry_region(translucent_damage); + auto render_damage_fb = data.target.framebuffer_region_from_geometry_region(data.damage); + self->provider()->prepare_blur(data.target, translucent_damage_fb); + self->provider()->render(tex, bounding_box, render_damage_fb, data.target, data.target); } GL_CALL(glDisable(GL_SCISSOR_TEST)); diff --git a/plugins/common/move-drag-interface.cpp b/plugins/common/move-drag-interface.cpp index 8945d8616..2552afd24 100644 --- a/plugins/common/move-drag-interface.cpp +++ b/plugins/common/move-drag-interface.cpp @@ -26,13 +26,13 @@ namespace wf { namespace move_drag { -static wf::geometry_t find_geometry_around(wf::dimensions_t size, wf::point_t grab, wf::pointf_t relative) +static wf::geometry_t find_geometry_around(wf::dimensions_t size, wf::pointf_t grab, wf::pointf_t relative) { return wf::geometry_t{ - grab.x - (int)std::floor(relative.x * size.width), - grab.y - (int)std::floor(relative.y * size.height), - size.width, - size.height, + grab.x - std::floor(relative.x * size.width), + grab.y - std::floor(relative.y * size.height), + (double)size.width, + (double)size.height, }; } @@ -65,7 +65,7 @@ class scale_around_grab_t : public wf::scene::transformer_base_node_t * The position where the grab appears on the outputs, in output-layout * coordinates. */ - wf::point_t grab_position; + wf::pointf_t grab_position; scale_around_grab_t() : transformer_base_node_t(false) {} @@ -111,7 +111,7 @@ class scale_around_grab_t : public wf::scene::transformer_base_node_t public: using transformer_render_instance_t::transformer_render_instance_t; - void transform_damage_region(wf::region_t& region) override + void transform_damage_region(wf::regionf_t& region) override { region |= self->get_bounding_box(); } @@ -178,7 +178,7 @@ class dragged_view_node_t : public wf::scene::node_t wf::geometry_t get_bounding_box() override { - wf::region_t bounding; + wf::regionf_t bounding; for (auto& view : views) { // Note: bbox will be in output layout coordinates now, since this is @@ -187,7 +187,13 @@ class dragged_view_node_t : public wf::scene::node_t bounding |= bbox; } - return wlr_box_from_pixman_box(bounding.get_extents()); + auto extents = bounding.get_extents(); + return { + extents.x1, + extents.y1, + extents.x2 - extents.x1, + extents.y2 - extents.y1, + }; } class dragged_view_render_instance_t : public wf::scene::render_instance_t @@ -217,7 +223,7 @@ class dragged_view_node_t : public wf::scene::node_t all_rendered.push_back(view.view->get_transformed_node()); } - auto push_damage_child = [=] (wf::region_t child_damage) + auto push_damage_child = [=] (wf::regionf_t child_damage) { push_damage(last_bbox); last_bbox = this->self.lock()->get_bounding_box(); @@ -229,14 +235,15 @@ class dragged_view_node_t : public wf::scene::node_t push_damage_child, shown_on); - const int BIG_NUMBER = 1e5; - wf::region_t big_region = - wf::geometry_t{-BIG_NUMBER, -BIG_NUMBER, 2 * BIG_NUMBER, 2 * BIG_NUMBER}; + const int BIG_NUMBER = 1e5; + wf::regionf_t big_region{wf::geometry_t{(double)-BIG_NUMBER, (double)-BIG_NUMBER, + 2.0 * BIG_NUMBER, + 2.0 * BIG_NUMBER}}; children_manager->set_visibility_region(big_region); } void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { for (auto& inst : children_manager->get_instances()) { @@ -304,13 +311,13 @@ core_drag_t::core_drag_t() core_drag_t::~core_drag_t() = default; -void core_drag_t::rebuild_wobbly(wayfire_toplevel_view view, wf::point_t grab, wf::pointf_t relative) +void core_drag_t::rebuild_wobbly(wayfire_toplevel_view view, wf::pointf_t grab, wf::pointf_t relative) { auto dim = wf::dimensions(wf::view_bounding_box_up_to(view, "wobbly")); modify_wobbly(view, find_geometry_around(dim, grab, relative)); } -bool core_drag_t::should_start_pending_drag(wf::point_t current_position) +bool core_drag_t::should_start_pending_drag(wf::pointf_t current_position) { if (!tentative_grab_position.has_value()) { @@ -329,9 +336,9 @@ void core_drag_t::start_drag(wayfire_toplevel_view grab_view, wf::pointf_t relat wf::dassert(!this->view, "Drag operation already in progress!"); auto bbox = wf::view_bounding_box_up_to(grab_view, "wobbly"); - wf::point_t rel_grab_pos = { - int(bbox.x + relative.x * bbox.width), - int(bbox.y + relative.y * bbox.height), + wf::pointf_t rel_grab_pos = { + bbox.x + relative.x * bbox.width, + bbox.y + relative.y * bbox.height, }; if (options.join_views) @@ -408,7 +415,7 @@ void core_drag_t::start_drag(wayfire_toplevel_view view, const drag_options_t& o start_drag(view, find_relative_grab(bbox, *tentative_grab_position), options); } -void core_drag_t::handle_motion(wf::point_t to) +void core_drag_t::handle_motion(wf::pointf_t to) { if (priv->view_held_in_place) { @@ -448,7 +455,7 @@ void core_drag_t::handle_motion(wf::point_t to) emit(&data); } -double core_drag_t::distance_to_grab_origin(wf::point_t to) const +double core_drag_t::distance_to_grab_origin(wf::pointf_t to) const { return abs(to - *tentative_grab_position); } @@ -537,10 +544,9 @@ bool core_drag_t::is_view_held_in_place() return priv->view_held_in_place; } -void core_drag_t::update_current_output(wf::point_t grab) +void core_drag_t::update_current_output(wf::pointf_t grab) { - wf::pointf_t origin = {1.0 * grab.x, 1.0 * grab.y}; - auto output = wf::get_core().output_layout->find_closest_output(origin); + auto output = wf::get_core().output_layout->find_closest_output(grab); update_current_output(output); } @@ -597,8 +603,8 @@ void adjust_view_on_output(drag_done_signal *ev) auto output_geometry = ev->focused_output->get_relative_geometry(); auto current_ws = ev->focused_output->wset()->get_current_workspace(); wf::point_t target_ws{ - (int)std::floor(1.0 * grab.x / output_geometry.width), - (int)std::floor(1.0 * grab.y / output_geometry.height), + (int)std::floor(grab.x / output_geometry.width), + (int)std::floor(grab.y / output_geometry.height), }; target_ws = target_ws + current_ws; @@ -620,11 +626,11 @@ void adjust_view_on_output(drag_done_signal *ev) auto bbox = wf::view_bounding_box_up_to(v.view, "wobbly"); auto wm = v.view->get_geometry(); - wf::point_t wm_offset = wf::origin(wm) + -wf::origin(bbox); + wf::pointf_t wm_offset = wf::origin(wm) + -wf::origin(bbox); bbox = wf::move_drag::find_geometry_around( wf::dimensions(bbox), grab, v.relative_grab); - wf::point_t target = wf::origin(bbox) + wm_offset; + wf::pointf_t target = wf::origin(bbox) + wm_offset; v.view->move(target.x, target.y); if (v.view->pending_fullscreen()) { diff --git a/plugins/common/wayfire/plugins/common/geometry-animation.hpp b/plugins/common/wayfire/plugins/common/geometry-animation.hpp index 7fde16e8c..a78d52603 100644 --- a/plugins/common/wayfire/plugins/common/geometry-animation.hpp +++ b/plugins/common/wayfire/plugins/common/geometry-animation.hpp @@ -28,7 +28,7 @@ class geometry_animation_t : public duration_t operator wf::geometry_t() const { - return {(int)x, (int)y, (int)width, (int)height}; + return {(double)x, (double)y, (double)width, (double)height}; } protected: @@ -46,9 +46,9 @@ class geometry_animation_t : public duration_t static inline wf::geometry_t interpolate(wf::geometry_t a, wf::geometry_t b, double alpha) { - const auto& interp = [=] (int32_t wf::geometry_t::*member) -> int32_t + const auto& interp = [=] (double wf::geometry_t::*member) -> double { - return std::round((1 - alpha) * a.*member + alpha * b.*member); + return (1 - alpha) * a.*member + alpha * b.*member; }; return { diff --git a/plugins/common/wayfire/plugins/common/move-drag-interface.hpp b/plugins/common/wayfire/plugins/common/move-drag-interface.hpp index 77aab4a22..d774af983 100644 --- a/plugins/common/wayfire/plugins/common/move-drag-interface.hpp +++ b/plugins/common/wayfire/plugins/common/move-drag-interface.hpp @@ -50,7 +50,7 @@ struct drag_focus_output_signal */ struct drag_motion_signal { - wf::point_t current_position; + wf::pointf_t current_position; }; /** @@ -101,7 +101,7 @@ struct drag_done_signal * The position of the input when the view was dropped. * In output-layout coordinates. */ - wf::point_t grab_position; + wf::pointf_t grab_position; }; /** @@ -109,7 +109,7 @@ struct drag_done_signal * Example: returns [0.5, 0.5] if the grab is the midpoint of the view. */ inline static wf::pointf_t find_relative_grab( - wf::geometry_t view, wf::point_t grab) + wf::geometry_t view, wf::pointf_t grab) { return wf::pointf_t{ 1.0 * (grab.x - view.x) / view.width, @@ -161,10 +161,10 @@ class core_drag_t : public signal::provider_t * Rebuild the wobbly model after a change in the scaling, so that the wobbly * model does not try to animate the scaling change itself. */ - void rebuild_wobbly(wayfire_toplevel_view view, wf::point_t grab, wf::pointf_t relative); + void rebuild_wobbly(wayfire_toplevel_view view, wf::pointf_t grab, wf::pointf_t relative); public: - std::optional tentative_grab_position; + std::optional tentative_grab_position; core_drag_t(); ~core_drag_t(); @@ -174,7 +174,7 @@ class core_drag_t : public signal::provider_t template void set_pending_drag(const Point& current_position) { - this->tentative_grab_position = {(int)current_position.x, (int)current_position.y}; + this->tentative_grab_position = {current_position.x, current_position.y}; } /** @@ -183,7 +183,7 @@ class core_drag_t : public signal::provider_t * Note that in some cases this functionality is not used at all, if the action for example was triggered * by a binding. */ - bool should_start_pending_drag(wf::point_t current_position); + bool should_start_pending_drag(wf::pointf_t current_position); /** * Start the actual dragging operation. Note: this should be called **after** set_pending_drag(). @@ -195,9 +195,9 @@ class core_drag_t : public signal::provider_t void start_drag(wayfire_toplevel_view grab_view, wf::pointf_t relative, const drag_options_t& options); void start_drag(wayfire_toplevel_view view, const drag_options_t& options); - void handle_motion(wf::point_t to); + void handle_motion(wf::pointf_t to); - double distance_to_grab_origin(wf::point_t to) const; + double distance_to_grab_origin(wf::pointf_t to) const; void handle_input_released(); void set_scale(double new_scale, double alpha = 1.0); @@ -214,7 +214,7 @@ class core_drag_t : public signal::provider_t std::unique_ptr priv; - void update_current_output(wf::point_t grab); + void update_current_output(wf::pointf_t grab); void update_current_output(wf::output_t *output); }; diff --git a/plugins/common/wayfire/plugins/common/preview-indication.hpp b/plugins/common/wayfire/plugins/common/preview-indication.hpp index f222a4899..1494b2b43 100644 --- a/plugins/common/wayfire/plugins/common/preview-indication.hpp +++ b/plugins/common/wayfire/plugins/common/preview-indication.hpp @@ -68,8 +68,8 @@ class preview_indication_t : public std::enable_shared_from_thisposition = position; } @@ -59,5 +59,5 @@ class simple_text_node_t : public wf::scene::node_t private: wf::cairo_text_t::params params; std::optional size; - wf::point_t position; + wf::pointf_t position; }; diff --git a/plugins/common/wayfire/plugins/common/workspace-wall.hpp b/plugins/common/wayfire/plugins/common/workspace-wall.hpp index fcdf5dc2a..d6693c9b7 100644 --- a/plugins/common/wayfire/plugins/common/workspace-wall.hpp +++ b/plugins/common/wayfire/plugins/common/workspace-wall.hpp @@ -77,7 +77,7 @@ class workspace_wall_t : public wf::signal::provider_t * @param geometry The rectangle in fb to draw to, in the same coordinate * system as the framebuffer's geometry. */ - void render_wall(const wf::render_target_t& fb, const wf::region_t& damage); + void render_wall(const wf::render_target_t& fb, const wf::regionf_t& damage); /** * Register a render hook and paint the whole output as a desktop wall diff --git a/plugins/common/workspace-wall.cpp b/plugins/common/workspace-wall.cpp index b3f583c6e..492cf9970 100644 --- a/plugins/common/workspace-wall.cpp +++ b/plugins/common/workspace-wall.cpp @@ -31,10 +31,10 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t { auto output_size = self->wall->output->get_screen_size(); return { - .x = ws.x * (output_size.width + self->wall->gap_size), - .y = ws.y * (output_size.height + self->wall->gap_size), - .width = output_size.width, - .height = output_size.height, + .x = (double)(ws.x * (output_size.width + self->wall->gap_size)), + .y = (double)(ws.y * (output_size.height + self->wall->gap_size)), + .width = (double)output_size.width, + .height = (double)output_size.height, }; } @@ -50,15 +50,15 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t { for (int j = 0; j < (int)self->workspaces[i].size(); j++) { - auto push_damage_child = [=] (const wf::region_t& damage) + auto push_damage_child = [=] (const wf::regionf_t& damage) { // Store the damage because we'll have to update the buffers self->aux_buffer_damage[i][j] |= damage; - wf::region_t our_damage; + wf::regionf_t our_damage; for (auto& rect : damage) { - wf::geometry_t box = wlr_box_from_pixman_box(rect); + wf::geometry_t box = geometry_from_pixman_box(rect); box = box + wf::origin(get_workspace_rect({i, j})); auto A = self->wall->viewport; auto B = self->get_bounding_box(); @@ -78,9 +78,9 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t } } - static int damage_sum_area(const wf::region_t& damage) + static double damage_sum_area(const wf::regionf_t& damage) { - int sum = 0; + double sum = 0; for (const auto& rect : damage) { sum += (rect.y2 - rect.y1) * (rect.x2 - rect.x1); @@ -89,7 +89,7 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t return sum; } - bool consider_rescale_workspace_buffer(int i, int j, const wf::region_t& visible_damage) + bool consider_rescale_workspace_buffer(int i, int j, const wf::regionf_t& visible_damage) { // In general, when rendering the auxilliary buffers for each workspace, we can render the // workspace thumbnails in a lower resolution, because at the end they are shown scaled. @@ -118,9 +118,9 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t // In general, it is worth changing the buffer scale if we have a lot of damage to the old // buffer, so that for ex. a full re-scale is actually cheaper than repaiting the old buffer. // This could easily happen for example if we have a video player during Expo start animation. - const int repaint_cost_current_scale = + const double repaint_cost_current_scale = damage_sum_area(visible_damage) * (current_scale * current_scale); - const int repaint_rescale_cost = (bbox.width * bbox.height) * (render_scale * render_scale); + const double repaint_rescale_cost = (bbox.width * bbox.height) * (render_scale * render_scale); if ((repaint_cost_current_scale > repaint_rescale_cost) || rescale_magnification) { @@ -131,7 +131,8 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t const int scaled_height = std::clamp(std::ceil(render_scale * full_size.height), 1.0f, 1.0f * full_size.height); - self->aux_buffer_current_subbox[i][j] = wf::geometry_t{0, 0, scaled_width, scaled_height}; + self->aux_buffer_current_subbox[i][j] = + wf::geometry_t{0.0, 0.0, (double)scaled_width, (double)scaled_height}; self->aux_buffer_damage[i][j] |= self->workspaces[i][j]->get_bounding_box(); return true; } @@ -141,7 +142,7 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { // Update workspaces in a render pass for (int i = 0; i < (int)self->workspaces.size(); i++) @@ -151,7 +152,7 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t const auto ws_bbox = self->wall->get_workspace_rectangle({i, j}); const auto visible_box = geometry_intersection(self->wall->viewport, ws_bbox) - wf::origin(ws_bbox); - wf::region_t visible_damage = self->aux_buffer_damage[i][j] & visible_box; + wf::regionf_t visible_damage = self->aux_buffer_damage[i][j] & visible_box; if (consider_rescale_workspace_buffer(i, j, visible_damage)) { visible_damage |= visible_box; @@ -225,13 +226,13 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t self->wall->render_wall(data.target, data.damage); } - void compute_visibility(wf::output_t *output, wf::region_t& visible) override + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { for (int i = 0; i < (int)self->workspaces.size(); i++) { for (int j = 0; j < (int)self->workspaces[i].size(); j++) { - wf::region_t ws_region = self->workspaces[i][j]->get_bounding_box(); + wf::regionf_t ws_region{self->workspaces[i][j]->get_bounding_box()}; for (auto& ch : this->instances[i][j]) { ch->compute_visibility(output, ws_region); @@ -300,7 +301,7 @@ class workspace_wall_t::workspace_wall_node_t : public scene::node_t // Buffers keeping the contents of almost-static workspaces per_workspace_map_t aux_buffers; // Damage accumulated for those buffers - per_workspace_map_t aux_buffer_damage; + per_workspace_map_t aux_buffer_damage; // Current rendering scale for the workspace per_workspace_map_t aux_buffer_current_scale; // Current subbox for the workspace @@ -343,7 +344,7 @@ wf::geometry_t workspace_wall_t::get_viewport() const } void workspace_wall_t::render_wall( - const wf::render_target_t& fb, const wf::region_t& damage) + const wf::render_target_t& fb, const wf::regionf_t& damage) { wall_frame_event_t data{fb}; this->emit(&data); @@ -377,8 +378,8 @@ wf::geometry_t workspace_wall_t::get_workspace_rectangle( { auto size = this->output->get_screen_size(); - return {ws.x * (size.width + gap_size), ws.y * (size.height + gap_size), - size.width, size.height}; + return {(double)(ws.x * (size.width + gap_size)), (double)(ws.y * (size.height + gap_size)), + (double)size.width, (double)size.height}; } wf::geometry_t workspace_wall_t::get_wall_rectangle() const @@ -386,9 +387,9 @@ wf::geometry_t workspace_wall_t::get_wall_rectangle() const auto size = this->output->get_screen_size(); auto workspace_size = this->output->wset()->get_workspace_grid_size(); - return {-gap_size, -gap_size, - workspace_size.width * (size.width + gap_size) + gap_size, - workspace_size.height * (size.height + gap_size) + gap_size}; + return {(double)-gap_size, (double)-gap_size, + (double)(workspace_size.width * (size.width + gap_size) + gap_size), + (double)(workspace_size.height * (size.height + gap_size) + gap_size)}; } void workspace_wall_t::set_ws_dim(const wf::point_t& ws, float value) diff --git a/plugins/cube/cube.cpp b/plugins/cube/cube.cpp index 8765e5c94..a59e8f4f4 100644 --- a/plugins/cube/cube.cpp +++ b/plugins/cube/cube.cpp @@ -47,7 +47,7 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer wf::scene::damage_callback push_damage; std::vector> ws_instances; - std::vector ws_damage; + std::vector ws_damage; std::vector framebuffers; wf::signal::connection_t on_cube_damage = @@ -68,7 +68,7 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer ws_instances.resize(self->workspaces.size()); for (int i = 0; i < (int)self->workspaces.size(); i++) { - auto push_damage_child = [=] (const wf::region_t& damage) + auto push_damage_child = [=] (const wf::regionf_t& damage) { ws_damage[i] |= damage; push_damage(self->get_bounding_box()); @@ -86,7 +86,7 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { instructions.push_back(wf::scene::render_instruction_t{ .instance = this, @@ -125,11 +125,11 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer self->cube->render(data, framebuffers); } - void compute_visibility(wf::output_t *output, wf::region_t& visible) override + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { for (int i = 0; i < (int)self->workspaces.size(); i++) { - wf::region_t ws_region = self->workspaces[i]->get_bounding_box(); + wf::regionf_t ws_region = self->workspaces[i]->get_bounding_box(); for (auto& ch : this->ws_instances[i]) { ch->compute_visibility(output, ws_region); diff --git a/plugins/decor/deco-layout.cpp b/plugins/decor/deco-layout.cpp index b008adea6..fd955c6ad 100644 --- a/plugins/decor/deco-layout.cpp +++ b/plugins/decor/deco-layout.cpp @@ -27,7 +27,7 @@ decoration_area_t::decoration_area_t(decoration_area_type_t type, wf::geometry_t * Initialize a new decoration area holding a button */ decoration_area_t::decoration_area_t(wf::geometry_t g, - std::function damage_callback, + std::function damage_callback, const decoration_theme_t& theme) { this->type = DECORATION_AREA_BUTTON; @@ -55,7 +55,7 @@ decoration_area_type_t decoration_area_t::get_type() const } decoration_layout_t::decoration_layout_t(const decoration_theme_t& th, - std::function callback) : + std::function callback) : titlebar_size(th.get_title_height()), border_size(th.get_border_size()), @@ -96,10 +96,10 @@ wf::geometry_t decoration_layout_t::create_buttons(int width, int) int per_button = 2 * button_padding + button_width; wf::geometry_t button_geometry = { - width - border_size + button_padding, /* 1 more padding initially */ - button_padding + border_size, - button_width, - button_height, + (double)(width - border_size + button_padding), /* 1 more padding initially */ + (double)(button_padding + border_size), + (double)button_width, + (double)button_height, }; for (auto type : wf::reverse(buttons)) @@ -113,8 +113,8 @@ wf::geometry_t decoration_layout_t::create_buttons(int width, int) int total_width = -button_padding + buttons.size() * per_button; return { - button_geometry.x, border_size, - total_width, titlebar_size + button_geometry.x, (double)border_size, + (double)total_width, (double)titlebar_size }; } @@ -132,34 +132,34 @@ void decoration_layout_t::resize(int width, int height) /* Titlebar dragging area (for move) */ wf::geometry_t title_geometry = { - border_size, - border_size, + (double)border_size, + (double)border_size, /* Up to the button, but subtract the padding to the left of the * title and the padding between title and button */ button_geometry_expanded.x - border_size, - titlebar_size, + (double)titlebar_size, }; this->layout_areas.push_back(std::make_unique( DECORATION_AREA_TITLE, title_geometry)); } /* Resizing edges - left */ - wf::geometry_t border_geometry = {0, 0, border_size, height}; + wf::geometry_t border_geometry = {0.0, 0.0, (double)border_size, (double)height}; this->layout_areas.push_back(std::make_unique( DECORATION_AREA_RESIZE_LEFT, border_geometry)); /* Resizing edges - right */ - border_geometry = {width - border_size, 0, border_size, height}; + border_geometry = {(double)(width - border_size), 0.0, (double)border_size, (double)height}; this->layout_areas.push_back(std::make_unique( DECORATION_AREA_RESIZE_RIGHT, border_geometry)); /* Resizing edges - top */ - border_geometry = {0, 0, width, border_size}; + border_geometry = {0.0, 0.0, (double)width, (double)border_size}; this->layout_areas.push_back(std::make_unique( DECORATION_AREA_RESIZE_TOP, border_geometry)); /* Resizing edges - bottom */ - border_geometry = {0, height - border_size, width, border_size}; + border_geometry = {0.0, (double)(height - border_size), (double)width, (double)border_size}; this->layout_areas.push_back(std::make_unique( DECORATION_AREA_RESIZE_BOTTOM, border_geometry)); } @@ -182,9 +182,9 @@ std::vector> decoration_layout_t::get_re return renderable; } -wf::region_t decoration_layout_t::calculate_region() const +wf::regionf_t decoration_layout_t::calculate_region() const { - wf::region_t r{}; + wf::regionf_t r{}; for (auto& area : layout_areas) { auto g = area->get_geometry(); @@ -197,7 +197,7 @@ wf::region_t decoration_layout_t::calculate_region() const return r; } -void decoration_layout_t::unset_hover(std::optional position) +void decoration_layout_t::unset_hover(std::optional position) { auto area = find_area_at(position); if (area && (area->get_type() == DECORATION_AREA_BUTTON)) @@ -211,7 +211,7 @@ decoration_layout_t::action_response_t decoration_layout_t::handle_motion( int x, int y) { auto previous_area = find_area_at(current_input); - auto current_area = find_area_at(wf::point_t{x, y}); + auto current_area = find_area_at(wf::pointf_t{(double)x, (double)y}); if (previous_area == current_area) { @@ -230,7 +230,7 @@ decoration_layout_t::action_response_t decoration_layout_t::handle_motion( } } - this->current_input = {x, y}; + this->current_input = wf::pointf_t{(double)x, (double)y}; update_cursor(); return {DECORATION_ACTION_NONE, 0}; @@ -271,7 +271,7 @@ decoration_layout_t::action_response_t decoration_layout_t::handle_press_event( } is_grabbed = true; - grab_origin = current_input.value_or(wf::point_t{0, 0}); + grab_origin = current_input.value_or(wf::pointf_t{0.0, 0.0}); } if (!pressed && double_click_at_release) @@ -314,7 +314,7 @@ decoration_layout_t::action_response_t decoration_layout_t::handle_press_event( * Find the layout area at the given coordinates, if any * @return The layout area or null on failure */ -nonstd::observer_ptr decoration_layout_t::find_area_at(std::optional point) +nonstd::observer_ptr decoration_layout_t::find_area_at(std::optional point) { if (!point) { diff --git a/plugins/decor/deco-layout.hpp b/plugins/decor/deco-layout.hpp index 5b3d705c3..72b1182cd 100644 --- a/plugins/decor/deco-layout.hpp +++ b/plugins/decor/deco-layout.hpp @@ -45,7 +45,7 @@ struct decoration_area_t * @param theme The theme to use for the button. */ decoration_area_t(wf::geometry_t g, - std::function damage_callback, + std::function damage_callback, const decoration_theme_t& theme); /** @return The geometry of the decoration area, relative to the layout */ @@ -99,7 +99,7 @@ class decoration_layout_t * layout needs a repaint. */ decoration_layout_t(const decoration_theme_t& theme, - std::function damage_callback); + std::function damage_callback); /** Regenerate layout using the new size */ void resize(int width, int height); @@ -111,7 +111,7 @@ class decoration_layout_t std::vector> get_renderable_areas(); /** @return The combined region of all layout areas */ - wf::region_t calculate_region() const; + wf::regionf_t calculate_region() const; struct action_response_t { @@ -145,15 +145,15 @@ class decoration_layout_t const int button_padding; const decoration_theme_t& theme; - std::function damage_callback; + std::function damage_callback; std::vector> layout_areas; bool is_grabbed = false; /* Position where the grab has started */ - wf::point_t grab_origin; + wf::pointf_t grab_origin; /* Last position of the input */ - std::optional current_input; + std::optional current_input; /* double-click timer */ wf::wl_timer timer; bool double_click_at_release = false; @@ -170,10 +170,10 @@ class decoration_layout_t * Find the layout area at the given coordinates, if any * @return The layout area or null on failure */ - nonstd::observer_ptr find_area_at(std::optional point); + nonstd::observer_ptr find_area_at(std::optional point); /** Unset hover state of hovered button at @position, if any */ - void unset_hover(std::optional position); + void unset_hover(std::optional position); wf::option_wrapper_t button_order{"decoration/button_order"}; }; } diff --git a/plugins/decor/deco-subsurface.cpp b/plugins/decor/deco-subsurface.cpp index 34c859b27..e8d8a0008 100644 --- a/plugins/decor/deco-subsurface.cpp +++ b/plugins/decor/deco-subsurface.cpp @@ -69,7 +69,7 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in public: wf::decor::decoration_theme_t theme; wf::decor::decoration_layout_t layout; - wf::region_t cached_region; + wf::regionf_t cached_region; wf::dimensions_t size; @@ -79,7 +79,10 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in simple_decoration_node_t(wayfire_toplevel_view view) : node_t(false), theme{}, - layout{theme, [=] (wlr_box box) { wf::scene::damage_node(shared_from_this(), box + get_offset()); }} + layout{theme, [=] (wf::geometry_t box) + { + wf::scene::damage_node(shared_from_this(), box + get_offset()); + }} { this->_view = view->weak_from_this(); view->connect(&title_set); @@ -97,16 +100,17 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in update_decoration_size(); } - wf::point_t get_offset() + wf::pointf_t get_offset() { - return {-current_thickness, -current_titlebar}; + return {(double)-current_thickness, (double)-current_titlebar}; } void render(const wf::scene::render_instruction_t& data) { auto origin = get_offset(); /* Clear background */ - wlr_box geometry{origin.x, origin.y, size.width, size.height}; + wf::geometry_t geometry{origin.x, origin.y, + (double)size.width, (double)size.height}; bool activated = false; if (auto view = _view.lock()) @@ -140,7 +144,7 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in { if (auto view = _view.lock()) { - wf::pointf_t local = at - wf::pointf_t{get_offset()}; + wf::pointf_t local = at - get_offset(); if (cached_region.contains_pointf(local) && view->is_mapped()) { return wf::scene::input_node_t{ @@ -183,10 +187,10 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in } void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { - auto our_region = self->cached_region + self->get_offset(); - wf::region_t our_damage = damage & our_region; + auto our_region = self->get_bounding_box(); + wf::regionf_t our_damage = damage & our_region; if (!our_damage.empty()) { instructions.push_back(wf::scene::render_instruction_t{ @@ -217,7 +221,7 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in /* wf::compositor_surface_t implementation */ void handle_pointer_enter(wf::pointf_t point) override { - point -= wf::pointf_t{get_offset()}; + point -= get_offset(); layout.handle_motion(point.x, point.y); } @@ -228,7 +232,7 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in void handle_pointer_motion(wf::pointf_t to, uint32_t) override { - to -= wf::pointf_t{get_offset()}; + to -= get_offset(); handle_action(layout.handle_motion(to.x, to.y)); } @@ -292,7 +296,7 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in void handle_touch_motion(uint32_t time_ms, int finger_id, wf::pointf_t position) override { - position -= wf::pointf_t{get_offset()}; + position -= get_offset(); handle_action(layout.handle_motion(position.x, position.y)); } diff --git a/plugins/grid/grid.cpp b/plugins/grid/grid.cpp index 5b00c592e..57c42de58 100644 --- a/plugins/grid/grid.cpp +++ b/plugins/grid/grid.cpp @@ -153,7 +153,8 @@ class wayfire_grid : public wf::plugin_interface_t, public wf::per_output_tracke if (slot.preview) { auto input = ev->input; - slot.preview->set_target_geometry({input.x, input.y, 1, 1}, 0, true); + slot.preview->set_target_geometry(wf::pointf_t{(double)input.x, (double)input.y}, 0, + true); slot.preview = nullptr; } @@ -171,7 +172,7 @@ class wayfire_grid : public wf::plugin_interface_t, public wf::per_output_tracke auto input = ev->input; slot.preview = std::make_shared( - wf::geometry_t{input.x, input.y, 1, 1}, ev->output, "move"); + wf::pointf_t{(double)input.x, (double)input.y}, ev->output, "move"); slot.preview->set_target_geometry(slot_geometry, 1); } }; @@ -201,7 +202,7 @@ class wayfire_grid : public wf::plugin_interface_t, public wf::per_output_tracke return is_floating && (view->get_output() != nullptr) && view->toplevel()->pending().mapped; } - void handle_slot(wayfire_toplevel_view view, int slot, wf::point_t delta = {0, 0}) + void handle_slot(wayfire_toplevel_view view, int slot, wf::pointf_t delta = {0, 0}) { if (!can_adjust_view(view)) { diff --git a/plugins/grid/wayfire/plugins/crossfade.hpp b/plugins/grid/wayfire/plugins/crossfade.hpp index 466985112..3c86fe45d 100644 --- a/plugins/grid/wayfire/plugins/crossfade.hpp +++ b/plugins/grid/wayfire/plugins/crossfade.hpp @@ -113,7 +113,7 @@ class crossfade_render_instance_t : public scene::render_instance_t scene::damage_callback push_damage) { this->self = std::dynamic_pointer_cast(self->shared_from_this()); - scene::damage_callback push_damage_child = [=] (const wf::region_t&) + scene::damage_callback push_damage_child = [=] (const wf::regionf_t&) { // XXX: we could attempt to calculate a meaningful damage, but // we update on each frame anyway so .. @@ -129,7 +129,7 @@ class crossfade_render_instance_t : public scene::render_instance_t void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { instructions.push_back(wf::scene::render_instruction_t{ .instance = this, diff --git a/plugins/ipc-rules/ipc-rules-common.hpp b/plugins/ipc-rules/ipc-rules-common.hpp index 90ec5866d..28ff0baa7 100644 --- a/plugins/ipc-rules/ipc-rules-common.hpp +++ b/plugins/ipc-rules/ipc-rules-common.hpp @@ -186,8 +186,9 @@ static inline wf::json_t view_to_json(wayfire_view view) auto toplevel = wf::toplevel_cast(view); description["parent"] = toplevel && toplevel->parent ? (int)toplevel->parent->get_id() : -1; description["geometry"] = - wf::ipc::geometry_to_json(toplevel ? toplevel->get_pending_geometry() : view->get_bounding_box()); - description["bbox"] = wf::ipc::geometry_to_json(view->get_bounding_box()); + wf::ipc::geometry_to_json(toplevel ? toplevel->get_pending_geometry() : + wf::from_framebuffer_box(view->get_bounding_box())); + description["bbox"] = wf::ipc::geometry_to_json(wf::from_framebuffer_box(view->get_bounding_box())); description["output-id"] = view->get_output() ? view->get_output()->get_id() : -1; description["output-name"] = output ? output->to_string() : "null"; description["last-focus-timestamp"] = wf::get_focus_timestamp(view); diff --git a/plugins/ipc/stipc.cpp b/plugins/ipc/stipc.cpp index f9159a8e0..5a95eca01 100644 --- a/plugins/ipc/stipc.cpp +++ b/plugins/ipc/stipc.cpp @@ -361,7 +361,12 @@ class stipc_plugin_t : public wf::plugin_interface_t move_view_to_output(toplevel, wo, false); } - wf::geometry_t g{x, y, width, height}; + wf::geometry_t g{ + (double)x, + (double)y, + (double)width, + (double)height, + }; toplevel->set_geometry(g); } diff --git a/plugins/protocols/wayfire-shell.cpp b/plugins/protocols/wayfire-shell.cpp index ee8f38710..8e1ee40da 100644 --- a/plugins/protocols/wayfire-shell.cpp +++ b/plugins/protocols/wayfire-shell.cpp @@ -40,9 +40,7 @@ class wfs_hotspot { idle_check_input.run_once([=] () { - auto gcf = wf::get_core().get_cursor_position(); - wf::point_t gc{(int)gcf.x, (int)gcf.y}; - process_input_motion(gc); + process_input_motion(wf::get_core().get_cursor_position()); }); }; @@ -51,9 +49,7 @@ class wfs_hotspot { idle_check_input.run_once([=] () { - auto gcf = wf::get_core().get_cursor_position(); - wf::point_t gc{(int)gcf.x, (int)gcf.y}; - process_input_motion(gc); + process_input_motion(wf::get_core().get_cursor_position()); }); }; @@ -61,15 +57,13 @@ class wfs_hotspot { idle_check_input.run_once([=] () { - auto gcf = wf::get_core().get_touch_position(0); - wf::point_t gc{(int)gcf.x, (int)gcf.y}; - process_input_motion(gc); + process_input_motion(wf::get_core().get_touch_position(0)); }); }; wf::signal::connection_t on_output_removed; - void process_input_motion(wf::point_t gc) + void process_input_motion(wf::pointf_t gc) { if (!(hotspot_geometry & gc)) { @@ -155,8 +149,8 @@ class wfs_hotspot if (ev->output == output) { /* Make hotspot inactive by setting the region to empty */ - hotspot_geometry = {0, 0, 0, 0}; - process_input_motion({0, 0}); + hotspot_geometry = {0.0, 0.0, 0.0, 0.0}; + process_input_motion({0.0, 0.0}); } }); diff --git a/plugins/scale/scale-title-filter.cpp b/plugins/scale/scale-title-filter.cpp index 70dd9dd71..82df2dc93 100644 --- a/plugins/scale/scale-title-filter.cpp +++ b/plugins/scale/scale-title-filter.cpp @@ -336,10 +336,10 @@ class scale_title_filter : public wf::per_output_plugin_instance_t } wf::geometry_t geometry{ - dim.width / 2 - (int)(overlay_size.width / output_scale / 2), - dim.height / 2 - (int)(overlay_size.height / output_scale / 2), - (int)(overlay_size.width / output_scale), - (int)(overlay_size.height / output_scale) + (double)(dim.width / 2 - (int)(overlay_size.width / output_scale / 2)), + (double)(dim.height / 2 - (int)(overlay_size.height / output_scale / 2)), + (double)(int)(overlay_size.width / output_scale), + (double)(int)(overlay_size.height / output_scale) }; tex->set_source_box(wlr_fbox{ diff --git a/plugins/scale/scale-title-overlay.cpp b/plugins/scale/scale-title-overlay.cpp index 6a325c28d..9ae2d0f76 100644 --- a/plugins/scale/scale-title-overlay.cpp +++ b/plugins/scale/scale-title-overlay.cpp @@ -119,7 +119,7 @@ class title_overlay_node_t : public node_t return get_bbox_for_node(tr, wm_geometry); } - return v->get_bounding_box(); + return wf::from_framebuffer_box(v->get_bounding_box()); } wf::dimensions_t find_maximal_title_size() @@ -135,8 +135,8 @@ class title_overlay_node_t : public node_t } auto bbox = get_scaled_bbox(v); - max_size.width = std::max(max_size.width, bbox.width); - max_size.height = std::max(max_size.height, bbox.height); + max_size.width = std::max(max_size.width, (int)std::ceil(bbox.width)); + max_size.height = std::max(max_size.height, (int)std::ceil(bbox.height)); } return max_size; @@ -263,7 +263,7 @@ class title_overlay_node_t : public node_t std::vector& instances, damage_callback push_damage, wf::output_t *output) override; - void do_push_damage(wf::region_t updated_region) + void do_push_damage(wf::regionf_t updated_region) { node_damage_signal ev; ev.region = updated_region; @@ -302,7 +302,7 @@ class title_overlay_render_instance_t : public render_instance_t } void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { if (!self->overlay_shown || !self->view->has_data()) { diff --git a/plugins/scale/scale.cpp b/plugins/scale/scale.cpp index 2795a1e4b..ba49037c7 100644 --- a/plugins/scale/scale.cpp +++ b/plugins/scale/scale.cpp @@ -3,6 +3,7 @@ */ #include #include +#include #include #include #include @@ -509,8 +510,7 @@ class wayfire_scale : public wf::per_output_plugin_instance_t, void handle_pointer_motion(wf::pointf_t to_f, uint32_t time) override { - wf::point_t to{(int)std::round(to_f.x), (int)std::round(to_f.y)}; - if (!drag_helper->view && last_selected_view && drag_helper->should_start_pending_drag(to)) + if (!drag_helper->view && last_selected_view && drag_helper->should_start_pending_drag(to_f)) { wf::move_drag::drag_options_t opts; opts.join_views = true; @@ -521,14 +521,14 @@ class wayfire_scale : public wf::per_output_plugin_instance_t, // another output. grab->set_wants_raw_input(true); drag_helper->start_drag(last_selected_view, opts); - drag_helper->handle_motion(to); + drag_helper->handle_motion(to_f); } else if (drag_helper->view) { - drag_helper->handle_motion(to); + drag_helper->handle_motion(to_f); if (last_selected_view) { const double threshold = 20.0; - if (drag_helper->distance_to_grab_origin(to) > threshold) + if (drag_helper->distance_to_grab_origin(to_f) > threshold) { last_selected_view = nullptr; } @@ -540,14 +540,13 @@ class wayfire_scale : public wf::per_output_plugin_instance_t, wf::point_t get_view_main_workspace(wayfire_toplevel_view view) { view = wf::find_topmost_parent(view); - auto ws = output->wset()->get_current_workspace(); - auto og = output->get_layout_geometry(); - auto vg = view->get_geometry(); - auto center = wf::point_t{vg.x + vg.width / 2, vg.y + vg.height / 2}; + auto ws = output->wset()->get_current_workspace(); + auto og = output->get_layout_geometry(); + auto vg = view->get_geometry(); return wf::point_t{ - ws.x + (int)std::floor((double)center.x / og.width), - ws.y + (int)std::floor((double)center.y / og.height)}; + ws.x + (int)std::floor((vg.x + vg.width / 2.0) / og.width), + ws.y + (int)std::floor((vg.y + vg.height / 2.0) / og.height)}; } /* Given row and column, return a view at this position in the scale grid, @@ -738,10 +737,9 @@ class wayfire_scale : public wf::per_output_plugin_instance_t, { auto vg = view->get_geometry(); auto og = output->get_relative_geometry(); - wf::region_t wr{og}; - wf::point_t center{vg.x + vg.width / 2, vg.y + vg.height / 2}; + wf::pointf_t center{vg.x + vg.width / 2, vg.y + vg.height / 2}; - if (wr.contains_point(center)) + if (og & center) { views.push_back(view); } @@ -803,18 +801,38 @@ class wayfire_scale : public wf::per_output_plugin_instance_t, static bool view_compare_x(const wayfire_toplevel_view& a, const wayfire_toplevel_view& b) { auto vg_a = a->get_geometry(); - std::vector a_coords = {vg_a.x, vg_a.width, vg_a.y, vg_a.height}; + std::array a_coords = { + vg_a.x, + vg_a.width, + vg_a.y, + vg_a.height, + }; auto vg_b = b->get_geometry(); - std::vector b_coords = {vg_b.x, vg_b.width, vg_b.y, vg_b.height}; + std::array b_coords = { + vg_b.x, + vg_b.width, + vg_b.y, + vg_b.height, + }; return a_coords < b_coords; } static bool view_compare_y(const wayfire_toplevel_view& a, const wayfire_toplevel_view& b) { auto vg_a = a->get_geometry(); - std::vector a_coords = {vg_a.y, vg_a.height, vg_a.x, vg_a.width}; + std::array a_coords = { + vg_a.y, + vg_a.height, + vg_a.x, + vg_a.width, + }; auto vg_b = b->get_geometry(); - std::vector b_coords = {vg_b.y, vg_b.height, vg_b.x, vg_b.width}; + std::array b_coords = { + vg_b.y, + vg_b.height, + vg_b.x, + vg_b.width, + }; return a_coords < b_coords; } @@ -977,7 +995,10 @@ class wayfire_scale : public wf::per_output_plugin_instance_t, add_transformer(view); auto geom = view->get_geometry(); - double view_scale = calculate_scale({geom.width, geom.height}); + double view_scale = calculate_scale({ + (int32_t)std::floor(geom.width), + (int32_t)std::floor(geom.height), + }); for (auto& child : view->enumerate_views(true)) { // Ensure a transformer for the view, and make sure that @@ -1017,7 +1038,10 @@ class wayfire_scale : public wf::per_output_plugin_instance_t, wf::pointf_t center = {vg.x + vg.width / 2.0, vg.y + vg.height / 2.0}; // Take padding into account - double scale = calculate_scale({vg.width, vg.height}); + double scale = calculate_scale({ + (int32_t)std::floor(vg.width), + (int32_t)std::floor(vg.height), + }); // Ensure child is not scaled more than parent if (!allow_scale_zoom && (child != view) && diff --git a/plugins/single_plugins/expo.cpp b/plugins/single_plugins/expo.cpp index 9fc869dd2..7fecb3469 100644 --- a/plugins/single_plugins/expo.cpp +++ b/plugins/single_plugins/expo.cpp @@ -160,7 +160,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar void handle_pointer_motion(wf::pointf_t pointer_position, uint32_t time_ms) override { - handle_input_move({(int)pointer_position.x, (int)pointer_position.y}); + handle_input_move(pointer_position); } void handle_keyboard_key(wf::seat_t*, wlr_keyboard_key_event event) override @@ -209,7 +209,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar return; } - handle_input_move({(int)position.x, (int)position.y}); + handle_input_move(position); } bool can_handle_drag() @@ -419,7 +419,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar } } - void start_moving(wayfire_toplevel_view view, wf::point_t local_grab) + void start_moving(wayfire_toplevel_view view, wf::pointf_t local_grab) { if (!(view->get_allowed_actions() & (wf::VIEW_ALLOW_WS_CHANGE | wf::VIEW_ALLOW_MOVE))) { @@ -447,7 +447,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar } const wf::point_t offscreen_point = {-10, -10}; - void handle_input_move(wf::point_t to) + void handle_input_move(wf::pointf_t to) { if (!state.button_pressed) { @@ -605,7 +605,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar * Find the coordinate of the given point from output-local coordinates * to coordinates relative to the first workspace (i.e (0,0)) */ - void input_coordinates_to_global_coordinates(int & sx, int & sy) + void input_coordinates_to_global_coordinates(double& sx, double& sy) { auto og = output->get_layout_geometry(); @@ -626,7 +626,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar * Find the coordinate of the given point from output-local coordinates * to output-workspace-local coordinates */ - wf::point_t input_coordinates_to_output_local_coordinates(wf::point_t ip) + wf::pointf_t input_coordinates_to_output_local_coordinates(wf::pointf_t ip) { input_coordinates_to_global_coordinates(ip.x, ip.y); @@ -643,9 +643,8 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar wayfire_toplevel_view find_view_at_coordinates(int gx, int gy) { - auto local = input_coordinates_to_output_local_coordinates({gx, gy}); - wf::pointf_t localf = {1.0 * local.x, 1.0 * local.y}; - auto view = wf::find_output_view_at(output, localf); + auto local = input_coordinates_to_output_local_coordinates({(double)gx, (double)gy}); + auto view = wf::find_output_view_at(output, local); if (view && view->is_mapped()) { return view; @@ -659,7 +658,7 @@ class wayfire_expo : public wf::per_output_plugin_instance_t, public wf::keyboar { wlr_box box = {x, y, 1, 1}; auto og = output->get_relative_geometry(); - auto in_grid = wf::origin(wf::scale_box(og, wall->get_viewport(), box)); + auto in_grid = wf::origin(wf::scale_box(og, wall->get_viewport(), wf::from_framebuffer_box(box))); auto grid = output->wset()->get_workspace_grid_size(); for (int i = 0; i < grid.width; i++) diff --git a/plugins/single_plugins/move.cpp b/plugins/single_plugins/move.cpp index 9bb9e673d..486cb19cb 100644 --- a/plugins/single_plugins/move.cpp +++ b/plugins/single_plugins/move.cpp @@ -145,7 +145,7 @@ class wayfire_move : public wf::per_output_plugin_instance_t, // move. // // We do the same for touch events. - wf::point_t last_input_press_position = {0, 0}; + wf::pointf_t last_input_press_position = {0, 0}; wf::signal::connection_t> on_raw_pointer_button = [=] (wf::input_event_signal *ev) { @@ -311,10 +311,10 @@ class wayfire_move : public wf::per_output_plugin_instance_t, return true; } - bool initiate(wayfire_toplevel_view view, wf::point_t grab_position) + bool initiate(wayfire_toplevel_view view, wf::pointf_t grab_position) { // First, make sure that the view is on the output the input is. - auto target_output = wf::get_core().output_layout->find_closest_output(wf::pointf_t{grab_position}); + auto target_output = wf::get_core().output_layout->find_closest_output(grab_position); if (target_output && (view->get_output() != target_output)) { auto parent = wf::find_topmost_parent(view); @@ -428,7 +428,7 @@ class wayfire_move : public wf::per_output_plugin_instance_t, wf::point_t tws = {cws.x + dx, cws.y + dy}; wf::dimensions_t ws_dim = output->wset()->get_workspace_grid_size(); wf::geometry_t possible = { - 0, 0, ws_dim.width, ws_dim.height + 0.0, 0.0, (double)ws_dim.width, (double)ws_dim.height }; /* Outside of workspace grid */ @@ -481,7 +481,8 @@ class wayfire_move : public wf::per_output_plugin_instance_t, if (slot.preview) { - slot.preview->set_target_geometry({input.x, input.y, 1, 1}, 0, true); + slot.preview->set_target_geometry(wf::pointf_t{(double)input.x, (double)input.y}, 0, + true); slot.preview = nullptr; } @@ -492,7 +493,7 @@ class wayfire_move : public wf::per_output_plugin_instance_t, if ((slot_geometry.width > 0) || (slot_geometry.height > 0)) { slot.preview = std::make_shared( - wf::geometry_t{input.x, input.y, 1, 1}, output, "move"); + wf::pointf_t{(double)input.x, (double)input.y}, output, "move"); slot.preview->set_target_geometry(slot_geometry, 1); } } @@ -501,7 +502,7 @@ class wayfire_move : public wf::per_output_plugin_instance_t, } /* Returns the currently used input coordinates in global compositor space */ - wf::point_t get_global_input_coords() + wf::pointf_t get_global_input_coords() { wf::pointf_t input; if (wf::get_core().get_touch_state().fingers.empty()) @@ -513,15 +514,15 @@ class wayfire_move : public wf::per_output_plugin_instance_t, input = {center.x, center.y}; } - return {(int)input.x, (int)input.y}; + return input; } /* Returns the currently used input coordinates in output-local space */ wf::point_t get_input_coords() { auto og = output->get_layout_geometry(); - auto coords = get_global_input_coords() - wf::point_t{og.x, og.y}; - return coords; + auto coords = get_global_input_coords() - wf::origin(og); + return {(int)std::floor(coords.x), (int)std::floor(coords.y)}; } bool is_snap_enabled() diff --git a/plugins/single_plugins/oswitch.cpp b/plugins/single_plugins/oswitch.cpp index 4bf539c4d..5c9fa7933 100644 --- a/plugins/single_plugins/oswitch.cpp +++ b/plugins/single_plugins/oswitch.cpp @@ -62,9 +62,9 @@ class wayfire_oswitch : public wf::plugin_interface_t } auto current_geo = current_output->get_layout_geometry(); - wf::point_t current_center = { - current_geo.x + current_geo.width / 2, - current_geo.y + current_geo.height / 2 + wf::pointf_t current_center = { + current_geo.x + current_geo.width / 2.0, + current_geo.y + current_geo.height / 2.0 }; wf::output_t *best_output = nullptr; @@ -80,9 +80,9 @@ class wayfire_oswitch : public wf::plugin_interface_t } auto geo = output->get_layout_geometry(); - wf::point_t center = { - geo.x + geo.width / 2, - geo.y + geo.height / 2 + wf::pointf_t center = { + geo.x + geo.width / 2.0, + geo.y + geo.height / 2.0 }; double dx = center.x - current_center.x; diff --git a/plugins/single_plugins/place.cpp b/plugins/single_plugins/place.cpp index 558204440..92fccf9ca 100644 --- a/plugins/single_plugins/place.cpp +++ b/plugins/single_plugins/place.cpp @@ -151,8 +151,10 @@ class wayfire_place_window : public wf::plugin_interface_t return; } - view->toplevel()->pending().geometry.x = rand() % area.width + area.x; - view->toplevel()->pending().geometry.y = rand() % area.height + area.y; + view->toplevel()->pending().geometry.x = area.x + + (rand() % std::max(1, (int)std::ceil(area.width))); + view->toplevel()->pending().geometry.y = area.y + + (rand() % std::max(1, (int)std::ceil(area.height))); } void center(wayfire_toplevel_view & view, wf::geometry_t workarea) @@ -170,11 +172,11 @@ class wayfire_place_window : public wf::plugin_interface_t return; } - wf::point_t pos = output->get_cursor_position().round_down(); + wf::pointf_t pos = output->get_cursor_position(); wf::geometry_t window = view->get_pending_geometry(); - window.x = workarea.x + std::clamp(pos.x - window.width / 2, + window.x = workarea.x + wf::clamp(pos.x - window.width / 2, 0, workarea.width - window.width); - window.y = workarea.y + std::clamp(pos.y - window.height / 2, + window.y = workarea.y + wf::clamp(pos.y - window.height / 2, 0, workarea.height - window.height); view->toplevel()->pending().geometry.x = window.x; view->toplevel()->pending().geometry.y = window.y; diff --git a/plugins/single_plugins/resize.cpp b/plugins/single_plugins/resize.cpp index 5d29fcc7d..3acc79762 100644 --- a/plugins/single_plugins/resize.cpp +++ b/plugins/single_plugins/resize.cpp @@ -57,7 +57,7 @@ class wayfire_resize : public wf::per_output_plugin_instance_t, public wf::point bool was_client_request, is_using_touch; bool preserve_aspect = false; - wf::point_t grab_start; + wf::pointf_t grab_start; wf::geometry_t grabbed_geometry; uint32_t edges; @@ -152,7 +152,7 @@ class wayfire_resize : public wf::per_output_plugin_instance_t, public wf::point } /* Returns the currently used input coordinates in global compositor space */ - wf::point_t get_global_input_coords() + wf::pointf_t get_global_input_coords() { wf::pointf_t input; if (is_using_touch) @@ -163,20 +163,21 @@ class wayfire_resize : public wf::per_output_plugin_instance_t, public wf::point input = wf::get_core().get_cursor_position(); } - return {(int)input.x, (int)input.y}; + return input; } /* Returns the currently used input coordinates in output-local space */ - wf::point_t get_input_coords() + wf::pointf_t get_input_coords() { auto og = output->get_layout_geometry(); - - return get_global_input_coords() - wf::point_t{og.x, og.y}; + return get_global_input_coords() - wf::origin(og); } /* Calculate resize edges, grab starts at (sx, sy), view's geometry is vg */ - uint32_t calculate_edges(wf::geometry_t vg, int sx, int sy) + uint32_t calculate_edges(wf::geometry_t vg, wf::pointf_t input) { + int sx = (int)input.x; + int sy = (int)input.y; int view_x = sx - vg.x; int view_y = sy - vg.y; @@ -208,8 +209,8 @@ class wayfire_resize : public wf::per_output_plugin_instance_t, public wf::point return false; } - this->edges = forced_edges ?: calculate_edges(view->get_bounding_box(), - get_input_coords().x, get_input_coords().y); + this->edges = forced_edges ?: calculate_edges( + wf::from_framebuffer_box(view->get_bounding_box()), get_input_coords()); if ((edges == 0) || !(view->get_allowed_actions() & wf::VIEW_ALLOW_RESIZE)) { @@ -367,8 +368,8 @@ class wayfire_resize : public wf::per_output_plugin_instance_t, public wf::point void input_motion() { auto input = get_input_coords(); - int dx = input.x - grab_start.x; - int dy = input.y - grab_start.y; + int dx = (int)input.x - (int)grab_start.x; + int dy = (int)input.y - (int)grab_start.y; wf::geometry_t desired = grabbed_geometry; double ratio = 1.0; @@ -426,8 +427,8 @@ class wayfire_resize : public wf::per_output_plugin_instance_t, public wf::point } } else { - desired.width = std::clamp(desired.width, min_size.width, max_size.width); - desired.height = std::clamp(desired.height, min_size.height, max_size.height); + desired.width = wf::clamp(desired.width, min_size.width, max_size.width); + desired.height = wf::clamp(desired.height, min_size.height, max_size.height); } // If we had to change the size due to ratio/min/max constraints, make sure to keep the gravity diff --git a/plugins/single_plugins/switcher.cpp b/plugins/single_plugins/switcher.cpp index 0459b01d0..0a8b85524 100644 --- a/plugins/single_plugins/switcher.cpp +++ b/plugins/single_plugins/switcher.cpp @@ -147,7 +147,7 @@ class WayfireSwitcher : public wf::per_output_plugin_instance_t, public wf::keyb void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { instructions.push_back(wf::scene::render_instruction_t{ .instance = this, diff --git a/plugins/single_plugins/vswipe.cpp b/plugins/single_plugins/vswipe.cpp index 9998cf6be..a4d59b1cf 100644 --- a/plugins/single_plugins/vswipe.cpp +++ b/plugins/single_plugins/vswipe.cpp @@ -34,9 +34,9 @@ static inline wf::geometry_t interpolate(wf::geometry_t a, wf::geometry_t b, double xalpha, double yalpha) { const auto& interp = - [=] (int32_t wf::geometry_t::*member, double alpha) -> int32_t + [=] (double wf::geometry_t::*member, double alpha) -> double { - return std::round((1 - alpha) * a.*member + alpha * b.*member); + return (1 - alpha) * a.*member + alpha * b.*member; }; return { diff --git a/plugins/single_plugins/zoom.cpp b/plugins/single_plugins/zoom.cpp index 20107fb56..7d161c4b1 100644 --- a/plugins/single_plugins/zoom.cpp +++ b/plugins/single_plugins/zoom.cpp @@ -80,7 +80,7 @@ class wayfire_zoom_screen : public wf::per_output_plugin_instance_t auto oc = output->get_cursor_position(); double x, y; - wlr_box b = output->get_relative_geometry(); + wlr_box b = wf::to_framebuffer_box(output->get_relative_geometry()); wlr_box_closest_point(&b, oc.x, oc.y, &x, &y); /* get rotation & scale */ @@ -99,7 +99,7 @@ class wayfire_zoom_screen : public wf::per_output_plugin_instance_t const float th = std::clamp(h / factor, 0.0f, h - y1); auto filter_mode = (interpolation_method == (int)interpolation_method_t::NEAREST) ? WLR_SCALE_FILTER_NEAREST : WLR_SCALE_FILTER_BILINEAR; - destination.blit(source, {x1, y1, tw, th}, {0, 0, w, h}, filter_mode); + destination.blit(source, {x1, y1, tw, th}, {0.0, 0.0, (double)w, (double)h}, filter_mode); if (!progression.running() && (progression - 1 <= 0.01)) { unset_hook(); diff --git a/plugins/tile/tile-dragging.hpp b/plugins/tile/tile-dragging.hpp index 130f7a5ee..8f8d2aa37 100644 --- a/plugins/tile/tile-dragging.hpp +++ b/plugins/tile/tile-dragging.hpp @@ -95,7 +95,7 @@ class drag_manager_t if (this->preview) { auto target = preview->get_output() ? - preview->get_output()->get_cursor_position().round_down() : wf::point_t{0, 0}; + preview->get_output()->get_cursor_position() : wf::pointf_t{0.0, 0.0}; this->preview->set_target_geometry(target, 0.0, true); this->preview.reset(); } @@ -119,7 +119,8 @@ class drag_manager_t if (!this->preview) { auto start_coords = get_wset_local_coordinates(output->wset(), input); - preview = std::make_shared(start_coords, output, "simple-tile"); + preview = std::make_shared( + start_coords, output, "simple-tile"); } auto preview_geometry = calculate_split_preview(view, split); @@ -319,7 +320,7 @@ class drag_manager_t * for INSERT_NONE */ static split_insertion_t calculate_insert_type( - nonstd::observer_ptr node, wf::point_t input, double sensitivity) + nonstd::observer_ptr node, wf::pointf_t input, double sensitivity) { auto window = node->geometry; @@ -369,7 +370,7 @@ class drag_manager_t * dropped at @input over @node */ split_insertion_t calculate_insert_type( - nonstd::observer_ptr node, wf::point_t input) + nonstd::observer_ptr node, wf::pointf_t input) { return calculate_insert_type(node, input, SPLIT_PREVIEW_PERCENTAGE); } @@ -409,7 +410,7 @@ class drag_manager_t /** * Return the node under the input which is suitable for dropping on. */ - nonstd::observer_ptr check_drop_destination(wf::output_t *output, wf::point_t global_coords, + nonstd::observer_ptr check_drop_destination(wf::output_t *output, wf::pointf_t global_coords, wayfire_toplevel_view dragged_view) { auto ws = output->wset()->get_current_workspace(); diff --git a/plugins/tile/tile-ipc.hpp b/plugins/tile/tile-ipc.hpp index 615ea3d00..9b592d99c 100644 --- a/plugins/tile/tile-ipc.hpp +++ b/plugins/tile/tile-ipc.hpp @@ -23,7 +23,7 @@ struct json_builder_data_t * Get a json description of the given tiling tree. */ inline wf::json_t tree_to_json(const std::unique_ptr& root, - const wf::point_t& offset, + const wf::pointf_t& offset, double rel_size = 1.0) { wf::json_t js; @@ -266,7 +266,10 @@ inline wf::json_t handle_ipc_get_layout(const json_t& params) auto cur_ws = ws->get_current_workspace(); auto resolution = ws->get_last_output_geometry().value_or(tile::default_output_resolution); - wf::point_t offset = {cur_ws.x * resolution.width, cur_ws.y * resolution.height}; + wf::pointf_t offset = { + (double)(cur_ws.x * resolution.width), + (double)(cur_ws.y * resolution.height), + }; response["layout"] = tree_to_json(tile_workspace_set_data_t::get(ws->shared_from_this()).roots[x][y], offset); diff --git a/plugins/tile/tree-controller.cpp b/plugins/tile/tree-controller.cpp index 096643dd5..4c26a3ca4 100644 --- a/plugins/tile/tree-controller.cpp +++ b/plugins/tile/tree-controller.cpp @@ -32,7 +32,7 @@ void for_each_view(nonstd::observer_ptr root, } nonstd::observer_ptr find_view_at( - nonstd::observer_ptr root, wf::point_t input) + nonstd::observer_ptr root, wf::pointf_t input) { if (root->as_view_node()) { @@ -58,34 +58,34 @@ nonstd::observer_ptr find_first_view_in_direction( /* Since nodes are arranged tightly into a grid, we can just find the * proper edge and find the view there */ - wf::point_t point; + wf::pointf_t point; switch (direction) { case INSERT_ABOVE: point = { - window.x + window.width / 2, - window.y - 1, + window.x + window.width / 2.0, + window.y - 1.0, }; break; case INSERT_BELOW: point = { - window.x + window.width / 2, + window.x + window.width / 2.0, window.y + window.height, }; break; case INSERT_LEFT: point = { - window.x - 1, - window.y + window.height / 2, + window.x - 1.0, + window.y + window.height / 2.0, }; break; case INSERT_RIGHT: point = { window.x + window.width, - window.y + window.height / 2, + window.y + window.height / 2.0, }; break; @@ -127,7 +127,7 @@ move_view_controller_t::~move_view_controller_t() void move_view_controller_t::input_motion() { - drag_helper->handle_motion(wf::get_core().get_cursor_position().round_down()); + drag_helper->handle_motion(wf::get_core().get_cursor_position()); } void move_view_controller_t::input_released(bool force_stop) @@ -137,7 +137,7 @@ void move_view_controller_t::input_released(bool force_stop) wf::geometry_t eval(nonstd::observer_ptr node) { - return node ? node->geometry : wf::geometry_t{0, 0, 0, 0}; + return node ? node->geometry : wf::geometry_t{0.0, 0.0, 0.0, 0.0}; } /* ----------------------- resize tile controller --------------------------- */ @@ -158,7 +158,7 @@ resize_view_controller_t::resize_view_controller_t(wf::workspace_set_t *wset, wa resize_view_controller_t::~resize_view_controller_t() {} -uint32_t resize_view_controller_t::calculate_resizing_edges(wf::point_t grab) +uint32_t resize_view_controller_t::calculate_resizing_edges(wf::pointf_t grab) { uint32_t result_edges = 0; auto window = this->grabbed_view->geometry; @@ -268,8 +268,8 @@ resize_view_controller_t::resizing_pair_t resize_view_controller_t::find_resizin return result_pair; } -void resize_view_controller_t::adjust_geometry(int32_t& x1, int32_t& len1, - int32_t& x2, int32_t& len2, int32_t delta) +void resize_view_controller_t::adjust_geometry(double& x1, double& len1, + double& x2, double& len2, double delta) { /* * On the line: @@ -277,10 +277,10 @@ void resize_view_controller_t::adjust_geometry(int32_t& x1, int32_t& len1, * x1 (x1+len1)=x2 x2+len2-1 * ._______________.___________________. */ - constexpr int MIN_SIZE = 50; + constexpr double MIN_SIZE = 50; - int maxPositive = std::max(0, len2 - MIN_SIZE); - int maxNegative = std::max(0, len1 - MIN_SIZE); + double maxPositive = std::max(0.0, len2 - MIN_SIZE); + double maxNegative = std::max(0.0, len1 - MIN_SIZE); /* Make sure we don't shrink one dimension too much */ delta = clamp(delta, -maxNegative, maxPositive); @@ -302,7 +302,7 @@ void resize_view_controller_t::input_motion() auto tx = wf::txn::transaction_t::create(); if (horizontal_pair.first && horizontal_pair.second) { - int dy = input.y - last_point.y; + double dy = input.y - last_point.y; auto g1 = horizontal_pair.first->geometry; auto g2 = horizontal_pair.second->geometry; @@ -314,7 +314,7 @@ void resize_view_controller_t::input_motion() if (vertical_pair.first && vertical_pair.second) { - int dx = input.x - last_point.x; + double dx = input.x - last_point.x; auto g1 = vertical_pair.first->geometry; auto g2 = vertical_pair.second->geometry; @@ -328,7 +328,7 @@ void resize_view_controller_t::input_motion() this->last_point = input; } -wf::point_t get_global_input_coordinates(wf::output_t *output) +wf::pointf_t get_global_input_coordinates(wf::output_t *output) { wf::pointf_t local = output->get_cursor_position(); @@ -337,7 +337,7 @@ wf::point_t get_global_input_coordinates(wf::output_t *output) local.x += size.width * vp.x; local.y += size.height * vp.y; - return {(int)local.x, (int)local.y}; + return local; } } // namespace tile } diff --git a/plugins/tile/tree-controller.hpp b/plugins/tile/tree-controller.hpp index 7edd18c3a..9c0295f7d 100644 --- a/plugins/tile/tree-controller.hpp +++ b/plugins/tile/tree-controller.hpp @@ -103,12 +103,12 @@ class resize_view_controller_t : public tile_controller_t wf::output_t *output; /** Last input event location */ - wf::point_t last_point; + wf::pointf_t last_point; /** Edges of the grabbed view that we're resizing */ uint32_t resizing_edges; /** Calculate the resizing edges for the grabbing view. */ - uint32_t calculate_resizing_edges(wf::point_t point); + uint32_t calculate_resizing_edges(wf::pointf_t point); /** The view we are resizing */ nonstd::observer_ptr grabbed_view; @@ -143,8 +143,8 @@ class resize_view_controller_t : public tile_controller_t * * @param delta How much change to apply */ - void adjust_geometry(int32_t& x1, int32_t& len1, - int32_t& x2, int32_t& len2, int32_t delta); + void adjust_geometry(double& x1, double& len1, + double& x2, double& len2, double delta); }; /** @@ -152,13 +152,13 @@ class resize_view_controller_t : public tile_controller_t * * Returns null if no view nodes are present. */ -nonstd::observer_ptr find_view_at(nonstd::observer_ptr root, wf::point_t input); +nonstd::observer_ptr find_view_at(nonstd::observer_ptr root, wf::pointf_t input); /** * Translate coordinates from output-local coordinates to the coordinate * system of the tiling trees, depending on the current workspace */ -wf::point_t get_global_input_coordinates(wf::output_t *output); +wf::pointf_t get_global_input_coordinates(wf::output_t *output); } } diff --git a/plugins/tile/tree.cpp b/plugins/tile/tree.cpp index 670c28779..dfb391e3b 100644 --- a/plugins/tile/tree.cpp +++ b/plugins/tile/tree.cpp @@ -43,11 +43,21 @@ wf::point_t get_wset_local_coordinates(std::shared_ptr wset return p; } +wf::pointf_t get_wset_local_coordinates(std::shared_ptr wset, wf::pointf_t p) +{ + auto vp = wset->get_current_workspace(); + auto size = wset->get_last_output_geometry().value_or(default_output_resolution); + p.x -= vp.x * size.width; + p.y -= vp.y * size.height; + return p; +} + wf::geometry_t get_wset_local_coordinates(std::shared_ptr wset, wf::geometry_t g) { - auto new_tl = get_wset_local_coordinates(wset, wf::point_t{g.x, g.y}); - g.x = new_tl.x; - g.y = new_tl.y; + auto vp = wset->get_current_workspace(); + auto size = wset->get_last_output_geometry().value_or(default_output_resolution); + g.x -= vp.x * size.width; + g.y -= vp.y * size.height; return g; } @@ -434,8 +444,8 @@ wf::geometry_t view_node_t::calculate_target_geometry() if (view->sticky) { - local_geometry.x = (local_geometry.x % size.width + size.width) % size.width; - local_geometry.y = (local_geometry.y % size.height + size.height) % size.height; + local_geometry.x = std::fmod(std::fmod(local_geometry.x, size.width) + size.width, size.width); + local_geometry.y = std::fmod(std::fmod(local_geometry.y, size.height) + size.height, size.height); } return local_geometry; diff --git a/plugins/tile/tree.hpp b/plugins/tile/tree.hpp index 0ccd17ac3..3e70da432 100644 --- a/plugins/tile/tree.hpp +++ b/plugins/tile/tree.hpp @@ -227,6 +227,7 @@ nonstd::observer_ptr get_root(nonstd::observer_ptr no */ wf::geometry_t get_wset_local_coordinates(std::shared_ptr wset, wf::geometry_t g); wf::point_t get_wset_local_coordinates(std::shared_ptr wset, wf::point_t g); +wf::pointf_t get_wset_local_coordinates(std::shared_ptr wset, wf::pointf_t g); // Since wsets may not have been attached to any output yet, they may not have a native 'resolution'. // In this case, we use a default resolution of 1920x1080 in order to layout views. This resolution will be diff --git a/plugins/vswitch/vswitch.cpp b/plugins/vswitch/vswitch.cpp index 9bb383455..9967dfbd2 100644 --- a/plugins/vswitch/vswitch.cpp +++ b/plugins/vswitch/vswitch.cpp @@ -311,8 +311,8 @@ class workspace_switch_t output->wset()->get_current_workspace()); auto size = output->get_screen_size(); geometry_t viewport = { - (int)std::round(animation.dx * (size.width + gap) + start.x), - (int)std::round(animation.dy * (size.height + gap) + start.y), + (double)std::round(animation.dx * (size.width + gap) + start.x), + (double)std::round(animation.dy * (size.height + gap) + start.y), start.width, start.height, }; diff --git a/plugins/window-rules/view-action-interface.cpp b/plugins/window-rules/view-action-interface.cpp index 26e5afb05..decbad648 100644 --- a/plugins/window-rules/view-action-interface.cpp +++ b/plugins/window-rules/view-action-interface.cpp @@ -360,7 +360,7 @@ std::optional view_action_interface_t::_parse_x11_geometry(std:: if (c == '-') { - x = std::max(workarea.width - w - x, 0); + x = std::max(workarea.width - w - x, 0.0); } x += workarea.x; @@ -375,7 +375,7 @@ std::optional view_action_interface_t::_parse_x11_geometry(std:: if (c == '-') { - y = std::max(workarea.height - h - y, 0); + y = std::max(workarea.height - h - y, 0.0); } y += workarea.y; @@ -383,7 +383,7 @@ std::optional view_action_interface_t::_parse_x11_geometry(std:: } } - return wf::geometry_t({x, y, w, h}); + return wf::geometry_t({(double)x, (double)y, (double)w, (double)h}); } std::tuple view_action_interface_t::_validate_alpha( @@ -620,10 +620,10 @@ wf::geometry_t view_action_interface_t::_get_workspace_grid_geometry( auto res = output->get_screen_size(); return wf::geometry_t{ - -vp.x * res.width, - -vp.y * res.height, - vsize.width * res.width, - vsize.height * res.height, + (double)(-vp.x * res.width), + (double)(-vp.y * res.height), + (double)(vsize.width * res.width), + (double)(vsize.height * res.height), }; } diff --git a/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp b/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp index 34470d61e..0e9f4ab98 100644 --- a/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp +++ b/plugins/wobbly/wayfire/plugins/wobbly/wobbly-signal.hpp @@ -32,7 +32,7 @@ struct wobbly_signal * For EVENT_GRAB and EVENT_MOVE: the coordinates of the grab * For EVENT_TRANSLATE: the amount of translation */ - wf::point_t pos; + wf::pointf_t pos; /** * For EVENT_SCALE: the new size of the base surface. @@ -43,12 +43,12 @@ struct wobbly_signal /** * Start wobblying when the view is being grabbed, for ex. when moving it */ -inline void start_wobbly(wayfire_toplevel_view view, int grab_x, int grab_y) +inline void start_wobbly(wayfire_toplevel_view view, double grab_x, double grab_y) { wobbly_signal sig; sig.view = view; sig.events = WOBBLY_EVENT_GRAB; - sig.pos = {grab_x, grab_y}; + sig.pos = {(double)grab_x, (double)grab_y}; wf::get_core().emit(&sig); } @@ -84,12 +84,12 @@ inline void end_wobbly(wayfire_toplevel_view view) /** * Indicate that the grab has moved (i.e cursor moved, touch moved, etc.) */ -inline void move_wobbly(wayfire_toplevel_view view, int grab_x, int grab_y) +inline void move_wobbly(wayfire_toplevel_view view, double grab_x, double grab_y) { wobbly_signal sig; sig.view = view; sig.events = WOBBLY_EVENT_MOVE; - sig.pos = {grab_x, grab_y}; + sig.pos = {(double)grab_x, (double)grab_y}; wf::get_core().emit(&sig); } @@ -108,7 +108,7 @@ inline void activate_wobbly(wayfire_toplevel_view view) /** * Translate the wobbly model (and its grab point, if any). */ -inline void translate_wobbly(wayfire_toplevel_view view, wf::point_t delta) +inline void translate_wobbly(wayfire_toplevel_view view, wf::pointf_t delta) { wobbly_signal sig; sig.view = view; diff --git a/plugins/wobbly/wobbly.cpp b/plugins/wobbly/wobbly.cpp index d714723b4..4d144aac8 100644 --- a/plugins/wobbly/wobbly.cpp +++ b/plugins/wobbly/wobbly.cpp @@ -188,15 +188,15 @@ class iwobbly_state_t {} /** Called when a grab starts */ - virtual void handle_grab_start(wf::point_t grab, bool takeover) + virtual void handle_grab_start(wf::pointf_t grab, bool takeover) {} /** Called when the wobbly grab is moved. */ - virtual void handle_grab_move(wf::point_t grab) + virtual void handle_grab_move(wf::pointf_t grab) {} /** Query the last grab point */ - virtual wf::point_t get_grab_position() const + virtual wf::pointf_t get_grab_position() const { return {0, 0}; } @@ -238,7 +238,12 @@ class iwobbly_state_t iwobbly_state_t(const wobbly_model_t& m, wayfire_toplevel_view v) : view(v), model(m) { - bounding_box = {model->x, model->y, model->width, model->height}; + bounding_box = { + (double)model->x, + (double)model->y, + (double)model->width, + (double)model->height, + }; } /** @@ -270,8 +275,8 @@ class iwobbly_state_t model->x = base.x; model->y = base.y; - model->width = std::max(1, base.width); - model->height = std::max(1, base.height); + model->width = std::max(1, (int)std::round(base.width)); + model->height = std::max(1, (int)std::round(base.height)); } protected: @@ -288,16 +293,16 @@ class wobbly_state_grabbed_t : public iwobbly_state_t { public: using iwobbly_state_t::iwobbly_state_t; - virtual void handle_grab_start(wf::point_t grab, bool takeover) override + virtual void handle_grab_start(wf::pointf_t grab, bool takeover) override { - this->last_grab = {(int)grab.x, (int)grab.y}; + this->last_grab = grab; if (!takeover) { wobbly_grab_notify(model.get(), last_grab.x, last_grab.y); } } - virtual wf::point_t get_grab_position() const override + virtual wf::pointf_t get_grab_position() const override { return this->last_grab; } @@ -337,11 +342,11 @@ class wobbly_state_grabbed_t : public iwobbly_state_t } protected: - wf::point_t last_grab; - void handle_grab_move(wf::point_t grab) override + wf::pointf_t last_grab; + void handle_grab_move(wf::pointf_t grab) override { wobbly_move_notify(model.get(), grab.x, grab.y); - this->last_grab = {(int)grab.x, (int)grab.y}; + this->last_grab = grab; } bool is_wobbly_done() const override @@ -585,12 +590,12 @@ class wobbly_transformer_node_t : public wf::scene::transformer_base_node_t { auto box = wobbly_boundingbox(model.get()); - wlr_box result; - result.x = box.tlx; - result.y = box.tly; - result.width = std::ceil(box.brx - box.tlx); - result.height = std::ceil(box.bry - box.tly); - return result; + return { + (double)box.tlx, + (double)box.tly, + std::ceil(box.brx - box.tlx), + std::ceil(box.bry - box.tly), + }; } void gen_render_instances( @@ -727,7 +732,7 @@ class wobbly_transformer_node_t : public wf::scene::transformer_base_node_t * @param grab The position of the starting grab. * @param end_grab Whether to end an existing grab. */ - void update_wobbly_state(bool start_grab, wf::point_t grab, bool end_grab) + void update_wobbly_state(bool start_grab, wf::pointf_t grab, bool end_grab) { bool was_grabbed = (state->get_wobbly_state() == wf::WOBBLY_STATE_GRABBED || @@ -825,17 +830,17 @@ class wobbly_transformer_node_t : public wf::scene::transformer_base_node_t } public: - void start_grab(wf::point_t grab) + void start_grab(wf::pointf_t grab) { update_wobbly_state(true, grab, false); } - void move(wf::point_t point) + void move(wf::pointf_t point) { state->handle_grab_move(point); } - void translate(wf::point_t delta) + void translate(wf::pointf_t delta) { state->translate_model(delta.x, delta.y); } @@ -889,7 +894,7 @@ class wobbly_render_instance_t : } } - void transform_damage_region(wf::region_t& damage) override + void transform_damage_region(wf::regionf_t& damage) override { damage |= self->get_bounding_box(); } @@ -996,7 +1001,7 @@ class wobbly_render_instance_t : wf::gles::bind_render_buffer(data.target); for (auto box : data.damage) { - wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box)); + wf::gles::render_target_logic_scissor(data.target, box); wobbly_graphics::render_triangles(self->wobbly_program, tex, wf::gles::render_target_orthographic_projection(data.target), vert.data(), uv.data(), count_triangles); diff --git a/src/api/wayfire/geometry.hpp b/src/api/wayfire/geometry.hpp index 464746a38..04fa6d1f5 100644 --- a/src/api/wayfire/geometry.hpp +++ b/src/api/wayfire/geometry.hpp @@ -10,6 +10,12 @@ extern "C" { namespace wf { +struct geometryf_t +{ + double x, y; + double width, height; +}; + struct point_t { int x, y; @@ -57,7 +63,7 @@ struct pointf_t point_t round_down() const { - return point_t{static_cast(x), static_cast(y)}; + return point_t{(int)std::floor(x), (int)std::floor(y)}; } }; @@ -67,12 +73,13 @@ struct dimensions_t int32_t height; }; -using geometry_t = wlr_box; +using geometry_t = geometryf_t; +using framebuffer_box_t = wlr_box; -point_t origin(const geometry_t& geometry); +pointf_t origin(const geometry_t& geometry); dimensions_t dimensions(const geometry_t& geometry); geometry_t construct_box( - const wf::point_t& origin, const wf::dimensions_t& dimensions); + const wf::pointf_t& origin, const wf::dimensions_t& dimensions); /* Returns the intersection of the two boxes, if the boxes don't intersect, * the resulting geometry has undefined (x,y) and width == height == 0 */ @@ -89,6 +96,9 @@ bool operator !=(const wf::dimensions_t& a, const wf::dimensions_t& b); bool operator ==(const wf::point_t& a, const wf::point_t& b); bool operator !=(const wf::point_t& a, const wf::point_t& b); +bool operator ==(const wf::pointf_t& a, const wf::pointf_t& b); +bool operator !=(const wf::pointf_t& a, const wf::pointf_t& b); + wf::point_t operator +(const wf::point_t& a, const wf::point_t& b); wf::point_t operator -(const wf::point_t& a, const wf::point_t& b); @@ -101,6 +111,13 @@ T clamp(T value, T min, T max) return std::min(std::max(value, min), max); } +template +auto clamp(T value, U min, V max) +{ + using R = std::common_type_t; + return wf::clamp((R)value, (R)min, (R)max); +} + /** * Return the closest geometry to window which is completely inside the output. * The returned geometry might be smaller, but never bigger than window. @@ -112,6 +129,11 @@ geometry_t clamp(geometry_t window, geometry_t output); // @box occupies in @A. wf::geometry_t scale_box(wf::geometry_t A, wf::geometry_t B, wf::geometry_t box); +framebuffer_box_t to_framebuffer_box(const geometry_t& box); +geometry_t from_framebuffer_box(const framebuffer_box_t& box); +framebuffer_box_t containing_box(const geometry_t& box); +framebuffer_box_t containing_box(const wlr_fbox& box); + // Transform a subbox from coordinate space A to coordinate space B. // The returned subbox will occupy the same relative part of @B as // @box occupies in @A. @@ -124,32 +146,37 @@ wlr_fbox geometry_to_fbox(const geometry_t& geometry); geometry_t fbox_to_geometry(const wlr_fbox& fbox); } -bool operator ==(const wf::geometry_t& a, const wf::geometry_t& b); -bool operator !=(const wf::geometry_t& a, const wf::geometry_t& b); +namespace wf +{ +bool operator ==(const geometry_t& a, const geometry_t& b); +bool operator !=(const geometry_t& a, const geometry_t& b); bool operator ==(const wlr_fbox& a, const wlr_fbox& b); bool operator !=(const wlr_fbox& a, const wlr_fbox& b); -wf::point_t operator +(const wf::point_t& a, const wf::geometry_t& b); -wf::geometry_t operator +(const wf::geometry_t & a, const wf::point_t& b); -wf::geometry_t operator -(const wf::geometry_t & a, const wf::point_t& b); +pointf_t operator +(const pointf_t& a, const geometry_t& b); +geometry_t operator +(const geometry_t& a, const pointf_t& b); +geometry_t operator -(const geometry_t& a, const pointf_t& b); +geometry_t operator +(const geometry_t& a, const framebuffer_box_t& b); +geometry_t operator -(const geometry_t& a, const framebuffer_box_t& b); /** Scale the box */ -wf::geometry_t operator *(const wf::geometry_t& box, double scale); +geometry_t operator *(const geometry_t& box, double scale); wlr_fbox operator *(const wlr_fbox& box, double scale); /* @return The length of the given vector */ -double abs(const wf::point_t & p); +double abs(const pointf_t& p); /* Returns true if point is inside rect */ -bool operator &(const wf::geometry_t& rect, const wf::point_t& point); +bool operator &(const geometry_t& rect, const point_t& point); /* Returns true if point is inside rect */ -bool operator &(const wf::geometry_t& rect, const wf::pointf_t& point); +bool operator &(const geometry_t& rect, const pointf_t& point); /* Returns true if the two geometries have a common point */ -bool operator &(const wf::geometry_t& r1, const wf::geometry_t& r2); +bool operator &(const geometry_t& r1, const geometry_t& r2); /* Make geometry and point printable */ -std::ostream& operator <<(std::ostream& stream, const wf::geometry_t& geometry); +std::ostream& operator <<(std::ostream& stream, const geometry_t& geometry); std::ostream& operator <<(std::ostream& stream, const wlr_fbox& geometry); +} #endif /* end of include guard: WF_GEOMETRY_HPP */ diff --git a/src/api/wayfire/opengl.hpp b/src/api/wayfire/opengl.hpp index e00517985..4d968368e 100644 --- a/src/api/wayfire/opengl.hpp +++ b/src/api/wayfire/opengl.hpp @@ -59,10 +59,11 @@ glm::mat4 output_transform(const render_target_t& target); * In contrast to framebuffer_t::scissor(), this method takes its argument * as a box with "logical" coordinates, not raw framebuffer coordinates. * - * @param box The scissor box, in the same coordinate system as the - * framebuffer's geometry. + * @param box The scissor box, in the same logical coordinate system as the + * render target's geometry. */ -void render_target_logic_scissor(const render_target_t& target, wlr_box box); +void render_target_logic_scissor(const render_target_t& target, wf::geometry_t box); +void render_target_logic_scissor(const render_target_t& target, const pixman_box64f_t& box); /** * Ensure that the default EGL/GLES context is current. diff --git a/src/api/wayfire/plugin.hpp b/src/api/wayfire/plugin.hpp index fd834af89..9b0077fdf 100644 --- a/src/api/wayfire/plugin.hpp +++ b/src/api/wayfire/plugin.hpp @@ -107,7 +107,7 @@ using wayfire_plugin_load_func = wf::plugin_interface_t * (*)(); /** * The version is defined as macro as well, to allow conditional compilation. */ -#define WAYFIRE_API_ABI_VERSION_MACRO 2026'05'07 +#define WAYFIRE_API_ABI_VERSION_MACRO 2026'05'15 /** * The version of Wayfire's API/ABI diff --git a/src/api/wayfire/region.hpp b/src/api/wayfire/region.hpp index 1e5d0cc0c..b0a48f828 100644 --- a/src/api/wayfire/region.hpp +++ b/src/api/wayfire/region.hpp @@ -6,17 +6,75 @@ /* ---------------------- pixman utility functions -------------------------- */ namespace wf { +struct regionf_t +{ + regionf_t(); + regionf_t(const pixman_region64f_t *damage); + regionf_t(const geometry_t& box); + ~regionf_t(); + + regionf_t(const regionf_t& other); + regionf_t(regionf_t&& other); + + regionf_t& operator =(const regionf_t& other); + regionf_t& operator =(regionf_t&& other); + + bool empty() const; + void clear(); + + void expand_edges(double amount); + pixman_box64f_t get_extents() const; + bool contains_point(const point_t& point) const; + bool contains_pointf(const pointf_t& point) const; + + regionf_t operator +(const pointf_t& vector) const; + regionf_t& operator +=(const pointf_t& vector); + + regionf_t operator -(const pointf_t& vector) const; + regionf_t& operator -=(const pointf_t& vector); + + regionf_t operator *(double scale) const; + regionf_t& operator *=(double scale); + + regionf_t operator &(const geometry_t& box) const; + regionf_t operator &(const regionf_t& other) const; + regionf_t& operator &=(const geometry_t& box); + regionf_t& operator &=(const regionf_t& other); + + regionf_t operator |(const geometry_t& other) const; + regionf_t operator |(const regionf_t& other) const; + regionf_t& operator |=(const geometry_t& other); + regionf_t& operator |=(const regionf_t& other); + + regionf_t operator ^(const geometry_t& box) const; + regionf_t operator ^(const regionf_t& other) const; + regionf_t& operator ^=(const geometry_t& box); + regionf_t& operator ^=(const regionf_t& other); + + pixman_region64f_t *to_pixman(); + const pixman_region64f_t *to_pixman() const; + + const pixman_box64f_t *begin() const; + const pixman_box64f_t *end() const; + + private: + pixman_region64f_t _region; + pixman_region64f_t *unconst() const; +}; + struct region_t { region_t(); /* Makes a copy of the given region */ region_t(const pixman_region32_t *damage); + region_t(const geometry_t& box); region_t(const wlr_box& box); ~region_t(); region_t(const region_t& other); region_t(region_t&& other); + region_t& operator =(const geometry_t& other); region_t& operator =(const region_t& other); region_t& operator =(region_t&& other); @@ -40,20 +98,26 @@ struct region_t /* Region intersection */ region_t operator &(const wlr_box& box) const; + region_t operator &(const geometry_t& box) const; region_t operator &(const region_t& other) const; region_t& operator &=(const wlr_box& box); + region_t& operator &=(const geometry_t& box); region_t& operator &=(const region_t& other); /* Region union */ region_t operator |(const wlr_box& other) const; + region_t operator |(const geometry_t& other) const; region_t operator |(const region_t& other) const; region_t& operator |=(const wlr_box& other); + region_t& operator |=(const geometry_t& other); region_t& operator |=(const region_t& other); /* Subtract the box/region from the current region */ region_t operator ^(const wlr_box& box) const; + region_t operator ^(const geometry_t& box) const; region_t operator ^(const region_t& other) const; region_t& operator ^=(const wlr_box& box); + region_t& operator ^=(const geometry_t& box); region_t& operator ^=(const region_t& other); pixman_region32_t *to_pixman(); @@ -71,5 +135,8 @@ struct region_t }; } +wf::region_t to_framebuffer_region(const wf::regionf_t& region); +wf::geometry_t geometry_from_pixman_box(const pixman_box64f_t& box); +wlr_fbox wlr_fbox_from_pixman_box(const pixman_box64f_t& box); wlr_box wlr_box_from_pixman_box(const pixman_box32_t& box); pixman_box32_t pixman_box_from_wlr_box(const wlr_box& box); diff --git a/src/api/wayfire/render-manager.hpp b/src/api/wayfire/render-manager.hpp index 7ce43589d..15db17503 100644 --- a/src/api/wayfire/render-manager.hpp +++ b/src/api/wayfire/render-manager.hpp @@ -140,7 +140,7 @@ class render_manager * frame. Note that a larger region might actually be repainted due to * double buffering. */ - wf::region_t get_scheduled_damage(); + wf::regionf_t get_scheduled_damage(); /** * @return The current wlr_color_transform from the icc_profile option, or NULL if none is set. @@ -174,7 +174,7 @@ class render_manager * @param region The output region to be damaged, in output-local coordinates. * @param repaint Whether to automatically schedule an output repaint. */ - void damage(const wf::region_t& region, bool repaint = true); + void damage(const wf::regionf_t& region, bool repaint = true); /** * @return A box in output-local coordinates containing the given diff --git a/src/api/wayfire/render.hpp b/src/api/wayfire/render.hpp index 002e830b3..30adda23a 100644 --- a/src/api/wayfire/render.hpp +++ b/src/api/wayfire/render.hpp @@ -357,7 +357,7 @@ struct render_target_t : public render_buffer_t * Get a render target which is the same as this, but whose geometry is * translated by @offset. */ - render_target_t translated(wf::point_t offset) const; + render_target_t translated(wf::pointf_t offset) const; /** * Get the geometry of the given box after projecting it onto the framebuffer. @@ -367,6 +367,7 @@ struct render_target_t : public render_buffer_t * transform. */ wlr_box framebuffer_box_from_geometry_box(wlr_box box) const; + wlr_box framebuffer_box_from_geometry_box(wf::geometry_t box) const; /** * Get the geometry of the given fbox after projecting it onto the framebuffer. @@ -381,7 +382,7 @@ struct render_target_t : public render_buffer_t * Get the geometry of the given region after projecting it onto the framebuffer. This is the same as * iterating over the rects in the region and transforming them with framebuffer_box_from_geometry_box. */ - wf::region_t framebuffer_region_from_geometry_region(const wf::region_t& region) const; + wf::region_t framebuffer_region_from_geometry_region(const wf::regionf_t& region) const; /** * Get the geometry of the given framebuffer box after projecting it back to the logical coordinate space. @@ -406,7 +407,7 @@ struct render_target_t : public render_buffer_t * This is the same as iterating over the rects in the region and transforming them with * geometry_box_from_framebuffer_box. */ - wf::region_t geometry_region_from_framebuffer_region(const wf::region_t& region) const; + wf::regionf_t geometry_region_from_framebuffer_region(const wf::region_t& region) const; /** * The inverse of the color transform that will be applied to the render target in the next compositing @@ -462,7 +463,7 @@ struct render_pass_params_t render_target_t target; /** The total damage accumulated from the instances since the last repaint. */ - region_t damage; + regionf_t damage; /** * The background color visible below all instances, if @@ -528,7 +529,7 @@ class render_pass_t * * @return The full damage which was rendered on the render target, as described in @run_partial(). */ - static wf::region_t run(const wf::render_pass_params_t& params); + static wf::regionf_t run(const wf::render_pass_params_t& params); /** * Execute the main part of a render pass. @@ -549,7 +550,7 @@ class render_pass_t * @return The full damage which was rendered on the render target. It may be more (or * less) than @params.damage because plugins are allowed to modify the damage in render-pass-begin. */ - wf::region_t run_partial(); + wf::regionf_t run_partial(); /** * The current wlroots render pass. @@ -562,7 +563,7 @@ class render_pass_t /** * Clear the given region (relative to the render target's geometry) with the given color. */ - void clear(const wf::region_t& region, const wf::color_t& color); + void clear(const wf::regionf_t& region, const wf::color_t& color); /** * Add a texture rendering operation to the pass. @@ -570,7 +571,7 @@ class render_pass_t void add_texture(const std::shared_ptr& texture, const wf::render_target_t& adjusted_target, const wf::geometry_t& geometry, - const wf::region_t& damage, + const wf::regionf_t& damage, float alpha = 1.0); /** @@ -579,7 +580,7 @@ class render_pass_t void add_texture(const std::shared_ptr& texture, const wf::render_target_t& adjusted_target, const wlr_fbox& geometry, - const wf::region_t& damage, + const wf::regionf_t& damage, float alpha = 1.0); /** @@ -588,7 +589,7 @@ class render_pass_t void add_rect(const wf::color_t& color, const wf::render_target_t& adjusted_target, const wf::geometry_t& geometry, - const wf::region_t& damage); + const wf::regionf_t& damage); /** * Add a colored rectangle to the pass using wlr_fbox for geometry. @@ -596,7 +597,7 @@ class render_pass_t void add_rect(const wf::color_t& color, const wf::render_target_t& adjusted_target, const wlr_fbox& geometry, - const wf::region_t& damage); + const wf::regionf_t& damage); /** * Get the wlr_renderer used in this pass. @@ -693,7 +694,7 @@ class render_pass_t */ struct render_pass_begin_signal { - render_pass_begin_signal(wf::render_pass_t& pass, wf::region_t& damage) : + render_pass_begin_signal(wf::render_pass_t& pass, wf::regionf_t& damage) : damage(damage), pass(pass) {} @@ -701,7 +702,7 @@ struct render_pass_begin_signal * The initial damage for this render pass. * Plugins may expand it further. */ - wf::region_t& damage; + wf::regionf_t& damage; /** * The render pass that is starting. diff --git a/src/api/wayfire/scene-operations.hpp b/src/api/wayfire/scene-operations.hpp index 4778ff33f..5a6256a5c 100644 --- a/src/api/wayfire/scene-operations.hpp +++ b/src/api/wayfire/scene-operations.hpp @@ -91,7 +91,7 @@ struct render_instance_manager_t public: render_instance_manager_t(std::vector nodes, damage_callback on_damage, wf::output_t *reference_output); - void set_visibility_region(wf::region_t region); + void set_visibility_region(wf::regionf_t region); std::vector& get_instances(); private: @@ -99,7 +99,7 @@ struct render_instance_manager_t std::vector instances; damage_callback on_damage; wf::output_t *reference_output; - std::optional visibility_region; + std::optional visibility_region; wf::signal::connection_t on_update; wf::wl_idle_call idle_visibility; diff --git a/src/api/wayfire/scene-render.hpp b/src/api/wayfire/scene-render.hpp index e38831e7b..85f8f906e 100644 --- a/src/api/wayfire/scene-render.hpp +++ b/src/api/wayfire/scene-render.hpp @@ -50,7 +50,7 @@ struct render_instruction_t render_pass_t *pass = NULL; // auto-filled by the render pass scheduling instructions render_instance_t *instance = NULL; render_target_t target; - wf::region_t damage; + wf::regionf_t damage; std::any data = {}; }; @@ -94,7 +94,7 @@ class render_instance_t */ virtual void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) = 0; + const wf::render_target_t& target, wf::regionf_t& damage) = 0; /** * Render the node with the given parameters. @@ -140,11 +140,11 @@ class render_instance_t * The visible region can be used for things like determining when to send frame done events to * wlr_surfaces and to ignore damage to invisible parts of a render instance. */ - virtual void compute_visibility(wf::output_t *output, wf::region_t& visible) + virtual void compute_visibility(wf::output_t *output, wf::regionf_t& visible) {} }; -using damage_callback = std::function; +using damage_callback = std::function; /** * A signal emitted when a part of the node is damaged. @@ -152,20 +152,26 @@ using damage_callback = std::function; */ struct node_damage_signal { - wf::region_t region; + wf::regionf_t region; }; /** * A helper function to emit the damage signal on a node. */ template -inline void damage_node(NodePtr node, wf::region_t damage) +inline void damage_node(NodePtr node, wf::regionf_t damage) { node_damage_signal data; data.region = damage; node->emit(&data); } +template +inline void damage_node(NodePtr node, wf::geometry_t damage) +{ + damage_node(node, wf::regionf_t{damage}); +} + /** * A helper function for direct scanout implementations. * It tries to forward the direct scanout request to the first render instance @@ -181,7 +187,7 @@ direct_scanout try_scanout_from_list( * afterwards. It also calls compute_visibility for the children instances. */ void compute_visibility_from_list(const std::vector& instances, wf::output_t *output, - wf::region_t& region, const wf::point_t& offset); + wf::regionf_t& region, const wf::pointf_t& offset); /** * A helper class for easier implementation of render instances. @@ -200,7 +206,7 @@ class simple_render_instance_t : public render_instance_t } void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { instructions.push_back(render_instruction_t{ .instance = this, diff --git a/src/api/wayfire/scene.hpp b/src/api/wayfire/scene.hpp index 2c7dcfa21..314075791 100644 --- a/src/api/wayfire/scene.hpp +++ b/src/api/wayfire/scene.hpp @@ -70,7 +70,7 @@ using node_weak_ptr = std::weak_ptr; class render_instance_t; using render_instance_uptr = std::unique_ptr; -using damage_callback = std::function; +using damage_callback = std::function; /** * Describes the current state of a node. diff --git a/src/api/wayfire/unstable/translation-node.hpp b/src/api/wayfire/unstable/translation-node.hpp index 481f3bb58..7f895cc81 100644 --- a/src/api/wayfire/unstable/translation-node.hpp +++ b/src/api/wayfire/unstable/translation-node.hpp @@ -19,12 +19,12 @@ class translation_node_t : public wf::scene::floating_inner_node_t * Set the offset the node applies to its children. * Note that damage is not automatically applied. */ - void set_offset(wf::point_t offset); + void set_offset(wf::pointf_t offset); /** * Get the current offset (set via @set_offset). Default offset is {0, 0}. */ - wf::point_t get_offset() const; + wf::pointf_t get_offset() const; public: // Implementation of node_t interface wf::pointf_t to_local(const wf::pointf_t& point) override; @@ -37,7 +37,7 @@ class translation_node_t : public wf::scene::floating_inner_node_t uint32_t optimize_update(uint32_t flags) override; protected: - wf::point_t offset = {0, 0}; + wf::pointf_t offset = {0, 0}; }; class translation_node_instance_t : public render_instance_t @@ -57,10 +57,10 @@ class translation_node_instance_t : public render_instance_t // Implementation of render_instance_t void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override; + const wf::render_target_t& target, wf::regionf_t& damage) override; void presentation_feedback(wf::output_t *output) override; wf::scene::direct_scanout try_scanout(wf::output_t *output) override; - void compute_visibility(wf::output_t *output, wf::region_t& visible) override; + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override; }; } } diff --git a/src/api/wayfire/unstable/wlr-surface-node.hpp b/src/api/wayfire/unstable/wlr-surface-node.hpp index bf5289afc..a1468b070 100644 --- a/src/api/wayfire/unstable/wlr-surface-node.hpp +++ b/src/api/wayfire/unstable/wlr-surface-node.hpp @@ -18,8 +18,8 @@ struct surface_state_t wlr_buffer *current_buffer = nullptr; wlr_texture *texture; // The texture of the wlr_client_buffer - wf::region_t accumulated_damage; - wf::region_t opaque_region; + wf::regionf_t accumulated_damage; + wf::regionf_t opaque_region; wf::dimensions_t size = {0, 0}; std::optional src_viewport; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; diff --git a/src/api/wayfire/view-transform.hpp b/src/api/wayfire/view-transform.hpp index a5d3128cb..76321d76e 100644 --- a/src/api/wayfire/view-transform.hpp +++ b/src/api/wayfire/view-transform.hpp @@ -36,7 +36,7 @@ class opaque_region_node_t /** * Get the opaque region of the node in its parent's coordinate system (same as get_bounding_box()). */ - virtual wf::region_t get_opaque_region() const + virtual wf::regionf_t get_opaque_region() const { return {}; } @@ -59,7 +59,7 @@ class transformer_base_node_t : public scene::floating_inner_node_t // Damage from the children, which is the region of @inner_content that // should be repainted on the next frame to have a valid copy of the // children's current content. - wf::region_t cached_damage; + wf::regionf_t cached_damage; std::shared_ptr get_updated_contents(const wf::geometry_t& bbox, float scale, std::vector& children); @@ -145,7 +145,7 @@ class transformer_render_instance_t : public render_instance_t } } - virtual void transform_damage_region(wf::region_t& damage) + virtual void transform_damage_region(wf::regionf_t& damage) {} wf::output_t *_shown_on; @@ -175,7 +175,7 @@ class transformer_render_instance_t : public render_instance_t void regen_instances() { - auto push_damage_child = [=] (wf::region_t region) + auto push_damage_child = [=] (wf::regionf_t region) { self->cached_damage |= region; transform_damage_region(region); @@ -194,7 +194,7 @@ class transformer_render_instance_t : public render_instance_t void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { if (!damage.empty()) { @@ -223,14 +223,14 @@ class transformer_render_instance_t : public render_instance_t return !children.empty(); } - void compute_visibility(wf::output_t *output, wf::region_t& visible) override + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { if (!(visible & self->get_bounding_box()).empty()) { // By default, we are not sure how the visibility region is affected, so we take a simple 0-or-1 // approach: if anything of the bounding box is visible, we assume the whole view is visible, and // we do not subtract anything from the visibility region of the nodes below. - wf::region_t copy = self->get_children_bounding_box(); + wf::regionf_t copy{self->get_children_bounding_box()}; for (auto& ch : this->children) { ch->compute_visibility(output, copy); diff --git a/src/api/wayfire/vulkan.hpp b/src/api/wayfire/vulkan.hpp index 343989e0c..987a660dc 100644 --- a/src/api/wayfire/vulkan.hpp +++ b/src/api/wayfire/vulkan.hpp @@ -154,7 +154,7 @@ class command_buffer_t : public wf::signal::provider_t * Typical usage: * for_each_scissor_rect(target, damage, [&] { vkCmdDraw(...); }); */ - void for_each_scissor_rect(const wf::render_target_t& target, const wf::region_t& damage, + void for_each_scissor_rect(const wf::render_target_t& target, const wf::regionf_t& damage, const std::function & callback); /** diff --git a/src/core/opengl.cpp b/src/core/opengl.cpp index 19e817cfc..8a10deb34 100644 --- a/src/core/opengl.cpp +++ b/src/core/opengl.cpp @@ -356,10 +356,10 @@ void wf::gles::scissor_render_buffer(const wf::render_buffer_t& buffer, wlr_box glm::mat4 wf::gles::render_target_orthographic_projection(const wf::render_target_t& target) { - auto ortho = glm::ortho(1.0f * target.geometry.x, - 1.0f * target.geometry.x + 1.0f * target.geometry.width, - 1.0f * target.geometry.y + 1.0f * target.geometry.height, - 1.0f * target.geometry.y); + auto ortho = glm::ortho((float)target.geometry.x, + (float)(target.geometry.x + target.geometry.width), + (float)(target.geometry.y + target.geometry.height), + (float)target.geometry.y); return gles::render_target_gl_to_framebuffer(target) * ortho; } @@ -398,11 +398,16 @@ glm::mat4 wf::gles::output_transform(const render_target_t& target) wlr_output_transform_compose(target.wl_transform, WL_OUTPUT_TRANSFORM_FLIPPED_180)); } -void wf::gles::render_target_logic_scissor(const wf::render_target_t& target, wlr_box box) +void wf::gles::render_target_logic_scissor(const wf::render_target_t& target, wf::geometry_t box) { wf::gles::scissor_render_buffer(target, target.framebuffer_box_from_geometry_box(box)); } +void wf::gles::render_target_logic_scissor(const wf::render_target_t& target, const pixman_box64f_t& box) +{ + render_target_logic_scissor(target, geometry_from_pixman_box(box)); +} + /* look up the actual values of wl_output_transform enum * All _flipped transforms have values (regular_transform + 4) */ glm::mat4 get_output_matrix_from_transform(wl_output_transform transform) diff --git a/src/core/output-layout.cpp b/src/core/output-layout.cpp index a97bb5972..ed22d69b4 100644 --- a/src/core/output-layout.cpp +++ b/src/core/output-layout.cpp @@ -150,10 +150,10 @@ std::string_view wf::layout_detail::get_output_source_name(output_image_source_t wf::geometry_t wf::layout_detail::calculate_output_geometry(const output_state_t& state) { wf::geometry_t geometry = { - state.position.get_x(), - state.position.get_y(), - (int32_t)(state.mode.width / state.scale), - (int32_t)(state.mode.height / state.scale), + (double)state.position.get_x(), + (double)state.position.get_y(), + (double)(int32_t)(state.mode.width / state.scale), + (double)(int32_t)(state.mode.height / state.scale), }; if (state.transform & 1) @@ -1027,7 +1027,7 @@ struct output_layout_output_t opts.filter_mode = WLR_SCALE_FILTER_BILINEAR; opts.clip = NULL; opts.src_box = {0, 0, 0, 0}; - opts.dst_box = {0, 0, handle->width, handle->height}; + opts.dst_box = {0, 0, (int)handle->width, (int)handle->height}; opts.transform = WL_OUTPUT_TRANSFORM_NORMAL; wlr_render_pass_add_texture(pass, &opts); diff --git a/src/core/scene.cpp b/src/core/scene.cpp index 97803780f..04cc35074 100644 --- a/src/core/scene.cpp +++ b/src/core/scene.cpp @@ -218,7 +218,7 @@ class default_render_instance_t : public render_instance_t } void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { // nothing to render here } @@ -260,10 +260,10 @@ wf::geometry_t node_t::get_children_bounding_box() return {0, 0, 0, 0}; } - int min_x = std::numeric_limits::max(); - int min_y = std::numeric_limits::max(); - int max_x = std::numeric_limits::min(); - int max_y = std::numeric_limits::min(); + double min_x = std::numeric_limits::max(); + double min_y = std::numeric_limits::max(); + double max_x = std::numeric_limits::lowest(); + double max_y = std::numeric_limits::lowest(); for (auto& ch : children) { @@ -421,7 +421,7 @@ class output_render_instance_t : public default_render_instance_t damage_callback transform_damage(damage_callback child_damage) { - return [=] (const wf::region_t& damage) + return [=] (const wf::regionf_t& damage) { if (self->get_output()) { @@ -434,7 +434,7 @@ class output_render_instance_t : public default_render_instance_t } void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { if (!self->get_output()) { @@ -443,7 +443,7 @@ class output_render_instance_t : public default_render_instance_t if (self->limit_region) { - wf::region_t our_damage = damage & *self->limit_region; + wf::regionf_t our_damage = damage & *self->limit_region; our_damage &= target.geometry; if (!our_damage.empty()) { @@ -460,7 +460,7 @@ class output_render_instance_t : public default_render_instance_t } void _schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) + const wf::render_target_t& target, wf::regionf_t& damage) { // In principle, we just have to schedule the children. // However, we need to adjust the target's geometry and the damage to @@ -498,7 +498,7 @@ class output_render_instance_t : public default_render_instance_t return direct_scanout::SKIP; } - void compute_visibility(wf::output_t *output, wf::region_t& visible) override + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { auto offset = wf::origin(output->get_layout_geometry()); compute_visibility_from_list(children, output, visible, offset); @@ -706,7 +706,7 @@ void render_instance_manager_t::regen_instances() } } -void render_instance_manager_t::set_visibility_region(wf::region_t region) +void render_instance_manager_t::set_visibility_region(wf::regionf_t region) { this->visibility_region = region; update_visibility(); @@ -719,7 +719,7 @@ void render_instance_manager_t::update_visibility() return; } - wf::region_t visibility = this->visibility_region.value(); + wf::regionf_t visibility = this->visibility_region.value(); for (auto& instance : instances) { instance->compute_visibility(reference_output, visibility); diff --git a/src/core/seat/drag-icon.cpp b/src/core/seat/drag-icon.cpp index 904c5c378..518d8d198 100644 --- a/src/core/seat/drag-icon.cpp +++ b/src/core/seat/drag-icon.cpp @@ -37,7 +37,7 @@ class dnd_root_icon_root_node_t : public floating_inner_node_t this->push_damage = push_damage; self->connect(&on_damage); - auto transformed_push_damage = [this] (wf::region_t region) + auto transformed_push_damage = [this] (wf::regionf_t region) { if (auto self = _self.lock()) { @@ -57,7 +57,7 @@ class dnd_root_icon_root_node_t : public floating_inner_node_t void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { auto self = _self.lock(); if (!self) @@ -81,11 +81,12 @@ class dnd_root_icon_root_node_t : public floating_inner_node_t wf::dassert(false, "Rendering a drag icon root node?"); } - void compute_visibility(wf::output_t *output, wf::region_t& visible) override + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { if (auto self = _self.lock()) { - compute_visibility_from_list(children, output, visible, self->get_position()); + compute_visibility_from_list(children, output, visible, + self->get_position()); } } }; @@ -129,7 +130,7 @@ class dnd_root_icon_root_node_t : public floating_inner_node_t return "dnd-icon " + stringify_flags(); } - wf::point_t get_position() + wf::pointf_t get_position() { if (icon) { @@ -194,7 +195,7 @@ wf::drag_icon_t::~drag_icon_t() wf::scene::remove_child(root_node); } -wf::point_t wf::drag_icon_t::get_position() +wf::pointf_t wf::drag_icon_t::get_position() { auto pos = icon->drag->grab_type == WLR_DRAG_GRAB_KEYBOARD_TOUCH ? wf::get_core().get_touch_position(icon->drag->touch_id) : @@ -206,13 +207,13 @@ wf::point_t wf::drag_icon_t::get_position() pos.y += icon->surface->current.dy; } - return {(int)pos.x, (int)pos.y}; + return pos; } void wf::drag_icon_t::update_position() { // damage previous position - wf::region_t dmg_region; + wf::regionf_t dmg_region; dmg_region |= last_box; last_box = wf::construct_box(get_position(), {icon->surface->current.width, icon->surface->current.height}); diff --git a/src/core/seat/drag-icon.hpp b/src/core/seat/drag-icon.hpp index ad890becb..875eecf72 100644 --- a/src/core/seat/drag-icon.hpp +++ b/src/core/seat/drag-icon.hpp @@ -26,7 +26,7 @@ class drag_icon_t /** Last icon box. */ wf::geometry_t last_box = {0, 0, 0, 0}; - wf::point_t get_position(); + wf::pointf_t get_position(); std::shared_ptr root_node; }; diff --git a/src/core/seat/input-method-popup.cpp b/src/core/seat/input-method-popup.cpp index e56ed01e1..6a38e072b 100644 --- a/src/core/seat/input-method-popup.cpp +++ b/src/core/seat/input-method-popup.cpp @@ -99,7 +99,10 @@ std::string wf::text_input_v3_popup::get_title() void wf::text_input_v3_popup::update_cursor_rect(wlr_box *cursor_rect) { - if (old_cursor_rect == *cursor_rect) + if ((old_cursor_rect.x == cursor_rect->x) && + (old_cursor_rect.y == cursor_rect->y) && + (old_cursor_rect.width == cursor_rect->width) && + (old_cursor_rect.height == cursor_rect->height)) { return; } @@ -129,7 +132,7 @@ void wf::text_input_v3_popup::update_geometry() bool cursor_rect = text_input->current.features & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE; auto cursor = text_input->current.cursor_rectangle; - int x = 0, y = 0; + double x = 0, y = 0; if (cursor_rect) { x = cursor.x; @@ -145,18 +148,18 @@ void wf::text_input_v3_popup::update_geometry() damage(); - wf::pointf_t popup_offset = wf::place_popup_at(wlr_surface, surface, {x* 1.0, y * 1.0}); + wf::pointf_t popup_offset = wf::place_popup_at(wlr_surface, surface, {x, y}); x = popup_offset.x; y = popup_offset.y; - auto width = surface->current.width; - auto height = surface->current.height; + double width = surface->current.width; + double height = surface->current.height; auto output = view->get_output(); auto g_output = output->get_layout_geometry(); // make sure right edge is on screen, sliding to the left when needed, // but keep left edge on screen nonetheless. - x = std::max(0, std::min(x, g_output.width - width)); + x = std::max(0.0, std::min(x, g_output.width - width)); // down edge is going to be out of screen; flip upwards if (y + height > g_output.height) { @@ -171,7 +174,7 @@ void wf::text_input_v3_popup::update_geometry() } // make sure top edge is on screen, sliding down and sacrificing down edge if unavoidable - y = std::max(0, y); + y = std::max(0.0, y); surface_root_node->set_offset({x, y}); geometry.x = x; diff --git a/src/core/window-manager.cpp b/src/core/window-manager.cpp index fcf86040a..3fe9fb1b9 100644 --- a/src/core/window-manager.cpp +++ b/src/core/window-manager.cpp @@ -223,7 +223,7 @@ void window_manager_t::tile_request(wayfire_toplevel_view view, data.edges = tiled_edges; data.workspace = workspace; data.desired_size = tiled_edges ? view->get_output()->workarea->get_workarea() : - get_last_windowed_geometry(view).value_or(wf::geometry_t{0, 0, -1, -1}); + get_last_windowed_geometry(view).value_or(wf::geometry_t{0.0, 0.0, -1.0, -1.0}); update_last_windowed_geometry(view); view->toplevel()->pending().tiled_edges = tiled_edges; @@ -274,7 +274,7 @@ void window_manager_t::fullscreen_request(wayfire_toplevel_view view, if (!state) { data.desired_size = view->pending_tiled_edges() ? wo->workarea->get_workarea() : - get_last_windowed_geometry(view).value_or(wf::geometry_t{0, 0, -1, -1}); + get_last_windowed_geometry(view).value_or(wf::geometry_t{0.0, 0.0, -1.0, -1.0}); } else { update_last_windowed_geometry(view); diff --git a/src/core/xdg-output-management.cpp b/src/core/xdg-output-management.cpp index bf5a303c8..4c6aecf05 100644 --- a/src/core/xdg-output-management.cpp +++ b/src/core/xdg-output-management.cpp @@ -156,7 +156,12 @@ void xdg_output_manager_v1::update_outputs() { int width, height; wlr_output_transformed_resolution(it->first, &width, &height); - wf::geometry_t xwayland_geometry = {xwayland_location_x, 0, width, height}; + wf::geometry_t xwayland_geometry = { + (double)xwayland_location_x, + 0.0, + (double)width, + (double)height, + }; update_output(it->first, geometry, xwayland_geometry); xwayland_location_x += width; wo->get_data_safe()->geometry = xwayland_geometry; diff --git a/src/geometry.cpp b/src/geometry.cpp index bc50bd88a..a0a1499bb 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -3,7 +3,7 @@ #include /* Geometry helpers */ -std::ostream& operator <<(std::ostream& stream, const wf::geometry_t& geometry) +std::ostream & wf::operator <<(std::ostream& stream, const wf::geometry_t& geometry) { stream << '(' << geometry.x << ',' << geometry.y << ' ' << geometry.width << 'x' << geometry.height << ')'; @@ -11,7 +11,7 @@ std::ostream& operator <<(std::ostream& stream, const wf::geometry_t& geometry) return stream; } -std::ostream& operator <<(std::ostream& stream, const wlr_fbox& geometry) +std::ostream& wf::operator <<(std::ostream& stream, const wlr_fbox& geometry) { stream << std::fixed << std::setprecision(2) << '(' << geometry.x << ',' << geometry.y << ' ' << geometry.width << 'x' << geometry.height << ')'; @@ -40,14 +40,14 @@ std::ostream& wf::operator <<(std::ostream& stream, const wf::pointf_t& pointf) return stream; } -wf::point_t wf::origin(const geometry_t& geometry) +wf::pointf_t wf::origin(const geometry_t& geometry) { return {geometry.x, geometry.y}; } wf::dimensions_t wf::dimensions(const geometry_t& geometry) { - return {geometry.width, geometry.height}; + return {(int)std::ceil(geometry.width), (int)std::ceil(geometry.height)}; } bool wf::operator ==(const wf::dimensions_t& a, const wf::dimensions_t& b) @@ -70,22 +70,32 @@ bool wf::operator !=(const wf::point_t& a, const wf::point_t& b) return !(a == b); } -bool operator ==(const wf::geometry_t& a, const wf::geometry_t& b) +bool wf::operator ==(const wf::pointf_t& a, const wf::pointf_t& b) +{ + return a.x == b.x && a.y == b.y; +} + +bool wf::operator !=(const wf::pointf_t& a, const wf::pointf_t& b) +{ + return !(a == b); +} + +bool wf::operator ==(const wf::geometry_t& a, const wf::geometry_t& b) { return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height; } -bool operator !=(const wf::geometry_t& a, const wf::geometry_t& b) +bool wf::operator !=(const wf::geometry_t& a, const wf::geometry_t& b) { return !(a == b); } -bool operator ==(const wlr_fbox& a, const wlr_fbox& b) +bool wf::operator ==(const wlr_fbox& a, const wlr_fbox& b) { return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height; } -bool operator !=(const wlr_fbox& a, const wlr_fbox& b) +bool wf::operator !=(const wlr_fbox& a, const wlr_fbox& b) { return !(a == b); } @@ -100,12 +110,12 @@ wf::point_t wf::operator -(const wf::point_t& a, const wf::point_t& b) return {a.x - b.x, a.y - b.y}; } -wf::point_t operator +(const wf::point_t& a, const wf::geometry_t& b) +wf::pointf_t wf::operator +(const wf::pointf_t& a, const wf::geometry_t& b) { return {a.x + b.x, a.y + b.y}; } -wf::geometry_t operator +(const wf::geometry_t & a, const wf::point_t& b) +wf::geometry_t wf::operator +(const wf::geometry_t & a, const wf::pointf_t& b) { return { a.x + b.x, @@ -115,9 +125,19 @@ wf::geometry_t operator +(const wf::geometry_t & a, const wf::point_t& b) }; } -wf::geometry_t operator -(const wf::geometry_t & a, const wf::point_t& b) +wf::geometry_t wf::operator -(const wf::geometry_t & a, const wf::pointf_t& b) +{ + return a + wf::pointf_t{-b.x, -b.y}; +} + +wf::geometry_t wf::operator +(const wf::geometry_t & a, const wf::framebuffer_box_t& b) { - return a + -b; + return a + wf::origin(wf::from_framebuffer_box(b)); +} + +wf::geometry_t wf::operator -(const wf::geometry_t & a, const wf::framebuffer_box_t& b) +{ + return a - wf::origin(wf::from_framebuffer_box(b)); } wf::point_t wf::operator -(const wf::point_t& a) @@ -125,20 +145,17 @@ wf::point_t wf::operator -(const wf::point_t& a) return {-a.x, -a.y}; } -wf::geometry_t operator *(const wf::geometry_t& box, double scale) +wf::geometry_t wf::operator *(const wf::geometry_t& box, double scale) { - wlr_box scaled; - scaled.x = std::floor(box.x * scale); - scaled.y = std::floor(box.y * scale); - /* Scale it the same way that regions are scaled, otherwise - * we get numerical issues. */ - scaled.width = std::ceil((box.x + box.width) * scale) - scaled.x; - scaled.height = std::ceil((box.y + box.height) * scale) - scaled.y; - - return scaled; + return { + box.x * scale, + box.y * scale, + box.width * scale, + box.height * scale, + }; } -wlr_fbox operator *(const wlr_fbox& box, double scale) +wlr_fbox wf::operator *(const wlr_fbox& box, double scale) { wlr_fbox scaled; scaled.x = box.x * scale; @@ -148,22 +165,24 @@ wlr_fbox operator *(const wlr_fbox& box, double scale) return scaled; } -double abs(const wf::point_t& p) +double wf::abs(const wf::pointf_t& p) { return std::sqrt(p.x * p.x + p.y * p.y); } -bool operator &(const wf::geometry_t& rect, const wf::point_t& point) +bool wf::operator &(const wf::geometry_t& rect, const wf::point_t& point) { - return wlr_box_contains_point(&rect, point.x, point.y); + return (rect.x <= point.x) && (point.x < rect.x + rect.width) && + (rect.y <= point.y) && (point.y < rect.y + rect.height); } -bool operator &(const wf::geometry_t& rect, const wf::pointf_t& point) +bool wf::operator &(const wf::geometry_t& rect, const wf::pointf_t& point) { - return wlr_box_contains_point(&rect, point.x, point.y); + return (rect.x <= point.x) && (point.x < rect.x + rect.width) && + (rect.y <= point.y) && (point.y < rect.y + rect.height); } -bool operator &(const wf::geometry_t& r1, const wf::geometry_t& r2) +bool wf::operator &(const wf::geometry_t& r1, const wf::geometry_t& r2) { if ((r1.x + r1.width <= r2.x) || (r2.x + r2.width <= r1.x) || (r1.y + r1.height <= r2.y) || (r2.y + r2.height <= r1.y)) @@ -177,13 +196,16 @@ bool operator &(const wf::geometry_t& r1, const wf::geometry_t& r2) wf::geometry_t wf::geometry_intersection(const wf::geometry_t& r1, const wf::geometry_t& r2) { - wlr_box result; - if (wlr_box_intersection(&result, &r1, &r2)) + const double x1 = std::max(r1.x, r2.x); + const double y1 = std::max(r1.y, r2.y); + const double x2 = std::min(r1.x + r1.width, r2.x + r2.width); + const double y2 = std::min(r1.y + r1.height, r2.y + r2.height); + if ((x1 < x2) && (y1 < y2)) { - return result; + return {x1, y1, x2 - x1, y2 - y1}; } - return {0, 0, 0, 0}; + return {0.0, 0.0, 0.0, 0.0}; } wf::geometry_t wf::clamp(wf::geometry_t window, wf::geometry_t output) @@ -200,23 +222,36 @@ wf::geometry_t wf::clamp(wf::geometry_t window, wf::geometry_t output) } wf::geometry_t wf::construct_box( - const wf::point_t& origin, const wf::dimensions_t& dimensions) + const wf::pointf_t& origin, const wf::dimensions_t& dimensions) { return { - origin.x, origin.y, dimensions.width, dimensions.height + origin.x, origin.y, (double)dimensions.width, (double)dimensions.height }; } -wf::geometry_t wf::scale_box( - wf::geometry_t A, wf::geometry_t B, wf::geometry_t box) +wf::framebuffer_box_t wf::to_framebuffer_box(const geometry_t& box) { - wlr_fbox scaled_fbox = scale_fbox(geometry_to_fbox(A), geometry_to_fbox(B), geometry_to_fbox(box)); - int x = (int)std::floor(scaled_fbox.x); - int y = (int)std::floor(scaled_fbox.y); - int x2 = (int)std::ceil(scaled_fbox.x + scaled_fbox.width); - int y2 = (int)std::floor(scaled_fbox.y + scaled_fbox.height); + return containing_box(box); +} - return wf::geometry_t{ +wf::geometry_t wf::from_framebuffer_box(const framebuffer_box_t& box) +{ + return {(double)box.x, (double)box.y, (double)box.width, (double)box.height}; +} + +wf::framebuffer_box_t wf::containing_box(const geometry_t& box) +{ + return containing_box(geometry_to_fbox(box)); +} + +wf::framebuffer_box_t wf::containing_box(const wlr_fbox& box) +{ + int x = (int)std::floor(box.x); + int y = (int)std::floor(box.y); + int x2 = (int)std::ceil(box.x + box.width); + int y2 = (int)std::ceil(box.y + box.height); + + return { .x = x, .y = y, .width = x2 - x, @@ -224,6 +259,13 @@ wf::geometry_t wf::scale_box( }; } +wf::geometry_t wf::scale_box( + wf::geometry_t A, wf::geometry_t B, wf::geometry_t box) +{ + wlr_fbox scaled_fbox = scale_fbox(geometry_to_fbox(A), geometry_to_fbox(B), geometry_to_fbox(box)); + return wf::fbox_to_geometry(scaled_fbox); +} + wlr_fbox wf::scale_fbox(wlr_fbox A, wlr_fbox B, wlr_fbox box) { double scale_x = B.width / A.width; @@ -254,15 +296,5 @@ wlr_fbox wf::geometry_to_fbox(const geometry_t& geometry) wf::geometry_t wf::fbox_to_geometry(const wlr_fbox& fbox) { - int x = (int)std::floor(fbox.x); - int y = (int)std::floor(fbox.y); - int x2 = (int)std::ceil(fbox.x + fbox.width); - int y2 = (int)std::ceil(fbox.y + fbox.height); - - return wf::geometry_t{ - .x = x, - .y = y, - .width = x2 - x, - .height = y2 - y, - }; + return {fbox.x, fbox.y, fbox.width, fbox.height}; } diff --git a/src/output/output.cpp b/src/output/output.cpp index ec97c8945..b91f065e6 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -141,7 +141,7 @@ wf::geometry_t wf::output_t::get_relative_geometry() const auto size = get_screen_size(); return { - 0, 0, size.width, size.height + 0.0, 0.0, (double)size.width, (double)size.height }; } @@ -153,10 +153,10 @@ wf::geometry_t wf::output_t::get_layout_geometry() const if (wlr_box_empty(&box)) { // Can happen when initializing the output - return {0, 0, handle->width, handle->height}; + return {0.0, 0.0, (double)handle->width, (double)handle->height}; } else { - return box; + return wf::from_framebuffer_box(box); } } @@ -169,7 +169,7 @@ void wf::output_t::ensure_pointer(bool center) const { auto ptr = wf::get_core().get_cursor_position(); if (!center && - (get_layout_geometry() & wf::point_t{(int)ptr.x, (int)ptr.y})) + (get_layout_geometry() & ptr)) { return; } @@ -194,7 +194,7 @@ wf::pointf_t wf::output_t::get_cursor_position() const bool wf::output_t::ensure_visible(wayfire_view v) { - auto bbox = v->get_bounding_box(); + auto bbox = wf::from_framebuffer_box(v->get_bounding_box()); auto g = this->get_relative_geometry(); /* Compute the percentage of the view which is visible */ diff --git a/src/output/render-manager.cpp b/src/output/render-manager.cpp index ca77d68da..bb215d2a3 100644 --- a/src/output/render-manager.cpp +++ b/src/output/render-manager.cpp @@ -48,20 +48,20 @@ struct swapchain_damage_manager_t std::unique_ptr instance_manager; void start_rendering() { - scene::damage_callback push_damage = [=] (wf::region_t region) + scene::damage_callback push_damage = [=] (wf::regionf_t region) { // Damage is pushed up to the root in root coordinate system, // we need it in output-buffer-local coordinate system. region += -wf::origin(wo->get_layout_geometry()); - region = + auto framebuffer_damage = wo->render->get_target_framebuffer().framebuffer_region_from_geometry_region(region); - this->damage_buffer(region, true); + this->damage_buffer(framebuffer_damage, true); }; std::vector nodes; nodes.push_back(wf::get_core().scene()); instance_manager = std::make_unique(nodes, push_damage, wo); - instance_manager->set_visibility_region(wo->get_layout_geometry()); + instance_manager->set_visibility_region(wf::regionf_t{wo->get_layout_geometry()}); } swapchain_damage_manager_t(output_t *output) @@ -114,7 +114,7 @@ struct swapchain_damage_manager_t } schedule_repaint(); - instance_manager->set_visibility_region(wo->get_layout_geometry()); + instance_manager->set_visibility_region(wf::regionf_t{wo->get_layout_geometry()}); }; /** @@ -144,7 +144,8 @@ struct swapchain_damage_manager_t /* Wlroots expects damage after scaling */ frame_damage |= box; - wlr_damage_ring_add_box(&damage_ring, &box); + auto fb_box = wf::to_framebuffer_box(box); + wlr_damage_ring_add_box(&damage_ring, &fb_box); if (repaint) { schedule_repaint(); @@ -329,7 +330,7 @@ struct swapchain_damage_manager_t * Return the damage that has been scheduled for the next frame up to now, * or, if in a repaint, the damage for the current frame */ - wf::region_t get_scheduled_damage(const wf::render_target_t& target) + wf::regionf_t get_scheduled_damage(const wf::render_target_t& target) { return target.geometry_region_from_framebuffer_region(frame_damage) & target.geometry; } @@ -358,7 +359,7 @@ struct swapchain_damage_manager_t { auto current = wo->wset()->get_current_workspace(); - wlr_box box = wo->get_relative_geometry(); + wlr_box box = wf::to_framebuffer_box(wo->get_relative_geometry()); box.x = (ws.x - current.x) * box.width; box.y = (ws.y - current.y) * box.height; @@ -1028,7 +1029,7 @@ class wf::render_manager::impl if (runtime_config.damage_debug) { /* Clear the screen to yellow, so that the repainted parts are visible */ - wf::region_t yellow = params.target.geometry; + wf::regionf_t yellow = params.target.geometry; yellow ^= total_damage; total_damage |= params.target.geometry; @@ -1036,9 +1037,9 @@ class wf::render_manager::impl } // Transform to buffer-local damage - total_damage = params.target.framebuffer_region_from_geometry_region(total_damage); - total_damage &= damage_manager->get_buffer_extents(); - return total_damage; + auto framebuffer_damage = params.target.framebuffer_region_from_geometry_region(total_damage); + framebuffer_damage &= damage_manager->get_buffer_extents(); + return framebuffer_damage; } void update_bound_output(wlr_buffer *buffer) @@ -1177,7 +1178,7 @@ scene::direct_scanout scene::try_scanout_from_list( } void scene::compute_visibility_from_list(const std::vector& instances, - wf::output_t *output, wf::region_t& region, const wf::point_t& offset) + wf::output_t *output, wf::regionf_t& region, const wf::pointf_t& offset) { region -= offset; for (auto& ch : instances) @@ -1233,7 +1234,7 @@ void render_manager::rem_post(post_hook_t *hook) pimpl->postprocessing->rem_post(hook); } -wf::region_t render_manager::get_scheduled_damage() +wf::regionf_t render_manager::get_scheduled_damage() { return pimpl->damage_manager->get_scheduled_damage(get_target_framebuffer()); } @@ -1254,7 +1255,7 @@ void render_manager::damage(const wlr_box& box, bool repaint) pimpl->damage_manager->damage_buffer(fb.framebuffer_box_from_geometry_box(box), repaint); } -void render_manager::damage(const wf::region_t& region, bool repaint) +void render_manager::damage(const wf::regionf_t& region, bool repaint) { auto fb = pimpl->postprocessing->get_target_framebuffer(); pimpl->damage_manager->damage_buffer(fb.framebuffer_region_from_geometry_region(region), repaint); diff --git a/src/output/workspace-impl.cpp b/src/output/workspace-impl.cpp index 42253bab0..33c292b0d 100644 --- a/src/output/workspace-impl.cpp +++ b/src/output/workspace-impl.cpp @@ -240,7 +240,7 @@ struct workspace_set_t::impl } else { view->set_geometry({ - int(px * new_geometry.width), int(py * new_geometry.height), + (double)int(px * new_geometry.width), (double)int(py * new_geometry.height), wm.width, wm.height }); } diff --git a/src/output/workspace-stream.cpp b/src/output/workspace-stream.cpp index 23f564041..c48b6c2dc 100644 --- a/src/output/workspace-stream.cpp +++ b/src/output/workspace-stream.cpp @@ -21,13 +21,13 @@ class workspace_stream_node_t::workspace_stream_instance_t : public scene:: // True for each instance generated from a desktop environment view. std::vector is_desktop_environment; - wf::point_t get_offset() + wf::pointf_t get_offset() { auto g = self->output->get_relative_geometry(); auto cws = self->output->wset()->get_current_workspace(); - return wf::point_t{ - (self->ws.x - cws.x) * g.width, - (self->ws.y - cws.y) * g.height, + return wf::pointf_t{ + (double)((self->ws.x - cws.x) * g.width), + (double)((self->ws.y - cws.y) * g.height), }; } @@ -36,7 +36,7 @@ class workspace_stream_node_t::workspace_stream_instance_t : public scene:: scene::damage_callback push_damage) { this->self = self; - auto translate_and_push_damage = [this, push_damage] (wf::region_t damage) + auto translate_and_push_damage = [this, push_damage] (wf::regionf_t damage) { damage += -get_offset(); damage &= this->self->get_bounding_box(); @@ -76,7 +76,7 @@ class workspace_stream_node_t::workspace_stream_instance_t : public scene:: void schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { auto bbox = self->get_bounding_box(); auto our_damage = damage & bbox; @@ -132,9 +132,10 @@ class workspace_stream_node_t::workspace_stream_instance_t : public scene:: } } - void compute_visibility(wf::output_t *output, wf::region_t& visible) override + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { - scene::compute_visibility_from_list(instances, output, visible, -get_offset()); + scene::compute_visibility_from_list(instances, output, visible, + -get_offset()); } }; diff --git a/src/region.cpp b/src/region.cpp index 3a183465d..1db4537b0 100644 --- a/src/region.cpp +++ b/src/region.cpp @@ -1,7 +1,27 @@ #include #include +#include + /* Pixman helpers */ +wlr_fbox wlr_fbox_from_pixman_box(const pixman_box64f_t& box) +{ + return { + box.x1, box.y1, + box.x2 - box.x1, + box.y2 - box.y1 + }; +} + +wf::geometry_t geometry_from_pixman_box(const pixman_box64f_t& box) +{ + return { + box.x1, box.y1, + box.x2 - box.x1, + box.y2 - box.y1 + }; +} + wlr_box wlr_box_from_pixman_box(const pixman_box32_t& box) { return { @@ -20,6 +40,292 @@ pixman_box32_t pixman_box_from_wlr_box(const wlr_box& box) }; } +wf::regionf_t::regionf_t() +{ + pixman_region64f_init(&_region); +} + +wf::regionf_t::regionf_t(const pixman_region64f_t *region) : wf::regionf_t() +{ + pixman_region64f_copy(this->to_pixman(), region); +} + +wf::regionf_t::regionf_t(const wf::geometry_t& box) +{ + pixman_region64f_init_rectf(&_region, box.x, box.y, box.width, box.height); +} + +wf::regionf_t::~regionf_t() +{ + pixman_region64f_fini(&_region); +} + +wf::regionf_t::regionf_t(const wf::regionf_t& other) : wf::regionf_t() +{ + pixman_region64f_copy(this->to_pixman(), other.unconst()); +} + +wf::regionf_t::regionf_t(wf::regionf_t&& other) : wf::regionf_t() +{ + std::swap(this->_region, other._region); +} + +wf::regionf_t& wf::regionf_t::operator =(const wf::regionf_t& other) +{ + if (&other == this) + { + return *this; + } + + pixman_region64f_copy(&_region, other.unconst()); + return *this; +} + +wf::regionf_t& wf::regionf_t::operator =(wf::regionf_t&& other) +{ + if (&other == this) + { + return *this; + } + + std::swap(_region, other._region); + return *this; +} + +bool wf::regionf_t::empty() const +{ + return !pixman_region64f_not_empty(this->unconst()); +} + +void wf::regionf_t::clear() +{ + pixman_region64f_clear(&_region); +} + +void wf::regionf_t::expand_edges(double amount) +{ + pixman_region64f_t *region = this->to_pixman(); + if (amount == 0.0) + { + return; + } + + int nrects; + const pixman_box64f_t *src_rects = pixman_region64f_rectangles(region, &nrects); + auto *dst_rects = (pixman_box64f_t*)malloc(nrects * sizeof(pixman_box64f_t)); + if (!dst_rects) + { + return; + } + + for (int i = 0; i < nrects; ++i) + { + dst_rects[i].x1 = src_rects[i].x1 - amount; + dst_rects[i].x2 = src_rects[i].x2 + amount; + dst_rects[i].y1 = src_rects[i].y1 - amount; + dst_rects[i].y2 = src_rects[i].y2 + amount; + if ((dst_rects[i].x1 > dst_rects[i].x2) || (dst_rects[i].y1 > dst_rects[i].y2)) + { + dst_rects[i].x1 = dst_rects[i].x2 = dst_rects[i].y1 = dst_rects[i].y2 = 0.0; + } + } + + pixman_region64f_fini(region); + pixman_region64f_init_rects(region, dst_rects, nrects); + free(dst_rects); +} + +pixman_box64f_t wf::regionf_t::get_extents() const +{ + return *pixman_region64f_extents(this->unconst()); +} + +bool wf::regionf_t::contains_point(const wf::point_t& point) const +{ + return pixman_region64f_contains_pointf(this->unconst(), point.x, point.y, NULL); +} + +bool wf::regionf_t::contains_pointf(const wf::pointf_t& point) const +{ + return pixman_region64f_contains_pointf(this->unconst(), point.x, point.y, NULL); +} + +wf::regionf_t wf::regionf_t::operator +(const wf::pointf_t& vector) const +{ + wf::regionf_t result{*this}; + pixman_region64f_translatef(&result._region, vector.x, vector.y); + return result; +} + +wf::regionf_t& wf::regionf_t::operator +=(const wf::pointf_t& vector) +{ + pixman_region64f_translatef(&_region, vector.x, vector.y); + return *this; +} + +wf::regionf_t wf::regionf_t::operator -(const wf::pointf_t& vector) const +{ + wf::regionf_t result{*this}; + pixman_region64f_translatef(&result._region, -vector.x, -vector.y); + return result; +} + +wf::regionf_t& wf::regionf_t::operator -=(const wf::pointf_t& vector) +{ + pixman_region64f_translatef(&_region, -vector.x, -vector.y); + return *this; +} + +wf::regionf_t wf::regionf_t::operator *(double scale) const +{ + wf::regionf_t result; + for (auto it = begin(); it != end(); ++it) + { + result |= wf::geometry_t{ + it->x1 * scale, + it->y1 * scale, + (it->x2 - it->x1) * scale, + (it->y2 - it->y1) * scale, + }; + } + + return result; +} + +wf::regionf_t& wf::regionf_t::operator *=(double scale) +{ + *this = *this * scale; + return *this; +} + +wf::regionf_t wf::regionf_t::operator &(const wf::geometry_t& box) const +{ + wf::regionf_t result; + pixman_region64f_intersect_rectf(result.to_pixman(), this->unconst(), + box.x, box.y, box.width, box.height); + return result; +} + +wf::regionf_t wf::regionf_t::operator &(const wf::regionf_t& other) const +{ + wf::regionf_t result; + pixman_region64f_intersect(result.to_pixman(), this->unconst(), other.unconst()); + return result; +} + +wf::regionf_t& wf::regionf_t::operator &=(const wf::geometry_t& box) +{ + pixman_region64f_intersect_rectf(this->to_pixman(), this->to_pixman(), + box.x, box.y, box.width, box.height); + return *this; +} + +wf::regionf_t& wf::regionf_t::operator &=(const wf::regionf_t& other) +{ + pixman_region64f_intersect(this->to_pixman(), this->to_pixman(), other.unconst()); + return *this; +} + +wf::regionf_t wf::regionf_t::operator |(const wf::geometry_t& other) const +{ + wf::regionf_t result; + pixman_region64f_union_rectf(result.to_pixman(), this->unconst(), + other.x, other.y, other.width, other.height); + return result; +} + +wf::regionf_t wf::regionf_t::operator |(const wf::regionf_t& other) const +{ + wf::regionf_t result; + pixman_region64f_union(result.to_pixman(), this->unconst(), other.unconst()); + return result; +} + +wf::regionf_t& wf::regionf_t::operator |=(const wf::geometry_t& other) +{ + pixman_region64f_union_rectf(this->to_pixman(), this->to_pixman(), + other.x, other.y, other.width, other.height); + return *this; +} + +wf::regionf_t& wf::regionf_t::operator |=(const wf::regionf_t& other) +{ + pixman_region64f_union(this->to_pixman(), this->to_pixman(), other.unconst()); + return *this; +} + +wf::regionf_t wf::regionf_t::operator ^(const wf::geometry_t& box) const +{ + wf::regionf_t result; + wf::regionf_t sub{box}; + pixman_region64f_subtract(result.to_pixman(), this->unconst(), sub.to_pixman()); + return result; +} + +wf::regionf_t wf::regionf_t::operator ^(const wf::regionf_t& other) const +{ + wf::regionf_t result; + pixman_region64f_subtract(result.to_pixman(), this->unconst(), other.unconst()); + return result; +} + +wf::regionf_t& wf::regionf_t::operator ^=(const wf::geometry_t& box) +{ + wf::regionf_t sub{box}; + pixman_region64f_subtract(this->to_pixman(), this->to_pixman(), sub.to_pixman()); + return *this; +} + +wf::regionf_t& wf::regionf_t::operator ^=(const wf::regionf_t& other) +{ + pixman_region64f_subtract(this->to_pixman(), this->to_pixman(), other.unconst()); + return *this; +} + +pixman_region64f_t*wf::regionf_t::to_pixman() +{ + return &_region; +} + +const pixman_region64f_t*wf::regionf_t::to_pixman() const +{ + return &_region; +} + +pixman_region64f_t*wf::regionf_t::unconst() const +{ + return const_cast(&_region); +} + +const pixman_box64f_t*wf::regionf_t::begin() const +{ + int n; + return pixman_region64f_rectangles(unconst(), &n); +} + +const pixman_box64f_t*wf::regionf_t::end() const +{ + int n; + auto begin = pixman_region64f_rectangles(unconst(), &n); + return begin + n; +} + +wf::region_t to_framebuffer_region(const wf::regionf_t& region) +{ + wf::region_t result; + for (auto it = region.begin(); it != region.end(); ++it) + { + result |= wf::to_framebuffer_box(wf::geometry_t{ + it->x1, + it->y1, + it->x2 - it->x1, + it->y2 - it->y1, + }); + } + + return result; +} + wf::region_t::region_t() { pixman_region32_init(&_region); @@ -30,6 +336,11 @@ wf::region_t::region_t(const pixman_region32_t *region) : wf::region_t() pixman_region32_copy(this->to_pixman(), region); } +wf::region_t::region_t(const wf::geometry_t& box) : wf::region_t() +{ + *this |= box; +} + wf::region_t::region_t(const wlr_box& box) { pixman_region32_init_rect(&_region, box.x, box.y, box.width, box.height); @@ -62,6 +373,13 @@ wf::region_t& wf::region_t::operator =(const wf::region_t& other) return *this; } +wf::region_t& wf::region_t::operator =(const wf::geometry_t& other) +{ + clear(); + *this |= other; + return *this; +} + wf::region_t& wf::region_t::operator =(wf::region_t&& other) { if (&other == this) @@ -202,6 +520,11 @@ wf::region_t wf::region_t::operator &(const wlr_box& box) const return result; } +wf::region_t wf::region_t::operator &(const wf::geometry_t& box) const +{ + return *this & wf::containing_box(box); +} + wf::region_t wf::region_t::operator &(const wf::region_t& other) const { wf::region_t result; @@ -219,6 +542,11 @@ wf::region_t& wf::region_t::operator &=(const wlr_box& box) return *this; } +wf::region_t& wf::region_t::operator &=(const wf::geometry_t& box) +{ + return *this &= wf::containing_box(box); +} + wf::region_t& wf::region_t::operator &=(const wf::region_t& other) { pixman_region32_intersect(this->to_pixman(), @@ -237,6 +565,11 @@ wf::region_t wf::region_t::operator |(const wlr_box& other) const return result; } +wf::region_t wf::region_t::operator |(const wf::geometry_t& other) const +{ + return *this | wf::containing_box(other); +} + wf::region_t wf::region_t::operator |(const wf::region_t& other) const { wf::region_t result; @@ -253,6 +586,11 @@ wf::region_t& wf::region_t::operator |=(const wlr_box& other) return *this; } +wf::region_t& wf::region_t::operator |=(const wf::geometry_t& other) +{ + return *this |= wf::containing_box(other); +} + wf::region_t& wf::region_t::operator |=(const wf::region_t& other) { pixman_region32_union(this->to_pixman(), this->to_pixman(), other.unconst()); @@ -270,6 +608,11 @@ wf::region_t wf::region_t::operator ^(const wlr_box& box) const return result; } +wf::region_t wf::region_t::operator ^(const wf::geometry_t& box) const +{ + return *this ^ wf::containing_box(box); +} + wf::region_t wf::region_t::operator ^(const wf::region_t& other) const { wf::region_t result; @@ -288,6 +631,11 @@ wf::region_t& wf::region_t::operator ^=(const wlr_box& box) return *this; } +wf::region_t& wf::region_t::operator ^=(const wf::geometry_t& box) +{ + return *this ^= wf::containing_box(box); +} + wf::region_t& wf::region_t::operator ^=(const wf::region_t& other) { pixman_region32_subtract(this->to_pixman(), diff --git a/src/render.cpp b/src/render.cpp index 20b47471f..a271cceb8 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -181,11 +181,35 @@ static const wlr_drm_format *choose_format_from_set(const wlr_drm_format_set *se */ static wlr_box round_fbox_to_containing_box(wlr_fbox fbox) { + return wf::containing_box(fbox); +} + +/** + * Rasterize a projected destination box for texture rendering. + * + * wlroots render passes only accept integer destination boxes. For exact + * integer-sized projected content rendered at a fractional origin, using a + * containing box expands the destination by one extra pixel and forces + * resampling. Snap the origin down to the framebuffer grid, but preserve an + * exact integer projected size when we have one. + */ +static wlr_box round_fbox_to_texture_dst_box(wlr_fbox fbox) +{ + static constexpr double epsilon = 1e-6; + const int x = (int)std::floor(fbox.x); + const int y = (int)std::floor(fbox.y); + const double rounded_width = std::round(fbox.width); + const double rounded_height = std::round(fbox.height); + const int x2 = (int)((std::abs(fbox.width - rounded_width) < epsilon) ? + (x + rounded_width) : std::ceil(fbox.x + fbox.width)); + const int y2 = (int)((std::abs(fbox.height - rounded_height) < epsilon) ? + (y + rounded_height) : std::ceil(fbox.y + fbox.height)); + return wlr_box{ - .x = (int)std::floor(fbox.x), - .y = (int)std::floor(fbox.y), - .width = (int)std::ceil(fbox.x + fbox.width) - (int)std::floor(fbox.x), - .height = (int)std::ceil(fbox.y + fbox.height) - (int)std::floor(fbox.y), + .x = x, + .y = y, + .width = x2 - x, + .height = y2 - y, }; } @@ -238,8 +262,8 @@ wf::buffer_reallocation_result_t wf::auxilliary_buffer_t::allocate(wf::dimension // the code. static wf::option_wrapper_t max_buffer_size{"workarounds/max_buffer_size"}; const int FALLBACK_MAX_BUFFER_SIZE = 4096; - size.width = std::max(1.0f, std::ceil(size.width * scale)); - size.height = std::max(1.0f, std::ceil(size.height * scale)); + size.width = std::max(1, (int)std::ceil(size.width * scale)); + size.height = std::max(1, (int)std::ceil(size.height * scale)); size = sanitize_buffer_size(size, max_buffer_size); if (buffer.get_size() == size) @@ -350,7 +374,7 @@ void wf::render_buffer_t::do_blit(wlr_texture *src_wlr_tex, wlr_fbox src_box, opts.transform = WL_OUTPUT_TRANSFORM_NORMAL; opts.clip = NULL; opts.src_box = src_box; - opts.dst_box = dst_box; + opts.dst_box = wf::to_framebuffer_box(dst_box); wlr_render_pass_add_texture(pass, &opts); if (!wlr_render_pass_submit(pass)) { @@ -463,10 +487,11 @@ wf::render_target_t::~render_target_t() } } -wf::render_target_t wf::render_target_t::translated(wf::point_t offset) const +wf::render_target_t wf::render_target_t::translated(wf::pointf_t offset) const { render_target_t copy = *this; - copy.geometry = copy.geometry + offset; + copy.geometry.x += offset.x; + copy.geometry.y += offset.y; return copy; } @@ -503,17 +528,27 @@ wlr_fbox wf::render_target_t::framebuffer_box_from_geometry_box(wlr_fbox box) co wlr_box wf::render_target_t::framebuffer_box_from_geometry_box(wlr_box box) const { - wlr_fbox fbox = geometry_to_fbox(box); + wlr_fbox fbox = geometry_to_fbox(from_framebuffer_box(box)); wlr_fbox scaled_fbox = framebuffer_box_from_geometry_box(fbox); return round_fbox_to_containing_box(scaled_fbox); } -wf::region_t wf::render_target_t::framebuffer_region_from_geometry_region(const wf::region_t& region) const +wlr_box wf::render_target_t::framebuffer_box_from_geometry_box(wf::geometry_t box) const +{ + return round_fbox_to_containing_box(framebuffer_box_from_geometry_box(geometry_to_fbox(box))); +} + +wf::region_t wf::render_target_t::framebuffer_region_from_geometry_region(const wf::regionf_t& region) const { wf::region_t result; for (const auto& rect : region) { - result |= framebuffer_box_from_geometry_box(wlr_box_from_pixman_box(rect)); + result |= round_fbox_to_containing_box(framebuffer_box_from_geometry_box(wlr_fbox{ + rect.x1, + rect.y1, + rect.x2 - rect.x1, + rect.y2 - rect.y1, + })); } return result; @@ -548,15 +583,21 @@ wlr_fbox wf::render_target_t::geometry_fbox_from_framebuffer_box(wlr_fbox fb_box wlr_box wf::render_target_t::geometry_box_from_framebuffer_box(wlr_box fb_box) const { - return round_fbox_to_containing_box(geometry_fbox_from_framebuffer_box(geometry_to_fbox(fb_box))); + return round_fbox_to_containing_box( + geometry_fbox_from_framebuffer_box(geometry_to_fbox(from_framebuffer_box(fb_box)))); } -wf::region_t wf::render_target_t::geometry_region_from_framebuffer_region(const wf::region_t& region) const +wf::regionf_t wf::render_target_t::geometry_region_from_framebuffer_region(const wf::region_t& region) const { - wf::region_t result; + wf::regionf_t result; for (const auto& rect : region) { - result |= geometry_box_from_framebuffer_box(wlr_box_from_pixman_box(rect)); + result |= fbox_to_geometry(geometry_fbox_from_framebuffer_box(wlr_fbox{ + (double)rect.x1, + (double)rect.y1, + (double)(rect.x2 - rect.x1), + (double)(rect.y2 - rect.y1), + })); } return result; @@ -570,7 +611,7 @@ wf::render_pass_t::render_pass_t(const render_pass_params_t& p) wf::dassert(p.target.get_buffer(), "Cannot run a render pass without a valid target!"); } -wf::region_t wf::render_pass_t::run(const wf::render_pass_params_t& params) +wf::regionf_t wf::render_pass_t::run(const wf::render_pass_params_t& params) { wf::render_pass_t pass{params}; auto damage = pass.run_partial(); @@ -578,7 +619,7 @@ wf::region_t wf::render_pass_t::run(const wf::render_pass_params_t& params) return damage; } -wf::region_t wf::render_pass_t::run_partial() +wf::regionf_t wf::render_pass_t::run_partial() { auto accumulated_damage = params.damage; if (params.flags & RPASS_EMIT_SIGNALS) @@ -588,7 +629,7 @@ wf::region_t wf::render_pass_t::run_partial() wf::get_core().emit(&ev); } - wf::region_t swap_damage = accumulated_damage; + wf::regionf_t swap_damage = accumulated_damage; // Gather instructions std::vector instructions; @@ -645,14 +686,14 @@ wlr_render_pass*wf::render_pass_t::get_wlr_pass() return _get_pass(); } -void wf::render_pass_t::clear(const wf::region_t& region, const wf::color_t& color) +void wf::render_pass_t::clear(const wf::regionf_t& region, const wf::color_t& color) { auto box = wf::construct_box({0, 0}, params.target.get_size()); auto damage = params.target.framebuffer_region_from_geometry_region(region); wlr_render_rect_options opts; opts.blend_mode = WLR_RENDER_BLEND_MODE_NONE; - opts.box = box; + opts.box = wf::to_framebuffer_box(box); opts.clip = damage.to_pixman(); opts.color = { .r = static_cast(color.r), @@ -666,7 +707,7 @@ void wf::render_pass_t::clear(const wf::region_t& region, const wf::color_t& col void wf::render_pass_t::add_texture(const std::shared_ptr& texture, const wf::render_target_t& adjusted_target, const wlr_fbox& geometry, - const wf::region_t& damage, float alpha) + const wf::regionf_t& damage, float alpha) { if (wlr_renderer_is_gles2(this->get_wlr_renderer())) { @@ -694,7 +735,7 @@ void wf::render_pass_t::add_texture(const std::shared_ptr& textur adjusted_target.wl_transform); opts.clip = fb_damage.to_pixman(); opts.src_box = texture->get_source_box().value_or(wlr_fbox{0, 0, 0, 0}); - opts.dst_box = fbox_to_geometry(adjusted_target.framebuffer_box_from_geometry_box(geometry)); + opts.dst_box = round_fbox_to_texture_dst_box(adjusted_target.framebuffer_box_from_geometry_box(geometry)); auto ct = texture->get_color_transform(); wlr_color_primaries primaries{}; @@ -708,7 +749,7 @@ void wf::render_pass_t::add_texture(const std::shared_ptr& textur } void wf::render_pass_t::add_rect(const wf::color_t& color, const wf::render_target_t& adjusted_target, - const wlr_fbox& geometry, const wf::region_t& damage) + const wlr_fbox& geometry, const wf::regionf_t& damage) { if (wlr_renderer_is_gles2(this->get_wlr_renderer())) { @@ -725,21 +766,21 @@ void wf::render_pass_t::add_rect(const wf::color_t& color, const wf::render_targ }; opts.blend_mode = WLR_RENDER_BLEND_MODE_PREMULTIPLIED; opts.clip = fb_damage.to_pixman(); - opts.box = fbox_to_geometry(adjusted_target.framebuffer_box_from_geometry_box(geometry)); + opts.box = round_fbox_to_containing_box(adjusted_target.framebuffer_box_from_geometry_box(geometry)); wf::dassert(opts.box.width >= 0); wf::dassert(opts.box.height >= 0); wlr_render_pass_add_rect(_get_pass(), &opts); } void wf::render_pass_t::add_texture(const std::shared_ptr& texture, - const wf::render_target_t& adjusted_target, const wf::geometry_t& geometry, const wf::region_t& damage, + const wf::render_target_t& adjusted_target, const wf::geometry_t& geometry, const wf::regionf_t& damage, float alpha) { add_texture(texture, adjusted_target, geometry_to_fbox(geometry), damage, alpha); } void wf::render_pass_t::add_rect(const wf::color_t& color, const wf::render_target_t& adjusted_target, - const wf::geometry_t& geometry, const wf::region_t& damage) + const wf::geometry_t& geometry, const wf::regionf_t& damage) { add_rect(color, adjusted_target, geometry_to_fbox(geometry), damage); } diff --git a/src/view/compositor-view.cpp b/src/view/compositor-view.cpp index 620c0637f..af8412e65 100644 --- a/src/view/compositor-view.cpp +++ b/src/view/compositor-view.cpp @@ -20,7 +20,8 @@ static void render_colored_rect(const wf::scene::render_instruction_t& data, wf::color_t premultiply{color.r * color.a, color.g * color.a, color.b * color.a, color.a}; w = std::max(w, 0); h = std::max(h, 0); - data.pass->add_rect(premultiply, data.target, wf::geometry_t{x, y, w, h}, data.damage); + data.pass->add_rect(premultiply, data.target, + wf::geometry_t{(double)x, (double)y, (double)w, (double)h}, data.damage); } class wf::color_rect_view_t::color_rect_node_t : public wf::scene::floating_inner_node_t diff --git a/src/view/layer-shell/layer-shell-node.cpp b/src/view/layer-shell/layer-shell-node.cpp index efd98aee7..27388b15f 100644 --- a/src/view/layer-shell/layer-shell-node.cpp +++ b/src/view/layer-shell/layer-shell-node.cpp @@ -79,14 +79,26 @@ wf::keyboard_focus_node_t wf::layer_shell_node_t::keyboard_refocus(wf::output_t return wf::keyboard_focus_node_t{}; } -wf::region_t wf::layer_shell_node_t::get_opaque_region() const +wf::regionf_t wf::layer_shell_node_t::get_opaque_region() const { auto view = _view.lock(); if (view && view->is_mapped() && view->get_wlr_surface()) { auto surf = view->get_wlr_surface(); - wf::region_t region{&surf->opaque_region}; + wf::regionf_t region; + int nrects = 0; + const auto rects = pixman_region32_rectangles(&surf->opaque_region, &nrects); + for (int i = 0; i < nrects; i++) + { + region |= wf::geometry_t{ + (double)rects[i].x1, + (double)rects[i].y1, + (double)(rects[i].x2 - rects[i].x1), + (double)(rects[i].y2 - rects[i].y1), + }; + } + region += this->get_offset(); return region; } diff --git a/src/view/layer-shell/layer-shell-node.hpp b/src/view/layer-shell/layer-shell-node.hpp index fd1372965..c8dbadcdd 100644 --- a/src/view/layer-shell/layer-shell-node.hpp +++ b/src/view/layer-shell/layer-shell-node.hpp @@ -24,7 +24,7 @@ class layer_shell_node_t : public wf::scene::translation_node_t, scene::damage_callback push_damage, wf::output_t *output) override; std::shared_ptr to_texture() const override; - wf::region_t get_opaque_region() const override; + wf::regionf_t get_opaque_region() const override; protected: std::weak_ptr _view; diff --git a/src/view/layer-shell/layer-shell.cpp b/src/view/layer-shell/layer-shell.cpp index 51d565423..5d409a4f3 100644 --- a/src/view/layer-shell/layer-shell.cpp +++ b/src/view/layer-shell/layer-shell.cpp @@ -99,11 +99,11 @@ class wayfire_layer_shell_view : public wf::view_interface_t void move(int x, int y) { wf::region_t damage = last_bounding_box; - surface_root_node->set_offset({x, y}); + surface_root_node->set_offset({(double)x, (double)y}); this->geometry.x = x; this->geometry.y = y; - last_bounding_box = get_bounding_box(); + last_bounding_box = wf::from_framebuffer_box(get_bounding_box()); damage |= last_bounding_box; wf::scene::damage_node(get_root_node(), last_bounding_box); wf::scene::update(get_root_node(), wf::scene::update_flag::GEOMETRY); @@ -542,7 +542,7 @@ void wayfire_layer_shell_view::commit() wf::scene::damage_node(get_root_node(), last_bounding_box); } - this->last_bounding_box = get_bounding_box(); + this->last_bounding_box = wf::from_framebuffer_box(get_bounding_box()); auto state = &lsurface->current; /* Update the keyboard focus enabled state. If a refocusing is needed, i.e diff --git a/src/view/toplevel-node.cpp b/src/view/toplevel-node.cpp index 1c07627c0..cf9d97c8e 100644 --- a/src/view/toplevel-node.cpp +++ b/src/view/toplevel-node.cpp @@ -98,7 +98,7 @@ class toplevel_view_render_instance_t : public wf::scene::translation_node_insta } auto og = output->get_relative_geometry(); - if (!(view->get_bounding_box() & og)) + if (!(wf::from_framebuffer_box(view->get_bounding_box()) & og)) { return wf::scene::direct_scanout::SKIP; } @@ -141,14 +141,26 @@ std::shared_ptr wf::toplevel_view_node_t::to_texture() const return nullptr; } -wf::region_t wf::toplevel_view_node_t::get_opaque_region() const +wf::regionf_t wf::toplevel_view_node_t::get_opaque_region() const { auto view = _view.lock(); if (view && view->is_mapped() && view->get_wlr_surface()) { auto surf = view->get_wlr_surface(); - wf::region_t region{&surf->opaque_region}; + wf::regionf_t region; + int nrects = 0; + const auto rects = pixman_region32_rectangles(&surf->opaque_region, &nrects); + for (int i = 0; i < nrects; i++) + { + region |= wf::geometry_t{ + (double)rects[i].x1, + (double)rects[i].y1, + (double)(rects[i].x2 - rects[i].x1), + (double)(rects[i].y2 - rects[i].y1), + }; + } + region += get_offset(); return region; } diff --git a/src/view/toplevel-node.hpp b/src/view/toplevel-node.hpp index b9c88d7ef..eded77af9 100644 --- a/src/view/toplevel-node.hpp +++ b/src/view/toplevel-node.hpp @@ -25,7 +25,7 @@ class toplevel_view_node_t : public wf::scene::translation_node_t, scene::damage_callback push_damage, wf::output_t *output) override; std::shared_ptr to_texture() const override; - wf::region_t get_opaque_region() const override; + wf::regionf_t get_opaque_region() const override; protected: std::weak_ptr _view; diff --git a/src/view/toplevel-view.cpp b/src/view/toplevel-view.cpp index 5f91f5507..5ff0578a8 100644 --- a/src/view/toplevel-view.cpp +++ b/src/view/toplevel-view.cpp @@ -22,10 +22,10 @@ static void reposition_relative_to_parent(wayfire_toplevel_view view) auto parent_geometry = view->parent->get_pending_geometry(); auto wm_geometry = view->get_pending_geometry(); - // Guess which workspace the parent is on - wf::point_t center = { - parent_geometry.x + parent_geometry.width / 2, - parent_geometry.y + parent_geometry.height / 2, + // Guess which workspace the parent is on from its logical center. + wf::pointf_t center = { + parent_geometry.x + parent_geometry.width / 2.0, + parent_geometry.y + parent_geometry.height / 2.0, }; if (view->parent->is_mapped()) @@ -39,8 +39,8 @@ static void reposition_relative_to_parent(wayfire_toplevel_view view) { auto scr_size = view->get_output()->get_screen_size(); wf::point_t parent_ws = { - (int)std::floor(1.0 * center.x / scr_size.width), - (int)std::floor(1.0 * center.y / scr_size.height), + (int)std::floor(center.x / scr_size.width), + (int)std::floor(center.y / scr_size.height), }; auto workarea = view->get_output()->render->get_ws_box( @@ -53,7 +53,7 @@ static void reposition_relative_to_parent(wayfire_toplevel_view view) wm_geometry.y = workarea.height / 2 - wm_geometry.height / 2; } - wm_geometry = wf::clamp(wm_geometry, workarea); + wm_geometry = wf::clamp(wm_geometry, wf::from_framebuffer_box(workarea)); } /* make sure view is visible afterwards */ diff --git a/src/view/translation-node.cpp b/src/view/translation-node.cpp index 0128c8b3b..9b39e994c 100644 --- a/src/view/translation-node.cpp +++ b/src/view/translation-node.cpp @@ -9,12 +9,12 @@ wf::scene::translation_node_t::translation_node_t(bool is_structure) : wf::pointf_t wf::scene::translation_node_t::to_local(const wf::pointf_t& point) { - return point - wf::pointf_t{get_offset()}; + return point - get_offset(); } wf::pointf_t wf::scene::translation_node_t::to_global(const wf::pointf_t& point) { - return point + wf::pointf_t{get_offset()}; + return point + get_offset(); } std::string wf::scene::translation_node_t::stringify() const @@ -36,12 +36,12 @@ wf::geometry_t wf::scene::translation_node_t::get_bounding_box() return get_children_bounding_box() + get_offset(); } -wf::point_t wf::scene::translation_node_t::get_offset() const +wf::pointf_t wf::scene::translation_node_t::get_offset() const { return offset; } -void wf::scene::translation_node_t::set_offset(wf::point_t offset) +void wf::scene::translation_node_t::set_offset(wf::pointf_t offset) { this->offset = offset; } @@ -76,7 +76,7 @@ wf::scene::translation_node_instance_t::translation_node_instance_t( void wf::scene::translation_node_instance_t::regen_instances() { children.clear(); - auto push_damage_child = [=] (wf::region_t child_damage) + auto push_damage_child = [=] (wf::regionf_t child_damage) { child_damage += self->get_offset(); push_damage(child_damage); @@ -93,12 +93,12 @@ void wf::scene::translation_node_instance_t::regen_instances() void wf::scene::translation_node_instance_t::schedule_instructions( std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) + const wf::render_target_t& target, wf::regionf_t& damage) { - wf::region_t our_damage = damage & self->get_bounding_box(); + wf::regionf_t our_damage = damage & self->get_bounding_box(); if (!our_damage.empty()) { - wf::point_t offset = self->get_offset(); + wf::pointf_t offset = self->get_offset(); damage += -offset; auto our_target = target.translated(-offset); @@ -121,7 +121,7 @@ void wf::scene::translation_node_instance_t::presentation_feedback(wf::output_t wf::scene::direct_scanout wf::scene::translation_node_instance_t::try_scanout(wf::output_t *output) { - if (self->get_offset() != wf::point_t{0, 0}) + if (self->get_offset() != wf::pointf_t{0.0, 0.0}) { return wf::scene::direct_scanout::OCCLUSION; } @@ -129,7 +129,7 @@ wf::scene::direct_scanout wf::scene::translation_node_instance_t::try_scanout(wf return try_scanout_from_list(this->children, output); } -void wf::scene::translation_node_instance_t::compute_visibility(wf::output_t *output, wf::region_t& visible) +void wf::scene::translation_node_instance_t::compute_visibility(wf::output_t *output, wf::regionf_t& visible) { compute_visibility_from_list(children, output, visible, self->get_offset()); } diff --git a/src/view/view-3d.cpp b/src/view/view-3d.cpp index 14556117b..e6a50a073 100644 --- a/src/view/view-3d.cpp +++ b/src/view/view-3d.cpp @@ -36,11 +36,11 @@ wf::geometry_t get_bbox_for_node(scene::node_t *node, wf::geometry_t box) const auto p4 = node->to_global( wf::pointf_t(box.x + box.width, box.y + box.height)); - const int x1 = std::floor(std::min({p1.x, p2.x, p3.x, p4.x})); - const int x2 = std::ceil(std::max({p1.x, p2.x, p3.x, p4.x})); - const int y1 = std::floor(std::min({p1.y, p2.y, p3.y, p4.y})); - const int y2 = std::ceil(std::max({p1.y, p2.y, p3.y, p4.y})); - return wlr_box{x1, y1, x2 - x1, y2 - y1}; + const double x1 = std::floor(std::min({p1.x, p2.x, p3.x, p4.x})); + const double x2 = std::ceil(std::max({p1.x, p2.x, p3.x, p4.x})); + const double y1 = std::floor(std::min({p1.y, p2.y, p3.y, p4.y})); + const double y2 = std::ceil(std::max({p1.y, p2.y, p3.y, p4.y})); + return {x1, y1, x2 - x1, y2 - y1}; } wf::geometry_t get_bbox_for_node(scene::node_ptr node, wf::geometry_t box) @@ -237,14 +237,13 @@ wf::geometry_t view_2d_transformer_t::get_bounding_box() return get_bbox_for_node(this, get_children_bounding_box()); } -static void transform_linear_damage(node_t *self, wf::region_t& damage) +static void transform_linear_damage(node_t *self, wf::regionf_t& damage) { auto copy = damage; damage.clear(); for (auto& box : copy) { - damage |= - get_bbox_for_node(self, wlr_box_from_pixman_box(box)); + damage |= get_bbox_for_node(self, geometry_from_pixman_box(box)); } } @@ -254,7 +253,7 @@ class view_2d_render_instance_t : public: using transformer_render_instance_t::transformer_render_instance_t; - void transform_damage_region(wf::region_t& damage) override + void transform_damage_region(wf::regionf_t& damage) override { transform_linear_damage(self.get(), damage); } @@ -295,7 +294,7 @@ class view_2d_render_instance_t : for (auto& box : data.damage) { - wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box)); + wf::gles::render_target_logic_scissor(data.target, box); // OpenGL::clear({1, 0, 0, 1}); OpenGL::render_transformed_texture(tex, bbox, ortho * flat_transform, glm::vec4{1.0, 1.0, 1.0, self->get_alpha()}); @@ -519,7 +518,7 @@ class view_3d_render_instance_t : using transformer_render_instance_t::transformer_render_instance_t; - void transform_damage_region(wf::region_t& damage) override + void transform_damage_region(wf::regionf_t& damage) override { transform_linear_damage(self.get(), damage); } @@ -546,7 +545,7 @@ class view_3d_render_instance_t : wf::gles::bind_render_buffer(data.target); for (auto& box : data.damage) { - wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box)); + wf::gles::render_target_logic_scissor(data.target, box); OpenGL::render_transformed_texture(tex, quad.geometry, {}, transform, self->color); } diff --git a/src/view/view.cpp b/src/view/view.cpp index fb71dd119..54aab20ae 100644 --- a/src/view/view.cpp +++ b/src/view/view.cpp @@ -72,7 +72,7 @@ void wf::view_interface_t::close() wlr_box wf::view_interface_t::get_bounding_box() { - return get_transformed_node()->get_bounding_box(); + return wf::to_framebuffer_box(get_transformed_node()->get_bounding_box()); } bool wf::view_interface_t::is_focusable() const diff --git a/src/view/wlr-subsurface-controller.cpp b/src/view/wlr-subsurface-controller.cpp index b5ba23b24..564a8c471 100644 --- a/src/view/wlr-subsurface-controller.cpp +++ b/src/view/wlr-subsurface-controller.cpp @@ -69,7 +69,7 @@ wf::wlr_subsurface_root_node_t::wlr_subsurface_root_node_t(wlr_subsurface *subsu on_subsurface_destroy.connect(&subsurface->events.destroy); on_subsurface_commit.connect(&subsurface->surface->events.commit); // Set initial offset but don't damage yet - this->offset = {subsurface->current.x, subsurface->current.y}; + this->offset = {(double)subsurface->current.x, (double)subsurface->current.y}; } std::string wf::wlr_subsurface_root_node_t::stringify() const @@ -79,8 +79,8 @@ std::string wf::wlr_subsurface_root_node_t::stringify() const bool wf::wlr_subsurface_root_node_t::update_offset(bool apply_damage) { - wf::point_t offset = {subsurface->current.x, subsurface->current.y}; - const bool changed = offset != get_offset(); + wf::pointf_t offset = {(double)subsurface->current.x, (double)subsurface->current.y}; + const bool changed = offset != get_offset(); if (changed && apply_damage) { diff --git a/src/view/wlr-surface-node.cpp b/src/view/wlr-surface-node.cpp index d8487e43b..525eab799 100644 --- a/src/view/wlr-surface-node.cpp +++ b/src/view/wlr-surface-node.cpp @@ -115,10 +115,35 @@ void wf::scene::surface_state_t::merge_state(wlr_surface *surface) this->seq = surface->current.seq; - wf::region_t current_damage; - wlr_surface_get_effective_damage(surface, current_damage.to_pixman()); + wf::region_t current_damage_raw; + wlr_surface_get_effective_damage(surface, current_damage_raw.to_pixman()); + wf::regionf_t current_damage; + for (const auto& rect : current_damage_raw) + { + current_damage |= geometry_from_pixman_box({ + (double)rect.x1, + (double)rect.y1, + (double)rect.x2, + (double)rect.y2, + }); + } + this->accumulated_damage |= current_damage; - this->opaque_region = wf::region_t{&surface->opaque_region}; + + wf::regionf_t opaque_region; + int nrects = 0; + const auto rects = pixman_region32_rectangles(&surface->opaque_region, &nrects); + for (int i = 0; i < nrects; i++) + { + opaque_region |= wf::geometry_t{ + (double)rects[i].x1, + (double)rects[i].y1, + (double)(rects[i].x2 - rects[i].x1), + (double)(rects[i].y2 - rects[i].y1), + }; + } + + this->opaque_region = std::move(opaque_region); } wf::scene::surface_state_t::~surface_state_t() @@ -278,7 +303,7 @@ class wf::scene::wlr_surface_node_t::wlr_surface_render_instance_t : public rend wf::output_t *visible_on; damage_callback push_damage; - wf::region_t last_visibility; + wf::regionf_t last_visibility; wf::signal::connection_t on_surface_damage = [=] (node_damage_signal *data) @@ -320,7 +345,8 @@ class wf::scene::wlr_surface_node_t::wlr_surface_render_instance_t : public rend this->push_damage = push_damage; this->visible_on = visible_on; self->connect(&on_surface_damage); - this->last_visibility |= wlr_box{INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX}; + this->last_visibility |= wf::geometry_t{(double)(INT_MIN / 2), (double)(INT_MIN / 2), (double)INT_MAX, + (double)INT_MAX}; } ~wlr_surface_render_instance_t() @@ -332,9 +358,9 @@ class wf::scene::wlr_surface_node_t::wlr_surface_render_instance_t : public rend } void schedule_instructions(std::vector& instructions, - const wf::render_target_t& target, wf::region_t& damage) override + const wf::render_target_t& target, wf::regionf_t& damage) override { - wf::region_t our_damage = damage & self->get_bounding_box(); + wf::regionf_t our_damage = damage & self->get_bounding_box(); if (!our_damage.empty()) { instructions.push_back(render_instruction_t{ @@ -386,7 +412,7 @@ class wf::scene::wlr_surface_node_t::wlr_surface_render_instance_t : public rend } // Finally, the opaque region must be the full surface. - wf::region_t non_opaque = output->get_relative_geometry(); + wf::region_t non_opaque = wf::region_t{wf::to_framebuffer_box(output->get_relative_geometry())}; non_opaque ^= wf::region_t{&wlr_surf->opaque_region}; if (!non_opaque.empty()) { @@ -409,7 +435,7 @@ class wf::scene::wlr_surface_node_t::wlr_surface_render_instance_t : public rend } } - void compute_visibility(wf::output_t *output, wf::region_t& visible) override + void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { auto our_box = self->get_bounding_box(); on_frame_done.disconnect(); diff --git a/src/view/xdg-shell.cpp b/src/view/xdg-shell.cpp index b6a767bbd..9fe099311 100644 --- a/src/view/xdg-shell.cpp +++ b/src/view/xdg-shell.cpp @@ -316,7 +316,8 @@ void wayfire_xdg_popup::unconstrain() auto parent_offset = toplevel_parent->get_surface_root_node()->to_global({0, 0}); box.x -= parent_offset.x; box.y -= parent_offset.y; - wlr_xdg_popup_unconstrain_from_box(popup, &box); + auto fb_box = wf::to_framebuffer_box(box); + wlr_xdg_popup_unconstrain_from_box(popup, &fb_box); } void wayfire_xdg_popup::destroy() @@ -366,7 +367,7 @@ void wayfire_xdg_popup::update_size() geometry.height = current_size.height; /* Damage new size */ - last_bounding_box = get_bounding_box(); + last_bounding_box = wf::from_framebuffer_box(get_bounding_box()); wf::scene::damage_node(get_root_node(), last_bounding_box); wf::scene::update(this->get_surface_root_node(), wf::scene::update_flag::GEOMETRY); } @@ -401,11 +402,11 @@ std::string wayfire_xdg_popup::get_title() void wayfire_xdg_popup::move(int x, int y) { wf::scene::damage_node(get_root_node(), last_bounding_box); - surface_root_node->set_offset({x, y}); + surface_root_node->set_offset({(double)x, (double)y}); geometry.x = x; geometry.y = y; damage(); - last_bounding_box = get_bounding_box(); + last_bounding_box = wf::from_framebuffer_box(get_bounding_box()); wf::scene::update(this->get_surface_root_node(), wf::scene::update_flag::GEOMETRY); } diff --git a/src/view/xdg-shell/xdg-toplevel-view.cpp b/src/view/xdg-shell/xdg-toplevel-view.cpp index c042ac7fd..937b10f64 100644 --- a/src/view/xdg-shell/xdg-toplevel-view.cpp +++ b/src/view/xdg-shell/xdg-toplevel-view.cpp @@ -525,7 +525,7 @@ void wf::fini_xdg_decoration_handlers() void wf::xdg_toplevel_view_t::start_map_tx() { LOGC(VIEWS, "Start mapping ", self()); - wlr_box box = xdg_toplevel->base->geometry; + wf::geometry_t box = wf::from_framebuffer_box(xdg_toplevel->base->geometry); auto margins = wtoplevel->pending().margins; box.x = wtoplevel->pending().geometry.x + margins.left; box.y = wtoplevel->pending().geometry.y + margins.top; diff --git a/src/view/xdg-shell/xdg-toplevel.cpp b/src/view/xdg-shell/xdg-toplevel.cpp index 7ce63866a..f651cb4b2 100644 --- a/src/view/xdg-shell/xdg-toplevel.cpp +++ b/src/view/xdg-shell/xdg-toplevel.cpp @@ -198,10 +198,10 @@ void wf::xdg_toplevel_t::handle_surface_commit() { if (toplevel) { - if (this->wm_offset != wf::origin(toplevel->base->geometry)) + if (this->wm_offset != wf::origin(wf::from_framebuffer_box(toplevel->base->geometry))) { // Trigger reppositioning in the view implementation - this->wm_offset = wf::origin(toplevel->base->geometry); + this->wm_offset = wf::origin(wf::from_framebuffer_box(toplevel->base->geometry)); xdg_toplevel_applied_state_signal event_applied; event_applied.old_state = current(); this->emit(&event_applied); @@ -241,7 +241,7 @@ void wf::xdg_toplevel_t::apply_pending_state() if (toplevel) { - this->wm_offset = wf::origin(toplevel->base->geometry); + this->wm_offset = wf::origin(wf::from_framebuffer_box(toplevel->base->geometry)); } } @@ -257,7 +257,7 @@ void wf::xdg_toplevel_t::emit_ready() wf::dimensions_t wf::xdg_toplevel_t::get_current_wlr_toplevel_size() { // Size did change => Start a new transaction to change the size. - return wf::dimensions(toplevel->base->geometry); + return wf::dimensions(wf::from_framebuffer_box(toplevel->base->geometry)); } wf::dimensions_t wf::xdg_toplevel_t::get_min_size() diff --git a/src/view/xdg-shell/xdg-toplevel.hpp b/src/view/xdg-shell/xdg-toplevel.hpp index 77a4355c2..f22d012a5 100644 --- a/src/view/xdg-shell/xdg-toplevel.hpp +++ b/src/view/xdg-shell/xdg-toplevel.hpp @@ -43,7 +43,7 @@ class xdg_toplevel_t : public toplevel_t, public std::enable_shared_from_thisgeometry.value(), cx, cy, &dx, &dy); + auto geometry = wf::to_framebuffer_box(data->geometry.value()); + wlr_box_closest_point(&geometry, cx, cy, &dx, &dy); const double dist = (dx - cx) * (dx - cx) + (dy - cy) * (dy - cy); if (dist < closest_dist) { diff --git a/src/view/xwayland/xwayland-toplevel-view.hpp b/src/view/xwayland/xwayland-toplevel-view.hpp index 3b37939f9..5441c00aa 100644 --- a/src/view/xwayland/xwayland-toplevel-view.hpp +++ b/src/view/xwayland/xwayland-toplevel-view.hpp @@ -40,7 +40,8 @@ class wayfire_xwayland_view : public wf::toplevel_view_interface_t, public wayfi void handle_client_configure(wlr_xwayland_surface_configure_event *ev) override { - wf::geometry_t configure_geometry = wlr_box{ev->x, ev->y, ev->width, ev->height}; + wf::geometry_t configure_geometry = wf::from_framebuffer_box( + wlr_box{ev->x, ev->y, ev->width, ev->height}); if (get_output()) { configure_geometry = wf::xw::calculate_wayfire_geometry(get_output(), configure_geometry); @@ -276,7 +277,7 @@ class wayfire_xwayland_view : public wf::toplevel_view_interface_t, public wayfi { /* Save geometry which the window has put itself in */ wf::geometry_t save_geometry = { - xw->x, xw->y, xw->width, xw->height + (double)xw->x, (double)xw->y, (double)xw->width, (double)xw->height }; /* Make sure geometry is properly visible on the view output */ @@ -303,10 +304,10 @@ class wayfire_xwayland_view : public wf::toplevel_view_interface_t, public wayfi } wf::geometry_t desired_geometry = { - xw->x, - xw->y, - xw->surface->current.width, - xw->surface->current.height + (double)xw->x, + (double)xw->y, + (double)xw->surface->current.width, + (double)xw->surface->current.height }; desired_geometry = wf::xw::calculate_wayfire_geometry(get_output(), desired_geometry); diff --git a/src/view/xwayland/xwayland-toplevel.hpp b/src/view/xwayland/xwayland-toplevel.hpp index b079bf39a..d83ee82ec 100644 --- a/src/view/xwayland/xwayland-toplevel.hpp +++ b/src/view/xwayland/xwayland-toplevel.hpp @@ -53,7 +53,7 @@ class xwayland_toplevel_t : public wf::toplevel_t, public std::enable_shared_fro wlr_xwayland_surface *xw; float output_scale = 1.0; - wf::point_t output_offset = {0, 0}; + wf::pointf_t output_offset = {0, 0}; void handle_surface_commit(); void reconfigure_xwayland_surface(); diff --git a/src/view/xwayland/xwayland-unmanaged-view.hpp b/src/view/xwayland/xwayland-unmanaged-view.hpp index ac0e07883..d931a41bd 100644 --- a/src/view/xwayland/xwayland-unmanaged-view.hpp +++ b/src/view/xwayland/xwayland-unmanaged-view.hpp @@ -101,12 +101,14 @@ class wayfire_unmanaged_xwayland_view : public wayfire_xwayland_view_internal_ba void update_geometry_from_xsurface() { static wf::option_wrapper_t force_xwayland_scaling{"workarounds/force_xwayland_scaling"}; - wf::region_t damage_region = last_bounding_box; // last bounding box - damage_region |= get_bounding_box(); // in case resize happened since last move + wf::regionf_t damage_region = last_bounding_box; // last bounding box + damage_region |= wf::from_framebuffer_box(get_bounding_box()); // in case resize happened since last + // move wf::scene::damage_node(get_root_node(), damage_region); auto wo = wf::xw::find_xwayland_surface_output(xw); - auto new_geometry = wf::xw::calculate_wayfire_geometry(wo, {xw->x, xw->y, xw->width, xw->height}); + auto new_geometry = wf::xw::calculate_wayfire_geometry(wo, { + (double)xw->x, (double)xw->y, (double)xw->width, (double)xw->height}); surface_root_node->set_offset(wf::origin(new_geometry)); if (main_surface && force_xwayland_scaling) { @@ -125,7 +127,7 @@ class wayfire_unmanaged_xwayland_view : public wayfire_xwayland_view_internal_ba } LOGC(XWL, "Xwayland unmanaged surface ", self(), " new geometry ", new_geometry); - last_bounding_box = get_bounding_box(); + last_bounding_box = wf::from_framebuffer_box(get_bounding_box()); wf::scene::damage_node(get_root_node(), last_bounding_box); wf::scene::update(surface_root_node, wf::scene::update_flag::GEOMETRY); } diff --git a/test/geometry/region_test.cpp b/test/geometry/region_test.cpp index 5d7f7415f..f925a0f4e 100644 --- a/test/geometry/region_test.cpp +++ b/test/geometry/region_test.cpp @@ -25,11 +25,28 @@ std::vector as_boxes(const wf::region_t& region) return boxes; } + +std::vector as_boxes(const wf::regionf_t& region) +{ + std::vector boxes; + for (auto it = region.begin(); it != region.end(); ++it) + { + boxes.push_back({it->x1, it->y1, it->x2 - it->x1, it->y2 - it->y1}); + } + + std::sort(boxes.begin(), boxes.end(), [] (const auto& a, const auto& b) + { + return std::tie(a.x, a.y, a.width, a.height) < + std::tie(b.x, b.y, b.width, b.height); + }); + + return boxes; +} } TEST_CASE("region supports copy move and clear semantics") { - wf::region_t original{{0, 0, 10, 10}}; + wf::region_t original{wf::geometry_t{0, 0, 10, 10}}; wf::region_t copy = original; copy += wf::point_t{5, 0}; @@ -41,7 +58,10 @@ TEST_CASE("region supports copy move and clear semantics") wf::region_t moved = std::move(copy); auto moved_boxes = as_boxes(moved); REQUIRE(moved_boxes.size() == 1); - REQUIRE(moved_boxes[0] == wf::geometry_t{5, 0, 10, 10}); + REQUIRE(moved_boxes[0].x == 5); + REQUIRE(moved_boxes[0].y == 0); + REQUIRE(moved_boxes[0].width == 10); + REQUIRE(moved_boxes[0].height == 10); REQUIRE(copy.empty()); moved.clear(); @@ -50,13 +70,23 @@ TEST_CASE("region supports copy move and clear semantics") TEST_CASE("region set operations preserve expected coverage") { - wf::region_t region{{0, 0, 10, 10}}; + wf::region_t region{wf::geometry_t{0, 0, 10, 10}}; auto intersection = region & wlr_box{5, 5, 10, 10}; - REQUIRE(as_boxes(intersection) == std::vector{{5, 5, 5, 5}}); + auto intersection_boxes = as_boxes(intersection); + REQUIRE(intersection_boxes.size() == 1); + REQUIRE(intersection_boxes[0].x == 5); + REQUIRE(intersection_boxes[0].y == 5); + REQUIRE(intersection_boxes[0].width == 5); + REQUIRE(intersection_boxes[0].height == 5); auto united = region | wlr_box{10, 0, 5, 10}; - REQUIRE(as_boxes(united) == std::vector{{0, 0, 15, 10}}); + auto united_boxes = as_boxes(united); + REQUIRE(united_boxes.size() == 1); + REQUIRE(united_boxes[0].x == 0); + REQUIRE(united_boxes[0].y == 0); + REQUIRE(united_boxes[0].width == 15); + REQUIRE(united_boxes[0].height == 10); auto subtracted = region ^ wlr_box{2, 2, 6, 6}; REQUIRE(subtracted.contains_point({1, 1})); @@ -71,26 +101,98 @@ TEST_CASE("region set operations preserve expected coverage") TEST_CASE("region translation scaling and float containment work together") { - wf::region_t region{{1, 2, 3, 4}}; + wf::region_t region{wf::geometry_t{1, 2, 3, 4}}; auto shifted = region + wf::point_t{2, 3}; auto scaled = shifted * 2.0f; - REQUIRE(as_boxes(shifted) == std::vector{{3, 5, 3, 4}}); - REQUIRE(as_boxes(scaled) == std::vector{{6, 10, 6, 8}}); + auto shifted_boxes = as_boxes(shifted); + REQUIRE(shifted_boxes.size() == 1); + REQUIRE(shifted_boxes[0].x == 3); + REQUIRE(shifted_boxes[0].y == 5); + REQUIRE(shifted_boxes[0].width == 3); + REQUIRE(shifted_boxes[0].height == 4); + + auto scaled_boxes = as_boxes(scaled); + REQUIRE(scaled_boxes.size() == 1); + REQUIRE(scaled_boxes[0].x == 6); + REQUIRE(scaled_boxes[0].y == 10); + REQUIRE(scaled_boxes[0].width == 6); + REQUIRE(scaled_boxes[0].height == 8); REQUIRE(scaled.contains_pointf({6.5, 10.5})); REQUIRE_FALSE(scaled.contains_pointf({12.5, 18.5})); } TEST_CASE("region edge expansion handles no-op growth and shrink") { - wf::region_t region{{0, 0, 10, 10}}; + wf::region_t region{wf::geometry_t{0, 0, 10, 10}}; region.expand_edges(0); - REQUIRE(as_boxes(region) == std::vector{{0, 0, 10, 10}}); + auto boxes0 = as_boxes(region); + REQUIRE(boxes0.size() == 1); + REQUIRE(boxes0[0].x == 0); + REQUIRE(boxes0[0].y == 0); + REQUIRE(boxes0[0].width == 10); + REQUIRE(boxes0[0].height == 10); region.expand_edges(2); - REQUIRE(as_boxes(region) == std::vector{{-2, -2, 14, 14}}); + auto boxes1 = as_boxes(region); + REQUIRE(boxes1.size() == 1); + REQUIRE(boxes1[0].x == -2); + REQUIRE(boxes1[0].y == -2); + REQUIRE(boxes1[0].width == 14); + REQUIRE(boxes1[0].height == 14); region.expand_edges(-3); - REQUIRE(as_boxes(region) == std::vector{{1, 1, 8, 8}}); + auto boxes2 = as_boxes(region); + REQUIRE(boxes2.size() == 1); + REQUIRE(boxes2[0].x == 1); + REQUIRE(boxes2[0].y == 1); + REQUIRE(boxes2[0].width == 8); + REQUIRE(boxes2[0].height == 8); +} + +TEST_CASE("floating region supports logical geometry operations") +{ + wf::regionf_t region{{1.25, 2.5, 3.5, 4.25}}; + auto shifted = region + wf::pointf_t{2, 3}; + auto scaled = shifted * 2.0; + + auto shifted_boxes = as_boxes(shifted); + REQUIRE(shifted_boxes == std::vector{{3.25, 5.5, 3.5, 4.25}}); + + auto scaled_boxes = as_boxes(scaled); + REQUIRE(scaled_boxes == std::vector{{6.5, 11.0, 7.0, 8.5}}); + REQUIRE(scaled.contains_pointf({6.5, 11.0})); + REQUIRE(scaled.contains_pointf({13.25, 19.25})); + REQUIRE_FALSE(scaled.contains_pointf({13.75, 19.75})); +} + +TEST_CASE("floating region converts conservatively to framebuffer region") +{ + wf::regionf_t logical{{1.25, 2.5, 3.5, 4.25}}; + auto framebuffer = to_framebuffer_region(logical); + auto framebuffer_boxes = as_boxes(framebuffer); + REQUIRE(framebuffer_boxes.size() == 1); + REQUIRE(framebuffer_boxes[0].x == 1); + REQUIRE(framebuffer_boxes[0].y == 2); + REQUIRE(framebuffer_boxes[0].width == 4); + REQUIRE(framebuffer_boxes[0].height == 5); +} + +TEST_CASE("geometry to integer box conversion contains fractional extents") +{ + auto box = wf::containing_box(wf::geometry_t{0.9, 1.1, 10.2, 5.8}); + REQUIRE(box.x == 0); + REQUIRE(box.y == 1); + REQUIRE(box.width == 12); + REQUIRE(box.height == 6); + + wf::region_t region; + region |= wf::geometry_t{0.9, 1.1, 10.2, 5.8}; + auto boxes = as_boxes(region); + REQUIRE(boxes.size() == 1); + REQUIRE(boxes[0].x == 0); + REQUIRE(boxes[0].y == 1); + REQUIRE(boxes[0].width == 12); + REQUIRE(boxes[0].height == 6); } diff --git a/test/protocol/meson.build b/test/protocol/meson.build index 4b9b37cf3..b90ffd52c 100644 --- a/test/protocol/meson.build +++ b/test/protocol/meson.build @@ -15,12 +15,45 @@ layer_shell_client_header = custom_target( output: 'wlr-layer-shell-client-protocol.h', command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@']) +viewporter_client_xml = join_paths(wl_protocol_dir, 'stable/viewporter/viewporter.xml') + +viewporter_client_header = custom_target( + 'viewporter-client-header', + input: viewporter_client_xml, + output: 'viewporter-client-protocol.h', + command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@']) + +viewporter_client_code = custom_target( + 'viewporter-client-code', + input: viewporter_client_xml, + output: 'viewporter-client-protocol.c', + command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@']) + +fractional_scale_client_xml = join_paths(wl_protocol_dir, + 'staging/fractional-scale/fractional-scale-v1.xml') + +fractional_scale_client_header = custom_target( + 'fractional-scale-client-header', + input: fractional_scale_client_xml, + output: 'fractional-scale-v1-client-protocol.h', + command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@']) + +fractional_scale_client_code = custom_target( + 'fractional-scale-client-code', + input: fractional_scale_client_xml, + output: 'fractional-scale-v1-client-protocol.c', + command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@']) + test_support_sources = [ '../support/headless-core-harness.cpp', '../support/wayland-client-utils.cpp', '../support/wayland-layer-shell-client-bridge.c', '../support/wayland-layer-shell-client.cpp', '../support/wayland-xdg-client.cpp', + fractional_scale_client_header, + fractional_scale_client_code, + viewporter_client_header, + viewporter_client_code, layer_shell_client_header, xdg_shell_client_header, ] @@ -47,5 +80,17 @@ layer_shell_test = executable( ], install: false) +scaling_test = executable( + 'scaling-test', + 'scaling-test.cpp', + test_support_sources, + dependencies: [doctest, libwayfire, wayland_client], + cpp_args: [ + '-DTEST_METADATA_DIR="' + meson.project_source_root() + '/metadata"', + '-DTEST_DEFAULTS_INI="' + meson.project_source_root() + '/wayfire.ini"', + ], + install: false) + test('Xdg-shell test', xdg_shell_test) test('Layer-shell test', layer_shell_test) +test('Scaling test', scaling_test) diff --git a/test/protocol/scaling-test.cpp b/test/protocol/scaling-test.cpp new file mode 100644 index 000000000..ecc85f522 --- /dev/null +++ b/test/protocol/scaling-test.cpp @@ -0,0 +1,146 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../support/headless-core-harness.hpp" +#include "../support/wayland-xdg-client.hpp" + +TEST_CASE("fractional-scale render stays pixel-aligned away from origin") +{ + wf::test::headless_core_harness_t harness; + auto *output = harness.output(); + REQUIRE(output != nullptr); + + auto config = wf::get_core().output_layout->get_current_configuration(); + REQUIRE(config.count(output->handle) == 1); + + config.at(output->handle).scale = 5.0 / 3.0; + REQUIRE(wf::get_core().output_layout->apply_configuration(config)); + + wf::test::wayland_xdg_client_t client{harness.socket_name()}; + REQUIRE(harness.run_until([&] + { + client.dispatch_once(); + return client.has_required_globals(); + })); + + std::vector mapped; + wf::signal::connection_t on_map = [&] (wf::view_mapped_signal *ev) + { + mapped.push_back(ev->view); + }; + wf::get_core().connect(&on_map); + + client.create_toplevel("rendering test", "org.wayfire.RenderingTest"); + REQUIRE(harness.run_until([&] + { + client.dispatch_once(); + return client.has_pending_configure(); + })); + + client.attach_and_commit(200, 120); + REQUIRE(harness.run_until([&] () { return mapped.size() == 1; })); + + auto view = wf::toplevel_cast(mapped.front()); + REQUIRE(view != nullptr); + REQUIRE(view->get_output() == output); + + view->move(1, 1); + + REQUIRE(harness.run_until([&] + { + client.dispatch_once(); + return client.last_fractional_scale().has_value(); + })); + + REQUIRE(client.last_fractional_scale().has_value()); + const uint32_t fractional_scale = client.last_fractional_scale().value(); + const int preferred_scale = client.last_preferred_buffer_scale(); + + CHECK(preferred_scale == 1); + CHECK(fractional_scale == 200); + + const int logical_width = 6; + const int logical_height = 6; + const int buffer_width = 10; + const int buffer_height = 10; + + std::vector pixels(buffer_width * buffer_height); + for (int y = 0; y < buffer_height; ++y) + { + for (int x = 0; x < buffer_width; ++x) + { + pixels[y * buffer_width + x] = ((x + y) % 2) ? 0x00ff0000u : 0x0000ff00u; + } + } + + client.attach_with_fractional_scale(logical_width, logical_height, pixels); + REQUIRE(harness.run_until([&] + { + client.dispatch_once(); + return view->get_geometry().x == 1 && view->get_geometry().y == 1 && + view->get_geometry().width == logical_width && + view->get_geometry().height == logical_height; + })); + + auto output_pixels = harness.capture_output_pixels(); + const int output_width = output->handle->width; + const int output_height = output->handle->height; + + std::set unique_pixels(output_pixels.begin(), output_pixels.end()); + + int min_x = output_width; + int min_y = output_height; + int max_x = -1; + int max_y = -1; + int mixed_pixels = 0; + + const uint32_t red = 0xff0000ffu; + const uint32_t green = 0xff00ff00u; + const uint32_t background = 0xff000000u; + + INFO("unique pixel count: ", unique_pixels.size()); + for (auto pixel : unique_pixels) + { + std::ostringstream out; + out << std::hex << pixel; + INFO("pixel value: 0x", out.str()); + } + + for (int y = 0; y < output_height; ++y) + { + for (int x = 0; x < output_width; ++x) + { + auto pixel = output_pixels[y * output_width + x]; + if (pixel != background) + { + min_x = std::min(min_x, x); + min_y = std::min(min_y, y); + max_x = std::max(max_x, x); + max_y = std::max(max_y, y); + } + + if ((pixel != background) && (pixel != red) && (pixel != green)) + { + mixed_pixels++; + } + } + } + + REQUIRE(max_x >= min_x); + REQUIRE(max_y >= min_y); + CHECK(min_x == 1); + CHECK(min_y == 1); + CHECK(max_x - min_x + 1 == buffer_width); + CHECK(max_y - min_y + 1 == buffer_height); + CHECK(mixed_pixels == 0); +} diff --git a/test/protocol/xdg-shell-test.cpp b/test/protocol/xdg-shell-test.cpp index 0ca86cd68..eeff3b47a 100644 --- a/test/protocol/xdg-shell-test.cpp +++ b/test/protocol/xdg-shell-test.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include diff --git a/test/support/headless-core-harness.cpp b/test/support/headless-core-harness.cpp index 91165145b..71428b37b 100644 --- a/test/support/headless-core-harness.cpp +++ b/test/support/headless-core-harness.cpp @@ -5,10 +5,13 @@ #include #include #include +#include #include #include #include +#include +#include #include #include @@ -18,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +45,7 @@ class test_config_backend_t : public wf::config_backend_t wf::config::load_configuration_options_from_string(config, "[core]\n" + "background_color = 0.0 0.0 0.0 1.0\n" "plugins = \n" "xwayland = false\n" "\n" @@ -114,6 +119,59 @@ struct wf::test::headless_core_harness_t::impl std::string test_runtime_dir; bool had_wayland_display = false; bool had_xdg_runtime_dir = false; + + std::vector capture_output_pixels() + { + auto *wo = core->output_layout->get_outputs().front(); + std::optional> captured_pixels; + wf::post_hook_t capture_hook = [&] (wf::auxilliary_buffer_t& source, const wf::render_buffer_t&) + { + auto framebuffer = source.get_renderbuffer(); + auto *buffer = framebuffer.get_buffer(); + if (!buffer) + { + return; + } + + auto *tex = wlr_texture_from_buffer(core->renderer, buffer); + if (!tex) + { + throw std::runtime_error("Failed to create texture from output buffer"); + } + + auto size = framebuffer.get_size(); + std::vector pixels(size.width * size.height); + wlr_texture_read_pixels_options opts{}; + opts.data = pixels.data(); + opts.format = DRM_FORMAT_ABGR8888; + opts.stride = size.width * 4; + if (!wlr_texture_read_pixels(tex, &opts)) + { + wlr_texture_destroy(tex); + throw std::runtime_error("Failed to read output pixels"); + } + + wlr_texture_destroy(tex); + captured_pixels = std::move(pixels); + }; + + wo->render->add_post(&capture_hook); + wo->render->damage_whole(); + wo->render->schedule_redraw(); + for (int i = 0; i < 50 && !captured_pixels.has_value(); ++i) + { + wl_event_loop_dispatch(core->ev_loop, 10); + wl_display_flush_clients(core->display); + } + + wo->render->rem_post(&capture_hook); + if (!captured_pixels.has_value()) + { + throw std::runtime_error("No output buffer available for capture"); + } + + return *captured_pixels; + } }; wf::test::headless_core_harness_t::headless_core_harness_t() @@ -263,3 +321,8 @@ const std::string& wf::test::headless_core_harness_t::socket_name() const { return priv->core->wayland_display; } + +std::vector wf::test::headless_core_harness_t::capture_output_pixels() +{ + return priv->capture_output_pixels(); +} diff --git a/test/support/headless-core-harness.hpp b/test/support/headless-core-harness.hpp index 91011be33..2fa9a8037 100644 --- a/test/support/headless-core-harness.hpp +++ b/test/support/headless-core-harness.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace wf::test @@ -24,6 +25,7 @@ class headless_core_harness_t wf::output_t *output() const; const std::string& socket_name() const; + std::vector capture_output_pixels(); private: struct impl; diff --git a/test/support/wayland-client-utils.cpp b/test/support/wayland-client-utils.cpp index eec83082a..b64674674 100644 --- a/test/support/wayland-client-utils.cpp +++ b/test/support/wayland-client-utils.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include @@ -15,14 +17,26 @@ namespace { int create_shm_file(size_t size) { - char name[] = "/wayfire-test-XXXXXX"; - int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + static uint64_t counter = 0; + int fd = -1; + std::string name; + for (int attempt = 0; attempt < 16; ++attempt) + { + name = "/wayfire-test-" + std::to_string(getpid()) + "-" + + std::to_string(counter++); + fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) + { + break; + } + } + if (fd < 0) { return -1; } - shm_unlink(name); + shm_unlink(name.c_str()); if (ftruncate(fd, size) < 0) { close(fd); @@ -86,3 +100,35 @@ wl_buffer*wf::test::create_shm_buffer(wl_shm *shm, int width, int height, uint32 close(fd); return buffer; } + +wl_buffer*wf::test::create_shm_buffer(wl_shm *shm, int width, int height, const std::vector& pixels) +{ + const int stride = width * 4; + const size_t size = stride * height; + if (pixels.size() != (size_t)(width * height)) + { + throw std::runtime_error("Pixel buffer size does not match dimensions"); + } + + int fd = create_shm_file(size); + if (fd < 0) + { + throw std::runtime_error("Failed to create shared memory file for test buffer"); + } + + void *data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + close(fd); + throw std::runtime_error("Failed to mmap test buffer"); + } + + std::memcpy(data, pixels.data(), size); + auto *pool = wl_shm_create_pool(shm, fd, size); + auto *buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, + WL_SHM_FORMAT_XRGB8888); + wl_shm_pool_destroy(pool); + munmap(data, size); + close(fd); + return buffer; +} diff --git a/test/support/wayland-client-utils.hpp b/test/support/wayland-client-utils.hpp index cb769b297..1c8864e04 100644 --- a/test/support/wayland-client-utils.hpp +++ b/test/support/wayland-client-utils.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include struct wl_buffer; struct wl_display; @@ -10,4 +11,5 @@ namespace wf::test { void wayland_dispatch_once(wl_display *display, int timeout_ms = 0); wl_buffer *create_shm_buffer(wl_shm *shm, int width, int height, uint32_t color); +wl_buffer *create_shm_buffer(wl_shm *shm, int width, int height, const std::vector& pixels); } diff --git a/test/support/wayland-xdg-client.cpp b/test/support/wayland-xdg-client.cpp index 1ee681b38..212c7884a 100644 --- a/test/support/wayland-xdg-client.cpp +++ b/test/support/wayland-xdg-client.cpp @@ -2,11 +2,15 @@ #include #include +#include #include +#include #include #include +#include "fractional-scale-v1-client-protocol.h" +#include "viewporter-client-protocol.h" #include "wayland-client-utils.hpp" #include "xdg-shell-client-protocol.h" @@ -17,14 +21,23 @@ struct wf::test::wayland_xdg_client_t::impl wl_compositor *compositor = nullptr; wl_shm *shm = nullptr; xdg_wm_base *wm_base = nullptr; + wp_fractional_scale_manager_v1 *fractional_scale_manager = nullptr; + wp_viewporter *viewporter = nullptr; wl_surface *surface = nullptr; ::xdg_surface *shell_surface = nullptr; ::xdg_toplevel *shell_toplevel = nullptr; - wl_buffer *buffer = nullptr; + wp_fractional_scale_v1 *fractional_scale = nullptr; + wp_viewport *viewport = nullptr; + wl_buffer *buffer = nullptr; bool configured = false; uint32_t configure_serial = 0; + std::optional> toplevel_size; + bool toplevel_configure_fullscreen = false; + int preferred_buffer_scale = 1; + std::optional preferred_fractional_scale; + std::pair committed_buffer_size = {0, 0}; static void handle_registry_global(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) @@ -41,7 +54,16 @@ struct wf::test::wayland_xdg_client_t::impl } else if (std::string{interface} == xdg_wm_base_interface.name) { self->wm_base = static_cast(wl_registry_bind(registry, - name, &xdg_wm_base_interface, std::min(version, 2u))); + name, &xdg_wm_base_interface, std::min(version, 7u))); + } else if (std::string{interface} == wp_fractional_scale_manager_v1_interface.name) + { + self->fractional_scale_manager = + static_cast(wl_registry_bind(registry, + name, &wp_fractional_scale_manager_v1_interface, 1)); + } else if (std::string{interface} == wp_viewporter_interface.name) + { + self->viewporter = static_cast(wl_registry_bind(registry, + name, &wp_viewporter_interface, 1)); } } @@ -62,6 +84,38 @@ struct wf::test::wayland_xdg_client_t::impl .ping = handle_ping, }; + static void handle_surface_enter(void*, wl_surface*, wl_output*) + {} + + static void handle_surface_leave(void*, wl_surface*, wl_output*) + {} + + static void handle_preferred_buffer_scale(void *data, wl_surface*, int32_t factor) + { + auto *self = static_cast(data); + self->preferred_buffer_scale = factor; + } + + static void handle_preferred_buffer_transform(void*, wl_surface*, uint32_t) + {} + + static constexpr wl_surface_listener surface_listener = { + .enter = handle_surface_enter, + .leave = handle_surface_leave, + .preferred_buffer_scale = handle_preferred_buffer_scale, + .preferred_buffer_transform = handle_preferred_buffer_transform, + }; + + static void handle_fractional_preferred_scale(void *data, wp_fractional_scale_v1*, uint32_t scale) + { + auto *self = static_cast(data); + self->preferred_fractional_scale = scale; + } + + static constexpr wp_fractional_scale_v1_listener fractional_scale_listener = { + .preferred_scale = handle_fractional_preferred_scale, + }; + static void handle_xdg_surface_configure(void *data, ::xdg_surface *surface, uint32_t serial) { @@ -74,6 +128,41 @@ struct wf::test::wayland_xdg_client_t::impl static constexpr ::xdg_surface_listener xdg_surface_listener = { .configure = handle_xdg_surface_configure, }; + + static void handle_toplevel_configure(void *data, ::xdg_toplevel*, int32_t width, + int32_t height, wl_array *states) + { + auto *self = static_cast(data); + self->toplevel_size = {{width, height}}; + self->toplevel_configure_fullscreen = false; + + auto *state = static_cast(states->data); + const size_t count = states->size / sizeof(uint32_t); + for (size_t i = 0; i < count; ++i) + { + if (state[i] == XDG_TOPLEVEL_STATE_FULLSCREEN) + { + self->toplevel_configure_fullscreen = true; + break; + } + } + } + + static void handle_toplevel_close(void*, ::xdg_toplevel*) + {} + + static void handle_toplevel_configure_bounds(void*, ::xdg_toplevel*, int32_t, int32_t) + {} + + static void handle_toplevel_wm_capabilities(void*, ::xdg_toplevel*, wl_array*) + {} + + static constexpr ::xdg_toplevel_listener xdg_toplevel_listener = { + .configure = handle_toplevel_configure, + .close = handle_toplevel_close, + .configure_bounds = handle_toplevel_configure_bounds, + .wm_capabilities = handle_toplevel_wm_capabilities, + }; }; wf::test::wayland_xdg_client_t::wayland_xdg_client_t(const std::string& socket_name) @@ -93,6 +182,16 @@ wf::test::wayland_xdg_client_t::wayland_xdg_client_t(const std::string& socket_n wf::test::wayland_xdg_client_t::~wayland_xdg_client_t() { destroy_toplevel(); + if (priv->fractional_scale_manager) + { + wp_fractional_scale_manager_v1_destroy(priv->fractional_scale_manager); + } + + if (priv->viewporter) + { + wp_viewporter_destroy(priv->viewporter); + } + if (priv->wm_base) { xdg_wm_base_destroy(priv->wm_base); @@ -146,7 +245,7 @@ bool wf::test::wayland_xdg_client_t::dispatch_until_configure(int max_iterations bool wf::test::wayland_xdg_client_t::has_required_globals() const { - return priv->compositor && priv->shm && priv->wm_base; + return priv->compositor && priv->shm && priv->wm_base && priv->viewporter; } void wf::test::wayland_xdg_client_t::create_toplevel(const std::string& title, @@ -159,9 +258,21 @@ void wf::test::wayland_xdg_client_t::create_toplevel(const std::string& title, xdg_wm_base_add_listener(priv->wm_base, &impl::wm_base_listener, priv.get()); priv->surface = wl_compositor_create_surface(priv->compositor); + wl_surface_add_listener(priv->surface, &impl::surface_listener, priv.get()); + if (priv->fractional_scale_manager) + { + priv->fractional_scale = wp_fractional_scale_manager_v1_get_fractional_scale( + priv->fractional_scale_manager, priv->surface); + wp_fractional_scale_v1_add_listener(priv->fractional_scale, + &impl::fractional_scale_listener, priv.get()); + } + + priv->viewport = wp_viewporter_get_viewport(priv->viewporter, priv->surface); + priv->shell_surface = xdg_wm_base_get_xdg_surface(priv->wm_base, priv->surface); xdg_surface_add_listener(priv->shell_surface, &impl::xdg_surface_listener, priv.get()); priv->shell_toplevel = xdg_surface_get_toplevel(priv->shell_surface); + xdg_toplevel_add_listener(priv->shell_toplevel, &impl::xdg_toplevel_listener, priv.get()); xdg_toplevel_set_title(priv->shell_toplevel, title.c_str()); xdg_toplevel_set_app_id(priv->shell_toplevel, app_id.c_str()); @@ -179,6 +290,69 @@ uint32_t wf::test::wayland_xdg_client_t::last_configure_serial() const return priv->configure_serial; } +std::optional> wf::test::wayland_xdg_client_t::last_toplevel_size() const +{ + return priv->toplevel_size; +} + +bool wf::test::wayland_xdg_client_t::last_toplevel_configure_fullscreen() const +{ + return priv->toplevel_configure_fullscreen; +} + +int wf::test::wayland_xdg_client_t::last_preferred_buffer_scale() const +{ + return priv->preferred_buffer_scale; +} + +std::optional wf::test::wayland_xdg_client_t::last_fractional_scale() const +{ + return priv->preferred_fractional_scale; +} + +void wf::test::wayland_xdg_client_t::attach_with_fractional_scale(int surface_width, int surface_height) +{ + if (!priv->preferred_fractional_scale) + { + throw std::runtime_error("No preferred fractional scale advertised yet"); + } + + const double scale = *priv->preferred_fractional_scale / 120.0; + const auto round_half_away_from_zero = [] (double value) + { + return int(std::copysign(std::floor(std::abs(value) + 0.5), value)); + }; + + const int buffer_width = round_half_away_from_zero(surface_width * scale); + const int buffer_height = round_half_away_from_zero(surface_height * scale); + + wl_surface_set_buffer_scale(priv->surface, 1); + wp_viewport_set_destination(priv->viewport, surface_width, surface_height); + attach_and_commit(buffer_width, buffer_height); +} + +void wf::test::wayland_xdg_client_t::attach_with_fractional_scale(int surface_width, int surface_height, + const std::vector& pixels) +{ + if (!priv->preferred_fractional_scale) + { + throw std::runtime_error("No preferred fractional scale advertised yet"); + } + + const double scale = *priv->preferred_fractional_scale / 120.0; + const auto round_half_away_from_zero = [] (double value) + { + return int(std::copysign(std::floor(std::abs(value) + 0.5), value)); + }; + + const int buffer_width = round_half_away_from_zero(surface_width * scale); + const int buffer_height = round_half_away_from_zero(surface_height * scale); + + wl_surface_set_buffer_scale(priv->surface, 1); + wp_viewport_set_destination(priv->viewport, surface_width, surface_height); + attach_and_commit(buffer_width, buffer_height, pixels); +} + void wf::test::wayland_xdg_client_t::ack_last_configure() { if (!priv->configured) @@ -189,9 +363,30 @@ void wf::test::wayland_xdg_client_t::ack_last_configure() xdg_surface_ack_configure(priv->shell_surface, priv->configure_serial); } +void wf::test::wayland_xdg_client_t::clear_pending_configure() +{ + priv->configured = false; + priv->toplevel_size.reset(); + priv->toplevel_configure_fullscreen = false; + priv->preferred_fractional_scale.reset(); +} + void wf::test::wayland_xdg_client_t::attach_and_commit(int width, int height) { priv->buffer = create_shm_buffer(priv->shm, width, height, 0xff336699u); + priv->committed_buffer_size = {width, height}; + + wl_surface_attach(priv->surface, priv->buffer, 0, 0); + wl_surface_damage_buffer(priv->surface, 0, 0, width, height); + wl_surface_commit(priv->surface); + wl_display_flush(priv->display); +} + +void wf::test::wayland_xdg_client_t::attach_and_commit(int width, int height, + const std::vector& pixels) +{ + priv->buffer = create_shm_buffer(priv->shm, width, height, pixels); + priv->committed_buffer_size = {width, height}; wl_surface_attach(priv->surface, priv->buffer, 0, 0); wl_surface_damage_buffer(priv->surface, 0, 0, width, height); @@ -199,6 +394,11 @@ void wf::test::wayland_xdg_client_t::attach_and_commit(int width, int height) wl_display_flush(priv->display); } +std::pair wf::test::wayland_xdg_client_t::last_committed_buffer_size() const +{ + return priv->committed_buffer_size; +} + void wf::test::wayland_xdg_client_t::commit_surface() { wl_surface_commit(priv->surface); @@ -213,6 +413,18 @@ void wf::test::wayland_xdg_client_t::destroy_toplevel() priv->buffer = nullptr; } + if (priv->viewport) + { + wp_viewport_destroy(priv->viewport); + priv->viewport = nullptr; + } + + if (priv->fractional_scale) + { + wp_fractional_scale_v1_destroy(priv->fractional_scale); + priv->fractional_scale = nullptr; + } + if (priv->shell_toplevel) { xdg_toplevel_destroy(priv->shell_toplevel); diff --git a/test/support/wayland-xdg-client.hpp b/test/support/wayland-xdg-client.hpp index 4797cf53d..f9d0f4fdc 100644 --- a/test/support/wayland-xdg-client.hpp +++ b/test/support/wayland-xdg-client.hpp @@ -4,6 +4,7 @@ #include #include #include +#include struct wl_display; struct wl_registry; @@ -36,8 +37,18 @@ class wayland_xdg_client_t void create_toplevel(const std::string& title, const std::string& app_id); bool has_pending_configure() const; uint32_t last_configure_serial() const; + std::optional> last_toplevel_size() const; + bool last_toplevel_configure_fullscreen() const; + int last_preferred_buffer_scale() const; + std::optional last_fractional_scale() const; + void attach_with_fractional_scale(int surface_width, int surface_height); + void attach_with_fractional_scale(int surface_width, int surface_height, + const std::vector& pixels); void ack_last_configure(); + void clear_pending_configure(); void attach_and_commit(int width, int height); + void attach_and_commit(int width, int height, const std::vector& pixels); + std::pair last_committed_buffer_size() const; void commit_surface(); void destroy_toplevel();