From f98c356efd4467c1c3c4ac7a51d89e1cf0d5ab1b Mon Sep 17 00:00:00 2001
From: Norman Feske <norman.feske@genode-labs.com>
Date: Fri, 9 Aug 2024 14:27:26 +0200
Subject: [PATCH] gui_session: manage view ID at the client side

This patch moves the management of view IDs from the server to the
client side. The former 'create_view' and 'create_child_view'
operations do no longer return a view ID but take a view ID as
argument. While changing those operations, this patch takes the
opportunity to allow for initial view attributes. Combined, those
changes simplify the window manager while accommodating typical
client use cases with less code.

To ease the client-side ID management, the Gui::Connection hosts
a 'view_ids' ID space for optional use. E.g., the new 'Top_level_view'
class uses this ID space for ID allocation. This class accommodates the
most typical use case of opening a single window.

The 'alloc_view_id' RPC function is no longer needed.

Issue #5242
---
 .../include/scout/graphics_backend_impl.h     |  12 +-
 repos/demo/src/server/nitlog/main.cc          |  51 +--
 repos/gems/include/nano3d/scene.h             |   9 +-
 repos/gems/src/app/backdrop/main.cc           |   4 +-
 repos/gems/src/app/decorator/window.h         |  29 +-
 repos/gems/src/app/menu_view/dialog.h         |  11 +-
 repos/gems/src/app/osci/main.cc               |  21 +-
 repos/gems/src/app/rom_osci/main.cc           |  21 +-
 repos/gems/src/app/screenshot_trigger/main.cc |  21 +-
 repos/gems/src/app/sculpt_manager/gui.cc      |  11 +-
 repos/gems/src/app/themed_decorator/window.h  | 107 +++---
 .../gems/src/lib/dialog/sandboxed_runtime.cc  |  20 +-
 repos/gems/src/server/gui_fader/main.cc       |  19 +-
 repos/gems/src/server/terminal/main.cc        |   4 +-
 repos/gems/src/server/wm/decorator_gui.h      | 294 ++++++----------
 repos/gems/src/server/wm/direct_gui.h         |  13 +-
 repos/gems/src/server/wm/gui.h                | 319 ++++++++----------
 repos/gems/src/server/wm/layouter_gui.h       |  15 +-
 repos/gems/src/server/wm/real_gui.h           |   2 +
 repos/libports/src/app/pdf_view/main.cc       |  10 +-
 repos/libports/src/app/usb_webcam/main.cc     |  10 +-
 .../qgenodeviewwidget/qgenodeviewwidget.cpp   |  10 +-
 .../src/test/mesa_demo/eglut/eglut_genode.cc  |  12 +-
 repos/os/include/gui_session/client.h         |  11 +-
 repos/os/include/gui_session/connection.h     | 144 ++++----
 repos/os/include/gui_session/gui_session.h    |  37 +-
 repos/os/src/app/pointer/main.cc              |   8 +-
 repos/os/src/app/status_bar/main.cc           |   7 +-
 repos/os/src/server/gui_fb/main.cc            |   6 +-
 repos/os/src/server/nitpicker/gui_session.cc  |  96 +++---
 repos/os/src/server/nitpicker/gui_session.h   |  10 +-
 repos/os/src/server/vmm/virtio_gpu.h          |   6 +-
 repos/os/src/test/capture/main.cc             |  30 +-
 repos/os/src/test/nitpicker/main.cc           |  75 ++--
 repos/os/src/test/vfs_capture/main.cc         |  30 +-
 repos/ports/src/virtualbox5/frontend/fb.h     |  21 +-
 repos/ports/src/virtualbox6/include/fb.h      |  21 +-
 37 files changed, 583 insertions(+), 944 deletions(-)

diff --git a/repos/demo/include/scout/graphics_backend_impl.h b/repos/demo/include/scout/graphics_backend_impl.h
index 6208eed97b..9f02aacb7b 100644
--- a/repos/demo/include/scout/graphics_backend_impl.h
+++ b/repos/demo/include/scout/graphics_backend_impl.h
@@ -58,19 +58,20 @@ class Scout::Graphics_backend_impl : public Graphics_backend
 
 		Point        _position;
 		Area         _view_size;
-		Gui::View_id _view { _gui.create_view() };
 		Canvas_base *_canvas[2];
 		bool         _flip_state = { false };
 
+		Gui::Top_level_view _view { _gui, { _position, _view_size } };
+
 		void _update_viewport()
 		{
 			using Command = Gui::Session::Command;
 
 			Gui::Rect rect(_position, _view_size);
-			_gui.enqueue<Command::Geometry>(_view, rect);
+			_gui.enqueue<Command::Geometry>(_view.id(), rect);
 
 			Gui::Point offset(0, _flip_state ? -_max_size.h : 0);
-			_gui.enqueue<Command::Offset>(_view, offset);
+			_gui.enqueue<Command::Offset>(_view.id(), offset);
 
 			_gui.execute();
 		}
@@ -109,8 +110,6 @@ class Scout::Graphics_backend_impl : public Graphics_backend
 			_position(position),
 			_view_size(view_size)
 		{
-			bring_to_front();
-
 			using PT = Genode::Pixel_rgb888;
 			static Canvas<PT> canvas_0(_base<PT>(0), max_size, alloc);
 			static Canvas<PT> canvas_1(_base<PT>(1), max_size, alloc);
@@ -161,8 +160,7 @@ class Scout::Graphics_backend_impl : public Graphics_backend
 
 		void bring_to_front() override
 		{
-			_gui.enqueue<Gui::Session::Command::Front>(_view);
-			_gui.execute();
+			_view.front();
 		}
 
 		void view_area(Area area) override
diff --git a/repos/demo/src/server/nitlog/main.cc b/repos/demo/src/server/nitlog/main.cc
index 3aaeabdc32..8b4ef8d1ff 100644
--- a/repos/demo/src/server/nitlog/main.cc
+++ b/repos/demo/src/server/nitlog/main.cc
@@ -348,48 +348,6 @@ class Nitlog::Root : public Root_component<Session_component>
 };
 
 
-class Log_view
-{
-	private:
-
-		Gui::Connection   &_gui;
-		Gui::Point         _pos;
-		Gui::Area          _size;
-		Gui::View_id const _view = _gui.create_view();
-
-		using Command = Gui::Session::Command;
-
-	public:
-
-		Log_view(Gui::Connection &gui, Gui::Rect geometry)
-		:
-			_gui(gui),
-			_pos(geometry.at),
-			_size(geometry.area)
-		{
-			move(_pos);
-			top();
-		}
-
-		void top()
-		{
-			_gui.enqueue<Command::Front>(_view);
-			_gui.execute();
-		}
-
-		void move(Gui::Point pos)
-		{
-			_pos = pos;
-
-			Gui::Rect rect(_pos, _size);
-			_gui.enqueue<Command::Geometry>(_view, rect);
-			_gui.execute();
-		}
-
-		Gui::Point pos() const { return _pos; }
-};
-
-
 struct Nitlog::Main
 {
 	Env &_env;
@@ -435,10 +393,7 @@ struct Nitlog::Main
 
 	bool const _canvas_initialized = (_init_canvas(), true);
 
-	/* create view for log window */
-	Gui::Rect const _view_geometry { Gui::Point(20, 20),
-	                                 Gui::Area(_win_w, _win_h) };
-	Log_view _view { _gui, _view_geometry };
+	Gui::Top_level_view _view { _gui, { { 20, 20 }, { _win_w, _win_h } } };
 
 	/* create root interface for service */
 	Root _root { _env.ep(), _sliced_heap, _log_window };
@@ -471,14 +426,14 @@ struct Nitlog::Main
 				Gui::Point const mouse_pos(x, y);
 
 				if (_key_cnt && _old_mouse_pos != _initial_mouse_pos)
-					_view.move(_view.pos() + mouse_pos - _old_mouse_pos);
+					_view.at(_view.at() + mouse_pos - _old_mouse_pos);
 
 				_old_mouse_pos = mouse_pos;
 			});
 
 			/* find selected view and bring it to front */
 			if (ev.press() && _key_cnt == 1)
-				_view.top();
+				_view.front();
 
 		}
 	}
diff --git a/repos/gems/include/nano3d/scene.h b/repos/gems/include/nano3d/scene.h
index 582081f461..7728a8c20f 100644
--- a/repos/gems/include/nano3d/scene.h
+++ b/repos/gems/include/nano3d/scene.h
@@ -144,7 +144,7 @@ class Nano3d::Scene
 
 		} _framebuffer { _gui, _size, _env.rm() };
 
-		Gui::View_id _view_id = _gui.create_view();
+		Gui::Top_level_view _view { _gui, { _pos, _size } };
 
 		using Pixel_surface = Genode::Surface<PT>;
 		using Alpha_surface = Genode::Surface<Genode::Pixel_alpha8>;
@@ -261,7 +261,7 @@ class Nano3d::Scene
 			                : -2*h;
 
 			Gui::Point const offset(0, buf_y);
-			_gui.enqueue<Command::Offset>(_view_id, offset);
+			_gui.enqueue<Command::Offset>(_view.id(), offset);
 			_gui.execute();
 
 			_do_sync = false;
