/* * Copyright (c) 2018-2020, Andreas Kling * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace WindowServer { class Screen; class MouseEvent; class Window; class ClientConnection; class WindowSwitcher; class Button; enum class ResizeDirection { None, Left, UpLeft, Up, UpRight, Right, DownRight, Down, DownLeft }; class WindowManager : public Core::Object { C_OBJECT(WindowManager) friend class Compositor; friend class WindowFrame; friend class WindowSwitcher; public: static WindowManager& the(); explicit WindowManager(const Gfx::PaletteImpl&); virtual ~WindowManager() override; Palette palette() const { return Palette(*m_palette); } RefPtr config() const { return m_config; } void reload_config(bool); void add_window(Window&); void remove_window(Window&); void notify_title_changed(Window&); void notify_rect_changed(Window&, const Gfx::Rect& oldRect, const Gfx::Rect& newRect); void notify_minimization_state_changed(Window&); void notify_opacity_changed(Window&); void notify_occlusion_state_changed(Window&); void notify_client_changed_app_menubar(ClientConnection&); Gfx::Rect maximized_window_rect(const Window&) const; const ClientConnection* dnd_client() const { return m_dnd_client.ptr(); } const String& dnd_text() const { return m_dnd_text; } const String& dnd_data_type() const { return m_dnd_data_type; } const String& dnd_data() const { return m_dnd_data; } const Gfx::Bitmap* dnd_bitmap() const { return m_dnd_bitmap; } Gfx::Rect dnd_rect() const; void start_dnd_drag(ClientConnection&, const String& text, Gfx::Bitmap*, const String& data_type, const String& data); void end_dnd_drag(); const Window* active_window() const { return m_active_window.ptr(); } const ClientConnection* active_client() const; bool active_window_is_modal() const { return m_active_window && m_active_window->is_modal(); } const Window* highlight_window() const { return m_highlight_window.ptr(); } void set_highlight_window(Window*); void move_to_front_and_make_active(Window&); Gfx::Rect menubar_rect() const; Gfx::Rect desktop_rect() const; const Cursor& active_cursor() const; const Cursor& arrow_cursor() const { return *m_arrow_cursor; } const Cursor& hand_cursor() const { return *m_hand_cursor; } const Cursor& resize_horizontally_cursor() const { return *m_resize_horizontally_cursor; } const Cursor& resize_vertically_cursor() const { return *m_resize_vertically_cursor; } const Cursor& resize_diagonally_tlbr_cursor() const { return *m_resize_diagonally_tlbr_cursor; } const Cursor& resize_diagonally_bltr_cursor() const { return *m_resize_diagonally_bltr_cursor; } const Cursor& i_beam_cursor() const { return *m_i_beam_cursor; } const Cursor& disallowed_cursor() const { return *m_disallowed_cursor; } const Cursor& move_cursor() const { return *m_move_cursor; } const Cursor& drag_cursor() const { return *m_drag_cursor; } void invalidate(const Gfx::Rect&); void invalidate(); void flush(const Gfx::Rect&); const Gfx::Font& font() const; const Gfx::Font& window_title_font() const; bool set_resolution(int width, int height); Gfx::Size resolution() const; void set_active_window(Window*); void set_hovered_button(Button*); const Button* cursor_tracking_button() const { return m_cursor_tracking_button.ptr(); } void set_cursor_tracking_button(Button*); void set_resize_candidate(Window&, ResizeDirection); void clear_resize_candidate(); ResizeDirection resize_direction_of_window(const Window&); void tell_wm_listeners_window_state_changed(Window&); void tell_wm_listeners_window_icon_changed(Window&); void tell_wm_listeners_window_rect_changed(Window&); void start_window_resize(Window&, const Gfx::Point&, MouseButton); void start_window_resize(Window&, const MouseEvent&); const Window* active_fullscreen_window() const { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; } Window* active_fullscreen_window() { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; } bool update_theme(String theme_path, String theme_name); void set_hovered_window(Window*); void deliver_mouse_event(Window& window, MouseEvent& event); void did_popup_a_menu(Badge); private: NonnullRefPtr get_cursor(const String& name); NonnullRefPtr get_cursor(const String& name, const Gfx::Point& hotspot); void process_mouse_event(MouseEvent&, Window*& hovered_window); void process_event_for_doubleclick(Window& window, MouseEvent& event); bool process_ongoing_window_resize(const MouseEvent&, Window*& hovered_window); bool process_ongoing_window_move(MouseEvent&, Window*& hovered_window); bool process_ongoing_drag(MouseEvent&, Window*& hovered_window); void start_window_move(Window&, const MouseEvent&); template IterationDecision for_each_visible_window_of_type_from_back_to_front(WindowType, Callback, bool ignore_highlight = false); template IterationDecision for_each_visible_window_of_type_from_front_to_back(WindowType, Callback, bool ignore_highlight = false); template IterationDecision for_each_visible_window_from_front_to_back(Callback); template IterationDecision for_each_visible_window_from_back_to_front(Callback); template void for_each_window_listening_to_wm_events(Callback); template void for_each_window(Callback); template IterationDecision for_each_window_of_type_from_front_to_back(WindowType, Callback, bool ignore_highlight = false); virtual void event(Core::Event&) override; void paint_window_frame(const Window&); void tell_wm_listener_about_window(Window& listener, Window&); void tell_wm_listener_about_window_icon(Window& listener, Window&); void tell_wm_listener_about_window_rect(Window& listener, Window&); void pick_new_active_window(); RefPtr m_arrow_cursor; RefPtr m_hand_cursor; RefPtr m_resize_horizontally_cursor; RefPtr m_resize_vertically_cursor; RefPtr m_resize_diagonally_tlbr_cursor; RefPtr m_resize_diagonally_bltr_cursor; RefPtr m_i_beam_cursor; RefPtr m_disallowed_cursor; RefPtr m_move_cursor; RefPtr m_drag_cursor; InlineLinkedList m_windows_in_order; struct DoubleClickInfo { struct ClickMetadata { Core::ElapsedTimer clock; Gfx::Point last_position; }; ClickMetadata& metadata_for_button(MouseButton); void reset() { m_left = {}; m_right = {}; m_middle = {}; m_back = {}; m_forward = {}; } WeakPtr m_clicked_window; private: ClickMetadata m_left; ClickMetadata m_right; ClickMetadata m_middle; ClickMetadata m_back; ClickMetadata m_forward; }; DoubleClickInfo m_double_click_info; int m_double_click_speed { 0 }; int m_max_distance_for_double_click { 4 }; WeakPtr m_active_window; WeakPtr m_hovered_window; WeakPtr m_highlight_window; WeakPtr m_active_input_window; WeakPtr m_move_window; Gfx::Point m_move_origin; Gfx::Point m_move_window_origin; WeakPtr m_resize_window; WeakPtr m_resize_candidate; MouseButton m_resizing_mouse_button { MouseButton::None }; Gfx::Rect m_resize_window_original_rect; Gfx::Point m_resize_origin; ResizeDirection m_resize_direction { ResizeDirection::None }; bool m_moved_or_resized_since_logo_keydown { false }; u8 m_keyboard_modifiers { 0 }; WindowSwitcher m_switcher; WeakPtr