Opened 18 years ago

Closed 18 years ago

Last modified 18 years ago

#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)

winmask.zip (28.7 KB) - added by dmik 18 years ago.
Non-rectangular widget test case

Download all attachments as: .zip

Change History (8)

comment:1 Changed 18 years ago by dmik

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.

comment:2 Changed 18 years ago by dmik

Component: 3rdpartykernel

comment:3 Changed 18 years ago by dmik

Status: newassigned

comment:4 Changed 18 years ago by dmik

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 Changed 18 years ago by anonymous

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 Changed 18 years ago by dmik

Resolution: fixed
Status: assignedclosed

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.

Changed 18 years ago by dmik

Attachment: winmask.zip added

Non-rectangular widget test case

comment:7 Changed 18 years ago by anonymous

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.

Note: See TracTickets for help on using tickets.