bugfix: handling initially fullscreen windows + allowing workspaces to be floating by default + allowing windows to be floating initially + fixes for #168 (#171)

* bugfix: handling initially fullscreen windows + allowing workspaces to be floating by default

* (#168) bugfix: enabling zwp_pointer_constraints_v1 and zwp_relative_pointer_manager_v1 so that we can game
This commit is contained in:
Matthew Kosarek 2024-06-21 07:50:36 -04:00 committed by GitHub
parent caab71d750
commit dbd50f3b74
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 138 additions and 36 deletions

View File

@ -132,7 +132,7 @@ void LeafNode::toggle_fullscreen()
if (node_interface.is_fullscreen(window))
next_state = mir_window_state_restored;
else
next_state = mir_window_state_maximized;
next_state = mir_window_state_fullscreen;
}
bool LeafNode::is_fullscreen() const

View File

@ -101,17 +101,23 @@ int main(int argc, char const* argv[])
};
notify_init("miracle-wm");
WaylandExtensions wayland_extensions = WaylandExtensions{}
.enable(miral::WaylandExtensions::zwlr_layer_shell_v1)
.enable(miral::WaylandExtensions::zwlr_foreign_toplevel_manager_v1)
.enable(miral::WaylandExtensions::zxdg_output_manager_v1)
.enable(miral::WaylandExtensions::zwp_virtual_keyboard_manager_v1)
.enable(miral::WaylandExtensions::zwlr_virtual_pointer_manager_v1)
.enable(miral::WaylandExtensions::zwp_input_method_manager_v2)
.enable(miral::WaylandExtensions::zwlr_screencopy_manager_v1)
.enable(miral::WaylandExtensions::ext_session_lock_manager_v1);
for (auto const& extension : {"zwp_pointer_constraints_v1", "zwp_relative_pointer_manager_v1"})
wayland_extensions.enable(extension);
return runner.run_with(
{ window_managers,
WaylandExtensions {}
.enable(miral::WaylandExtensions::zwlr_layer_shell_v1)
.enable(miral::WaylandExtensions::zwlr_foreign_toplevel_manager_v1)
.enable(miral::WaylandExtensions::zxdg_output_manager_v1)
.enable(miral::WaylandExtensions::zwp_virtual_keyboard_manager_v1)
.enable(miral::WaylandExtensions::zwlr_virtual_pointer_manager_v1)
.enable(miral::WaylandExtensions::zwp_input_method_manager_v2)
.enable(miral::WaylandExtensions::zwlr_screencopy_manager_v1)
.enable(miral::WaylandExtensions::ext_session_lock_manager_v1),
wayland_extensions,
X11Support {}.default_to_enabled(),
config_keymap,
external_client_launcher,

View File

@ -796,6 +796,39 @@ void MiracleConfig::_load()
}
}
if (config["workspaces"])
{
try
{
auto const& workspaces = config["workspaces"];
if (!workspaces.IsSequence())
{
mir::log_error("workspaces: expected sequence: L%d:%d", workspaces.Mark().line, workspaces.Mark().column);
}
else
{
for (auto const& workspace : workspaces)
{
auto num = workspace["number"].as<int>();
auto type = window_type_from_string(workspace["layout"].as<std::string>());
if (type != WindowType::tiled && type != WindowType::floating)
{
mir::log_error("layout should be 'tiled' or 'floating': L%d:%d", workspace["layout"].Mark().line, workspace["layout"].Mark().column);
continue;
}
workspace_configs.push_back({
num, type
});
}
}
}
catch (YAML::BadConversion const& e)
{
mir::log_error("workspaces: unable to parse: %s, L%d:%d", e.msg.c_str(), e.mark.line, e.mark.column);
}
}
read_animation_definitions(config);
}
@ -1110,3 +1143,14 @@ bool MiracleConfig::are_animations_enabled() const
{
return animations_enabled;
}
WorkspaceConfig MiracleConfig::get_workspace_config(int key) const
{
for (auto const& config : workspace_configs)
{
if (config.num == key)
return config;
}
return { key, WindowType::tiled };
}

View File

@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MIRACLEWM_MIRACLE_CONFIG_H
#include "animation_defintion.h"
#include "window_metadata.h"
#include <atomic>
#include <functional>
#include <glm/glm.hpp>
@ -124,6 +125,12 @@ struct BorderConfig
glm::vec4 color;
};
struct WorkspaceConfig
{
int num = -1;
WindowType layout = WindowType::tiled;
};
class MiracleConfig
{
public:
@ -145,6 +152,7 @@ public:
[[nodiscard]] BorderConfig const& get_border_config() const;
[[nodiscard]] std::array<AnimationDefinition, (int)AnimateableEvent::max> const& get_animation_definitions() const;
[[nodiscard]] bool are_animations_enabled() const;
[[nodiscard]] WorkspaceConfig get_workspace_config(int key) const;
/// Register a listener on configuration change. A lower "priority" number signifies that the
/// listener should be triggered earlier. A higher priority means later
@ -191,6 +199,7 @@ private:
std::atomic<bool> has_changes = false;
bool animations_enabled = true;
std::array<AnimationDefinition, (int)AnimateableEvent::max> animation_defintions;
std::vector<WorkspaceConfig> workspace_configs;
};
}

