mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 06:57:45 +00:00
WindowServer: In HighDPI mode, load high-res window buttons and high-res cursors
Bitmap::load_from_file("foo.png", 2) will now look for "foo-2x.png" and try load that as a bitmap with scale factor 2 if it exists. If it doesn't, it falls back to the 1x bitmap as normal. Only places that know that they'll draw the bitmap to a 2x painter should pass "2" for the second argument. Use this new API in WindowServer for loading window buttons and cursors. As a testing aid, ctrl-shift-super-i can force HighDPI icons off in HighDPI mode. Toggling between low-res and high-res icons makes it easy to see if the high-res version of an icon looks right: It should look like the low-res version, just less jaggy. We'll likely have to grow a better API for loading scaled resources, but for now this suffices. Things to check: - `chres 640 480` followed by `chres 640 480 2` followed by `chres 640 480` - window buttons in window context menu (in task bar and on title bar) still have low-res icons - ctrl-shift-super-i in high-res mode toggles sharpness of window buttons and of arrow cursorf - arrow cursor hotspot is still where you'd expect
This commit is contained in:
parent
5ad2cbe9ad
commit
98637bd549
8 changed files with 86 additions and 18 deletions
|
@ -713,7 +713,10 @@ bool Compositor::set_resolution(int desired_width, int desired_height, int scale
|
|||
return false;
|
||||
}
|
||||
|
||||
int old_scale_factor = Screen::the().scale_factor();
|
||||
bool success = Screen::the().set_resolution(desired_width, desired_height, scale_factor);
|
||||
if (success && old_scale_factor != scale_factor)
|
||||
WindowManager::the().reload_icon_bitmaps_after_scale_change();
|
||||
init_bitmaps();
|
||||
invalidate_occlusions();
|
||||
compose();
|
||||
|
|
|
@ -46,7 +46,8 @@ CursorParams CursorParams::parse_from_file_name(const StringView& cursor_path, c
|
|||
auto params_str = file_title.substring_view(last_dot_in_title.value() + 1);
|
||||
|
||||
CursorParams params(default_hotspot);
|
||||
for (size_t i = 0; i + 1 < params_str.length();) {
|
||||
bool in_display_scale_part = false;
|
||||
for (size_t i = 0; i + 1 < params_str.length() && !in_display_scale_part;) {
|
||||
auto property = params_str[i++];
|
||||
|
||||
auto value = [&]() -> Optional<size_t> {
|
||||
|
@ -88,6 +89,9 @@ CursorParams CursorParams::parse_from_file_name(const StringView& cursor_path, c
|
|||
else
|
||||
dbgln("Cursor frame rate outside of valid range (100-1000ms)");
|
||||
break;
|
||||
case '-':
|
||||
in_display_scale_part = true;
|
||||
break;
|
||||
default:
|
||||
dbg() << "Ignore unknown property '" << property << "' with value " << value.value() << " parsed from cursor path: " << cursor_path;
|
||||
return { default_hotspot };
|
||||
|
|
|
@ -57,6 +57,7 @@ static Gfx::Bitmap* s_restore_icon;
|
|||
static Gfx::Bitmap* s_close_icon;
|
||||
|
||||
static String s_last_title_button_icons_path;
|
||||
static int s_last_title_button_icons_scale;
|
||||
|
||||
WindowFrame::WindowFrame(Window& window)
|
||||
: m_window(window)
|
||||
|
@ -96,34 +97,35 @@ void WindowFrame::set_button_icons()
|
|||
return;
|
||||
|
||||
String icons_path = WindowManager::the().palette().title_button_icons_path();
|
||||
int icons_scale = WindowManager::the().compositor_icon_scale();
|
||||
|
||||
StringBuilder full_path;
|
||||
if (!s_minimize_icon || s_last_title_button_icons_path != icons_path) {
|
||||
if (!s_minimize_icon || s_last_title_button_icons_path != icons_path || s_last_title_button_icons_scale != icons_scale) {
|
||||
full_path.append(icons_path);
|
||||
full_path.append("window-minimize.png");
|
||||
if (!(s_minimize_icon = Gfx::Bitmap::load_from_file(full_path.to_string()).leak_ref()))
|
||||
s_minimize_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/downward-triangle.png").leak_ref();
|
||||
if (!(s_minimize_icon = Gfx::Bitmap::load_from_file(full_path.to_string(), icons_scale).leak_ref()))
|
||||
s_minimize_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/downward-triangle.png", icons_scale).leak_ref();
|
||||
full_path.clear();
|
||||
}
|
||||
if (!s_maximize_icon || s_last_title_button_icons_path != icons_path) {
|
||||
if (!s_maximize_icon || s_last_title_button_icons_path != icons_path || s_last_title_button_icons_scale != icons_scale) {
|
||||
full_path.append(icons_path);
|
||||
full_path.append("window-maximize.png");
|
||||
if (!(s_maximize_icon = Gfx::Bitmap::load_from_file(full_path.to_string()).leak_ref()))
|
||||
s_maximize_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/upward-triangle.png").leak_ref();
|
||||
if (!(s_maximize_icon = Gfx::Bitmap::load_from_file(full_path.to_string(), icons_scale).leak_ref()))
|
||||
s_maximize_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/upward-triangle.png", icons_scale).leak_ref();
|
||||
full_path.clear();
|
||||
}
|
||||
if (!s_restore_icon || s_last_title_button_icons_path != icons_path) {
|
||||
if (!s_restore_icon || s_last_title_button_icons_path != icons_path || s_last_title_button_icons_scale != icons_scale) {
|
||||
full_path.append(icons_path);
|
||||
full_path.append("window-restore.png");
|
||||
if (!(s_restore_icon = Gfx::Bitmap::load_from_file(full_path.to_string()).leak_ref()))
|
||||
s_restore_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-restore.png").leak_ref();
|
||||
if (!(s_restore_icon = Gfx::Bitmap::load_from_file(full_path.to_string(), icons_scale).leak_ref()))
|
||||
s_restore_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-restore.png", icons_scale).leak_ref();
|
||||
full_path.clear();
|
||||
}
|
||||
if (!s_close_icon || s_last_title_button_icons_path != icons_path) {
|
||||
if (!s_close_icon || s_last_title_button_icons_path != icons_path || s_last_title_button_icons_scale != icons_scale) {
|
||||
full_path.append(icons_path);
|
||||
full_path.append("window-close.png");
|
||||
if (!(s_close_icon = Gfx::Bitmap::load_from_file(full_path.to_string()).leak_ref()))
|
||||
s_close_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-close.png").leak_ref();
|
||||
if (!(s_close_icon = Gfx::Bitmap::load_from_file(full_path.to_string(), icons_scale).leak_ref()))
|
||||
s_close_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-close.png", icons_scale).leak_ref();
|
||||
full_path.clear();
|
||||
}
|
||||
|
||||
|
@ -134,6 +136,7 @@ void WindowFrame::set_button_icons()
|
|||
m_maximize_button->set_icon(m_window.is_maximized() ? *s_restore_icon : *s_maximize_icon);
|
||||
|
||||
s_last_title_button_icons_path = icons_path;
|
||||
s_last_title_button_icons_scale = icons_scale;
|
||||
}
|
||||
|
||||
void WindowFrame::did_set_maximized(Badge<Window>, bool maximized)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <AK/LogStream.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/CharacterBitmap.h>
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/Painter.h>
|
||||
|
@ -84,7 +85,7 @@ NonnullRefPtr<Cursor> WindowManager::get_cursor(const String& name)
|
|||
{
|
||||
static const auto s_default_cursor_path = "/res/cursors/arrow.x2y2.png";
|
||||
auto path = m_config->read_entry("Cursor", name, s_default_cursor_path);
|
||||
auto gb = Gfx::Bitmap::load_from_file(path);
|
||||
auto gb = Gfx::Bitmap::load_from_file(path, compositor_icon_scale());
|
||||
if (gb)
|
||||
return Cursor::create(*gb, path);
|
||||
return Cursor::create(*Gfx::Bitmap::load_from_file(s_default_cursor_path), s_default_cursor_path);
|
||||
|
@ -1092,6 +1093,12 @@ void WindowManager::event(Core::Event& event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (key_event.type() == Event::KeyDown && (key_event.modifiers() == (Mod_Ctrl | Mod_Logo | Mod_Shift) && key_event.key() == Key_I)) {
|
||||
reload_icon_bitmaps_after_scale_change(!m_allow_hidpi_icons);
|
||||
Compositor::the().invalidate_screen();
|
||||
return;
|
||||
}
|
||||
|
||||
if (MenuManager::the().current_menu()) {
|
||||
MenuManager::the().dispatch_event(event);
|
||||
return;
|
||||
|
@ -1486,4 +1493,21 @@ Gfx::IntPoint WindowManager::get_recommended_window_position(const Gfx::IntPoint
|
|||
|
||||
return point;
|
||||
}
|
||||
|
||||
int WindowManager::compositor_icon_scale() const
|
||||
{
|
||||
if (!m_allow_hidpi_icons)
|
||||
return 1;
|
||||
return scale_factor();
|
||||
}
|
||||
|
||||
void WindowManager::reload_icon_bitmaps_after_scale_change(bool allow_hidpi_icons)
|
||||
{
|
||||
m_allow_hidpi_icons = allow_hidpi_icons;
|
||||
reload_config();
|
||||
for_each_window([&](Window& window) {
|
||||
window.frame().set_button_icons();
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,6 +230,9 @@ public:
|
|||
|
||||
Gfx::IntPoint get_recommended_window_position(const Gfx::IntPoint& desired);
|
||||
|
||||
int compositor_icon_scale() const;
|
||||
void reload_icon_bitmaps_after_scale_change(bool allow_hidpi_icons = true);
|
||||
|
||||
private:
|
||||
NonnullRefPtr<Cursor> get_cursor(const String& name);
|
||||
|
||||
|
@ -263,6 +266,7 @@ private:
|
|||
|
||||
void do_move_to_front(Window&, bool, bool);
|
||||
|
||||
bool m_allow_hidpi_icons { true };
|
||||
RefPtr<Cursor> m_hidden_cursor;
|
||||
RefPtr<Cursor> m_arrow_cursor;
|
||||
RefPtr<Cursor> m_hand_cursor;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue