#14 closed enhancement (fixed)
Implement QWidget::setMask() for non-toplevel widgets
Reported by: | dmik | Owned by: | dmik |
---|---|---|---|
Priority: | normal | Milestone: | qt-os2-3.3.1-rc07 |
Component: | kernel | Version: | |
Severity: | normal | Keywords: | widget mask |
Cc: |
Description
We need to implement the QWidget::setMask()
functionality for non-toplevel widgets, in order to have things like push buttons in the Norwegian Wood theme (see the themes
example) working properly.
Attachments (1)
Change History (8)
comment:1 by , 19 years ago
comment:2 by , 19 years ago
Component: | 3rdparty → kernel |
---|
comment:3 by , 19 years ago
Status: | new → assigned |
---|
comment:4 by , 19 years ago
Yes, WinSetClipRegion
will definitely help (it causes WinBeginPaint
to setup clipping accodringly and WM_HITTEST to return HT_TRANSPARENT for areas outside the clip region).
However, not everything is that good: when a parent of the window with a non-NULL clip region has the WS_CLIPCHILDREN style, this window is excluded from the parent's update region entirely, ignoring the clip region. As a result, areas of the window outside the clip region are not repainted, neither by the parent (due to an incorrect handling of WS_CLIPCHILDREN), nor by the window itelsf (due to the clip region). This obviously looks like a PM bug.
A possible workaround is to remove the WS_CLIPCHILDREN style from all Qt windows and clip children manually on every WM_PAINT, taking their clip regions into account (instead of just bounding rectangles). Will try it.
P.S. Btw, setting a clip region on standard window classes (tested with WC_BUTTON) has no desired result to the effect that windows of these classes ignore the clip region and continue to paint themselves everywhere (within their bounds). Probably, because they have WS_PARENTCLIP set or do some other trick. This is irrelevant to Qt though, because we don't use standard window classes besides WC_FRAME.
comment:5 by , 19 years ago
Making setMask() work properly is not that easy as I expected, even for non-toplevel windows. I've implemented it by removing WS_CLIPCHILDREN and WS_CLIPSIBLINGS flags from all widgets being created and doing all clipping stuff myself in WM_PAINT and when requesting a PS to draw to a window directly (i.e in QWidget::repaint()/erase()). It works perfectly well, but only until overlapped child widgets don't move (for example, as a result of complex layout management taking place when widgets are resized).
It turned out that the behavior of PM related to window repainting is something weird when no WS_CLIP* flags are used (yep, toolkit docs say that nothing is guaranteed in this case :). For example, moving a child widget placed (in Z-order) behind some other child widget using WinSetWindowPos() does not invalidate areas one might expect, that produces totally wrong results. It seems that we also have to manage invalidation manually when widgets are sized and/or moved, rather than let WinSetWindowPos() do it. Hopefully, it seems to be possible by enclosing this call with WinLockWindowUpdate() calls.
Will try this approach in a few days. If it doesn't work properly, I'll postpone this ticket for some time: it has aleady taken too much while not being a major issue at the moment (and prevents me from getting a new release candidate out).
comment:6 by , 19 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Implemented in changeset:64.
Hugh, it was really not easy at all. I had to reimplement WM_PAINT
handling, WinInvalidateRegion()
and 90% of WinSetWindowPos()
functionality to take clip regions (set by WinSetClipRegion()
) into account. It looks like active PM development at IBM was suspended right in the middle of implementing the non-rectangular window shape feature (for example, mouse hit/enter/leave code already obeys window regions while everything else does not).
Anyway, the themes
example now looks and functions as it should. I've also attached the winmask
test case that demonstrates and allows to test all aspects of non-rectangular non-toplevel widget functionality.
comment:7 by , 19 years ago
Forgot to mention. All widget mask code is enclosed in #if !defined (QT_PM_NO_WIDGETMASK)
statements, the old functionality is preserverd. So, if one encounters any problems and doesn't need widget masks at all, he can define QT_PM_NO_WIDGETMASK to restore the old behavior.
I hope we will be able to make usage of the untdocumented
WinSetClipRegion
API (pmwin.h
). This API doesn't work for top-level windows (i.e. HWND_DESKTOP children), however (I cannot recall where I read this, but it's true). For the time being, there is no acceptable way to mask top-level windows. You can create dozens of separate 1x1 pixel windows that comprise mask's curves, but is definitely not an option for a Qt widget -- it normally has children, it needs to lay them out, and all these things.