@@ -279,11 +279,6 @@ class Nano3d::Scene
 		:
 			_env(env), _pos(pos), _size(size)
 		{
-			Gui::Rect rect(_pos, _size);
-			_gui.enqueue<Command::Geometry>(_view_id, rect);
-			_gui.enqueue<Command::Front>(_view_id);
-			_gui.execute();
-
 			_gui.input.sigh(_input_handler);
 
 			_timer.sigh(_periodic_handler);
diff --git a/repos/gems/src/app/backdrop/main.cc b/repos/gems/src/app/backdrop/main.cc
index 0b43e7e9c3..a78883ae4c 100644
--- a/repos/gems/src/app/backdrop/main.cc
+++ b/repos/gems/src/app/backdrop/main.cc
@@ -110,7 +110,7 @@ struct Backdrop::Main
 
 	Constructible<Buffer> _buffer { };
 
-	Gui::View_id _view_id = _gui.create_view();
+	Gui::View_id const _view_id { 1 };
 
 	void _update_view()
 	{
@@ -148,6 +148,8 @@ struct Backdrop::Main
 
 	Main(Genode::Env &env) : _env(env)
 	{
+		_gui.view(_view_id, { });
+
 		_gui.mode_sigh(_config_handler);
 
 		_config.sigh(_config_handler);
diff --git a/repos/gems/src/app/decorator/window.h b/repos/gems/src/app/decorator/window.h
index 705dda85ff..393489d565 100644
--- a/repos/gems/src/app/decorator/window.h
+++ b/repos/gems/src/app/decorator/window.h
@@ -38,46 +38,47 @@ class Decorator::Window : public Window_base
 		 */
 		bool _gui_views_up_to_date = false;
 
-		struct Gui_view
+		struct Gui_view : Genode::Noncopyable
 		{
 			Gui::Connection &_gui;
 
-			Gui::View_id _id { _gui.create_view() };
+			Gui::View_ref _view_ref { };
+
+			Gui::View_ids::Element _id { _view_ref, _gui.view_ids };
 
 			using Command = Gui::Session::Command;
 
-			Gui_view(Gui::Connection &gui, unsigned id = 0)
-			:
-				_gui(gui)
+			Gui_view(Gui::Connection &gui, unsigned win_id = 0) : _gui(gui)
 			{
 				/*
 				 * We supply the window ID as label for the anchor view.
 				 */
-				if (id)
-					_gui.enqueue<Command::Title>(_id, Gui::Title { id });
+				_gui.view(_id.id(), { .title = { win_id },
+				                      .rect  = { },
+				                      .front = false });
 			}
 
 			~Gui_view()
 			{
-				_gui.destroy_view(_id);
+				_gui.destroy_view(id());
 			}
 
-			Gui::View_id id() const { return _id; }
+			Gui::View_id id() const { return _id.id(); }
 
 			void stack(Gui::View_id neighbor)
 			{
-				_gui.enqueue<Command::Front_of>(_id, neighbor);
+				_gui.enqueue<Command::Front_of>(id(), neighbor);
 			}
 
-			void stack_front_most() { _gui.enqueue<Command::Front>(_id); }
+			void stack_front_most() { _gui.enqueue<Command::Front>(id()); }
 
-			void stack_back_most()  { _gui.enqueue<Command::Back>(_id); }
+			void stack_back_most()  { _gui.enqueue<Command::Back>(id()); }
 
 			void place(Rect rect)
 			{
-				_gui.enqueue<Command::Geometry>(_id, rect);
+				_gui.enqueue<Command::Geometry>(id(), rect);
 				Point offset = Point(0, 0) - rect.at;
-				_gui.enqueue<Command::Offset>(_id, offset);
+				_gui.enqueue<Command::Offset>(id(), offset);
 			}
 		};
 
diff --git a/repos/gems/src/app/menu_view/dialog.h b/repos/gems/src/app/menu_view/dialog.h
index b6e39fbe29..8e61fa020e 100644
--- a/repos/gems/src/app/menu_view/dialog.h
+++ b/repos/gems/src/app/menu_view/dialog.h
@@ -74,7 +74,8 @@ struct Menu_view::Dialog : List_model<Dialog>::Element
 
 	Constructible<Gui_buffer> _buffer { };
 
-	Gui::View_id const _view_id = _gui.create_view();
+	Gui::View_ref _view_ref { };
+	Gui::View_ids::Element const _view { _view_ref, _gui.view_ids };
 
 	Point _position { };
 
@@ -110,8 +111,8 @@ struct Menu_view::Dialog : List_model<Dialog>::Element
 		using Command = Gui::Session::Command;
 
 		_view_geometry = geometry;
-		_gui.enqueue<Command::Geometry>(_view_id, _view_geometry);
-		_gui.enqueue<Command::Front>(_view_id);
+		_gui.enqueue<Command::Geometry>(_view.id(), _view_geometry);
+		_gui.enqueue<Command::Front>(_view.id());
 		_gui.execute();
 	}
 
@@ -130,11 +131,15 @@ struct Menu_view::Dialog : List_model<Dialog>::Element
 		_env(env), _global_widget_factory(widget_factory), _action(action),
 		_name(_name_from_attr(node))
 	{
+		_gui.view(_view.id(), { });
+
 		_dialog_rom.sigh(_dialog_handler);
 		_dialog_handler.local_submit();
 		_gui.input.sigh(_input_handler);
 	}
 
+	~Dialog() { _gui.destroy_view(_view.id()); }
+
 	Widget::Hovered hovered_widget() const
 	{
 		return _root_widget.hovered(_hovered_position);
diff --git a/repos/gems/src/app/osci/main.cc b/repos/gems/src/app/osci/main.cc
index 9ef2697f94..2a70ec9e9f 100644
--- a/repos/gems/src/app/osci/main.cc
+++ b/repos/gems/src/app/osci/main.cc
@@ -49,24 +49,7 @@ struct Osci::Main
 
 	Constructible<Gui_buffer> _gui_buffer { };
 
-	struct View
-	{
-		Gui::Connection &_gui;
-
-		Gui::View_id _id { _gui.create_view() };
-
-		View(Gui::Connection &gui, Point position, Area size) : _gui(gui)
-		{
-			using Command = Gui::Session::Command;
-			_gui.enqueue<Command::Geometry>(_id, Rect(position, size));
-			_gui.enqueue<Command::Front>(_id);
-			_gui.execute();
-		}
-
-		~View() { _gui.destroy_view(_id); }
-	};
-
-	Constructible<View> _view { };
+	Constructible<Gui::Top_level_view> _view { };
 
 	Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer };
 
@@ -130,7 +113,7 @@ struct Osci::Main
 		_gui_buffer.construct(_gui, _size, _env.ram(), _env.rm(),
 		                      Gui_buffer::Alpha::OPAQUE, _background);
 
-		_view.construct(_gui, Point::from_xml(config), _size);
+		_view.construct(_gui, Rect { Point::from_xml(config), _size });
 
 		_timer.trigger_periodic(1000*config.attribute_value("period_ms",  20));
 	}
diff --git a/repos/gems/src/app/rom_osci/main.cc b/repos/gems/src/app/rom_osci/main.cc
index 388d497534..16c4d492e6 100644
--- a/repos/gems/src/app/rom_osci/main.cc
+++ b/repos/gems/src/app/rom_osci/main.cc
@@ -86,24 +86,7 @@ struct Osci::Main
 
 	Constructible<Gui_buffer> _gui_buffer { };
 
-	struct View
-	{
-		Gui::Connection &_gui;
-
-		Gui::View_id _id { _gui.create_view() };
-
-		View(Gui::Connection &gui, Point position, Area size) : _gui(gui)
-		{
-			using Command = Gui::Session::Command;
-			_gui.enqueue<Command::Geometry>(_id, Rect(position, size));
-			_gui.enqueue<Command::Front>(_id);
-			_gui.execute();
-		}
-
-		~View() { _gui.destroy_view(_id); }
-	};
-
-	Constructible<View> _view { };
+	Constructible<Gui::Top_level_view> _view { };
 
 	Attached_rom_dataspace _config    { _env, "config" };
 	Attached_rom_dataspace _recording { _env, "recording" };
@@ -286,7 +269,7 @@ struct Osci::Main
 		_gui_buffer.construct(_gui, _size, _env.ram(), _env.rm(),
 		                      Gui_buffer::Alpha::OPAQUE, _background);
 
-		_view.construct(_gui, Point::from_xml(config), _size);
+		_view.construct(_gui, Rect { Point::from_xml(config), _size });
 
 		_channels.update_from_xml(config,
 			[&] (Xml_node const &node) -> Registered<Channel> & {
diff --git a/repos/gems/src/app/screenshot_trigger/main.cc b/repos/gems/src/app/screenshot_trigger/main.cc
index 61b0212acb..249dd79de1 100644
--- a/repos/gems/src/app/screenshot_trigger/main.cc
+++ b/repos/gems/src/app/screenshot_trigger/main.cc
@@ -52,24 +52,7 @@ struct Screenshot_trigger::Main
 
 	Constructible<Gui_buffer> _gui_buffer { };
 
-	struct View
-	{
-		Gui::Connection &_gui;
-
-		Gui::View_id _id { _gui.create_view() };
-
-		View(Gui::Connection &gui, Point position, Area size) : _gui(gui)
-		{
-			using Command = Gui::Session::Command;
-			_gui.enqueue<Command::Geometry>(_id, Rect(position, size));
-			_gui.enqueue<Command::Front>(_id);
-			_gui.execute();
-		}
-
-		~View() { _gui.destroy_view(_id); }
-	};
-
-	Constructible<View> _view { };
+	Constructible<Gui::Top_level_view> _view { };
 
 	Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer };
 	Signal_handler<Main> _input_handler { _env.ep(), *this, &Main::_handle_input };
@@ -80,7 +63,7 @@ struct Screenshot_trigger::Main
 	void visible(bool visible)
 	{
 		_visible = visible;
-		_view.conditional(visible, _gui, _position, _area);
+		_view.conditional(visible, _gui, Rect { _position, _area });
 	}
 
 	void _handle_input()
diff --git a/repos/gems/src/app/sculpt_manager/gui.cc b/repos/gems/src/app/sculpt_manager/gui.cc
index fad116e070..0de28cf592 100644
--- a/repos/gems/src/app/sculpt_manager/gui.cc
+++ b/repos/gems/src/app/sculpt_manager/gui.cc
@@ -121,18 +121,15 @@ struct Gui::Session_component : Rpc_object<Gui::Session>
 	Input::Session_capability input() override {
 		return _input_component.cap(); }
 
-	Create_view_result create_view() override {
-		return _gui_session.create_view(); }
+	View_result view(View_id id, View_attr const &attr) override {
+		return _gui_session.view(id, attr); }
 
-	Create_child_view_result create_child_view(View_id parent) override {
-		return _gui_session.create_child_view(parent); }
+	Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override {
+		return _gui_session.child_view(id, parent, attr); }
 
 	void destroy_view(View_id view) override {
 		_gui_session.destroy_view(view); }
 
-	Alloc_view_id_result alloc_view_id(View_capability view_cap) override {
-		return _gui_session.alloc_view_id(view_cap); }
-
 	View_id_result view_id(View_capability view_cap, View_id id) override {
 		return _gui_session.view_id(view_cap, id); }
 
diff --git a/repos/gems/src/app/themed_decorator/window.h b/repos/gems/src/app/themed_decorator/window.h
index b69d4d06e6..902b6c8524 100644
--- a/repos/gems/src/app/themed_decorator/window.h
+++ b/repos/gems/src/app/themed_decorator/window.h
@@ -141,74 +141,63 @@ class Decorator::Window : public Window_base, public Animator::Item
 			func(_maximizer);
 		}
 
-		struct Gui_view
+		struct Gui_view : Genode::Noncopyable
 		{
 			using Command = Gui::Session::Command;
 
-			bool const _view_is_remote;
+			Gui::Connection       &_gui;
+			Gui::View_ref          _view_ref { };
+			Gui::View_ids::Element _id { _view_ref, _gui.view_ids };
 
-			Gui::Connection &_gui;
+			Gui_view(Gui::Connection &gui) : _gui(gui) { }
 
-			Gui::View_id _id;
-
-			Gui_view(Gui::Connection &gui, unsigned win_id = 0)
-			:
-				_view_is_remote(false),
-				_gui(gui),
-				_id(_gui.create_view())
-			{
-				/*
-				 * We supply the window ID as label for the anchor view.
-				 */
-				if (win_id)
-					_gui.enqueue<Command::Title>(_id, Gui::Title { win_id });
-			}
-
-			Gui::View_id _create_remote_view(Gui::Connection &remote_gui)
-			{
-				/* create view at the remote GUI session */
-				Gui::View_id id = remote_gui.create_view();
-				Gui::View_capability view_cap = remote_gui.view_capability(id);
-
-				/* import remote view into local GUI session */
-				return _gui.alloc_view_id(view_cap);
-			}
-
-			/**
-			 * Constructor called for creating a view that refers to a buffer
-			 * of another GUI session
-			 */
-			Gui_view(Gui::Connection &gui,
-			         Gui::Connection &remote_gui)
-			:
-				_view_is_remote(true),
-				_gui(gui),
-				_id(_create_remote_view(remote_gui))
-			{ }
-
-			~Gui_view()
-			{
-				if (_view_is_remote)
-					_gui.release_view_id(_id);
-				else
-					_gui.destroy_view(_id);
-			}
-
-			Gui::View_id id() const { return _id; }
+			Gui::View_id id() const { return _id.id(); }
 
 			void stack(Gui::View_id neighbor)
 			{
-				_gui.enqueue<Command::Front_of>(_id, neighbor);
+				_gui.enqueue<Command::Front_of>(id(), neighbor);
 			}
 
-			void stack_front_most() { _gui.enqueue<Command::Front>(_id); }
+			void stack_front_most() { _gui.enqueue<Command::Front>(id()); }
 
-			void stack_back_most()  { _gui.enqueue<Command::Back>(_id); }
+			void stack_back_most()  { _gui.enqueue<Command::Back>(id()); }
 
 			void place(Rect rect, Point offset)
 			{
-				_gui.enqueue<Command::Geometry>(_id, rect);
-				_gui.enqueue<Command::Offset>(_id, offset);
+				_gui.enqueue<Command::Geometry>(id(), rect);
+				_gui.enqueue<Command::Offset>(id(), offset);
+			}
+		};
+
+		struct Content_view : Gui_view
+		{
+			Content_view(Gui::Connection &gui, unsigned win_id = 0) : Gui_view(gui)
+			{
+				/* supply the window ID as label for the anchor view */
+				_gui.view(id(), { .title = { win_id },
+				                  .rect  = { },
+				                  .front = false });
+			}
+
+			~Content_view() { _gui.destroy_view(id()); }
+		};
+
+		struct Remote_view : Gui_view
+		{
+			Gui::Connection &_remote_gui;
+
+			Remote_view(Gui::Connection &gui, Gui::Connection &remote_gui)
+			:
+				Gui_view(gui), _remote_gui(remote_gui)
+			{
+				remote_gui.view(id(), { });
+				gui.view_id(remote_gui.view_capability(id()), id());
+			}
+
+			~Remote_view()
+			{
+				_gui.release_view_id(id());
+				_remote_gui.destroy_view(id());
 			}
 		};
 
@@ -269,12 +258,12 @@ class Decorator::Window : public Window_base, public Animator::Item
 			return Area(outer_size.w - inner_size.w, outer_size.h);
 		}
 
-		Gui_view _bottom_view { _gui, _gui_top_bottom },
-		         _right_view  { _gui, _gui_left_right },
-		         _left_view   { _gui, _gui_left_right },
-		         _top_view    { _gui, _gui_top_bottom };
+		Remote_view _bottom_view { _gui, _gui_top_bottom },
+		            _right_view  { _gui, _gui_left_right },
+		            _left_view   { _gui, _gui_left_right },
+		            _top_view    { _gui, _gui_top_bottom };
 
