Serenity Operating System
1/*
2 * Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/LexicalPath.h>
8#include <WindowServer/Cursor.h>
9#include <WindowServer/Screen.h>
10#include <WindowServer/WindowManager.h>
11
12namespace WindowServer {
13
14Cursor::Cursor(NonnullRefPtr<Gfx::Bitmap const>&& bitmap, int scale_factor, Gfx::CursorParams const& cursor_params)
15 : m_params(cursor_params.constrained(*bitmap))
16 , m_rect(bitmap->rect())
17{
18 m_bitmaps.set(scale_factor, move(bitmap));
19 update_rect_if_animated();
20}
21
22void Cursor::update_rect_if_animated()
23{
24 if (m_params.frames() > 1) {
25 VERIFY(m_rect.width() % m_params.frames() == 0);
26 m_rect.set_width(m_rect.width() / m_params.frames());
27 }
28}
29
30NonnullRefPtr<Cursor const> Cursor::create(NonnullRefPtr<Gfx::Bitmap const>&& bitmap, int scale_factor)
31{
32 auto hotspot = bitmap->rect().center();
33 return adopt_ref(*new Cursor(move(bitmap), scale_factor, Gfx::CursorParams(hotspot)));
34}
35
36RefPtr<Cursor const> Cursor::create(StringView filename, StringView default_filename)
37{
38 auto cursor = adopt_ref(*new Cursor());
39 if (cursor->load(filename, default_filename))
40 return cursor;
41 return {};
42}
43
44bool Cursor::load(StringView filename, StringView default_filename)
45{
46 bool did_load_any = false;
47
48 auto load_bitmap = [&](StringView path, int scale_factor) {
49 auto bitmap_or_error = Gfx::Bitmap::load_from_file(path, scale_factor);
50 if (bitmap_or_error.is_error())
51 return;
52 did_load_any = true;
53 m_bitmaps.set(scale_factor, bitmap_or_error.release_value());
54 };
55
56 Screen::for_each_scale_factor_in_use([&](int scale_factor) {
57 load_bitmap(filename, scale_factor);
58 return IterationDecision::Continue;
59 });
60 if (!did_load_any) {
61 Screen::for_each_scale_factor_in_use([&](int scale_factor) {
62 load_bitmap(default_filename, scale_factor);
63 return IterationDecision::Continue;
64 });
65 }
66 if (did_load_any) {
67 auto& bitmap = this->bitmap(1);
68 m_rect = bitmap.rect();
69 m_params = Gfx::CursorParams::parse_from_filename(filename, m_rect.center()).constrained(bitmap);
70 update_rect_if_animated();
71 }
72 return did_load_any;
73}
74
75RefPtr<Cursor const> Cursor::create(Gfx::StandardCursor standard_cursor)
76{
77 switch (standard_cursor) {
78 case Gfx::StandardCursor::None:
79 return nullptr;
80 case Gfx::StandardCursor::Hidden:
81 return WindowManager::the().hidden_cursor();
82 case Gfx::StandardCursor::Arrow:
83 return WindowManager::the().arrow_cursor();
84 case Gfx::StandardCursor::Crosshair:
85 return WindowManager::the().crosshair_cursor();
86 case Gfx::StandardCursor::IBeam:
87 return WindowManager::the().i_beam_cursor();
88 case Gfx::StandardCursor::ResizeHorizontal:
89 return WindowManager::the().resize_horizontally_cursor();
90 case Gfx::StandardCursor::ResizeVertical:
91 return WindowManager::the().resize_vertically_cursor();
92 case Gfx::StandardCursor::ResizeDiagonalTLBR:
93 return WindowManager::the().resize_diagonally_tlbr_cursor();
94 case Gfx::StandardCursor::ResizeDiagonalBLTR:
95 return WindowManager::the().resize_diagonally_bltr_cursor();
96 case Gfx::StandardCursor::ResizeColumn:
97 return WindowManager::the().resize_column_cursor();
98 case Gfx::StandardCursor::ResizeRow:
99 return WindowManager::the().resize_row_cursor();
100 case Gfx::StandardCursor::Hand:
101 return WindowManager::the().hand_cursor();
102 case Gfx::StandardCursor::Help:
103 return WindowManager::the().help_cursor();
104 case Gfx::StandardCursor::Drag:
105 return WindowManager::the().drag_cursor();
106 case Gfx::StandardCursor::DragCopy:
107 return WindowManager::the().drag_copy_cursor();
108 case Gfx::StandardCursor::Move:
109 return WindowManager::the().move_cursor();
110 case Gfx::StandardCursor::Wait:
111 return WindowManager::the().wait_cursor();
112 case Gfx::StandardCursor::Disallowed:
113 return WindowManager::the().disallowed_cursor();
114 case Gfx::StandardCursor::Eyedropper:
115 return WindowManager::the().eyedropper_cursor();
116 case Gfx::StandardCursor::Zoom:
117 return WindowManager::the().zoom_cursor();
118 default:
119 VERIFY_NOT_REACHED();
120 }
121}
122
123}