View File

@ -77,8 +77,7 @@ bool OutputContent::handle_pointer_event(const MirPointerEvent* event)
if (get_active_workspace_num() < 0)
return false;
if (select_window_from_point(static_cast<int>(x), static_cast<int>(y)))
return true;
select_window_from_point(static_cast<int>(x), static_cast<int>(y));
auto const action = mir_pointer_event_action(event);
if (has_clicked_floating_window || get_active_workspace()->has_floating_window(active_window))
@ -93,13 +92,18 @@ bool OutputContent::handle_pointer_event(const MirPointerEvent* event)
return false;
}
WindowType OutputContent::allocate_position(miral::WindowSpecification& requested_specification)
WindowType OutputContent::allocate_position(miral::ApplicationInfo const& app_info, miral::WindowSpecification& requested_specification)
{
if (!window_helpers::is_tileable(requested_specification))
return WindowType::other;
requested_specification = get_active_tree()->allocate_position(requested_specification);
return WindowType::tiled;
auto type = get_active_workspace()->allocate_position(requested_specification);
if (type == WindowType::floating)
{
requested_specification = floating_window_manager.place_new_window(app_info, requested_specification);
}
return type;
}
std::shared_ptr<WindowMetadata> OutputContent::advise_new_window(miral::WindowInfo const& window_info, WindowType type)
@ -109,7 +113,8 @@ std::shared_ptr<WindowMetadata> OutputContent::advise_new_window(miral::WindowIn
{
case WindowType::tiled:
{
auto node = get_active_tree()->advise_new_window(window_info);
auto const& tree = get_active_tree();
auto node = tree->advise_new_window(window_info);
metadata = std::make_shared<WindowMetadata>(WindowType::tiled, window_info.window(), get_active_workspace());
metadata->associate_to_node(node);
break;
@ -117,6 +122,8 @@ std::shared_ptr<WindowMetadata> OutputContent::advise_new_window(miral::WindowIn
case WindowType::floating:
{
floating_window_manager.advise_new_window(window_info);
metadata = std::make_shared<WindowMetadata>(WindowType::floating, window_info.window(), get_active_workspace());
get_active_workspace()->add_floating_window(window_info.window());
break;
}
case WindowType::other:
@ -138,6 +145,12 @@ std::shared_ptr<WindowMetadata> OutputContent::advise_new_window(miral::WindowIn
spec.min_width() = mir::geometry::Width(0);
spec.min_height() = mir::geometry::Height(0);
tools.modify_window(window_info.window(), spec);
// Warning: We need to advise fullscreen only after we've associated the userdata() appropriately
if (type == WindowType::tiled && window_helpers::is_window_fullscreen(window_info.state()))
{
get_active_tree()->advise_fullscreen_window(window_info.window());
}
return metadata;
}
else
@ -382,7 +395,7 @@ OutputContent::confirm_placement_on_display(
mir::log_error("Unsupported window type: %d", (int)metadata->get_type());
break;
}
return new_placement;
return modified_placement;
}
bool OutputContent::select_window_from_point(int x, int y)
@ -829,7 +842,7 @@ void OutputContent::add_immediately(miral::Window& window)
{
auto& prev_info = tools.info_for(window);
WindowSpecification spec = window_helpers::copy_from(prev_info);
WindowType type = allocate_position(spec);
WindowType type = allocate_position(tools.info_for(window.application()), spec);
tools.modify_window(window, spec);
advise_new_window(tools.info_for(window), type);
auto metadata = window_helpers::get_metadata(window, tools);

View File

@ -53,7 +53,7 @@ public:
[[nodiscard]] int get_active_workspace_num() const { return active_workspace; }
[[nodiscard]] std::shared_ptr<WorkspaceContent> const& get_active_workspace() const;
bool handle_pointer_event(MirPointerEvent const* event);
WindowType allocate_position(miral::WindowSpecification& requested_specification);
WindowType allocate_position(miral::ApplicationInfo const& app_info, miral::WindowSpecification& requested_specification);
std::shared_ptr<WindowMetadata> advise_new_window(miral::WindowInfo const& window_info, WindowType type);
void handle_window_ready(miral::WindowInfo& window_info, std::shared_ptr<miracle::WindowMetadata> const& metadata);
void advise_focus_gained(std::shared_ptr<miracle::WindowMetadata> const& metadata);

View File

@ -235,7 +235,7 @@ auto Policy::place_new_window(
auto new_spec = requested_specification;
pending_output = active_output;
pending_type = active_output->allocate_position(new_spec);
pending_type = active_output->allocate_position(app_info, new_spec);
return new_spec;
}

View File

@ -68,27 +68,20 @@ miral::WindowSpecification TilingWindowTree::allocate_position(const miral::Wind
new_spec.max_height() = geom::Height { std::numeric_limits<int>::max() };
auto node = get_active_lane()->create_space_for_window();
auto rect = node->get_visible_area();
new_spec.size() = rect.size;
new_spec.top_left() = rect.top_left;
if (new_spec.state().is_set() && window_helpers::is_window_fullscreen(new_spec.state().value()))
if (!new_spec.state().is_set() || !window_helpers::is_window_fullscreen(new_spec.state().value()))
{
// Don't start anyone in fullscreen mode
new_spec.state() = mir::optional_value<MirWindowState>();
// We only set the size immediately if we have no strong opinions about the size
new_spec.size() = rect.size;
new_spec.top_left() = rect.top_left;
}
return new_spec;
}
std::shared_ptr<LeafNode> TilingWindowTree::advise_new_window(miral::WindowInfo const& window_info)
{
auto node = get_active_lane()->confirm_window(window_info.window());
if (window_helpers::is_window_fullscreen(window_info.state()))
{
tiling_interface.select_active_window(window_info.window());
advise_fullscreen_window(window_info.window());
}
return node;
return get_active_lane()->confirm_window(window_info.window());
}
bool TilingWindowTree::try_resize_active_window(miracle::Direction direction)

View File

@ -225,5 +225,9 @@ void WindowManagerToolsTilingInterface::on_animation(
mir::geometry::Rectangle new_rectangle(
{ spec.top_left().value().x.as_int(), spec.top_left().value().y.as_int() },
{ scale.x, scale.y });
clip(window, new_rectangle);
if (metadata->get_type() == WindowType::tiled)
clip(window, new_rectangle);
else
noclip(window);
}

View File

@ -21,6 +21,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
using namespace miracle;
WindowType miracle::window_type_from_string(std::string const& str)
{
if (str == "tiled")
return WindowType::tiled;
else if (str == "floating")
return WindowType::floating;
else if (str == "other")
return WindowType::other;
else
return WindowType::none;
}
WindowMetadata::WindowMetadata(WindowType type, miral::Window const& window) :
WindowMetadata(type, window, nullptr)
{

View File

@ -38,6 +38,8 @@ enum class WindowType
other
};
WindowType window_type_from_string(std::string const&);
/// Applied to WindowInfo to enable
class WindowMetadata
{

View File

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "tiling_window_tree.h"
#include "window_helpers.h"
#include "window_metadata.h"
#include "miracle_config.h"
#include <mir/log.h>
#include <mir/scene/surface.h>
@ -37,7 +38,8 @@ WorkspaceContent::WorkspaceContent(
tools { tools },
tree(std::make_shared<TilingWindowTree>(screen, node_interface, config)),
workspace { workspace },
node_interface{ node_interface}
node_interface{ node_interface},
config { config }
{
}
@ -51,6 +53,21 @@ std::shared_ptr<TilingWindowTree> const& WorkspaceContent::get_tree() const
return tree;
}
WindowType WorkspaceContent::allocate_position(miral::WindowSpecification& requested_specification)
{
auto layout = config->get_workspace_config(workspace).layout;
switch (layout)
{
case WindowType::tiled:
{
requested_specification = tree->allocate_position(requested_specification);
return WindowType::tiled;
}
default:
return layout;
}
}
void WorkspaceContent::show()
{
auto fullscreen_node = tree->show();

View File

@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MIRACLEWM_WORKSPACE_CONTENT_H
#include "animator.h"
#include "window_metadata.h"
#include <glm/glm.hpp>
#include <memory>
#include <miral/minimal_window_manager.h>
@ -29,7 +30,6 @@ namespace miracle
class OutputContent;
class MiracleConfig;
class TilingWindowTree;
class WindowMetadata;
class TilingInterface;
class WorkspaceContent
@ -44,6 +44,7 @@ public:
[[nodiscard]] int get_workspace() const;
[[nodiscard]] std::shared_ptr<TilingWindowTree> const& get_tree() const;
WindowType allocate_position(miral::WindowSpecification& requested_specification);
void show();
void hide();
void transfer_pinned_windows_to(std::shared_ptr<WorkspaceContent> const& other);
@ -65,6 +66,7 @@ private:
int workspace;
std::vector<miral::Window> floating_windows;
TilingInterface& node_interface;
std::shared_ptr<MiracleConfig> config;
};
} // miracle