diff --git a/examples/14_display.cpp b/examples/14_display.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d6eacab514d092c1cd37a8781d3666fadf30d049
--- /dev/null
+++ b/examples/14_display.cpp
@@ -0,0 +1,47 @@
+#include <cstdio>
+#include <cerrno>
+
+#include <iostream>
+
+#include "simple/graphical/initializer.h"
+
+using namespace simple::graphical;
+
+std::ostream& operator<<(std::ostream& os, display::mode mode)
+{
+	os << to_string(mode.format) << ' '
+		<< mode.size.x() << 'x' << mode.size.y() << '@'
+		<< mode.refresh_rate;
+	return os;
+}
+
+int main() try
+{
+	initializer graphics;
+
+	for(auto&& display : graphics.displays())
+	{
+		std::cout << "---Didplay---"<< '\n';
+		for(auto&& mode : display.modes())
+		{
+			std::cout << mode;
+			if(mode == display.current_mode())
+				std::cout << " <--";
+			std::cout << '\n';
+		}
+		std::cout << '\n';
+	}
+
+	return 0;
+}
+catch(...)
+{
+	if(errno)
+		std::perror("ERROR");
+
+	const char* sdl_error = SDL_GetError();
+	if(*sdl_error)
+		std::puts(sdl_error);
+
+	throw;
+}
diff --git a/source/simple/graphical.hpp b/source/simple/graphical.hpp
index c6d2aa241fdafe6a261e05f3c96d919704271e60..e98fd59edc722dbfe34889298f081e37a478f977 100644
--- a/source/simple/graphical.hpp
+++ b/source/simple/graphical.hpp
@@ -2,6 +2,7 @@
 #include "graphical/color.h"
 #include "graphical/color_vector.hpp"
 #include "graphical/common_def.h"
+#include "graphical/display.h"
 #include "graphical/gl_window.h"
 #include "graphical/initializer.h"
 #include "graphical/palette_view.h"
