source: trunk/doc/swt003.html@ 9

Last change on this file since 9 was 9, checked in by lpino, 18 years ago
  • Initial commit
File size: 20.6 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<?xml-stylesheet type="text/css"
3href="eclipseos2-xxe.css"
4?>
5<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
6"xhtml1-strict.dtd">
7<html>
8 <head>
9 <link href="eclipseos2.css" rel="stylesheet" type="text/css" />
10
11 <title>Eclipse for OS/2 Transitional Project Notes</title>
12 </head>
13
14 <body>
15 <h1>SWT Step 3. Basics of GUI, part 2</h1>
16
17 <h2>Objective</h2>
18
19 <p>Implement basic visualization facilities such as primitive drawing. In
20 particular, this means the implementation of
21 <code>o.e.swt.graphics.GC</code> [#Base] class. The test example of this
22 step should be able to create an SWT top window and draw some graphic
23 primitives in it.</p>
24
25 <h2>Task notes</h2>
26
27 <h3><a name="FrameClientWindow">Frame client window (obsolete)</a></h3>
28
29 <p>In OS/2, as opposed to Windows (at least from the API point of view),
30 the client part of the frame window (the area where the custom drawing
31 takes place) is the separate window with its own window class and
32 procedure. SWT uses the Windows approach and therefore the frame window
33 (i.e. <code>Decorations</code> and <code>Shell</code> widgets) should
34 encapsulate the client window functionality to be as a whole for the user.
35 To achieve this the client window, an instance of the special
36 <code>ClientArea</code> class (which is derived from the
37 <code>Composite</code>), is anonymously created by the
38 <code>Decorations.createHandle()</code> method. "Anonymously" means that
39 this instance is unaccessible anywhere outside the
40 <code>Decorations</code> class. The special feature of the
41 <code>ClientArea</code> class is that it uses its parent's (i.e. the
42 <code>Decorations</code>) event table and, when sending or posting
43 messages, sets the <code>Event.widget</code> field to the value of
44 <code>parent</code> rather than <code>this</code>. This means that all
45 events (specifically, the <code>SWT.Paint</code> event) generated by the
46 client window look as <code>Decorations</code> events to the user (and
47 directed to listeners registered on the <code>Decorations</code>
48 instance).</p>
49
50 <h3>Window presentation space</h3>
51
52 <p>The presentation space handle to do low level painting in the window is
53 obtained via the <code>Control.internal_new_GC()</code> method and must be
54 freed by the <code>Control.internal_dispose_GC()</code> method when no
55 more needed. The logic of work of these two methods is as follows:</p>
56
57 <ul>
58 <li>if <code>data</code> argument is <code>null</code> or
59 <code>data.rcl</code> is <code>null</code> then <code>WinGetPS()</code>
60 is used to obtain the presentation space handle and
61 <code>WinReleasePS()</code> -- to release it. Otherwise
62 <code>WinBeginPaint()</code> obtains a handle, reusing
63 <code>data.hps</code> (if not <code>null)</code> and filling
64 <code>data.rcl</code> with the updating rectangle, and
65 <code>WinEndPaint()</code> releases the presentation space
66 obtained.</li>
67
68 <li><code>WinGetPS()</code> and <code>WinBeginPaint()</code> use
69 <code>data.hwnd</code>, if it is not zero, as the window handle to
70 obtain the presentation space for. Otherwise <code>Control.handle</code>
71 is used. The latter is the normal behavior (i.e. <code>data.hwnd</code>
72 should normally be zero), the former can be used to substitute the
73 handle in subclasses when obtaining the presentation space handle (it is
74 not currently used and may be removed in the future).</li>
75
76 <li>Also, If <code>data</code> is not <code>null</code>,
77 <code>data.device</code> is assigned to the return value of
78 <code>getDevice()</code> and <code>data.hdc</code> is filled with the
79 device context handle returned by <code>GpiQueryDevice()</code> for the
80 presentation space obtained above.</li>
81 </ul>
82
83 <h4>WM_PAINT message</h4>
84
85 <p>In the Windows version, the <code>WM_PAINT</code> handler uses the
86 device context obtained via the <code>BeginPaint()</code> API call, which
87 initializes it with default attributes. To setup the correct graphics
88 context (a pen, brush, etc.) the <code>GC.win32_new()</code> method is
89 called every time when the <code>WM_PAINT</code> message occurs. Although
90 the same technique can be used in OS/2 too (and the existing code is ready
91 to do it) at the present time the "long-term" presentation space is used
92 to save attributes between <code>WM_PAINT</code> messages (and for some
93 other purposes). This presentation space is allocated only once (lazily in
94 the <code>WM_PAINT</code> handler) for every <code>Control</code> widget
95 which has at least one <code>SWT.Paint</code> event listener registered,
96 and it is released when the widget is being destroyed. However, the
97 <code>Composite</code> class (and its descendants, of course) allocates
98 such presentation space even if no <code>SWT.Paint</code> listeners are
99 registered, to draw the background (this behavior may change in the
100 future). This approach should lead to a better performance since no calls
101 to setup attributes on every paint message (except the first one) are made
102 (the <code>GCData.doInit</code> field is used by <code>GC.pm_new()</code>
103 and the <code>WM_PAINT</code> handler to indicate the need to setup the
104 presentation space). At the same time, this should not cause the increase
105 of memory usage because the presentation space is obtained via the
106 <code>WinGetPS()</code> call, which returns the cached presentation
107 space.</p>
108
109 <p>Besides other things, the long-term presentation space is used to store
110 the default view transformation matrix to do the automatic coordinate
111 space flipping when using <code>Gpi*</code> functions for painting (see
112 also <a href="swt002.html#ScreenCoordinates">here</a>). It allows to
113 update the matrix only when the window is resized instead of doing it on
114 every paint message.</p>
115
116 <h3><a name="GraphicPrimitives">Graphic primitives (obsolete)</a></h3>
117
118 <p>There is some muddle with dimensions of graphic primitives in the Win32
119 version of SWT: for example, the javadoc says that
120 <code>GC.drawRoundRectangle()</code>draws a rectangle, those left and
121 right edges are at <kbd>x</kbd> and <kbd>x + width</kbd>, top and bottom
122 edges are at <kbd>y</kbd> and <kbd>y + height</kbd>. But it's not the case
123 -- actually, the right edge is at <kbd>x + width - 1</kbd>, and the bottom
124 one is at <kbd>y + height - 1</kbd>, i.e. the horizontal and vertical size
125 is one pixel smaller than it stated. Besides this, all <code>fill*</code>
126 versions of primitives draw figures one pixel smaller in size than their
127 <code>draw*</code> versions, i.e. the rectangle drawn by
128 <code>GC.fillRectangle(0,0,10,10)</code> is not the same in size as by
129 <code>GC.drawRectangle(0,0,10,10)</code> -- the size of the former is 11
130 by 11 pixels while the size of the latter is 10 by 10. The docs just say
131 that <code>fill*</code> versions fill the interior of a primitive, but we
132 see no reasons for the interior to be one pixel smaller than the outline
133 (although it's an expected behavior of the corresponding Win32 API calls,
134 but not OS/2 ones). Also, there are errors when drawing very small figures
135 (few pixels in size) and figures with the negative width and/or height
136 (see the <code>SWT003_01</code> example). Most of these things look just
137 like bugs, so in OS/2 version we decided to fix them until any
138 incompatibility issue appears. "To fix" here means that the bounding
139 rectangle of all primitives in the OS/2 version of SWT always follows the
140 rule stated in the javadoc for <code>GC.drawRectangle()</code> about the
141 edges and covers an area <kbd>width + 1</kbd> pixels wide by <kbd>height +
142 1</kbd> pixels tall.</p>
143
144 <h3>Colors</h3>
145
146 <p>In the Win32 version of SWT, if the device is in the palette mode (that
147 is, when it can display only 256 distinct colors simultaneously) and we
148 try to create new colors inside the paint event listener (as we draw in a
149 window) these colors will not appear on the screen until the next window
150 invalidation (see the <code>SWT003_02</code> example). It is because new
151 colors are being added to the physical palette when it's already selected
152 to the device context at the beginning of the paint event handling and
153 won't be selected again until the next paint event. In the OS/2 version we
154 solve this problem by posting the <code>WM_REALIZEPALETTE</code> message
155 to every <code>Shell</code> widget when the new color is created, which
156 causes widgets to invalidate themselves.</p>
157
158 <h3>Styled lines</h3>
159
160 <p>In Windows, when drawing styled lines (dotted, dashed etc.) intervals
161 between sytle segments are considered to be the "background" of the line
162 and therefore are drawn by the current brush (see the SWT003_01 example).
163 In OS/2 they are considered to be transparent and this behavior cannot be
164 altered. Due to the inefficiency of the only possible application-level
165 implementation of this functionality it is left as is at the present.</p>
166
167 <h2>Step checklist</h2>
168
169 <table>
170 <col width="40%" />
171
172 <col />
173
174 <col width="50%" />
175
176 <thead>
177 <tr>
178 <th>Operation</th>
179
180 <th>Status</th>
181
182 <th>Remarks</th>
183 </tr>
184 </thead>
185
186 <tr>
187 <td>Implement <code>OS.WinWindowFromID()</code> and <code>FID_*</code>
188 constants</td>
189
190 <td>Done [dmik]</td>
191
192 <td></td>
193 </tr>
194
195 <tr>
196 <td>Implement the frame client window creation and the message routing
197 for it</td>
198
199 <td>Done [dmik]</td>
200
201 <td></td>
202 </tr>
203
204 <tr>
205 <td>Add <code>OS.GpiCreateRegion()</code>,
206 <code>WinQueryUpdateRegion()</code>,
207 <code>WinInvalidateRegion()</code> and <code>RGN_*
208 </code>constants</td>
209
210 <td>Done [dmik]</td>
211
212 <td>The <code>RECTL</code> structure (which is originally passed as a
213 pointer) is passed as an <code>int</code> array (with four elements)
214 from Java to simplify access to it from the native
215 implementation.</td>
216 </tr>
217
218 <tr>
219 <td>Add <code>OS.GpiQueryRegionRects()</code>, <code>RGNRECT</code>
220 class, <code>RECTDIR_*</code> constants</td>
221
222 <td>Done [dmik]</td>
223
224 <td></td>
225 </tr>
226
227 <tr>
228 <td>Implement <code>WM_PAINT</code> message handling and
229 <code>SWT.Paint</code> event firing</td>
230
231 <td>Done [dmik]</td>
232
233 <td></td>
234 </tr>
235
236 <tr>
237 <td>Implement <code>OS.WinGetMaxPosition()</code></td>
238
239 <td>Done [dmik]</td>
240
241 <td>Used to implement the <code>Display.getClientArea()</code> method,
242 which returns the size and position of maximized windows of the
243 desktop. These values can differ from
244 <code>Display.getBounds()</code>, e.g. when XCenter is running. Note:
245 XCenter 1.0.1 has a strange feature -- it reduces the maximum height
246 (reported by <code>WinGetMaxPosition()</code>) by the value of its own
247 height plus additional 5 pixels, therefore the reported maximum height
248 is 5 pixels less than the actual. Possibly, it's a bug.</td>
249 </tr>
250
251 <tr>
252 <td>Implement <code>Device.getBounds()</code>,
253 <code>getClientArea()</code> for <code>Device</code>,
254 <code>Display</code> and controls that support this</td>
255
256 <td>Done [dmik]</td>
257
258 <td><code>Scrollable.getClientArea()</code> code is temporary (should
259 take the scrollers into account)</td>
260 </tr>
261
262 <tr>
263 <td>Add <code>OS.GpiMove</code>, <code>OS.GpiBox</code>,
264 <code>GPI_*</code> and <code>DRO_*</code> constants, implement
265 <code>GC.{fill|draw}[Round]Rectangle()</code> methods</td>
266
267 <td>Done [dmik]</td>
268
269 <td><code>POINTL</code> structures are passed as arrays of
270 <code>int</code> with two elements (x and y).</td>
271 </tr>
272
273 <tr>
274 <td>Add <code>WM_CALCVALIDRECTS</code> message handling,
275 <code>OS.CVR_*</code> constants</td>
276
277 <td>Done [dmik]</td>
278
279 <td><code>Composite</code> instance returns <code>CVR_REDRAW</code> on
280 <code>WM_CALCVALIDRECTS</code> if it has the <code>CANVAS</code> state
281 and no <code>SWT.NO_REDRAW_RESIZE</code> style to completely
282 invalidate itself when resizing.</td>
283 </tr>
284
285 <tr>
286 <td>Create the draft <code>SWT003</code> testcase</td>
287
288 <td>Done [dmik]</td>
289
290 <td></td>
291 </tr>
292
293 <tr>
294 <td>Fix the bug of <code>GpiBox()</code></td>
295
296 <td>Done [dmik]</td>
297
298 <td><code>GpiBox()</code> draws the rectangle 1 pixel higher than it
299 should do, when rounded corners and <code>DRO_FILL</code> or
300 <code>DRO_OUTLINEFILL</code> are specified.</td>
301 </tr>
302
303 <tr>
304 <td>Add the long-term presentation space creation for a
305 <code>Control</code> object</td>
306
307 <td>Done [dmik]</td>
308
309 <td></td>
310 </tr>
311
312 <tr>
313 <td>Implement <code>OS.GpiSetDefaultViewMatrix()</code>,
314 <code>TRANSFORM_*</code> constants</td>
315
316 <td>Done [dmik]</td>
317
318 <td>Necessary for automatic coordinate space flipping.</td>
319 </tr>
320
321 <tr>
322 <td>Add <code>OS.SHORT{1|2}FROMMP</code> pseudo macros</td>
323
324 <td>Done [dmik]</td>
325
326 <td></td>
327 </tr>
328
329 <tr>
330 <td>Add the <code>o.e.swt.widgets.ClientArea</code> class</td>
331
332 <td>Done [dmik]</td>
333
334 <td>This class represents the frame client window.</td>
335 </tr>
336
337 <tr>
338 <td>Implement <code>OS.DevQueryCaps()</code> and <code>CAPS_*</code>
339 constants</td>
340
341 <td>Done [dmik]</td>
342
343 <td>Currently, constants are almost fully commented -- uncomment when
344 needed.</td>
345 </tr>
346
347 <tr>
348 <td>Overload <code>OS.WinSendMsg()</code> with one, that takes
349 <code>OS.RECTL</code> as the first message parameter</td>
350
351 <td>Done [dmik]</td>
352
353 <td>Currently used to send <code>WM_CALCFRAMERECT</code> message.</td>
354 </tr>
355
356 <tr>
357 <td>Add <code>OS.GpiCreatePalette()</code>,
358 <code>GpiDeletePalette()</code>, <code>LCOL_*</code> and
359 <code>LCOLF_*</code> constants,
360 <code>GpiQueryNearestPaletteIndex()</code>,
361 <code>GpiQueryPaletteInfo()</code>,
362 <code>GpiSetPaletteEntries()</code>, <code>GpiSelectPalette()</code>,
363 <code>GpiCreateLogColorTable()</code>,
364 <code>WinRealizePalette()</code></td>
365
366 <td>Done [dmik]</td>
367
368 <td>Note: <code>GpiQueryNearestPaletteIndex()</code> is undocumented.
369 We hope it presents in Warp4 and earlier OS/2 versions...</td>
370 </tr>
371
372 <tr>
373 <td>Add <code>OS.GpiQueryColor()</code>, <code>GpiSetColor()</code>,
374 <code>GpiQueryBackColor()</code>, <code>GpiSetBackColor()</code>,
375 <code>GpiQieryMix()</code>, <code>GpiSetMix()</code>,
376 <code>FM_*</code> constants, <code>GpiQueryBackMix()</code>,
377 <code>GpiSetBackMix()</code>, <code>BM_*</code> constants,
378 <code>GpiQueryPattern()</code>, <code>GpiSetPattern()</code>,
379 <code>PATSYM_*</code> constants</td>
380
381 <td>Done [dmik]</td>
382
383 <td></td>
384 </tr>
385
386 <tr>
387 <td>Add <code>WM_REALIZEPALETTE</code> message handling, implement
388 <code>{get|set}{Foreground|Background}()</code> methods of
389 <code>Control</code> and <code>GC</code> classes,
390 <code>OS.WinQuerySysColor()</code> and <code>SYSCLR_*</code>
391 constants</td>
392
393 <td>Done [dmik]</td>
394
395 <td></td>
396 </tr>
397
398 <tr>
399 <td>Add the <code>GC.Color</code> class and implement color
400 handling</td>
401
402 <td>Done [dmik]</td>
403
404 <td></td>
405 </tr>
406
407 <tr>
408 <td>Add <code>OS.GpiLine()</code>, <code>GpiBeginArea()</code>,
409 <code>GpiEndArea()</code>, <code>GpiPartialArc()</code>,
410 <code>GpiSetArcParams()</code>,
411 <code>GpiQueryCurrentPosition()</code>, implement
412 <code>GC.drawLine()</code>, <code>{draw|fill}Arc()</code>,
413 <code>{draw|fill}Oval()</code> methods</td>
414
415 <td>Done [dmik]</td>
416
417 <td><code>ARCPARAMS</code> structure is passed to
418 <code>GpiSetArcParams()</code> as an array of
419 <code>int[4]</code>.</td>
420 </tr>
421
422 <tr>
423 <td>Create <code>TestCase</code> and <code>SWTTestCase</code> classes
424 to simplify test case writing, remove the <code>SWT003</code> tescase
425 and create <code>SWT003_01</code> and <code>SWT003_02</code> instead,
426 update the <code>SWT004</code> testcase</td>
427
428 <td>Done [dmik]</td>
429
430 <td>If the step requires several different testcases each with its own
431 top shell window, it's possible to do so, naming them as
432 <code>SWTXXX_YY</code> where XXX is the step number and YY is the
433 number of the testcase. Such testcases can be run as usual, specifying
434 the step name in the format above via the <kbd>test.step</kbd>
435 property in the <kbd>build.prp</kbd> file or on the command line.</td>
436 </tr>
437
438 <tr>
439 <td>Add <code>OS.GpiPolyLine()</code>, implement
440 <code>GC.getBackground()</code>, <code>getForeground()</code>,
441 <code>drawPolyline()</code>, <code>drawPolygon()</code>,
442 <code>fillPolygon()</code></td>
443
444 <td>Done [dmik]</td>
445
446 <td></td>
447 </tr>
448
449 <tr>
450 <td>Add <code>OS.Gpi{Query|Set}LineType()</code>,
451 <code>LINETYPE_*</code> constants, implement
452 <code>GC.{get|set}LineStyle()</code>, <code>drawFocus()</code></td>
453
454 <td>Done [dmik]</td>
455
456 <td></td>
457 </tr>
458
459 <tr>
460 <td>Add <code>OS.Gpi{Begin|End|Stoke}Path()</code>,
461 <code>Gpi{Query|Set}LineWidthGeom()</code>,
462 <code>GpiSetLine{End|Join}</code>, implement
463 <code>GC.{get|set}LineWidth</code>,
464 <code>{get|set}XORMode()</code></td>
465
466 <td>Done [dmik]</td>
467
468 <td></td>
469 </tr>
470
471 <tr>
472 <td>Readress the <code>Decorations.redraw()</code> methods to the
473 client window; add <code>OS.WinEnableWindowUpdate()</code>, implement
474 <code>Control.setRedraw()</code>; add
475 <code>OS.WinIsWindowShowing()</code>, implement
476 <code>Control.isShowing()</code></td>
477
478 <td>Done [dmik]</td>
479
480 <td></td>
481 </tr>
482
483 <tr>
484 <td>Add <code>OS.GpiQueryClipBox()</code>,
485 <code>GpiSetClipRegion()</code>, <code>GpiQueryRegionBox()</code>,
486 <code>GpiCombineRegion()</code>, <code>GpiPtInRegion()</code> and
487 <code>PRGN_*</code> constants, <code>GpiRectInRegion()</code> abd
488 <code>RRGN_*</code> constants; implement the o.e.swt.graphics.Region
489 class, implement <code>GC.{get|set}Clipping()</code>; add testcase
490 <code>SWT003_03</code> to test clipping</td>
491
492 <td>Done [dmik]</td>
493
494 <td><code>Region</code> class is fully implemented. However, there's a
495 potential question about using regions with other devices than the
496 screen (since OS/2 requires the presentation space to be specified
497 when operating regions, the screen PS is used for this purpose).</td>
498 </tr>
499
500 <tr>
501 <td>Move the frame class and window procedure definition code from the
502 <code>Shell</code> to the <code>Decorations</code> class</td>
503
504 <td>Will be done on next steps</td>
505
506 <td><code>Decorations</code> is logically a frame too. And if it will
507 be used/subclassed directly (i.e. not by the <code>Shell</code>) then
508 we need this code in it.</td>
509 </tr>
510
511 <tr>
512 <td>Try to re-enable <code>SWT.CLIP_SIBLINGS</code> and
513 <code>SWT.CLIP_CHILDREN</code> styles recognition in
514 <code>Control.widgetStyle()</code>, and remove forcing them in
515 <code>Composite.WM_PAINT()</code> and
516 <code>Composite.widgetStyle()</code></td>
517
518 <td>Will be done on next steps</td>
519
520 <td>In Windows version it is intentionally commented because: "When
521 strict clipping was not enforced on all widgets, poorly written
522 application code could draw outside of the control". Is it the same in
523 OS/2? Possibly, not.</td>
524 </tr>
525 </table>
526 </body>
527</html>
Note: See TracBrowser for help on using the repository browser.