Skip to content
Merged
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
84 changes: 58 additions & 26 deletions lib/gui/ewidgetdesktop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,22 @@ void eWidgetDesktop::addRootWidget(eWidget *root)
ASSERT(!root->m_desktop);

int invert_sense = 0;
/* buffered mode paints back-to-front, while immediate mode is front-to-back. */
/* m_root is always kept sorted front-to-back in immediate mode (used for
clip region calculation, front to back), and back-to-front in buffered
mode (used for composition, back to front). immediate mode painting
itself walks m_root in reverse (back-to-front) -- see paint(). */
if (m_comp_mode == cmBuffered)
invert_sense = 1;

ePtrList<eWidget>::iterator insert_position = m_root.begin();

/* <= rather than < : among widgets sharing the same (e.g. default,
unset) zPosition, the one added last ends up on top, consistent
with how child widgets are stacked (see eWidget::insertIntoParent)
and with the painting order below. */
for (;;)
{
if ((insert_position == m_root.end()) || (invert_sense ^ (insert_position->m_z_position < root->m_z_position)))
if ((insert_position == m_root.end()) || (invert_sense ^ (insert_position->m_z_position <= root->m_z_position)))
{
m_root.insert(insert_position, root);
break;
Expand Down Expand Up @@ -59,7 +66,7 @@ int eWidgetDesktop::movedWidget(eWidget *root)
return 0; /* native move ok */
}

void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible, bool parent)
void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible)
{
/* start with our clip region, clipped with the parent's */
if (widget->m_vis & eWidget::wVisShow)
Expand All @@ -68,8 +75,13 @@ void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visib
widget->m_visible_region.moveBy(widget->position());
widget->m_visible_region &= parent_visible; // in parent space!

if (!widget->isTransparent() && (!widget->m_gradient_alphablend || parent) && (widget->m_cornerRadius == 0 || parent) && (!widget->m_alphaBlend || parent))
/* remove everything this widget will contain from parent's visible list, unless widget is transparent. */
if (!widget->isTransparent() && !widget->m_gradient_alphablend && widget->m_cornerRadius == 0 && !widget->m_alphaBlend)
/* remove everything this widget will contain from parent's visible list, unless the
widget is transparent, alphablended, gradient-alphablended or rounded -- in that
case whatever is behind it (a parent widget, another root widget, or the desktop
background) must stay available so it keeps being calculated/painted underneath.
this applies the same way at root (screen) level as it does for nested widgets,
so overlapping root windows respect zPosition and composite correctly. */
parent_visible -= widget->m_visible_region; // will remove child regions too!

/* now prepare for recursing to childs */
Expand All @@ -87,7 +99,7 @@ void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visib
if (i != widget->m_childs.end())
{
if (i->m_vis & eWidget::wVisShow)
calcWidgetClipRegion(*i, widget->m_visible_region, false);
calcWidgetClipRegion(*i, widget->m_visible_region);
else
clearVisibility(*i);
}
Expand Down Expand Up @@ -275,20 +287,21 @@ void eWidgetDesktop::setPalette(gPixmap &pm)
}
}

void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp)
void eWidgetDesktop::paintBackground(eWidgetDesktopCompBuffer *comp, bool clearDirty)
{
if (!comp)
return;

comp->m_dirty_region &= comp->m_background_region;
gRegion background_dirty = comp->m_dirty_region & comp->m_background_region;

gPainter painter(comp->m_dc);

painter.resetClip(comp->m_dirty_region);
painter.resetClip(background_dirty);
painter.setBackgroundColor(comp->m_background_color);
painter.clear();

comp->m_dirty_region = gRegion();
if (clearDirty)
comp->m_dirty_region = gRegion();
}


