diff --git a/plugins/single_plugins/move.cpp b/plugins/single_plugins/move.cpp index cd4270866..d9b45ff0f 100644 --- a/plugins/single_plugins/move.cpp +++ b/plugins/single_plugins/move.cpp @@ -49,7 +49,7 @@ class wf_move_mirror_view : public wf::mirror_view_t virtual void close() { if (show_animation) - emit_view_pre_unmap(self()); + emit_view_pre_unmap(); wf::mirror_view_t::close(); } diff --git a/plugins/single_plugins/place.cpp b/plugins/single_plugins/place.cpp index 11271ce04..47da2c33a 100644 --- a/plugins/single_plugins/place.cpp +++ b/plugins/single_plugins/place.cpp @@ -20,14 +20,16 @@ class wayfire_place_window : public wf::plugin_interface_t created_cb = [=] (wf::signal_data_t *data) { + auto ev = (map_view_signal*) (data); auto view = get_signaled_view(data); if (view->role != wf::VIEW_ROLE_TOPLEVEL || view->parent || - view->fullscreen || view->tiled_edges) + view->fullscreen || view->tiled_edges || ev->is_positioned) { return; } + ev->is_positioned = true; auto workarea = output->workspace->get_workarea(); auto mode = placement_mode->as_string(); diff --git a/src/api/signal-definitions.hpp b/src/api/signal-definitions.hpp index acfe8d947..9ad8765ab 100644 --- a/src/api/signal-definitions.hpp +++ b/src/api/signal-definitions.hpp @@ -14,10 +14,15 @@ wayfire_view get_signaled_view(wf::signal_data_t *data); using create_view_signal = _view_signal; using destroy_view_signal = _view_signal; -using map_view_signal = _view_signal; using unmap_view_signal = _view_signal; using pre_unmap_view_signal = _view_signal; +struct map_view_signal : public _view_signal +{ + /* Indicates whether the position already has its initial posittion */ + bool is_positioned = false; +}; + /* Indicates the view is no longer available, for ex. it has been minimized * or unmapped */ using view_disappeared_signal = _view_signal; diff --git a/src/api/view.hpp b/src/api/view.hpp index 1ea24d676..564ffae90 100644 --- a/src/api/view.hpp +++ b/src/api/view.hpp @@ -401,28 +401,29 @@ class view_interface_t : public surface_interface_t, public wf::object_base_t * Called whenever the minimized, tiled, fullscreened * or activated state changes */ virtual void desktop_state_updated(); -}; -/** - * Emit the view map signal. It indicates that a view has been mapped, i.e. - * plugins can now "work" with it. Note that not all views will emit the map - * event. - */ -void emit_view_map(wayfire_view view); + /** + * Emit the view map signal. It indicates that a view has been mapped, i.e. + * plugins can now "work" with it. Note that not all views will emit the map + * event. + */ + virtual void emit_view_map(); -/** - * Emit the view unmap signal. It indicates that the view is in the process of - * being destroyed. Most plugins should stop any actions they have on the view. - */ -void emit_view_unmap(wayfire_view view); + /** + * Emit the view unmap signal. It indicates that the view is in the process of + * being destroyed. Most plugins should stop any actions they have on the view. + */ + virtual void emit_view_unmap(); + + /** + * Emit the view pre-unmap signal. It is emitted right before the view + * destruction start. At this moment a plugin can still take a snapshot of the + * view. Note that not all views emit the pre-unmap signal, however the unmap + * signal is mandatory for all views. + */ + virtual void emit_view_pre_unmap(); +}; -/** - * Emit the view pre-unmap signal. It is emitted right before the view - * destruction start. At this moment a plugin can still take a snapshot of the - * view. Note that not all views emit the pre-unmap signal, however the unmap - * signal is mandatory for all views. - */ -void emit_view_pre_unmap(wayfire_view view); wayfire_view wl_surface_to_wayfire_view(wl_resource *surface); } diff --git a/src/view/compositor-view.cpp b/src/view/compositor-view.cpp index 47e257fd9..3993b35a8 100644 --- a/src/view/compositor-view.cpp +++ b/src/view/compositor-view.cpp @@ -41,14 +41,14 @@ void wf::mirror_view_t::close() if (!base_view) return; - emit_view_pre_unmap(self()); + emit_view_pre_unmap(); base_view->disconnect_signal("unmap", &base_view_unmapped); base_view->disconnect_signal("damaged-region", &base_view_damaged); base_view = nullptr; emit_map_state_change(this); - emit_view_unmap(self()); + emit_view_unmap(); unref(); } @@ -138,7 +138,7 @@ void wf::color_rect_view_t::close() { this->_is_mapped = false; - emit_view_unmap(self()); + emit_view_unmap(); emit_map_state_change(this); unref(); diff --git a/src/view/view-impl.cpp b/src/view/view-impl.cpp index f9a78ddc0..9a09a132f 100644 --- a/src/view/view-impl.cpp +++ b/src/view/view-impl.cpp @@ -256,14 +256,6 @@ void wf::wlr_view_t::commit() this->last_bounding_box = get_bounding_box(); } -void wf::emit_view_map(wayfire_view view) -{ - map_view_signal data; - data.view = view; - view->get_output()->emit_signal("map-view", &data); - view->emit_signal("map", &data); -} - void wf::wlr_view_t::map(wlr_surface *surface) { wlr_surface_base_t::map(surface); @@ -279,44 +271,18 @@ void wf::wlr_view_t::map(wlr_surface *surface) } damage(); - emit_view_map(self()); + emit_view_map(); /* Might trigger repositioning */ set_toplevel_parent(this->parent); } -void wf::emit_view_unmap(wayfire_view view) -{ - unmap_view_signal data; - data.view = view; - - if (view->get_output()) - { - view->get_output()->emit_signal("unmap-view", &data); - view->get_output()->emit_signal("view-disappeared", &data); - } - - view->emit_signal("unmap", &data); - view->emit_signal("disappeared", &data); -} - -void wf::emit_view_pre_unmap(wayfire_view view) -{ - pre_unmap_view_signal data; - data.view = view; - - if (view->get_output()) - view->get_output()->emit_signal("pre-unmap-view", &data); - - view->emit_signal("pre-unmap", &data); -} - void wf::wlr_view_t::unmap() { damage(); /* Pre-unmap is typically used for animations. If the view is a regular * toplevel view, we don't need to animate */ if (this->role == wf::VIEW_ROLE_TOPLEVEL) - emit_view_pre_unmap(self()); + emit_view_pre_unmap(); destroy_toplevel(); @@ -329,7 +295,47 @@ void wf::wlr_view_t::unmap() c->set_toplevel_parent(nullptr); wlr_surface_base_t::unmap(); - emit_view_unmap(self()); + emit_view_unmap(); +} + +void wf::emit_view_map_signal(wayfire_view view, bool has_position) +{ + map_view_signal data; + data.view = view; + data.is_positioned = has_position; + view->get_output()->emit_signal("map-view", &data); + view->emit_signal("map", &data); +} + +void wf::view_interface_t::emit_view_map() +{ + emit_view_map_signal(self(), false); +} + +void wf::view_interface_t::emit_view_unmap() +{ + unmap_view_signal data; + data.view = self(); + + if (get_output()) + { + get_output()->emit_signal("unmap-view", &data); + get_output()->emit_signal("view-disappeared", &data); + } + + emit_signal("unmap", &data); + emit_signal("disappeared", &data); +} + +void wf::view_interface_t::emit_view_pre_unmap() +{ + pre_unmap_view_signal data; + data.view = self(); + + if (get_output()) + get_output()->emit_signal("pre-unmap-view", &data); + + emit_signal("pre-unmap", &data); } void wf::wlr_view_t::destroy() diff --git a/src/view/view-impl.hpp b/src/view/view-impl.hpp index 53bb1a6fc..d7d31d571 100644 --- a/src/view/view-impl.hpp +++ b/src/view/view-impl.hpp @@ -183,6 +183,9 @@ class wlr_view_t : } }; +/** Emit the map signal for the given view */ +void emit_view_map_signal(wayfire_view view, bool has_position); + wf::surface_interface_t* wf_surface_from_void(void *handle); wf::view_interface_t* wf_view_from_void(void *handle); diff --git a/src/view/xwayland.cpp b/src/view/xwayland.cpp index 31929c4d2..7ce2f6e21 100644 --- a/src/view/xwayland.cpp +++ b/src/view/xwayland.cpp @@ -32,6 +32,9 @@ class wayfire_xwayland_view_base : public wf::wlr_view_t int last_server_width = 0; int last_server_height = 0; + /** The geometry requested by the client */ + bool self_positioned = false; + wf::signal_callback_t output_geometry_changed = [this] (wf::signal_data_t*) { @@ -49,6 +52,22 @@ class wayfire_xwayland_view_base : public wf::wlr_view_t on_destroy.set_callback([&] (void*) { destroy(); }); on_configure.set_callback([&] (void* data) { auto ev = static_cast (data); + if ((ev->mask & XCB_CONFIG_WINDOW_X) && (ev->mask & XCB_CONFIG_WINDOW_Y)) + { + self_positioned = true; + } else + { + /* Until the first configure we send to the client, the position + * of the window in the X server and in Wayfire is out-of-sync, + * so we can't rely on the position in the event. */ + auto o = get_output(); + if (o) + { + auto og = get_output()->get_layout_geometry(); + ev->x = geometry.x + og.x; + ev->y = geometry.y + og.y; + } + } configure_request({ev->x, ev->y, ev->width, ev->height}); }); on_set_title.set_callback([&] (void*) { @@ -248,6 +267,16 @@ class wayfire_xwayland_view : public wayfire_xwayland_view_base wayfire_xwayland_view_base::destroy(); } + void emit_view_map() override + { + /* Some X clients position themselves on map, and others let the window + * manager determine this. We try to heuristically guess which of the + * two cases we're dealing with by checking whether we have recevied + * a valid ConfigureRequest before mapping */ + bool client_self_positioned = self_positioned; + emit_view_map_signal(self(), client_self_positioned); + } + void map(wlr_surface *surface) override { /* override-redirect status changed between creation and MapNotify */ @@ -287,14 +316,6 @@ class wayfire_xwayland_view : public wayfire_xwayland_view_base if (xw->fullscreen) fullscreen_request(get_output(), true); - auto real_output = get_output()->get_layout_geometry(); - if (!tiled_edges && !fullscreen && !parent) - { - int desired_x = xw->x - real_output.x; - int desired_y = xw->y - real_output.y; - move(desired_x, desired_y); - } - wf::wlr_view_t::map(surface); create_toplevel(); } @@ -500,7 +521,7 @@ void wayfire_unmanaged_xwayland_view::unmap() /* O-R focuseable views are treated like normal windows, i.e they have the * pre-unmap event and have unmap animations */ if (view_impl->keyboard_focus_enabled) - emit_view_pre_unmap(self()); + emit_view_pre_unmap(); wf::wlr_view_t::unmap(); }