#define MIR_INCLUDE_DEPRECATED_EVENT_HEADER
#include <linux/input.h>
#include <map>
#include <vector>
#include <mutex>
char const*
const me::wm_description =
"window management strategy [{tiling|fullscreen}]";
namespace
{
char const* const wm_tiling = "tiling";
char const* const wm_fullscreen = "fullscreen";
{
public:
private:
void add_surface(std::shared_ptr<ms::Surface>
const&,
ms::Session*)
override {}
void remove_surface(std::weak_ptr<ms::Surface>
const&,
ms::Session*)
override {}
void add_session(std::shared_ptr<ms::Session> const&) override {}
void remove_session(std::shared_ptr<ms::Session> const&) override {}
void add_display(
Rectangle const&)
override {}
void remove_display(
Rectangle const&)
override {}
void click(
Point)
override {}
void drag(
Point)
override {}
void resize(
Point)
override {}
{ return requested_value; }
};
{
public:
using FocusControllerFactory = std::function<std::shared_ptr<msh::FocusController>()>;
explicit TilingWindowManager(FocusControllerFactory const& focus_controller) :
focus_controller{focus_controller}
{
}
{
auto parameters = request_parameters;
std::lock_guard<decltype(mutex)> lock(mutex);
auto const ptile = session_info.find(&session);
if (ptile != end(session_info))
{
clip_to_tile(parameters, tile);
}
return parameters;
}
void add_surface(
std::shared_ptr<ms::Surface> const& surface,
{
std::lock_guard<decltype(mutex)> lock(mutex);
session_info[session].surfaces.push_back(surface);
surface_info[surface].session = session_info[session].session;
}
void remove_surface(
std::weak_ptr<ms::Surface> const& surface,
{
std::lock_guard<decltype(mutex)> lock(mutex);
auto& surfaces = session_info[session].surfaces;
for (auto i = begin(surfaces); i != end(surfaces); ++i)
{
if (surface.lock() == i->lock())
{
surfaces.erase(i);
break;
}
}
surface_info.erase(surface);
}
void add_session(std::shared_ptr<ms::Session> const& session) override
{
std::lock_guard<decltype(mutex)> lock(mutex);
session_info[session.get()] = session;
update_tiles();
}
void remove_session(std::shared_ptr<ms::Session> const& session) override
{
std::lock_guard<decltype(mutex)> lock(mutex);
session_info.erase(session.get());
update_tiles();
}
void add_display(
Rectangle const& area)
override
{
std::lock_guard<decltype(mutex)> lock(mutex);
displays.add(area);
update_tiles();
}
void remove_display(
Rectangle const& area)
override
{
std::lock_guard<decltype(mutex)> lock(mutex);
displays.remove(area);
update_tiles();
}
void click(
Point cursor)
override
{
std::lock_guard<decltype(mutex)> lock(mutex);
if (auto const session = session_under(cursor))
focus_controller()->set_focus_to(session);
old_cursor = cursor;
}
void drag(
Point cursor)
override
{
std::lock_guard<decltype(mutex)> lock(mutex);
if (auto const session = session_under(cursor))
{
if (session == session_under(old_cursor))
{
auto const& info = session_info[session.get()];
if (drag(old_surface.lock(), cursor, old_cursor, info.tile))
{
}
else if (drag(session->default_surface(), cursor, old_cursor, info.tile))
{
old_surface = session->default_surface();
}
else
{
for (auto const& ps : info.surfaces)
{
auto const new_surface = ps.lock();
if (drag(new_surface, cursor, old_cursor, info.tile))
{
old_surface = new_surface;
break;
}
}
}
}
}
old_cursor = cursor;
}
void resize(
Point cursor)
override
{
std::lock_guard<decltype(mutex)> lock(mutex);
if (auto const session = session_under(cursor))
{
if (session == session_under(old_cursor))
{
auto const& info = session_info[session.get()];
if (resize(old_surface.lock(), cursor, old_cursor, info.tile))
{
}
else if (resize(session->default_surface(), cursor, old_cursor, info.tile))
{
old_surface = session->default_surface();
}
else
{
for (auto const& ps : info.surfaces)
{
auto const new_surface = ps.lock();
if (resize(new_surface, cursor, old_cursor, info.tile))
{
old_surface = new_surface;
break;
}
}
}
}
}
old_cursor = cursor;
}
{
if (auto const focussed_session = focus_controller()->focussed_application().lock())
{
if (auto const focussed_surface = focussed_session->default_surface())
{
{
std::lock_guard<decltype(mutex)> lock(mutex);
if (surface_info[focussed_surface].state == state)
}
}
}
}
{ return requested_value; }
{
switch (attrib)
{
{
std::lock_guard<decltype(mutex)> lock(mutex);
set_state(surface, value);
break;
}
default:
break;
}
}
private:
void update_tiles()
{
if (session_info.size() < 1 || displays.size() < 1) return;
auto const sessions = session_info.size();
auto const bounding_rect = displays.bounding_rectangle();
auto const total_width = bounding_rect.size.width.as_int();
auto const total_height = bounding_rect.size.height.as_int();
auto index = 0;
for (auto& info : session_info)
{
auto const x = (total_width*index)/sessions;
++index;
auto const dx = (total_width*index)/sessions -
x;
auto const old_tile = info.second.tile;
update_surfaces(info.first, old_tile, new_tile);
info.second.tile = new_tile;
}
}
{
auto& info = session_info[session];
for (auto const& ps : info.surfaces)
{
if (auto const surface = ps.lock())
{
auto const old_pos = surface->
top_left();
surface->
move_to(old_pos + displacement);
fit_to_new_tile(*surface, old_tile, new_tile);
}
}
}
{
}
{
auto const old_size = surface.
size();
auto const scaled_height = old_size.height == old_tile.
size.
height ? new_tile.
size.
height : old_size.height;
auto width = std::min(new_tile.
size.
width.
as_int()-displacement.dx.as_int(), scaled_width.as_int());
}
{
if (surface && surface->input_area_contains(from))
{
auto const top_left = surface->top_left();
auto const surface_size = surface->size();
auto const bottom_right = top_left + as_displacement(surface_size);
auto movement = to - from;
movement.dx = std::max(movement.dx, (bounds.
top_left - top_left).dx);
movement.dy = std::max(movement.dy, (bounds.
top_left - top_left).dy);
movement.dx = std::min(movement.dx, (bounds.
bottom_right() - bottom_right).
dx);
movement.dy = std::min(movement.dy, (bounds.
bottom_right() - bottom_right).
dy);
auto new_pos = surface->top_left() + movement;
surface->move_to(new_pos);
return true;
}
return false;
}
static bool resize(std::shared_ptr<ms::Surface> surface,
Point cursor,
Point old_cursor,
Rectangle bounds)
{
if (surface && surface->input_area_contains(old_cursor))
{
auto const top_left = surface->top_left();
auto const old_displacement = old_cursor - top_left;
auto const new_displacement = cursor - top_left;
auto const scale_x = new_displacement.dx.as_float()/std::max(1.0f, old_displacement.dx.as_float());
auto const scale_y = new_displacement.dy.as_float()/std::max(1.0f, old_displacement.dy.as_float());
if (scale_x <= 0.0f || scale_y <= 0.0f) return false;
auto const old_size = surface->size();
Size new_size{scale_x*old_size.
width, scale_y*old_size.height};
auto const size_limits = as_size(bounds.
bottom_right() - top_left);
if (new_size.width > size_limits.width)
new_size.width = size_limits.width;
if (new_size.height > size_limits.height)
new_size.height = size_limits.height;
surface->resize(new_size);
return true;
}
return false;
}
struct SurfaceInfo
{
SurfaceInfo() = default;
std::weak_ptr<ms::Session> session;
};
{
switch (value)
{
break;
break;
break;
break;
default:
return;
}
for (auto& i : surface_info)
{
if (auto const sp = i.first.lock())
{
if (sp.get() == &surface)
{
auto& surface_info = i.second;
{
surface_info.restore_rect = {sp->top_left(), sp->size()};
}
if (surface_info.state == new_state)
{
return;
}
auto const& session_info =
this->session_info[surface_info.session.lock().get()];
switch (new_state)
{
sp->move_to(surface_info.restore_rect.top_left);
sp->resize(surface_info.restore_rect.size);
break;
sp->move_to(session_info.tile.top_left);
sp->resize(session_info.tile.size);
break;
sp->move_to({session_info.tile.top_left.x, surface_info.restore_rect.top_left.y});
sp->resize({session_info.tile.size.width, surface_info.restore_rect.size.height});
break;
sp->move_to({surface_info.restore_rect.top_left.x, session_info.tile.top_left.y});
sp->resize({surface_info.restore_rect.size.width, session_info.tile.size.height});
break;
default:
break;
}
surface_info.state = new_state;
}
}
}
}
std::shared_ptr<ms::Session> session_under(
Point position)
{
for(auto& info : session_info)
{
if (info.second.tile.contains(position))
{
return info.second.session.lock();
}
}
return std::shared_ptr<ms::Session>{};
}
struct SessionInfo
{
SessionInfo() = default;
SessionInfo& operator=(std::weak_ptr<ms::Session> const& session)
{
this->session = session;
surfaces.clear();
return *this;
}
std::weak_ptr<ms::Session> session;
std::vector<std::weak_ptr<ms::Surface>> surfaces;
};
FocusControllerFactory const focus_controller;
std::mutex mutex;
std::map<ms::Session const*, SessionInfo> session_info;
std::map<std::weak_ptr<ms::Surface>, SurfaceInfo, std::owner_less<std::weak_ptr<ms::Surface>>> surface_info;
std::weak_ptr<ms::Surface> old_surface;
};
}
{
public:
explicit EventTracker(std::shared_ptr<me::WindowManager> const& window_manager) :
window_manager{window_manager} {}
bool handle(
MirEvent const& event)
override
{
{
return handle_key_event(event.
key);
return handle_motion_event(event.
motion);
default:
return false;
}
}
private:
{
static const int modifier_mask =
{
if (auto const wm = window_manager.lock())
{
return true;
return true;
return true;
default:
break;
}
}
return false;
}
{
{
if (auto const wm = window_manager.lock())
{
return false;
}
}
{
if (auto const wm = window_manager.lock())
{
{
return true;
return true;
default:
;
}
}
}
return false;
}
{
long total_x = 0;
long total_y = 0;
for (auto p = pointer_coordinates; p != pointer_coordinates + pointer_count; ++p)
{
total_y += p->y;
}
return Point{total_x/pointer_count, total_y/pointer_count};
}
std::weak_ptr<me::WindowManager> const window_manager;
};
{
auto tmp = wm.lock();
if (!tmp)
{
auto const options = server.get_options();
if (selection == wm_tiling)
{
auto focus_controller_factory = [this] { return server.the_focus_controller(); };
tmp = std::make_shared<TilingWindowManager>(focus_controller_factory);
}
else if (selection == wm_fullscreen)
tmp = std::make_shared<FullscreenWindowManager>(server.the_shell_display_layout());
else
et = std::make_shared<EventTracker>(tmp);
server.the_composite_event_filter()->prepend(et);
wm = tmp;
}
return tmp;
}