Reduce immediate modeness of Window
This commit is contained in:
@@ -2022,6 +2022,8 @@ open_directory(Browser &b, const QUrl &url, bool record, float side_scroll)
|
||||
push_hist(b.hist_back_, b);
|
||||
}
|
||||
b.dir_url_ = dir;
|
||||
if (b.page_ && b.page_->host && b.page_->host->retitle)
|
||||
b.page_->host->retitle();
|
||||
b.size_cache_.clear();
|
||||
invalidate_thumbs(b);
|
||||
b.scroll_.offset = 0;
|
||||
|
||||
@@ -32,6 +32,10 @@ struct HostActions {
|
||||
std::function<std::vector<std::string>()> bookmarks;
|
||||
std::function<bool(const QUrl &url)> bookmarked;
|
||||
std::function<void(QUrl url)> toggle_bookmark;
|
||||
// The viewer has finished an open, with an image or with an error.
|
||||
std::function<void()> opened;
|
||||
// The page now shows another location, which the title has to follow.
|
||||
std::function<void()> retitle;
|
||||
};
|
||||
|
||||
// The menu that a right click on a file opens: what this application knows
|
||||
|
||||
@@ -83,6 +83,8 @@ void
|
||||
Cropper::open(const QUrl &url)
|
||||
{
|
||||
this->jpeg_url_ = url;
|
||||
if (this->page_ && this->page_->host && this->page_->host->retitle)
|
||||
this->page_->host->retitle();
|
||||
this->file_.clear();
|
||||
this->image_.reset();
|
||||
this->grid_ = {};
|
||||
|
||||
+4
-14
@@ -776,7 +776,8 @@ apply_open(Viewer &v, uint64_t gen, const Viewer::CachedOpen &cached)
|
||||
const string &message = cached.message;
|
||||
v.cms_icc_ = cached.cms_icc;
|
||||
v.opening_ = false;
|
||||
v.open_done_ = true;
|
||||
if (v.page_ && v.page_->host && v.page_->host->opened)
|
||||
v.page_->host->opened();
|
||||
v.set_message(message);
|
||||
if (!message.empty())
|
||||
qWarning("%s: %s", qUtf8Printable(v.url_.toString(QUrl::PrettyDecoded)),
|
||||
@@ -1087,7 +1088,6 @@ start_open(Viewer &v, bool invalidate)
|
||||
v.open_gen_++;
|
||||
v.scale_gen_++;
|
||||
v.opening_ = true;
|
||||
v.open_done_ = false;
|
||||
v.detached_ = false;
|
||||
v.scale_job_pending_ = false;
|
||||
v.scale_failed_ = false;
|
||||
@@ -1996,7 +1996,8 @@ Viewer::open(const QUrl &url)
|
||||
if (url == this->url_ && this->image_ && this->image_->width &&
|
||||
this->image_->height) {
|
||||
this->opening_ = false;
|
||||
this->open_done_ = true;
|
||||
if (this->page_ && this->page_->host && this->page_->host->opened)
|
||||
this->page_->host->opened();
|
||||
request_render(*this);
|
||||
return;
|
||||
}
|
||||
@@ -2027,7 +2028,6 @@ Viewer::cancel_loads()
|
||||
this->open_gen_++;
|
||||
this->scale_gen_++;
|
||||
this->opening_ = false;
|
||||
this->open_done_ = false;
|
||||
this->detached_ = true;
|
||||
this->scale_job_pending_ = false;
|
||||
this->scale_failed_ = false;
|
||||
@@ -2068,16 +2068,6 @@ Viewer::has_view() const
|
||||
return !this->opening_ && !this->url_.isEmpty();
|
||||
}
|
||||
|
||||
bool
|
||||
Viewer::consume_open_done()
|
||||
{
|
||||
if (!this->open_done_)
|
||||
return false;
|
||||
|
||||
this->open_done_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Viewer::screen_changed(
|
||||
const ScreenState &state, bool changed, bool force_reload)
|
||||
|
||||
@@ -72,7 +72,6 @@ struct Viewer : Widget {
|
||||
CieDiagram *cie_ = nullptr;
|
||||
Column *tags_ = nullptr;
|
||||
bool opening_ = false;
|
||||
bool open_done_ = false;
|
||||
bool detached_ = false;
|
||||
|
||||
// The URL identifies what is on screen; the loader below works on the
|
||||
@@ -143,7 +142,6 @@ struct Viewer : Widget {
|
||||
// Shown over the image until dismissed; an empty one takes it down.
|
||||
void set_message(const std::string &message);
|
||||
[[nodiscard]] bool has_view() const;
|
||||
[[nodiscard]] bool consume_open_done();
|
||||
void screen_changed(
|
||||
const ScreenState &state, bool changed, bool force_reload) override;
|
||||
void update(Kit &kit) override;
|
||||
|
||||
+9
-22
@@ -4319,20 +4319,7 @@ Kit::clip_pop()
|
||||
this->list_.pop_clip();
|
||||
}
|
||||
|
||||
bool
|
||||
Kit::set_dpr(float dpr)
|
||||
{
|
||||
const float next = dpr > 0.f ? dpr : 1.f;
|
||||
if (abs(next - this->dpr_) < 0.01f)
|
||||
return false;
|
||||
|
||||
this->dpr_ = next;
|
||||
if (this->inited_)
|
||||
reset_fonts();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Kit::reset_fonts()
|
||||
{
|
||||
QFont font = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
|
||||
@@ -4350,11 +4337,8 @@ Kit::reset_fonts()
|
||||
this->text_cache_.texts.clear();
|
||||
this->font_epoch_++;
|
||||
string error;
|
||||
if (!this->text_backend_.reset(font, this->dpr_, &error)) {
|
||||
if (!this->text_backend_.reset(font, this->dpr_, &error))
|
||||
qWarning("font backend reset failed: %s", error.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -5480,7 +5464,10 @@ Kit::relayout_popups()
|
||||
bool
|
||||
Kit::set_host(float width_pts, float height_pts, float dpr)
|
||||
{
|
||||
const bool changed = set_dpr(dpr);
|
||||
const float next = dpr > 0.f ? dpr : 1.f;
|
||||
const bool changed = abs(next - this->dpr_) >= 0.01f;
|
||||
if (changed)
|
||||
this->dpr_ = next;
|
||||
this->host_w_ = px(width_pts);
|
||||
this->host_h_ = px(height_pts);
|
||||
return changed;
|
||||
@@ -5492,13 +5479,12 @@ Kit::frame_ui(Page &ui)
|
||||
if (!this->inited_)
|
||||
return;
|
||||
|
||||
// An inactive page may have missed a change to the window chrome.
|
||||
if (this->root_ != &ui)
|
||||
ui.invalidate_arrange();
|
||||
this->root_ = &ui;
|
||||
ui.content->update(*this);
|
||||
if (ui.toolbar)
|
||||
ui.toolbar->sync_buttons();
|
||||
if (ui.titlebar)
|
||||
ui.titlebar->sync(*this);
|
||||
|
||||
this->text_frame_++;
|
||||
ui.arrange(*this, {0, 0, this->host_w_, this->host_h_});
|
||||
@@ -5508,6 +5494,7 @@ Kit::frame_ui(Page &ui)
|
||||
if (this->notify)
|
||||
this->notify(Change::State, nullptr);
|
||||
this->hot_ = hit(this->mouse_x_, this->mouse_y_);
|
||||
sync_cursor();
|
||||
tooltip(this->hot_);
|
||||
prepare_tooltip(*this);
|
||||
paint();
|
||||
|
||||
+2
-2
@@ -1102,9 +1102,9 @@ struct Kit {
|
||||
bool gesture(float x, float y, float scale_factor, float angle_delta);
|
||||
bool mouse_double_click(
|
||||
float x, float y, Qt::MouseButton button, unsigned mods);
|
||||
bool set_dpr(float dpr);
|
||||
// Whether the ratio changed, to which the host answers with reset_fonts().
|
||||
bool set_host(float width_pts, float height_pts, float dpr);
|
||||
bool reset_fonts();
|
||||
void reset_fonts();
|
||||
void bake_colours(const ScreenState &state);
|
||||
void draw_icon(int x, int y, int size, const char *name, Colour colour);
|
||||
// Coverage copies scalar alpha; other bitmaps are sRGB premultiplied.
|
||||
|
||||
+91
-73
@@ -158,6 +158,12 @@ Window::Window(App *app, QWindow *parent) : QWindow(parent), app_(app)
|
||||
resize(kWindowWidth, kWindowHeight);
|
||||
connect(this, &QWindow::screenChanged, this,
|
||||
[this](QScreen *new_screen) { handle_screen_change(new_screen); });
|
||||
// Not on WindowStateChange: a state we ask for is taken for granted
|
||||
// before the window system confirms it, if it ever does.
|
||||
connect(shell(), &QWindow::windowStateChanged, this, [this] {
|
||||
sync_host();
|
||||
request_render();
|
||||
});
|
||||
this->ui_wake_.setSingleShot(true);
|
||||
connect(
|
||||
&this->ui_wake_, &QTimer::timeout, this, [this] { request_render(); });
|
||||
@@ -178,10 +184,12 @@ Window::Window(App *app, QWindow *parent) : QWindow(parent), app_(app)
|
||||
};
|
||||
this->kit_.start_move = [this] {
|
||||
this->system_grab_ = shell()->startSystemMove();
|
||||
sync_host();
|
||||
request_render();
|
||||
};
|
||||
this->kit_.start_resize = [this](Qt::Edges edges) {
|
||||
this->system_grab_ = shell()->startSystemResize(edges);
|
||||
sync_host();
|
||||
request_render();
|
||||
};
|
||||
this->kit_.start_drag = [this](QMimeData *mime, const QImage &icon) {
|
||||
@@ -298,7 +306,16 @@ Window::initialize(const QUrl &url, BrowseSetup setup, Mode mode)
|
||||
if (change == SettingsChange::Preferences) {
|
||||
this->renderer_.dither_enabled =
|
||||
!this->app_->settings.disable_dithering;
|
||||
this->settings_apply_pending_ = true;
|
||||
// Not inside the dialog's Save: libcolord's synchronous calls spin
|
||||
// the main loop, which would reap the dialog from under it.
|
||||
this->kit_.post([this] {
|
||||
if (this->viewer_)
|
||||
this->viewer_->loaders_ =
|
||||
this->app_->settings.enabled_loaders;
|
||||
if (this->renderer_ready_)
|
||||
apply_screen_profile(screen(), true);
|
||||
request_render();
|
||||
});
|
||||
}
|
||||
if (this->browser_)
|
||||
this->browser_->rescan();
|
||||
@@ -329,6 +346,7 @@ Window::initialize(const QUrl &url, BrowseSetup setup, Mode mode)
|
||||
this->browser_->thumb_size_ =
|
||||
this->app_->settings.browser_thumbnail_size;
|
||||
}
|
||||
sync_host();
|
||||
apply_screen_profile(screen(), false);
|
||||
|
||||
if (mode == Mode::Browse)
|
||||
@@ -521,10 +539,19 @@ Window::bind_host()
|
||||
return;
|
||||
if (this->browser_)
|
||||
this->browser_->hist_forward_.clear();
|
||||
open_viewer(url);
|
||||
// Before the open, which completes right away when it is cached.
|
||||
this->awaiting_view_ = true;
|
||||
open_viewer(url);
|
||||
request_render();
|
||||
};
|
||||
this->host_.opened = [this] {
|
||||
if (!this->awaiting_view_)
|
||||
return;
|
||||
this->awaiting_view_ = false;
|
||||
set_mode(Mode::View);
|
||||
request_render();
|
||||
};
|
||||
this->host_.retitle = [this] { sync_title(); };
|
||||
this->host_.new_window = [this](QUrl url) {
|
||||
if (url.isEmpty())
|
||||
url = current_url();
|
||||
@@ -716,7 +743,7 @@ Window::sync_title()
|
||||
QWindow *w = shell();
|
||||
if (w->title() != title) {
|
||||
w->setTitle(title);
|
||||
// This runs every frame, and only here has the name really changed.
|
||||
// Callers sync whenever it may have changed, but only here has it.
|
||||
accessible_renamed(this);
|
||||
}
|
||||
if (this != w && this->title() != title)
|
||||
@@ -1067,21 +1094,37 @@ Window::accessibleRoot() const
|
||||
#endif
|
||||
}
|
||||
|
||||
// Everything the platform tells about the window that the kit draws from.
|
||||
// It is cheap, so whatever may change any of it syncs all of it.
|
||||
void
|
||||
Window::sync_csd()
|
||||
Window::sync_host()
|
||||
{
|
||||
this->kit_.sync_cursor();
|
||||
if (this->kit_.cursor_ != this->cursor_applied_) {
|
||||
this->cursor_applied_ = this->kit_.cursor_;
|
||||
setCursor(this->cursor_applied_);
|
||||
if (!this->renderer_ready_)
|
||||
return;
|
||||
|
||||
const float dpr = host_dpr(*this);
|
||||
this->kit_.dpi_ = host_dpi(*this);
|
||||
if (this->kit_.set_host(float(width()), float(height()), dpr))
|
||||
reset_fonts();
|
||||
|
||||
QWindow *sh = shell();
|
||||
this->kit_.fullscreen_ = bool(sh->windowState() & Qt::WindowFullScreen);
|
||||
this->kit_.maximized_ = bool(sh->windowState() & Qt::WindowMaximized);
|
||||
this->kit_.csd_ = this->csd_ && !this->kit_.fullscreen_;
|
||||
this->kit_.active_ = this->system_grab_ || sh->isActive() || isActive();
|
||||
const bool shadow = this->kit_.csd_ && !this->kit_.maximized_;
|
||||
if (this->kit_.csd_shadow_ != shadow) {
|
||||
this->kit_.csd_shadow_ = shadow;
|
||||
for (auto &page : this->pages_)
|
||||
if (page)
|
||||
page->invalidate_arrange();
|
||||
}
|
||||
const bool shadow = this->kit_.csd_shadow_;
|
||||
|
||||
QRegion mask;
|
||||
if (shadow) {
|
||||
// Input still has to reach the resize band, which lies in the shadow.
|
||||
// setMask() speaks logical points, while the frame is in pixels:
|
||||
// one conversion back, rather than two roundings that disagree.
|
||||
const float dpr = host_dpr(*this);
|
||||
const auto pt = [dpr](int v) { return int(lround(double(v) / dpr)); };
|
||||
const int band = int(lround(double(kResizeBorderPts)));
|
||||
const Rect f = this->kit_.frame();
|
||||
@@ -1089,12 +1132,25 @@ Window::sync_csd()
|
||||
mask = QRegion(frame.adjusted(-band, -band, band, band));
|
||||
}
|
||||
setMask(mask);
|
||||
if (QWindow *sh = shell(); sh != this)
|
||||
if (sh != this)
|
||||
sh->setMask(QRegion());
|
||||
const float dpr = host_dpr(*this);
|
||||
const uint32_t inset =
|
||||
this->renderer_.dest_inset =
|
||||
shadow ? uint32_t(max(0L, lround(double(kGlowPts) * double(dpr)))) : 0;
|
||||
this->renderer_.dest_inset = inset;
|
||||
}
|
||||
|
||||
// Text shaped and measured with the old fonts is stale, and so is whatever
|
||||
// the contents sized after them.
|
||||
void
|
||||
Window::reset_fonts()
|
||||
{
|
||||
if (!this->renderer_ready_)
|
||||
return;
|
||||
|
||||
this->kit_.reset_fonts();
|
||||
for (auto &page : this->pages_)
|
||||
if (page && page->content)
|
||||
page->content->rescale(this->kit_);
|
||||
request_render();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1155,6 +1211,7 @@ Window::open_viewer(const QUrl &url)
|
||||
return;
|
||||
this->viewer_->open(url);
|
||||
sync_viewer_preloads();
|
||||
sync_title();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1216,30 +1273,6 @@ Window::render()
|
||||
this->renderer_.resize(pixel_size());
|
||||
this->resize_pending_ = false;
|
||||
}
|
||||
if (this->settings_apply_pending_ && this->renderer_.extent().width &&
|
||||
this->renderer_.extent().height) {
|
||||
if (this->viewer_)
|
||||
this->viewer_->loaders_ = this->app_->settings.enabled_loaders;
|
||||
apply_screen_profile(screen(), true);
|
||||
this->settings_apply_pending_ = false;
|
||||
}
|
||||
|
||||
const float w = float(width());
|
||||
const float h = float(height());
|
||||
const float dpr = host_dpr(*this);
|
||||
this->kit_.dpi_ = host_dpi(*this);
|
||||
const bool fullscreen = bool(shell()->windowState() & Qt::WindowFullScreen);
|
||||
bool rescale = this->kit_.set_host(w, h, dpr);
|
||||
if (this->font_change_pending_) {
|
||||
this->font_change_pending_ = false;
|
||||
if (!rescale)
|
||||
rescale = this->kit_.reset_fonts();
|
||||
} else if (this->kit_.text_backend_.settings_changed())
|
||||
rescale = this->kit_.reset_fonts() || rescale;
|
||||
if (rescale)
|
||||
for (auto &page : this->pages_)
|
||||
if (page && page->content)
|
||||
page->content->rescale(this->kit_);
|
||||
|
||||
// Nothing to do for a resize: relayout_popups() re-places every popup
|
||||
// and drops the ones whose opener stopped being shown.
|
||||
@@ -1247,34 +1280,16 @@ Window::render()
|
||||
if (!ui)
|
||||
return;
|
||||
|
||||
// Completing an open below may change the mode after this page is drawn.
|
||||
const bool show_image =
|
||||
this->mode_ == Mode::View || this->mode_ == Mode::CropJpeg;
|
||||
|
||||
this->kit_.fullscreen_ = fullscreen;
|
||||
this->kit_.maximized_ = bool(shell()->windowState() & Qt::WindowMaximized);
|
||||
this->kit_.csd_ = this->csd_ && !fullscreen;
|
||||
const bool shadow = this->kit_.csd_ && !this->kit_.maximized_;
|
||||
if (this->kit_.csd_shadow_ != shadow) {
|
||||
this->kit_.csd_shadow_ = shadow;
|
||||
ui->invalidate_arrange();
|
||||
}
|
||||
this->kit_.active_ =
|
||||
this->system_grab_ || shell()->isActive() || isActive();
|
||||
sync_title();
|
||||
if (ui->titlebar)
|
||||
ui->titlebar->sync(this->kit_);
|
||||
if (ui->toolbar)
|
||||
ui->toolbar->busy = this->awaiting_view_ || ui->content->busy();
|
||||
this->kit_.frame_ui(*ui);
|
||||
sync_csd();
|
||||
if (this->viewer_ && this->viewer_->consume_open_done() &&
|
||||
this->awaiting_view_) {
|
||||
this->awaiting_view_ = false;
|
||||
set_mode(Mode::View);
|
||||
request_render();
|
||||
if (this->kit_.cursor_ != this->cursor_applied_) {
|
||||
this->cursor_applied_ = this->kit_.cursor_;
|
||||
setCursor(this->cursor_applied_);
|
||||
}
|
||||
|
||||
const bool show_image =
|
||||
this->mode_ == Mode::View || this->mode_ == Mode::CropJpeg;
|
||||
const bool deferred = this->present_retry_.isActive();
|
||||
const bool presented = !deferred &&
|
||||
this->renderer_.draw_frame(this->kit_.list_.mesh(), show_image);
|
||||
@@ -1356,6 +1371,7 @@ Window::handle_screen_change(QScreen *target_screen)
|
||||
this->resize_pending_ = true;
|
||||
if (this->renderer_ready_)
|
||||
apply_screen_profile(target_screen, false);
|
||||
sync_host();
|
||||
request_render();
|
||||
}
|
||||
|
||||
@@ -1454,12 +1470,12 @@ Window::event(QEvent *event)
|
||||
}
|
||||
case QEvent::DevicePixelRatioChange:
|
||||
this->resize_pending_ = true;
|
||||
sync_host();
|
||||
request_render();
|
||||
break;
|
||||
case QEvent::ApplicationFontChange:
|
||||
case QEvent::FontChange:
|
||||
this->font_change_pending_ = true;
|
||||
request_render();
|
||||
case QEvent::ThemeChange:
|
||||
// The only word of a new system font, which Qt has already re-read.
|
||||
reset_fonts();
|
||||
break;
|
||||
case QEvent::PlatformSurface: {
|
||||
auto *surface_event = (QPlatformSurfaceEvent *) event;
|
||||
@@ -1526,6 +1542,10 @@ Window::focus_gained()
|
||||
{
|
||||
sync_macos_app_menu(this->app_);
|
||||
accessible_activated(this);
|
||||
sync_host();
|
||||
// Nothing tells of font settings changing while we are in front.
|
||||
if (this->renderer_ready_ && this->kit_.text_backend_.settings_changed())
|
||||
reset_fonts();
|
||||
request_render();
|
||||
}
|
||||
|
||||
@@ -1546,18 +1566,16 @@ Window::focus_lost()
|
||||
// Past the guard above, so that the hand-off it describes stays what it
|
||||
// is: one window, and nothing for a screen reader to read out twice.
|
||||
accessible_activated(this);
|
||||
sync_host();
|
||||
request_render();
|
||||
}
|
||||
|
||||
bool
|
||||
Window::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if ((watched == qGuiApp || watched == this || watched == shell()) &&
|
||||
(event->type() == QEvent::ApplicationFontChange ||
|
||||
event->type() == QEvent::FontChange)) {
|
||||
this->font_change_pending_ = true;
|
||||
request_render();
|
||||
}
|
||||
// Qt then posts a copy to every top-level window, which says nothing new.
|
||||
if (watched == qGuiApp && event->type() == QEvent::ApplicationFontChange)
|
||||
reset_fonts();
|
||||
if (watched != this && watched != shell())
|
||||
return false;
|
||||
|
||||
@@ -1568,6 +1586,7 @@ Window::eventFilter(QObject *watched, QEvent *event)
|
||||
(event->type() == QEvent::Enter || event->type() == QEvent::MouseMove ||
|
||||
event->type() == QEvent::MouseButtonPress)) {
|
||||
this->system_grab_ = false;
|
||||
sync_host();
|
||||
request_render();
|
||||
}
|
||||
if (watched != this)
|
||||
@@ -1619,6 +1638,7 @@ void
|
||||
Window::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
this->resize_pending_ = true;
|
||||
sync_host();
|
||||
request_render();
|
||||
}
|
||||
|
||||
@@ -1662,7 +1682,6 @@ Window::open_any(const QUrl &input)
|
||||
(url_to_path(url).isEmpty() || QFileInfo(url_to_path(url)).isDir()))
|
||||
return;
|
||||
this->cropper_->open(url);
|
||||
sync_title();
|
||||
request_render();
|
||||
return;
|
||||
}
|
||||
@@ -1719,7 +1738,6 @@ Window::reveal_file(const QUrl &input)
|
||||
cancel_viewer_loads();
|
||||
set_mode(Mode::Browse);
|
||||
request_render();
|
||||
sync_title();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+2
-3
@@ -77,7 +77,8 @@ class Window final : public QWindow
|
||||
void bind_host();
|
||||
void set_mode(Mode m);
|
||||
void sync_title();
|
||||
void sync_csd();
|
||||
void sync_host();
|
||||
void reset_fonts();
|
||||
bool handle_native_gesture(QNativeGestureEvent *event);
|
||||
bool handle_touch(QTouchEvent *event);
|
||||
bool handle_input_method(QInputMethodEvent *event);
|
||||
@@ -102,8 +103,6 @@ class Window final : public QWindow
|
||||
bool renderer_ready_ = false;
|
||||
bool exposed_ = false;
|
||||
bool resize_pending_ = false;
|
||||
bool settings_apply_pending_ = false;
|
||||
bool font_change_pending_ = false;
|
||||
bool update_pending_ = false;
|
||||
std::string screen_profile_label_; // Its name and source
|
||||
// What the screen profile last saw of Windows Advanced Color, against
|
||||
|
||||
Reference in New Issue
Block a user