diff --git a/source/simple/graphical/display.cpp b/source/simple/graphical/display.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..02a8f9b6c8349d0efd86fa7e44ccd4e55002838b
--- /dev/null
+++ b/source/simple/graphical/display.cpp
@@ -0,0 +1,145 @@
+#include "display.h"
+
+namespace simple::graphical
+{
+
+	namespace detail
+	{
+
+		template <typename Derived, typename... Payload>
+		Derived& index_iterator<Derived,Payload...>::operator++() noexcept
+		{
+			++index;
+			return static_cast<Derived&>(*this);
+		}
+
+		template <typename Derived, typename... Payload>
+		Derived index_iterator<Derived,Payload...>::operator++(int) noexcept
+		{
+			Derived temp = static_cast<Derived&>(*this);
+			++(*this);
+			return temp;
+		}
+
+		template <typename Derived, typename... Payload>
+		bool index_iterator<Derived,Payload...>::operator==(const Derived& other) const noexcept
+		{
+			return index == other.index;
+		}
+
+		template <typename Derived, typename... Payload>
+		bool index_iterator<Derived,Payload...>::operator!=(const Derived& other) const noexcept
+		{
+			return !(*this == other);
+		}
+
+		template <typename Derived, typename... Payload>
+		int index_iterator<Derived,Payload...>::operator-(const Derived& other) const noexcept
+		{
+			return index - other.index;
+		}
+
+		template <typename Derived, typename... Payload>
+		index_iterator<Derived,Payload...>::index_iterator(protector, int index, Payload... payload) noexcept
+		: index(index), payload{payload...}
+		{ }
+
+		template <typename Iterator, typename... Payload>
+		Iterator index_list<Iterator,Payload...>::make_iterator(int index) const noexcept
+		{
+			using protector = typename Iterator::protector;
+			return std::make_from_tuple<Iterator>(
+				std::tuple_cat(
+					std::tuple{protector{},index},
+					payload
+				)
+			);
+		}
+
+		template <typename Iterator, typename... Payload>
+		Iterator index_list<Iterator,Payload...>::begin() const noexcept
+		{
+			return make_iterator(0);
+		}
+
+		template <typename Iterator, typename... Payload>
+		Iterator index_list<Iterator,Payload...>::end() const noexcept
+		{
+			return make_iterator(count);
+		}
+
+		template <typename Iterator,typename... Payload>
+		index_list<Iterator,Payload...>::index_list(int count, Payload... payload) noexcept
+		: count(count), payload{payload...}
+		{ }
+
+		template class index_iterator<display::mode_iterator,int>;
+		template class index_list<display::mode_iterator, int>;
+		template class index_iterator<display_iterator>;
+		template class index_list<display_iterator>;
+
+	} // namespace detail
+
+	display::mode from_sdl_mode(const SDL_DisplayMode& mode)
+	{
+		return {
+			static_cast<pixel_format::type>(mode.format),
+			{mode.w, mode.h},
+			mode.refresh_rate
+		};
+	}
+
+	bool display::mode::operator==(const mode& other) const noexcept
+	{
+		return other.format == format &&
+			other.size == size &&
+			other.refresh_rate == refresh_rate;
+	}
+
+	bool display::mode::operator!=(const mode& other) const noexcept
+	{
+		return !operator==(other);
+	}
+
+	auto display::mode_iterator::operator*() const -> mode
+	{
+		SDL_DisplayMode mode;
+		int display_index = std::get<0>(payload);
+		sdlcore::utils::throw_error(
+			SDL_GetDisplayMode(display_index, index, &mode));
+		return from_sdl_mode(mode);
+	}
+
+	auto display::current_mode() const -> mode
+	{
+		SDL_DisplayMode mode;
+		sdlcore::utils::throw_error(
+			SDL_GetCurrentDisplayMode(index, &mode));
+		return from_sdl_mode(mode);
+	}
+
+	auto display::initial_mode() const -> mode
+	{
+		SDL_DisplayMode mode;
+		sdlcore::utils::throw_error(
+			SDL_GetDesktopDisplayMode(index, &mode));
+		return from_sdl_mode(mode);
+	}
+
+	auto display::modes() const noexcept -> mode_list
+	{
+		auto count = SDL_GetNumDisplayModes(index);
+		if(count < 0)
+			count = 0;
+		return mode_list(count, index);
+	}
+
+	display::display(int index) noexcept : index(index)
+	{ }
+
+	display display_iterator::operator*() const
+	{
+		return display(index);
+	}
+
+} // namespace simple::graphical
diff --git a/source/simple/graphical/display.h b/source/simple/graphical/display.h
new file mode 100644
index 0000000000000000000000000000000000000000..d711494dde96988a87080b15eb9f74d182e89f57
--- /dev/null
+++ b/source/simple/graphical/display.h
@@ -0,0 +1,113 @@
+#ifndef SIMPLE_GRAPHICAL_DISPLAY_H
+#define SIMPLE_GRAPHICAL_DISPLAY_H
+
+#include "common_def.h"
+#include "pixel_format.h"
+
+namespace simple::graphical
+{
+
+	namespace detail
+	{
+
+		// there is probably some library that does this better...
+		// maybe boost/iterator??
+		template <typename Derived, typename... Payload>
+		class index_iterator
+		{
+			protected:
+
+			class protector {};
+
+			public:
+			Derived& operator++() noexcept;
+			Derived operator++(int) noexcept;
+			bool operator==(const Derived&) const noexcept;
+			bool operator!=(const Derived&) const noexcept;
+			int operator-(const Derived&) const noexcept;
+
+			explicit index_iterator(protector, int, Payload...) noexcept;
+
+			protected:
+			int index;
+			std::tuple<Payload...> payload;
+		};
+
+		template <typename Iterator, typename... Payload>
+		class index_list
+		{
+			public:
+			Iterator begin() const noexcept;
+			Iterator end() const noexcept;
+
+			protected:
+			explicit index_list(int, Payload...) noexcept;
+			private:
+			Iterator make_iterator(int) const noexcept;
+			int count;
+			std::tuple<Payload...> payload;
+		};
+
+	} // namespace detail
+
+	class display
+	{
+		public:
+
+		struct mode
+		{
+			pixel_format::type format;
+			int2 size;
+			int refresh_rate;
+			bool operator==(const mode&) const noexcept;
+			bool operator!=(const mode&) const noexcept;
+		};
+
+		class mode_iterator : public detail::index_iterator<mode_iterator,int>
+		{
+			public:
+			using index_iterator<mode_iterator,int>::index_iterator;
+			mode operator*() const;
+
+			friend class detail::index_list<mode_iterator, int>;
+		};
+
+		class mode_list : public detail::index_list<mode_iterator, int>
+		{
+			private:
+			using index_list<mode_iterator,int>::index_list;
+			friend display;
+		};
+
+		mode current_mode() const;
+		mode initial_mode() const;
+		mode_list modes() const noexcept;
+		// TODO: bounds, DPI
+		private:
+		explicit display(int) noexcept;
+		int index;
+
+		friend class display_iterator;
+		friend class window;
+	};
+
+	class display_iterator : public detail::index_iterator<display_iterator>
+	{
+		public:
+		using index_iterator<display_iterator>::index_iterator;
+		display operator*() const;
+
+		friend class detail::index_list<display_iterator>;
+	};
+
+	class display_list : public detail::index_list<display_iterator>
+	{
+		private:
+		using index_list<display_iterator>::index_list;
+		friend class initializer;
+	};
+
+
+} // namespace simple::graphical
+
+#endif /* end of include guard */
diff --git a/source/simple/graphical/initializer.cpp b/source/simple/graphical/initializer.cpp
index e76fd76422cf61767fc019c83677bf04119d6692..eb3ce595cb6573cda842646ed7526232d7766fe2 100644
--- a/source/simple/graphical/initializer.cpp
+++ b/source/simple/graphical/initializer.cpp
@@ -66,3 +66,11 @@ initializer::screensaver_control::~screensaver_control() noexcept
 
 initializer::initializer() : sdlcore::initializer(sdlcore::system_flag::video), screensaver()
 {}
