Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 39 additions & 23 deletions src/ui/classic/xcbinputwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,13 @@ int XCBInputWindow::calculatePositionX(const Rect &cursorRect,
int x = cursorRect.left();

auto &theme = parent_->theme();
int leftSW = theme.inputPanel->shadowMargin->marginLeft.value();
int rightSW = theme.inputPanel->shadowMargin->marginRight.value();
int leftSW =
physicalFromLogical(theme.inputPanel->shadowMargin->marginLeft.value());
int rightSW = physicalFromLogical(
theme.inputPanel->shadowMargin->marginRight.value());

int actualWidth = width() - leftSW - rightSW;
actualWidth = actualWidth <= 0 ? width() : actualWidth;
int actualWidth = physicalWidth_ - leftSW - rightSW;
actualWidth = actualWidth <= 0 ? physicalWidth_ : actualWidth;

if (closestScreen != nullptr) {
int newX = std::max(x, closestScreen->left());
Expand All @@ -105,27 +107,31 @@ int XCBInputWindow::calculatePositionY(const Rect &cursorRect,
int y = cursorRect.top();

auto &theme = parent_->theme();
int topSW = theme.inputPanel->shadowMargin->marginTop.value();
int bottomSW = theme.inputPanel->shadowMargin->marginBottom.value();
int topSW =
physicalFromLogical(theme.inputPanel->shadowMargin->marginTop.value());
int bottomSW = physicalFromLogical(
theme.inputPanel->shadowMargin->marginBottom.value());

int actualHeight = height() - topSW - bottomSW;
actualHeight = actualHeight <= 0 ? height() : actualHeight;
int actualHeight = physicalHeight_ - topSW - bottomSW;
actualHeight = actualHeight <= 0 ? physicalHeight_ : actualHeight;

if (closestScreen != nullptr) {
int h = cursorRect.height();
int newY;
if (y < closestScreen->top()) {
newY = closestScreen->top();
} else {
newY = y + (h ? h : (10 * ((dpi_ < 0 ? 96.0 : dpi_) / 96.0)));
newY = y + (h ? h : physicalFromLogical(10));
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// Try flip y.
if (newY + actualHeight > closestScreen->bottom()) {
if (newY > closestScreen->bottom()) {
newY = closestScreen->bottom() - actualHeight - 40;
newY = closestScreen->bottom() - actualHeight -
physicalFromLogical(40);
} else { /* better position the window */
newY = newY - actualHeight - ((h == 0) ? 40 : h);
newY = newY - actualHeight -
((h == 0) ? physicalFromLogical(40) : h);
}

// If after flip, top is out of the screen, we still prefer the top
Expand Down Expand Up @@ -165,9 +171,12 @@ void XCBInputWindow::updateDPI(InputContext *inputContext) {
dpi_ = ui_->dpiByPosition(inputContext->cursorRect().left(),
inputContext->cursorRect().top());

setFontDPI(dpi_);
// Let Cairo device scale handle HiDPI so Pango keeps logical font sizes.
setFontDPI(-1);
}

double XCBInputWindow::scale() const { return scaleForDPI(dpi_); }

void XCBInputWindow::update(InputContext *inputContext) {
if (!wid_) {
return;
Expand All @@ -185,15 +194,19 @@ void XCBInputWindow::update(InputContext *inputContext) {
return;
}

if (width != this->width() || height != this->height()) {
resize(width, height);
auto oldPhysicalWidth = physicalWidth_;
auto oldPhysicalHeight = physicalHeight_;
resize(width, height);
if (physicalWidth_ != oldPhysicalWidth ||
physicalHeight_ != oldPhysicalHeight) {
if (atomBlur_) {
Rect rect(0, 0, width, height);
shrink(rect, *ui_->parent()->theme().inputPanel->blurMargin);
Rect logicalRect(0, 0, width, height);
shrink(logicalRect, *ui_->parent()->theme().inputPanel->blurMargin);
if (!*ui_->parent()->theme().inputPanel->enableBlur ||
rect.isEmpty()) {
logicalRect.isEmpty()) {
xcb_delete_property(ui_->connection(), wid_, atomBlur_);
} else {
auto rect = physicalFromLogical(logicalRect);
std::vector<uint32_t> data;
if (ui_->parent()->theme().inputPanel->blurMask->empty()) {
data.push_back(rect.left());
Expand All @@ -208,10 +221,11 @@ void XCBInputWindow::update(InputContext *inputContext) {
auto region = parent_->theme().mask(
parent_->theme().maskConfig(), width, height);
for (const auto &rect : region) {
data.push_back(rect.left());
data.push_back(rect.top());
data.push_back(rect.width());
data.push_back(rect.height());
auto physicalRect = physicalFromLogical(rect);
data.push_back(physicalRect.left());
data.push_back(physicalRect.top());
data.push_back(physicalRect.width());
data.push_back(physicalRect.height());
}
xcb_change_property(ui_->connection(),
XCB_PROP_MODE_REPLACE, wid_, atomBlur_,
Expand Down Expand Up @@ -250,7 +264,8 @@ bool XCBInputWindow::filterEvent(xcb_generic_event_t *event) {
break;
}
if (buttonPress->detail == XCB_BUTTON_INDEX_1) {
click(buttonPress->event_x, buttonPress->event_y);
click(logicalFromPhysical(buttonPress->event_x),
logicalFromPhysical(buttonPress->event_y));
} else if (buttonPress->detail == XCB_BUTTON_INDEX_4) {
wheel(/*up=*/true);
} else if (buttonPress->detail == XCB_BUTTON_INDEX_5) {
Expand All @@ -261,7 +276,8 @@ bool XCBInputWindow::filterEvent(xcb_generic_event_t *event) {
case XCB_MOTION_NOTIFY: {
auto *motion = reinterpret_cast<xcb_motion_notify_event_t *>(event);
if (motion->event == wid_) {
if (hover(motion->event_x, motion->event_y)) {
if (hover(logicalFromPhysical(motion->event_x),
logicalFromPhysical(motion->event_y))) {
repaint();
}
return true;
Expand Down
1 change: 1 addition & 0 deletions src/ui/classic/xcbinputwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class XCBInputWindow : public XCBWindow, protected InputWindow {

private:
void repaint();
double scale() const override;
const Rect *getClosestScreen(const Rect &cursorRect) const;
int calculatePositionX(const Rect &cursorRect,
const Rect *closestScreen) const;
Expand Down
46 changes: 22 additions & 24 deletions src/ui/classic/xcbmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@ bool XCBMenu::filterEvent(xcb_generic_event_t *event) {
}
if (auto *menu =
childByPosition(buttonPress->root_x, buttonPress->root_y)) {
menu->handleButtonPress(buttonPress->root_x - menu->x_,
buttonPress->root_y - menu->y_);
menu->handleButtonPress(
menu->logicalFromPhysical(buttonPress->root_x - menu->x_),
menu->logicalFromPhysical(buttonPress->root_y - menu->y_));
} else {
hideAll();
return true;
Expand All @@ -120,8 +121,9 @@ bool XCBMenu::filterEvent(xcb_generic_event_t *event) {
}

if (auto *menu = childByPosition(motion->root_x, motion->root_y)) {
menu->handleMotionNotify(motion->root_x - menu->x_,
motion->root_y - menu->y_);
menu->handleMotionNotify(
menu->logicalFromPhysical(motion->root_x - menu->x_),
menu->logicalFromPhysical(motion->root_y - menu->y_));
}
return true;
}
Expand Down Expand Up @@ -279,7 +281,7 @@ XCBMenu *XCBMenu::childByPosition(int rootX, int rootY) {
while (result) {
Rect rect;
rect.setPosition(result->x_, result->y_)
.setSize(result->width_, result->height_);
.setSize(result->physicalWidth_, result->physicalHeight_);
if (rect.contains(rootX, rootY)) {
break;
}
Expand Down Expand Up @@ -353,7 +355,8 @@ void XCBMenu::setHoveredIndex(int idx) {
// FCITX_INFO() << this << " in timer show submenu "
// << newMenu;
newMenu->show(
item.first->region_.translated(x_, y_),
physicalFromLogical(item.first->region_)
.translated(x_, y_),
ConstrainAdjustment::Slide);
}
} else {
Expand Down Expand Up @@ -385,18 +388,14 @@ std::pair<MenuItem *, Action *> XCBMenu::actionAt(size_t index) {
void XCBMenu::updateDPI(int x, int y) {
dpi_ = ui_->dpiByPosition(x, y);

// Unlike pango cairo context, Cairo font map does not accept negative dpi.
// Restore to default value instead.
if (dpi_ < 0) {
pango_cairo_font_map_set_resolution(
PANGO_CAIRO_FONT_MAP(fontMap_.get()), fontMapDefaultDPI_);
} else {
pango_cairo_font_map_set_resolution(
PANGO_CAIRO_FONT_MAP(fontMap_.get()), dpi_);
}
pango_cairo_context_set_resolution(context_.get(), dpi_);
// Let Cairo device scale handle HiDPI so Pango keeps logical font sizes.
pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(fontMap_.get()),
fontMapDefaultDPI_);
pango_cairo_context_set_resolution(context_.get(), -1);
}

double XCBMenu::scale() const { return scaleForDPI(dpi_); }

void XCBMenu::update() {
auto *ic = lastRelevantIc();
if (!ic) {
Expand Down Expand Up @@ -501,7 +500,7 @@ void XCBMenu::update() {
.setSize(maxItemWidth + *highlightMargin.marginLeft +
*highlightMargin.marginRight,
maxItemHeight + *highlightMargin.marginTop +
*highlightMargin.marginTop);
*highlightMargin.marginBottom);
item.layoutX_ = width + *textMargin.marginLeft +
(hasCheckable ? checkBox.width() : 0);
item.layoutY_ = height + *textMargin.marginTop +
Expand Down Expand Up @@ -664,20 +663,19 @@ void XCBMenu::show(Rect rect, ConstrainAdjustment adjustY) {
x = x + rect.width();

if (closestScreen) {

if (x + width() > closestScreen->right()) {
x = rect.left() - width();
if (x + physicalWidth_ > closestScreen->right()) {
x = rect.left() - physicalWidth_;
}

switch (adjustY) {
case ConstrainAdjustment::Slide:
if (y + height() > closestScreen->bottom()) {
y = closestScreen->bottom() - height();
if (y + physicalHeight_ > closestScreen->bottom()) {
y = closestScreen->bottom() - physicalHeight_;
}
break;
case ConstrainAdjustment::Flip:
if (y + height() > closestScreen->bottom()) {
y = rect.top() - height();
if (y + physicalHeight_ > closestScreen->bottom()) {
y = rect.top() - physicalHeight_;
}
break;
};
Expand Down
1 change: 1 addition & 0 deletions src/ui/classic/xcbmenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class XCBMenu : public XCBWindow, public TrackableObject<XCBMenu> {
void setHoveredIndex(int idx);
void setChild(XCBMenu *child);
void updateDPI(int x, int y);
double scale() const override;
std::pair<MenuItem *, Action *> actionAt(size_t index);

MenuPool *pool_;
Expand Down
74 changes: 62 additions & 12 deletions src/ui/classic/xcbwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

#include "xcbwindow.h"
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <cairo-xcb.h>
Expand Down Expand Up @@ -77,9 +79,12 @@ void XCBWindow::createWindow(xcb_visualid_t vid, bool overrideRedirect) {
params.colormap = colorMap;
vid_ = vid;

physicalWidth_ = physicalSizeFromLogical(width_);
physicalHeight_ = physicalSizeFromLogical(height_);

auto cookie = xcb_aux_create_window_checked(
conn, depth, wid_, screen->root, 0, 0, width_, height_, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, vid, valueMask, &params);
conn, depth, wid_, screen->root, 0, 0, physicalWidth_, physicalHeight_,
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, vid, valueMask, &params);
if (auto error = makeUniqueCPtr(xcb_request_check(conn, cookie))) {
CLASSICUI_DEBUG() << "Create window failed: "
<< static_cast<int>(error->error_code) << " " << vid
Expand All @@ -105,8 +110,10 @@ void XCBWindow::createWindow(xcb_visualid_t vid, bool overrideRedirect) {
conn, wid_,
vid ? xcb_aux_find_visual_by_id(screen, vid)
: xcb_aux_find_visual_by_id(screen, screen->root_visual),
width_, height_));
physicalWidth_, physicalHeight_));
if (surface_) {
auto s = scale();
cairo_surface_set_device_scale(surface_.get(), s, s);
ui_->setCairoDevice(cairo_surface_get_device(surface_.get()));
}
contentSurface_.reset();
Expand All @@ -132,23 +139,38 @@ void XCBWindow::destroyWindow() {
}

void XCBWindow::resize(unsigned int width, unsigned int height) {
const uint32_t vals[2] = {width, height};
xcb_configure_window(ui_->connection(), wid_,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
vals);
cairo_xcb_surface_set_size(surface_.get(), width, height);
auto s = scale();
auto newPhysicalWidth = physicalSizeFromLogical(width);
auto newPhysicalHeight = physicalSizeFromLogical(height);
if (newPhysicalWidth != physicalWidth_ ||
newPhysicalHeight != physicalHeight_) {
const uint32_t vals[2] = {static_cast<uint32_t>(newPhysicalWidth),
static_cast<uint32_t>(newPhysicalHeight)};
xcb_configure_window(ui_->connection(), wid_,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
vals);
cairo_xcb_surface_set_size(surface_.get(), newPhysicalWidth,
newPhysicalHeight);
physicalWidth_ = newPhysicalWidth;
physicalHeight_ = newPhysicalHeight;
}
cairo_surface_set_device_scale(surface_.get(), s, s);
Window::resize(width, height);
CLASSICUI_DEBUG() << "Resize: " << width << " " << height;
CLASSICUI_DEBUG() << "Resize: " << width << " " << height << " scale " << s
<< " physical " << physicalWidth_ << " "
<< physicalHeight_;
}

cairo_surface_t *XCBWindow::prerender() {
#if 1
contentSurface_.reset(cairo_surface_create_similar_image(
surface_.get(), CAIRO_FORMAT_ARGB32, width(), height()));
surface_.get(), CAIRO_FORMAT_ARGB32, physicalWidth_, physicalHeight_));
#else
contentSurface_.reset(
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width(), height()));
contentSurface_.reset(cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, physicalWidth_, physicalHeight_));
#endif
auto s = scale();
cairo_surface_set_device_scale(contentSurface_.get(), s, s);
return contentSurface_.get();
}

Expand All @@ -160,4 +182,32 @@ void XCBWindow::render() {
cairo_destroy(cr);
CLASSICUI_DEBUG() << "Render";
}

int XCBWindow::logicalFromPhysical(int value) const {
return static_cast<int>(std::floor(value / scale()));
}

int XCBWindow::physicalFromLogical(int value) const {
return static_cast<int>(std::lround(value * scale()));
}

int XCBWindow::physicalSizeFromLogical(int size) const {
return std::max(1, physicalFromLogical(size));
}

Rect XCBWindow::physicalFromLogical(const Rect &rect) const {
return Rect()
.setLeft(physicalFromLogical(rect.left()))
.setTop(physicalFromLogical(rect.top()))
.setRight(physicalFromLogical(rect.right()))
.setBottom(physicalFromLogical(rect.bottom()));
}

double XCBWindow::scaleForDPI(int dpi) {
if (dpi <= 0) {
return 1.0;
}
return static_cast<double>(dpi) / 96.0;
}

} // namespace fcitx::classicui
Loading
Loading