diff --git a/android/service/android_api_skeleton.cpp b/android/service/android_api_skeleton.cpp index 29fc40adc4f99a91b0e1747890a6b768c342a6c1..9bab40ab560156db92932c380fd8139e8c3b04c7 100644 --- a/android/service/android_api_skeleton.cpp +++ b/android/service/android_api_skeleton.cpp @@ -73,10 +73,13 @@ void AndroidApiSkeleton::launch_application(anbox::protobuf::bridge::LaunchAppli std::vector argv = { "/system/bin/am", "start", - // Launch any application always in the freeform stack - "--stack", "2", }; + if (request->has_stack()) { + argv.push_back("--stack"); + argv.push_back(std::to_string(request->stack())); + } + if (request->has_launch_bounds()) { argv.push_back("--launch-bounds"); std::stringstream launch_bounds; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6f80342e74b885632284c27ec74efdfbaef52b4a..9a8fe0a0dd637c6a11b4f8c5f9097dfcb72b9b56 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -120,6 +120,8 @@ set(SOURCES anbox/graphics/density.h anbox/graphics/rect.cpp anbox/graphics/layer_composer.cpp + anbox/graphics/multi_window_composer_strategy.cpp + anbox/graphics/single_window_composer_strategy.cpp anbox/graphics/program_family.cpp anbox/graphics/primitives.h anbox/graphics/renderer.h @@ -149,6 +151,8 @@ set(SOURCES anbox/wm/task.cpp anbox/wm/stack.cpp anbox/wm/manager.cpp + anbox/wm/single_window_manager.cpp + anbox/wm/multi_window_manager.cpp anbox/wm/window_state.cpp anbox/wm/window.cpp @@ -181,12 +185,14 @@ set(SOURCES anbox/ubuntu/audio_sink.cpp anbox/dbus/interface.h + anbox/dbus/codecs.h anbox/dbus/skeleton/service.cpp anbox/dbus/skeleton/application_manager.cpp anbox/dbus/stub/application_manager.cpp anbox/application/launcher_storage.cpp anbox/application/database.cpp + anbox/application/manager.h anbox/cmds/version.cpp anbox/cmds/session_manager.cpp diff --git a/src/anbox/application/manager.h b/src/anbox/application/manager.h new file mode 100644 index 0000000000000000000000000000000000000000..b05593b9ba17ceebb26f60e37f07879a37e30a26 --- /dev/null +++ b/src/anbox/application/manager.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_APPLICATION_MANAGER_H_ +#define ANBOX_APPLICATION_MANAGER_H_ + +#include "anbox/android/intent.h" +#include "anbox/do_not_copy_or_move.h" +#include "anbox/graphics/rect.h" +#include "anbox/wm/stack.h" + +#include + +#include + +namespace anbox { +namespace application { +class Manager : public DoNotCopyOrMove { + public: + virtual void launch(const android::Intent &intent, + const graphics::Rect &launch_bounds = graphics::Rect::Invalid, + const wm::Stack::Id &stack = wm::Stack::Id::Default) = 0; + + virtual core::Property& ready() = 0; +}; + +class RestrictedManager : public Manager { + public: + RestrictedManager( + const std::shared_ptr &other, + const wm::Stack::Id &launch_stack = wm::Stack::Id::Invalid) : + other_(other), + launch_stack_(launch_stack) {} + + virtual ~RestrictedManager() {} + + void launch(const android::Intent &intent, + const graphics::Rect &launch_bounds = graphics::Rect::Invalid, + const wm::Stack::Id &stack = wm::Stack::Id::Default) override { + auto selected_stack = stack; + // If we have a static launch stack set use that one instead of + // the one the caller gave us. + if (launch_stack_ != wm::Stack::Id::Invalid) + selected_stack = launch_stack_; + other_->launch(intent, launch_bounds, selected_stack); + } + + core::Property& ready() override { return other_->ready(); } + + private: + std::shared_ptr other_; + wm::Stack::Id launch_stack_; +}; +} // namespace application +} // namespace anbox + +#endif diff --git a/src/anbox/bridge/android_api_stub.cpp b/src/anbox/bridge/android_api_stub.cpp index 2a471d550af181691a7fd46f20cdaea1083a54de..4762b151f609c6f8b96160fa09a459680deba947 100644 --- a/src/anbox/bridge/android_api_stub.cpp +++ b/src/anbox/bridge/android_api_stub.cpp @@ -20,6 +20,7 @@ #include "anbox/logger.h" #include "anbox/rpc/channel.h" #include "anbox/utils.h" +#include "anbox/wm/stack.h" #include "anbox_bridge.pb.h" #include "anbox_rpc.pb.h" @@ -46,7 +47,8 @@ void AndroidApiStub::ensure_rpc_channel() { } void AndroidApiStub::launch(const android::Intent &intent, - const graphics::Rect &launch_bounds) { + const graphics::Rect &launch_bounds, + const wm::Stack::Id &stack) { ensure_rpc_channel(); auto c = std::make_shared>(); @@ -57,6 +59,20 @@ void AndroidApiStub::launch(const android::Intent &intent, launch_wait_handle_.expect_result(); } + switch (stack) { + case wm::Stack::Id::Default: + message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_DEFAULT); + break; + case wm::Stack::Id::Fullscreen: + message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_FULLSCREEN); + break; + case wm::Stack::Id::Freeform: + message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_FREEFORM); + break; + default: + break; + } + if (launch_bounds != graphics::Rect::Invalid) { auto rect = message.mutable_launch_bounds(); rect->set_left(launch_bounds_.left()); diff --git a/src/anbox/bridge/android_api_stub.h b/src/anbox/bridge/android_api_stub.h index 0bb6a5c54f112a63d3e1dad3393f09d0bfddf3a0..d95fd7bd90f90441fd8ce282276afb3edec03b71 100644 --- a/src/anbox/bridge/android_api_stub.h +++ b/src/anbox/bridge/android_api_stub.h @@ -18,7 +18,7 @@ #ifndef ANBOX_BRIDGE_ANDROID_API_STUB_H_ #define ANBOX_BRIDGE_ANDROID_API_STUB_H_ -#include "anbox/application_manager.h" +#include "anbox/application/manager.h" #include "anbox/common/wait_handle.h" #include "anbox/graphics/rect.h" @@ -35,7 +35,7 @@ namespace rpc { class Channel; } // namespace rpc namespace bridge { -class AndroidApiStub : public anbox::ApplicationManager { +class AndroidApiStub : public anbox::application::Manager { public: AndroidApiStub(); ~AndroidApiStub(); @@ -48,7 +48,10 @@ class AndroidApiStub : public anbox::ApplicationManager { void resize_task(const std::int32_t &id, const anbox::graphics::Rect &rect, const std::int32_t &resize_mode); - void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) override; + void launch(const android::Intent &intent, + const graphics::Rect &launch_bounds = graphics::Rect::Invalid, + const wm::Stack::Id &stack = wm::Stack::Id::Default) override; + core::Property& ready() override; private: diff --git a/src/anbox/cli.h b/src/anbox/cli.h index f1831ce1941a0efeb8ae0e0bce2db5a57d3330fb..e398919b35010b0adb022d11e3b7cdb27d747407 100644 --- a/src/anbox/cli.h +++ b/src/anbox/cli.h @@ -73,7 +73,7 @@ std::ostream& operator<<(std::ostream& out, // We are imposing size constraints to ensure a consistent CLI layout. typedef SizeConstrainedString<20> Name; typedef SizeConstrainedString<60> Usage; -typedef SizeConstrainedString<80> Description; +typedef SizeConstrainedString<100> Description; /// @brief Flag models an input parameter to a command. class Flag : public DoNotCopyOrMove { diff --git a/src/anbox/cmds/launch.cpp b/src/anbox/cmds/launch.cpp index 2a3671afed127e5b22fc8fa29d5bc0ff633687b6..a73e2b6607b13e73a223cafb6bfd81b4c4cff057 100644 --- a/src/anbox/cmds/launch.cpp +++ b/src/anbox/cmds/launch.cpp @@ -50,10 +50,12 @@ anbox::cmds::Launch::Launch() flag(cli::make_flag(cli::Name{"package"}, cli::Description{"Package the intent should go to"}, intent_.package)); - flag(cli::make_flag( - cli::Name{"component"}, - cli::Description{"Component of a package the intent should go"}, - intent_.component)); + flag(cli::make_flag(cli::Name{"component"}, + cli::Description{"Component of a package the intent should go"}, + intent_.component)); + flag(cli::make_flag(cli::Name{"stack"}, + cli::Description{"Which window stack the activity should be started on. Possible: default, fullscreen, freeform"}, + stack_)); action([this](const cli::Command::Context&) { auto trap = core::posix::trap_signals_for_process({core::posix::Signal::sig_term, core::posix::Signal::sig_int}); @@ -82,7 +84,7 @@ anbox::cmds::Launch::Launch() dispatcher->dispatch([&]() { if (stub->ready()) { try { - stub->launch(intent_); + stub->launch(intent_, graphics::Rect::Invalid, stack_); success = true; } catch (std::exception &err) { ERROR("err %s", err.what()); @@ -97,7 +99,7 @@ anbox::cmds::Launch::Launch() if (!ready) return; try { - stub->launch(intent_); + stub->launch(intent_, graphics::Rect::Invalid, stack_); success = true; } catch (std::exception &err) { ERROR("Failed to launch activity: %s", err.what()); diff --git a/src/anbox/cmds/launch.h b/src/anbox/cmds/launch.h index 8ee4537a25e406b9e566e13615fc7269936d2e3a..b7a6dfe41b231a2a519904e6afdf7ab98092bfac 100644 --- a/src/anbox/cmds/launch.h +++ b/src/anbox/cmds/launch.h @@ -23,6 +23,7 @@ #include #include "anbox/android/intent.h" +#include "anbox/wm/stack.h" #include "anbox/cli.h" namespace anbox { @@ -33,6 +34,7 @@ class Launch : public cli::CommandWithFlagsAndAction { private: android::Intent intent_; + wm::Stack::Id stack_; }; } // namespace cmds } // namespace anbox diff --git a/src/anbox/cmds/session_manager.cpp b/src/anbox/cmds/session_manager.cpp index 15de80c326583301c9ce26625150d0fe48d3754f..5c294d034ef12e2ca2db1a41216c472880836c90 100644 --- a/src/anbox/cmds/session_manager.cpp +++ b/src/anbox/cmds/session_manager.cpp @@ -41,7 +41,8 @@ #include "anbox/rpc/connection_creator.h" #include "anbox/runtime.h" #include "anbox/ubuntu/platform_policy.h" -#include "anbox/wm/manager.h" +#include "anbox/wm/multi_window_manager.h" +#include "anbox/wm/single_window_manager.h" #include "external/xdg/xdg.h" @@ -54,6 +55,8 @@ namespace fs = boost::filesystem; namespace { +const anbox::graphics::Rect default_single_window_size{0, 0, 1024, 768}; + class NullConnectionCreator : public anbox::network::ConnectionCreator< boost::asio::local::stream_protocol> { public: @@ -86,7 +89,8 @@ anbox::cmds::SessionManager::BusFactory anbox::cmds::SessionManager::session_bus anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) : CommandWithFlagsAndAction{cli::Name{"session-manager"}, cli::Usage{"session-manager"}, cli::Description{"Run the the anbox session manager"}}, - bus_factory_(bus_factory) { + bus_factory_(bus_factory), + window_size_(default_single_window_size) { // Just for the purpose to allow QtMir (or unity8) to find this on our // /proc/*/cmdline // for proper confinement etc. @@ -96,6 +100,12 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) flag(cli::make_flag(cli::Name{"gles-driver"}, cli::Description{"Which GLES driver to use. Possible values are 'host' or'translator'"}, gles_driver_)); + flag(cli::make_flag(cli::Name{"single-window"}, + cli::Description{"Start in single window mode."}, + single_window_)); + flag(cli::make_flag(cli::Name{"window-size"}, + cli::Description{"Size of the window in single window mode, e.g. --window-size=1024,768"}, + window_size_)); action([this](const cli::Command::Context &) { auto trap = core::posix::trap_signals_for_process( @@ -135,19 +145,39 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) auto android_api_stub = std::make_shared(); - auto policy = std::make_shared(input_manager, - android_api_stub); + auto app_manager = std::static_pointer_cast(android_api_stub); + if (!single_window_) { + // When we're not running single window mode we need to restrict ourself to + // only launch applications in freeform mode as otherwise the window tracking + // doesn't work. + app_manager = std::make_shared( + android_api_stub, wm::Stack::Id::Freeform); + } + + auto display_frame = graphics::Rect::Invalid; + if (single_window_) + display_frame = window_size_; + + auto policy = std::make_shared(input_manager, display_frame, single_window_); // FIXME this needs to be removed and solved differently behind the scenes registerDisplayManager(policy); auto app_db = std::make_shared(); - auto window_manager = std::make_shared(policy, app_db); + + std::shared_ptr window_manager; + if (single_window_) + window_manager = std::make_shared(policy, display_frame, app_db); + else + window_manager = std::make_shared(policy, android_api_stub, app_db); auto gl_server = std::make_shared( - graphics::GLRendererServer::Config{gles_driver_}, window_manager); + graphics::GLRendererServer::Config{gles_driver_, single_window_}, window_manager); + policy->set_window_manager(window_manager); policy->set_renderer(gl_server->renderer()); + window_manager->setup(); + auto audio_server = std::make_shared(rt, policy); const auto socket_path = SystemConfiguration::instance().socket_dir(); @@ -198,7 +228,7 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) auto bus = bus_factory_(); bus->install_executor(core::dbus::asio::make_executor(bus, rt->service())); - auto skeleton = anbox::dbus::skeleton::Service::create_for_bus(bus, android_api_stub); + auto skeleton = anbox::dbus::skeleton::Service::create_for_bus(bus, app_manager); rt->start(); trap->run(); diff --git a/src/anbox/cmds/session_manager.h b/src/anbox/cmds/session_manager.h index 88d3d58a51d35bbae8fa602ca192ad2106741de9..9ffb4191ff17a089989e2b02e0e2fe8871125568 100644 --- a/src/anbox/cmds/session_manager.h +++ b/src/anbox/cmds/session_manager.h @@ -27,6 +27,7 @@ #include #include "anbox/graphics/gl_renderer_server.h" +#include "anbox/graphics/rect.h" namespace anbox { namespace cmds { @@ -42,6 +43,8 @@ class SessionManager : public cli::CommandWithFlagsAndAction { BusFactory bus_factory_; std::string desktop_file_hint_; graphics::GLRendererServer::Config::Driver gles_driver_; + bool single_window_ = false; + graphics::Rect window_size_; }; } // namespace cmds } // namespace anbox diff --git a/src/anbox/dbus/codecs.h b/src/anbox/dbus/codecs.h new file mode 100644 index 0000000000000000000000000000000000000000..4a8459ed940943e80d91dde0dedad158454c5624 --- /dev/null +++ b/src/anbox/dbus/codecs.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ + +#ifndef ANBOX_DBUS_CODECS_H_ +#define ANBOX_DBUS_CODECS_H_ + +#include "anbox/wm/stack.h" + +#include + +#include + +namespace core { +namespace dbus { +template<> +struct Codec { + inline static void encode_argument(Message::Writer &out, const anbox::wm::Stack::Id &stack) { + std::stringstream ss; + ss << stack; + auto s = ss.str(); + out.push_stringn(s.c_str(), s.length()); + } + + inline static void decode_argument(Message::Reader &in, anbox::wm::Stack::Id &stack) { + std::stringstream ss; + ss << in.pop_string(); + ss >> stack; + } +}; +} // namespace dbus +} // namespace core + +#endif diff --git a/src/anbox/dbus/skeleton/application_manager.cpp b/src/anbox/dbus/skeleton/application_manager.cpp index 31ec7dcb66050d15407d1091c2211b5ee672eee8..e021a2d1b66d097efecdb87bbac47ad3bd58e327 100644 --- a/src/anbox/dbus/skeleton/application_manager.cpp +++ b/src/anbox/dbus/skeleton/application_manager.cpp @@ -18,6 +18,7 @@ #include "anbox/dbus/skeleton/application_manager.h" #include "anbox/android/intent.h" #include "anbox/dbus/interface.h" +#include "anbox/dbus/codecs.h" #include "anbox/logger.h" #include @@ -27,7 +28,7 @@ namespace dbus { namespace skeleton { ApplicationManager::ApplicationManager( const core::dbus::Bus::Ptr &bus, const core::dbus::Object::Ptr &object, - const std::shared_ptr &impl) + const std::shared_ptr &impl) : bus_(bus), object_(object), impl_(impl), properties_{ object_->get_property() }, signals_{ object_->get_signal() } { @@ -51,10 +52,13 @@ ApplicationManager::ApplicationManager( reader >> bottom; graphics::Rect launch_bounds{left, top, right, bottom}; + wm::Stack::Id stack = wm::Stack::Id::Default; + reader >> stack; + core::dbus::Message::Ptr reply; try { - launch(intent, launch_bounds); + launch(intent, launch_bounds, stack); reply = core::dbus::Message::make_method_return(msg); } catch (std::exception const &err) { reply = core::dbus::Message::make_error(msg, "org.anbox.Error.Failed", @@ -88,8 +92,10 @@ void ApplicationManager::on_property_value_changed(const typename Property::Valu dict, the_empty_list_of_invalidated_properties)); } -void ApplicationManager::launch(const android::Intent &intent, const graphics::Rect &launch_bounds) { - impl_->launch(intent, launch_bounds); +void ApplicationManager::launch(const android::Intent &intent, + const graphics::Rect &launch_bounds, + const wm::Stack::Id &stack) { + impl_->launch(intent, launch_bounds, stack); } core::Property& ApplicationManager::ready() { diff --git a/src/anbox/dbus/skeleton/application_manager.h b/src/anbox/dbus/skeleton/application_manager.h index c72f40b50f38cade43e78553ae73b5b2465dd606..890081592198743a516b303dd196fe07ea77ec2b 100644 --- a/src/anbox/dbus/skeleton/application_manager.h +++ b/src/anbox/dbus/skeleton/application_manager.h @@ -18,7 +18,7 @@ #ifndef ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_ #define ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_ -#include "anbox/application_manager.h" +#include "anbox/application/manager.h" #include #include @@ -30,14 +30,17 @@ namespace anbox { namespace dbus { namespace skeleton { -class ApplicationManager : public anbox::ApplicationManager { +class ApplicationManager : public anbox::application::Manager { public: ApplicationManager(const core::dbus::Bus::Ptr &bus, const core::dbus::Object::Ptr &object, - const std::shared_ptr &impl); + const std::shared_ptr &impl); ~ApplicationManager(); - void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) override; + void launch(const android::Intent &intent, + const graphics::Rect &launch_bounds = graphics::Rect::Invalid, + const wm::Stack::Id &stack = wm::Stack::Id::Default) override; + core::Property& ready() override; private: @@ -47,7 +50,7 @@ class ApplicationManager : public anbox::ApplicationManager { core::dbus::Bus::Ptr bus_; core::dbus::Service::Ptr service_; core::dbus::Object::Ptr object_; - std::shared_ptr impl_; + std::shared_ptr impl_; struct { std::shared_ptr> ready; } properties_; diff --git a/src/anbox/dbus/skeleton/service.cpp b/src/anbox/dbus/skeleton/service.cpp index 75e0580b7de01553305bb74a31d6b53b85fe7047..40910c14877cc367b418791c82739334ca4c7e86 100644 --- a/src/anbox/dbus/skeleton/service.cpp +++ b/src/anbox/dbus/skeleton/service.cpp @@ -24,7 +24,7 @@ namespace dbus { namespace skeleton { std::shared_ptr Service::create_for_bus( const core::dbus::Bus::Ptr &bus, - const std::shared_ptr &application_manager) { + const std::shared_ptr &application_manager) { auto service = core::dbus::Service::add_service( bus, anbox::dbus::interface::Service::name()); auto object = @@ -35,7 +35,7 @@ std::shared_ptr Service::create_for_bus( Service::Service( const core::dbus::Bus::Ptr &bus, const core::dbus::Service::Ptr &service, const core::dbus::Object::Ptr &object, - const std::shared_ptr &application_manager) + const std::shared_ptr &application_manager) : bus_(bus), service_(service), object_(object), diff --git a/src/anbox/dbus/skeleton/service.h b/src/anbox/dbus/skeleton/service.h index c1698610ec9a631d0c4a9a195d2c21bbd0d1049f..46fe8ee69283930c0e8fa47f1c64877825b5c3f5 100644 --- a/src/anbox/dbus/skeleton/service.h +++ b/src/anbox/dbus/skeleton/service.h @@ -18,7 +18,7 @@ #ifndef ANBOX_DBUS_SKELETON_SERVICE_H_ #define ANBOX_DBUS_SKELETON_SERVICE_H_ -#include "anbox/application_manager.h" +#include "anbox/application/manager.h" #include "anbox/do_not_copy_or_move.h" #include @@ -33,19 +33,19 @@ class Service : public DoNotCopyOrMove { public: static std::shared_ptr create_for_bus( const core::dbus::Bus::Ptr &bus, - const std::shared_ptr &application_manager); + const std::shared_ptr &application_manager); Service( const core::dbus::Bus::Ptr &bus, const core::dbus::Service::Ptr &service, const core::dbus::Object::Ptr &object, - const std::shared_ptr &application_manager); + const std::shared_ptr &application_manager); ~Service(); private: core::dbus::Bus::Ptr bus_; core::dbus::Service::Ptr service_; core::dbus::Object::Ptr object_; - std::shared_ptr application_manager_; + std::shared_ptr application_manager_; }; } // namespace skeleton } // namespace dbus diff --git a/src/anbox/dbus/stub/application_manager.cpp b/src/anbox/dbus/stub/application_manager.cpp index ec4b21eb70ad2513c75f2bf96273a147c774393d..e11176f3e445413832746089f9ddca473862c038 100644 --- a/src/anbox/dbus/stub/application_manager.cpp +++ b/src/anbox/dbus/stub/application_manager.cpp @@ -17,6 +17,7 @@ #include "anbox/dbus/stub/application_manager.h" #include "anbox/dbus/interface.h" +#include "anbox/dbus/codecs.h" #include "anbox/logger.h" namespace anbox { @@ -41,13 +42,15 @@ ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus, ApplicationManager::~ApplicationManager() {} -void ApplicationManager::launch(const android::Intent &intent, const graphics::Rect &launch_bounds) { +void ApplicationManager::launch(const android::Intent &intent, + const graphics::Rect &launch_bounds, + const wm::Stack::Id &stack) { auto result = object_->invoke_method_synchronously< anbox::dbus::interface::ApplicationManager::Methods::Launch, anbox::dbus::interface::ApplicationManager::Methods::Launch::ResultType>( intent.action, intent.uri, intent.type, intent.flags, intent.package, intent.component, launch_bounds.left(), launch_bounds.top(), - launch_bounds.right(), launch_bounds.bottom()); + launch_bounds.right(), launch_bounds.bottom(), stack); if (result.is_error()) throw std::runtime_error(result.error().print()); } diff --git a/src/anbox/dbus/stub/application_manager.h b/src/anbox/dbus/stub/application_manager.h index bb44358ca5174ad941fe4847564baa33659f606b..f70a93b391a8189e2fa18f669ba6a89fa04aaf53 100644 --- a/src/anbox/dbus/stub/application_manager.h +++ b/src/anbox/dbus/stub/application_manager.h @@ -18,7 +18,7 @@ #ifndef ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_ #define ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_ -#include "anbox/application_manager.h" +#include "anbox/application/manager.h" #include #include @@ -29,7 +29,7 @@ namespace anbox { namespace dbus { namespace stub { -class ApplicationManager : public anbox::ApplicationManager { +class ApplicationManager : public anbox::application::Manager { public: static std::shared_ptr create_for_bus( const core::dbus::Bus::Ptr &bus); @@ -39,7 +39,10 @@ class ApplicationManager : public anbox::ApplicationManager { const core::dbus::Object::Ptr &object); ~ApplicationManager(); - void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) override; + void launch(const android::Intent &intent, + const graphics::Rect &launch_bounds = graphics::Rect::Invalid, + const wm::Stack::Id &stack = wm::Stack::Id::Default) override; + core::Property& ready() override; private: diff --git a/src/anbox/graphics/emugl/RenderControl.cpp b/src/anbox/graphics/emugl/RenderControl.cpp index 78f2ab0dcfee2fb9e55f519cd82428359a7997cf..b479be06caba377975e81394956cb355a910abd3 100644 --- a/src/anbox/graphics/emugl/RenderControl.cpp +++ b/src/anbox/graphics/emugl/RenderControl.cpp @@ -404,8 +404,7 @@ void rcPostLayer(const char *name, uint32_t color_buffer, Renderable r{ name, color_buffer, - {displayFrameLeft, displayFrameTop, displayFrameRight, - displayFrameBottom}, + {displayFrameLeft, displayFrameTop, displayFrameRight, displayFrameBottom}, {sourceCropLeft, sourceCropTop, sourceCropRight, sourceCropBottom}}; frame_layers.push_back(r); } diff --git a/src/anbox/graphics/gl_renderer_server.cpp b/src/anbox/graphics/gl_renderer_server.cpp index b28ee10eeb8a069352ad804b153bc0570eeac066..bc3f9d0893f4f00cda3d8de04d4ba0edac3ba1f2 100644 --- a/src/anbox/graphics/gl_renderer_server.cpp +++ b/src/anbox/graphics/gl_renderer_server.cpp @@ -20,6 +20,8 @@ #include "anbox/graphics/emugl/RenderControl.h" #include "anbox/graphics/emugl/Renderer.h" #include "anbox/graphics/layer_composer.h" +#include "anbox/graphics/multi_window_composer_strategy.h" +#include "anbox/graphics/single_window_composer_strategy.h" #include "anbox/logger.h" #include "anbox/wm/manager.h" @@ -64,9 +66,15 @@ void logger_write(const emugl::LogLevel &level, const char *format, ...) { namespace anbox { namespace graphics { GLRendererServer::GLRendererServer(const Config &config, const std::shared_ptr &wm) - : renderer_(std::make_shared<::Renderer>()), - wm_(wm), - composer_(std::make_shared(renderer_, wm)) { + : renderer_(std::make_shared<::Renderer>()) { + + std::shared_ptr composer_strategy; + if (config.single_window) + composer_strategy = std::make_shared(wm); + else + composer_strategy = std::make_shared(wm); + + composer_ = std::make_shared(renderer_, composer_strategy); auto gl_libs = emugl::default_gl_libraries(true); diff --git a/src/anbox/graphics/gl_renderer_server.h b/src/anbox/graphics/gl_renderer_server.h index f07e960704b9cf4cc5dcff3905eeef4e452c6084..2df0fca1e93bf1eb1adff869fc72b5c18cc05c0d 100644 --- a/src/anbox/graphics/gl_renderer_server.h +++ b/src/anbox/graphics/gl_renderer_server.h @@ -37,6 +37,7 @@ class GLRendererServer { struct Config { enum class Driver { Translator, Host }; Driver driver; + bool single_window; }; GLRendererServer(const Config &config, const std::shared_ptr &wm); diff --git a/src/anbox/graphics/layer_composer.cpp b/src/anbox/graphics/layer_composer.cpp index 3483d75ba71e0678a2379b01cb5779f96b2d38fd..dbacc97ade69532b60244c8d69318f8e95715fef 100644 --- a/src/anbox/graphics/layer_composer.cpp +++ b/src/anbox/graphics/layer_composer.cpp @@ -22,72 +22,17 @@ namespace anbox { namespace graphics { -LayerComposer::LayerComposer(const std::shared_ptr renderer, - const std::shared_ptr &wm) - : renderer_(renderer), wm_(wm) {} +LayerComposer::LayerComposer(const std::shared_ptr renderer, const std::shared_ptr &strategy) + : renderer_(renderer), strategy_(strategy) {} LayerComposer::~LayerComposer() {} void LayerComposer::submit_layers(const RenderableList &renderables) { - std::map, RenderableList> win_layers; - for (const auto &renderable : renderables) { - // Ignore all surfaces which are not meant for a task - if (!utils::string_starts_with(renderable.name(), "org.anbox.surface.")) - continue; - - wm::Task::Id task_id = 0; - if (sscanf(renderable.name().c_str(), "org.anbox.surface.%d", &task_id) != - 1 || - !task_id) - continue; - - auto w = wm_->find_window_for_task(task_id); - if (!w) continue; - - if (win_layers.find(w) == win_layers.end()) { - win_layers.insert({w, {renderable}}); - continue; - } - - win_layers[w].push_back(renderable); - } - - for (const auto &w : win_layers) { - const auto &window = w.first; - const auto &renderables = w.second; - RenderableList final_renderables; - auto new_window_frame = Rect::Invalid; - auto max_layer_area = -1; - - for (auto &r : renderables) { - const auto layer_area = r.screen_position().width() * r.screen_position().height(); - // We always prioritize layers which are lower in the list we got - // from SurfaceFlinger as they are already ordered. - if (layer_area <= max_layer_area) - continue; - - max_layer_area = layer_area; - new_window_frame = r.screen_position(); - } - - for (auto &r : renderables) { - // As we get absolute display coordinates from the Android hwcomposer we - // need to recalculate all layer coordinates into relatives ones to the - // window they are drawn into. - auto rect = Rect{ - r.screen_position().left() - new_window_frame.left() + r.crop().left(), - r.screen_position().top() - new_window_frame.top() + r.crop().top(), - r.screen_position().right() - new_window_frame.left() + r.crop().left(), - r.screen_position().bottom() - new_window_frame.top() + r.crop().top()}; - - auto new_renderable = r; - new_renderable.set_screen_position(rect); - final_renderables.push_back(new_renderable); - } - - renderer_->draw(window->native_handle(), Rect{0, 0, window->frame().width(), - window->frame().height()}, - final_renderables); + auto win_layers = strategy_->process_layers(renderables); + for (auto &w : win_layers) { + renderer_->draw(w.first->native_handle(), + Rect{0, 0, w.first->frame().width(), w.first->frame().height()}, + w.second); } } } // namespace graphics diff --git a/src/anbox/graphics/layer_composer.h b/src/anbox/graphics/layer_composer.h index f71c351904a683ff3a4b16911bc28d985a720263..955a66321b92b8baaa1ccca3ed36763f6ad236fe 100644 --- a/src/anbox/graphics/layer_composer.h +++ b/src/anbox/graphics/layer_composer.h @@ -21,23 +21,33 @@ #include "anbox/graphics/renderer.h" #include +#include namespace anbox { namespace wm { class Manager; +class Window; } // namespace wm namespace graphics { class LayerComposer { public: + class Strategy { + public: + typedef std::map, RenderableList> WindowRenderableList; + + virtual ~Strategy() {} + virtual WindowRenderableList process_layers(const RenderableList &renderables) = 0; + }; + LayerComposer(const std::shared_ptr renderer, - const std::shared_ptr &wm); + const std::shared_ptr &strategy); ~LayerComposer(); void submit_layers(const RenderableList &renderables); private: std::shared_ptr renderer_; - std::shared_ptr wm_; + std::shared_ptr strategy_; }; } // namespace graphics } // namespace anbox diff --git a/src/anbox/graphics/multi_window_composer_strategy.cpp b/src/anbox/graphics/multi_window_composer_strategy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c58f97d18adc48ea81a17aa15647ecf370aa848 --- /dev/null +++ b/src/anbox/graphics/multi_window_composer_strategy.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/graphics/multi_window_composer_strategy.h" +#include "anbox/wm/manager.h" +#include "anbox/utils.h" + +namespace anbox { +namespace graphics { +MultiWindowComposerStrategy::MultiWindowComposerStrategy(const std::shared_ptr &wm) : wm_(wm) {} + +std::map, RenderableList> MultiWindowComposerStrategy::process_layers(const RenderableList &renderables) { + WindowRenderableList win_layers; + for (const auto &renderable : renderables) { + // Ignore all surfaces which are not meant for a task + if (!utils::string_starts_with(renderable.name(), "org.anbox.surface.")) + continue; + + wm::Task::Id task_id = 0; + if (sscanf(renderable.name().c_str(), "org.anbox.surface.%d", &task_id) != 1 || !task_id) + continue; + + auto w = wm_->find_window_for_task(task_id); + if (!w) continue; + + if (win_layers.find(w) == win_layers.end()) { + win_layers.insert({w, {renderable}}); + continue; + } + + win_layers[w].push_back(renderable); + } + + for (auto &w : win_layers) { + const auto &renderables = w.second; + RenderableList final_renderables; + auto new_window_frame = Rect::Invalid; + auto max_layer_area = -1; + + for (auto &r : renderables) { + const auto layer_area = r.screen_position().width() * r.screen_position().height(); + // We always prioritize layers which are lower in the list we got + // from SurfaceFlinger as they are already ordered. + if (layer_area < max_layer_area) + continue; + + max_layer_area = layer_area; + new_window_frame = r.screen_position(); + } + + for (auto &r : renderables) { + // As we get absolute display coordinates from the Android hwcomposer we + // need to recalculate all layer coordinates into relatives ones to the + // window they are drawn into. + auto rect = Rect{ + r.screen_position().left() - new_window_frame.left() + r.crop().left(), + r.screen_position().top() - new_window_frame.top() + r.crop().top(), + r.screen_position().right() - new_window_frame.left() + r.crop().left(), + r.screen_position().bottom() - new_window_frame.top() + r.crop().top()}; + + auto new_renderable = r; + new_renderable.set_screen_position(rect); + final_renderables.push_back(new_renderable); + } + + w.second = final_renderables; + } + + return win_layers; +} +} // namespace graphics +} // namespace anbox diff --git a/src/anbox/application_manager.h b/src/anbox/graphics/multi_window_composer_strategy.h similarity index 53% rename from src/anbox/application_manager.h rename to src/anbox/graphics/multi_window_composer_strategy.h index 0a21a293502de874b07a4143e619e5558a6cb3b4..e7dbdf96d1770fecd50fc0e2548e88f5cfac7b06 100644 --- a/src/anbox/application_manager.h +++ b/src/anbox/graphics/multi_window_composer_strategy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Simon Fels + * Copyright (C) 2017 Simon Fels * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published @@ -15,23 +15,26 @@ * */ -#ifndef ANBOX_APPLICATION_MANAGER_H_ -#define ANBOX_APPLICATION_MANAGER_H_ +#ifndef ANBOX_GRAPHICS_MULTI_WINDOW_COMPOSER_STRATEGY_H_ +#define ANBOX_GRAPHICS_MULTI_WINDOW_COMPOSER_STRATEGY_H_ -#include "anbox/android/intent.h" -#include "anbox/do_not_copy_or_move.h" -#include "anbox/graphics/rect.h" +#include "anbox/graphics/layer_composer.h" -#include - -#include +#include namespace anbox { -class ApplicationManager : public DoNotCopyOrMove { +namespace graphics { +class MultiWindowComposerStrategy : public LayerComposer::Strategy { public: - virtual void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) = 0; - virtual core::Property& ready() = 0; + MultiWindowComposerStrategy(const std::shared_ptr &wm); + ~MultiWindowComposerStrategy() = default; + + WindowRenderableList process_layers(const RenderableList &renderables) override; + +private: + std::shared_ptr wm_; }; +} // namespace graphics } // namespace anbox #endif diff --git a/src/anbox/graphics/rect.cpp b/src/anbox/graphics/rect.cpp index b98116a73cd42f0e714bd56192f8fb8ebe721131..d3306c52a57dc0a059c003c9f05c9a9f20d3baa5 100644 --- a/src/anbox/graphics/rect.cpp +++ b/src/anbox/graphics/rect.cpp @@ -16,10 +16,13 @@ */ #include "anbox/graphics/rect.h" +#include "anbox/utils.h" #include #include +#include + namespace anbox { namespace graphics { const Rect Rect::Invalid{-1, -1, -1, -1}; @@ -51,5 +54,34 @@ std::ostream &operator<<(std::ostream &out, const Rect &rect) { << "," << rect.bottom() << "} {" << rect.width() << "," << rect.height() << "}"; } + +std::istream& operator>>(std::istream& in, anbox::graphics::Rect &rect) +try { + std::string str; + in >> str; + auto tokens = anbox::utils::string_split(str, ','); + + switch (tokens.size()) { + case 2: { + rect = anbox::graphics::Rect(0, 0, + boost::lexical_cast(tokens[0]), + boost::lexical_cast(tokens[1])); + break; + } + case 4: + rect = anbox::graphics::Rect( + boost::lexical_cast(tokens[0]), + boost::lexical_cast(tokens[1]), + boost::lexical_cast(tokens[2]), + boost::lexical_cast(tokens[3])); + break; + default: + break; + } + + return in; +} catch (...) { + return in; +} } // namespace graphics } // namespace anbox diff --git a/src/anbox/graphics/rect.h b/src/anbox/graphics/rect.h index 8c3060edde27e6e365f1b2e24245d87c1319d319..39037270a2a7db996fd9a0a1f01beb2b66b0c8d3 100644 --- a/src/anbox/graphics/rect.h +++ b/src/anbox/graphics/rect.h @@ -75,6 +75,7 @@ class Rect { }; std::ostream &operator<<(std::ostream &out, const Rect &rect); +std::istream& operator>>(std::istream& in, anbox::graphics::Rect &rect); } // namespace graphics } // namespace anbox diff --git a/src/anbox/graphics/single_window_composer_strategy.cpp b/src/anbox/graphics/single_window_composer_strategy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4f72ee5cf5c3201baf708472061459d3505b764 --- /dev/null +++ b/src/anbox/graphics/single_window_composer_strategy.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/graphics/single_window_composer_strategy.h" +#include "anbox/wm/manager.h" +#include "anbox/utils.h" +#include "anbox/logger.h" + +namespace { +const constexpr char *sprite_name{"Sprite"}; +} + +namespace anbox { +namespace graphics { +SingleWindowComposerStrategy::SingleWindowComposerStrategy(const std::shared_ptr &wm) : wm_(wm) {} + +std::map, RenderableList> SingleWindowComposerStrategy::process_layers(const RenderableList &renderables) { + WindowRenderableList win_layers; + // FIXME there will be only one window in single-window mode ever so it + // doesn't matter which task + auto window = wm_->find_window_for_task(0); + + // Filter out any unwanted layers like the one responsible for the mouse + // cursor which we don't want to render. + RenderableList final_renderables; + for (const auto &r : renderables) { + if (r.name() == sprite_name) + continue; + final_renderables.push_back(r); + } + + win_layers.insert({window, final_renderables}); + return win_layers; +} +} // namespace graphics +} // namespace anbox diff --git a/src/anbox/graphics/single_window_composer_strategy.h b/src/anbox/graphics/single_window_composer_strategy.h new file mode 100644 index 0000000000000000000000000000000000000000..cd7d663c81244b40de92454d52fe5748c77007ac --- /dev/null +++ b/src/anbox/graphics/single_window_composer_strategy.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_GRAPHICS_SINGLE_WINDOW_COMPOSER_STRATEGY_H_ +#define ANBOX_GRAPHICS_SINGLE_WINDOW_COMPOSER_STRATEGY_H_ + +#include "anbox/graphics/layer_composer.h" + +#include + +namespace anbox { +namespace graphics { +class SingleWindowComposerStrategy : public LayerComposer::Strategy { + public: + SingleWindowComposerStrategy(const std::shared_ptr &wm); + ~SingleWindowComposerStrategy() = default; + + WindowRenderableList process_layers(const RenderableList &renderables) override; + +private: + std::shared_ptr wm_; +}; +} // namespace graphics +} // namespace anbox + +#endif diff --git a/src/anbox/protobuf/anbox_bridge.proto b/src/anbox/protobuf/anbox_bridge.proto index 11bde22293c0e4f2e992eb9d07421b41acf4ed1a..993ae5ede1d4f97597272472edfdf36299dc29af 100644 --- a/src/anbox/protobuf/anbox_bridge.proto +++ b/src/anbox/protobuf/anbox_bridge.proto @@ -34,6 +34,12 @@ message Notification { message LaunchApplication { required Intent intent = 1; optional Rect launch_bounds = 2; + enum Stack { + DEFAULT = 0; + FULLSCREEN = 1; + FREEFORM = 2; + } + optional Stack stack = 3 [default = DEFAULT]; } message SetFocusedTask { diff --git a/src/anbox/ubuntu/platform_policy.cpp b/src/anbox/ubuntu/platform_policy.cpp index 17992a670bae003e83d4d547428ff1973c80fb44..6c88c1bac1c841455b36488402a94240ebee809f 100644 --- a/src/anbox/ubuntu/platform_policy.cpp +++ b/src/anbox/ubuntu/platform_policy.cpp @@ -18,13 +18,13 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch-default" #include "anbox/ubuntu/platform_policy.h" -#include "anbox/bridge/android_api_stub.h" #include "anbox/input/device.h" #include "anbox/input/manager.h" #include "anbox/logger.h" #include "anbox/ubuntu/keycode_converter.h" #include "anbox/ubuntu/window.h" #include "anbox/ubuntu/audio_sink.h" +#include "anbox/wm/manager.h" #include @@ -36,32 +36,38 @@ namespace anbox { namespace ubuntu { PlatformPolicy::PlatformPolicy( const std::shared_ptr &input_manager, - const std::shared_ptr &android_api) + const graphics::Rect &static_display_frame, + bool single_window) : input_manager_(input_manager), - android_api_(android_api), - event_thread_running_(false) { + event_thread_running_(false), + single_window_(single_window) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS) < 0) { const auto message = utils::string_format("Failed to initialize SDL: %s", SDL_GetError()); BOOST_THROW_EXCEPTION(std::runtime_error(message)); } auto display_frame = graphics::Rect::Invalid; - for (auto n = 0; n < SDL_GetNumVideoDisplays(); n++) { - SDL_Rect r; - if (SDL_GetDisplayBounds(n, &r) != 0) continue; + if (static_display_frame == graphics::Rect::Invalid) { + for (auto n = 0; n < SDL_GetNumVideoDisplays(); n++) { + SDL_Rect r; + if (SDL_GetDisplayBounds(n, &r) != 0) continue; - graphics::Rect frame{r.x, r.y, r.x + r.w, r.y + r.h}; + graphics::Rect frame{r.x, r.y, r.x + r.w, r.y + r.h}; + + if (display_frame == graphics::Rect::Invalid) + display_frame = frame; + else + display_frame.merge(frame); + } if (display_frame == graphics::Rect::Invalid) - display_frame = frame; - else - display_frame.merge(frame); + BOOST_THROW_EXCEPTION( + std::runtime_error("No valid display configuration found")); + } else { + display_frame = static_display_frame; + window_size_immutable_ = true; } - if (display_frame == graphics::Rect::Invalid) - BOOST_THROW_EXCEPTION( - std::runtime_error("No valid display configuration found")); - display_info_.horizontal_resolution = display_frame.width(); display_info_.vertical_resolution = display_frame.height(); @@ -101,6 +107,10 @@ void PlatformPolicy::set_renderer(const std::shared_ptr &renderer) { renderer_ = renderer; } +void PlatformPolicy::set_window_manager(const std::shared_ptr &window_manager) { + window_manager_ = window_manager; +} + void PlatformPolicy::process_events() { event_thread_running_ = true; @@ -153,25 +163,31 @@ void PlatformPolicy::process_input_event(const SDL_Event &event) { mouse_events.push_back({EV_SYN, SYN_REPORT, 0}); break; case SDL_MOUSEMOTION: - // As we get only absolute coordindates relative to our window we have to - // calculate the correct position based on the current focused window - window = SDL_GetWindowFromID(event.window.windowID); - if (!window) break; - - SDL_GetWindowPosition(window, &x, &y); - x += event.motion.x; - y += event.motion.y; + if (!single_window_) { + // As we get only absolute coordindates relative to our window we have to + // calculate the correct position based on the current focused window + window = SDL_GetWindowFromID(event.window.windowID); + if (!window) break; + + SDL_GetWindowPosition(window, &x, &y); + x += event.motion.x; + y += event.motion.y; + } else { + // When running the whole Android system in a single window we don't + // need to reacalculate and the pointer position as they are already + // relative to our window. + x = event.motion.x; + y = event.motion.y; + } // NOTE: Sending relative move events doesn't really work and we have - // changes - // in libinputflinger to take ABS_X/ABS_Y instead for absolute position - // events. + // changes in libinputflinger to take ABS_X/ABS_Y instead for absolute + // position events. mouse_events.push_back({EV_ABS, ABS_X, x}); mouse_events.push_back({EV_ABS, ABS_Y, y}); // We're sending relative position updates here too but they will be only - // used - // by the Android side EventHub/InputReader to determine if the cursor was - // moved. They are not used to find out the exact position. + // used by the Android side EventHub/InputReader to determine if the cursor + // was moved. They are not used to find out the exact position. mouse_events.push_back({EV_REL, REL_X, event.motion.xrel}); mouse_events.push_back({EV_REL, REL_Y, event.motion.yrel}); mouse_events.push_back({EV_SYN, SYN_REPORT, 0}); @@ -214,7 +230,7 @@ std::shared_ptr PlatformPolicy::create_window( } auto id = next_window_id(); - auto w = std::make_shared(renderer_, id, task, shared_from_this(), frame, title); + auto w = std::make_shared(renderer_, id, task, shared_from_this(), frame, title, !window_size_immutable_); windows_.insert({id, w}); return w; } @@ -225,7 +241,8 @@ void PlatformPolicy::window_deleted(const Window::Id &id) { WARNING("Got window removed event for unknown window (id %d)", id); return; } - if (auto window = w->second.lock()) android_api_->remove_task(window->task()); + if (auto window = w->second.lock()) + window_manager_->remove_task(window->task()); windows_.erase(w); } @@ -234,7 +251,7 @@ void PlatformPolicy::window_wants_focus(const Window::Id &id) { if (w == windows_.end()) return; if (auto window = w->second.lock()) - android_api_->set_focused_task(window->task()); + window_manager_->set_focused_task(window->task()); } void PlatformPolicy::window_moved(const Window::Id &id, const std::int32_t &x, @@ -246,7 +263,7 @@ void PlatformPolicy::window_moved(const Window::Id &id, const std::int32_t &x, auto new_frame = window->frame(); new_frame.translate(x, y); window->update_frame(new_frame); - android_api_->resize_task(window->task(), new_frame, 3); + window_manager_->resize_task(window->task(), new_frame, 3); } } @@ -264,7 +281,7 @@ void PlatformPolicy::window_resized(const Window::Id &id, // representing this window and then we're back to the original size of // the task. window->update_frame(new_frame); - android_api_->resize_task(window->task(), new_frame, 3); + window_manager_->resize_task(window->task(), new_frame, 3); } } diff --git a/src/anbox/ubuntu/platform_policy.h b/src/anbox/ubuntu/platform_policy.h index 53bd7635e490e3aca3c323f7689ac97719203a8f..9a09c0ddbe03a57bf03f755df6f338720bb6ae73 100644 --- a/src/anbox/ubuntu/platform_policy.h +++ b/src/anbox/ubuntu/platform_policy.h @@ -35,9 +35,9 @@ namespace input { class Device; class Manager; } // namespace input -namespace bridge { -class AndroidApiStub; -} // namespace bridge +namespace wm { +class Manager; +} // namespace wm namespace ubuntu { class PlatformPolicy : public std::enable_shared_from_this, public platform::Policy, @@ -45,7 +45,8 @@ class PlatformPolicy : public std::enable_shared_from_this, public DisplayManager { public: PlatformPolicy(const std::shared_ptr &input_manager, - const std::shared_ptr &android_api); + const graphics::Rect &static_display_frame = graphics::Rect::Invalid, + bool single_window = false); ~PlatformPolicy(); std::shared_ptr create_window( @@ -63,6 +64,7 @@ class PlatformPolicy : public std::enable_shared_from_this, DisplayInfo display_info() const override; void set_renderer(const std::shared_ptr &renderer); + void set_window_manager(const std::shared_ptr &window_manager); void set_clipboard_data(const ClipboardData &data) override; ClipboardData get_clipboard_data() override; @@ -78,7 +80,7 @@ class PlatformPolicy : public std::enable_shared_from_this, std::shared_ptr renderer_; std::shared_ptr input_manager_; - std::shared_ptr android_api_; + std::shared_ptr window_manager_; // We don't own the windows anymore after the got created by us so we // need to be careful once we try to use them again. std::map> windows_; @@ -88,6 +90,8 @@ class PlatformPolicy : public std::enable_shared_from_this, std::shared_ptr pointer_; std::shared_ptr keyboard_; DisplayManager::DisplayInfo display_info_; + bool window_size_immutable_ = false; + bool single_window_ = false; }; } // namespace wm } // namespace anbox diff --git a/src/anbox/ubuntu/window.cpp b/src/anbox/ubuntu/window.cpp index d87d1e673409773384c4c39bc0ae5d07c4279755..a9795c95656ec2005e34799b3f13df8a3d13242f 100644 --- a/src/anbox/ubuntu/window.cpp +++ b/src/anbox/ubuntu/window.cpp @@ -40,7 +40,8 @@ Window::Window(const std::shared_ptr &renderer, const Id &id, const wm::Task::Id &task, const std::shared_ptr &observer, const graphics::Rect &frame, - const std::string &title) + const std::string &title, + bool resizable) : wm::Window(renderer, task, frame, title), id_(id), observer_(observer), @@ -48,12 +49,21 @@ Window::Window(const std::shared_ptr &renderer, native_window_(0) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); - window_ = SDL_CreateWindow(title.c_str(), frame.left(), frame.top(), + // NOTE: We don't furce GL initialization of the window as this will + // be take care of by the Renderer when we attach to it. On EGL + // initializing GL here will cause a surface to be created and the + // renderer will attempt to create one too which will not work as + // only a single surface per EGLNativeWindowType is supported. + std::uint32_t flags = 0; + if (resizable) + flags |= SDL_WINDOW_RESIZABLE; + + window_ = SDL_CreateWindow(title.c_str(), + frame.left(), frame.top(), frame.width(), frame.height(), - SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + flags); if (!window_) { - const auto message = - utils::string_format("Failed to create window: %s", SDL_GetError()); + const auto message = utils::string_format("Failed to create window: %s", SDL_GetError()); BOOST_THROW_EXCEPTION(std::runtime_error(message)); } @@ -77,6 +87,8 @@ Window::Window(const std::shared_ptr &renderer, ERROR("Unknown subsystem (%d)", info.subsystem); BOOST_THROW_EXCEPTION(std::runtime_error("SDL subsystem not suported")); } + + SDL_ShowWindow(window_); } Window::~Window() { diff --git a/src/anbox/ubuntu/window.h b/src/anbox/ubuntu/window.h index d5ad1a7579a5a4f31e2beceedcd46e898a95e0f0..801fa38a475c2d957061860ee366e8ba15583f04 100644 --- a/src/anbox/ubuntu/window.h +++ b/src/anbox/ubuntu/window.h @@ -51,7 +51,8 @@ class Window : public std::enable_shared_from_this, public wm::Window { const Id &id, const wm::Task::Id &task, const std::shared_ptr &observer, const graphics::Rect &frame, - const std::string &title); + const std::string &title, + bool resizable); ~Window(); void process_event(const SDL_Event &event); diff --git a/src/anbox/wm/manager.cpp b/src/anbox/wm/manager.cpp index 779f25728a5507c308dfb00a5f81034cbdf36921..577075ce6baf3dab8a1e16f09102edb6afe5632f 100644 --- a/src/anbox/wm/manager.cpp +++ b/src/anbox/wm/manager.cpp @@ -16,93 +16,9 @@ */ #include "anbox/wm/manager.h" -#include "anbox/application/database.h" -#include "anbox/platform/policy.h" -#include "anbox/logger.h" - -#include namespace anbox { namespace wm { -Manager::Manager(const std::shared_ptr &policy, - const std::shared_ptr &app_db) - : platform_policy_(policy), app_db_(app_db) {} - Manager::~Manager() {} - -void Manager::apply_window_state_update(const WindowState::List &updated, - const WindowState::List &removed) { - std::lock_guard l(mutex_); - - // Base on the update we get from the Android WindowManagerService we will - // create - // different window instances with the properties supplied. Incoming layer - // updates - // from SurfaceFlinger will be mapped later into those windows and eventually - // composited there via GLES (e.g. for popups, ..) - - std::map task_updates; - - for (const auto &window : updated) { - // Ignore all windows which are not part of the freeform task stack - if (window.stack() != Stack::Freeform) continue; - - // And also those which don't have a surface mapped at the moment - if (!window.has_surface()) continue; - - // If we know that task already we first collect all window updates - // for it so we can apply all of them together. - auto w = windows_.find(window.task()); - if (w != windows_.end()) { - auto t = task_updates.find(window.task()); - if (t == task_updates.end()) - task_updates.insert({window.task(), {window}}); - else - task_updates[window.task()].push_back(window); - continue; - } - - auto title = window.package_name(); - auto app = app_db_->find_by_package(window.package_name()); - if (app.valid()) - title = app.name; - - auto platform_window = platform_policy_->create_window(window.task(), window.frame(), title); - platform_window->attach(); - windows_.insert({window.task(), platform_window}); - } - - // Send updates we collected per task down to the corresponding window - // so that they can update themself. - for (const auto &u : task_updates) { - auto w = windows_.find(u.first); - if (w == windows_.end()) continue; - - w->second->update_state(u.second); - } - - // As final step we process all windows we need to remove as they - // got killed on the other side. We need to respect here that we - // also get removals for windows which are part of a task which is - // still in use by other windows. - for (const auto &window : removed) { - auto w = windows_.find(window.task()); - if (w == windows_.end()) continue; - - if (task_updates.find(window.task()) == task_updates.end()) { - auto platform_window = w->second; - platform_window->release(); - windows_.erase(w); - } - } -} - -std::shared_ptr Manager::find_window_for_task(const Task::Id &task) { - std::lock_guard l(mutex_); - for (const auto &w : windows_) { - if (w.second->task() == task) return w.second; - } - return nullptr; -} -} // namespace wm -} // namespace anbox +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/manager.h b/src/anbox/wm/manager.h index 8fda1c913aae6be267eea42273b719d28c477fbf..ca999a36c67b254d91c43939f3d636d0c2c8ac33 100644 --- a/src/anbox/wm/manager.h +++ b/src/anbox/wm/manager.h @@ -26,29 +26,22 @@ #include namespace anbox { -namespace application { -class Database; -} // namespace application -namespace platform { -class Policy; -} // namespace platform namespace wm { class Manager { public: - Manager(const std::shared_ptr &policy, - const std::shared_ptr &app_db); - ~Manager(); + virtual ~Manager(); - void apply_window_state_update(const WindowState::List &updated, - const WindowState::List &removed); + virtual void setup() {} - std::shared_ptr find_window_for_task(const Task::Id &task); + virtual void apply_window_state_update(const WindowState::List &updated, const WindowState::List &removed) = 0; - private: - std::mutex mutex_; - std::shared_ptr platform_policy_; - std::shared_ptr app_db_; - std::map> windows_; + virtual void resize_task(const Task::Id &task, const anbox::graphics::Rect &rect, + const std::int32_t &resize_mode) = 0; + virtual void set_focused_task(const Task::Id &task) = 0; + virtual void remove_task(const Task::Id &task) = 0; + + // FIXME only applies for the multi-window case + virtual std::shared_ptr find_window_for_task(const Task::Id &task) = 0; }; } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/multi_window_manager.cpp b/src/anbox/wm/multi_window_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83ab0b6bed0e953e8c00b1a6128886f894f15824 --- /dev/null +++ b/src/anbox/wm/multi_window_manager.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/application/database.h" +#include "anbox/wm/multi_window_manager.h" +#include "anbox/platform/policy.h" +#include "anbox/bridge/android_api_stub.h" +#include "anbox/logger.h" + +#include + +namespace anbox { +namespace wm { +MultiWindowManager::MultiWindowManager(const std::shared_ptr &policy, + const std::shared_ptr &android_api_stub, + const std::shared_ptr &app_db) + : platform_policy_(policy), android_api_stub_(android_api_stub), app_db_(app_db) {} + +MultiWindowManager::~MultiWindowManager() {} + +void MultiWindowManager::apply_window_state_update(const WindowState::List &updated, + const WindowState::List &removed) { + std::lock_guard l(mutex_); + + // Base on the update we get from the Android WindowManagerService we will + // create different window instances with the properties supplied. Incoming + // layer updates from SurfaceFlinger will be mapped later into those windows + // and eventually composited there via GLES (e.g. for popups, ..) + + std::map task_updates; + + for (const auto &window : updated) { + // Ignore all windows which are not part of the freeform task stack + if (window.stack() != Stack::Id::Freeform) continue; + + // And also those which don't have a surface mapped at the moment + if (!window.has_surface()) continue; + + // If we know that task already we first collect all window updates + // for it so we can apply all of them together. + auto w = windows_.find(window.task()); + if (w != windows_.end()) { + auto t = task_updates.find(window.task()); + if (t == task_updates.end()) + task_updates.insert({window.task(), {window}}); + else + task_updates[window.task()].push_back(window); + continue; + } + + auto title = window.package_name(); + auto app = app_db_->find_by_package(window.package_name()); + if (app.valid()) + title = app.name; + + auto platform_window = platform_policy_->create_window(window.task(), window.frame(), title); + platform_window->attach(); + windows_.insert({window.task(), platform_window}); + } + + // Send updates we collected per task down to the corresponding window + // so that they can update themself. + for (const auto &u : task_updates) { + auto w = windows_.find(u.first); + if (w == windows_.end()) continue; + + w->second->update_state(u.second); + } + + // As final step we process all windows we need to remove as they + // got killed on the other side. We need to respect here that we + // also get removals for windows which are part of a task which is + // still in use by other windows. + for (const auto &window : removed) { + auto w = windows_.find(window.task()); + if (w == windows_.end()) continue; + + if (task_updates.find(window.task()) == task_updates.end()) { + auto platform_window = w->second; + platform_window->release(); + windows_.erase(w); + } + } +} + +std::shared_ptr MultiWindowManager::find_window_for_task(const Task::Id &task) { + std::lock_guard l(mutex_); + for (const auto &w : windows_) { + if (w.second->task() == task) return w.second; + } + return nullptr; +} + +void MultiWindowManager::resize_task(const Task::Id &task, const anbox::graphics::Rect &rect, + const std::int32_t &resize_mode) { + android_api_stub_->resize_task(task, rect, resize_mode); +} + +void MultiWindowManager::set_focused_task(const Task::Id &task) { + android_api_stub_->set_focused_task(task); +} + +void MultiWindowManager::remove_task(const Task::Id &task) { + android_api_stub_->remove_task(task); +} +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/multi_window_manager.h b/src/anbox/wm/multi_window_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..4e2d7c49b6871fec1c8056652b032198b46f57d5 --- /dev/null +++ b/src/anbox/wm/multi_window_manager.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_MULTI_WINDOW_MANAGER_H_ +#define ANBOX_WM_MULTI_WINDOW_MANAGER_H_ + +#include "anbox/wm/manager.h" + +#include +#include +#include + +namespace anbox { +namespace application { +class Database; +} // namespace application +namespace bridge { +class AndroidApiStub; +} // namespace bridge +namespace platform { +class Policy; +} // namespace platform +namespace wm { +class MultiWindowManager : public Manager { + public: + MultiWindowManager(const std::shared_ptr &policy, + const std::shared_ptr &android_api_stub, + const std::shared_ptr &app_db); + ~MultiWindowManager(); + + void apply_window_state_update(const WindowState::List &updated, const WindowState::List &removed) override; + + std::shared_ptr find_window_for_task(const Task::Id &task) override; + + void resize_task(const Task::Id &task, const anbox::graphics::Rect &rect, + const std::int32_t &resize_mode) override; + void set_focused_task(const Task::Id &task) override; + void remove_task(const Task::Id &task) override; + + private: + std::mutex mutex_; + std::shared_ptr platform_policy_; + std::shared_ptr android_api_stub_; + std::shared_ptr app_db_; + std::map> windows_; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/src/anbox/wm/single_window_manager.cpp b/src/anbox/wm/single_window_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6adb43eb429a93ee536b1df8a0b7776811f713d5 --- /dev/null +++ b/src/anbox/wm/single_window_manager.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/wm/single_window_manager.h" +#include "anbox/platform/policy.h" +#include "anbox/logger.h" + +#include + +#include +#include + +namespace anbox { +namespace wm { +SingleWindowManager::SingleWindowManager(const std::shared_ptr &policy, + const graphics::Rect &window_size, + const std::shared_ptr &app_db) + : platform_policy_(policy), window_size_(window_size), app_db_(app_db) {} + +SingleWindowManager::~SingleWindowManager() {} + +void SingleWindowManager::setup() { + window_ = platform_policy_->create_window(0, window_size_, "Anbox - Android in a Box"); + if (!window_->attach()) + WARNING("Failed to attach window to renderer"); +} + +void SingleWindowManager::apply_window_state_update(const WindowState::List &updated, const WindowState::List &removed) { + (void)updated; + (void)removed; +} + +std::shared_ptr SingleWindowManager::find_window_for_task(const Task::Id &task) { + (void)task; + return window_; +} + +void SingleWindowManager::resize_task(const Task::Id &task, const anbox::graphics::Rect &rect, + const std::int32_t &resize_mode) { + (void)task; + (void)rect; + (void)resize_mode; +} + +void SingleWindowManager::set_focused_task(const Task::Id &task) { + (void)task; +} + +void SingleWindowManager::remove_task(const Task::Id &task) { + if (task != 0) { + WARNING("Window with invalid task id was closed"); + return; + } + + // FIXME easiest to terminate is sending ourself the terminate signal + // which will be then processed by the main loop and terminate the whole + // application. + kill(getpid(), SIGTERM); +} +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/single_window_manager.h b/src/anbox/wm/single_window_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..6d0d2cad682e5fcdbed3333ad9bfd95af0ff26eb --- /dev/null +++ b/src/anbox/wm/single_window_manager.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_SINGLE_WINDOW_MANAGER_H_ +#define ANBOX_WM_SINGLE_WINDOW_MANAGER_H_ + +#include "anbox/wm/manager.h" + +#include +#include +#include + +namespace anbox { +namespace application { +class Database; +} // namespace application +namespace platform { +class Policy; +} // namespace platform +namespace wm { +class Window; +class SingleWindowManager : public Manager { + public: + SingleWindowManager(const std::shared_ptr &policy, + const graphics::Rect &window_size, + const std::shared_ptr &app_db); + ~SingleWindowManager(); + + void setup() override; + + void apply_window_state_update(const WindowState::List &updated, const WindowState::List &removed) override; + + std::shared_ptr find_window_for_task(const Task::Id &task) override; + + void resize_task(const Task::Id &task, const anbox::graphics::Rect &rect, + const std::int32_t &resize_mode) override; + void set_focused_task(const Task::Id &task) override; + void remove_task(const Task::Id &task) override; + + private: + std::shared_ptr platform_policy_; + graphics::Rect window_size_; + std::shared_ptr app_db_; + std::shared_ptr window_; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/src/anbox/wm/stack.cpp b/src/anbox/wm/stack.cpp index 009a8602bfa8cdf6ddea377d4cf6770de05c385d..800850d2b4339835cba256f4d2d75ec5374209d3 100644 --- a/src/anbox/wm/stack.cpp +++ b/src/anbox/wm/stack.cpp @@ -19,9 +19,33 @@ namespace anbox { namespace wm { -Stack::Id Stack::Invalid = -1; -Stack::Id Stack::Default = 0; -Stack::Id Stack::Fullscreen = 1; -Stack::Id Stack::Freeform = 2; +std::ostream &operator<<(std::ostream &out, const Stack::Id &stack) { + switch (stack) { + case anbox::wm::Stack::Id::Default: + out << "default"; + break; + case anbox::wm::Stack::Id::Fullscreen: + out << "fullscreen"; + break; + case anbox::wm::Stack::Id::Freeform: + out << "freeform"; + break; + default: + break; + } + return out; +} + +std::istream& operator>>(std::istream& in, Stack::Id &stack) { + std::string s; + in >> s; + if (s == "default") + stack = anbox::wm::Stack::Id::Default; + else if (s == "fullscreen") + stack = anbox::wm::Stack::Id::Fullscreen; + else if (s == "freeform") + stack = anbox::wm::Stack::Id::Freeform; + return in; +} } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/stack.h b/src/anbox/wm/stack.h index 092b29d2a0a1b772a78415d89cdcb978f89f8f16..67163173354bd1e6f32f442caf30eb2049b3ea59 100644 --- a/src/anbox/wm/stack.h +++ b/src/anbox/wm/stack.h @@ -18,23 +18,28 @@ #ifndef ANBOX_WM_STACK_H_ #define ANBOX_WM_STACK_H_ -#include +#include namespace anbox { namespace wm { class Stack { public: - typedef std::int32_t Id; - - static Id Invalid; - static Id Default; - static Id Fullscreen; - static Id Freeform; + enum class Id { + Invalid = -1, + Default = 0, + Fullscreen = 1, + Freeform = 2, + }; Stack() = delete; Stack(const Stack&) = delete; }; + +std::ostream& operator<<(std::ostream &out, Stack::Id const &stack); +std::istream& operator>>(std::istream &in, Stack::Id &stack); } // namespace wm } // namespace anbox + + #endif diff --git a/src/anbox/wm/window.cpp b/src/anbox/wm/window.cpp index 76deb1b6bbe4fccc403df8c84e93a60ae375b1ce..0fc948b9df4ec36c855274c429cb20f1700cab63 100644 --- a/src/anbox/wm/window.cpp +++ b/src/anbox/wm/window.cpp @@ -24,7 +24,9 @@ namespace wm { Window::Window(const std::shared_ptr &renderer, const Task::Id &task, const graphics::Rect &frame, const std::string &title) : renderer_(renderer), task_(task), frame_(frame), title_(title) {} -Window::~Window() {} +Window::~Window() { + release(); +} void Window::update_state(const WindowState::List &states) { (void)states; @@ -47,11 +49,12 @@ std::string Window::title() const { return title_; } bool Window::attach() { if (!renderer_) return false; - return renderer_->createNativeWindow(native_handle()); + attached_ = renderer_->createNativeWindow(native_handle()); + return attached_; } void Window::release() { - if (!renderer_) + if (!renderer_ || !attached_) return; renderer_->destroyNativeWindow(native_handle()); } diff --git a/src/anbox/wm/window.h b/src/anbox/wm/window.h index 7878894008815377733c022b0fcc149c5aff9fb9..7c3b282a2bc14da5abd74b8edd1de818884abc84 100644 --- a/src/anbox/wm/window.h +++ b/src/anbox/wm/window.h @@ -64,6 +64,7 @@ class Window { Task::Id task_; graphics::Rect frame_; std::string title_; + bool attached_ = false; }; } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/window_state.cpp b/src/anbox/wm/window_state.cpp index d5b1494dfa0e7872fd4867ca8ad3955636749e81..e35b83ca5354befa09565c72864adaa2e58b37c0 100644 --- a/src/anbox/wm/window_state.cpp +++ b/src/anbox/wm/window_state.cpp @@ -25,7 +25,7 @@ WindowState::WindowState() frame_(graphics::Rect::Invalid), package_name_(""), task_(Task::Invalid), - stack_(Stack::Invalid) {} + stack_(Stack::Id::Invalid) {} WindowState::WindowState(const Display::Id &display, bool has_surface, const graphics::Rect &frame, diff --git a/tests/anbox/graphics/layer_composer_tests.cpp b/tests/anbox/graphics/layer_composer_tests.cpp index b2ef1cc8aa145c275ef02fe61544484247f0a4f5..c99801b477ec8e0a42e9df852d8614c4237febf3 100644 --- a/tests/anbox/graphics/layer_composer_tests.cpp +++ b/tests/anbox/graphics/layer_composer_tests.cpp @@ -22,10 +22,11 @@ #include "anbox/application/database.h" #include "anbox/platform/default_policy.h" -#include "anbox/wm/manager.h" +#include "anbox/wm/multi_window_manager.h" #include "anbox/wm/window_state.h" #include "anbox/graphics/layer_composer.h" +#include "anbox/graphics/multi_window_composer_strategy.h" using namespace ::testing; @@ -46,7 +47,7 @@ TEST(LayerComposer, FindsNoSuitableWindowForLayer) { // from the manager. auto platform_policy = std::make_shared(); auto app_db = std::make_shared(); - auto wm = std::make_shared(platform_policy, app_db); + auto wm = std::make_shared(platform_policy, nullptr, app_db); auto single_window = wm::WindowState{ wm::Display::Id{1}, @@ -54,12 +55,12 @@ TEST(LayerComposer, FindsNoSuitableWindowForLayer) { graphics::Rect{0, 0, 1024, 768}, "org.anbox.test.1", wm::Task::Id{1}, - wm::Stack::Freeform, + wm::Stack::Id::Freeform, }; wm->apply_window_state_update({single_window}, {}); - LayerComposer composer(renderer, wm); + LayerComposer composer(renderer, std::make_shared(wm)); // A single renderable which has a different task id then the window we know // about @@ -80,7 +81,7 @@ TEST(LayerComposer, MapsLayersToWindows) { // from the manager. auto platform_policy = std::make_shared(); auto app_db = std::make_shared(); - auto wm = std::make_shared(platform_policy, app_db); + auto wm = std::make_shared(platform_policy, nullptr, app_db); auto first_window = wm::WindowState{ wm::Display::Id{1}, @@ -88,7 +89,7 @@ TEST(LayerComposer, MapsLayersToWindows) { graphics::Rect{0, 0, 1024, 768}, "org.anbox.foo", wm::Task::Id{1}, - wm::Stack::Freeform, + wm::Stack::Id::Freeform, }; auto second_window = wm::WindowState{ @@ -97,12 +98,12 @@ TEST(LayerComposer, MapsLayersToWindows) { graphics::Rect{300, 400, 1324, 1168}, "org.anbox.bar", wm::Task::Id{2}, - wm::Stack::Freeform, + wm::Stack::Id::Freeform, }; wm->apply_window_state_update({first_window, second_window}, {}); - LayerComposer composer(renderer, wm); + LayerComposer composer(renderer, std::make_shared(wm)); // A single renderable which has a different task id then the window we know // about @@ -140,7 +141,7 @@ TEST(LayerComposer, WindowPartiallyOffscreen) { // from the manager. auto platform_policy = std::make_shared(); auto app_db = std::make_shared(); - auto wm = std::make_shared(platform_policy, app_db); + auto wm = std::make_shared(platform_policy, nullptr, app_db); auto window = wm::WindowState{ wm::Display::Id{1}, @@ -148,12 +149,12 @@ TEST(LayerComposer, WindowPartiallyOffscreen) { graphics::Rect{-100, -100, 924, 668}, "org.anbox.foo", wm::Task::Id{1}, - wm::Stack::Freeform, + wm::Stack::Id::Freeform, }; wm->apply_window_state_update({window}, {}); - LayerComposer composer(renderer, wm); + LayerComposer composer(renderer, std::make_shared(wm)); // Window is build out of two layers where one is placed inside the other // but the layer covering the whole window is placed with its top left @@ -185,7 +186,7 @@ TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) { // from the manager. auto platform_policy = std::make_shared(); auto app_db = std::make_shared(); - auto wm = std::make_shared(platform_policy, app_db); + auto wm = std::make_shared(platform_policy, nullptr, app_db); auto window = wm::WindowState{ wm::Display::Id{1}, @@ -193,12 +194,12 @@ TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) { graphics::Rect{1120, 270, 2144, 1038}, "org.anbox.foo", wm::Task::Id{3}, - wm::Stack::Freeform, + wm::Stack::Id::Freeform, }; wm->apply_window_state_update({window}, {}); - LayerComposer composer(renderer, wm); + LayerComposer composer(renderer, std::make_shared(wm)); // Having two renderables where the second smaller one overlaps the bigger // one and goes a bit offscreen. This should be still placed correctly and