+
+display_list initializer::displays() const noexcept
+{
+		auto count = SDL_GetNumVideoDisplays();
+		if(count < 0)
+			count = 0;
+		return display_list(count);
+}
diff --git a/source/simple/graphical/initializer.h b/source/simple/graphical/initializer.h
index 1f85198e18262247d4e9c84c41932b35aab5180a..f30cb14bb2393a16438c22bc621dfe30de4aa671 100644
--- a/source/simple/graphical/initializer.h
+++ b/source/simple/graphical/initializer.h
@@ -2,6 +2,8 @@
 #define SIMPLE_GRAPHICAL_INITIALIZER_H
 #include "simple/sdlcore/initializer.h"
 
+#include "display.h"
+
 namespace simple::graphical
 {
 
@@ -27,6 +29,7 @@ namespace simple::graphical
 		public:
 		initializer();
 		screensaver_control screensaver;
+		display_list displays() const noexcept;
 	};
 
 } // namespace simple::graphical
diff --git a/source/simple/graphical/pixel_format.cpp b/source/simple/graphical/pixel_format.cpp
index 0d418a8e0aef338b9d776888757f5e86599856d6..9602db66918b671a69384b79c38a21bcc031814f 100644
--- a/source/simple/graphical/pixel_format.cpp
+++ b/source/simple/graphical/pixel_format.cpp
@@ -1,4 +1,5 @@
 #include <type_traits>
+#include "simple/support/enum.hpp"
 
 #include "pixel_format.h"
 #include "palette_view.h"
@@ -63,4 +64,9 @@ namespace simple::graphical
 		return SDL_GetPixelFormatName(guts()->format);
 	}
 
+	const char* to_string(pixel_format::type type) noexcept
+	{
+		return SDL_GetPixelFormatName(support::to_integer(type));
+	}
+
 } // namespace simple::graphical
diff --git a/source/simple/graphical/pixel_format.h b/source/simple/graphical/pixel_format.h
index 217cd7441ebd67a0ccd07f6c30c718c29a210301..dea460ddf8438f39795677a15c3a1ee36edfd837 100644
--- a/source/simple/graphical/pixel_format.h
+++ b/source/simple/graphical/pixel_format.h
@@ -1,9 +1,7 @@
 #ifndef SIMPLE_GRAPHICAL_PIXEL_FORMAT_H
 #define SIMPLE_GRAPHICAL_PIXEL_FORMAT_H
 
-#include <memory>
 #include <optional>
-#include <SDL2/SDL.h>
 #include "simple/sdlcore/utils.hpp"
 #include "color.h"
 #include "palette_view.h"
@@ -96,6 +94,8 @@ namespace simple::graphical
 		friend surface convert(const surface& source, const pixel_format& format);
 	};
 
+	const char* to_string(pixel_format::type) noexcept;
+
 } // namespace simple::graphical
 
 #endif /* end of include guard */
diff --git a/source/simple/graphical/window.cpp b/source/simple/graphical/window.cpp
index dcb58b829f50041c24a2ac6b0066ac75e1875f7d..3a0ac46f93b73cf848ea3639cde5b24a871a245d 100644
--- a/source/simple/graphical/window.cpp
+++ b/source/simple/graphical/window.cpp
@@ -108,4 +108,11 @@ namespace simple::graphical
 		return SDL_GetWindowID(guts().get());
 	}
 
+	display window::display() const
+	{
+		int index = SDL_GetWindowDisplayIndex(guts().get());
+		sdlcore::utils::throw_error(index < 0);
+		return graphical::display(index);
+	}
+
 } // namespace simple::graphical
diff --git a/source/simple/graphical/window.h b/source/simple/graphical/window.h
index a5b90ed01685f4c305661671c7deb730c82c38d0..f74c78dc3f402733e6f9df3eae6aeb32f906e7f1 100644
--- a/source/simple/graphical/window.h
+++ b/source/simple/graphical/window.h
@@ -9,6 +9,7 @@
 #include "simple/sdlcore/utils.hpp"
 
 #include "common_def.h"
+#include "display.h"
 
 namespace simple::graphical
 {
@@ -80,6 +81,8 @@ namespace simple::graphical
 
 		uint32_t id() const noexcept;
 
+		graphical::display display() const;
+
 		protected:
 
 		window