-		Gui_view _content_view { _gui, (unsigned)id() };
+		Content_view _content_view { _gui, (unsigned)id() };
 
 		void _repaint_decorations(Gui_buffer &buffer, Area area)
 		{
diff --git a/repos/gems/src/lib/dialog/sandboxed_runtime.cc b/repos/gems/src/lib/dialog/sandboxed_runtime.cc
index 2313ffa0b4..46089510c0 100644
--- a/repos/gems/src/lib/dialog/sandboxed_runtime.cc
+++ b/repos/gems/src/lib/dialog/sandboxed_runtime.cc
@@ -58,6 +58,7 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session>
 	Registry<Gui_session>::Element _element;
 
 	using View_capability = Gui::View_capability;
+	using View_id         = Gui::View_id;
 
 	Genode::Connection<Gui::Session> _connection;
 
@@ -125,25 +126,22 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session>
 	Input::Session_capability input() override {
 		return _input_component.cap(); }
 
-	Create_view_result create_view() override {
-		return _gui_session.create_view(); }
+	View_result view(View_id id, View_attr const &attr) override {
+		return _gui_session.view(id, attr); }
 
-	Create_child_view_result create_child_view(Gui::View_id parent) override {
-		return _gui_session.create_child_view(parent); }
+	Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override {
+		return _gui_session.child_view(id, parent, attr); }
 
-	void destroy_view(Gui::View_id view) override {
+	void destroy_view(View_id view) override {
 		_gui_session.destroy_view(view); }
 
-	Alloc_view_id_result alloc_view_id(View_capability view_cap) override {
-		return _gui_session.alloc_view_id(view_cap); }
-
-	View_id_result view_id(View_capability view_cap, Gui::View_id id) override {
+	View_id_result view_id(View_capability view_cap, View_id id) override {
 		return _gui_session.view_id(view_cap, id); }
 
-	View_capability view_capability(Gui::View_id view) override {
+	View_capability view_capability(View_id view) override {
 		return _gui_session.view_capability(view); }
 
-	void release_view_id(Gui::View_id view) override {
+	void release_view_id(View_id view) override {
 		_gui_session.release_view_id(view); }
 
 	Dataspace_capability command_dataspace() override {
diff --git a/repos/gems/src/server/gui_fader/main.cc b/repos/gems/src/server/gui_fader/main.cc
index 643486c750..62ff1bd123 100644
--- a/repos/gems/src/server/gui_fader/main.cc
+++ b/repos/gems/src/server/gui_fader/main.cc
@@ -345,18 +345,20 @@ class Gui_fader::Gui_session_component
 			return _gui.input.rpc_cap();
 		}
 
-		Create_view_result create_view() override
+		View_result view(View_id id, View_attr const &attr) override
 		{
-			_view_id.construct(_gui.create_view());
+			_view_id.construct(id);
+			_gui.view(id, attr);
 			_update_view_visibility();
-			return *_view_id;
+			return View_result::OK;
 		}
 
-		Create_child_view_result create_child_view(View_id parent) override
+		Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override
 		{
-			_view_id.construct(_gui.create_child_view(parent));
+			_view_id.construct(id);
+			_gui.child_view(id, parent, attr);
 			_update_view_visibility();
-			return *_view_id;
+			return Child_view_result::OK;
 		}
 
 		void destroy_view(View_id id) override
@@ -364,11 +366,6 @@ class Gui_fader::Gui_session_component
 			return _gui.destroy_view(id);
 		}
 
-		Alloc_view_id_result alloc_view_id(View_capability view_cap) override
-		{
-			return _gui.alloc_view_id(view_cap);
-		}
-
 		View_id_result view_id(View_capability view_cap, View_id id) override
 		{
 			_gui.view_id(view_cap, id);
diff --git a/repos/gems/src/server/terminal/main.cc b/repos/gems/src/server/terminal/main.cc
index 47c0b481d2..f81db3a24b 100644
--- a/repos/gems/src/server/terminal/main.cc
+++ b/repos/gems/src/server/terminal/main.cc
@@ -116,7 +116,7 @@ struct Terminal::Main : Character_consumer
 
 	Framebuffer::Mode _fb_mode { };
 
-	Gui::View_id _view = _gui.create_view();
+	Gui::View_id _view { };
 
 	Point _pointer { }; /* pointer positon in pixels */
 
@@ -209,6 +209,8 @@ struct Terminal::Main : Character_consumer
 
 	Main(Env &env) : _env(env)
 	{
+		_gui.view(_view, { });
+
 		_timer .sigh(_flush_handler);
 		_config.sigh(_config_handler);
 
diff --git a/repos/gems/src/server/wm/decorator_gui.h b/repos/gems/src/server/wm/decorator_gui.h
index 2d938c2989..39982fbb47 100644
--- a/repos/gems/src/server/wm/decorator_gui.h
+++ b/repos/gems/src/server/wm/decorator_gui.h
@@ -58,97 +58,6 @@ struct Wm::Decorator_content_callback : Interface
 };
 
 
-class Wm::Decorator_content_registry
-{
-	public:
-
-		/**
-		 * Exception type
-		 */
-		struct Lookup_failed { };
-
-	private:
-
-		using View_id = Gui::View_id;
-
-		struct Entry : List<Entry>::Element
-		{
-			View_id             const decorator_view_id;
-			Window_registry::Id const win_id;
-
-			Entry(View_id decorator_view_id, Window_registry::Id win_id)
-			:
-				decorator_view_id(decorator_view_id),
-				win_id(win_id)
-			{ }
-		};
-
-		List<Entry>  _list { };
-		Allocator   &_entry_alloc;
-
-		Entry const &_lookup(View_id view_id) const
-		{
-			for (Entry const *e = _list.first(); e; e = e->next()) {
-				if (e->decorator_view_id == view_id)
-					return *e;
-			}
-
-			throw Lookup_failed();
-		}
-
-		void _remove(Entry const &e)
-		{
-			_list.remove(&e);
-			destroy(_entry_alloc, const_cast<Entry *>(&e));
-		}
-
-	public:
-
-		Decorator_content_registry(Allocator &entry_alloc)
-		:
-			_entry_alloc(entry_alloc)
-		{ }
-
-		~Decorator_content_registry()
-		{
-			while (Entry *e = _list.first())
-				_remove(*e);
-		}
-
-		void insert(View_id decorator_view_id, Window_registry::Id win_id)
-		{
-			Entry *e = new (_entry_alloc) Entry(decorator_view_id, win_id);
-			_list.insert(e);
-		}
-
-		/**
-		 * Lookup window ID for a given decorator content view
-		 *
-		 * \throw Lookup_failed
-		 */
-		Window_registry::Id lookup(View_id view_id) const
-		{
-			return _lookup(view_id).win_id;
-		}
-
-		bool registered(View_id view_id) const
-		{
-			try { lookup(view_id); return true; } catch (...) { }
-			return false;
-		}
-
-		/**
-		 * Remove entry
-		 *
-		 * \throw Lookup_failed
-		 */
-		void remove(View_id view_id)
-		{
-			_remove(_lookup(view_id));
-		}
-};
-
-
 struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
                                    private List<Decorator_gui_session>::Element
 {
@@ -159,6 +68,18 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 	using View_id         = Gui::View_id;
 	using Command_buffer  = Gui::Session::Command_buffer;
 
+	struct Content_view_ref : Gui::View_ref
+	{
+		Gui::View_ids::Element id;
+
+		Window_registry::Id win_id;
+
+		Content_view_ref(Window_registry::Id win_id, Gui::View_ids &ids, View_id id)
+		: id(*this, ids, id), win_id(win_id) { }
+	};
+
+	Gui::View_ids _content_view_ids { };
+
 	Genode::Env &_env;
 
 	Genode::Heap _heap { _env.ram(), _env.rm() };
@@ -181,9 +102,6 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 
 	Decorator_content_callback &_content_callback;
 
-	/* XXX don't allocate content-registry entries from heap */
-	Decorator_content_registry _content_registry { _heap };
-
 	Allocator &_md_alloc;
 
 	/* Gui::Connection requires a valid input session */
@@ -194,6 +112,13 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 	Signal_handler<Decorator_gui_session>
 		_input_handler { _env.ep(), *this, &Decorator_gui_session::_handle_input };
 
+	Window_registry::Id _win_id_from_title(Gui::Title const &title)
+	{
+		unsigned value = 0;
+		Genode::ascii_to(title.string(), value);
+		return { value };
+	}
+
 	/**
 	 * Constructor
 	 *
@@ -233,75 +158,17 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 	{
 		switch (cmd.opcode) {
 
-		case Command::TITLE:
-			{
-				unsigned id = 0;
-				Genode::ascii_to(cmd.title.title.string(), id);
-
-				if (id > 0)
-					_content_registry.insert(cmd.title.view,
-					                         Window_registry::Id(id));
-				return;
-			}
-
-		case Command::FRONT:
-		case Command::BACK:
-		case Command::FRONT_OF:
-		case Command::BEHIND_OF:
-
-			try {
-
-				/* the first argument is the same for all stacking operations */
-				View_id const view_id = cmd.front.view;
-
-				/*
-				 * If the content view is re-stacked, replace it by the real
-				 * window content.
-				 *
-				 * The lookup fails with an exception for non-content views.
-				 * In this case, forward the command.
-				 */
-				Window_registry::Id win_id = _content_registry.lookup(view_id);
-
-				/*
-				 * Replace content view originally created by the decorator
-				 * by view that shows the real window content.
-				 */
-				View_capability view_cap = _content_callback.content_view(win_id);
-
-				_gui.session.destroy_view(view_id);
-				_gui.session.view_id(view_cap, view_id);
-
-				_gui.enqueue(cmd);
-				_gui.execute();
-
-				/*
-				 * Now that the physical content view exists, it is time
-				 * to revisit the child views.
-				 */
-				_content_callback.update_content_child_views(win_id);
-
-			} catch (Decorator_content_registry::Lookup_failed) {
-
-				_gui.enqueue(cmd);
-			}
-
-			return;
-
 		case Command::GEOMETRY:
 
-			try {
-
-				/*
-				 * If the content view changes position, propagate the new
-				 * position to the GUI service to properly transform absolute
-				 * input coordinates.
-				 */
-				Window_registry::Id win_id = _content_registry.lookup(cmd.geometry.view);
-
-				_content_callback.content_geometry(win_id, cmd.geometry.rect);
-			}
-			catch (Decorator_content_registry::Lookup_failed) { }
+			/*
+			 * If the content view changes position, propagate the new position
+			 * to the GUI service to properly transform absolute input
+			 * coordinates.
+			 */
+			_content_view_ids.apply<Content_view_ref const>(cmd.geometry.view,
+				[&] (Content_view_ref const &view_ref) {
+					_content_callback.content_geometry(view_ref.win_id, cmd.geometry.rect); },
+				[&] { });
 
 			/* forward command */
 			_gui.enqueue(cmd);
@@ -309,19 +176,29 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 
 		case Command::OFFSET:
 
-			try {
-
-				/*
-				 * If non-content views change their offset (if the lookup
-				 * fails), propagate the event
-				 */
-				_content_registry.lookup(cmd.geometry.view);
-			}
-			catch (Decorator_content_registry::Lookup_failed) {
-				_gui.enqueue(cmd);
-			}
+			/*
+			 * If non-content views change their offset (if the lookup
+			 * fails), propagate the event
+			 */
+			_content_view_ids.apply<Content_view_ref const>(cmd.geometry.view,
+				[&] (Content_view_ref const &) { },
+				[&] { _gui.enqueue(cmd); });
 			return;
 
+		case Command::FRONT:
+		case Command::BACK:
+		case Command::FRONT_OF:
+		case Command::BEHIND_OF:
+
+			_content_view_ids.apply<Content_view_ref const>(cmd.front.view,
+				[&] (Content_view_ref const &view_ref) {
+					_content_callback.update_content_child_views(view_ref.win_id); },
+				[&] { });
+
+			_gui.enqueue(cmd);
+			return;
+
+		case Command::TITLE:
 		case Command::BACKGROUND:
 		case Command::NOP:
 
@@ -359,14 +236,40 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 		return _dummy_input_component_cap;
 	}
 
-	Create_view_result create_view() override
+	View_result view(View_id id, View_attr const &attr) override
 	{
-		return _gui.session.create_view();
+		/*
+		 * The decorator marks a content view by specifying the window ID
+		 * as view title. For such views, we import the view from the
+		 * corresponding GUI cient instead of creating a new view.
+		 */
+		Window_registry::Id const win_id = _win_id_from_title(attr.title);
+		if (win_id.valid()) {
+			try {
+				Content_view_ref &view_ref_ptr = *new (_heap)
+					Content_view_ref(Window_registry::Id(win_id), _content_view_ids, id);
+
+				View_capability view_cap = _content_callback.content_view(win_id);
+				View_id_result result = _gui.session.view_id(view_cap, id);
+				if (result != View_id_result::OK)
+					destroy(_heap, &view_ref_ptr);
+
+				switch (result) {
+				case View_id_result::OUT_OF_RAM:  return View_result::OUT_OF_RAM;
+				case View_id_result::OUT_OF_CAPS: return View_result::OUT_OF_CAPS;
+				case View_id_result::OK:          return View_result::OK;
+				case View_id_result::INVALID:     break; /* fall back to regular view */
+				};
+			}
+			catch (Genode::Out_of_ram)  { return View_result::OUT_OF_RAM; }
+			catch (Genode::Out_of_caps) { return View_result::OUT_OF_CAPS; }
+		}
+		return _gui.session.view(id, attr);
 	}
 
-	Create_child_view_result create_child_view(View_id parent) override
+	Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override
 	{
-		return _gui.session.create_child_view(parent);
+		return _gui.session.child_view(id, parent, attr);
 	}
 
 	void destroy_view(View_id view) override
@@ -374,23 +277,22 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 		/*
 		 * Reset view geometry when destroying a content view
 		 */
-		if (_content_registry.registered(view)) {
-			Gui::Rect rect(Gui::Point(0, 0), Gui::Area(0, 0));
-			_gui.enqueue<Gui::Session::Command::Geometry>(view, rect);
-			_gui.execute();
+		_content_view_ids.apply<Content_view_ref>(view,
+			[&] (Content_view_ref &view_ref) {
 
-			Window_registry::Id win_id = _content_registry.lookup(view);
-			_content_callback.hide_content_child_views(win_id);
-		}
+				_content_callback.hide_content_child_views(view_ref.win_id);
+
+				Gui::Rect rect(Gui::Point(0, 0), Gui::Area(0, 0));
+				_gui.enqueue<Gui::Session::Command::Geometry>(view, rect);
+				_gui.execute();
+
+				destroy(_heap, &view_ref);
+			},
+			[&] { });
 
 		_gui.session.destroy_view(view);
 	}
 
-	Alloc_view_id_result alloc_view_id(View_capability view_cap) override
-	{
-		return _gui.session.alloc_view_id(view_cap);
-	}
-
 	View_id_result view_id(View_capability view_cap, View_id id) override
 	{
 		return _gui.session.view_id(view_cap, id);
@@ -403,7 +305,10 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 
 	void release_view_id(View_id view) override
 	{
-		/* XXX dealloc View_ptr */
+		_content_view_ids.apply<Content_view_ref>(view,
+			[&] (Content_view_ref &view_ref) { destroy(_heap, &view_ref); },
+			[&] { });
+
 		_gui.session.release_view_id(view);
 	}
 
@@ -414,14 +319,9 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
 
 	void execute() override
 	{
-		for (unsigned i = 0; i < _client_command_buffer.num(); i++) {
-			try {
-				_execute_command(_client_command_buffer.get(i));
-			}
-			catch (...) {
-				Genode::warning("unhandled exception while processing command from decorator");
-			}
-		}
+		for (unsigned i = 0; i < _client_command_buffer.num(); i++)
+			_execute_command(_client_command_buffer.get(i));
+
 		_gui.execute();
 	}
 
diff --git a/repos/gems/src/server/wm/direct_gui.h b/repos/gems/src/server/wm/direct_gui.h
index 82c4c8c0c0..e79a7c1b10 100644
--- a/repos/gems/src/server/wm/direct_gui.h
+++ b/repos/gems/src/server/wm/direct_gui.h
@@ -68,14 +68,14 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session>
 			return _session.input();
 		}
 
-		Create_view_result create_view() override
+		View_result view(View_id id, View_attr const &attr) override
 		{
-			return _session.create_view();
+			return _session.view(id, attr);
 		}
 
-		Create_child_view_result create_child_view(View_id parent) override
+		Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override
 		{
-			return _session.create_child_view(parent);
+			return _session.child_view(id, parent, attr);
 		}
 
 		void destroy_view(View_id view) override
@@ -83,11 +83,6 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session>
 			_session.destroy_view(view);
 		}
 
-		Alloc_view_id_result alloc_view_id(View_capability view_cap) override
-		{
-			return _session.alloc_view_id(view_cap);
-		}
-
 		View_id_result view_id(View_capability view_cap, View_id id) override
 		{
 			return _session.view_id(view_cap, id);
diff --git a/repos/gems/src/server/wm/gui.h b/repos/gems/src/server/wm/gui.h
index 806a5a9da0..0babf8ffc5 100644
--- a/repos/gems/src/server/wm/gui.h
+++ b/repos/gems/src/server/wm/gui.h
@@ -111,21 +111,42 @@ class Wm::Gui::View : private Genode::Weak_object<View>,
 		using Command = Gui::Session::Command;
 		using View_id = Gui::View_id;
 
-		Session_label          _session_label;
-		Real_gui              &_real_gui;
-		Constructible<View_id> _real_view       { };
-		Title                  _title           { };
-		Rect                   _geometry        { };
-		Point                  _buffer_offset   { };
-		Weak_ptr<View>         _neighbor_ptr    { };
-		bool                   _neighbor_behind { };
-		bool                   _has_alpha;
+		Session_label           _session_label;
+		Real_gui               &_real_gui;
+		Gui::View_ref           _real_view_ref { };
+		View_ids::Element const _real_view;
+		Title                   _title           { };
+		Rect                    _geometry        { };
+		Point                   _buffer_offset   { };
+		Weak_ptr<View>          _neighbor_ptr    { };
+		bool                    _neighbor_behind { };
+		bool                    _has_alpha;
+
+		void _with_temporary_view_id(View_capability cap, auto const &fn)
+		{
+			Gui::View_ref          ref { };
+			Gui::View_ids::Element tmp { ref, _real_gui.view_ids };
+
+			switch (_real_gui.session.view_id(cap, tmp.id())) {
+			case Gui::Session::View_id_result::OUT_OF_RAM:
+			case Gui::Session::View_id_result::OUT_OF_CAPS:
+			case Gui::Session::View_id_result::INVALID:
+				warning("unable to obtain view ID for given view capability");
+				return;
+			case Gui::Session::View_id_result::OK:
+				break;
+			}
+			fn(tmp.id());
+			_real_gui.session.release_view_id(tmp.id());
+		};
 
 		View(Real_gui            &real_gui,
+		     View_id       const &real_view_id,
 		     Session_label const &session_label,
 		     bool                 has_alpha)
 		:
 			_session_label(session_label), _real_gui(real_gui),
+			_real_view(_real_view_ref, _real_gui.view_ids, real_view_id),
 			_has_alpha(has_alpha)
 		{ }
 
@@ -139,37 +160,28 @@ class Wm::Gui::View : private Genode::Weak_object<View>,
 		 */
 		void _unsynchronized_apply_view_config(Locked_ptr<View> &neighbor)
 		{
-			if (!_real_view.constructed())
-				return;
-
 			_propagate_view_geometry();
-			_real_gui.enqueue<Command::Offset>(*_real_view, _buffer_offset);
-			_real_gui.enqueue<Command::Title> (*_real_view, _title);
+			_real_gui.enqueue<Command::Offset>(_real_view.id(), _buffer_offset);
+			_real_gui.enqueue<Command::Title> (_real_view.id(), _title);
 
-			Constructible<View_id> real_neighbor_id { };
+			if (neighbor.valid()) {
+				_with_temporary_view_id(neighbor->real_view_cap(), [&] (View_id id) {
+					if (_neighbor_behind)
+						_real_gui.enqueue<Command::Front_of>(_real_view.id(), id);
+					else
+						_real_gui.enqueue<Command::Behind_of>(_real_view.id(), id);
 
-			if (neighbor.valid())
-				_real_gui.session.alloc_view_id(neighbor->real_view_cap()).with_result(
-					[&] (View_id id) { real_neighbor_id.construct(id); },
-					[&] (auto) { warning("unable to obtain real_neighbor_id"); }
-				);
+					_real_gui.execute();
+				});
 
-			if (real_neighbor_id.constructed()) {
-				if (_neighbor_behind)
-					_real_gui.enqueue<Command::Front_of>(*_real_view, *real_neighbor_id);
-				else
-					_real_gui.enqueue<Command::Behind_of>(*_real_view, *real_neighbor_id);
 			} else {
 				if (_neighbor_behind)
-					_real_gui.enqueue<Command::Front>(*_real_view);
+					_real_gui.enqueue<Command::Front>(_real_view.id());
 				else
-					_real_gui.enqueue<Command::Back>(*_real_view);
+					_real_gui.enqueue<Command::Back>(_real_view.id());
+
+				_real_gui.execute();
 			}
-
-			_real_gui.execute();
-
-			if (real_neighbor_id.constructed())
-				_real_gui.session.release_view_id(*real_neighbor_id);
 		}
 
 		void _apply_view_config()
@@ -182,8 +194,7 @@ class Wm::Gui::View : private Genode::Weak_object<View>,
 
 		~View()
 		{
-			if (_real_view.constructed())
-				_real_gui.session.destroy_view(*_real_view);
+			_real_gui.session.destroy_view(_real_view.id());
 		}
 
 		using Genode::Weak_object<View>::weak_ptr;
@@ -196,24 +207,16 @@ class Wm::Gui::View : private Genode::Weak_object<View>,
 		virtual void geometry(Rect geometry)
 		{
 			_geometry = geometry;
-
-			/*
-			 * Propagate new size to real GUI view but
-			 */
-			if (_real_view.constructed()) {
-				_propagate_view_geometry();
-				_real_gui.execute();
-			}
+			_propagate_view_geometry();
+			_real_gui.execute();
 		}
 
 		virtual void title(Title const &title)
 		{
 			_title = title;
 
-			if (_real_view.constructed()) {
-				_real_gui.enqueue<Command::Title>(*_real_view, title);
-				_real_gui.execute();
-			}
+			_real_gui.enqueue<Command::Title>(_real_view.id(), title);
+			_real_gui.execute();
 		}
 
 		virtual Point input_anchor_position() const = 0;
@@ -222,19 +225,15 @@ class Wm::Gui::View : private Genode::Weak_object<View>,
 
 		View_capability real_view_cap()
 		{
-			return _real_view.constructed()
-			     ? _real_gui.session.view_capability(*_real_view)
-			     : View_capability();
+			return _real_gui.session.view_capability(_real_view.id());
 		}
 
 		void buffer_offset(Point buffer_offset)
 		{
 			_buffer_offset = buffer_offset;
 
-			if (_real_view.constructed()) {
-				_real_gui.enqueue<Command::Offset>(*_real_view, _buffer_offset);
-				_real_gui.execute();
-			}
+			_real_gui.enqueue<Command::Offset>(_real_view.id(), _buffer_offset);
+			_real_gui.execute();
 		}
 
 		bool has_alpha() const { return _has_alpha; }
@@ -270,15 +269,23 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme
 	public:
 
 		Top_level_view(Real_gui                     &real_gui,
+		               View_id                       view_id,
 		               bool                          has_alpha,
 		               Window_registry              &window_registry,
 		               Input_origin_changed_handler &input_origin_changed_handler)
 		:
-			View(real_gui, real_gui.label, has_alpha),
+			View(real_gui, view_id, real_gui.label, has_alpha),
 			_window_registry(window_registry),
 			_input_origin_changed_handler(input_origin_changed_handler),
 			_session_label(real_gui.label)
-		{ }
+		{
+			/*
+			 * Create and configure physical GUI view.
+			 */
+			_real_gui.session.view(_real_view.id(), { .title = _title,
+			                                          .rect  = { },
+			                                          .front = false });
+		}
 
 		~Top_level_view()
 		{
@@ -290,31 +297,6 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme
 
 		using List<Top_level_view>::Element::next;
 
-		void init_real_gui_view()
-		{
-			if (_real_view.constructed())
-				return;
-
-			/*
-			 * Create and configure physical GUI view.
-			 */
-			_real_gui.session.create_view().with_result(
-				[&] (View_id id) {
-					_real_view.construct(id);
-					_real_gui.enqueue<Command::Offset>(id, _buffer_offset);
-					_real_gui.enqueue<Command::Title> (id, _title.string());
-					_real_gui.execute();
-				},
-				[&] (Gui::Session::Create_view_error) {
-					warning("init_real_view failed");
-				}
-			);
-
-			if (!_real_view.constructed()) {
-				warning("failed to created content view for ", _title);
-			}
-		}
-
 		void _propagate_view_geometry() override { }
 
 		void geometry(Rect geometry) override
@@ -373,13 +355,7 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme
 
 		View_capability content_view()
 		{
-			init_real_gui_view();
-
-			if (_real_view.constructed())
-				return _real_gui.session.view_capability(*_real_view);
-
-			error("content_view was unable to obtain real view");
-			return { };
+			return _real_gui.session.view_capability(_real_view.id());
 		}
 
 		void hidden(bool hidden) { _window_registry.hidden(_win_id, hidden); }
@@ -402,13 +378,16 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element
 
 		Weak_ptr<View> mutable _parent;
 
+		bool _visible = false;
+
 	public:
 
 		Child_view(Real_gui      &real_gui,
+		           View_id        real_gui_id,
 		           bool           has_alpha,
 		           Weak_ptr<View> parent)
 		:
-			View(real_gui, real_gui.label, has_alpha), _parent(parent)
+			View(real_gui, real_gui_id, real_gui.label, has_alpha), _parent(parent)
 		{
 			try_to_init_real_view();
 		}
@@ -422,8 +401,7 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element
 
 		void _propagate_view_geometry() override
 		{
-			if (_real_view.constructed())
-				_real_gui.enqueue<Command::Geometry>(*_real_view, _geometry);
+			_real_gui.enqueue<Command::Geometry>(_real_view.id(), _geometry);
 		}
 
 		void stack(Weak_ptr<View> neighbor_ptr, bool behind) override
@@ -451,35 +429,30 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element
 
 		void try_to_init_real_view()
 		{
-			if (_real_view.constructed())
-				return;
-
 			Locked_ptr<View> parent(_parent);
 			if (!parent.valid())
 				return;
 
-			Constructible<View_id> parent_id { };
-			_real_gui.session.alloc_view_id(parent->real_view_cap()).with_result(
-				[&] (View_id id) { parent_id.construct(id); },
-				[&] (Gui::Session::Alloc_view_id_error e) {
-					warning("try_to_init_real_view could not alloc parent ID e=", (int)e);
-				}
-			);
-			if (!parent_id.constructed()) {
-				warning("try_to_init_real_view failed to obtain parent ID");
-				return;
-			}
+			_with_temporary_view_id(parent->real_view_cap(), [&] (View_id parent_id) {
 
-			_real_gui.session.create_child_view(*parent_id).with_result(
-				[&] (View_id id) { _real_view.construct(id); },
-				[&] (Gui::Session::Create_child_view_error) { }
-			);
-			if (!_real_view.constructed()) {
-				warning("try_to_init_real_view failed to create child view");
-				return;
-			}
+				if (_visible)
+					return;
 
-			_real_gui.session.release_view_id(*parent_id);
+				Gui::Session::View_attr const attr { .title = _title,
+				                                     .rect  = _geometry,
+				                                     .front = false };
+
+				switch (_real_gui.session.child_view(_real_view.id(), parent_id, attr)) {
+				case Gui::Session::Child_view_result::OUT_OF_RAM:
+				case Gui::Session::Child_view_result::OUT_OF_CAPS:
+				case Gui::Session::Child_view_result::INVALID:
+					warning("unable to create child view");
+					return;
+				case Gui::Session::Child_view_result::OK:
+					break;
+				};
+				_visible = true;
+			});
 
 			if (_neighbor_ptr == _parent)
 				_unsynchronized_apply_view_config(parent);
@@ -494,11 +467,8 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element
 
 		void hide()
 		{
-			if (!_real_view.constructed())
-				return;
-
-			_real_gui.session.destroy_view(*_real_view);
-			_real_view.destruct();
+			_real_gui.session.destroy_view(_real_view.id());
+			_visible = false;
 		}
 };
 
@@ -511,8 +481,7 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>,
 
 		friend class List<Session_component>;
 
-		using View_id  = Gui::View_id;
-		using View_ids = Id_space<Gui::View_ref>;
+		using View_id = Gui::View_id;
 
 		struct View_ref : Gui::View_ref
 		{
@@ -550,7 +519,7 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>,
 		Real_gui                     _real_gui { _env, _session_label };
 		Window_registry             &_window_registry;
 		Tslab<Top_level_view, 8000>  _top_level_view_alloc;
-		Tslab<Child_view, 6000>      _child_view_alloc;
+		Tslab<Child_view, 7000>      _child_view_alloc;
 		Tslab<View_ref, 4000>        _view_ref_alloc;
 		List<Top_level_view>         _top_level_views { };
 		List<Child_view>             _child_views { };
@@ -972,26 +941,28 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>,
 		}
 
 		template <typename VIEW>
-		Create_view_result _create_view_with_id(auto &dealloc, auto const &create_fn)
+		View_result _create_view_with_id(auto &dealloc, View_id id, View_attr const &attr, auto const &create_fn)
 		{
-			Create_view_error error { };
+			release_view_id(id);
+
+			View_result error { };
 
 			VIEW *view_ptr = nullptr;
 			try {
-				view_ptr = create_fn();
+				view_ptr = &create_fn();
 			}
-			catch (Out_of_ram)  { error = Create_view_error::OUT_OF_RAM;  }
-			catch (Out_of_caps) { error = Create_view_error::OUT_OF_CAPS; }
+			catch (Out_of_ram)  { error = View_result::OUT_OF_RAM;  }
+			catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; }
 			if (!view_ptr)
 				return error;
 
 			View_ref *view_ref_ptr = nullptr;
 			try {
 				view_ref_ptr =
-					new (_view_ref_alloc) View_ref(view_ptr->weak_ptr(), _view_ids);
+					new (_view_ref_alloc) View_ref(view_ptr->weak_ptr(), _view_ids, id);
 			}
-			catch (Out_of_ram)  { error = Create_view_error::OUT_OF_RAM;  }
-			catch (Out_of_caps) { error = Create_view_error::OUT_OF_CAPS; }
+			catch (Out_of_ram)  { error = View_result::OUT_OF_RAM;  }
+			catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; }
 			if (!view_ref_ptr) {
 				destroy(dealloc, view_ptr);
 				return error;
@@ -999,64 +970,64 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>,
 
 			_env.ep().manage(*view_ptr);
 
-			return view_ref_ptr->id.id();
+			/* apply initial view attributes */
+			_execute_command(Command::Title    { id, attr.title });
+			_execute_command(Command::Geometry { id, attr.rect  });
+			if (attr.front) {
+				_execute_command(Command::Front { id });
+				_window_registry.flush();
+			}
+
+			return View_result::OK;
 		}
 
-		Create_view_result create_view() override
+		View_result view(View_id id, View_attr const &attr) override
 		{
 			Top_level_view *view_ptr = nullptr;
 
-			Create_view_result const result =
-				_create_view_with_id<Top_level_view>(_top_level_view_alloc,
-					[&] {
+			View_result const result =
+				_create_view_with_id<Top_level_view>(_top_level_view_alloc, id, attr,
+					[&] () -> Top_level_view & {
 						view_ptr = new (_top_level_view_alloc)
-							Top_level_view(_real_gui, _has_alpha,
+							Top_level_view(_real_gui, id, _has_alpha,
 							               _window_registry, *this);
-						return view_ptr;
+						return *view_ptr;
 					});
 
-			if (result.ok() && view_ptr) {
-
-				view_ptr->init_real_gui_view();
-
+			if (result == View_result::OK && view_ptr) {
 				view_ptr->resizeable(_mode_sigh.valid());
 				_top_level_views.insert(view_ptr);
 			}
 			return result;
 		}
 
-		Create_child_view_result create_child_view(View_id const parent) override
+		Child_view_result child_view(View_id const id, View_id const parent, View_attr const &attr) override
 		{
-			using Error = Create_child_view_error;
 			return _with_view(parent,
-				[&] (View &parent) -> Create_child_view_result {
+				[&] (View &parent) -> Child_view_result {
 
 					Child_view *view_ptr = nullptr;
 
-					Create_view_result const result =
-						_create_view_with_id<Child_view>(_child_view_alloc,
-							[&] {
+					View_result const result =
+						_create_view_with_id<Child_view>(_child_view_alloc, id, attr,
+							[&] () -> Child_view & {
 								view_ptr = new (_child_view_alloc)
-									Child_view(_real_gui, _has_alpha, parent.weak_ptr());
-								return view_ptr;
+									Child_view(_real_gui, id, _has_alpha, parent.weak_ptr());
+								return *view_ptr;
 							});
 
-					return result.convert<Create_child_view_result>(
-						[&] (View_id id) {
-							if (view_ptr)
-								_child_views.insert(view_ptr);
-							return id;
-						},
-						[&] (Create_view_error e) {
-							switch (e) {
-							case Create_view_error::OUT_OF_RAM:  return Error::OUT_OF_RAM;
-							case Create_view_error::OUT_OF_CAPS: return Error::OUT_OF_CAPS;
-							};
-							return Error::INVALID;
-						}
-					);
+					switch (result) {
+					case View_result::OUT_OF_RAM:  return Child_view_result::OUT_OF_RAM;
+					case View_result::OUT_OF_CAPS: return Child_view_result::OUT_OF_CAPS;
+					case View_result::OK:          break;
+					}
+
+					if (view_ptr)
+						_child_views.insert(view_ptr);
+
+					return Child_view_result::OK;
 				},
-				[&] () -> Create_child_view_result { return Error::INVALID; });
+				[&] () -> Child_view_result { return Child_view_result::INVALID; });
 		}
 
 		void destroy_view(View_id id) override
@@ -1079,22 +1050,6 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>,
 			release_view_id(id);
 		}
 
-		Alloc_view_id_result alloc_view_id(View_capability view_cap) override
-		{
-			return _env.ep().rpc_ep().apply(view_cap,
-				[&] (View *view_ptr) -> Alloc_view_id_result {
-					if (!view_ptr)
-						return Alloc_view_id_error::INVALID;
-					try {
-						View_ref &view_ref = *new (_view_ref_alloc)
-							View_ref(view_ptr->weak_ptr(), _view_ids);
-						return view_ref.id.id();
-					}
-					catch (Out_of_ram)  { return Alloc_view_id_error::OUT_OF_RAM;  }
-					catch (Out_of_caps) { return Alloc_view_id_error::OUT_OF_CAPS; }
-				});
-		}
-
 		View_id_result view_id(View_capability view_cap, View_id id) override
 		{
 			/* prevent ID conflict in 'View_ids::Element' constructor */
@@ -1192,7 +1147,11 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>,
 			 * upgrades initiated by the wm client's buffer operation twice.
 			 */
 			_has_alpha = has_alpha;
-			return _real_gui.session.buffer(mode, has_alpha);
+
+			Buffer_result const result = _real_gui.session.buffer(mode, has_alpha);
+
+			_window_registry.flush();
+			return result;
 		}
 
 		void focus(Genode::Capability<Gui::Session>) override { }
diff --git a/repos/gems/src/server/wm/layouter_gui.h b/repos/gems/src/server/wm/layouter_gui.h
index 9ef22cdfe8..833de80511 100644
--- a/repos/gems/src/server/wm/layouter_gui.h
+++ b/repos/gems/src/server/wm/layouter_gui.h
@@ -62,17 +62,18 @@ struct Wm::Layouter_gui_session : Genode::Rpc_object<Gui::Session>
 		return _input_session_cap;
 	}
 
-	Create_view_result create_view() override { return View_id(); }
+	View_result view(View_id, View_attr const &) override
+	{
+		return View_result::OK;
+	}
 
-	Create_child_view_result create_child_view(View_id) override { return View_id(); }
+	Child_view_result child_view(View_id, View_id, View_attr const &) override
+	{
+		return Child_view_result::OK;
+	}
 
 	void destroy_view(View_id) override { }
 
-	Alloc_view_id_result alloc_view_id(View_capability) override
-	{
-		return View_id();
-	}
-
 	View_id_result view_id(View_capability, View_id) override
 	{
 		return View_id_result::OK;
diff --git a/repos/gems/src/server/wm/real_gui.h b/repos/gems/src/server/wm/real_gui.h
index bfbeac4f13..f41af24b0e 100644
--- a/repos/gems/src/server/wm/real_gui.h
+++ b/repos/gems/src/server/wm/real_gui.h
@@ -54,6 +54,8 @@ struct Wm::Real_gui
 
 	public:
 
+		Gui::View_ids view_ids { };
+
 		template <typename CMD>
 		void enqueue(auto &&... args) { enqueue(Gui::Session::Command( CMD { args... } )); }
 
diff --git a/repos/libports/src/app/pdf_view/main.cc b/repos/libports/src/app/pdf_view/main.cc
index af7c092125..904a47183d 100644
--- a/repos/libports/src/app/pdf_view/main.cc
+++ b/repos/libports/src/app/pdf_view/main.cc
@@ -107,7 +107,7 @@ class Pdf_view
 		Genode::Signal_handler<Pdf_view> _input_handler {
 			_env.ep(), *this, &Pdf_view::_handle_input_events };
 
-		Gui::View_id _view = _gui.create_view();
+		Gui::Top_level_view _view { _gui };
 
 		pixel_t *_fb_base() { return _fb_ds->local_addr<pixel_t>(); }
 
@@ -140,10 +140,8 @@ class Pdf_view
 			_pdfapp.resolution = Genode::min(_nit_mode.area.w/5,
 			                                 _nit_mode.area.h/4);
 
-			using Command = Gui::Session::Command;
-			_gui.enqueue<Command::Geometry>(_view, Gui::Rect(Gui::Point(), _nit_mode.area));
-			_gui.enqueue<Command::Front>(_view);
-			_gui.execute();
+			_view.area(_nit_mode.area);
+			_view.front();
 		}
 
 		void _handle_nit_mode()
@@ -272,7 +270,7 @@ class Pdf_view
 		void title(Gui::Title const &msg)
 		{
 			using Command = Gui::Session::Command;
-			_gui.enqueue<Command::Title>(_view, msg);
+			_gui.enqueue<Command::Title>(_view.id(), msg);
 			_gui.execute();
 		}
 
diff --git a/repos/libports/src/app/usb_webcam/main.cc b/repos/libports/src/app/usb_webcam/main.cc
index 2d626fe37b..97ea891001 100644
--- a/repos/libports/src/app/usb_webcam/main.cc
+++ b/repos/libports/src/app/usb_webcam/main.cc
@@ -48,8 +48,8 @@ class Viewer
 
 		Genode::Env            &_env;
 		Gui::Connection         _gui  { _env, "webcam" };
-		Gui::View_id            _view { _gui.create_view() };
 		Framebuffer::Mode const _mode;
+		Gui::Top_level_view     _view { _gui, { { }, _mode.area } };
 
 		Constructible<Genode::Attached_dataspace> _fb_ds { };
 		uint8_t *_framebuffer { nullptr };
@@ -65,14 +65,6 @@ class Viewer
 
 			_fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace());
 			_framebuffer = _fb_ds->local_addr<uint8_t>();
-
-			using Command = Gui::Session::Command;
-			using namespace Gui;
-
-			_gui.enqueue<Command::Geometry>(_view, Gui::Rect(Gui::Point(0, 0), _mode.area));
-			_gui.enqueue<Command::Front>(_view);
-			_gui.enqueue<Command::Title>(_view, "webcam");
-			_gui.execute();
 		}
 
 		uint8_t *framebuffer() { return _framebuffer; }
diff --git a/repos/libports/src/lib/qgenodeviewwidget/qgenodeviewwidget.cpp b/repos/libports/src/lib/qgenodeviewwidget/qgenodeviewwidget.cpp
index e3084970cf..a60ccc03a3 100644
--- a/repos/libports/src/lib/qgenodeviewwidget/qgenodeviewwidget.cpp
+++ b/repos/libports/src/lib/qgenodeviewwidget/qgenodeviewwidget.cpp
@@ -221,13 +221,15 @@ void QGenodeViewWidget::paintEvent(QPaintEvent *event)
 	QGenodePlatformWindow *platform_window =
 		dynamic_cast<QGenodePlatformWindow*>(window()->windowHandle()->handle());
 
-	Gui::View_id const neighbor_id =
-		gui->alloc_view_id(platform_window->view_cap());
+	Gui::View_ref tmp_view_ref { };
+	Gui::View_ids::Element neighbor_id { tmp_view_ref, gui->view_ids };
 
-	gui->enqueue<Command::Front_of>(view_id, neighbor_id);
+	gui->view_id(platform_window->view_cap(), neighbor_id.id());
+
+	gui->enqueue<Command::Front_of>(view_id, neighbor_id.id());
 	gui->execute();
 
-	gui->release_view_id(neighbor_id);
+	gui->release_view_id(neighbor_id.id());
 }
 
 
diff --git a/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc b/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc
index ea9779cb81..d432ba8bf5 100644
--- a/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc
+++ b/repos/libports/src/test/mesa_demo/eglut/eglut_genode.cc
@@ -48,7 +48,8 @@ struct Window : Genode_egl_window
 	Framebuffer::Mode mode;
 	Gui::Connection   gui { env };
 	Genode::Constructible<Genode::Attached_dataspace> ds { };
-	Gui::View_id      view { };
+
+	Gui::Top_level_view view { gui };
 
 	Genode::addr_t fb_addr { 0 };
 	Genode::addr_t fb_size { 0 };
@@ -63,13 +64,8 @@ struct Window : Genode_egl_window
 		type   = WINDOW;
 
 		gui.buffer(mode, false);
-		view = gui.create_view();
 
 		mode_change();
-
-		gui.enqueue<Command::Title>(view, "eglut");
-		gui.enqueue<Command::Front>(view);
-		gui.execute();
 	}
 
 	void mode_change()
@@ -81,9 +77,7 @@ struct Window : Genode_egl_window
 
 		addr = ds->local_addr<unsigned char>();
 
-		Gui::Rect rect { Gui::Point { 0, 0 }, mode.area };
-		gui.enqueue<Command::Geometry>(view, rect);
-		gui.execute();
+		view.area(mode.area);
 	}
 
 	void refresh()
diff --git a/repos/os/include/gui_session/client.h b/repos/os/include/gui_session/client.h
index 5508e132f0..a28776f9fc 100644
--- a/repos/os/include/gui_session/client.h
+++ b/repos/os/include/gui_session/client.h
@@ -30,18 +30,15 @@ struct Gui::Session_client : Rpc_client<Session>
 	Input::Session_capability input() override {
 		return call<Rpc_input>(); }
 
-	Create_view_result create_view() override {
-		return call<Rpc_create_view>(); }
+	View_result view(View_id id, View_attr const &attr) override {
+		return call<Rpc_view>(id, attr); }
 
-	Create_child_view_result create_child_view(View_id parent) override {
-		return call<Rpc_create_child_view>(parent); }
+	Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override {
+		return call<Rpc_child_view>(id, parent, attr); }
 
 	void destroy_view(View_id view) override {
 		call<Rpc_destroy_view>(view); }
 
-	Alloc_view_id_result alloc_view_id(View_capability view) override {
-		return call<Rpc_alloc_view_id>(view); }
-
 	View_id_result view_id(View_capability view, View_id id) override {
 		return call<Rpc_view_id>(view, id); }
 
diff --git a/repos/os/include/gui_session/connection.h b/repos/os/include/gui_session/connection.h
index 52a473fb7f..07d1710fca 100644
--- a/repos/os/include/gui_session/connection.h
+++ b/repos/os/include/gui_session/connection.h
@@ -19,7 +19,10 @@
 #include <input_session/client.h>
 #include <base/connection.h>
 
-namespace Gui { class Connection; }
+namespace Gui {
+	class  Connection;
+	struct Top_level_view;
+}
 
 
 class Gui::Connection : private Genode::Connection<Session>
@@ -40,6 +43,8 @@ class Gui::Connection : private Genode::Connection<Session>
 
 	public:
 
+		View_ids view_ids { };
+
 		/**
 		 * Framebuffer access
 		 */
@@ -64,44 +69,33 @@ class Gui::Connection : private Genode::Connection<Session>
 			_env(env)
 		{ }
 
-		View_id create_view()
+		void view(View_id id, Session::View_attr const &attr)
 		{
-			View_id result { };
-			for (bool retry = false; ; ) {
-				using Error = Session_client::Create_view_error;
-				_client.create_view().with_result(
-					[&] (View_id id) { result = id; },
-					[&] (Error e) {
-						switch (e) {
-						case Error::OUT_OF_RAM:  upgrade_ram(8*1024); retry = true; return;
-						case Error::OUT_OF_CAPS: upgrade_caps(2);     retry = true; return;
-						}
-					});
-				if (!retry)
-					break;
+			for (;;) {
+				using Result = Session::View_result;
+				switch (_client.view(id, attr)) {
+				case Result::OUT_OF_RAM:  upgrade_ram(8*1024); break;
+				case Result::OUT_OF_CAPS: upgrade_caps(2);     break;
+				case Result::OK:
+					return;
+				}
 			}
-			return result;
 		}
 
-		View_id create_child_view(View_id parent)
+		void child_view(View_id id, View_id parent, Session::View_attr const &attr)
 		{
-			View_id result { };
-			for (bool retry = false; ; ) {
-				using Error = Session_client::Create_child_view_error;
-				_client.create_child_view(parent).with_result(
-					[&] (View_id id) { result = id; },
-					[&] (Error e) {
-						switch (e) {
-						case Error::OUT_OF_RAM:  upgrade_ram(8*1024); retry = true; return;
-						case Error::OUT_OF_CAPS: upgrade_caps(2);     retry = true; return;
-						case Error::INVALID:     break;
-						}
-						error("failed to create child view for invalid parent view");
-					});
-				if (!retry)
-					break;
+			for (;;) {
+				using Result = Session::Child_view_result;
+				switch (_client.child_view(id, parent, attr)) {
+				case Result::OUT_OF_RAM:  upgrade_ram(8*1024); break;
+				case Result::OUT_OF_CAPS: upgrade_caps(2);     break;
+				case Result::OK:
+					return;
+				case Result::INVALID:
+					error("failed to create child view for invalid parent view");
+					return;
+				}
 			}
-			return result;
 		}
 
 		void destroy_view(View_id view)
@@ -119,27 +113,6 @@ class Gui::Connection : private Genode::Connection<Session>
 			return _client.view_capability(id);
 		}
 
-		View_id alloc_view_id(View_capability view)
-		{
-			View_id result { };
-			for (bool retry = false; ; ) {
-				using Error = Session_client::Alloc_view_id_error;
-				_client.alloc_view_id(view).with_result(
-					[&] (View_id id) { result = id; },
-					[&] (Error e) {
-						switch (e) {
-						case Error::OUT_OF_RAM:  upgrade_ram(8*1024); retry = true; return;
-						case Error::OUT_OF_CAPS: upgrade_caps(2);     retry = true; return;
-						case Error::INVALID: break;
-						}
-						warning("attempt to alloc ID for invalid view");
-					});
-				if (!retry)
-					break;
-			}
-			return result;
-		}
-
 		void view_id(View_capability view, View_id id)
 		{
 			using Result = Session::View_id_result;
@@ -200,17 +173,62 @@ class Gui::Connection : private Genode::Connection<Session>
 			_command_buffer.reset();
 		}
 
-	/**
-	 * Return physical screen mode
-	 */
-	Framebuffer::Mode mode() { return _client.mode(); }
+		/**
+		 * Return physical screen mode
+		 */
+		Framebuffer::Mode mode() { return _client.mode(); }
 
-	/**
-	 * Register signal handler to be notified about mode changes
-	 */
-	void mode_sigh(Signal_context_capability sigh) { _client.mode_sigh(sigh); }
+		/**
+		 * Register signal handler to be notified about mode changes
+		 */
+		void mode_sigh(Signal_context_capability sigh) { _client.mode_sigh(sigh); }
 
-	void focus(Capability<Session> focused) { _client.focus(focused); }
+		void focus(Capability<Session> focused) { _client.focus(focused); }
+};
+
+
+/**
+ * Helper for the common case of creating a top-level view
+ */
+class Gui::Top_level_view : View_ref, View_ids::Element
+{
+	private:
+
+		Connection &_gui;
+
+		Rect _rect;
+
+	public:
+
+		using View_ids::Element::id;
+
+		Top_level_view(Connection &gui, Rect rect = { })
+		:
+			View_ids::Element(*this, gui.view_ids), _gui(gui), _rect(rect)
+		{
+			_gui.view(id(), { .title = { }, .rect = rect, .front = true });
+		}
+
+		~Top_level_view() { _gui.destroy_view(id()); }
+
+		void front()
+		{
+			_gui.enqueue<Session::Command::Front>(id());
+			_gui.execute();
+		}
+
+		void geometry(Rect rect)
+		{
+			_rect = rect;
+			_gui.enqueue<Session::Command::Geometry>(id(), _rect);
+			_gui.execute();
+		}
+
+		void area(Area area) { geometry(Rect { _rect.at, area } ); }
+		void at  (Point at)  { geometry(Rect { at, _rect.area } ); }
+
+		Area  area() const { return _rect.area; }
+		Point at()   const { return _rect.at;   }
 };
 
 #endif /* _INCLUDE__GUI_SESSION__CONNECTION_H_ */
diff --git a/repos/os/include/gui_session/gui_session.h b/repos/os/include/gui_session/gui_session.h
index c17a6150c4..e631beef44 100644
--- a/repos/os/include/gui_session/gui_session.h
+++ b/repos/os/include/gui_session/gui_session.h
@@ -37,6 +37,7 @@ namespace Gui {
 	struct View_ref : Interface { };
 
 	using View_capability = Capability<View>;
+	using View_ids        = Id_space<View_ref>;
 	using View_id         = Id_space<View_ref>::Id;
 
 	using Title = String<64>;
@@ -170,16 +171,21 @@ struct Gui::Session : Genode::Session
 	 */
 	virtual Input::Session_capability input() = 0;
 
-	enum class Create_view_error { OUT_OF_RAM, OUT_OF_CAPS };
-	using      Create_view_result = Attempt<View_id, Create_view_error>;
+	struct View_attr
+	{
+		Title title;
+		Rect  rect;
+		bool  front;
+	};
+
+	enum class View_result { OK, OUT_OF_RAM, OUT_OF_CAPS };
 
 	/**
 	 * Create a new top-level view at the buffer
 	 */
-	virtual Create_view_result create_view() = 0;
+	virtual View_result view(View_id, View_attr const &) = 0;
 
-	enum class Create_child_view_error { OUT_OF_RAM, OUT_OF_CAPS, INVALID };
-	using      Create_child_view_result = Attempt<View_id, Create_child_view_error>;
+	enum class Child_view_result { OK, OUT_OF_RAM, OUT_OF_CAPS, INVALID };
 
 	/**
 	 * Create a new child view at the buffer
@@ -187,24 +193,13 @@ struct Gui::Session : Genode::Session
 	 * The 'parent' argument allows the client to use the location of an
 	 * existing view as the coordinate origin for the to-be-created view.
 	 */
-	virtual Create_child_view_result create_child_view(View_id parent) = 0;
+	virtual Child_view_result child_view(View_id, View_id parent, View_attr const &) = 0;
 
 	/**
 	 * Destroy view
 	 */
 	virtual void destroy_view(View_id) = 0;
 
-	enum class Alloc_view_id_error { OUT_OF_RAM, OUT_OF_CAPS, INVALID };
-	using      Alloc_view_id_result = Attempt<View_id, Alloc_view_id_error>;
-
-	/**
-	 * Return session-local ID for the specified view
-	 *
-	 * The ID returned by this method can be used to issue commands via the
-	 * 'execute' method.
-	 */
-	virtual Alloc_view_id_result alloc_view_id(View_capability) = 0;
-
 	enum class View_id_result { OK, OUT_OF_RAM, OUT_OF_CAPS, INVALID };
 
 	/**
@@ -286,10 +281,9 @@ struct Gui::Session : Genode::Session
 
 	GENODE_RPC(Rpc_framebuffer, Framebuffer::Session_capability, framebuffer);
 	GENODE_RPC(Rpc_input, Input::Session_capability, input);
-	GENODE_RPC(Rpc_create_view, Create_view_result, create_view);
-	GENODE_RPC(Rpc_create_child_view, Create_child_view_result, create_child_view, View_id);
+	GENODE_RPC(Rpc_view, View_result, view, View_id, View_attr const &);
+	GENODE_RPC(Rpc_child_view, Child_view_result, child_view, View_id, View_id, View_attr const &);
 	GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_id);
-	GENODE_RPC(Rpc_alloc_view_id, Alloc_view_id_result, alloc_view_id, View_capability);
 	GENODE_RPC(Rpc_view_id, View_id_result, view_id, View_capability, View_id);
 	GENODE_RPC(Rpc_view_capability, View_capability, view_capability, View_id);
 	GENODE_RPC(Rpc_release_view_id, void, release_view_id, View_id);
@@ -302,8 +296,7 @@ struct Gui::Session : Genode::Session
 	GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Framebuffer::Mode, bool);
 
 	GENODE_RPC_INTERFACE(Rpc_framebuffer, Rpc_input,
-	                     Rpc_create_view, Rpc_create_child_view, Rpc_destroy_view,
-	                     Rpc_alloc_view_id, Rpc_view_id,
+	                     Rpc_view, Rpc_child_view, Rpc_destroy_view, Rpc_view_id,
 	                     Rpc_view_capability, Rpc_release_view_id,
 	                     Rpc_command_dataspace, Rpc_execute, Rpc_mode,
 	                     Rpc_mode_sigh, Rpc_buffer, Rpc_focus);
diff --git a/repos/os/src/app/pointer/main.cc b/repos/os/src/app/pointer/main.cc
index f045ccfb63..ec98137354 100644
--- a/repos/os/src/app/pointer/main.cc
+++ b/repos/os/src/app/pointer/main.cc
@@ -68,7 +68,7 @@ class Pointer::Main : public Rom::Reader
 
 		Gui::Connection _gui { _env };
 
-		Gui::View_id _view = _gui.create_view();
+		Gui::Top_level_view _view { _gui };
 
 		bool _default_pointer_visible = false;
 
@@ -166,7 +166,7 @@ void Pointer::Main::_show_default_pointer()
 	_gui.framebuffer.refresh(0, 0, pointer_size.w, pointer_size.h);
 
 	Gui::Rect geometry(Gui::Point(0, 0), pointer_size);
-	_gui.enqueue<Gui::Session::Command::Geometry>(_view, geometry);
+	_gui.enqueue<Gui::Session::Command::Geometry>(_view.id(), geometry);
 	_gui.execute();
 
 	_default_pointer_visible = true;
@@ -227,7 +227,7 @@ void Pointer::Main::_show_shape_pointer(Shape_report &shape_report)
 	_gui.framebuffer.refresh(0, 0, shape_size.w, shape_size.h);
 
 	Gui::Rect geometry(shape_hot, shape_size);
-	_gui.enqueue<Gui::Session::Command::Geometry>(_view, geometry);
+	_gui.enqueue<Gui::Session::Command::Geometry>(_view.id(), geometry);
 	_gui.execute();
 
 	_default_pointer_visible = false;
@@ -357,7 +357,7 @@ Pointer::Main::Main(Genode::Env &env) : _env(env)
 		}
 	}
 
-	_gui.enqueue<Gui::Session::Command::Front>(_view);
+	_gui.enqueue<Gui::Session::Command::Front>(_view.id());
 	_gui.execute();
 
 	_update_pointer();
diff --git a/repos/os/src/app/status_bar/main.cc b/repos/os/src/app/status_bar/main.cc
index 072eb30cab..ceefc3426d 100644
--- a/repos/os/src/app/status_bar/main.cc
+++ b/repos/os/src/app/status_bar/main.cc
@@ -186,7 +186,7 @@ struct Status_bar::Main
 
 	Reconstructible<Buffer> _buffer { _env.rm(), _gui };
 
-	Gui::View_id const _view { _gui.create_view() };
+	Gui::Top_level_view const _view { _gui };
 
 	void _draw_status_bar()
 	{
@@ -199,9 +199,6 @@ struct Status_bar::Main
 		_focus_ds.sigh(_focus_handler);
 		_gui.mode_sigh(_mode_handler);
 
-		/* schedule initial view-stacking command, needed only once */
-		_gui.enqueue<Gui::Session::Command::Front>(_view);
-
 		/* import initial state */
 		_handle_mode();
 		_handle_focus();
@@ -244,7 +241,7 @@ void Status_bar::Main::_handle_mode()
 
 	Rect const geometry(Point(0, 0), _buffer->mode().area);
 
-	_gui.enqueue<Gui::Session::Command::Geometry>(_view, geometry);
+	_gui.enqueue<Gui::Session::Command::Geometry>(_view.id(), geometry);
 	_gui.execute();
 }
 
diff --git a/repos/os/src/server/gui_fb/main.cc b/repos/os/src/server/gui_fb/main.cc
index eb94644be6..db02a179cb 100644
--- a/repos/os/src/server/gui_fb/main.cc
+++ b/repos/os/src/server/gui_fb/main.cc
@@ -242,7 +242,7 @@ struct Nit_fb::Main : View_updater
 
 	unsigned refresh_rate = 0;
 
-	Gui::View_id view = gui.create_view();
+	Gui::Top_level_view const view { gui };
 
 	Genode::Attached_dataspace input_ds { env.rm(), gui.input.dataspace() };
 
@@ -301,8 +301,8 @@ struct Nit_fb::Main : View_updater
 	void update_view() override
 	{
 		using Command = Gui::Session::Command;
-		gui.enqueue<Command::Geometry>(view, Rect(position, fb_session.size()));
-		gui.enqueue<Command::Front>(view);
+		gui.enqueue<Command::Geometry>(view.id(), Rect(position, fb_session.size()));
+		gui.enqueue<Command::Front>(view.id());
 		gui.execute();
 	}
 
diff --git a/repos/os/src/server/nitpicker/gui_session.cc b/repos/os/src/server/nitpicker/gui_session.cc
index eae16c0e33..38b9ec8ecb 100644
--- a/repos/os/src/server/nitpicker/gui_session.cc
+++ b/repos/os/src/server/nitpicker/gui_session.cc
@@ -198,30 +198,39 @@ void Gui_session::_adopt_new_view(View &view)
 }
 
 
-Gui_session::Create_view_result Gui_session::_create_view_with_id(auto const &create_fn)
+Gui_session::View_result
+Gui_session::_create_view_and_ref(View_id const id, View_attr const &attr, auto const &create_fn)
 {
-	Create_view_error error { };
+	release_view_id(id);
+
+	View_result error { }; /* assigned only in the error case */
 	try {
 		View &view = create_fn();
 		try {
-			View_ref &view_ref =
-				*new (_view_ref_alloc) View_ref(view.weak_ptr(), _view_ids);
+			new (_view_ref_alloc) View_ref(view.weak_ptr(), _view_ids, id);
 			_adopt_new_view(view);
-			return view_ref.id.id();
+
+			/* apply initial view attributes */
+			_execute_command(Command::Title    { id, attr.title });
+			_execute_command(Command::Geometry { id, attr.rect  });
+			if (attr.front)
+				_execute_command(Command::Front { id });
+
+			return View_result::OK;
 		}
-		catch (Out_of_ram)  { error = Create_view_error::OUT_OF_RAM;  }
-		catch (Out_of_caps) { error = Create_view_error::OUT_OF_CAPS; }
+		catch (Out_of_ram)  { error = View_result::OUT_OF_RAM;  }
+		catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; }
 		destroy(_view_alloc, &view);
 	}
-	catch (Out_of_ram)  { error = Create_view_error::OUT_OF_RAM;  }
-	catch (Out_of_caps) { error = Create_view_error::OUT_OF_CAPS; }
+	catch (Out_of_ram)  { error = View_result::OUT_OF_RAM;  }
+	catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; }
 	return error;
 }
 
 