Expand All @@ -301,12 +314,13 @@ void eWidgetDesktop::paintLayer(eWidget *widget, int layer)
return;
gPainter painter(comp->m_dc);
painter.moveOffset(-comp->m_position);
if (widget->m_cornerRadius > 0 || widget->m_gradient_set || widget->m_alphaBlend)
{
painter.resetClip(comp->m_dirty_region);
painter.setBackgroundColor(gRGB(0, 0, 0, 0xFF));
painter.clear();
}
/* no pre-clear here: alphablended/gradient/rounded-corner drawing (see
gPixmap::drawRectangle/drawRectangleNew) blends against whatever is
already in the destination, and rounded corners outside the radius
are deliberately left untouched. Both rely on the real content behind
this widget -- the desktop background or another root widget -- having
already been painted there (see paint()); clearing to a fixed color
first would blend/leave that fixed color instead of what's behind. */
widget->doPaint(painter, comp->m_dirty_region, layer);
painter.resetOffset();
}
Expand All @@ -315,26 +329,44 @@ void eWidgetDesktop::paint()
{
m_require_redraw = 0;

/* walk all root windows. */
for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
if (m_comp_mode == cmImmediate)
{
/* paint the true (video) background first: widgets with a transparent,
alphablended, gradient-alphablended or rounded-corner background rely
on whatever is behind them -- the desktop background, or another root
widget -- already being painted, so they can composite on top of it. */
paintBackground(&m_screen, false);

/* m_root is sorted front-to-back (see addRootWidget). paint it back-to-
front, so widgets further back are painted first and the ones in front
of them (which may be transparent/blended) composite correctly on top,
respecting zPosition. */
for (ePtrList<eWidget>::reverse_iterator i(m_root.rbegin()); i != m_root.rend(); ++i)
{
if (!(i->m_vis & eWidget::wVisShow))
continue;

if (!(i->m_vis & eWidget::wVisShow))
continue;

if (m_comp_mode == cmImmediate)
paintLayer(i, 0);
else
}

m_screen.m_dirty_region = gRegion();
}
else
{
/* walk all root windows. */
for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
{
if (!(i->m_vis & eWidget::wVisShow))
continue;

for (int l = 0; l < MAX_LAYER; ++l)
{
paintLayer(i, l);
paintBackground(i->m_comp_buffer[l]);
}
}
}

if (m_comp_mode == cmImmediate)
paintBackground(&m_screen);

if (m_comp_mode == cmBuffered)
{
// redrawComposition(0);
Expand Down
4 changes: 2 additions & 2 deletions lib/gui/ewidgetdesktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ class eWidgetDesktop: public sigc::trackable
void setMargins(const eRect& value) { m_margins = value; }
private:
ePtrList<eWidget> m_root;
void calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible, bool parent = true);
void paintBackground(eWidgetDesktopCompBuffer *comp);
void calcWidgetClipRegion(eWidget *widget, gRegion &parent_visible);
void paintBackground(eWidgetDesktopCompBuffer *comp, bool clearDirty = true);

eMainloop *m_mainloop;
ePtr<eTimer> m_timer;
Expand Down
10 changes: 10 additions & 0 deletions lib/gui/ewindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,13 @@ void eWindow::setCornerRadius(int radius, uint8_t edges)
eWidget::setCornerRadius(radius, edges);
m_child->setCornerRadius(radius, edges);
}

void eWindow::setWidgetAlphaBlend(bool blend)
{
/* set alphablend for child, too -- the window itself only ever paints its
border/title decoration (see event(evtPaint)), the actual background is
painted by m_child, so it needs to alphablend as well for a screen-level
alphaBlend skin attribute to have any visible effect. */
eWidget::setWidgetAlphaBlend(blend);
m_child->setWidgetAlphaBlend(blend);
}
1 change: 1 addition & 0 deletions lib/gui/ewindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class eWindow: public eWidget
void setBackgroundColor(const gRGB &col) override;
void setBackgroundGradient(const gRGB &startcolor, const gRGB &midcolor, const gRGB &endcolor, uint8_t direction, bool alphablend);
void setCornerRadius(int radius, uint8_t edges);
void setWidgetAlphaBlend(bool blend) override;

void setFlag(int flags);
void clearFlag(int flags);
Expand Down
Loading