diff --git a/laf b/laf index 0ae7eb7c7..410da165b 160000 --- a/laf +++ b/laf @@ -1 +1 @@ -Subproject commit 0ae7eb7c7fd40c5a3829cfddaede60f458877920 +Subproject commit 410da165bde1e7353eb46aa58481a956f2ad489b diff --git a/src/app/app.cpp b/src/app/app.cpp index 92a0b91f6..401da312f 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -359,7 +359,7 @@ void App::run() if (isGui()) { #ifdef _WIN32 // How to interpret one finger on Windows tablets. - ui::Manager::getDefault()->nativeWindow() + ui::Manager::getDefault()->display()->nativeWindow() ->setInterpretOneFingerGestureAsMouseMovement( preferences().experimental.oneFingerAsMouseMovement()); #endif diff --git a/src/app/commands/cmd_fullscreen_mode.cpp b/src/app/commands/cmd_fullscreen_mode.cpp index 3a78293c0..39cd63797 100644 --- a/src/app/commands/cmd_fullscreen_mode.cpp +++ b/src/app/commands/cmd_fullscreen_mode.cpp @@ -43,7 +43,7 @@ void FullscreenModeCommand::onExecute(Context* ctx) if (!manager) return; - os::Window* window = manager->nativeWindow(); + os::Window* window = manager->display()->nativeWindow(); ASSERT(window); if (!window) return; diff --git a/src/app/commands/cmd_fullscreen_preview.cpp b/src/app/commands/cmd_fullscreen_preview.cpp index 2797f04a5..6b260e87b 100644 --- a/src/app/commands/cmd_fullscreen_preview.cpp +++ b/src/app/commands/cmd_fullscreen_preview.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -51,8 +51,13 @@ public: , m_pal(m_sprite->palette(editor->frame())) , m_proj(editor->projection()) , m_index_bg_color(-1) - , m_doublebuf(Image::create(IMAGE_RGB, ui::display_w(), ui::display_h())) - , m_doublesur(os::instance()->makeRgbaSurface(ui::display_w(), ui::display_h())) { + , m_doublebuf(Image::create( + IMAGE_RGB, + editor->display()->size().w, + editor->display()->size().h)) + , m_doublesur(os::instance()->makeRgbaSurface( + editor->display()->size().w, + editor->display()->size().h)) { // Do not use DocWriter (do not lock the document) because we // will call other sub-commands (e.g. previous frame, next frame, // etc.). @@ -170,6 +175,7 @@ protected: } virtual void onPaint(PaintEvent& ev) override { + gfx::Size displaySize = display()->size(); Graphics* g = ev.graphics(); EditorRender& render = m_editor->renderEngine(); render.setRefLayersVisiblity(false); @@ -213,18 +219,18 @@ protected: 255, BlendMode::NORMAL); break; case TiledMode::X_AXIS: - for (u=x-w; ustyles.listHeaderLabel()); m_contextLabel.setStyle(theme->styles.listHeaderLabel()); - m_splitter1.setPosition(ui::display_w()*3/4 * 4/10); - m_splitter2.setPosition(ui::display_w()*3/4 * 2/10); + gfx::Size displaySize = display()->size(); + m_splitter1.setPosition(displaySize.w*3/4 * 4/10); + m_splitter2.setPosition(displaySize.w*3/4 * 2/10); addChild(&m_splitter1); m_splitter1.addChild(&m_actionLabel); @@ -881,7 +882,8 @@ void KeyboardShortcutsCommand::onExecute(Context* context) std::string neededSearchCopy = m_search; KeyboardShortcutsWindow window(keys, menuKeys, neededSearchCopy); - window.setBounds(gfx::Rect(0, 0, ui::display_w()*3/4, ui::display_h()*3/4)); + gfx::Size displaySize = ui::get_desktop_size(); + window.setBounds(gfx::Rect(0, 0, displaySize.w*3/4, displaySize.h*3/4)); window.loadLayout(); window.centerWindow(); diff --git a/src/app/commands/cmd_options.cpp b/src/app/commands/cmd_options.cpp index bcf5369ed..b10567409 100644 --- a/src/app/commands/cmd_options.cpp +++ b/src/app/commands/cmd_options.cpp @@ -725,7 +725,7 @@ public: m_pref.tablet.api(tabletStr); m_pref.experimental.loadWintabDriver(wintabState); - manager()->nativeWindow() + manager()->display()->nativeWindow() ->setInterpretOneFingerGestureAsMouseMovement( oneFingerAsMouseMovement()->isSelected()); @@ -845,10 +845,8 @@ private: void updateScreenScaling() { ui::Manager* manager = ui::Manager::getDefault(); - os::Window* window = manager->nativeWindow(); os::instance()->setGpuAcceleration(m_pref.general.gpuAcceleration()); - window->setScale(m_pref.general.screenScale()); - manager->setNativeWindow(window); + manager->updateAllDisplaysWithNewScale(m_pref.general.screenScale()); } void onApply() { diff --git a/src/app/commands/cmd_paste_text.cpp b/src/app/commands/cmd_paste_text.cpp index fdbc7fb70..1619fc740 100644 --- a/src/app/commands/cmd_paste_text.cpp +++ b/src/app/commands/cmd_paste_text.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019-2020 Igara Studio S.A. +// Copyright (C) 2019-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -29,7 +29,7 @@ #include "render/dithering.h" #include "render/ordered_dither.h" #include "render/quantization.h" -#include "ui/system.h" +#include "ui/manager.h" #include "paste_text.xml.h" @@ -124,10 +124,11 @@ private: } if (!m_fontPopup->isVisible()) { + gfx::Size displaySize = manager()->display()->size(); gfx::Rect bounds = fontFace()->bounds(); m_fontPopup->showPopup( gfx::Rect(bounds.x, bounds.y+bounds.h, - ui::display_w()/2, ui::display_h()/2)); + displaySize.w/2, displaySize.h/2)); } else { m_fontPopup->closeWindow(NULL); diff --git a/src/app/commands/cmd_undo.cpp b/src/app/commands/cmd_undo.cpp index 53666bc32..2b7ca04ee 100644 --- a/src/app/commands/cmd_undo.cpp +++ b/src/app/commands/cmd_undo.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2020 Igara Studio S.A. +// Copyright (C) 2020-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -94,7 +94,7 @@ void UndoCommand::onExecute(Context* context) current_editor->drawSpriteClipped( gfx::Region(gfx::Rect(0, 0, sprite->width(), sprite->height()))); - current_editor->manager()->flipDisplay(); + current_editor->display()->flipDisplay(); base::this_thread::sleep_for(0.01); } } diff --git a/src/app/commands/screenshot.cpp b/src/app/commands/screenshot.cpp index e0c5d975c..a0df48399 100644 --- a/src/app/commands/screenshot.cpp +++ b/src/app/commands/screenshot.cpp @@ -69,7 +69,7 @@ void ScreenshotCommand::onExecute(Context* ctx) app::ResourceFinder rf(false); rf.includeDesktopDir(""); - os::Window* window = ui::Manager::getDefault()->nativeWindow(); + os::Window* window = ui::Manager::getDefault()->display()->nativeWindow(); os::Surface* surface = window->surface(); std::string fn; diff --git a/src/app/console.cpp b/src/app/console.cpp index 78c1951da..242904232 100644 --- a/src/app/console.cpp +++ b/src/app/console.cpp @@ -70,8 +70,13 @@ public: void centerConsole() { initTheme(); + remapWindow(); - setBounds(gfx::Rect(0, 0, ui::display_w()*9/10, ui::display_h()*6/10)); + + // TODO center to main window or screen workspace + gfx::Size displaySize = manager()->display()->size(); + setBounds(gfx::Rect(0, 0, displaySize.w*9/10, displaySize.h*6/10)); + centerWindow(); invalidate(); } @@ -116,14 +121,16 @@ Console::Console(Context* ctx) if (!ui::is_ui_thread()) return; - if (ctx) + if (ctx) { m_withUI = (ctx->isUIAvailable()); - else + } + else { m_withUI = (App::instance() && App::instance()->isGui() && Manager::getDefault() && - Manager::getDefault()->nativeWindow()); + Manager::getDefault()->display()->nativeWindow()); + } if (!m_withUI) return; diff --git a/src/app/modules/gui.cpp b/src/app/modules/gui.cpp index 25d33ef2d..b063cd013 100644 --- a/src/app/modules/gui.cpp +++ b/src/app/modules/gui.cpp @@ -81,8 +81,13 @@ static struct { ////////////////////////////////////////////////////////////////////// -class CustomizedGuiManager : public Manager - , public LayoutIO { +class CustomizedGuiManager : public ui::Manager + , public ui::LayoutIO { +public: + CustomizedGuiManager(const os::WindowRef& nativeWindow) + : ui::Manager(nativeWindow) { + } + protected: bool onProcessMessage(Message* msg) override; #if ENABLE_DEVMODE @@ -90,7 +95,7 @@ protected: #endif void onInitTheme(InitThemeEvent& ev) override; LayoutIO* onGetLayoutIO() override { return this; } - void onNewDisplayConfiguration() override; + void onNewDisplayConfiguration(Display* display) override; // LayoutIO implementation std::string loadLayout(Widget* widget) override; @@ -193,8 +198,7 @@ int init_module_gui() } // Create the default-manager - manager = new CustomizedGuiManager(); - manager->setNativeWindow(main_window.get()); + manager = new CustomizedGuiManager(main_window); // Setup the GUI theme for all widgets gui_theme = new SkinTheme; @@ -205,17 +209,20 @@ int init_module_gui() // Handle live resize too redraw the entire manager, dispatch the UI // messages, and flip the window. - main_window->handleResize = + os::instance()->handleWindowResize = [](os::Window* window) { - manager->invalidate(); + Display* display = manager->getDisplayFromNativeWindow(window); + if (!display) + display = manager->display(); + ASSERT(display); Message* msg = new Message(kResizeDisplayMessage); + msg->setDisplay(display); msg->setRecipient(manager); msg->setPropagateToChildren(true); - manager->enqueueMessage(msg); + manager->enqueueMessage(msg); manager->dispatchMessages(); - manager->flipDisplay(); }; // Set graphics options for next time @@ -292,7 +299,7 @@ static void load_gui_config(int& w, int& h, bool& maximized, static void save_gui_config() { - os::Window* window = manager->nativeWindow(); + os::Window* window = manager->display()->nativeWindow(); if (window) { set_config_bool("GfxMode", "Maximized", window->isMaximized()); set_config_int("GfxMode", "Width", window->originalWidth()); @@ -327,6 +334,8 @@ void update_screen_for_document(const Doc* document) void load_window_pos(Widget* window, const char* section, const bool limitMinSize) { + Size desktopSize = ui::get_desktop_size(); + // Default position Rect orig_pos = window->bounds(); Rect pos = orig_pos; @@ -335,16 +344,16 @@ void load_window_pos(Widget* window, const char* section, pos = get_config_rect(section, "WindowPos", pos); if (limitMinSize) { - pos.w = base::clamp(pos.w, orig_pos.w, ui::display_w()); - pos.h = base::clamp(pos.h, orig_pos.h, ui::display_h()); + pos.w = base::clamp(pos.w, orig_pos.w, desktopSize.w); + pos.h = base::clamp(pos.h, orig_pos.h, desktopSize.h); } else { - pos.w = std::min(pos.w, ui::display_w()); - pos.h = std::min(pos.h, ui::display_h()); + pos.w = std::min(pos.w, desktopSize.w); + pos.h = std::min(pos.h, desktopSize.h); } - pos.setOrigin(Point(base::clamp(pos.x, 0, ui::display_w()-pos.w), - base::clamp(pos.y, 0, ui::display_h()-pos.h))); + pos.setOrigin(Point(base::clamp(pos.x, 0, desktopSize.w-pos.w), + base::clamp(pos.y, 0, desktopSize.h-pos.h))); window->setBounds(pos); } @@ -653,9 +662,9 @@ void CustomizedGuiManager::onInitTheme(InitThemeEvent& ev) AppMenus::instance()->initTheme(); } -void CustomizedGuiManager::onNewDisplayConfiguration() +void CustomizedGuiManager::onNewDisplayConfiguration(Display* display) { - Manager::onNewDisplayConfiguration(); + Manager::onNewDisplayConfiguration(display); save_gui_config(); // TODO Should we provide a more generic way for all ui::Window to diff --git a/src/app/ui/color_bar.cpp b/src/app/ui/color_bar.cpp index bc8386005..40db5d391 100644 --- a/src/app/ui/color_bar.cpp +++ b/src/app/ui/color_bar.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -1884,12 +1884,13 @@ void ColorBar::showPalettePresets() } if (!m_palettePopup->isVisible()) { + gfx::Size displaySize = ui::get_desktop_size(); gfx::Rect bounds = m_buttons.getItem( static_cast(PalButton::PRESETS))->bounds(); m_palettePopup->showPopup( gfx::Rect(bounds.x, bounds.y+bounds.h, - ui::display_w()/2, ui::display_h()*3/4)); + displaySize.w/2, displaySize.h*3/4)); } else { m_palettePopup->closeWindow(NULL); diff --git a/src/app/ui/color_button.cpp b/src/app/ui/color_button.cpp index 3692c3bc1..73f5df230 100644 --- a/src/app/ui/color_button.cpp +++ b/src/app/ui/color_button.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2020 Igara Studio S.A. +// Copyright (C) 2020-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -302,12 +302,13 @@ void ColorButton::openPopup(const bool forcePinned) m_window->setColor(m_color, ColorPopup::ChangeType); m_window->openWindow(); + gfx::Size displaySize = ui::get_desktop_size(); gfx::Rect winBounds; if (!pinned || (forcePinned && m_hiddenPopupBounds.isEmpty())) { winBounds = gfx::Rect(m_window->bounds().origin(), m_window->sizeHint()); - winBounds.x = base::clamp(bounds().x, 0, ui::display_w()-winBounds.w); - if (bounds().y2() <= ui::display_h()-winBounds.h) + winBounds.x = base::clamp(bounds().x, 0, displaySize.w-winBounds.w); + if (bounds().y2() <= displaySize.h-winBounds.h) winBounds.y = std::max(0, bounds().y2()); else winBounds.y = std::max(0, bounds().y-winBounds.h); @@ -318,8 +319,8 @@ void ColorButton::openPopup(const bool forcePinned) else { winBounds = m_windowDefaultBounds; } - winBounds.x = base::clamp(winBounds.x, 0, ui::display_w()-winBounds.w); - winBounds.y = base::clamp(winBounds.y, 0, ui::display_h()-winBounds.h); + winBounds.x = base::clamp(winBounds.x, 0, displaySize.w-winBounds.w); + winBounds.y = base::clamp(winBounds.y, 0, displaySize.h-winBounds.h); m_window->setBounds(winBounds); m_window->manager()->dispatchMessages(); diff --git a/src/app/ui/draggable_widget.h b/src/app/ui/draggable_widget.h index ebcdd6461..1c6e7f74f 100644 --- a/src/app/ui/draggable_widget.h +++ b/src/app/ui/draggable_widget.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -147,14 +147,16 @@ private: paint.style(os::Paint::Fill); surface->drawRect(gfx::Rect(0, 0, surface->width(), surface->height()), paint); } + + ui::Display* display = this->Base::display(); { - ui::Graphics g(surface, 0, 0); + ui::Graphics g(display, surface, 0, 0); g.setFont(AddRef(this->font())); drawFloatingOverlay(g); } m_floatingOverlay = base::make_ref( - surface, gfx::Point(), + display, surface, gfx::Point(), (ui::Overlay::ZOrder)(ui::Overlay::MouseZOrder-1)); ui::OverlayManager::instance()->addOverlay(m_floatingOverlay); } diff --git a/src/app/ui/editor/brush_preview.cpp b/src/app/ui/editor/brush_preview.cpp index cfee3160b..56c726695 100644 --- a/src/app/ui/editor/brush_preview.cpp +++ b/src/app/ui/editor/brush_preview.cpp @@ -349,7 +349,7 @@ void BrushPreview::show(const gfx::Point& screenPos) // Save area and draw the cursor if (!(m_type & NATIVE_CROSSHAIR) || (m_type & BRUSH_BOUNDARIES)) { - ui::ScreenGraphics g; + ui::ScreenGraphics g(m_editor->display()); ui::SetClip clip(&g); gfx::Color uiCursorColor = color_utils::color_for_ui(appCursorColor); forEachBrushPixel(&g, m_screenPosition, spritePos, uiCursorColor, &BrushPreview::savePixelDelegate); @@ -387,7 +387,7 @@ void BrushPreview::hide() if (m_withModifiedPixels) { // Restore pixels - ui::ScreenGraphics g; + ui::ScreenGraphics g(m_editor->display()); ui::SetClip clip(&g); forEachBrushPixel(&g, m_screenPosition, m_editorPosition, gfx::ColorNone, &BrushPreview::clearPixelDelegate); diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp index 1c2b173ac..cf3e0eece 100644 --- a/src/app/ui/editor/editor.cpp +++ b/src/app/ui/editor/editor.cpp @@ -947,7 +947,7 @@ void Editor::drawSpriteClipped(const gfx::Region& updateRegion) Region screenRegion; getDrawableRegion(screenRegion, kCutTopWindows); - ScreenGraphics screenGraphics; + ScreenGraphics screenGraphics(display()); GraphicsPtr editorGraphics = getGraphics(clientBounds()); for (const Rect& updateRect : updateRegion) { @@ -1163,7 +1163,6 @@ void Editor::drawTileNumbers(ui::Graphics* g, const Cel* cel) int ti_offset = static_cast(cel->layer())->tileset()->baseIndex() - 1; - const gfx::Rect rc = cel->bounds(); const doc::Image* image = cel->image(); std::string text; for (int y=0; yheight(); ++y) { diff --git a/src/app/ui/editor/standby_state.cpp b/src/app/ui/editor/standby_state.cpp index facfcabf8..c8300099e 100644 --- a/src/app/ui/editor/standby_state.cpp +++ b/src/app/ui/editor/standby_state.cpp @@ -1029,7 +1029,7 @@ void StandbyState::Decorator::postRenderDecorator(EditorPostRender* render) if (StandbyState::Decorator::getSymmetryHandles(editor, handles)) { skin::SkinTheme* theme = static_cast(ui::get_theme()); os::Surface* part = theme->parts.transformationHandle()->bitmap(0); - ScreenGraphics g; + ScreenGraphics g(editor->display()); for (const auto& handle : handles) g.drawRgbaSurface(part, handle.bounds.x, handle.bounds.y); } diff --git a/src/app/ui/editor/zooming_state.cpp b/src/app/ui/editor/zooming_state.cpp index fa99a0e33..b9c132c7b 100644 --- a/src/app/ui/editor/zooming_state.cpp +++ b/src/app/ui/editor/zooming_state.cpp @@ -67,7 +67,7 @@ bool ZoomingState::onMouseUp(Editor* editor, MouseMessage* msg) bool ZoomingState::onMouseMove(Editor* editor, MouseMessage* msg) { gfx::Point pt = (msg->position() - m_startPos); - int threshold = 8 * guiscale() * editor->manager()->nativeWindow()->scale(); + int threshold = 8 * guiscale() * editor->display()->nativeWindow()->scale(); if (m_moved || std::sqrt(pt.x*pt.x + pt.y*pt.y) > threshold) { m_moved = true; diff --git a/src/app/ui/file_selector.cpp b/src/app/ui/file_selector.cpp index 3249bbce8..06eb04302 100644 --- a/src/app/ui/file_selector.cpp +++ b/src/app/ui/file_selector.cpp @@ -421,7 +421,8 @@ bool FileSelector::show( FILESEL_TRACE("FILESEL: Start folder '%s' (%p)\n", start_folder_path.c_str(), start_folder); - setMinSize(gfx::Size(ui::display_w()*9/10, ui::display_h()*9/10)); + gfx::Size displaySize = ui::get_desktop_size(); + setMinSize(gfx::Size(displaySize.w*9/10, displaySize.h*9/10)); remapWindow(); centerWindow(); diff --git a/src/app/ui/main_window.cpp b/src/app/ui/main_window.cpp index defb46db6..50b108d8a 100644 --- a/src/app/ui/main_window.cpp +++ b/src/app/ui/main_window.cpp @@ -77,10 +77,8 @@ public: ui::set_theme(ui::get_theme(), newUIScale); - Manager* manager = Manager::getDefault(); - os::Window* window = manager->nativeWindow(); - window->setScale(newScreenScale); - manager->setNativeWindow(window); + Manager::getDefault() + ->updateAllDisplaysWithNewScale(newScreenScale); } }; @@ -370,12 +368,13 @@ void MainWindow::onResize(ui::ResizeEvent& ev) { app::gen::MainWindow::onResize(ev); - os::Window* window = manager()->nativeWindow(); - if ((window) && - (window->scale()*ui::guiscale() > 2) && + gfx::Size desktopSize = ui::get_desktop_size(); + ui::Display* display = this->display(); + if ((display) && + (display->nativeWindow()->scale()*ui::guiscale() > 2) && (!m_scalePanic) && - (ui::display_w()/ui::guiscale() < 320 || - ui::display_h()/ui::guiscale() < 260)) { + (desktopSize.w/ui::guiscale() < 320 || + desktopSize.h/ui::guiscale() < 260)) { showNotification(m_scalePanic = new ScreenScalePanic); } } diff --git a/src/app/ui/preview_editor.cpp b/src/app/ui/preview_editor.cpp index e591ebd5b..4759c72f5 100644 --- a/src/app/ui/preview_editor.cpp +++ b/src/app/ui/preview_editor.cpp @@ -224,13 +224,14 @@ bool PreviewEditorWindow::onProcessMessage(ui::Message* msg) SkinTheme* theme = SkinTheme::instance(); // Default bounds - int width = ui::display_w()/4; - int height = ui::display_h()/4; + gfx::Size desktopSize = ui::get_desktop_size(); + const int width = desktopSize.w/4; + const int height = desktopSize.h/4; int extra = 2*theme->dimensions.miniScrollbarSize(); setBounds( gfx::Rect( - ui::display_w() - width - ToolBar::instance()->bounds().w - extra, - ui::display_h() - height - StatusBar::instance()->bounds().h - extra, + desktopSize.w - width - ToolBar::instance()->bounds().w - extra, + desktopSize.h - height - StatusBar::instance()->bounds().h - extra, width, height)); load_window_pos(this, "MiniEditor", false); diff --git a/src/app/ui/tabs.cpp b/src/app/ui/tabs.cpp index d14eeed69..82bee8719 100644 --- a/src/app/ui/tabs.cpp +++ b/src/app/ui/tabs.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2017 David Capello // // This program is distributed under the terms of @@ -941,6 +941,7 @@ void Tabs::createFloatingOverlay(Tab* tab) { ASSERT(!m_floatingOverlay); + ui::Display* display = this->display(); os::SurfaceRef surface = os::instance()->makeRgbaSurface( tab->width, m_tabsHeight); @@ -953,13 +954,13 @@ void Tabs::createFloatingOverlay(Tab* tab) surface->drawRect(gfx::Rect(0, 0, surface->width(), surface->height()), paint); } { - Graphics g(surface, 0, 0); + Graphics g(display, surface, 0, 0); g.setFont(AddRef(font())); drawTab(&g, g.getClipBounds(), tab, 0, true, true); } m_floatingOverlay = base::make_ref( - surface, gfx::Point(), + display, surface, gfx::Point(), (ui::Overlay::ZOrder)(Overlay::MouseZOrder-1)); OverlayManager::instance()->addOverlay(m_floatingOverlay); } diff --git a/src/app/ui/timeline/timeline.cpp b/src/app/ui/timeline/timeline.cpp index 12d7f4cca..74966bd63 100644 --- a/src/app/ui/timeline/timeline.cpp +++ b/src/app/ui/timeline/timeline.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -1242,7 +1242,7 @@ bool Timeline::onProcessMessage(Message* msg) if (!m_confPopup->isVisible()) { gfx::Rect bounds = m_confPopup->bounds(); - ui::fit_bounds(BOTTOM, gearBounds, bounds); + ui::fit_bounds(display(), BOTTOM, gearBounds, bounds); m_confPopup->moveWindow(bounds); m_confPopup->openWindow(); diff --git a/src/app/ui/toolbar.cpp b/src/app/ui/toolbar.cpp index 5bb21e40c..c819c6bd2 100644 --- a/src/app/ui/toolbar.cpp +++ b/src/app/ui/toolbar.cpp @@ -530,7 +530,8 @@ void ToolBar::openTipWindow(int group_index, Tool* tool) if (tool && m_popupWindow && m_popupWindow->isVisible()) toolrc.x += arrow.x - m_popupWindow->bounds().w; - m_tipWindow->pointAt(TOP | RIGHT, toolrc); + m_tipWindow->pointAt(TOP | RIGHT, toolrc, + ui::Manager::getDefault()->display()); if (m_tipOpened) m_tipWindow->openWindow(); diff --git a/src/tests/test.h b/src/tests/test.h index 1d2d746c8..00b396183 100644 --- a/src/tests/test.h +++ b/src/tests/test.h @@ -40,7 +40,7 @@ int main(int argc, char* argv[]) // Do not create a os::System, as we don't need it for testing purposes. //os::ScopedHandle system(os::create_system()); ui::UISystem uiSystem; - ui::Manager uiManager; + ui::Manager uiManager(nullptr); #endif exitcode = RUN_ALL_TESTS(); diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index a2db7bb6c..563aa9b58 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,4 +1,5 @@ # Aseprite UI Library +# Copyright (C) 2019 Igara Studio S.A. # Copyright (C) 2001-2018 David Capello if(WIN32) @@ -13,6 +14,7 @@ add_library(ui-lib combobox.cpp component.cpp cursor.cpp + display.cpp entry.cpp event.cpp fit_bounds.cpp diff --git a/src/ui/combobox.cpp b/src/ui/combobox.cpp index 71de76dcb..fa95fd067 100644 --- a/src/ui/combobox.cpp +++ b/src/ui/combobox.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2017 David Capello // // This file is released under the terms of the MIT license. @@ -614,8 +614,12 @@ void ComboBox::openListBox() m_window = new Window(Window::WithoutTitleBar); View* view = new View(); m_listbox = new ComboBoxListBox(this); + // TODO create a real native window for comboboxes + m_window->setDisplay(display()); m_window->setOnTop(true); m_window->setWantFocus(false); + m_window->setSizeable(false); + m_window->setMoveable(false); Widget* viewport = view->viewport(); { @@ -627,8 +631,10 @@ void ComboBox::openListBox() if (!item->hasFlags(HIDDEN)) size.h += item->sizeHint().h; - int max = std::max(entryBounds.y, ui::display_h() - entryBounds.y2()) - 8*guiscale(); - size.h = base::clamp(size.h, textHeight(), max); + const int maxVal = + std::max(entryBounds.y, display()->size().h - entryBounds.y2()) + - 8*guiscale(); + size.h = base::clamp(size.h, textHeight(), maxVal); viewport->setMinSize(size); } @@ -688,7 +694,7 @@ gfx::Rect ComboBox::getListBoxPos() const gfx::Point(m_button->bounds().x2(), entryBounds.y2() + m_window->bounds().h)); - if (rc.y2() > ui::display_h()) + if (rc.y2() > display()->size().h) rc.offset(0, -(rc.h + entryBounds.h)); return rc; diff --git a/src/ui/display.cpp b/src/ui/display.cpp new file mode 100644 index 000000000..e24f3a9f3 --- /dev/null +++ b/src/ui/display.cpp @@ -0,0 +1,114 @@ +// Aseprite UI Library +// Copyright (C) 2019-2021 Igara Studio S.A. +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ui/display.h" + +#include "base/debug.h" +#include "ui/widget.h" +#include "ui/window.h" + +#include + +namespace ui { + +Display::Display(const os::WindowRef& nativeWindow, + Widget* containedWidget) + : m_nativeWindow(nativeWindow) + , m_containedWidget(containedWidget) +{ + ASSERT(m_nativeWindow); + ASSERT(m_containedWidget); + ASSERT(m_containedWidget->type() == kManagerWidget || + m_containedWidget->type() == kWindowWidget); + m_dirtyRegion = bounds(); +} + +os::Surface* Display::surface() const +{ + return m_nativeWindow->surface(); +} + +gfx::Size Display::size() const +{ + ASSERT(m_nativeWindow); + const int scale = m_nativeWindow->scale(); + ASSERT(scale > 0); + return gfx::Size(m_nativeWindow->width() / scale, + m_nativeWindow->height() / scale); +} + +void Display::dirtyRect(const gfx::Rect& bounds) +{ + m_dirtyRegion.createUnion(m_dirtyRegion, gfx::Region(bounds)); +} + +void Display::flipDisplay() +{ + if (!m_dirtyRegion.isEmpty()) { + // Limit the region to the bounds of the window + m_dirtyRegion &= gfx::Region(bounds()); + + if (!m_dirtyRegion.isEmpty()) { + // Invalidate the dirty region in the os::Window + m_nativeWindow->invalidateRegion(m_dirtyRegion); + m_dirtyRegion.clear(); + } + } +} + +void Display::invalidateRect(const gfx::Rect& rect) +{ + m_containedWidget->invalidateRect(rect); +} + +void Display::invalidateRegion(const gfx::Region& region) +{ + m_containedWidget->invalidateRegion(region); +} + +void Display::addWindow(Window* window) +{ + m_windows.insert(m_windows.begin(), window); +} + +void Display::removeWindow(Window* window) +{ + auto it = std::find(m_windows.begin(), m_windows.end(), window); + ASSERT(it != m_windows.end()) + if (it == m_windows.end()) + return; + + m_windows.erase(it); +} + +// TODO code similar to Manager::handleWindowZOrder() +void Display::handleWindowZOrder(Window* window) +{ + removeWindow(window); + + if (window->isOnTop()) + m_windows.insert(m_windows.begin(), window); + else { + int pos = (int)m_windows.size(); + + for (auto it=m_windows.rbegin(), + end=m_windows.rend(); + it != end; ++it) { + if (static_cast(*it)->isOnTop()) + break; + + --pos; + } + + m_windows.insert(m_windows.begin()+pos, window); + } +} + +} // namespace ui diff --git a/src/ui/display.h b/src/ui/display.h new file mode 100644 index 000000000..ad84bfc44 --- /dev/null +++ b/src/ui/display.h @@ -0,0 +1,83 @@ +// Aseprite UI Library +// Copyright (C) 2019-2021 Igara Studio S.A. +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifndef UI_DISPLAY_H_INCLUDED +#define UI_DISPLAY_H_INCLUDED +#pragma once + +#include "gfx/rect.h" +#include "gfx/region.h" +#include "gfx/size.h" +#include "os/window.h" + +#include + +namespace ui { + class Widget; + class Window; + + // Wraps a native window (os::Window). On each "display" we can show + // the main manager or a window (containedWidget), and a set of + // children window that doesn't have a native window counterpart + // (tooltips?) + class Display { + public: + Display(const os::WindowRef& nativeWindow, + Widget* containedWidget); + + os::Window* nativeWindow() { return m_nativeWindow.get(); } + os::Surface* surface() const; + + gfx::Size size() const; + gfx::Rect bounds() const { return gfx::Rect(size()); } + + Widget* containedWidget() const { return m_containedWidget; } + + // Mark the given rectangle as a area to be flipped to the real + // screen. + void dirtyRect(const gfx::Rect& bounds); + + // Refreshes the real display with the UI content. + void flipDisplay(); + + // Returns the invalid region in the screen to being updated with + // PaintMessages. This region is cleared when each widget receives + // a paint message. + const gfx::Region& getInvalidRegion() const { + return m_invalidRegion; + } + + void addInvalidRegion(const gfx::Region& b) { + m_invalidRegion |= b; + } + + void subtractInvalidRegion(const gfx::Region& b) { + m_invalidRegion -= b; + } + + void setInvalidRegion(const gfx::Region& b) { + m_invalidRegion = b; + } + + void invalidateRect(const gfx::Rect& rect); + void invalidateRegion(const gfx::Region& region); + + void addWindow(Window* window); + void removeWindow(Window* window); + void handleWindowZOrder(Window* window); + const std::vector& getWindows() const { return m_windows; } + + private: + os::WindowRef m_nativeWindow; + Widget* m_containedWidget; // A ui::Manager or a ui::Window + std::vector m_windows; // Sub-windows in this display + gfx::Region m_invalidRegion; // Invalid region (we didn't receive paint messages yet for this). + gfx::Region m_dirtyRegion; // Region to flip to the os::Display + }; + +} // namespace ui + +#endif diff --git a/src/ui/entry.cpp b/src/ui/entry.cpp index 0a898a207..b78f2ec8e 100644 --- a/src/ui/entry.cpp +++ b/src/ui/entry.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -16,7 +16,6 @@ #include "os/draw_text.h" #include "os/font.h" #include "os/system.h" -#include "ui/manager.h" #include "ui/menu.h" #include "ui/message.h" #include "ui/scale.h" @@ -452,7 +451,7 @@ gfx::Size Entry::sizeHintWithText(Entry* entry, + 2*entry->theme()->getEntryCaretSize(entry).w + entry->border().width(); - w = std::min(w, ui::display_w()/2); + w = std::min(w, ui::get_desktop_size().w/2); int h = + entry->font()->height() @@ -471,7 +470,7 @@ void Entry::onSizeHint(SizeHintEvent& ev) + trailing + border().width(); - w = std::min(w, ui::display_w()/2); + w = std::min(w, ui::get_desktop_size().w/2); int h = + font()->height() diff --git a/src/ui/fit_bounds.cpp b/src/ui/fit_bounds.cpp index 3614eeaa9..ec8f05922 100644 --- a/src/ui/fit_bounds.cpp +++ b/src/ui/fit_bounds.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2019 Igara Studio S.A. +// Copyright (C) 2019-2020 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. @@ -9,14 +9,17 @@ #include "config.h" #endif +#include "ui/fit_bounds.h" + #include "base/clamp.h" #include "gfx/rect.h" #include "ui/base.h" +#include "ui/display.h" #include "ui/system.h" namespace ui { -int fit_bounds(int arrowAlign, const gfx::Rect& target, gfx::Rect& bounds) +int fit_bounds(Display* display, int arrowAlign, const gfx::Rect& target, gfx::Rect& bounds) { bounds.x = target.x; bounds.y = target.y; @@ -58,8 +61,9 @@ int fit_bounds(int arrowAlign, const gfx::Rect& target, gfx::Rect& bounds) break; } - bounds.x = base::clamp(bounds.x, 0, ui::display_w()-bounds.w); - bounds.y = base::clamp(bounds.y, 0, ui::display_h()-bounds.h); + gfx::Size displaySize = display->size(); + bounds.x = base::clamp(bounds.x, 0, displaySize.w-bounds.w); + bounds.y = base::clamp(bounds.y, 0, displaySize.h-bounds.h); if (target.intersects(bounds)) { switch (trycount) { diff --git a/src/ui/fit_bounds.h b/src/ui/fit_bounds.h index f18f3b18b..f6d1451f6 100644 --- a/src/ui/fit_bounds.h +++ b/src/ui/fit_bounds.h @@ -1,18 +1,21 @@ // Aseprite UI Library +// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. -#ifndef UI_POINT_AT_H_INCLUDED -#define UI_POINT_AT_H_INCLUDED +#ifndef UI_FIT_BOUNDS_H_INCLUDED +#define UI_FIT_BOUNDS_H_INCLUDED #pragma once #include "gfx/fwd.h" namespace ui { - int fit_bounds(int arrowAlign, const gfx::Rect& target, gfx::Rect& bounds); + class Display; + + int fit_bounds(Display* display, int arrowAlign, const gfx::Rect& target, gfx::Rect& bounds); } // namespace ui diff --git a/src/ui/graphics.cpp b/src/ui/graphics.cpp index 44eb97de7..9ee21b8c4 100644 --- a/src/ui/graphics.cpp +++ b/src/ui/graphics.cpp @@ -24,7 +24,7 @@ #include "os/surface.h" #include "os/system.h" #include "os/window.h" -#include "ui/manager.h" +#include "ui/display.h" #include "ui/scale.h" #include "ui/theme.h" @@ -34,8 +34,9 @@ namespace ui { -Graphics::Graphics(const os::SurfaceRef& surface, int dx, int dy) - : m_surface(surface) +Graphics::Graphics(Display* display, const os::SurfaceRef& surface, int dx, int dy) + : m_display(display) + , m_surface(surface) , m_dx(dx) , m_dy(dy) { @@ -45,8 +46,8 @@ Graphics::~Graphics() { // If we were drawing in the screen surface, we mark these regions // as dirty for the final flip. - if (m_surface == os::instance()->defaultWindow()->surface()) - Manager::getDefault()->dirtyRect(m_dirtyBounds); + if (m_display) + m_display->dirtyRect(m_dirtyBounds); } int Graphics::width() const @@ -611,8 +612,8 @@ void Graphics::dirty(const gfx::Rect& bounds) ////////////////////////////////////////////////////////////////////// // ScreenGraphics -ScreenGraphics::ScreenGraphics() - : Graphics(AddRef(os::instance()->defaultWindow()->surface()), 0, 0) +ScreenGraphics::ScreenGraphics(Display* display) + : Graphics(display, AddRef(display->surface()), 0, 0) { setFont(AddRef(get_theme()->getDefaultFont())); } diff --git a/src/ui/graphics.h b/src/ui/graphics.h index d0db15fb9..2a5589692 100644 --- a/src/ui/graphics.h +++ b/src/ui/graphics.h @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2019-2020 Igara Studio S.A. +// Copyright (C) 2019-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -33,7 +33,9 @@ namespace os { } namespace ui { - using os::Paint; + using os::Paint; // Define ui::Paint = os::Paint + + class Display; // Class to render a widget in the screen. class Graphics { @@ -44,7 +46,7 @@ namespace ui { Checked, }; - Graphics(const os::SurfaceRef& surface, int dx, int dy); + Graphics(Display* display, const os::SurfaceRef& surface, int dx, int dy); ~Graphics(); int width() const; @@ -127,6 +129,7 @@ namespace ui { gfx::Size doUIStringAlgorithm(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, int align, bool draw); void dirty(const gfx::Rect& bounds); + Display* m_display; os::SurfaceRef m_surface; int m_dx; int m_dy; @@ -138,7 +141,7 @@ namespace ui { // Class to draw directly in the screen. class ScreenGraphics : public Graphics { public: - ScreenGraphics(); + ScreenGraphics(Display* display); virtual ~ScreenGraphics(); }; diff --git a/src/ui/int_entry.cpp b/src/ui/int_entry.cpp index 5e88a0dc0..dba24c90a 100644 --- a/src/ui/int_entry.cpp +++ b/src/ui/int_entry.cpp @@ -183,10 +183,11 @@ void IntEntry::openPopup() Rect rc = bounds(); gfx::Size sz = m_popupWindow->sizeHint(); + gfx::Size displaySize = display()->size(); rc.w = 128*guiscale(); - if (rc.x+rc.w > ui::display_w()) + if (rc.x+rc.w > displaySize.w) rc.x = rc.x-rc.w+bounds().w; - if (rc.y+rc.h+sz.h < ui::display_h()) + if (rc.y+rc.h+sz.h < displaySize.h) rc.y += rc.h; else rc.y -= sz.h; diff --git a/src/ui/manager.cpp b/src/ui/manager.cpp index be97a457f..2059ab1a6 100644 --- a/src/ui/manager.cpp +++ b/src/ui/manager.cpp @@ -76,7 +76,6 @@ typedef std::list Messages; typedef std::list Filters; Manager* Manager::m_defaultManager = nullptr; -gfx::Region Manager::m_dirtyRegion; #ifdef DEBUG_UI_THREADS static base::thread::native_id_type manager_thread = 0; @@ -160,13 +159,15 @@ bool Manager::widgetAssociatedToManager(Widget* widget) widget) != mouse_widgets_list.end()); } -Manager::Manager() +Manager::Manager(const os::WindowRef& nativeWindow) : Widget(kManagerWidget) - , m_window(nullptr) - , m_eventQueue(nullptr) + , m_display(nativeWindow, this) + , m_eventQueue(os::instance()->eventQueue()) , m_lockedWindow(nullptr) , m_mouseButton(kButtonNone) { + nativeWindow->setUserData(&m_display); + #ifdef DEBUG_UI_THREADS ASSERT(!manager_thread); manager_thread = base::this_thread::native_id(); @@ -183,14 +184,15 @@ Manager::Manager() capture_widget = nullptr; } - setBounds(gfx::Rect(0, 0, ui::display_w(), ui::display_h())); + setBounds(m_display.bounds()); setVisible(true); - m_dirtyRegion = bounds(); - // Default manager is the first one (and is always visible). if (!m_defaultManager) m_defaultManager = this; + + // TODO check if this is needed + onNewDisplayConfiguration(&m_display); } Manager::~Manager() @@ -226,16 +228,12 @@ Manager::~Manager() } } -void Manager::setNativeWindow(os::Window* window) +Display* Manager::getDisplayFromNativeWindow(os::Window* window) const { - base::ScopedValue lock( - auto_window_adjustment, false, - auto_window_adjustment); - - m_window = window; - m_eventQueue = os::instance()->eventQueue(); - - onNewDisplayConfiguration(); + if (window) + return window->userData(); + else + return nullptr; } void Manager::run() @@ -253,11 +251,8 @@ void Manager::run() loop.pumpMessages(); } -void Manager::flipDisplay() +void Manager::flipAllDisplays() { - if (!m_window) - return; - OverlayManager* overlays = OverlayManager::instance(); update_cursor_overlay(); @@ -265,15 +260,15 @@ void Manager::flipDisplay() // Draw overlays. overlays->drawOverlays(); - // Invalidate the dirty region in the laf::os::Display (the real OS window). - m_dirtyRegion.createIntersection( - m_dirtyRegion, - gfx::Region(gfx::Rect(0, 0, ui::display_w(), ui::display_h()))); + m_display.flipDisplay(); +} - if (!m_dirtyRegion.isEmpty()) { - m_window->invalidateRegion(m_dirtyRegion); - m_dirtyRegion.clear(); - } +void Manager::updateAllDisplaysWithNewScale(int scale) +{ + os::Window* nativeWindow = m_display.nativeWindow(); + nativeWindow->setScale(scale); + + onNewDisplayConfiguration(&m_display); } bool Manager::generateMessages() @@ -308,7 +303,8 @@ bool Manager::generateMessages() return false; } -void Manager::generateSetCursorMessage(const gfx::Point& mousePos, +void Manager::generateSetCursorMessage(Display* display, + const gfx::Point& mousePos, KeyModifiers modifiers, PointerType pointerType) { @@ -319,7 +315,8 @@ void Manager::generateSetCursorMessage(const gfx::Point& mousePos, if (dst) enqueueMessage( newMouseMessage( - kSetCursorMessage, dst, + kSetCursorMessage, + display, dst, mousePos, pointerType, m_mouseButton, @@ -375,10 +372,15 @@ void Manager::generateMessagesFromOSEvents() if (osEvent.type() == os::Event::None) break; + Display* display = getDisplayFromNativeWindow(osEvent.window().get()); + if (!display) + display = this->display(); + switch (osEvent.type()) { case os::Event::CloseApp: { Message* msg = new Message(kCloseDisplayMessage); + msg->setDisplay(display); msg->setRecipient(this); msg->setPropagateToChildren(true); enqueueMessage(msg); @@ -387,6 +389,7 @@ void Manager::generateMessagesFromOSEvents() case os::Event::CloseWindow: { Message* msg = new Message(kCloseDisplayMessage); + msg->setDisplay(display); msg->setRecipient(this); msg->setPropagateToChildren(true); enqueueMessage(msg); @@ -395,6 +398,7 @@ void Manager::generateMessagesFromOSEvents() case os::Event::ResizeWindow: { Message* msg = new Message(kResizeDisplayMessage); + msg->setDisplay(display); msg->setRecipient(this); msg->setPropagateToChildren(true); enqueueMessage(msg); @@ -403,6 +407,7 @@ void Manager::generateMessagesFromOSEvents() case os::Event::DropFiles: { Message* msg = new DropFilesMessage(osEvent.files()); + msg->setDisplay(display); msg->setRecipient(this); enqueueMessage(msg); break; @@ -419,6 +424,8 @@ void Manager::generateMessagesFromOSEvents() osEvent.unicodeChar(), osEvent.repeat()); + msg->setDisplay(display); + if (osEvent.isDeadKey()) static_cast(msg)->setDeadKey(true); @@ -449,6 +456,7 @@ void Manager::generateMessagesFromOSEvents() case os::Event::MouseMove: { _internal_set_mouse_position(osEvent.position()); handleMouseMove( + display, osEvent.position(), osEvent.modifiers(), osEvent.pointerType(), @@ -459,6 +467,7 @@ void Manager::generateMessagesFromOSEvents() case os::Event::MouseDown: { handleMouseDown( + display, osEvent.position(), m_mouseButton = mouse_button_from_os_to_ui(osEvent), osEvent.modifiers(), @@ -468,6 +477,7 @@ void Manager::generateMessagesFromOSEvents() case os::Event::MouseUp: { handleMouseUp( + display, osEvent.position(), mouse_button_from_os_to_ui(osEvent), osEvent.modifiers(), @@ -478,6 +488,7 @@ void Manager::generateMessagesFromOSEvents() case os::Event::MouseDoubleClick: { handleMouseDoubleClick( + display, osEvent.position(), m_mouseButton = mouse_button_from_os_to_ui(osEvent), osEvent.modifiers(), @@ -486,7 +497,8 @@ void Manager::generateMessagesFromOSEvents() } case os::Event::MouseWheel: { - handleMouseWheel(osEvent.position(), + handleMouseWheel(display, + osEvent.position(), osEvent.modifiers(), osEvent.pointerType(), osEvent.wheelDelta(), @@ -497,7 +509,8 @@ void Manager::generateMessagesFromOSEvents() case os::Event::TouchMagnify: { _internal_set_mouse_position(osEvent.position()); - handleTouchMagnify(osEvent.position(), + handleTouchMagnify(display, + osEvent.position(), osEvent.modifiers(), osEvent.magnification()); break; @@ -515,13 +528,20 @@ void Manager::generateMessagesFromOSEvents() // Generate just one kSetCursorMessage for the last mouse position if (lastMouseMoveEvent.type() != os::Event::None) { osEvent = lastMouseMoveEvent; - generateSetCursorMessage(osEvent.position(), + + Display* display = getDisplayFromNativeWindow(osEvent.window().get()); + if (!display) + display = this->display(); + + generateSetCursorMessage(display, + osEvent.position(), osEvent.modifiers(), osEvent.pointerType()); } } -void Manager::handleMouseMove(const gfx::Point& mousePos, +void Manager::handleMouseMove(Display* display, + const gfx::Point& mousePos, const KeyModifiers modifiers, const PointerType pointerType, const float pressure) @@ -532,7 +552,8 @@ void Manager::handleMouseMove(const gfx::Point& mousePos, Widget* dst = (capture_widget ? capture_widget: mouse_widget); enqueueMessage( newMouseMessage( - kMouseMoveMessage, dst, + kMouseMoveMessage, + display, dst, mousePos, pointerType, m_mouseButton, @@ -542,7 +563,8 @@ void Manager::handleMouseMove(const gfx::Point& mousePos, pressure)); } -void Manager::handleMouseDown(const gfx::Point& mousePos, +void Manager::handleMouseDown(Display* display, + const gfx::Point& mousePos, MouseButton mouseButton, KeyModifiers modifiers, PointerType pointerType) @@ -552,6 +574,7 @@ void Manager::handleMouseDown(const gfx::Point& mousePos, enqueueMessage( newMouseMessage( kMouseDownMessage, + display, (capture_widget ? capture_widget: mouse_widget), mousePos, pointerType, @@ -559,7 +582,8 @@ void Manager::handleMouseDown(const gfx::Point& mousePos, modifiers)); } -void Manager::handleMouseUp(const gfx::Point& mousePos, +void Manager::handleMouseUp(Display* display, + const gfx::Point& mousePos, MouseButton mouseButton, KeyModifiers modifiers, PointerType pointerType) @@ -567,6 +591,7 @@ void Manager::handleMouseUp(const gfx::Point& mousePos, enqueueMessage( newMouseMessage( kMouseUpMessage, + display, (capture_widget ? capture_widget: mouse_widget), mousePos, pointerType, @@ -574,7 +599,8 @@ void Manager::handleMouseUp(const gfx::Point& mousePos, modifiers)); } -void Manager::handleMouseDoubleClick(const gfx::Point& mousePos, +void Manager::handleMouseDoubleClick(Display* display, + const gfx::Point& mousePos, MouseButton mouseButton, KeyModifiers modifiers, PointerType pointerType) @@ -584,12 +610,13 @@ void Manager::handleMouseDoubleClick(const gfx::Point& mousePos, enqueueMessage( newMouseMessage( kDoubleClickMessage, - dst, mousePos, pointerType, + display, dst, mousePos, pointerType, mouseButton, modifiers)); } } -void Manager::handleMouseWheel(const gfx::Point& mousePos, +void Manager::handleMouseWheel(Display* display, + const gfx::Point& mousePos, KeyModifiers modifiers, PointerType pointerType, const gfx::Point& wheelDelta, @@ -597,12 +624,14 @@ void Manager::handleMouseWheel(const gfx::Point& mousePos, { enqueueMessage(newMouseMessage( kMouseWheelMessage, + display, (capture_widget ? capture_widget: mouse_widget), mousePos, pointerType, m_mouseButton, modifiers, wheelDelta, preciseWheel)); } -void Manager::handleTouchMagnify(const gfx::Point& mousePos, +void Manager::handleTouchMagnify(Display* display, + const gfx::Point& mousePos, const KeyModifiers modifiers, const double magnification) { @@ -614,6 +643,7 @@ void Manager::handleTouchMagnify(const gfx::Point& mousePos, mousePos, magnification); + msg->setDisplay(display); msg->setRecipient(widget); enqueueMessage(msg); @@ -622,6 +652,8 @@ void Manager::handleTouchMagnify(const gfx::Point& mousePos, // Handles Z order: Send the window to top (only when you click in a // window that aren't the desktop). +// +// TODO code similar to Display::handleWindowZOrder() void Manager::handleWindowZOrder() { if (capture_widget || !mouse_widget) @@ -642,6 +674,8 @@ void Manager::handleWindowZOrder() (window != win_manager->getTopWindow())) { base::ScopedValue scoped(m_lockedWindow, window, nullptr); + window->display()->handleWindowZOrder(window); + // Put it in the top of the list win_manager->removeChild(window); @@ -718,8 +752,8 @@ void Manager::dispatchMessages() flushRedraw(); pumpQueue(); - // Flip the back-buffer to the real display. - flipDisplay(); + // Flip back-buffers to real displays. + flipAllDisplays(); } } } @@ -854,8 +888,11 @@ void Manager::setMouse(Widget* widget) // Put the mouse mouse_widget = widget; if (widget) { + Display* display = mouse_widget->display(); + auto msg = newMouseMessage( - kMouseEnterMessage, nullptr, + kMouseEnterMessage, + display, nullptr, get_mouse_position(), PointerType::Unknown, m_mouseButton, @@ -865,7 +902,8 @@ void Manager::setMouse(Widget* widget) msg->setPropagateToParent(true); msg->setCommonAncestor(commonAncestor); enqueueMessage(msg); - generateSetCursorMessage(get_mouse_position(), + generateSetCursorMessage(display, + get_mouse_position(), kKeyUninitializedModifier, PointerType::Unknown); @@ -888,7 +926,10 @@ void Manager::setCapture(Widget* widget) widget->enableFlags(HAS_CAPTURE); capture_widget = widget; - m_window->captureMouse(); + Display* display = (widget ? widget->display(): &m_display); + ASSERT(display && display->nativeWindow()); + if (display && display->nativeWindow()) + display->nativeWindow()->captureMouse(); } // Sets the focus to the "magnetic" widget inside the window @@ -925,10 +966,14 @@ void Manager::freeMouse() void Manager::freeCapture() { if (capture_widget) { + Display* display = capture_widget->display(); + capture_widget->disableFlags(HAS_CAPTURE); capture_widget = nullptr; - m_window->releaseMouse(); + ASSERT(display && display->nativeWindow()); + if (display && display->nativeWindow()) + display->nativeWindow()->releaseMouse(); } } @@ -1073,11 +1118,6 @@ bool Manager::isFocusMovementMessage(Message* msg) return false; } -void Manager::dirtyRect(const gfx::Rect& bounds) -{ - m_dirtyRegion.createUnion(m_dirtyRegion, gfx::Region(bounds)); -} - // Configures the window for begin the loop void Manager::_openWindow(Window* window) { @@ -1100,6 +1140,9 @@ void Manager::_openWindow(Window* window) // Relayout window->layout(); + // Same display as the manager. + window->setDisplay(this->display()); + // Dirty the entire window and show it window->setVisible(true); window->invalidate(); @@ -1121,6 +1164,8 @@ void Manager::_openWindow(Window* window) void Manager::_closeWindow(Window* window, bool redraw_background) { + window->setDisplay(nullptr); + if (!hasChild(window)) return; @@ -1189,7 +1234,7 @@ bool Manager::onProcessMessage(Message* msg) return true; case kResizeDisplayMessage: - onNewDisplayConfiguration(); + onNewDisplayConfiguration(msg->display()); break; case kKeyDownMessage: @@ -1236,7 +1281,7 @@ void Manager::onResize(ResizeEvent& ev) setBoundsQuietly(new_pos); // The whole manager area is invalid now. - m_invalidRegion = gfx::Region(new_pos); + m_display.setInvalidRegion(gfx::Region(new_pos)); const int dx = new_pos.x - old_pos.x; const int dy = new_pos.y - old_pos.y; @@ -1306,11 +1351,12 @@ void Manager::onInitTheme(InitThemeEvent& ev) window->layout(); } else { + gfx::Size displaySize = m_display.size(); gfx::Rect bounds = window->bounds(); bounds *= newUIScale; bounds /= oldUIScale; - bounds.x = base::clamp(bounds.x, 0, m_window->width() - bounds.w); - bounds.y = base::clamp(bounds.y, 0, m_window->height() - bounds.h); + bounds.x = base::clamp(bounds.x, 0, displaySize.w - bounds.w); + bounds.y = base::clamp(bounds.y, 0, displaySize.h - bounds.h); window->setBounds(bounds); } } @@ -1322,19 +1368,19 @@ LayoutIO* Manager::onGetLayoutIO() return nullptr; } -void Manager::onNewDisplayConfiguration() +void Manager::onNewDisplayConfiguration(Display* display) { - if (m_window) { - int w = m_window->width() / m_window->scale(); - int h = m_window->height() / m_window->scale(); - if ((bounds().w != w || - bounds().h != h)) { - setBounds(gfx::Rect(0, 0, w, h)); - } + ASSERT(display); + Widget* container = display->containedWidget(); + + gfx::Size displaySize = display->size(); + if ((bounds().w != displaySize.w || + bounds().h != displaySize.h)) { + container->setBounds(gfx::Rect(displaySize)); } - _internal_set_mouse_window(m_window); - invalidate(); + _internal_set_mouse_display(display); + container->invalidate(); flushRedraw(); } @@ -1497,10 +1543,11 @@ bool Manager::sendMessageToWidget(Message* msg, Widget* widget) PaintMessage* paintMsg = static_cast(msg); + // TODO use paintMsg->display() here // Restore overlays in the region that we're going to paint. OverlayManager::instance()->restoreOverlappedAreas(paintMsg->rect()); - os::Surface* surface = m_window->surface(); + os::Surface* surface = paintMsg->display()->surface(); surface->saveClip(); if (surface->clipRect(paintMsg->rect())) { @@ -1520,8 +1567,7 @@ bool Manager::sendMessageToWidget(Message* msg, Widget* widget) } if (m_window) { - m_window->invalidateRegion( - gfx::Region(gfx::Rect(0, 0, display_w(), display_h()))); + m_window->invalidateRegion(gfx::Region(m_window->bounds())); // TODO m_window->update() ?? } @@ -1539,7 +1585,7 @@ bool Manager::sendMessageToWidget(Message* msg, Widget* widget) // As this kPaintMessage's rectangle was updated, we can // remove it from "m_invalidRegion". - m_invalidRegion -= gfx::Region(paintMsg->rect()); + paintMsg->display()->subtractInvalidRegion(gfx::Region(paintMsg->rect())); } else { // Call the message handler @@ -1690,6 +1736,7 @@ Widget* Manager::findMagneticWidget(Widget* widget) // static Message* Manager::newMouseMessage( MessageType type, + Display* display, Widget* widget, const gfx::Point& mousePos, PointerType pointerType, @@ -1716,6 +1763,9 @@ Message* Manager::newMouseMessage( type, pointerType, button, modifiers, mousePos, wheelDelta, preciseWheel, pressure); + if (display) + msg->setDisplay(display); + if (widget) msg->setRecipient(widget); diff --git a/src/ui/manager.h b/src/ui/manager.h index 8e8ecf520..9a5fea4be 100644 --- a/src/ui/manager.h +++ b/src/ui/manager.h @@ -10,6 +10,7 @@ #pragma once #include "gfx/region.h" +#include "ui/display.h" #include "ui/keys.h" #include "ui/message_type.h" #include "ui/mouse_button.h" @@ -32,17 +33,19 @@ namespace ui { static Manager* getDefault() { return m_defaultManager; } static bool widgetAssociatedToManager(Widget* widget); - Manager(); + Manager(const os::WindowRef& nativeWindow); ~Manager(); - os::Window* nativeWindow() { return m_window; } - void setNativeWindow(os::Window* window); + Display* display() { return &m_display; } + Display* getDisplayFromNativeWindow(os::Window* window) const; // Executes the main message loop. void run(); - // Refreshes the real display with the UI content. - void flipDisplay(); + // Refreshes all real displays with the UI content. + void flipAllDisplays(); + + void updateAllDisplaysWithNewScale(int scale); // Adds the given "msg" message to the queue of messages to be // dispached. "msg" cannot be used after this function, it'll be @@ -86,21 +89,6 @@ namespace ui { bool isFocusMovementMessage(Message* msg); bool processFocusMovementMessage(Message* msg); - // Returns the invalid region in the screen to being updated with - // PaintMessages. This region is cleared when each widget receives - // a paint message. - const gfx::Region& getInvalidRegion() const { - return m_invalidRegion; - } - - void addInvalidRegion(const gfx::Region& b) { - m_invalidRegion |= b; - } - - // Mark the given rectangle as a area to be flipped to the real - // screen - void dirtyRect(const gfx::Rect& bounds); - void _openWindow(Window* window); void _closeWindow(Window* window, bool redraw_background); @@ -112,35 +100,43 @@ namespace ui { void onBroadcastMouseMessage(WidgetsList& targets) override; void onInitTheme(InitThemeEvent& ev) override; virtual LayoutIO* onGetLayoutIO(); - virtual void onNewDisplayConfiguration(); + virtual void onNewDisplayConfiguration(Display* display); private: - void generateSetCursorMessage(const gfx::Point& mousePos, + void generateSetCursorMessage(Display* display, + const gfx::Point& mousePos, KeyModifiers modifiers, PointerType pointerType); void generateMessagesFromOSEvents(); - void handleMouseMove(const gfx::Point& mousePos, + + void handleMouseMove(Display* display, + const gfx::Point& mousePos, const KeyModifiers modifiers, const PointerType pointerType, const float pressure); - void handleMouseDown(const gfx::Point& mousePos, + void handleMouseDown(Display* display, + const gfx::Point& mousePos, MouseButton mouseButton, KeyModifiers modifiers, PointerType pointerType); - void handleMouseUp(const gfx::Point& mousePos, + void handleMouseUp(Display* display, + const gfx::Point& mousePos, MouseButton mouseButton, KeyModifiers modifiers, PointerType pointerType); - void handleMouseDoubleClick(const gfx::Point& mousePos, + void handleMouseDoubleClick(Display* display, + const gfx::Point& mousePos, MouseButton mouseButton, KeyModifiers modifiers, PointerType pointerType); - void handleMouseWheel(const gfx::Point& mousePos, + void handleMouseWheel(Display* display, + const gfx::Point& mousePos, KeyModifiers modifiers, PointerType pointerType, const gfx::Point& wheelDelta, bool preciseWheel); - void handleTouchMagnify(const gfx::Point& mousePos, + void handleTouchMagnify(Display* display, + const gfx::Point& mousePos, const KeyModifiers modifiers, const double magnification); void handleWindowZOrder(); @@ -154,7 +150,9 @@ namespace ui { static Widget* findMagneticWidget(Widget* widget); static Message* newMouseMessage( MessageType type, - Widget* widget, const gfx::Point& mousePos, + Display* display, + Widget* widget, + const gfx::Point& mousePos, PointerType pointerType, MouseButton button, KeyModifiers modifiers, @@ -164,12 +162,10 @@ namespace ui { void broadcastKeyMsg(Message* msg); static Manager* m_defaultManager; - static gfx::Region m_dirtyRegion; WidgetsList m_garbage; - os::Window* m_window; + Display m_display; os::EventQueue* m_eventQueue; - gfx::Region m_invalidRegion; // Invalid region (we didn't receive paint messages yet for this). // This member is used to make freeWidget() a no-op when we // restack a window if the user clicks on it. diff --git a/src/ui/menu.cpp b/src/ui/menu.cpp index d533a0f7e..7a3b4338e 100644 --- a/src/ui/menu.cpp +++ b/src/ui/menu.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -14,6 +14,7 @@ #include "base/clamp.h" #include "gfx/size.h" #include "os/font.h" +#include "ui/display.h" #include "ui/intern.h" #include "ui/ui.h" @@ -102,14 +103,15 @@ static MenuItem* find_previtem(Menu* menu, MenuItem* menuitem); static void add_scrollbars_if_needed(Window* window) { const gfx::Rect rc0 = window->bounds(); + gfx::Size displaySize = window->display()->size(); gfx::Rect rc = rc0; if (rc.x < 0) { rc.w += rc.x; rc.x = 0; } - if (rc.x2() > ui::display_w()) { - rc.w = ui::display_w() - rc.x; + if (rc.x2() > displaySize.w) { + rc.w = displaySize.w - rc.x; } bool vscrollbarsAdded = false; @@ -118,8 +120,8 @@ static void add_scrollbars_if_needed(Window* window) rc.y = 0; vscrollbarsAdded = true; } - if (rc.y2() > ui::display_h()) { - rc.h = ui::display_h() - rc.y; + if (rc.y2() > displaySize.h) { + rc.h = displaySize.h - rc.y; vscrollbarsAdded = true; } @@ -133,11 +135,11 @@ static void add_scrollbars_if_needed(Window* window) if (vscrollbarsAdded) { rc.w += 2*view->verticalBar()->getBarWidth(); - if (rc.x2() > ui::display_w()) { - rc.x = ui::display_w() - rc.w; + if (rc.x2() > displaySize.w) { + rc.x = displaySize.w - rc.w; if (rc.x < 0) { rc.x = 0; - rc.w = ui::display_w(); + rc.w = displaySize.w; } } } @@ -311,6 +313,7 @@ void Menu::showPopup(const gfx::Point& pos) MenuBaseData* base = menubox->createBase(); base->was_clicked = true; window->setMoveable(false); // Can't move the window + window->setSizeable(false); // Can't resize the window // Set children menubox->setMenu(this); @@ -320,9 +323,10 @@ void Menu::showPopup(const gfx::Point& pos) window->remapWindow(); // Menubox position + gfx::Size displaySize = display()->size(); window->positionWindow( - base::clamp(pos.x, 0, ui::display_w() - window->bounds().w), - base::clamp(pos.y, 0, ui::display_h() - window->bounds().h)); + base::clamp(pos.x, 0, displaySize.w - window->bounds().w), + base::clamp(pos.y, 0, displaySize.h - window->bounds().h)); add_scrollbars_if_needed(window.get()); @@ -821,9 +825,10 @@ bool MenuItem::onProcessMessage(Message* msg) // Menubox position Rect pos = window->bounds(); + Size displaySize = display()->size(); if (inBar()) { - pos.x = base::clamp(bounds().x, 0, ui::display_w()-pos.w); + pos.x = base::clamp(bounds().x, 0, displaySize.w-pos.w); pos.y = std::max(0, bounds().y2()); } else { @@ -832,9 +837,9 @@ bool MenuItem::onProcessMessage(Message* msg) int x, y = bounds().y-3*guiscale(); Rect r1(0, 0, pos.w, pos.h), r2(0, 0, pos.w, pos.h); - r1.x = x_left = base::clamp(x_left, 0, ui::display_w()-pos.w); - r2.x = x_right = base::clamp(x_right, 0, ui::display_w()-pos.w); - r1.y = r2.y = y = base::clamp(y, 0, ui::display_h()-pos.h); + r1.x = x_left = base::clamp(x_left, 0, displaySize.w-pos.w); + r2.x = x_right = base::clamp(x_right, 0, displaySize.w-pos.w); + r1.y = r2.y = y = base::clamp(y, 0, displaySize.h-pos.h); // Calculate both intersections gfx::Rect s1 = r1.createIntersection(old_pos); @@ -1408,6 +1413,7 @@ MenuBoxWindow::MenuBoxWindow(MenuBox* menubox) : Window(WithoutTitleBar, "") { setMoveable(false); // Can't move the window + setSizeable(false); // Can't resize the window addChild(menubox); remapWindow(); } diff --git a/src/ui/message.cpp b/src/ui/message.cpp index 504e21f27..71f326dc6 100644 --- a/src/ui/message.cpp +++ b/src/ui/message.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -13,7 +13,6 @@ #include "base/memory.h" #include "os/system.h" -#include "ui/manager.h" #include "ui/widget.h" #include @@ -23,6 +22,7 @@ namespace ui { Message::Message(MessageType type, KeyModifiers modifiers) : m_type(type) , m_flags(0) + , m_display(nullptr) , m_recipient(nullptr) , m_commonAncestor(nullptr) { @@ -36,6 +36,11 @@ Message::~Message() { } +void Message::setDisplay(Display* display) +{ + m_display = display; +} + void Message::setRecipient(Widget* widget) { ASSERT(m_recipient == nullptr); diff --git a/src/ui/message.h b/src/ui/message.h index b8787360d..3c01a66df 100644 --- a/src/ui/message.h +++ b/src/ui/message.h @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -20,6 +20,7 @@ namespace ui { + class Display; class Timer; class Widget; @@ -35,6 +36,7 @@ namespace ui { virtual ~Message(); MessageType type() const { return m_type; } + Display* display() const { return m_display; } Widget* recipient() const { return m_recipient; } bool fromFilter() const { return hasFlag(FromFilter); } void setFromFilter(const bool state) { setFlag(FromFilter, state); } @@ -50,6 +52,7 @@ namespace ui { bool onlyCmdPressed() const { return m_modifiers == kKeyCmdModifier; } bool onlyWinPressed() const { return m_modifiers == kKeyWinModifier; } + void setDisplay(Display* display); void setRecipient(Widget* widget); void removeRecipient(Widget* widget); @@ -72,6 +75,7 @@ namespace ui { MessageType m_type; // Type of message int m_flags; // Special flags for this message + Display* m_display; Widget* m_recipient; // Recipient of this message Widget* m_commonAncestor; // Common ancestor between the Leave <-> Enter messages KeyModifiers m_modifiers; // Key modifiers pressed when message was created @@ -101,7 +105,9 @@ namespace ui { class PaintMessage : public Message { public: PaintMessage(int count, const gfx::Rect& rect) - : Message(kPaintMessage), m_count(count), m_rect(rect) { + : Message(kPaintMessage) + , m_count(count) + , m_rect(rect) { } int count() const { return m_count; } diff --git a/src/ui/move_region.cpp b/src/ui/move_region.cpp index bd5b65a0e..8afefcb0d 100644 --- a/src/ui/move_region.cpp +++ b/src/ui/move_region.cpp @@ -22,9 +22,13 @@ namespace ui { using namespace gfx; -void move_region(Manager* manager, const Region& region, int dx, int dy) +void move_region(Display* display, const Region& region, int dx, int dy) { - os::Window* window = manager->nativeWindow(); + ASSERT(display); + if (!display) + return; + + os::Window* window = display->nativeWindow(); ASSERT(window); if (!window) return; @@ -43,7 +47,7 @@ void move_region(Manager* manager, const Region& region, int dx, int dy) surface->scrollTo(rc, dx, dy); rc.offset(dx, dy); - manager->dirtyRect(rc); + display->dirtyRect(rc); } // As rectangles in the region internals are separated by bands // through the y-axis, we can sort the rectangles by y-axis and then @@ -87,7 +91,7 @@ void move_region(Manager* manager, const Region& region, int dx, int dy) surface->scrollTo(rc, dx, dy); rc.offset(dx, dy); - manager->dirtyRect(rc); + display->dirtyRect(rc); } } diff --git a/src/ui/move_region.h b/src/ui/move_region.h index e945fc231..74b3b5d7f 100644 --- a/src/ui/move_region.h +++ b/src/ui/move_region.h @@ -1,4 +1,5 @@ // Aseprite UI Library +// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2001-2015 David Capello // // This file is released under the terms of the MIT license. @@ -12,9 +13,9 @@ namespace ui { - class Manager; + class Display; - void move_region(Manager* manager, const gfx::Region& region, int dx, int dy); + void move_region(Display* display, const gfx::Region& region, int dx, int dy); } // namespace ui diff --git a/src/ui/overlay.cpp b/src/ui/overlay.cpp index 18be98fb4..d28266524 100644 --- a/src/ui/overlay.cpp +++ b/src/ui/overlay.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. @@ -13,14 +13,16 @@ #include "os/surface.h" #include "os/system.h" -#include "ui/manager.h" +#include "ui/display.h" namespace ui { -Overlay::Overlay(const os::SurfaceRef& overlaySurface, +Overlay::Overlay(Display* display, + const os::SurfaceRef& overlaySurface, const gfx::Point& pos, ZOrder zorder) - : m_surface(overlaySurface) + : m_display(display) + , m_surface(overlaySurface) , m_overlap(nullptr) , m_captured(nullptr) , m_pos(pos) @@ -33,11 +35,8 @@ Overlay::~Overlay() ASSERT(!m_captured); if (m_surface) { - Manager* manager = Manager::getDefault(); - if (manager) - manager->invalidateRect(gfx::Rect(m_pos.x, m_pos.y, - m_surface->width(), - m_surface->height())); + if (m_display) + m_display->invalidateRect(bounds()); m_surface.reset(); } @@ -69,7 +68,7 @@ void Overlay::drawOverlay() os::SurfaceLock lock(m_surface.get()); m_captured->drawRgbaSurface(m_surface.get(), m_pos.x, m_pos.y); - Manager::getDefault()->dirtyRect( + m_display->dirtyRect( gfx::Rect(m_pos.x, m_pos.y, m_surface->width(), m_surface->height())); @@ -83,24 +82,27 @@ void Overlay::moveOverlay(const gfx::Point& newPos) m_pos = newPos; } -void Overlay::captureOverlappedArea(os::Surface* screen) +void Overlay::captureOverlappedArea() { if (!m_surface || m_captured) return; + os::Surface* displaySurface = m_display->surface(); + os::SurfaceLock lockDisplaySurface(displaySurface); + if (!m_overlap) { // Use the same color space for the overlay as in the screen m_overlap = os::instance()->makeSurface(m_surface->width(), m_surface->height(), - screen->colorSpace()); + displaySurface->colorSpace()); } os::SurfaceLock lock(m_overlap.get()); - screen->blitTo(m_overlap.get(), m_pos.x, m_pos.y, 0, 0, - m_overlap->width(), m_overlap->height()); + displaySurface->blitTo(m_overlap.get(), m_pos.x, m_pos.y, 0, 0, + m_overlap->width(), m_overlap->height()); - m_captured = screen; + m_captured = displaySurface; } void Overlay::restoreOverlappedArea(const gfx::Rect& restoreBounds) @@ -118,8 +120,7 @@ void Overlay::restoreOverlappedArea(const gfx::Rect& restoreBounds) m_overlap->blitTo(m_captured, 0, 0, m_pos.x, m_pos.y, m_overlap->width(), m_overlap->height()); - Manager::getDefault()->dirtyRect(bounds()); - + m_display->dirtyRect(bounds()); m_captured = nullptr; } diff --git a/src/ui/overlay.h b/src/ui/overlay.h index 79ed040eb..057305267 100644 --- a/src/ui/overlay.h +++ b/src/ui/overlay.h @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. @@ -20,6 +20,7 @@ namespace os { } namespace ui { + class Display; class Overlay; using OverlayRef = base::Ref; @@ -31,7 +32,8 @@ namespace ui { MouseZOrder = 5000 }; - Overlay(const os::SurfaceRef& overlaySurface, + Overlay(Display* display, + const os::SurfaceRef& overlaySurface, const gfx::Point& pos, ZOrder zorder = NormalZOrder); ~Overlay(); @@ -41,7 +43,7 @@ namespace ui { const gfx::Point& position() const { return m_pos; } gfx::Rect bounds() const; - void captureOverlappedArea(os::Surface* screen); + void captureOverlappedArea(); void restoreOverlappedArea(const gfx::Rect& restoreBounds); void drawOverlay(); @@ -52,6 +54,7 @@ namespace ui { } private: + Display* m_display; os::SurfaceRef m_surface; os::SurfaceRef m_overlap; diff --git a/src/ui/overlay_manager.cpp b/src/ui/overlay_manager.cpp index 5bf0fd4bf..e2b1cf69f 100644 --- a/src/ui/overlay_manager.cpp +++ b/src/ui/overlay_manager.cpp @@ -11,8 +11,6 @@ #include "ui/overlay_manager.h" -#include "os/surface.h" -#include "os/window.h" #include "ui/manager.h" #include "ui/overlay.h" @@ -68,11 +66,6 @@ void OverlayManager::restoreOverlappedAreas(const gfx::Rect& restoreBounds) if (m_overlays.empty()) return; - // TODO can we remove this? - Manager* manager = Manager::getDefault(); - if (!manager) - return; - for (auto& overlay : *this) overlay->restoreOverlappedArea(restoreBounds); } @@ -82,15 +75,8 @@ void OverlayManager::drawOverlays() if (m_overlays.empty()) return; - Manager* manager = Manager::getDefault(); - if (!manager) - return; - - os::Surface* windowSurface = manager->nativeWindow()->surface(); - os::SurfaceLock lock(windowSurface); - for (auto& overlay : *this) - overlay->captureOverlappedArea(windowSurface); + overlay->captureOverlappedArea(); for (auto& overlay : *this) overlay->drawOverlay(); diff --git a/src/ui/slider.cpp b/src/ui/slider.cpp index 01897a0f6..190de3291 100644 --- a/src/ui/slider.cpp +++ b/src/ui/slider.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2019-2020 Igara Studio S.A. +// Copyright (C) 2019-2021 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. @@ -13,7 +13,6 @@ #include "base/clamp.h" #include "os/font.h" -#include "ui/manager.h" #include "ui/message.h" #include "ui/size_hint_event.h" #include "ui/system.h" diff --git a/src/ui/system.cpp b/src/ui/system.cpp index b80e01f85..0077a6996 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -36,17 +36,15 @@ namespace ui { base::thread::native_id_type main_gui_thread; // Current mouse cursor type. - static CursorType mouse_cursor_type = kOutsideDisplay; static const Cursor* mouse_cursor_custom = nullptr; static const Cursor* mouse_cursor = nullptr; -static os::Window* mouse_window = nullptr; +static Display* mouse_display = nullptr; static OverlayRef mouse_cursor_overlay = nullptr; static bool use_native_mouse_cursor = true; static bool support_native_custom_cursor = false; // Mouse information (button and position). - static gfx::Point m_mouse_pos; static int mouse_cursor_scale = 1; @@ -58,7 +56,9 @@ static void update_mouse_overlay(const Cursor* cursor) if (mouse_cursor && mouse_scares == 0) { if (!mouse_cursor_overlay) { + ASSERT(mouse_display); mouse_cursor_overlay = base::make_ref( + mouse_display, mouse_cursor->getSurface(), get_mouse_position(), Overlay::MouseZOrder); @@ -83,20 +83,22 @@ static bool update_custom_native_cursor(const Cursor* cursor) // Check if we can use a custom native mouse in this platform if (support_native_custom_cursor && - mouse_window) { + mouse_display) { + os::Window* nativeWindow = mouse_display->nativeWindow(); + if (cursor) { - result = mouse_window->setNativeMouseCursor( + result = nativeWindow->setNativeMouseCursor( // The surface is already scaled by guiscale() cursor->getSurface().get(), cursor->getFocus(), // We scale the cursor by the os::Display scale - mouse_window->scale() * mouse_cursor_scale); + nativeWindow->scale() * mouse_cursor_scale); } else if (mouse_cursor_type == kOutsideDisplay) { - result = mouse_window->setNativeMouseCursor(os::NativeCursor::Arrow); + result = nativeWindow->setNativeMouseCursor(os::NativeCursor::Arrow); } else { - result = mouse_window->setNativeMouseCursor(os::NativeCursor::Hidden); + result = nativeWindow->setNativeMouseCursor(os::NativeCursor::Hidden); } } @@ -146,8 +148,8 @@ static void update_mouse_cursor() } // Set native cursor - if (mouse_window) { - bool ok = mouse_window->setNativeMouseCursor(nativeCursor); + if (mouse_display) { + bool ok = mouse_display->nativeWindow()->setNativeMouseCursor(nativeCursor); // It looks like the specific native cursor is not supported, // so we can should use the internal overlay (even when we @@ -166,7 +168,8 @@ static void update_mouse_cursor() } // Try to use a custom native cursor if it's possible - if (nativeCursor == os::NativeCursor::Hidden && + if (mouse_display && + nativeCursor == os::NativeCursor::Hidden && !update_custom_native_cursor(cursor)) { // Or an overlay as last resource update_mouse_overlay(cursor); @@ -207,7 +210,7 @@ UISystem::~UISystem() details::exitWidgets(); - _internal_set_mouse_window(nullptr); + _internal_set_mouse_display(nullptr); if (!update_custom_native_cursor(nullptr)) update_mouse_overlay(nullptr); @@ -215,29 +218,24 @@ UISystem::~UISystem() g_instance = nullptr; } -void _internal_set_mouse_window(os::Window* window) +void _internal_set_mouse_display(Display* display) { CursorType cursor = get_mouse_cursor(); set_mouse_cursor(kNoCursor); - mouse_window = window; - if (window) + mouse_display = display; + if (display) set_mouse_cursor(cursor); // Restore mouse cursor } -int display_w() +void _internal_free_mouse_display(Display* display) { - if (mouse_window) - return mouse_window->width() / mouse_window->scale(); - else - return 1; + if (mouse_display == display) + _internal_set_mouse_display(nullptr); } -int display_h() +gfx::Size get_desktop_size() { - if (mouse_window) - return mouse_window->height() / mouse_window->scale(); - else - return 1; + return Manager::getDefault()->display()->size(); } void set_clipboard_text(const std::string& text) @@ -331,8 +329,8 @@ const gfx::Point& get_mouse_position() void set_mouse_position(const gfx::Point& newPos) { - if (mouse_window) - mouse_window->setMousePosition(newPos); + if (mouse_display) + mouse_display->nativeWindow()->setMousePosition(newPos); _internal_set_mouse_position(newPos); } diff --git a/src/ui/system.h b/src/ui/system.h index 79c8842c3..cbede9855 100644 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -16,12 +16,11 @@ #include #include -namespace os { class Window; } - namespace ui { class ClipboardDelegate; class Cursor; + class Display; class Widget; class UISystem { @@ -41,8 +40,7 @@ namespace ui { ClipboardDelegate* m_clipboardDelegate; }; - int display_w(); - int display_h(); + gfx::Size get_desktop_size(); void set_clipboard_text(const std::string& text); bool get_clipboard_text(std::string& text); @@ -61,7 +59,8 @@ namespace ui { void hide_mouse_cursor(); void show_mouse_cursor(); - void _internal_set_mouse_window(os::Window* window); + void _internal_set_mouse_display(Display* display); + void _internal_free_mouse_display(Display* display); void _internal_no_mouse_position(); void _internal_set_mouse_position(const gfx::Point& newPos); diff --git a/src/ui/tooltips.cpp b/src/ui/tooltips.cpp index e108589f8..cf5815554 100644 --- a/src/ui/tooltips.cpp +++ b/src/ui/tooltips.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -122,7 +122,11 @@ void TooltipManager::onTick() if (!arrowAlign) target.setOrigin(ui::get_mouse_position()+12*guiscale()); - if (m_tipWindow->pointAt(arrowAlign, target)) { + if (m_tipWindow->pointAt(arrowAlign, + target, + m_target.widget->display())) { + // TODO create a native transparent window for the tooltip + m_tipWindow->setDisplay(m_target.widget->display()); m_tipWindow->openWindow(); } else { @@ -161,7 +165,9 @@ void TipWindow::setCloseOnKeyDown(bool state) m_closeOnKeyDown = state; } -bool TipWindow::pointAt(int arrowAlign, const gfx::Rect& target) +bool TipWindow::pointAt(int arrowAlign, + const gfx::Rect& target, + const ui::Display* display) { // TODO merge this code with the new ui::fit_bounds() algorithm @@ -212,8 +218,9 @@ bool TipWindow::pointAt(int arrowAlign, const gfx::Rect& target) break; } - x = base::clamp(x, 0, ui::display_w()-w); - y = base::clamp(y, 0, ui::display_h()-h); + auto displayBounds = display->bounds(); + x = base::clamp(x, displayBounds.x, displayBounds.x2()-w); + y = base::clamp(y, displayBounds.y, displayBounds.y2()-h); if (m_target.intersects(gfx::Rect(x, y, w, h))) { switch (trycount) { diff --git a/src/ui/tooltips.h b/src/ui/tooltips.h index da5e990f0..cb9cf69c4 100644 --- a/src/ui/tooltips.h +++ b/src/ui/tooltips.h @@ -1,4 +1,5 @@ // Aseprite UI Library +// Copyright (C) 2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -18,6 +19,7 @@ namespace ui { + class Display; class TextBox; class TipWindow; @@ -70,7 +72,9 @@ namespace ui { // Returns false there is no enough screen space to show the // window. - bool pointAt(int arrowAlign, const gfx::Rect& target); + bool pointAt(int arrowAlign, + const gfx::Rect& target, + const ui::Display* display); TextBox* textBox() const { return m_textBox; } diff --git a/src/ui/ui.h b/src/ui/ui.h index c11df9cdd..5c49d9c40 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2019-2020 Igara Studio S.A. +// Copyright (C) 2019-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -19,6 +19,7 @@ #include "ui/component.h" #include "ui/cursor.h" #include "ui/cursor_type.h" +#include "ui/display.h" #include "ui/entry.h" #include "ui/event.h" #include "ui/fit_bounds.h" diff --git a/src/ui/view.cpp b/src/ui/view.cpp index 1d53cffc3..0403e1792 100644 --- a/src/ui/view.cpp +++ b/src/ui/view.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2017 David Capello // // This file is released under the terms of the MIT license. @@ -13,8 +13,8 @@ #include "base/clamp.h" #include "gfx/size.h" +#include "ui/display.h" #include "ui/intern.h" -#include "ui/manager.h" #include "ui/message.h" #include "ui/move_region.h" #include "ui/resize_event.h" @@ -28,8 +28,8 @@ #ifdef DEBUG_SCROLL_EVENTS #include "base/thread.h" -#include "os/display.h" #include "os/surface.h" +#include "os/window.h" #endif #include @@ -289,9 +289,9 @@ void View::onSetViewScroll(const gfx::Point& pt) // Remove invalid region in the screen (areas that weren't // re-painted yet) - Manager* manager = this->manager(); - if (manager) - validRegion -= manager->getInvalidRegion(); + Display* display = this->display(); + if (display) + validRegion -= display->getInvalidRegion(); // Add extra regions that cannot be scrolled (this can be customized // by subclassing ui::View). We use two ScrollRegionEvent, this @@ -327,27 +327,25 @@ void View::onSetViewScroll(const gfx::Point& pt) invalidRegion -= movable; // Remove the moved region as invalid movable.offset(-delta); - ui::move_region(manager, movable, delta.x, delta.y); + ui::move_region(display, movable, delta.x, delta.y); } #ifdef DEBUG_SCROLL_EVENTS // Paint invalid region with red fill - { - auto display = manager->getDisplay(); - if (display) - display->invalidateRegion( - gfx::Region(gfx::Rect(0, 0, display_w(), display_h()))); + if (auto nativeWindow = display->nativeWindow()) { + nativeWindow->invalidateRegion(gfx::Region(display->bounds())); base::this_thread::sleep_for(0.002); { - os::Surface* surface = display->getSurface(); + os::Surface* surface = nativeWindow->surface(); os::SurfaceLock lock(surface); + os::Paint p; + p.style(os::Paint::Fill); + p.color(gfx::rgba(255, 0, 0)); for (const auto& rc : invalidRegion) - surface->fillRect(gfx::rgba(255, 0, 0), rc); + surface->drawRect(rc, p); } - if (display) - display->invalidateRegion( - gfx::Region(gfx::Rect(0, 0, display_w(), display_h()))); - base::this_thread::sleep_for(0.002); + nativeWindow->invalidateRegion(gfx::Region(display->bounds())); + base::this_thread::sleep_for(0.02); } #endif diff --git a/src/ui/widget.cpp b/src/ui/widget.cpp index 61d88cee7..007ad1982 100644 --- a/src/ui/widget.cpp +++ b/src/ui/widget.cpp @@ -420,6 +420,14 @@ Manager* Widget::manager() const return Manager::getDefault(); } +Display* Widget::display() const +{ + if (Window* win = this->window()) + return win->display(); + else + return manager()->display(); +} + int Widget::getChildIndex(Widget* child) { auto it = std::find(m_children.begin(), m_children.end(), child); @@ -754,36 +762,31 @@ void Widget::getRegion(gfx::Region& region) void Widget::getDrawableRegion(gfx::Region& region, DrawableRegionFlags flags) { - Widget* window, *manager, *view; - getRegion(region); // Cut the top windows areas if (flags & kCutTopWindows) { - window = this->window(); - manager = (window ? window->manager(): nullptr); + Window* window = this->window(); + Display* display = this->display(); - while (manager) { - const WidgetsList& windows_list = manager->children(); - WidgetsList::const_reverse_iterator it = - std::find(windows_list.rbegin(), windows_list.rend(), window); + const auto& uiWindows = display->getWindows(); - if (!windows_list.empty() && - window != windows_list.front() && - it != windows_list.rend()) { - // Subtract the rectangles - for (++it; it != windows_list.rend(); ++it) { - if (!(*it)->isVisible()) - continue; + // Reverse iterator + auto it = std::find(uiWindows.rbegin(), + uiWindows.rend(), window); - Region reg1; - (*it)->getRegion(reg1); - region.createSubtraction(region, reg1); - } + if (!uiWindows.empty() && + window != uiWindows.front() && + it != uiWindows.rend()) { + // Subtract the rectangles of each window + for (++it; it != uiWindows.rend(); ++it) { + if (!(*it)->isVisible()) + continue; + + Region reg1; + (*it)->getRegion(reg1); + region -= reg1; } - - window = manager->window(); - manager = (window ? window->manager(): nullptr); } } @@ -804,7 +807,7 @@ void Widget::getDrawableRegion(gfx::Region& region, DrawableRegionFlags flags) else { reg1.createIntersection(reg2, reg3); } - region.createSubtraction(region, reg1); + region -= reg1; } } } @@ -813,36 +816,35 @@ void Widget::getDrawableRegion(gfx::Region& region, DrawableRegionFlags flags) if (!hasFlags(DECORATIVE)) { Widget* p = this->parent(); while (p) { - region.createIntersection( - region, Region(p->childrenBounds())); + region &= Region(p->childrenBounds()); p = p->parent(); } } else { Widget* p = parent(); if (p) { - region.createIntersection( - region, Region(p->bounds())); + region &= Region(p->bounds()); } } // Limit to the manager area - window = this->window(); - manager = (window ? window->manager(): nullptr); + { + Window* window = this->window(); + Manager* manager = (window ? window->manager(): nullptr); + while (manager) { + View* view = View::getView(manager); - while (manager) { - view = View::getView(manager); + Rect cpos; + if (view) + cpos = static_cast(view)->viewportBounds(); + else + cpos = manager->childrenBounds(); - Rect cpos; - if (view) - cpos = static_cast(view)->viewportBounds(); - else - cpos = manager->childrenBounds(); + region &= Region(cpos); - region.createIntersection(region, Region(cpos)); - - window = manager->window(); - manager = (window ? window->manager(): nullptr); + window = manager->window(); + manager = (window ? window->manager(): nullptr); + } } } @@ -980,6 +982,7 @@ void Widget::flushRedraw() processing.push(this); } + Display* display = this->display(); Manager* manager = this->manager(); ASSERT(manager); if (!manager) @@ -1018,13 +1021,14 @@ void Widget::flushRedraw() for (c=0; csetDisplay(display); msg->setRecipient(widget); // Enqueue the draw message manager->enqueueMessage(msg); } - manager->addInvalidRegion(widget->m_updateRegion); + display->addInvalidRegion(widget->m_updateRegion); widget->m_updateRegion.clear(); } } @@ -1040,6 +1044,8 @@ void Widget::paint(Graphics* graphics, std::queue processing; processing.push(this); + Display* display = this->display(); + while (!processing.empty()) { Widget* widget = processing.front(); processing.pop(); @@ -1059,17 +1065,17 @@ void Widget::paint(Graphics* graphics, region.createIntersection(region, drawRegion); Graphics graphics2( + display, base::AddRef(graphics->getInternalSurface()), widget->bounds().x, widget->bounds().y); graphics2.setFont(AddRef(widget->font())); - for (Region::const_iterator - it = region.begin(), - end = region.end(); it != end; ++it) { - IntersectClip clip(&graphics2, Rect(*it).offset( - -widget->bounds().x, - -widget->bounds().y)); + for (const gfx::Rect& rc : region) { + IntersectClip clip(&graphics2, + Rect(rc).offset( + -widget->bounds().x, + -widget->bounds().y)); widget->paintEvent(&graphics2, isBg); } } @@ -1089,14 +1095,22 @@ bool Widget::paintEvent(Graphics* graphics, enableFlags(HIDDEN); if (parent()) { - gfx::Region rgn(parent()->bounds()); - rgn.createIntersection( - rgn, - gfx::Region( + if (parent()->display() == display()) { + gfx::Region rgn(parent()->bounds()); + rgn &= gfx::Region( graphics->getClipBounds().offset( graphics->getInternalDeltaX(), - graphics->getInternalDeltaY()))); - parent()->paint(graphics, rgn, true); + graphics->getInternalDeltaY())); + parent()->paint(graphics, rgn, true); + } + else { + // TODO clear surface with transparent color, the following + // line doesn't work because we have to specify the + // SkBlendMode::kSrc mode instead of + // SkBlendMode::kSrcOver + + //graphics->fillRect(gfx::rgba(0, 0, 0, 0), clientBounds()); + } } disableFlags(HIDDEN); @@ -1152,17 +1166,19 @@ void Widget::invalidateRegion(const Region& region) class DeleteGraphicsAndSurface { public: DeleteGraphicsAndSurface(const gfx::Rect& clip, - const os::SurfaceRef& surface) - : m_pt(clip.origin()), m_surface(surface) { + const os::SurfaceRef& surface, + os::SurfaceRef& dst) + : m_pt(clip.origin()) + , m_surface(surface) + , m_dst(dst) { } void operator()(Graphics* graphics) { { - os::Surface* dst = os::instance()->defaultWindow()->surface(); os::SurfaceLock lockSrc(m_surface.get()); - os::SurfaceLock lockDst(dst); + os::SurfaceLock lockDst(m_dst.get()); m_surface->blitTo( - dst, 0, 0, m_pt.x, m_pt.y, + m_dst.get(), 0, 0, m_pt.x, m_pt.y, m_surface->width(), m_surface->height()); } m_surface.reset(); @@ -1172,25 +1188,27 @@ public: private: gfx::Point m_pt; os::SurfaceRef m_surface; + os::SurfaceRef m_dst; }; GraphicsPtr Widget::getGraphics(const gfx::Rect& clip) { GraphicsPtr graphics; - os::SurfaceRef surface; - os::Surface* defaultSurface = os::instance()->defaultWindow()->surface(); + Display* display = this->display(); + os::SurfaceRef dstSurface = AddRef(display->surface()); // In case of double-buffering, we need to create the temporary // buffer only if the default surface is the screen. - if (isDoubleBuffered() && defaultSurface->isDirectToScreen()) { - surface = os::instance()->makeSurface(clip.w, clip.h); - graphics.reset(new Graphics(surface, -clip.x, -clip.y), - DeleteGraphicsAndSurface(clip, surface)); + if (isDoubleBuffered() && dstSurface->isDirectToScreen()) { + os::SurfaceRef surface = + os::instance()->makeSurface(clip.w, clip.h); + graphics.reset(new Graphics(display, surface, -clip.x, -clip.y), + DeleteGraphicsAndSurface(clip, surface, + dstSurface)); } // In other case, we can draw directly onto the screen. else { - surface = AddRef(defaultSurface); - graphics.reset(new Graphics(surface, bounds().x, bounds().y)); + graphics.reset(new Graphics(display, dstSurface, bounds().x, bounds().y)); } graphics->setFont(AddRef(font())); diff --git a/src/ui/widget.h b/src/ui/widget.h index eadd36d42..74f496e3c 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This file is released under the terms of the MIT license. @@ -29,6 +29,7 @@ namespace ui { + class Display; class InitThemeEvent; class KeyMessage; class LoadLayoutEvent; @@ -161,6 +162,7 @@ namespace ui { Window* window() const; Widget* parent() const { return m_parent; } Manager* manager() const; + Display* display() const; // Returns a list of children. const WidgetsList& children() const { return m_children; } diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 8ef052b2d..d0c2e6435 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2018-2020 Igara Studio S.A. +// Copyright (C) 2018-2021 Igara Studio S.A. // Copyright (C) 2001-2017 David Capello // // This file is released under the terms of the MIT license. @@ -13,6 +13,7 @@ #include "gfx/size.h" #include "ui/button.h" +#include "ui/display.h" #include "ui/graphics.h" #include "ui/intern.h" #include "ui/label.h" @@ -107,6 +108,7 @@ protected: Window::Window(Type type, const std::string& text) : Widget(kWindowWidget) + , m_display(nullptr) , m_closer(nullptr) , m_titleLabel(nullptr) , m_closeButton(nullptr) @@ -133,6 +135,27 @@ Window::~Window() manager()->_closeWindow(this, isVisible()); } +Display* Window::display() const +{ + if (m_display) + return m_display; + else if (auto man = manager()) + return man->display(); + else + return nullptr; +} + +void Window::setDisplay(Display* display) +{ + if (m_display) + m_display->removeWindow(this); + + m_display = display; + + if (m_display) + m_display->addWindow(this); +} + void Window::setAutoRemap(bool state) { m_isAutoRemap = state; @@ -658,12 +681,13 @@ void Window::moveWindow(const gfx::Rect& rect, bool use_blit) moveableRegion.createIntersection(oldDrawableRegion, reg1); // Move the window's graphics - ScreenGraphics g; + Display* display = this->display(); + ScreenGraphics g(display); hide_mouse_cursor(); { IntersectClip clip(&g, man_pos); if (clip) { - ui::move_region(manager, moveableRegion, dx, dy); + ui::move_region(display, moveableRegion, dx, dy); } } show_mouse_cursor(); diff --git a/src/ui/window.h b/src/ui/window.h index 069264b9c..04b751b6e 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -1,4 +1,5 @@ // Aseprite UI Library +// Copyright (C) 2019-2021 Igara Studio S.A. // Copyright (C) 2001-2017 David Capello // // This file is released under the terms of the MIT license. @@ -27,6 +28,9 @@ namespace ui { explicit Window(Type type, const std::string& text = ""); ~Window(); + Display* display() const; + void setDisplay(Display* display); + Widget* closer() const { return m_closer; } void setAutoRemap(bool state); @@ -77,6 +81,7 @@ namespace ui { void limitSize(int* w, int* h); void moveWindow(const gfx::Rect& rect, bool use_blit); + Display* m_display; Widget* m_closer; Label* m_titleLabel; ButtonBase* m_closeButton;