-Gui_session::Create_view_result Gui_session::create_view()
+Gui_session::View_result Gui_session::view(View_id const id, View_attr const &attr)
 {
-	return _create_view_with_id([&] () -> View & {
+	return _create_view_and_ref(id, attr, [&] () -> View & {
 		return *new (_view_alloc)
 			View(*this, _texture,
 			     { .transparent = false, .background = false },
@@ -230,39 +239,32 @@ Gui_session::Create_view_result Gui_session::create_view()
 }
 
 
-Gui_session::Create_child_view_result Gui_session::create_child_view(View_id const parent)
+Gui_session::Child_view_result
+Gui_session::child_view(View_id const id, View_id const parent, View_attr const &attr)
 {
-	using Error = Create_child_view_error;
-
 	return _with_view(parent,
-		[&] (View &parent) -> Create_child_view_result {
+		[&] (View &parent) -> Child_view_result {
 
 			View *view_ptr = nullptr;
-			Create_view_result const result = _create_view_with_id(
-				[&] () -> View & {
-					view_ptr = new (_view_alloc)
-						View(*this, _texture,
-						     { .transparent = false, .background = false },
-						     &parent);
-					return *view_ptr;
-				});
+			View_result const result = _create_view_and_ref(id, attr, [&] () -> View & {
+				view_ptr = new (_view_alloc)
+					View(*this, _texture,
+					     { .transparent = false, .background = false },
+					     &parent);
+				return *view_ptr;
+			});
 
-			return result.convert<Create_child_view_result>(
-				[&] (View_id id) {
-					if (view_ptr)
-						parent.add_child(*view_ptr);
-					return id;
-				},
-				[&] (Create_view_error e) {
-					switch (e) {
-					case Create_view_error::OUT_OF_RAM:  return Error::OUT_OF_RAM;
-					case Create_view_error::OUT_OF_CAPS: return Error::OUT_OF_CAPS;
-					};
-					return Error::INVALID;
-				});
+			switch (result) {
+			case View_result::OUT_OF_RAM:  return Child_view_result::OUT_OF_RAM;
+			case View_result::OUT_OF_CAPS: return Child_view_result::OUT_OF_CAPS;
+			case View_result::OK:          break;
+			}
+			if (view_ptr)
+				parent.add_child(*view_ptr);
+			return Child_view_result::OK;
 		},
-		[&] /* parent view does not exist */ () -> Create_child_view_result {
-			return Error::INVALID; }
+		[&] /* parent view does not exist */ () -> Child_view_result {
+			return Child_view_result::INVALID; }
 	);
 }
 
@@ -317,24 +319,6 @@ void Gui_session::destroy_view(View_id const id)
 }
 
 
-Gui_session::Alloc_view_id_result
-Gui_session::alloc_view_id(View_capability view_cap)
-{
-	return _env.ep().rpc_ep().apply(view_cap,
-		[&] (View *view_ptr) -> Alloc_view_id_result {
-			if (!view_ptr)
-				return Alloc_view_id_error::INVALID;
-			try {
-				View_ref &view_ref = *new (_view_ref_alloc)
-					View_ref(view_ptr->weak_ptr(), _view_ids);
-				return view_ref.id.id();
-			}
-			catch (Out_of_ram)  { return Alloc_view_id_error::OUT_OF_RAM;  }
-			catch (Out_of_caps) { return Alloc_view_id_error::OUT_OF_CAPS; }
-		});
-}
-
-
 Gui_session::View_id_result
 Gui_session::view_id(View_capability view_cap, View_id id)
 {
diff --git a/repos/os/src/server/nitpicker/gui_session.h b/repos/os/src/server/nitpicker/gui_session.h
index b8cdb509cf..0129a2b05b 100644
--- a/repos/os/src/server/nitpicker/gui_session.h
+++ b/repos/os/src/server/nitpicker/gui_session.h
@@ -48,8 +48,6 @@ class Nitpicker::Gui_session : public  Session_object<Gui::Session>,
 {
 	private:
 
-		using View_ids = Id_space<Gui::View_ref>;
-
 		struct View_ref : Gui::View_ref
 		{
 			Weak_ptr<View> _weak_ptr;
@@ -178,7 +176,7 @@ class Nitpicker::Gui_session : public  Session_object<Gui::Session>,
 
 		void _adopt_new_view(View &);
 
-		Create_view_result _create_view_with_id(auto const &);
+		View_result _create_view_and_ref(View_id, View_attr const &attr, auto const &);
 
 		auto _with_view(View_id id, auto const &fn, auto const &missing_fn)
 		-> decltype(missing_fn())
@@ -386,14 +384,12 @@ class Nitpicker::Gui_session : public  Session_object<Gui::Session>,
 		Input::Session_capability input() override {
 			return _input_session_cap; }
 
-		Create_view_result create_view() override;
+		View_result view(View_id, View_attr const &attr) override;
 
-		Create_child_view_result create_child_view(View_id) override;
+		Child_view_result child_view(View_id, View_id, View_attr const &attr) override;
 
 		void destroy_view(View_id) override;
 
-		Alloc_view_id_result alloc_view_id(View_capability) override;
-
 		View_id_result view_id(View_capability, View_id) override;
 
 		View_capability view_capability(View_id) override;
diff --git a/repos/os/src/server/vmm/virtio_gpu.h b/repos/os/src/server/vmm/virtio_gpu.h
index 58ece4b3fd..59633d77bd 100644
--- a/repos/os/src/server/vmm/virtio_gpu.h
+++ b/repos/os/src/server/vmm/virtio_gpu.h
@@ -297,7 +297,7 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
 		Cpu::Signal_handler<Virtio_gpu_device> _handler;
 		Constructible<Attached_dataspace>      _fb_ds { };
 		Framebuffer::Mode                      _fb_mode { _gui.mode() };
-		Gui::View_id                           _view = _gui.create_view();
+		Gui::Top_level_view                    _view { _gui, { { }, _fb_mode.area } };
 
 		using Area = Genode::Area<>;
 		using Rect = Genode::Rect<>;
@@ -465,8 +465,8 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
 				_fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace());
 
 			using Command = Gui::Session::Command;
-			_gui.enqueue<Command::Geometry>(_view, Rect(Point(0, 0), _fb_mode.area));
-			_gui.enqueue<Command::Front>(_view);
+			_gui.enqueue<Command::Geometry>(_view.id(), Rect(Point(0, 0), _fb_mode.area));
+			_gui.enqueue<Command::Front>(_view.id());
 			_gui.execute();
 			return _gui.mode();
 		}
diff --git a/repos/os/src/test/capture/main.cc b/repos/os/src/test/capture/main.cc
index 6081681947..915e248168 100644
--- a/repos/os/src/test/capture/main.cc
+++ b/repos/os/src/test/capture/main.cc
@@ -25,34 +25,10 @@ namespace Test {
 
 	using namespace Genode;
 
-	struct View;
 	struct Main;
 }
 
 
-class Test::View
-{
-	private:
-
-		Gui::Connection   &_gui;
-		Gui::View_id const _id = _gui.create_view();
-		Gui::Rect    const _rect;
-
-	public:
-
-		View(Gui::Connection &gui, Gui::Rect rect) : _gui(gui), _rect(rect)
-		{
-			using Command = Gui::Session::Command;
-
-			_gui.enqueue<Command::Geometry>(_id, rect);
-			_gui.enqueue<Command::Front>(_id);
-			_gui.execute();
-		}
-
-		virtual ~View() { }
-};
-
-
 struct Test::Main
 {
 	Env &_env;
@@ -94,7 +70,7 @@ struct Test::Main
 
 		Attached_dataspace _fb_ds { _env.rm(), _gui.framebuffer.dataspace() };
 
-		Registry<Registered<View>> _views { };
+		Registry<Registered<Gui::Top_level_view>> _views { };
 
 		Output(Env &env, Allocator &alloc, Xml_node const &config)
 		:
@@ -109,12 +85,12 @@ struct Test::Main
 
 			config.for_each_sub_node("view", [&] (Xml_node node) {
 				new (_alloc)
-					Registered<View>(_views, _gui, view_rect(node)); });
+					Registered<Gui::Top_level_view>(_views, _gui, view_rect(node)); });
 		}
 
 		~Output()
 		{
-			_views.for_each([&] (Registered<View> &view) {
+			_views.for_each([&] (Registered<Gui::Top_level_view> &view) {
 				destroy(_alloc, &view); });
 		}
 
diff --git a/repos/os/src/test/nitpicker/main.cc b/repos/os/src/test/nitpicker/main.cc
index b4212a2025..b64911fb54 100644
--- a/repos/os/src/test/nitpicker/main.cc
+++ b/repos/os/src/test/nitpicker/main.cc
@@ -34,12 +34,7 @@ class Test::View : private List<View>::Element, Interface
 {
 	public:
 
-		struct Attr
-		{
-			Gui::Point pos;
-			Gui::Area  size;
-			Gui::Title title;
-		};
+		using Attr = Gui::Session::View_attr;
 
 	private:
 
@@ -48,24 +43,18 @@ class Test::View : private List<View>::Element, Interface
 
 		using Command = Gui::Session::Command;
 
-		Gui::Connection   &_gui;
+		Gui::Connection &_gui;
+
 		Gui::View_id const _id;
-		Attr         const _attr;
-		Gui::Point         _pos = _attr.pos;
+		Gui::Area    const _size;
+		Gui::Point         _pos;
 
 	public:
 
-		View(Gui::Connection &gui, Attr const attr, auto const &create_fn)
+		View(Gui::Connection &gui, Gui::View_id const id, Attr const attr)
 		:
-			_gui(gui), _id(create_fn()), _attr(attr)
-		{
-			using namespace Gui;
-
-			_gui.enqueue<Command::Geometry>(_id, Gui::Rect { _pos, _attr.size });
-			_gui.enqueue<Command::Front>(_id);
-			_gui.enqueue<Command::Title>(_id, _attr.title);
-			_gui.execute();
-		}
+			_gui(gui), _id(id), _size(attr.rect.area), _pos(attr.rect.at)
+		{ }
 
 		Gui::View_capability view_cap()
 		{
@@ -81,13 +70,13 @@ class Test::View : private List<View>::Element, Interface
 		virtual void move(Gui::Point const pos)
 		{
 			_pos = pos;
-			_gui.enqueue<Command::Geometry>(_id, Gui::Rect { _pos, _attr.size });
+			_gui.enqueue<Command::Geometry>(_id, Gui::Rect { _pos, _size });
 			_gui.execute();
 		}
 
 		virtual Gui::Point pos() const { return _pos; }
 
-		Gui::Rect rect() const { return { pos(), _attr.size }; }
+		Gui::Rect rect() const { return { pos(), _size }; }
 
 		bool contains(Gui::Point pos) { return rect().contains(pos); }
 };
@@ -95,10 +84,12 @@ class Test::View : private List<View>::Element, Interface
 
 struct Test::Top_level_view : View
 {
-	Top_level_view(Gui::Connection &gui, Attr const &attr)
+	Top_level_view(Gui::Connection &gui, Gui::View_id const id, Attr const &attr)
 	:
-		View(gui, attr, [&] { return gui.create_view(); })
-	{ }
+		View(gui, id, attr)
+	{
+		gui.view(id, attr);
+	}
 };
 
 
@@ -106,17 +97,15 @@ struct Test::Child_view : View
 {
 	View &_parent;
 
-	Child_view(Gui::Connection &gui, View &parent, Attr const &attr)
+	Child_view(Gui::Connection &gui, Gui::View_id const id, View &parent, Attr const &attr)
 	:
-		View(gui, attr,
-			[&] /* create_fn */ {
-				Gui::View_id const parent_id = gui.alloc_view_id(parent.view_cap());
-				Gui::View_id const id = gui.create_child_view(parent_id);
-				gui.release_view_id(parent_id);
-				return id;
-			}
-		), _parent(parent)
-	{ }
+		View(gui, id, attr), _parent(parent)
+	{
+		Gui::View_id const parent_id { 0 }; /* temporary */
+		gui.view_id(parent.view_cap(), parent_id);
+		gui.child_view(id, parent_id, attr);
+		gui.release_view_id(parent_id);
+	}
 
 	void move(Gui::Point const pos) override
 	{
@@ -219,17 +208,17 @@ struct Test::Main
 	/*
 	 * View '_v1' is used as coordinate origin of '_v2' and '_v3'.
 	 */
-	Top_level_view _v1 { _gui,  { .pos   = { 150, 100 },
-	                              .size  = { 230, 200 },
-	                              .title = "Eins" } };
+	Top_level_view _v1 { _gui,  { 1 }, { .title = "Eins",
+	                                     .rect  = { { 150, 100 }, { 230, 200 } },
+	                                     .front = true } };
 
-	Child_view _v2 { _gui, _v1, { .pos   = {  20,  20 },
-	                              .size  = { 230, 210 },
-	                              .title = "Zwei" } };
+	Child_view _v2 { _gui, { 2 }, _v1, { .title = "Zwei",
+	                                     .rect  = { {  20,  20 }, { 230, 210 } },
+	                                     .front = true } };
 
-	Child_view _v3 { _gui, _v1, { .pos   = { 40,  40 },
-	                              .size  = { 230, 220 },
-	                              .title = "Drei" } };
+	Child_view _v3 { _gui, { 3 }, _v1, { .title = "Drei",
+	                                     .rect  = { {  40,  40 }, { 230, 220 } },
+	                                     .front = true } };
 
 	Signal_handler<Main> _input_handler { _env.ep(), *this, &Main::_handle_input };
 
diff --git a/repos/os/src/test/vfs_capture/main.cc b/repos/os/src/test/vfs_capture/main.cc
index e9a301752b..43b15f7b01 100644
--- a/repos/os/src/test/vfs_capture/main.cc
+++ b/repos/os/src/test/vfs_capture/main.cc
@@ -27,34 +27,10 @@ namespace Test {
 
 	using namespace Genode;
 
-	struct View;
 	struct Main;
 }
 
 
-class Test::View
-{
-	private:
-
-		Gui::Connection   &_gui;
-		Gui::View_id const _id = _gui.create_view();
-		Gui::Rect    const _rect;
-
-	public:
-
-		View(Gui::Connection &gui, Gui::Rect rect) : _gui(gui), _rect(rect)
-		{
-			using Command = Gui::Session::Command;
-
-			_gui.enqueue<Command::Geometry>(_id, rect);
-			_gui.enqueue<Command::Front>(_id);
-			_gui.execute();
-		}
-
-		virtual ~View() { }
-};
-
-
 struct Test::Main
 {
 	Env &_env;
@@ -98,7 +74,7 @@ struct Test::Main
 
 		Attached_dataspace _fb_ds { _env.rm(), _gui.framebuffer.dataspace() };
 
-		Registry<Registered<View>> _views { };
+		Registry<Registered<Gui::Top_level_view>> _views { };
 
 		Output(Env &env, Allocator &alloc, Xml_node const &config)
 		:
@@ -113,12 +89,12 @@ struct Test::Main
 
 			config.for_each_sub_node("view", [&] (Xml_node node) {
 				new (_alloc)
-					Registered<View>(_views, _gui, view_rect(node)); });
+					Registered<Gui::Top_level_view>(_views, _gui, view_rect(node)); });
 		}
 
 		~Output()
 		{
-			_views.for_each([&] (Registered<View> &view) {
+			_views.for_each([&] (Registered<Gui::Top_level_view> &view) {
 				destroy(_alloc, &view); });
 		}
 
diff --git a/repos/ports/src/virtualbox5/frontend/fb.h b/repos/ports/src/virtualbox5/frontend/fb.h
index dd65c1fcc1..89e332779d 100644
--- a/repos/ports/src/virtualbox5/frontend/fb.h
+++ b/repos/ports/src/virtualbox5/frontend/fb.h
@@ -31,10 +31,10 @@ class Genodefb :
 {
 	private:
 
-		Genode::Env     &_env;
-		Gui::Connection &_gui;
-		Gui::View_id     _view;
-		Fb_Genode::Mode  _fb_mode { .area = { 1024, 768 } };
+		Genode::Env        &_env;
+		Gui::Connection    &_gui;
+		Gui::Top_level_view _view { _gui };
+		Fb_Genode::Mode     _fb_mode { .area = { 1024, 768 } };
 
 		/*
 		 * The mode currently used by the VM. Can be smaller than the
@@ -73,22 +73,13 @@ class Genodefb :
 		void _adjust_buffer()
 		{
 			_gui.buffer(_fb_mode, false);
-
-			Gui::Rect rect(Gui::Point(0, 0), _fb_mode.area);
-
-			_gui.enqueue<Gui::Session::Command::Geometry>(_view, rect);
-			_gui.execute();
+			_view.area(_fb_mode.area);
 		}
 
 		Fb_Genode::Mode _initial_setup()
 		{
-			_view = _gui.create_view();
-
 			_adjust_buffer();
-
-			_gui.enqueue<Gui::Session::Command::Front>(_view);
-			_gui.execute();
-
+			_view.front();
 			return _fb_mode;
 		}
 
diff --git a/repos/ports/src/virtualbox6/include/fb.h b/repos/ports/src/virtualbox6/include/fb.h
index 6e31237ec4..f1db4d66a0 100644
--- a/repos/ports/src/virtualbox6/include/fb.h
+++ b/repos/ports/src/virtualbox6/include/fb.h
@@ -30,10 +30,10 @@ class Genodefb :
 {
 	private:
 
-		Genode::Env     &_env;
-		Gui::Connection &_gui;
-		Gui::View_id     _view;
-		Fb_Genode::Mode  _fb_mode { .area = { 1024, 768 } };
+		Genode::Env        &_env;
+		Gui::Connection    &_gui;
+		Gui::Top_level_view _view { _gui };
+		Fb_Genode::Mode     _fb_mode { .area = { 1024, 768 } };
 
 		/*
 		 * The mode currently used by the VM. Can be smaller than the
@@ -71,22 +71,13 @@ class Genodefb :
 		void _adjust_buffer()
 		{
 			_gui.buffer(_fb_mode, false);
-
-			Gui::Rect rect(Gui::Point(0, 0), _fb_mode.area);
-
-			_gui.enqueue<Gui::Session::Command::Geometry>(_view, rect);
-			_gui.execute();
+			_view.area(_fb_mode.area);
 		}
 
 		Fb_Genode::Mode _initial_setup()
 		{
-			_view = _gui.create_view();
-
 			_adjust_buffer();
-
-			_gui.enqueue<Gui::Session::Command::Front>(_view);
-			_gui.execute();
-
+			_view.front();
 			return _fb_mode;
 		}