Serenity Operating System
1/*
2 * Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, the SerenityOS developers.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include <AK/StringBuilder.h>
11#include <AK/Vector.h>
12#include <Kernel/API/KeyCode.h>
13#include <LibCore/Event.h>
14#include <LibGUI/FocusSource.h>
15#include <LibGUI/Forward.h>
16#include <LibGUI/WindowType.h>
17#include <LibGfx/Bitmap.h>
18#include <LibGfx/Point.h>
19#include <LibGfx/Rect.h>
20
21namespace GUI {
22
23class Event : public Core::Event {
24public:
25 enum Type {
26 Show = 1000,
27 Hide,
28 Paint,
29 MultiPaint,
30 Resize,
31 Move,
32 MouseMove,
33 MouseDown,
34 MouseDoubleClick,
35 MouseUp,
36 MouseWheel,
37 Enter,
38 Leave,
39 KeyDown,
40 KeyUp,
41 WindowEntered,
42 WindowLeft,
43 WindowBecameInactive,
44 WindowBecameActive,
45 WindowInputPreempted,
46 WindowInputRestored,
47 FocusIn,
48 FocusOut,
49 WindowCloseRequest,
50 ContextMenu,
51 EnabledChange,
52 DragEnter,
53 DragLeave,
54 DragMove,
55 Drop,
56 ThemeChange,
57 FontsChange,
58 ScreenRectsChange,
59 ActionEnter,
60 ActionLeave,
61 AppletAreaRectChange,
62
63 __Begin_WM_Events,
64 WM_WindowRemoved,
65 WM_WindowStateChanged,
66 WM_WindowRectChanged,
67 WM_WindowIconBitmapChanged,
68 WM_AppletAreaSizeChanged,
69 WM_SuperKeyPressed,
70 WM_SuperSpaceKeyPressed,
71 WM_SuperDKeyPressed,
72 WM_SuperDigitKeyPressed,
73 WM_WorkspaceChanged,
74 WM_KeymapChanged,
75 __End_WM_Events,
76 };
77
78 Event() = default;
79 explicit Event(Type type)
80 : Core::Event(type)
81 {
82 }
83 virtual ~Event() = default;
84
85 bool is_key_event() const { return type() == KeyUp || type() == KeyDown; }
86 bool is_paint_event() const { return type() == Paint; }
87};
88
89class WMEvent : public Event {
90public:
91 WMEvent(Type type, int client_id, int window_id)
92 : Event(type)
93 , m_client_id(client_id)
94 , m_window_id(window_id)
95 {
96 }
97
98 int client_id() const { return m_client_id; }
99 int window_id() const { return m_window_id; }
100
101private:
102 int m_client_id { -1 };
103 int m_window_id { -1 };
104};
105
106class WMSuperKeyPressedEvent : public WMEvent {
107public:
108 explicit WMSuperKeyPressedEvent(int client_id)
109 : WMEvent(Event::Type::WM_SuperKeyPressed, client_id, 0)
110 {
111 }
112};
113
114class WMSuperSpaceKeyPressedEvent : public WMEvent {
115public:
116 explicit WMSuperSpaceKeyPressedEvent(int client_id)
117 : WMEvent(Event::Type::WM_SuperSpaceKeyPressed, client_id, 0)
118 {
119 }
120};
121
122class WMSuperDKeyPressedEvent : public WMEvent {
123public:
124 explicit WMSuperDKeyPressedEvent(int client_id)
125 : WMEvent(Event::Type::WM_SuperDKeyPressed, client_id, 0)
126 {
127 }
128};
129
130class WMSuperDigitKeyPressedEvent : public WMEvent {
131public:
132 WMSuperDigitKeyPressedEvent(int client_id, u8 digit)
133 : WMEvent(Event::Type::WM_SuperDigitKeyPressed, client_id, 0)
134 , m_digit(digit)
135 {
136 }
137
138 u8 digit() const { return m_digit; }
139
140private:
141 u8 m_digit { 0 };
142};
143
144class WMAppletAreaSizeChangedEvent : public WMEvent {
145public:
146 explicit WMAppletAreaSizeChangedEvent(Gfx::IntSize size)
147 : WMEvent(Event::Type::WM_AppletAreaSizeChanged, 0, 0)
148 , m_size(size)
149 {
150 }
151
152 Gfx::IntSize size() const { return m_size; }
153
154private:
155 Gfx::IntSize m_size;
156};
157
158class WMWindowRemovedEvent : public WMEvent {
159public:
160 WMWindowRemovedEvent(int client_id, int window_id)
161 : WMEvent(Event::Type::WM_WindowRemoved, client_id, window_id)
162 {
163 }
164};
165
166class WMWindowStateChangedEvent : public WMEvent {
167public:
168 WMWindowStateChangedEvent(int client_id, int window_id, StringView title, Gfx::IntRect const& rect, unsigned workspace_row, unsigned workspace_column, bool is_active, bool is_blocked, WindowType window_type, bool is_minimized, bool is_frameless, Optional<int> progress)
169 : WMEvent(Event::Type::WM_WindowStateChanged, client_id, window_id)
170 , m_title(title)
171 , m_rect(rect)
172 , m_window_type(window_type)
173 , m_workspace_row(workspace_row)
174 , m_workspace_column(workspace_column)
175 , m_active(is_active)
176 , m_blocked(is_blocked)
177 , m_minimized(is_minimized)
178 , m_frameless(is_frameless)
179 , m_progress(progress)
180 {
181 }
182
183 DeprecatedString const& title() const { return m_title; }
184 Gfx::IntRect const& rect() const { return m_rect; }
185 bool is_active() const { return m_active; }
186 bool is_blocked() const { return m_blocked; }
187 WindowType window_type() const { return m_window_type; }
188 bool is_minimized() const { return m_minimized; }
189 bool is_frameless() const { return m_frameless; }
190 Optional<int> progress() const { return m_progress; }
191 unsigned workspace_row() const { return m_workspace_row; }
192 unsigned workspace_column() const { return m_workspace_column; }
193
194private:
195 DeprecatedString m_title;
196 Gfx::IntRect m_rect;
197 WindowType m_window_type;
198 unsigned m_workspace_row;
199 unsigned m_workspace_column;
200 bool m_active;
201 bool m_blocked;
202 bool m_minimized;
203 bool m_frameless;
204 Optional<int> m_progress;
205};
206
207class WMWindowRectChangedEvent : public WMEvent {
208public:
209 WMWindowRectChangedEvent(int client_id, int window_id, Gfx::IntRect const& rect)
210 : WMEvent(Event::Type::WM_WindowRectChanged, client_id, window_id)
211 , m_rect(rect)
212 {
213 }
214
215 Gfx::IntRect const& rect() const { return m_rect; }
216
217private:
218 Gfx::IntRect m_rect;
219};
220
221class WMWindowIconBitmapChangedEvent : public WMEvent {
222public:
223 WMWindowIconBitmapChangedEvent(int client_id, int window_id, Gfx::Bitmap const* bitmap)
224 : WMEvent(Event::Type::WM_WindowIconBitmapChanged, client_id, window_id)
225 , m_bitmap(move(bitmap))
226 {
227 }
228
229 Gfx::Bitmap const* bitmap() const { return m_bitmap; }
230
231private:
232 RefPtr<Gfx::Bitmap const> m_bitmap;
233};
234
235class WMWorkspaceChangedEvent : public WMEvent {
236public:
237 explicit WMWorkspaceChangedEvent(int client_id, unsigned current_row, unsigned current_column)
238 : WMEvent(Event::Type::WM_WorkspaceChanged, client_id, 0)
239 , m_current_row(current_row)
240 , m_current_column(current_column)
241 {
242 }
243
244 unsigned current_row() const { return m_current_row; }
245 unsigned current_column() const { return m_current_column; }
246
247private:
248 unsigned const m_current_row;
249 unsigned const m_current_column;
250};
251
252class WMKeymapChangedEvent : public WMEvent {
253public:
254 explicit WMKeymapChangedEvent(int client_id, DeprecatedString const& keymap)
255 : WMEvent(Event::Type::WM_KeymapChanged, client_id, 0)
256 , m_keymap(keymap)
257 {
258 }
259
260 DeprecatedString const& keymap() const { return m_keymap; }
261
262private:
263 const DeprecatedString m_keymap;
264};
265
266class MultiPaintEvent final : public Event {
267public:
268 explicit MultiPaintEvent(Vector<Gfx::IntRect, 32> rects, Gfx::IntSize window_size)
269 : Event(Event::MultiPaint)
270 , m_rects(move(rects))
271 , m_window_size(window_size)
272 {
273 }
274
275 Vector<Gfx::IntRect, 32> const& rects() const { return m_rects; }
276 Gfx::IntSize window_size() const { return m_window_size; }
277
278private:
279 Vector<Gfx::IntRect, 32> m_rects;
280 Gfx::IntSize m_window_size;
281};
282
283class PaintEvent final : public Event {
284public:
285 explicit PaintEvent(Gfx::IntRect const& rect, Gfx::IntSize window_size = {})
286 : Event(Event::Paint)
287 , m_rect(rect)
288 , m_window_size(window_size)
289 {
290 }
291
292 Gfx::IntRect const& rect() const { return m_rect; }
293 Gfx::IntSize window_size() const { return m_window_size; }
294
295private:
296 Gfx::IntRect m_rect;
297 Gfx::IntSize m_window_size;
298};
299
300class ResizeEvent final : public Event {
301public:
302 explicit ResizeEvent(Gfx::IntSize size)
303 : Event(Event::Resize)
304 , m_size(size)
305 {
306 }
307
308 Gfx::IntSize size() const { return m_size; }
309
310private:
311 Gfx::IntSize m_size;
312};
313
314class MoveEvent final : public Event {
315public:
316 explicit MoveEvent(Gfx::IntPoint size)
317 : Event(Event::Move)
318 , m_position(size)
319 {
320 }
321
322 Gfx::IntPoint position() const { return m_position; }
323
324private:
325 Gfx::IntPoint m_position;
326};
327
328class ContextMenuEvent final : public Event {
329public:
330 explicit ContextMenuEvent(Gfx::IntPoint position, Gfx::IntPoint screen_position)
331 : Event(Event::ContextMenu)
332 , m_position(position)
333 , m_screen_position(screen_position)
334 {
335 }
336
337 Gfx::IntPoint position() const { return m_position; }
338 Gfx::IntPoint screen_position() const { return m_screen_position; }
339
340private:
341 Gfx::IntPoint m_position;
342 Gfx::IntPoint m_screen_position;
343};
344
345class ShowEvent final : public Event {
346public:
347 ShowEvent()
348 : Event(Event::Show)
349 {
350 }
351};
352
353class HideEvent final : public Event {
354public:
355 HideEvent()
356 : Event(Event::Hide)
357 {
358 }
359};
360
361enum MouseButton : u8 {
362 None = 0,
363 Primary = 1,
364 Secondary = 2,
365 Middle = 4,
366 Backward = 8,
367 Forward = 16,
368};
369
370class KeyEvent final : public Event {
371public:
372 KeyEvent(Type type, KeyCode key, u8 modifiers, u32 code_point, u32 scancode)
373 : Event(type)
374 , m_key(key)
375 , m_modifiers(modifiers)
376 , m_code_point(code_point)
377 , m_scancode(scancode)
378 {
379 }
380
381 KeyCode key() const { return m_key; }
382 bool ctrl() const { return m_modifiers & Mod_Ctrl; }
383 bool alt() const { return m_modifiers & Mod_Alt; }
384 bool altgr() const { return m_modifiers & Mod_AltGr; }
385 bool shift() const { return m_modifiers & Mod_Shift; }
386 bool super() const { return m_modifiers & Mod_Super; }
387 u8 modifiers() const { return m_modifiers; }
388 u32 code_point() const { return m_code_point; }
389 DeprecatedString text() const
390 {
391 StringBuilder sb;
392 sb.append_code_point(m_code_point);
393 return sb.to_deprecated_string();
394 }
395 u32 scancode() const { return m_scancode; }
396
397 DeprecatedString to_deprecated_string() const;
398
399 bool is_arrow_key() const
400 {
401 switch (m_key) {
402 case KeyCode::Key_Up:
403 case KeyCode::Key_Down:
404 case KeyCode::Key_Left:
405 case KeyCode::Key_Right:
406 return true;
407 default:
408 return false;
409 }
410 }
411
412private:
413 friend class ConnectionToWindowServer;
414 KeyCode m_key { KeyCode::Key_Invalid };
415 u8 m_modifiers { 0 };
416 u32 m_code_point { 0 };
417 u32 m_scancode { 0 };
418};
419
420class MouseEvent final : public Event {
421public:
422 MouseEvent(Type type, Gfx::IntPoint position, unsigned buttons, MouseButton button, unsigned modifiers, int wheel_delta_x, int wheel_delta_y, int wheel_raw_delta_x, int wheel_raw_delta_y)
423 : Event(type)
424 , m_position(position)
425 , m_buttons(buttons)
426 , m_button(button)
427 , m_modifiers(modifiers)
428 , m_wheel_delta_x(wheel_delta_x)
429 , m_wheel_delta_y(wheel_delta_y)
430 , m_wheel_raw_delta_x(wheel_raw_delta_x)
431 , m_wheel_raw_delta_y(wheel_raw_delta_y)
432 {
433 }
434
435 Gfx::IntPoint position() const { return m_position; }
436 int x() const { return m_position.x(); }
437 int y() const { return m_position.y(); }
438 MouseButton button() const { return m_button; }
439 unsigned buttons() const { return m_buttons; }
440 bool ctrl() const { return m_modifiers & Mod_Ctrl; }
441 bool alt() const { return m_modifiers & Mod_Alt; }
442 bool shift() const { return m_modifiers & Mod_Shift; }
443 bool super() const { return m_modifiers & Mod_Super; }
444 unsigned modifiers() const { return m_modifiers; }
445 int wheel_delta_x() const { return m_wheel_delta_x; }
446 int wheel_delta_y() const { return m_wheel_delta_y; }
447 int wheel_raw_delta_x() const { return m_wheel_raw_delta_x; }
448 int wheel_raw_delta_y() const { return m_wheel_raw_delta_y; }
449
450private:
451 Gfx::IntPoint m_position;
452 unsigned m_buttons { 0 };
453 MouseButton m_button { MouseButton::None };
454 unsigned m_modifiers { 0 };
455 int m_wheel_delta_x { 0 };
456 int m_wheel_delta_y { 0 };
457 int m_wheel_raw_delta_x { 0 };
458 int m_wheel_raw_delta_y { 0 };
459};
460
461class DragEvent final : public Event {
462public:
463 DragEvent(Type type, Gfx::IntPoint position, Vector<DeprecatedString> mime_types)
464 : Event(type)
465 , m_position(position)
466 , m_mime_types(move(mime_types))
467 {
468 }
469
470 Gfx::IntPoint position() const { return m_position; }
471 Vector<DeprecatedString> const& mime_types() const { return m_mime_types; }
472
473private:
474 Gfx::IntPoint m_position;
475 Vector<DeprecatedString> m_mime_types;
476};
477
478class DropEvent final : public Event {
479public:
480 DropEvent(Gfx::IntPoint, DeprecatedString const& text, NonnullRefPtr<Core::MimeData const> mime_data);
481
482 ~DropEvent() = default;
483
484 Gfx::IntPoint position() const { return m_position; }
485 DeprecatedString const& text() const { return m_text; }
486 Core::MimeData const& mime_data() const { return m_mime_data; }
487
488private:
489 Gfx::IntPoint m_position;
490 DeprecatedString m_text;
491 NonnullRefPtr<Core::MimeData const> m_mime_data;
492};
493
494class ThemeChangeEvent final : public Event {
495public:
496 ThemeChangeEvent()
497 : Event(Type::ThemeChange)
498 {
499 }
500};
501
502class FontsChangeEvent final : public Event {
503public:
504 FontsChangeEvent()
505 : Event(Type::FontsChange)
506 {
507 }
508};
509
510class ScreenRectsChangeEvent final : public Event {
511public:
512 explicit ScreenRectsChangeEvent(Vector<Gfx::IntRect, 4> const& rects, size_t main_screen_index)
513 : Event(Type::ScreenRectsChange)
514 , m_rects(rects)
515 , m_main_screen_index(main_screen_index)
516 {
517 }
518
519 Vector<Gfx::IntRect, 4> const& rects() const { return m_rects; }
520 size_t main_screen_index() const { return m_main_screen_index; }
521
522private:
523 Vector<Gfx::IntRect, 4> m_rects;
524 size_t m_main_screen_index;
525};
526
527class AppletAreaRectChangeEvent final : public Event {
528public:
529 explicit AppletAreaRectChangeEvent(Gfx::IntRect rect)
530 : Event(Type::AppletAreaRectChange)
531 , m_rect(rect)
532 {
533 }
534
535 Gfx::IntRect rect() const { return m_rect; }
536
537private:
538 Gfx::IntRect const m_rect;
539};
540
541class FocusEvent final : public Event {
542public:
543 explicit FocusEvent(Type type, FocusSource source)
544 : Event(type)
545 , m_source(source)
546 {
547 }
548
549 FocusSource source() const { return m_source; }
550
551private:
552 FocusSource m_source { FocusSource::Programmatic };
553};
554
555class ActionEvent final : public Event {
556public:
557 ActionEvent(Type, Action&);
558 ~ActionEvent() = default;
559
560 Action const& action() const { return *m_action; }
561 Action& action() { return *m_action; }
562
563private:
564 NonnullRefPtr<Action> m_action;
565};
566
567inline StringView mouse_button_to_string(MouseButton key)
568{
569 switch (key) {
570 case MouseButton::None:
571 return "None"sv;
572 case MouseButton::Primary:
573 return "Primary"sv;
574 case MouseButton::Secondary:
575 return "Secondary"sv;
576 case MouseButton::Middle:
577 return "Middle"sv;
578 case MouseButton::Backward:
579 return "Backward"sv;
580 case MouseButton::Forward:
581 return "Forward"sv;
582 default:
583 VERIFY_NOT_REACHED();
584 }
585}
586
587}