Implement basic visualization facilities such as primitive drawing. In
particular, this means the implementation of
o.e.swt.graphics.GC
[#Base] class. The test example of this
step should be able to create an SWT top window and draw some graphic
primitives in it.
In OS/2, as opposed to Windows (at least from the API point of view),
the client part of the frame window (the area where the custom drawing
takes place) is the separate window with its own window class and
procedure. SWT uses the Windows approach and therefore the frame window
(i.e. Decorations
and Shell
widgets) should
encapsulate the client window functionality to be as a whole for the user.
To achieve this the client window, an instance of the special
ClientArea
class (which is derived from the
Composite
), is anonymously created by the
Decorations.createHandle()
method. "Anonymously" means that
this instance is unaccessible anywhere outside the
Decorations
class. The special feature of the
ClientArea
class is that it uses its parent's (i.e. the
Decorations
) event table and, when sending or posting
messages, sets the Event.widget
field to the value of
parent
rather than this
. This means that all
events (specifically, the SWT.Paint
event) generated by the
client window look as Decorations
events to the user (and
directed to listeners registered on the Decorations
instance).
The presentation space handle to do low level painting in the window is
obtained via the Control.internal_new_GC()
method and must be
freed by the Control.internal_dispose_GC()
method when no
more needed. The logic of work of these two methods is as follows:
data
argument is null
or
data.rcl
is null
then WinGetPS()
is used to obtain the presentation space handle and
WinReleasePS()
-- to release it. Otherwise
WinBeginPaint()
obtains a handle, reusing
data.hps
(if not null)
and filling
data.rcl
with the updating rectangle, and
WinEndPaint()
releases the presentation space
obtained.WinGetPS()
and WinBeginPaint()
use
data.hwnd
, if it is not zero, as the window handle to
obtain the presentation space for. Otherwise Control.handle
is used. The latter is the normal behavior (i.e. data.hwnd
should normally be zero), the former can be used to substitute the
handle in subclasses when obtaining the presentation space handle (it is
not currently used and may be removed in the future).data
is not null
,
data.device
is assigned to the return value of
getDevice()
and data.hdc
is filled with the
device context handle returned by GpiQueryDevice()
for the
presentation space obtained above.In the Windows version, the WM_PAINT
handler uses the
device context obtained via the BeginPaint()
API call, which
initializes it with default attributes. To setup the correct graphics
context (a pen, brush, etc.) the GC.win32_new()
method is
called every time when the WM_PAINT
message occurs. Although
the same technique can be used in OS/2 too (and the existing code is ready
to do it) at the present time the "long-term" presentation space is used
to save attributes between WM_PAINT
messages (and for some
other purposes). This presentation space is allocated only once (lazily in
the WM_PAINT
handler) for every Control
widget
which has at least one SWT.Paint
event listener registered,
and it is released when the widget is being destroyed. However, the
Composite
class (and its descendants, of course) allocates
such presentation space even if no SWT.Paint
listeners are
registered, to draw the background (this behavior may change in the
future). This approach should lead to a better performance since no calls
to setup attributes on every paint message (except the first one) are made
(the GCData.doInit
field is used by GC.pm_new()
and the WM_PAINT
handler to indicate the need to setup the
presentation space). At the same time, this should not cause the increase
of memory usage because the presentation space is obtained via the
WinGetPS()
call, which returns the cached presentation
space.
Besides other things, the long-term presentation space is used to store
the default view transformation matrix to do the automatic coordinate
space flipping when using Gpi*
functions for painting (see
also here). It allows to
update the matrix only when the window is resized instead of doing it on
every paint message.
There is some muddle with dimensions of graphic primitives in the Win32
version of SWT: for example, the javadoc says that
GC.drawRoundRectangle()
draws a rectangle, those left and
right edges are at x and x + width, top and bottom
edges are at y and y + height. But it's not the case
-- actually, the right edge is at x + width - 1, and the bottom
one is at y + height - 1, i.e. the horizontal and vertical size
is one pixel smaller than it stated. Besides this, all fill*
versions of primitives draw figures one pixel smaller in size than their
draw*
versions, i.e. the rectangle drawn by
GC.fillRectangle(0,0,10,10)
is not the same in size as by
GC.drawRectangle(0,0,10,10)
-- the size of the former is 11
by 11 pixels while the size of the latter is 10 by 10. The docs just say
that fill*
versions fill the interior of a primitive, but we
see no reasons for the interior to be one pixel smaller than the outline
(although it's an expected behavior of the corresponding Win32 API calls,
but not OS/2 ones). Also, there are errors when drawing very small figures
(few pixels in size) and figures with the negative width and/or height
(see the SWT003_01
example). Most of these things look just
like bugs, so in OS/2 version we decided to fix them until any
incompatibility issue appears. "To fix" here means that the bounding
rectangle of all primitives in the OS/2 version of SWT always follows the
rule stated in the javadoc for GC.drawRectangle()
about the
edges and covers an area width + 1 pixels wide by height +
1 pixels tall.
In the Win32 version of SWT, if the device is in the palette mode (that
is, when it can display only 256 distinct colors simultaneously) and we
try to create new colors inside the paint event listener (as we draw in a
window) these colors will not appear on the screen until the next window
invalidation (see the SWT003_02
example). It is because new
colors are being added to the physical palette when it's already selected
to the device context at the beginning of the paint event handling and
won't be selected again until the next paint event. In the OS/2 version we
solve this problem by posting the WM_REALIZEPALETTE
message
to every Shell
widget when the new color is created, which
causes widgets to invalidate themselves.
In Windows, when drawing styled lines (dotted, dashed etc.) intervals between sytle segments are considered to be the "background" of the line and therefore are drawn by the current brush (see the SWT003_01 example). In OS/2 they are considered to be transparent and this behavior cannot be altered. Due to the inefficiency of the only possible application-level implementation of this functionality it is left as is at the present.
Operation | Status | Remarks |
---|---|---|
Implement OS.WinWindowFromID() and FID_*
constants |
Done [dmik] | |
Implement the frame client window creation and the message routing for it | Done [dmik] | |
Add OS.GpiCreateRegion() ,
WinQueryUpdateRegion() ,
WinInvalidateRegion() and RGN_*
constants |
Done [dmik] | The RECTL structure (which is originally passed as a
pointer) is passed as an int array (with four elements)
from Java to simplify access to it from the native
implementation. |
Add OS.GpiQueryRegionRects() , RGNRECT
class, RECTDIR_* constants |
Done [dmik] | |
Implement WM_PAINT message handling and
SWT.Paint event firing |
Done [dmik] | |
Implement OS.WinGetMaxPosition() |
Done [dmik] | Used to implement the Display.getClientArea() method,
which returns the size and position of maximized windows of the
desktop. These values can differ from
Display.getBounds() , e.g. when XCenter is running. Note:
XCenter 1.0.1 has a strange feature -- it reduces the maximum height
(reported by WinGetMaxPosition() ) by the value of its own
height plus additional 5 pixels, therefore the reported maximum height
is 5 pixels less than the actual. Possibly, it's a bug. |
Implement Device.getBounds() ,
getClientArea() for Device ,
Display and controls that support this |
Done [dmik] | Scrollable.getClientArea() code is temporary (should
take the scrollers into account) |
Add OS.GpiMove , OS.GpiBox ,
GPI_* and DRO_* constants, implement
GC.{fill|draw}[Round]Rectangle() methods |
Done [dmik] | POINTL structures are passed as arrays of
int with two elements (x and y). |
Add WM_CALCVALIDRECTS message handling,
OS.CVR_* constants |
Done [dmik] | Composite instance returns CVR_REDRAW on
WM_CALCVALIDRECTS if it has the CANVAS state
and no SWT.NO_REDRAW_RESIZE style to completely
invalidate itself when resizing. |
Create the draft SWT003 testcase |
Done [dmik] | |
Fix the bug of GpiBox() |
Done [dmik] | GpiBox() draws the rectangle 1 pixel higher than it
should do, when rounded corners and DRO_FILL or
DRO_OUTLINEFILL are specified. |
Add the long-term presentation space creation for a
Control object |
Done [dmik] | |
Implement OS.GpiSetDefaultViewMatrix() ,
TRANSFORM_* constants |
Done [dmik] | Necessary for automatic coordinate space flipping. |
Add OS.SHORT{1|2}FROMMP pseudo macros |
Done [dmik] | |
Add the o.e.swt.widgets.ClientArea class |
Done [dmik] | This class represents the frame client window. |
Implement OS.DevQueryCaps() and CAPS_*
constants |
Done [dmik] | Currently, constants are almost fully commented -- uncomment when needed. |
Overload OS.WinSendMsg() with one, that takes
OS.RECTL as the first message parameter |
Done [dmik] | Currently used to send WM_CALCFRAMERECT message. |
Add OS.GpiCreatePalette() ,
GpiDeletePalette() , LCOL_* and
LCOLF_* constants,
GpiQueryNearestPaletteIndex() ,
GpiQueryPaletteInfo() ,
GpiSetPaletteEntries() , GpiSelectPalette() ,
GpiCreateLogColorTable() ,
WinRealizePalette() |
Done [dmik] | Note: GpiQueryNearestPaletteIndex() is undocumented.
We hope it presents in Warp4 and earlier OS/2 versions... |
Add OS.GpiQueryColor() , GpiSetColor() ,
GpiQueryBackColor() , GpiSetBackColor() ,
GpiQieryMix() , GpiSetMix() ,
FM_* constants, GpiQueryBackMix() ,
GpiSetBackMix() , BM_* constants,
GpiQueryPattern() , GpiSetPattern() ,
PATSYM_* constants |
Done [dmik] | |
Add WM_REALIZEPALETTE message handling, implement
{get|set}{Foreground|Background}() methods of
Control and GC classes,
OS.WinQuerySysColor() and SYSCLR_*
constants |
Done [dmik] | |
Add the GC.Color class and implement color
handling |
Done [dmik] | |
Add OS.GpiLine() , GpiBeginArea() ,
GpiEndArea() , GpiPartialArc() ,
GpiSetArcParams() ,
GpiQueryCurrentPosition() , implement
GC.drawLine() , {draw|fill}Arc() ,
{draw|fill}Oval() methods |
Done [dmik] | ARCPARAMS structure is passed to
GpiSetArcParams() as an array of
int[4] . |
Create TestCase and SWTTestCase classes
to simplify test case writing, remove the SWT003 tescase
and create SWT003_01 and SWT003_02 instead,
update the SWT004 testcase |
Done [dmik] | If the step requires several different testcases each with its own
top shell window, it's possible to do so, naming them as
SWTXXX_YY where XXX is the step number and YY is the
number of the testcase. Such testcases can be run as usual, specifying
the step name in the format above via the test.step
property in the build.prp file or on the command line. |
Add OS.GpiPolyLine() , implement
GC.getBackground() , getForeground() ,
drawPolyline() , drawPolygon() ,
fillPolygon() |
Done [dmik] | |
Add OS.Gpi{Query|Set}LineType() ,
LINETYPE_* constants, implement
GC.{get|set}LineStyle() , drawFocus() |
Done [dmik] | |
Add OS.Gpi{Begin|End|Stoke}Path() ,
Gpi{Query|Set}LineWidthGeom() ,
GpiSetLine{End|Join} , implement
GC.{get|set}LineWidth ,
{get|set}XORMode() |
Done [dmik] | |
Readress the Decorations.redraw() methods to the
client window; add OS.WinEnableWindowUpdate() , implement
Control.setRedraw() ; add
OS.WinIsWindowShowing() , implement
Control.isShowing() |
Done [dmik] | |
Add OS.GpiQueryClipBox() ,
GpiSetClipRegion() , GpiQueryRegionBox() ,
GpiCombineRegion() , GpiPtInRegion() and
PRGN_* constants, GpiRectInRegion() abd
RRGN_* constants; implement the o.e.swt.graphics.Region
class, implement GC.{get|set}Clipping() ; add testcase
SWT003_03 to test clipping |
Done [dmik] | Region class is fully implemented. However, there's a
potential question about using regions with other devices than the
screen (since OS/2 requires the presentation space to be specified
when operating regions, the screen PS is used for this purpose). |
Move the frame class and window procedure definition code from the
Shell to the Decorations class |
Will be done on next steps | Decorations is logically a frame too. And if it will
be used/subclassed directly (i.e. not by the Shell ) then
we need this code in it. |
Try to re-enable SWT.CLIP_SIBLINGS and
SWT.CLIP_CHILDREN styles recognition in
Control.widgetStyle() , and remove forcing them in
Composite.WM_PAINT() and
Composite.widgetStyle() |
Will be done on next steps | In Windows version it is intentionally commented because: "When strict clipping was not enforced on all widgets, poorly written application code could draw outside of the control". Is it the same in OS/2? Possibly, not. |