1 /*
2 * Copyright 2001-2019 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Stephan Aßmus, superstippi@gmx.de
7 * Axel Dörfler, axeld@pinc-software.de
8 * Adrian Oanca, adioanca@cotty.iren.ro
9 * Ingo Weinhold. ingo_weinhold@gmx.de
10 * Julian Harnath, julian.harnath@rwth-aachen.de
11 * Joseph Groover, looncraz@looncraz.net
12 */
13
14
15 #include <View.h>
16
17 #include <algorithm>
18 #include <new>
19
20 #include <math.h>
21 #include <stdio.h>
22
23 #include <Application.h>
24 #include <Bitmap.h>
25 #include <Button.h>
26 #include <Cursor.h>
27 #include <File.h>
28 #include <GradientLinear.h>
29 #include <GradientRadial.h>
30 #include <GradientRadialFocus.h>
31 #include <GradientDiamond.h>
32 #include <GradientConic.h>
33 #include <InterfaceDefs.h>
34 #include <Layout.h>
35 #include <LayoutContext.h>
36 #include <LayoutUtils.h>
37 #include <MenuBar.h>
38 #include <Message.h>
39 #include <MessageQueue.h>
40 #include <ObjectList.h>
41 #include <Picture.h>
42 #include <Point.h>
43 #include <Polygon.h>
44 #include <PropertyInfo.h>
45 #include <Region.h>
46 #include <ScrollBar.h>
47 #include <Shape.h>
48 #include <Shelf.h>
49 #include <String.h>
50 #include <Window.h>
51
52 #include <AppMisc.h>
53 #include <AppServerLink.h>
54 #include <binary_compatibility/Interface.h>
55 #include <binary_compatibility/Support.h>
56 #include <MessagePrivate.h>
57 #include <MessageUtils.h>
58 #include <PortLink.h>
59 #include <ServerProtocol.h>
60 #include <ServerProtocolStructs.h>
61 #include <ShapePrivate.h>
62 #include <ToolTip.h>
63 #include <ToolTipManager.h>
64 #include <TokenSpace.h>
65 #include <ViewPrivate.h>
66
67 using std::nothrow;
68
69 //#define DEBUG_BVIEW
70 #ifdef DEBUG_BVIEW
71 # include <stdio.h>
72 # define STRACE(x) printf x
73 # define BVTRACE _PrintToStream()
74 #else
75 # define STRACE(x) ;
76 # define BVTRACE ;
77 #endif
78
79
80 static property_info sViewPropInfo[] = {
81 { "Frame", { B_GET_PROPERTY, B_SET_PROPERTY },
82 { B_DIRECT_SPECIFIER, 0 }, "The view's frame rectangle.", 0,
83 { B_RECT_TYPE }
84 },
85 { "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY },
86 { B_DIRECT_SPECIFIER, 0 }, "Whether or not the view is hidden.",
87 0, { B_BOOL_TYPE }
88 },
89 { "Shelf", { 0 },
90 { B_DIRECT_SPECIFIER, 0 }, "Directs the scripting message to the "
91 "shelf.", 0
92 },
93 { "View", { B_COUNT_PROPERTIES, 0 },
94 { B_DIRECT_SPECIFIER, 0 }, "Returns the number of child views.", 0,
95 { B_INT32_TYPE }
96 },
97 { "View", { 0 },
98 { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, 0 },
99 "Directs the scripting message to the specified view.", 0
100 },
101
102 { 0 }
103 };
104
105
106 // #pragma mark -
107
108
109 static inline uint32
get_uint32_color(rgb_color color)110 get_uint32_color(rgb_color color)
111 {
112 return B_BENDIAN_TO_HOST_INT32(*(uint32*)&color);
113 // rgb_color is always in rgba format, no matter what endian;
114 // we always return the int32 value in host endian.
115 }
116
117
118 static inline rgb_color
get_rgb_color(uint32 value)119 get_rgb_color(uint32 value)
120 {
121 value = B_HOST_TO_BENDIAN_INT32(value);
122 return *(rgb_color*)&value;
123 }
124
125
126 // #pragma mark -
127
128
129 namespace BPrivate {
130
ViewState()131 ViewState::ViewState()
132 {
133 pen_location.Set(0, 0);
134 pen_size = 1.0;
135
136 // NOTE: the clipping_region is empty
137 // on construction but it is not used yet,
138 // we avoid having to keep track of it via
139 // this flag
140 clipping_region_used = false;
141
142 high_color = (rgb_color){ 0, 0, 0, 255 };
143 low_color = (rgb_color){ 255, 255, 255, 255 };
144 view_color = low_color;
145 which_view_color = B_NO_COLOR;
146 which_view_color_tint = B_NO_TINT;
147
148 which_high_color = B_NO_COLOR;
149 which_high_color_tint = B_NO_TINT;
150
151 which_low_color = B_NO_COLOR;
152 which_low_color_tint = B_NO_TINT;
153
154 pattern = B_SOLID_HIGH;
155 drawing_mode = B_OP_COPY;
156
157 origin.Set(0, 0);
158
159 line_join = B_MITER_JOIN;
160 line_cap = B_BUTT_CAP;
161 miter_limit = B_DEFAULT_MITER_LIMIT;
162 fill_rule = B_NONZERO;
163
164 alpha_source_mode = B_PIXEL_ALPHA;
165 alpha_function_mode = B_ALPHA_OVERLAY;
166
167 scale = 1.0;
168
169 font = *be_plain_font;
170 font_flags = font.Flags();
171 font_aliasing = false;
172
173 parent_composite_transform.Reset();
174 parent_composite_scale = 1.0f;
175 parent_composite_origin.Set(0, 0);
176
177 // We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated,
178 // because we should get the clipping region from app_server.
179 // The other flags do not need to be included because the data they
180 // represent is already in sync with app_server - app_server uses the
181 // same init (default) values.
182 valid_flags = ~B_VIEW_CLIP_REGION_BIT;
183
184 archiving_flags = B_VIEW_FRAME_BIT | B_VIEW_RESIZE_BIT;
185 }
186
187
188 void
UpdateServerFontState(BPrivate::PortLink & link)189 ViewState::UpdateServerFontState(BPrivate::PortLink &link)
190 {
191 link.StartMessage(AS_VIEW_SET_FONT_STATE);
192 link.Attach<uint16>(font_flags);
193 // always present
194
195 if (font_flags & B_FONT_FAMILY_AND_STYLE)
196 link.Attach<uint32>(font.FamilyAndStyle());
197
198 if (font_flags & B_FONT_SIZE)
199 link.Attach<float>(font.Size());
200
201 if (font_flags & B_FONT_SHEAR)
202 link.Attach<float>(font.Shear());
203
204 if (font_flags & B_FONT_ROTATION)
205 link.Attach<float>(font.Rotation());
206
207 if (font_flags & B_FONT_FALSE_BOLD_WIDTH)
208 link.Attach<float>(font.FalseBoldWidth());
209
210 if (font_flags & B_FONT_SPACING)
211 link.Attach<uint8>(font.Spacing());
212
213 if (font_flags & B_FONT_ENCODING)
214 link.Attach<uint8>(font.Encoding());
215
216 if (font_flags & B_FONT_FACE)
217 link.Attach<uint16>(font.Face());
218
219 if (font_flags & B_FONT_FLAGS)
220 link.Attach<uint32>(font.Flags());
221 }
222
223
224 void
UpdateServerState(BPrivate::PortLink & link)225 ViewState::UpdateServerState(BPrivate::PortLink &link)
226 {
227 UpdateServerFontState(link);
228
229 link.StartMessage(AS_VIEW_SET_STATE);
230
231 ViewSetStateInfo info;
232 info.penLocation = pen_location;
233 info.penSize = pen_size;
234 info.highColor = high_color;
235 info.lowColor = low_color;
236 info.whichHighColor = which_high_color;
237 info.whichLowColor = which_low_color;
238 info.whichHighColorTint = which_high_color_tint;
239 info.whichLowColorTint = which_low_color_tint;
240 info.pattern = pattern;
241 info.drawingMode = drawing_mode;
242 info.origin = origin;
243 info.scale = scale;
244 info.lineJoin = line_join;
245 info.lineCap = line_cap;
246 info.miterLimit = miter_limit;
247 info.fillRule = fill_rule;
248 info.alphaSourceMode = alpha_source_mode;
249 info.alphaFunctionMode = alpha_function_mode;
250 info.fontAntialiasing = font_aliasing;
251 link.Attach<ViewSetStateInfo>(info);
252
253 // BAffineTransform is transmitted as a double array
254 double _transform[6];
255 if (transform.Flatten(_transform, sizeof(_transform)) != B_OK)
256 return;
257 link.Attach<double[6]>(_transform);
258
259 // we send the 'local' clipping region... if we have one...
260 // TODO: Could be optimized, but is low prio, since most views won't
261 // have a custom clipping region.
262 if (clipping_region_used) {
263 int32 count = clipping_region.CountRects();
264 link.Attach<int32>(count);
265 for (int32 i = 0; i < count; i++)
266 link.Attach<BRect>(clipping_region.RectAt(i));
267 } else {
268 // no clipping region
269 link.Attach<int32>(-1);
270 }
271
272 // Although we might have a 'local' clipping region, when we call
273 // BView::GetClippingRegion() we ask for the 'global' one and it
274 // is kept on server, so we must invalidate B_VIEW_CLIP_REGION_BIT flag
275
276 valid_flags = ~B_VIEW_CLIP_REGION_BIT;
277 }
278
279
280 void
UpdateFrom(BPrivate::PortLink & link)281 ViewState::UpdateFrom(BPrivate::PortLink &link)
282 {
283 link.StartMessage(AS_VIEW_GET_STATE);
284
285 int32 code;
286 if (link.FlushWithReply(code) != B_OK
287 || code != B_OK)
288 return;
289
290 ViewGetStateInfo info;
291 link.Read<ViewGetStateInfo>(&info);
292
293 // set view's font state
294 font_flags = B_FONT_ALL;
295 font.SetFamilyAndStyle(info.fontID);
296 font.SetSize(info.fontSize);
297 font.SetShear(info.fontShear);
298 font.SetRotation(info.fontRotation);
299 font.SetFalseBoldWidth(info.fontFalseBoldWidth);
300 font.SetSpacing(info.fontSpacing);
301 font.SetEncoding(info.fontEncoding);
302 font.SetFace(info.fontFace);
303 font.SetFlags(info.fontFlags);
304
305 // set view's state
306 pen_location = info.viewStateInfo.penLocation;
307 pen_size = info.viewStateInfo.penSize;
308 high_color = info.viewStateInfo.highColor;
309 low_color = info.viewStateInfo.lowColor;
310 pattern = info.viewStateInfo.pattern;
311 drawing_mode = info.viewStateInfo.drawingMode;
312 origin = info.viewStateInfo.origin;
313 scale = info.viewStateInfo.scale;
314 line_join = info.viewStateInfo.lineJoin;
315 line_cap = info.viewStateInfo.lineCap;
316 miter_limit = info.viewStateInfo.miterLimit;
317 fill_rule = info.viewStateInfo.fillRule;
318 alpha_source_mode = info.viewStateInfo.alphaSourceMode;
319 alpha_function_mode = info.viewStateInfo.alphaFunctionMode;
320 font_aliasing = info.viewStateInfo.fontAntialiasing;
321
322 // BAffineTransform is transmitted as a double array
323 double _transform[6];
324 link.Read<double[6]>(&_transform);
325 if (transform.Unflatten(B_AFFINE_TRANSFORM_TYPE, _transform,
326 sizeof(_transform)) != B_OK) {
327 return;
328 }
329
330 // read the user clipping
331 // (that's NOT the current View visible clipping but the additional
332 // user specified clipping!)
333 int32 clippingRectCount;
334 link.Read<int32>(&clippingRectCount);
335 if (clippingRectCount >= 0) {
336 clipping_region.MakeEmpty();
337 for (int32 i = 0; i < clippingRectCount; i++) {
338 BRect rect;
339 link.Read<BRect>(&rect);
340 clipping_region.Include(rect);
341 }
342 } else {
343 // no user clipping used
344 clipping_region_used = false;
345 }
346
347 valid_flags = ~(B_VIEW_CLIP_REGION_BIT | B_VIEW_PARENT_COMPOSITE_BIT)
348 | (valid_flags & B_VIEW_PARENT_COMPOSITE_BIT);
349 }
350
351 } // namespace BPrivate
352
353
354 // #pragma mark -
355
356
357 // archiving constants
358 namespace {
359 const char* const kSizesField = "BView:sizes";
360 // kSizesField = {min, max, pref}
361 const char* const kAlignmentField = "BView:alignment";
362 const char* const kLayoutField = "BView:layout";
363 }
364
365
366 struct BView::LayoutData {
LayoutDataBView::LayoutData367 LayoutData()
368 :
369 fMinSize(),
370 fMaxSize(),
371 fPreferredSize(),
372 fAlignment(),
373 fLayoutInvalidationDisabled(0),
374 fLayout(NULL),
375 fLayoutContext(NULL),
376 fLayoutItems(5, false),
377 fLayoutValid(true), // TODO: Rethink these initial values!
378 fMinMaxValid(true), //
379 fLayoutInProgress(false),
380 fNeedsRelayout(true)
381 {
382 }
383
384 status_t
AddDataToArchiveBView::LayoutData385 AddDataToArchive(BMessage* archive)
386 {
387 status_t err = archive->AddSize(kSizesField, fMinSize);
388
389 if (err == B_OK)
390 err = archive->AddSize(kSizesField, fMaxSize);
391
392 if (err == B_OK)
393 err = archive->AddSize(kSizesField, fPreferredSize);
394
395 if (err == B_OK)
396 err = archive->AddAlignment(kAlignmentField, fAlignment);
397
398 return err;
399 }
400
401 void
PopulateFromArchiveBView::LayoutData402 PopulateFromArchive(BMessage* archive)
403 {
404 archive->FindSize(kSizesField, 0, &fMinSize);
405 archive->FindSize(kSizesField, 1, &fMaxSize);
406 archive->FindSize(kSizesField, 2, &fPreferredSize);
407 archive->FindAlignment(kAlignmentField, &fAlignment);
408 }
409
410 BSize fMinSize;
411 BSize fMaxSize;
412 BSize fPreferredSize;
413 BAlignment fAlignment;
414 int fLayoutInvalidationDisabled;
415 BLayout* fLayout;
416 BLayoutContext* fLayoutContext;
417 BObjectList<BLayoutItem> fLayoutItems;
418 bool fLayoutValid;
419 bool fMinMaxValid;
420 bool fLayoutInProgress;
421 bool fNeedsRelayout;
422 };
423
424
BView(const char * name,uint32 flags,BLayout * layout)425 BView::BView(const char* name, uint32 flags, BLayout* layout)
426 :
427 BHandler(name)
428 {
429 _InitData(BRect(0, 0, -1, -1), name, B_FOLLOW_NONE,
430 flags | B_SUPPORTS_LAYOUT);
431 SetLayout(layout);
432 }
433
434
BView(BRect frame,const char * name,uint32 resizingMode,uint32 flags)435 BView::BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags)
436 :
437 BHandler(name)
438 {
439 _InitData(frame, name, resizingMode, flags);
440 }
441
442
BView(BMessage * archive)443 BView::BView(BMessage* archive)
444 :
445 BHandler(BUnarchiver::PrepareArchive(archive))
446 {
447 BUnarchiver unarchiver(archive);
448 if (!archive)
449 debugger("BView cannot be constructed from a NULL archive.");
450
451 BRect frame;
452 archive->FindRect("_frame", &frame);
453
454 uint32 resizingMode;
455 if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK)
456 resizingMode = 0;
457
458 uint32 flags;
459 if (archive->FindInt32("_flags", (int32*)&flags) != B_OK)
460 flags = 0;
461
462 _InitData(frame, Name(), resizingMode, flags);
463
464 font_family family;
465 font_style style;
466 if (archive->FindString("_fname", 0, (const char**)&family) == B_OK
467 && archive->FindString("_fname", 1, (const char**)&style) == B_OK) {
468 BFont font;
469 font.SetFamilyAndStyle(family, style);
470
471 float size;
472 if (archive->FindFloat("_fflt", 0, &size) == B_OK)
473 font.SetSize(size);
474
475 float shear;
476 if (archive->FindFloat("_fflt", 1, &shear) == B_OK
477 && shear >= 45.0 && shear <= 135.0)
478 font.SetShear(shear);
479
480 float rotation;
481 if (archive->FindFloat("_fflt", 2, &rotation) == B_OK
482 && rotation >=0 && rotation <= 360)
483 font.SetRotation(rotation);
484
485 SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE
486 | B_FONT_SHEAR | B_FONT_ROTATION);
487 }
488
489 int32 color = 0;
490 if (archive->FindInt32("_color", 0, &color) == B_OK)
491 SetHighColor(get_rgb_color(color));
492 if (archive->FindInt32("_color", 1, &color) == B_OK)
493 SetLowColor(get_rgb_color(color));
494 if (archive->FindInt32("_color", 2, &color) == B_OK)
495 SetViewColor(get_rgb_color(color));
496
497 float tint = B_NO_TINT;
498 if (archive->FindInt32("_uicolor", 0, &color) == B_OK
499 && color != B_NO_COLOR) {
500 if (archive->FindFloat("_uitint", 0, &tint) != B_OK)
501 tint = B_NO_TINT;
502
503 SetHighUIColor((color_which)color, tint);
504 }
505 if (archive->FindInt32("_uicolor", 1, &color) == B_OK
506 && color != B_NO_COLOR) {
507 if (archive->FindFloat("_uitint", 1, &tint) != B_OK)
508 tint = B_NO_TINT;
509
510 SetLowUIColor((color_which)color, tint);
511 }
512 if (archive->FindInt32("_uicolor", 2, &color) == B_OK
513 && color != B_NO_COLOR) {
514 if (archive->FindFloat("_uitint", 2, &tint) != B_OK)
515 tint = B_NO_TINT;
516
517 SetViewUIColor((color_which)color, tint);
518 }
519
520 uint32 evMask;
521 uint32 options;
522 if (archive->FindInt32("_evmask", 0, (int32*)&evMask) == B_OK
523 && archive->FindInt32("_evmask", 1, (int32*)&options) == B_OK)
524 SetEventMask(evMask, options);
525
526 BPoint origin;
527 if (archive->FindPoint("_origin", &origin) == B_OK)
528 SetOrigin(origin);
529
530 float scale;
531 if (archive->FindFloat("_scale", &scale) == B_OK)
532 SetScale(scale);
533
534 BAffineTransform transform;
535 if (archive->FindFlat("_transform", &transform) == B_OK)
536 SetTransform(transform);
537
538 float penSize;
539 if (archive->FindFloat("_psize", &penSize) == B_OK)
540 SetPenSize(penSize);
541
542 BPoint penLocation;
543 if (archive->FindPoint("_ploc", &penLocation) == B_OK)
544 MovePenTo(penLocation);
545
546 int16 lineCap;
547 int16 lineJoin;
548 float lineMiter;
549 if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK
550 && archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK
551 && archive->FindFloat("_lmmiter", &lineMiter) == B_OK)
552 SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter);
553
554 int16 fillRule;
555 if (archive->FindInt16("_fillrule", &fillRule) == B_OK)
556 SetFillRule(fillRule);
557
558 int16 alphaBlend;
559 int16 modeBlend;
560 if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK
561 && archive->FindInt16("_blend", 1, &modeBlend) == B_OK)
562 SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend);
563
564 uint32 drawingMode;
565 if (archive->FindInt32("_dmod", (int32*)&drawingMode) == B_OK)
566 SetDrawingMode((drawing_mode)drawingMode);
567
568 fLayoutData->PopulateFromArchive(archive);
569
570 if (archive->FindInt16("_show", &fShowLevel) != B_OK)
571 fShowLevel = 0;
572
573 if (BUnarchiver::IsArchiveManaged(archive)) {
574 int32 i = 0;
575 while (unarchiver.EnsureUnarchived("_views", i++) == B_OK)
576 ;
577 unarchiver.EnsureUnarchived(kLayoutField);
578
579 } else {
580 BMessage msg;
581 for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK;
582 i++) {
583 BArchivable* object = instantiate_object(&msg);
584 if (BView* child = dynamic_cast<BView*>(object))
585 AddChild(child);
586 }
587 }
588 }
589
590
591 BArchivable*
Instantiate(BMessage * data)592 BView::Instantiate(BMessage* data)
593 {
594 if (!validate_instantiation(data , "BView"))
595 return NULL;
596
597 return new(std::nothrow) BView(data);
598 }
599
600
601 status_t
Archive(BMessage * data,bool deep) const602 BView::Archive(BMessage* data, bool deep) const
603 {
604 BArchiver archiver(data);
605 status_t ret = BHandler::Archive(data, deep);
606
607 if (ret != B_OK)
608 return ret;
609
610 if ((fState->archiving_flags & B_VIEW_FRAME_BIT) != 0)
611 ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset));
612
613 if (ret == B_OK)
614 ret = data->AddInt32("_resize_mode", ResizingMode());
615
616 if (ret == B_OK)
617 ret = data->AddInt32("_flags", Flags());
618
619 if (ret == B_OK && (fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) != 0) {
620 ret = data->AddInt32("_evmask", fEventMask);
621 if (ret == B_OK)
622 ret = data->AddInt32("_evmask", fEventOptions);
623 }
624
625 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FONT_BIT) != 0) {
626 BFont font;
627 GetFont(&font);
628
629 font_family family;
630 font_style style;
631 font.GetFamilyAndStyle(&family, &style);
632 ret = data->AddString("_fname", family);
633 if (ret == B_OK)
634 ret = data->AddString("_fname", style);
635 if (ret == B_OK)
636 ret = data->AddFloat("_fflt", font.Size());
637 if (ret == B_OK)
638 ret = data->AddFloat("_fflt", font.Shear());
639 if (ret == B_OK)
640 ret = data->AddFloat("_fflt", font.Rotation());
641 }
642
643 // colors
644 if (ret == B_OK)
645 ret = data->AddInt32("_color", get_uint32_color(HighColor()));
646 if (ret == B_OK)
647 ret = data->AddInt32("_color", get_uint32_color(LowColor()));
648 if (ret == B_OK)
649 ret = data->AddInt32("_color", get_uint32_color(ViewColor()));
650
651 if (ret == B_OK)
652 ret = data->AddInt32("_uicolor", (int32)HighUIColor());
653 if (ret == B_OK)
654 ret = data->AddInt32("_uicolor", (int32)LowUIColor());
655 if (ret == B_OK)
656 ret = data->AddInt32("_uicolor", (int32)ViewUIColor());
657
658 if (ret == B_OK)
659 ret = data->AddFloat("_uitint", fState->which_high_color_tint);
660 if (ret == B_OK)
661 ret = data->AddFloat("_uitint", fState->which_low_color_tint);
662 if (ret == B_OK)
663 ret = data->AddFloat("_uitint", fState->which_view_color_tint);
664
665 // NOTE: we do not use this flag any more
666 // if ( 1 ){
667 // ret = data->AddInt32("_dbuf", 1);
668 // }
669
670 if (ret == B_OK && (fState->archiving_flags & B_VIEW_ORIGIN_BIT) != 0)
671 ret = data->AddPoint("_origin", Origin());
672
673 if (ret == B_OK && (fState->archiving_flags & B_VIEW_SCALE_BIT) != 0)
674 ret = data->AddFloat("_scale", Scale());
675
676 if (ret == B_OK && (fState->archiving_flags & B_VIEW_TRANSFORM_BIT) != 0) {
677 BAffineTransform transform = Transform();
678 ret = data->AddFlat("_transform", &transform);
679 }
680
681 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) != 0)
682 ret = data->AddFloat("_psize", PenSize());
683
684 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) != 0)
685 ret = data->AddPoint("_ploc", PenLocation());
686
687 if (ret == B_OK && (fState->archiving_flags & B_VIEW_LINE_MODES_BIT) != 0) {
688 ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode());
689 if (ret == B_OK)
690 ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode());
691 if (ret == B_OK)
692 ret = data->AddFloat("_lmmiter", LineMiterLimit());
693 }
694
695 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FILL_RULE_BIT) != 0)
696 ret = data->AddInt16("_fillrule", (int16)FillRule());
697
698 if (ret == B_OK && (fState->archiving_flags & B_VIEW_BLENDING_BIT) != 0) {
699 source_alpha alphaSourceMode;
700 alpha_function alphaFunctionMode;
701 GetBlendingMode(&alphaSourceMode, &alphaFunctionMode);
702
703 ret = data->AddInt16("_blend", (int16)alphaSourceMode);
704 if (ret == B_OK)
705 ret = data->AddInt16("_blend", (int16)alphaFunctionMode);
706 }
707
708 if (ret == B_OK && (fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) != 0)
709 ret = data->AddInt32("_dmod", DrawingMode());
710
711 if (ret == B_OK)
712 ret = fLayoutData->AddDataToArchive(data);
713
714 if (ret == B_OK)
715 ret = data->AddInt16("_show", fShowLevel);
716
717 if (deep && ret == B_OK) {
718 for (BView* child = fFirstChild; child != NULL && ret == B_OK;
719 child = child->fNextSibling)
720 ret = archiver.AddArchivable("_views", child, deep);
721
722 if (ret == B_OK)
723 ret = archiver.AddArchivable(kLayoutField, GetLayout(), deep);
724 }
725
726 return archiver.Finish(ret);
727 }
728
729
730 status_t
AllUnarchived(const BMessage * from)731 BView::AllUnarchived(const BMessage* from)
732 {
733 BUnarchiver unarchiver(from);
734 status_t err = B_OK;
735
736 int32 count;
737 from->GetInfo("_views", NULL, &count);
738
739 for (int32 i = 0; err == B_OK && i < count; i++) {
740 BView* child;
741 err = unarchiver.FindObject<BView>("_views", i, child);
742 if (err == B_OK)
743 err = _AddChild(child, NULL) ? B_OK : B_ERROR;
744 }
745
746 if (err == B_OK) {
747 BLayout*& layout = fLayoutData->fLayout;
748 err = unarchiver.FindObject(kLayoutField, layout);
749 if (err == B_OK && layout) {
750 fFlags |= B_SUPPORTS_LAYOUT;
751 fLayoutData->fLayout->SetOwner(this);
752 }
753 }
754
755 return err;
756 }
757
758
759 status_t
AllArchived(BMessage * into) const760 BView::AllArchived(BMessage* into) const
761 {
762 return BHandler::AllArchived(into);
763 }
764
765
~BView()766 BView::~BView()
767 {
768 STRACE(("BView(%s)::~BView()\n", this->Name()));
769
770 if (fOwner != NULL) {
771 debugger("Trying to delete a view that belongs to a window. "
772 "Call RemoveSelf first.");
773 }
774
775 // we also delete all our children
776
777 BView* child = fFirstChild;
778 while (child) {
779 BView* nextChild = child->fNextSibling;
780
781 delete child;
782 child = nextChild;
783 }
784
785 SetLayout(NULL);
786 _RemoveLayoutItemsFromLayout(true);
787
788 delete fLayoutData;
789
790 _RemoveSelf();
791
792 if (fToolTip != NULL)
793 fToolTip->ReleaseReference();
794
795 if (fVerScroller != NULL)
796 fVerScroller->SetTarget((BView*)NULL);
797 if (fHorScroller != NULL)
798 fHorScroller->SetTarget((BView*)NULL);
799
800 SetName(NULL);
801
802 _RemoveCommArray();
803 delete fState;
804 }
805
806
807 BRect
Bounds() const808 BView::Bounds() const
809 {
810 _CheckLock();
811
812 if (fIsPrinting)
813 return fState->print_rect;
814
815 return fBounds;
816 }
817
818
819 void
_ConvertToParent(BPoint * point,bool checkLock) const820 BView::_ConvertToParent(BPoint* point, bool checkLock) const
821 {
822 if (!fParent)
823 return;
824
825 if (checkLock)
826 _CheckLock();
827
828 // - our scrolling offset
829 // + our bounds location within the parent
830 point->x += -fBounds.left + fParentOffset.x;
831 point->y += -fBounds.top + fParentOffset.y;
832 }
833
834
835 void
ConvertToParent(BPoint * point) const836 BView::ConvertToParent(BPoint* point) const
837 {
838 _ConvertToParent(point, true);
839 }
840
841
842 BPoint
ConvertToParent(BPoint point) const843 BView::ConvertToParent(BPoint point) const
844 {
845 ConvertToParent(&point);
846
847 return point;
848 }
849
850
851 void
_ConvertFromParent(BPoint * point,bool checkLock) const852 BView::_ConvertFromParent(BPoint* point, bool checkLock) const
853 {
854 if (!fParent)
855 return;
856
857 if (checkLock)
858 _CheckLock();
859
860 // - our bounds location within the parent
861 // + our scrolling offset
862 point->x += -fParentOffset.x + fBounds.left;
863 point->y += -fParentOffset.y + fBounds.top;
864 }
865
866
867 void
ConvertFromParent(BPoint * point) const868 BView::ConvertFromParent(BPoint* point) const
869 {
870 _ConvertFromParent(point, true);
871 }
872
873
874 BPoint
ConvertFromParent(BPoint point) const875 BView::ConvertFromParent(BPoint point) const
876 {
877 ConvertFromParent(&point);
878
879 return point;
880 }
881
882
883 void
ConvertToParent(BRect * rect) const884 BView::ConvertToParent(BRect* rect) const
885 {
886 if (!fParent)
887 return;
888
889 _CheckLock();
890
891 // - our scrolling offset
892 // + our bounds location within the parent
893 rect->OffsetBy(-fBounds.left + fParentOffset.x,
894 -fBounds.top + fParentOffset.y);
895 }
896
897
898 BRect
ConvertToParent(BRect rect) const899 BView::ConvertToParent(BRect rect) const
900 {
901 ConvertToParent(&rect);
902
903 return rect;
904 }
905
906
907 void
ConvertFromParent(BRect * rect) const908 BView::ConvertFromParent(BRect* rect) const
909 {
910 if (!fParent)
911 return;
912
913 _CheckLock();
914
915 // - our bounds location within the parent
916 // + our scrolling offset
917 rect->OffsetBy(-fParentOffset.x + fBounds.left,
918 -fParentOffset.y + fBounds.top);
919 }
920
921
922 BRect
ConvertFromParent(BRect rect) const923 BView::ConvertFromParent(BRect rect) const
924 {
925 ConvertFromParent(&rect);
926
927 return rect;
928 }
929
930
931 void
_ConvertToScreen(BPoint * point,bool checkLock) const932 BView::_ConvertToScreen(BPoint* point, bool checkLock) const
933 {
934 if (!fParent) {
935 if (fOwner)
936 fOwner->ConvertToScreen(point);
937
938 return;
939 }
940
941 if (checkLock)
942 _CheckOwnerLock();
943
944 _ConvertToParent(point, false);
945 fParent->_ConvertToScreen(point, false);
946 }
947
948
949 void
ConvertToScreen(BPoint * point) const950 BView::ConvertToScreen(BPoint* point) const
951 {
952 _ConvertToScreen(point, true);
953 }
954
955
956 BPoint
ConvertToScreen(BPoint point) const957 BView::ConvertToScreen(BPoint point) const
958 {
959 ConvertToScreen(&point);
960
961 return point;
962 }
963
964
965 void
_ConvertFromScreen(BPoint * point,bool checkLock) const966 BView::_ConvertFromScreen(BPoint* point, bool checkLock) const
967 {
968 if (!fParent) {
969 if (fOwner)
970 fOwner->ConvertFromScreen(point);
971
972 return;
973 }
974
975 if (checkLock)
976 _CheckOwnerLock();
977
978 _ConvertFromParent(point, false);
979 fParent->_ConvertFromScreen(point, false);
980 }
981
982
983 void
ConvertFromScreen(BPoint * point) const984 BView::ConvertFromScreen(BPoint* point) const
985 {
986 _ConvertFromScreen(point, true);
987 }
988
989
990 BPoint
ConvertFromScreen(BPoint point) const991 BView::ConvertFromScreen(BPoint point) const
992 {
993 ConvertFromScreen(&point);
994
995 return point;
996 }
997
998
999 void
ConvertToScreen(BRect * rect) const1000 BView::ConvertToScreen(BRect* rect) const
1001 {
1002 BPoint offset(0.0, 0.0);
1003 ConvertToScreen(&offset);
1004 rect->OffsetBy(offset);
1005 }
1006
1007
1008 BRect
ConvertToScreen(BRect rect) const1009 BView::ConvertToScreen(BRect rect) const
1010 {
1011 ConvertToScreen(&rect);
1012
1013 return rect;
1014 }
1015
1016
1017 void
ConvertFromScreen(BRect * rect) const1018 BView::ConvertFromScreen(BRect* rect) const
1019 {
1020 BPoint offset(0.0, 0.0);
1021 ConvertFromScreen(&offset);
1022 rect->OffsetBy(offset);
1023 }
1024
1025
1026 BRect
ConvertFromScreen(BRect rect) const1027 BView::ConvertFromScreen(BRect rect) const
1028 {
1029 ConvertFromScreen(&rect);
1030
1031 return rect;
1032 }
1033
1034
1035 uint32
Flags() const1036 BView::Flags() const
1037 {
1038 _CheckLock();
1039 return fFlags & ~_RESIZE_MASK_;
1040 }
1041
1042
1043 void
SetFlags(uint32 flags)1044 BView::SetFlags(uint32 flags)
1045 {
1046 if (Flags() == flags)
1047 return;
1048
1049 if (fOwner) {
1050 if (flags & B_PULSE_NEEDED) {
1051 _CheckLock();
1052 if (fOwner->fPulseRunner == NULL)
1053 fOwner->SetPulseRate(fOwner->PulseRate());
1054 }
1055
1056 uint32 changesFlags = flags ^ fFlags;
1057 if (changesFlags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
1058 | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE
1059 | B_TRANSPARENT_BACKGROUND)) {
1060 _CheckLockAndSwitchCurrent();
1061
1062 fOwner->fLink->StartMessage(AS_VIEW_SET_FLAGS);
1063 fOwner->fLink->Attach<uint32>(flags);
1064 fOwner->fLink->Flush();
1065 }
1066 }
1067
1068 /* Some useful info:
1069 fFlags is a unsigned long (32 bits)
1070 * bits 1-16 are used for BView's flags
1071 * bits 17-32 are used for BView' resize mask
1072 * _RESIZE_MASK_ is used for that. Look into View.h to see how
1073 it's defined
1074 */
1075 fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_);
1076
1077 fState->archiving_flags |= B_VIEW_FLAGS_BIT;
1078 }
1079
1080
1081 BRect
Frame() const1082 BView::Frame() const
1083 {
1084 return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y);
1085 }
1086
1087
1088 void
Hide()1089 BView::Hide()
1090 {
1091 if (fOwner && fShowLevel == 0) {
1092 _CheckLockAndSwitchCurrent();
1093 fOwner->fLink->StartMessage(AS_VIEW_HIDE);
1094 fOwner->fLink->Flush();
1095 }
1096 fShowLevel++;
1097
1098 if (fShowLevel == 1)
1099 _InvalidateParentLayout();
1100 }
1101
1102
1103 void
Show()1104 BView::Show()
1105 {
1106 fShowLevel--;
1107 if (fOwner && fShowLevel == 0) {
1108 _CheckLockAndSwitchCurrent();
1109 fOwner->fLink->StartMessage(AS_VIEW_SHOW);
1110 fOwner->fLink->Flush();
1111 }
1112
1113 if (fShowLevel == 0)
1114 _InvalidateParentLayout();
1115 }
1116
1117
1118 bool
IsFocus() const1119 BView::IsFocus() const
1120 {
1121 if (fOwner) {
1122 _CheckLock();
1123 return fOwner->CurrentFocus() == this;
1124 } else
1125 return false;
1126 }
1127
1128
1129 bool
IsHidden(const BView * lookingFrom) const1130 BView::IsHidden(const BView* lookingFrom) const
1131 {
1132 if (fShowLevel > 0)
1133 return true;
1134
1135 // may we be egocentric?
1136 if (lookingFrom == this)
1137 return false;
1138
1139 // we have the same visibility state as our
1140 // parent, if there is one
1141 if (fParent)
1142 return fParent->IsHidden(lookingFrom);
1143
1144 // if we're the top view, and we're interested
1145 // in the "global" view, we're inheriting the
1146 // state of the window's visibility
1147 if (fOwner && lookingFrom == NULL)
1148 return fOwner->IsHidden();
1149
1150 return false;
1151 }
1152
1153
1154 bool
IsHidden() const1155 BView::IsHidden() const
1156 {
1157 return IsHidden(NULL);
1158 }
1159
1160
1161 bool
IsPrinting() const1162 BView::IsPrinting() const
1163 {
1164 return fIsPrinting;
1165 }
1166
1167
1168 BPoint
LeftTop() const1169 BView::LeftTop() const
1170 {
1171 return Bounds().LeftTop();
1172 }
1173
1174
1175 void
SetResizingMode(uint32 mode)1176 BView::SetResizingMode(uint32 mode)
1177 {
1178 if (fOwner) {
1179 _CheckLockAndSwitchCurrent();
1180
1181 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_MODE);
1182 fOwner->fLink->Attach<uint32>(mode);
1183 }
1184
1185 // look at SetFlags() for more info on the below line
1186 fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_);
1187 }
1188
1189
1190 uint32
ResizingMode() const1191 BView::ResizingMode() const
1192 {
1193 return fFlags & _RESIZE_MASK_;
1194 }
1195
1196
1197 void
SetViewCursor(const BCursor * cursor,bool sync)1198 BView::SetViewCursor(const BCursor* cursor, bool sync)
1199 {
1200 if (cursor == NULL || fOwner == NULL)
1201 return;
1202
1203 _CheckLock();
1204
1205 ViewSetViewCursorInfo info;
1206 info.cursorToken = cursor->fServerToken;
1207 info.viewToken = _get_object_token_(this);
1208 info.sync = sync;
1209
1210 BPrivate::AppServerLink link;
1211 link.StartMessage(AS_SET_VIEW_CURSOR);
1212 link.Attach<ViewSetViewCursorInfo>(info);
1213
1214 if (sync) {
1215 // Make sure the server has processed the message.
1216 int32 code;
1217 link.FlushWithReply(code);
1218 }
1219 }
1220
1221
1222 void
Flush() const1223 BView::Flush() const
1224 {
1225 if (fOwner)
1226 fOwner->Flush();
1227 }
1228
1229
1230 void
Sync() const1231 BView::Sync() const
1232 {
1233 _CheckOwnerLock();
1234 if (fOwner)
1235 fOwner->Sync();
1236 }
1237
1238
1239 BWindow*
Window() const1240 BView::Window() const
1241 {
1242 return fOwner;
1243 }
1244
1245
1246 // #pragma mark - Hook Functions
1247
1248
1249 void
AttachedToWindow()1250 BView::AttachedToWindow()
1251 {
1252 // Hook function
1253 STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name()));
1254 }
1255
1256
1257 void
AllAttached()1258 BView::AllAttached()
1259 {
1260 // Hook function
1261 STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name()));
1262 }
1263
1264
1265 void
DetachedFromWindow()1266 BView::DetachedFromWindow()
1267 {
1268 // Hook function
1269 STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name()));
1270 }
1271
1272
1273 void
AllDetached()1274 BView::AllDetached()
1275 {
1276 // Hook function
1277 STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name()));
1278 }
1279
1280
1281 void
Draw(BRect updateRect)1282 BView::Draw(BRect updateRect)
1283 {
1284 // Hook function
1285 STRACE(("\tHOOK: BView(%s)::Draw()\n", Name()));
1286 }
1287
1288
1289 void
DrawAfterChildren(BRect updateRect)1290 BView::DrawAfterChildren(BRect updateRect)
1291 {
1292 // Hook function
1293 STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name()));
1294 }
1295
1296
1297 void
FrameMoved(BPoint newPosition)1298 BView::FrameMoved(BPoint newPosition)
1299 {
1300 // Hook function
1301 STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name()));
1302 }
1303
1304
1305 void
FrameResized(float newWidth,float newHeight)1306 BView::FrameResized(float newWidth, float newHeight)
1307 {
1308 // Hook function
1309 STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name()));
1310 }
1311
1312
1313 void
GetPreferredSize(float * _width,float * _height)1314 BView::GetPreferredSize(float* _width, float* _height)
1315 {
1316 STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name()));
1317
1318 if (_width != NULL)
1319 *_width = fBounds.Width();
1320 if (_height != NULL)
1321 *_height = fBounds.Height();
1322 }
1323
1324
1325 void
ResizeToPreferred()1326 BView::ResizeToPreferred()
1327 {
1328 STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name()));
1329
1330 float width;
1331 float height;
1332 GetPreferredSize(&width, &height);
1333
1334 ResizeTo(width, height);
1335 }
1336
1337
1338 void
KeyDown(const char * bytes,int32 numBytes)1339 BView::KeyDown(const char* bytes, int32 numBytes)
1340 {
1341 // Hook function
1342 STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name()));
1343
1344 if (Window())
1345 Window()->_KeyboardNavigation();
1346 }
1347
1348
1349 void
KeyUp(const char * bytes,int32 numBytes)1350 BView::KeyUp(const char* bytes, int32 numBytes)
1351 {
1352 // Hook function
1353 STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name()));
1354 }
1355
1356
1357 void
MouseDown(BPoint where)1358 BView::MouseDown(BPoint where)
1359 {
1360 // Hook function
1361 STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name()));
1362 }
1363
1364
1365 void
MouseUp(BPoint where)1366 BView::MouseUp(BPoint where)
1367 {
1368 // Hook function
1369 STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name()));
1370 }
1371
1372
1373 void
MouseMoved(BPoint where,uint32 code,const BMessage * dragMessage)1374 BView::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
1375 {
1376 // Hook function
1377 STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name()));
1378 }
1379
1380
1381 void
Pulse()1382 BView::Pulse()
1383 {
1384 // Hook function
1385 STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name()));
1386 }
1387
1388
1389 void
TargetedByScrollView(BScrollView * scroll_view)1390 BView::TargetedByScrollView(BScrollView* scroll_view)
1391 {
1392 // Hook function
1393 STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name()));
1394 }
1395
1396
1397 void
WindowActivated(bool active)1398 BView::WindowActivated(bool active)
1399 {
1400 // Hook function
1401 STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name()));
1402 }
1403
1404
1405 // #pragma mark - Input Functions
1406
1407
1408 void
BeginRectTracking(BRect startRect,uint32 style)1409 BView::BeginRectTracking(BRect startRect, uint32 style)
1410 {
1411 if (_CheckOwnerLockAndSwitchCurrent()) {
1412 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_RECT_TRACK);
1413 fOwner->fLink->Attach<BRect>(startRect);
1414 fOwner->fLink->Attach<uint32>(style);
1415 fOwner->fLink->Flush();
1416 }
1417 }
1418
1419
1420 void
EndRectTracking()1421 BView::EndRectTracking()
1422 {
1423 if (_CheckOwnerLockAndSwitchCurrent()) {
1424 fOwner->fLink->StartMessage(AS_VIEW_END_RECT_TRACK);
1425 fOwner->fLink->Flush();
1426 }
1427 }
1428
1429
1430 void
DragMessage(BMessage * message,BRect dragRect,BHandler * replyTo)1431 BView::DragMessage(BMessage* message, BRect dragRect, BHandler* replyTo)
1432 {
1433 if (!message)
1434 return;
1435
1436 _CheckOwnerLock();
1437
1438 // calculate the offset
1439 BPoint offset;
1440 uint32 buttons;
1441 BMessage* current = fOwner->CurrentMessage();
1442 if (!current || current->FindPoint("be:view_where", &offset) != B_OK)
1443 GetMouse(&offset, &buttons, false);
1444 offset -= dragRect.LeftTop();
1445
1446 if (!dragRect.IsValid()) {
1447 DragMessage(message, NULL, B_OP_BLEND, offset, replyTo);
1448 return;
1449 }
1450
1451 // TODO: that's not really what should happen - the app_server should take
1452 // the chance *NOT* to need to drag a whole bitmap around but just a frame.
1453
1454 // create a drag bitmap for the rect
1455 BBitmap* bitmap = new(std::nothrow) BBitmap(dragRect, B_RGBA32);
1456 if (bitmap == NULL)
1457 return;
1458
1459 uint32* bits = (uint32*)bitmap->Bits();
1460 uint32 bytesPerRow = bitmap->BytesPerRow();
1461 uint32 width = dragRect.IntegerWidth() + 1;
1462 uint32 height = dragRect.IntegerHeight() + 1;
1463 uint32 lastRow = (height - 1) * width;
1464
1465 memset(bits, 0x00, height * bytesPerRow);
1466
1467 // top
1468 for (uint32 i = 0; i < width; i += 2)
1469 bits[i] = 0xff000000;
1470
1471 // bottom
1472 for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2)
1473 bits[lastRow + i] = 0xff000000;
1474
1475 // left
1476 for (uint32 i = 0; i < lastRow; i += width * 2)
1477 bits[i] = 0xff000000;
1478
1479 // right
1480 for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2)
1481 bits[width - 1 + i] = 0xff000000;
1482
1483 DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo);
1484 }
1485
1486
1487 void
DragMessage(BMessage * message,BBitmap * image,BPoint offset,BHandler * replyTo)1488 BView::DragMessage(BMessage* message, BBitmap* image, BPoint offset,
1489 BHandler* replyTo)
1490 {
1491 DragMessage(message, image, B_OP_COPY, offset, replyTo);
1492 }
1493
1494
1495 void
DragMessage(BMessage * message,BBitmap * image,drawing_mode dragMode,BPoint offset,BHandler * replyTo)1496 BView::DragMessage(BMessage* message, BBitmap* image,
1497 drawing_mode dragMode, BPoint offset, BHandler* replyTo)
1498 {
1499 if (message == NULL)
1500 return;
1501
1502 if (image == NULL) {
1503 // TODO: workaround for drags without a bitmap - should not be necessary if
1504 // we move the rectangle dragging into the app_server
1505 image = new(std::nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32);
1506 if (image == NULL)
1507 return;
1508 }
1509
1510 if (replyTo == NULL)
1511 replyTo = this;
1512
1513 if (replyTo->Looper() == NULL)
1514 debugger("DragMessage: warning - the Handler needs a looper");
1515
1516 _CheckOwnerLock();
1517
1518 if (!message->HasInt32("buttons")) {
1519 BMessage* msg = fOwner->CurrentMessage();
1520 uint32 buttons;
1521
1522 if (msg == NULL
1523 || msg->FindInt32("buttons", (int32*)&buttons) != B_OK) {
1524 BPoint point;
1525 GetMouse(&point, &buttons, false);
1526 }
1527
1528 message->AddInt32("buttons", buttons);
1529 }
1530
1531 BMessage::Private privateMessage(message);
1532 privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper()));
1533
1534 int32 bufferSize = message->FlattenedSize();
1535 char* buffer = new(std::nothrow) char[bufferSize];
1536 if (buffer != NULL) {
1537 message->Flatten(buffer, bufferSize);
1538
1539 fOwner->fLink->StartMessage(AS_VIEW_DRAG_IMAGE);
1540 fOwner->fLink->Attach<int32>(image->_ServerToken());
1541 fOwner->fLink->Attach<int32>((int32)dragMode);
1542 fOwner->fLink->Attach<BPoint>(offset);
1543 fOwner->fLink->Attach<int32>(bufferSize);
1544 fOwner->fLink->Attach(buffer, bufferSize);
1545
1546 // we need to wait for the server
1547 // to actually process this message
1548 // before we can delete the bitmap
1549 int32 code;
1550 fOwner->fLink->FlushWithReply(code);
1551
1552 delete [] buffer;
1553 } else {
1554 fprintf(stderr, "BView::DragMessage() - no memory to flatten drag "
1555 "message\n");
1556 }
1557
1558 delete image;
1559 }
1560
1561
1562 void
GetMouse(BPoint * _location,uint32 * _buttons,bool checkMessageQueue)1563 BView::GetMouse(BPoint* _location, uint32* _buttons, bool checkMessageQueue)
1564 {
1565 if (_location == NULL && _buttons == NULL)
1566 return;
1567
1568 _CheckOwnerLockAndSwitchCurrent();
1569
1570 uint32 eventOptions = fEventOptions | fMouseEventOptions;
1571 bool noHistory = eventOptions & B_NO_POINTER_HISTORY;
1572 bool fullHistory = eventOptions & B_FULL_POINTER_HISTORY;
1573
1574 if (checkMessageQueue && !noHistory) {
1575 Window()->UpdateIfNeeded();
1576 BMessageQueue* queue = Window()->MessageQueue();
1577 queue->Lock();
1578
1579 // Look out for mouse update messages
1580
1581 BMessage* message;
1582 for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) {
1583 switch (message->what) {
1584 case B_MOUSE_MOVED:
1585 case B_MOUSE_UP:
1586 case B_MOUSE_DOWN:
1587 bool deleteMessage;
1588 if (!Window()->_StealMouseMessage(message, deleteMessage))
1589 continue;
1590
1591 if (!fullHistory && message->what == B_MOUSE_MOVED) {
1592 // Check if the message is too old. Some applications
1593 // check the message queue in such a way that mouse
1594 // messages *must* pile up. This check makes them work
1595 // as intended, although these applications could simply
1596 // use the version of BView::GetMouse() that does not
1597 // check the history. Also note that it isn't a problem
1598 // to delete the message in case there is not a newer
1599 // one. If we don't find a message in the queue, we will
1600 // just fall back to asking the app_sever directly. So
1601 // the imposed delay will not be a problem on slower
1602 // computers. This check also prevents another problem,
1603 // when the message that we use is *not* removed from
1604 // the queue. Subsequent calls to GetMouse() would find
1605 // this message over and over!
1606 bigtime_t eventTime;
1607 if (message->FindInt64("when", &eventTime) == B_OK
1608 && system_time() - eventTime > 10000) {
1609 // just discard the message
1610 if (deleteMessage)
1611 delete message;
1612 continue;
1613 }
1614 }
1615 if (_location != NULL)
1616 message->FindPoint("screen_where", _location);
1617 if (_buttons != NULL)
1618 message->FindInt32("buttons", (int32*)_buttons);
1619 queue->Unlock();
1620 // we need to hold the queue lock until here, because
1621 // the message might still be used for something else
1622
1623 if (_location != NULL)
1624 ConvertFromScreen(_location);
1625
1626 if (deleteMessage)
1627 delete message;
1628
1629 return;
1630 }
1631 }
1632 queue->Unlock();
1633 }
1634
1635 // If no mouse update message has been found in the message queue,
1636 // we get the current mouse location and buttons from the app_server
1637
1638 fOwner->fLink->StartMessage(AS_GET_MOUSE);
1639
1640 int32 code;
1641 if (fOwner->fLink->FlushWithReply(code) == B_OK
1642 && code == B_OK) {
1643 BPoint location;
1644 uint32 buttons;
1645 fOwner->fLink->Read<BPoint>(&location);
1646 fOwner->fLink->Read<uint32>(&buttons);
1647 // TODO: ServerWindow replies with an int32 here
1648
1649 ConvertFromScreen(&location);
1650 // TODO: in beos R5, location is already converted to the view
1651 // local coordinate system, so if an app checks the window message
1652 // queue by itself, it might not find what it expects.
1653 // NOTE: the fact that we have mouse coords in screen space in our
1654 // queue avoids the problem that messages already in the queue will
1655 // be outdated as soon as a window or even the view moves. The
1656 // second situation being quite common actually, also with regards
1657 // to scrolling. An app reading these messages would have to know
1658 // the locations of the window and view for each message...
1659 // otherwise it is potentially broken anyways.
1660 if (_location != NULL)
1661 *_location = location;
1662 if (_buttons != NULL)
1663 *_buttons = buttons;
1664 } else {
1665 if (_location != NULL)
1666 _location->Set(0, 0);
1667 if (_buttons != NULL)
1668 *_buttons = 0;
1669 }
1670 }
1671
1672
1673 void
MakeFocus(bool focus)1674 BView::MakeFocus(bool focus)
1675 {
1676 if (fOwner == NULL)
1677 return;
1678
1679 // TODO: If this view has focus and focus == false,
1680 // will there really be no other view with focus? No
1681 // cycling to the next one?
1682 BView* focusView = fOwner->CurrentFocus();
1683 if (focus) {
1684 // Unfocus a previous focus view
1685 if (focusView != NULL && focusView != this)
1686 focusView->MakeFocus(false);
1687
1688 // if we want to make this view the current focus view
1689 fOwner->_SetFocus(this, true);
1690 } else {
1691 // we want to unfocus this view, but only if it actually has focus
1692 if (focusView == this)
1693 fOwner->_SetFocus(NULL, true);
1694 }
1695 }
1696
1697
1698 BScrollBar*
ScrollBar(orientation direction) const1699 BView::ScrollBar(orientation direction) const
1700 {
1701 switch (direction) {
1702 case B_VERTICAL:
1703 return fVerScroller;
1704
1705 case B_HORIZONTAL:
1706 return fHorScroller;
1707
1708 default:
1709 return NULL;
1710 }
1711 }
1712
1713
1714 void
ScrollBy(float deltaX,float deltaY)1715 BView::ScrollBy(float deltaX, float deltaY)
1716 {
1717 ScrollTo(BPoint(fBounds.left + deltaX, fBounds.top + deltaY));
1718 }
1719
1720
1721 void
ScrollTo(BPoint where)1722 BView::ScrollTo(BPoint where)
1723 {
1724 // scrolling by fractional values is not supported
1725 where.x = roundf(where.x);
1726 where.y = roundf(where.y);
1727
1728 // no reason to process this further if no scroll is intended.
1729 if (where.x == fBounds.left && where.y == fBounds.top)
1730 return;
1731
1732 // make sure scrolling is within valid bounds
1733 if (fHorScroller) {
1734 float min, max;
1735 fHorScroller->GetRange(&min, &max);
1736
1737 if (where.x < min)
1738 where.x = min;
1739 else if (where.x > max)
1740 where.x = max;
1741 }
1742 if (fVerScroller) {
1743 float min, max;
1744 fVerScroller->GetRange(&min, &max);
1745
1746 if (where.y < min)
1747 where.y = min;
1748 else if (where.y > max)
1749 where.y = max;
1750 }
1751
1752 _CheckLockAndSwitchCurrent();
1753
1754 float xDiff = where.x - fBounds.left;
1755 float yDiff = where.y - fBounds.top;
1756
1757 // if we're attached to a window tell app_server about this change
1758 if (fOwner) {
1759 fOwner->fLink->StartMessage(AS_VIEW_SCROLL);
1760 fOwner->fLink->Attach<float>(xDiff);
1761 fOwner->fLink->Attach<float>(yDiff);
1762
1763 fOwner->fLink->Flush();
1764
1765 // fState->valid_flags &= ~B_VIEW_FRAME_BIT;
1766 }
1767
1768 // we modify our bounds rectangle by deltaX/deltaY coord units hor/ver.
1769 fBounds.OffsetTo(where.x, where.y);
1770
1771 // then set the new values of the scrollbars
1772 if (fHorScroller && xDiff != 0.0)
1773 fHorScroller->SetValue(fBounds.left);
1774 if (fVerScroller && yDiff != 0.0)
1775 fVerScroller->SetValue(fBounds.top);
1776
1777 }
1778
1779
1780 status_t
SetEventMask(uint32 mask,uint32 options)1781 BView::SetEventMask(uint32 mask, uint32 options)
1782 {
1783 if (fEventMask == mask && fEventOptions == options)
1784 return B_OK;
1785
1786 // don't change the mask if it's zero and we've got options
1787 if (mask != 0 || options == 0)
1788 fEventMask = mask | (fEventMask & 0xffff0000);
1789 fEventOptions = options;
1790
1791 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT;
1792
1793 if (fOwner) {
1794 _CheckLockAndSwitchCurrent();
1795
1796 fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK);
1797 fOwner->fLink->Attach<uint32>(mask);
1798 fOwner->fLink->Attach<uint32>(options);
1799 fOwner->fLink->Flush();
1800 }
1801
1802 return B_OK;
1803 }
1804
1805
1806 uint32
EventMask()1807 BView::EventMask()
1808 {
1809 return fEventMask;
1810 }
1811
1812
1813 status_t
SetMouseEventMask(uint32 mask,uint32 options)1814 BView::SetMouseEventMask(uint32 mask, uint32 options)
1815 {
1816 // Just don't do anything if the view is not yet attached
1817 // or we were called outside of BView::MouseDown()
1818 if (fOwner != NULL
1819 && fOwner->CurrentMessage() != NULL
1820 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) {
1821 _CheckLockAndSwitchCurrent();
1822 fMouseEventOptions = options;
1823
1824 fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK);
1825 fOwner->fLink->Attach<uint32>(mask);
1826 fOwner->fLink->Attach<uint32>(options);
1827 fOwner->fLink->Flush();
1828 return B_OK;
1829 }
1830
1831 return B_ERROR;
1832 }
1833
1834
1835 // #pragma mark - Graphic State Functions
1836
1837
1838 void
PushState()1839 BView::PushState()
1840 {
1841 _CheckOwnerLockAndSwitchCurrent();
1842
1843 fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE);
1844
1845 fState->valid_flags &= ~B_VIEW_PARENT_COMPOSITE_BIT;
1846
1847 // initialize origin, scale and transform, new states start "clean".
1848 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT
1849 | B_VIEW_TRANSFORM_BIT;
1850 fState->scale = 1.0f;
1851 fState->origin.Set(0, 0);
1852 fState->transform.Reset();
1853 }
1854
1855
1856 void
PopState()1857 BView::PopState()
1858 {
1859 _CheckOwnerLockAndSwitchCurrent();
1860
1861 fOwner->fLink->StartMessage(AS_VIEW_POP_STATE);
1862 _FlushIfNotInTransaction();
1863
1864 // invalidate all flags (except those that are not part of pop/push)
1865 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT;
1866 }
1867
1868
1869 void
SetOrigin(BPoint where)1870 BView::SetOrigin(BPoint where)
1871 {
1872 SetOrigin(where.x, where.y);
1873 }
1874
1875
1876 void
SetOrigin(float x,float y)1877 BView::SetOrigin(float x, float y)
1878 {
1879 if (fState->IsValid(B_VIEW_ORIGIN_BIT)
1880 && x == fState->origin.x && y == fState->origin.y)
1881 return;
1882
1883 fState->origin.x = x;
1884 fState->origin.y = y;
1885
1886 if (_CheckOwnerLockAndSwitchCurrent()) {
1887 fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN);
1888 fOwner->fLink->Attach<float>(x);
1889 fOwner->fLink->Attach<float>(y);
1890
1891 fState->valid_flags |= B_VIEW_ORIGIN_BIT;
1892 }
1893
1894 // our local coord system origin has changed, so when archiving we'll add
1895 // this too
1896 fState->archiving_flags |= B_VIEW_ORIGIN_BIT;
1897 }
1898
1899
1900 BPoint
Origin() const1901 BView::Origin() const
1902 {
1903 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) {
1904 // we don't keep graphics state information, therefor
1905 // we need to ask the server for the origin after PopState()
1906 _CheckOwnerLockAndSwitchCurrent();
1907
1908 fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN);
1909
1910 int32 code;
1911 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1912 fOwner->fLink->Read<BPoint>(&fState->origin);
1913
1914 fState->valid_flags |= B_VIEW_ORIGIN_BIT;
1915 }
1916
1917 return fState->origin;
1918 }
1919
1920
1921 void
SetScale(float scale) const1922 BView::SetScale(float scale) const
1923 {
1924 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale)
1925 return;
1926
1927 if (fOwner) {
1928 _CheckLockAndSwitchCurrent();
1929
1930 fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE);
1931 fOwner->fLink->Attach<float>(scale);
1932
1933 fState->valid_flags |= B_VIEW_SCALE_BIT;
1934 }
1935
1936 fState->scale = scale;
1937 fState->archiving_flags |= B_VIEW_SCALE_BIT;
1938 }
1939
1940
1941 float
Scale() const1942 BView::Scale() const
1943 {
1944 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) {
1945 _CheckLockAndSwitchCurrent();
1946
1947 fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE);
1948
1949 int32 code;
1950 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1951 fOwner->fLink->Read<float>(&fState->scale);
1952
1953 fState->valid_flags |= B_VIEW_SCALE_BIT;
1954 }
1955
1956 return fState->scale;
1957 }
1958
1959
1960 void
SetTransform(BAffineTransform transform)1961 BView::SetTransform(BAffineTransform transform)
1962 {
1963 if (fState->IsValid(B_VIEW_TRANSFORM_BIT) && transform == fState->transform)
1964 return;
1965
1966 if (fOwner != NULL) {
1967 _CheckLockAndSwitchCurrent();
1968
1969 fOwner->fLink->StartMessage(AS_VIEW_SET_TRANSFORM);
1970 fOwner->fLink->Attach<BAffineTransform>(transform);
1971
1972 fState->valid_flags |= B_VIEW_TRANSFORM_BIT;
1973 }
1974
1975 fState->transform = transform;
1976 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
1977 }
1978
1979
1980 BAffineTransform
Transform() const1981 BView::Transform() const
1982 {
1983 if (!fState->IsValid(B_VIEW_TRANSFORM_BIT) && fOwner != NULL) {
1984 _CheckLockAndSwitchCurrent();
1985
1986 fOwner->fLink->StartMessage(AS_VIEW_GET_TRANSFORM);
1987
1988 int32 code;
1989 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1990 fOwner->fLink->Read<BAffineTransform>(&fState->transform);
1991
1992 fState->valid_flags |= B_VIEW_TRANSFORM_BIT;
1993 }
1994
1995 return fState->transform;
1996 }
1997
1998
1999 BAffineTransform
TransformTo(coordinate_space basis) const2000 BView::TransformTo(coordinate_space basis) const
2001 {
2002 if (basis == B_CURRENT_STATE_COORDINATES)
2003 return B_AFFINE_IDENTITY_TRANSFORM;
2004
2005 if (!fState->IsValid(B_VIEW_PARENT_COMPOSITE_BIT) && fOwner != NULL) {
2006 _CheckLockAndSwitchCurrent();
2007
2008 fOwner->fLink->StartMessage(AS_VIEW_GET_PARENT_COMPOSITE);
2009
2010 int32 code;
2011 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2012 fOwner->fLink->Read<BAffineTransform>(&fState->parent_composite_transform);
2013 fOwner->fLink->Read<float>(&fState->parent_composite_scale);
2014 fOwner->fLink->Read<BPoint>(&fState->parent_composite_origin);
2015 }
2016
2017 fState->valid_flags |= B_VIEW_PARENT_COMPOSITE_BIT;
2018 }
2019
2020 BAffineTransform transform = fState->parent_composite_transform * Transform();
2021 float scale = fState->parent_composite_scale * Scale();
2022 transform.PreScaleBy(scale, scale);
2023 BPoint origin = Origin();
2024 origin.x *= fState->parent_composite_scale;
2025 origin.y *= fState->parent_composite_scale;
2026 origin += fState->parent_composite_origin;
2027 transform.TranslateBy(origin);
2028
2029 if (basis == B_PREVIOUS_STATE_COORDINATES) {
2030 transform.TranslateBy(-fState->parent_composite_origin);
2031 transform.PreMultiplyInverse(fState->parent_composite_transform);
2032 transform.ScaleBy(1.0f / fState->parent_composite_scale);
2033 return transform;
2034 }
2035
2036 if (basis == B_VIEW_COORDINATES)
2037 return transform;
2038
2039 origin = B_ORIGIN;
2040
2041 if (basis == B_PARENT_VIEW_COORDINATES || basis == B_PARENT_VIEW_DRAW_COORDINATES) {
2042 BView* parent = Parent();
2043 if (parent != NULL) {
2044 ConvertToParent(&origin);
2045 transform.TranslateBy(origin);
2046 if (basis == B_PARENT_VIEW_DRAW_COORDINATES)
2047 transform = transform.PreMultiplyInverse(parent->TransformTo(B_VIEW_COORDINATES));
2048 return transform;
2049 }
2050 basis = B_WINDOW_COORDINATES;
2051 }
2052
2053 ConvertToScreen(&origin);
2054 if (basis == B_WINDOW_COORDINATES) {
2055 BWindow* window = Window();
2056 if (window != NULL)
2057 origin -= window->Frame().LeftTop();
2058 }
2059 transform.TranslateBy(origin);
2060 return transform;
2061 }
2062
2063
2064 void
TranslateBy(double x,double y)2065 BView::TranslateBy(double x, double y)
2066 {
2067 if (fOwner != NULL) {
2068 _CheckLockAndSwitchCurrent();
2069
2070 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_TRANSLATE);
2071 fOwner->fLink->Attach<double>(x);
2072 fOwner->fLink->Attach<double>(y);
2073
2074 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT;
2075 }
2076
2077 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
2078 }
2079
2080
2081 void
ScaleBy(double x,double y)2082 BView::ScaleBy(double x, double y)
2083 {
2084 if (fOwner != NULL) {
2085 _CheckLockAndSwitchCurrent();
2086
2087 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_SCALE);
2088 fOwner->fLink->Attach<double>(x);
2089 fOwner->fLink->Attach<double>(y);
2090
2091 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT;
2092 }
2093
2094 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
2095 }
2096
2097
2098 void
RotateBy(double angleRadians)2099 BView::RotateBy(double angleRadians)
2100 {
2101 if (fOwner != NULL) {
2102 _CheckLockAndSwitchCurrent();
2103
2104 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_ROTATE);
2105 fOwner->fLink->Attach<double>(angleRadians);
2106
2107 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT;
2108 }
2109
2110 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
2111 }
2112
2113
2114 void
SetLineMode(cap_mode lineCap,join_mode lineJoin,float miterLimit)2115 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit)
2116 {
2117 if (fState->IsValid(B_VIEW_LINE_MODES_BIT)
2118 && lineCap == fState->line_cap && lineJoin == fState->line_join
2119 && miterLimit == fState->miter_limit)
2120 return;
2121
2122 if (fOwner) {
2123 _CheckLockAndSwitchCurrent();
2124
2125 ViewSetLineModeInfo info;
2126 info.lineJoin = lineJoin;
2127 info.lineCap = lineCap;
2128 info.miterLimit = miterLimit;
2129
2130 fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE);
2131 fOwner->fLink->Attach<ViewSetLineModeInfo>(info);
2132
2133 fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
2134 }
2135
2136 fState->line_cap = lineCap;
2137 fState->line_join = lineJoin;
2138 fState->miter_limit = miterLimit;
2139
2140 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT;
2141 }
2142
2143
2144 join_mode
LineJoinMode() const2145 BView::LineJoinMode() const
2146 {
2147 // This will update the current state, if necessary
2148 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
2149 LineMiterLimit();
2150
2151 return fState->line_join;
2152 }
2153
2154
2155 cap_mode
LineCapMode() const2156 BView::LineCapMode() const
2157 {
2158 // This will update the current state, if necessary
2159 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
2160 LineMiterLimit();
2161
2162 return fState->line_cap;
2163 }
2164
2165
2166 float
LineMiterLimit() const2167 BView::LineMiterLimit() const
2168 {
2169 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) {
2170 _CheckLockAndSwitchCurrent();
2171
2172 fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE);
2173
2174 int32 code;
2175 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2176
2177 ViewSetLineModeInfo info;
2178 fOwner->fLink->Read<ViewSetLineModeInfo>(&info);
2179
2180 fState->line_cap = info.lineCap;
2181 fState->line_join = info.lineJoin;
2182 fState->miter_limit = info.miterLimit;
2183 }
2184
2185 fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
2186 }
2187
2188 return fState->miter_limit;
2189 }
2190
2191
2192 void
SetFillRule(int32 fillRule)2193 BView::SetFillRule(int32 fillRule)
2194 {
2195 if (fState->IsValid(B_VIEW_FILL_RULE_BIT) && fillRule == fState->fill_rule)
2196 return;
2197
2198 if (fOwner) {
2199 _CheckLockAndSwitchCurrent();
2200
2201 fOwner->fLink->StartMessage(AS_VIEW_SET_FILL_RULE);
2202 fOwner->fLink->Attach<int32>(fillRule);
2203
2204 fState->valid_flags |= B_VIEW_FILL_RULE_BIT;
2205 }
2206
2207 fState->fill_rule = fillRule;
2208
2209 fState->archiving_flags |= B_VIEW_FILL_RULE_BIT;
2210 }
2211
2212
2213 int32
FillRule() const2214 BView::FillRule() const
2215 {
2216 if (!fState->IsValid(B_VIEW_FILL_RULE_BIT) && fOwner) {
2217 _CheckLockAndSwitchCurrent();
2218
2219 fOwner->fLink->StartMessage(AS_VIEW_GET_FILL_RULE);
2220
2221 int32 code;
2222 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2223
2224 int32 fillRule;
2225 fOwner->fLink->Read<int32>(&fillRule);
2226
2227 fState->fill_rule = fillRule;
2228 }
2229
2230 fState->valid_flags |= B_VIEW_FILL_RULE_BIT;
2231 }
2232
2233 return fState->fill_rule;
2234 }
2235
2236
2237 void
SetDrawingMode(drawing_mode mode)2238 BView::SetDrawingMode(drawing_mode mode)
2239 {
2240 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT)
2241 && mode == fState->drawing_mode)
2242 return;
2243
2244 if (fOwner) {
2245 _CheckLockAndSwitchCurrent();
2246
2247 fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE);
2248 fOwner->fLink->Attach<int8>((int8)mode);
2249
2250 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
2251 }
2252
2253 fState->drawing_mode = mode;
2254 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT;
2255 }
2256
2257
2258 drawing_mode
DrawingMode() const2259 BView::DrawingMode() const
2260 {
2261 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) {
2262 _CheckLockAndSwitchCurrent();
2263
2264 fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE);
2265
2266 int32 code;
2267 if (fOwner->fLink->FlushWithReply(code) == B_OK
2268 && code == B_OK) {
2269 int8 drawingMode;
2270 fOwner->fLink->Read<int8>(&drawingMode);
2271
2272 fState->drawing_mode = (drawing_mode)drawingMode;
2273 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
2274 }
2275 }
2276
2277 return fState->drawing_mode;
2278 }
2279
2280
2281 void
SetBlendingMode(source_alpha sourceAlpha,alpha_function alphaFunction)2282 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction)
2283 {
2284 if (fState->IsValid(B_VIEW_BLENDING_BIT)
2285 && sourceAlpha == fState->alpha_source_mode
2286 && alphaFunction == fState->alpha_function_mode)
2287 return;
2288
2289 if (fOwner) {
2290 _CheckLockAndSwitchCurrent();
2291
2292 ViewBlendingModeInfo info;
2293 info.sourceAlpha = sourceAlpha;
2294 info.alphaFunction = alphaFunction;
2295
2296 fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE);
2297 fOwner->fLink->Attach<ViewBlendingModeInfo>(info);
2298
2299 fState->valid_flags |= B_VIEW_BLENDING_BIT;
2300 }
2301
2302 fState->alpha_source_mode = sourceAlpha;
2303 fState->alpha_function_mode = alphaFunction;
2304
2305 fState->archiving_flags |= B_VIEW_BLENDING_BIT;
2306 }
2307
2308
2309 void
GetBlendingMode(source_alpha * _sourceAlpha,alpha_function * _alphaFunction) const2310 BView::GetBlendingMode(source_alpha* _sourceAlpha,
2311 alpha_function* _alphaFunction) const
2312 {
2313 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) {
2314 _CheckLockAndSwitchCurrent();
2315
2316 fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE);
2317
2318 int32 code;
2319 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2320 ViewBlendingModeInfo info;
2321 fOwner->fLink->Read<ViewBlendingModeInfo>(&info);
2322
2323 fState->alpha_source_mode = info.sourceAlpha;
2324 fState->alpha_function_mode = info.alphaFunction;
2325
2326 fState->valid_flags |= B_VIEW_BLENDING_BIT;
2327 }
2328 }
2329
2330 if (_sourceAlpha)
2331 *_sourceAlpha = fState->alpha_source_mode;
2332
2333 if (_alphaFunction)
2334 *_alphaFunction = fState->alpha_function_mode;
2335 }
2336
2337
2338 void
MovePenTo(BPoint point)2339 BView::MovePenTo(BPoint point)
2340 {
2341 MovePenTo(point.x, point.y);
2342 }
2343
2344
2345 void
MovePenTo(float x,float y)2346 BView::MovePenTo(float x, float y)
2347 {
2348 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT)
2349 && x == fState->pen_location.x && y == fState->pen_location.y)
2350 return;
2351
2352 if (fOwner) {
2353 _CheckLockAndSwitchCurrent();
2354
2355 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC);
2356 fOwner->fLink->Attach<BPoint>(BPoint(x, y));
2357
2358 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
2359 }
2360
2361 fState->pen_location.x = x;
2362 fState->pen_location.y = y;
2363
2364 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT;
2365 }
2366
2367
2368 void
MovePenBy(float x,float y)2369 BView::MovePenBy(float x, float y)
2370 {
2371 // this will update the pen location if necessary
2372 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT))
2373 PenLocation();
2374
2375 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y);
2376 }
2377
2378
2379 BPoint
PenLocation() const2380 BView::PenLocation() const
2381 {
2382 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) {
2383 _CheckLockAndSwitchCurrent();
2384
2385 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC);
2386
2387 int32 code;
2388 if (fOwner->fLink->FlushWithReply(code) == B_OK
2389 && code == B_OK) {
2390 fOwner->fLink->Read<BPoint>(&fState->pen_location);
2391
2392 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
2393 }
2394 }
2395
2396 return fState->pen_location;
2397 }
2398
2399
2400 void
SetPenSize(float size)2401 BView::SetPenSize(float size)
2402 {
2403 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size)
2404 return;
2405
2406 if (fOwner) {
2407 _CheckLockAndSwitchCurrent();
2408
2409 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE);
2410 fOwner->fLink->Attach<float>(size);
2411
2412 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
2413 }
2414
2415 fState->pen_size = size;
2416 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT;
2417 }
2418
2419
2420 float
PenSize() const2421 BView::PenSize() const
2422 {
2423 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) {
2424 _CheckLockAndSwitchCurrent();
2425
2426 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE);
2427
2428 int32 code;
2429 if (fOwner->fLink->FlushWithReply(code) == B_OK
2430 && code == B_OK) {
2431 fOwner->fLink->Read<float>(&fState->pen_size);
2432
2433 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
2434 }
2435 }
2436
2437 return fState->pen_size;
2438 }
2439
2440
2441 void
SetHighColor(rgb_color color)2442 BView::SetHighColor(rgb_color color)
2443 {
2444 SetHighUIColor(B_NO_COLOR);
2445
2446 // are we up-to-date already?
2447 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT)
2448 && fState->high_color == color)
2449 return;
2450
2451 if (fOwner) {
2452 _CheckLockAndSwitchCurrent();
2453
2454 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR);
2455 fOwner->fLink->Attach<rgb_color>(color);
2456
2457 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2458 }
2459
2460 fState->high_color = color;
2461
2462 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT;
2463 }
2464
2465
2466 rgb_color
HighColor() const2467 BView::HighColor() const
2468 {
2469 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) {
2470 _CheckLockAndSwitchCurrent();
2471
2472 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR);
2473
2474 int32 code;
2475 if (fOwner->fLink->FlushWithReply(code) == B_OK
2476 && code == B_OK) {
2477 fOwner->fLink->Read<rgb_color>(&fState->high_color);
2478
2479 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2480 }
2481 }
2482
2483 return fState->high_color;
2484 }
2485
2486
2487 void
SetHighUIColor(color_which which,float tint)2488 BView::SetHighUIColor(color_which which, float tint)
2489 {
2490 if (fState->IsValid(B_VIEW_WHICH_HIGH_COLOR_BIT)
2491 && fState->which_high_color == which
2492 && fState->which_high_color_tint == tint)
2493 return;
2494
2495 if (fOwner != NULL) {
2496 _CheckLockAndSwitchCurrent();
2497
2498 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_UI_COLOR);
2499 fOwner->fLink->Attach<color_which>(which);
2500 fOwner->fLink->Attach<float>(tint);
2501
2502 fState->valid_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT;
2503 }
2504
2505 fState->which_high_color = which;
2506 fState->which_high_color_tint = tint;
2507
2508 if (which != B_NO_COLOR) {
2509 fState->archiving_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT;
2510 fState->archiving_flags &= ~B_VIEW_HIGH_COLOR_BIT;
2511 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2512
2513 fState->high_color = tint_color(ui_color(which), tint);
2514 } else {
2515 fState->valid_flags &= ~B_VIEW_HIGH_COLOR_BIT;
2516 fState->archiving_flags &= ~B_VIEW_WHICH_HIGH_COLOR_BIT;
2517 }
2518 }
2519
2520
2521 color_which
HighUIColor(float * tint) const2522 BView::HighUIColor(float* tint) const
2523 {
2524 if (!fState->IsValid(B_VIEW_WHICH_HIGH_COLOR_BIT)
2525 && fOwner != NULL) {
2526 _CheckLockAndSwitchCurrent();
2527
2528 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_UI_COLOR);
2529
2530 int32 code;
2531 if (fOwner->fLink->FlushWithReply(code) == B_OK
2532 && code == B_OK) {
2533 fOwner->fLink->Read<color_which>(&fState->which_high_color);
2534 fOwner->fLink->Read<float>(&fState->which_high_color_tint);
2535 fOwner->fLink->Read<rgb_color>(&fState->high_color);
2536
2537 fState->valid_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT;
2538 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2539 }
2540 }
2541
2542 if (tint != NULL)
2543 *tint = fState->which_high_color_tint;
2544
2545 return fState->which_high_color;
2546 }
2547
2548
2549 void
SetLowColor(rgb_color color)2550 BView::SetLowColor(rgb_color color)
2551 {
2552 SetLowUIColor(B_NO_COLOR);
2553
2554 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT)
2555 && fState->low_color == color)
2556 return;
2557
2558 if (fOwner) {
2559 _CheckLockAndSwitchCurrent();
2560
2561 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR);
2562 fOwner->fLink->Attach<rgb_color>(color);
2563
2564 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2565 }
2566
2567 fState->low_color = color;
2568
2569 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT;
2570 }
2571
2572
2573 rgb_color
LowColor() const2574 BView::LowColor() const
2575 {
2576 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) {
2577 _CheckLockAndSwitchCurrent();
2578
2579 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR);
2580
2581 int32 code;
2582 if (fOwner->fLink->FlushWithReply(code) == B_OK
2583 && code == B_OK) {
2584 fOwner->fLink->Read<rgb_color>(&fState->low_color);
2585
2586 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2587 }
2588 }
2589
2590 return fState->low_color;
2591 }
2592
2593
2594 void
SetLowUIColor(color_which which,float tint)2595 BView::SetLowUIColor(color_which which, float tint)
2596 {
2597 if (fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT)
2598 && fState->which_low_color == which
2599 && fState->which_low_color_tint == tint)
2600 return;
2601
2602 if (fOwner != NULL) {
2603 _CheckLockAndSwitchCurrent();
2604
2605 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_UI_COLOR);
2606 fOwner->fLink->Attach<color_which>(which);
2607 fOwner->fLink->Attach<float>(tint);
2608
2609 fState->valid_flags |= B_VIEW_WHICH_LOW_COLOR_BIT;
2610 }
2611
2612 fState->which_low_color = which;
2613 fState->which_low_color_tint = tint;
2614
2615 if (which != B_NO_COLOR) {
2616 fState->archiving_flags |= B_VIEW_WHICH_LOW_COLOR_BIT;
2617 fState->archiving_flags &= ~B_VIEW_LOW_COLOR_BIT;
2618 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2619
2620 fState->low_color = tint_color(ui_color(which), tint);
2621 } else {
2622 fState->valid_flags &= ~B_VIEW_LOW_COLOR_BIT;
2623 fState->archiving_flags &= ~B_VIEW_WHICH_LOW_COLOR_BIT;
2624 }
2625 }
2626
2627
2628 color_which
LowUIColor(float * tint) const2629 BView::LowUIColor(float* tint) const
2630 {
2631 if (!fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT)
2632 && fOwner != NULL) {
2633 _CheckLockAndSwitchCurrent();
2634
2635 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_UI_COLOR);
2636
2637 int32 code;
2638 if (fOwner->fLink->FlushWithReply(code) == B_OK
2639 && code == B_OK) {
2640 fOwner->fLink->Read<color_which>(&fState->which_low_color);
2641 fOwner->fLink->Read<float>(&fState->which_low_color_tint);
2642 fOwner->fLink->Read<rgb_color>(&fState->low_color);
2643
2644 fState->valid_flags |= B_VIEW_WHICH_LOW_COLOR_BIT;
2645 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2646 }
2647 }
2648
2649 if (tint != NULL)
2650 *tint = fState->which_low_color_tint;
2651
2652 return fState->which_low_color;
2653 }
2654
2655
2656 bool
HasDefaultColors() const2657 BView::HasDefaultColors() const
2658 {
2659 // If we don't have any of these flags, then we have default colors
2660 uint32 testMask = B_VIEW_VIEW_COLOR_BIT | B_VIEW_HIGH_COLOR_BIT
2661 | B_VIEW_LOW_COLOR_BIT | B_VIEW_WHICH_VIEW_COLOR_BIT
2662 | B_VIEW_WHICH_HIGH_COLOR_BIT | B_VIEW_WHICH_LOW_COLOR_BIT;
2663
2664 return (fState->archiving_flags & testMask) == 0;
2665 }
2666
2667
2668 bool
HasSystemColors() const2669 BView::HasSystemColors() const
2670 {
2671 return fState->which_view_color == B_PANEL_BACKGROUND_COLOR
2672 && fState->which_high_color == B_PANEL_TEXT_COLOR
2673 && fState->which_low_color == B_PANEL_BACKGROUND_COLOR
2674 && fState->which_view_color_tint == B_NO_TINT
2675 && fState->which_high_color_tint == B_NO_TINT
2676 && fState->which_low_color_tint == B_NO_TINT;
2677 }
2678
2679
2680 void
AdoptParentColors()2681 BView::AdoptParentColors()
2682 {
2683 AdoptViewColors(Parent());
2684 }
2685
2686
2687 void
AdoptSystemColors()2688 BView::AdoptSystemColors()
2689 {
2690 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
2691 SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
2692 SetHighUIColor(B_PANEL_TEXT_COLOR);
2693 }
2694
2695
2696 void
AdoptViewColors(BView * view)2697 BView::AdoptViewColors(BView* view)
2698 {
2699 if (view == NULL || (view->Window() != NULL && !view->LockLooper()))
2700 return;
2701
2702 float tint = B_NO_TINT;
2703 float viewTint = tint;
2704 color_which viewWhich = view->ViewUIColor(&viewTint);
2705
2706 // View color
2707 if (viewWhich != B_NO_COLOR)
2708 SetViewUIColor(viewWhich, viewTint);
2709 else
2710 SetViewColor(view->ViewColor());
2711
2712 // Low color
2713 color_which which = view->LowUIColor(&tint);
2714 if (which != B_NO_COLOR)
2715 SetLowUIColor(which, tint);
2716 else if (viewWhich != B_NO_COLOR)
2717 SetLowUIColor(viewWhich, viewTint);
2718 else
2719 SetLowColor(view->LowColor());
2720
2721 // High color
2722 which = view->HighUIColor(&tint);
2723 if (which != B_NO_COLOR)
2724 SetHighUIColor(which, tint);
2725 else
2726 SetHighColor(view->HighColor());
2727
2728 if (view->Window() != NULL)
2729 view->UnlockLooper();
2730 }
2731
2732
2733 void
SetViewColor(rgb_color color)2734 BView::SetViewColor(rgb_color color)
2735 {
2736 SetViewUIColor(B_NO_COLOR);
2737
2738 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT)
2739 && fState->view_color == color)
2740 return;
2741
2742 if (fOwner) {
2743 _CheckLockAndSwitchCurrent();
2744
2745 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR);
2746 fOwner->fLink->Attach<rgb_color>(color);
2747 fOwner->fLink->Flush();
2748
2749 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2750 }
2751
2752 fState->view_color = color;
2753
2754 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT;
2755 }
2756
2757
2758 rgb_color
ViewColor() const2759 BView::ViewColor() const
2760 {
2761 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) {
2762 _CheckLockAndSwitchCurrent();
2763
2764 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR);
2765
2766 int32 code;
2767 if (fOwner->fLink->FlushWithReply(code) == B_OK
2768 && code == B_OK) {
2769 fOwner->fLink->Read<rgb_color>(&fState->view_color);
2770
2771 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2772 }
2773 }
2774
2775 return fState->view_color;
2776 }
2777
2778
2779 void
SetViewUIColor(color_which which,float tint)2780 BView::SetViewUIColor(color_which which, float tint)
2781 {
2782 if (fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)
2783 && fState->which_view_color == which
2784 && fState->which_view_color_tint == tint)
2785 return;
2786
2787 if (fOwner != NULL) {
2788 _CheckLockAndSwitchCurrent();
2789
2790 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_UI_COLOR);
2791 fOwner->fLink->Attach<color_which>(which);
2792 fOwner->fLink->Attach<float>(tint);
2793
2794 fState->valid_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT;
2795 }
2796
2797 fState->which_view_color = which;
2798 fState->which_view_color_tint = tint;
2799
2800 if (which != B_NO_COLOR) {
2801 fState->archiving_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT;
2802 fState->archiving_flags &= ~B_VIEW_VIEW_COLOR_BIT;
2803 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2804
2805 fState->view_color = tint_color(ui_color(which), tint);
2806 } else {
2807 fState->valid_flags &= ~B_VIEW_VIEW_COLOR_BIT;
2808 fState->archiving_flags &= ~B_VIEW_WHICH_VIEW_COLOR_BIT;
2809 }
2810
2811 if (!fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT))
2812 SetLowUIColor(which, tint);
2813 }
2814
2815
2816 color_which
ViewUIColor(float * tint) const2817 BView::ViewUIColor(float* tint) const
2818 {
2819 if (!fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)
2820 && fOwner != NULL) {
2821 _CheckLockAndSwitchCurrent();
2822
2823 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_UI_COLOR);
2824
2825 int32 code;
2826 if (fOwner->fLink->FlushWithReply(code) == B_OK
2827 && code == B_OK) {
2828 fOwner->fLink->Read<color_which>(&fState->which_view_color);
2829 fOwner->fLink->Read<float>(&fState->which_view_color_tint);
2830 fOwner->fLink->Read<rgb_color>(&fState->view_color);
2831
2832 fState->valid_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT;
2833 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2834 }
2835 }
2836
2837 if (tint != NULL)
2838 *tint = fState->which_view_color_tint;
2839
2840 return fState->which_view_color;
2841 }
2842
2843
2844 void
ForceFontAliasing(bool enable)2845 BView::ForceFontAliasing(bool enable)
2846 {
2847 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT)
2848 && enable == fState->font_aliasing)
2849 return;
2850
2851 if (fOwner) {
2852 _CheckLockAndSwitchCurrent();
2853
2854 fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING);
2855 fOwner->fLink->Attach<bool>(enable);
2856
2857 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT;
2858 }
2859
2860 fState->font_aliasing = enable;
2861 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT;
2862 }
2863
2864
2865 void
SetFont(const BFont * font,uint32 mask)2866 BView::SetFont(const BFont* font, uint32 mask)
2867 {
2868 if (!font || mask == 0)
2869 return;
2870
2871 if (mask == B_FONT_ALL) {
2872 fState->font = *font;
2873 } else {
2874 // TODO: move this into a BFont method
2875 if (mask & B_FONT_FAMILY_AND_STYLE)
2876 fState->font.SetFamilyAndStyle(font->FamilyAndStyle());
2877
2878 if (mask & B_FONT_SIZE)
2879 fState->font.SetSize(font->Size());
2880
2881 if (mask & B_FONT_SHEAR)
2882 fState->font.SetShear(font->Shear());
2883
2884 if (mask & B_FONT_ROTATION)
2885 fState->font.SetRotation(font->Rotation());
2886
2887 if (mask & B_FONT_FALSE_BOLD_WIDTH)
2888 fState->font.SetFalseBoldWidth(font->FalseBoldWidth());
2889
2890 if (mask & B_FONT_SPACING)
2891 fState->font.SetSpacing(font->Spacing());
2892
2893 if (mask & B_FONT_ENCODING)
2894 fState->font.SetEncoding(font->Encoding());
2895
2896 if (mask & B_FONT_FACE)
2897 fState->font.SetFace(font->Face());
2898
2899 if (mask & B_FONT_FLAGS)
2900 fState->font.SetFlags(font->Flags());
2901 }
2902
2903 fState->font_flags |= mask;
2904
2905 if (fOwner) {
2906 _CheckLockAndSwitchCurrent();
2907
2908 fState->UpdateServerFontState(*fOwner->fLink);
2909 fState->valid_flags |= B_VIEW_FONT_BIT;
2910 }
2911
2912 fState->archiving_flags |= B_VIEW_FONT_BIT;
2913 // TODO: InvalidateLayout() here for convenience?
2914 }
2915
2916
2917 void
GetFont(BFont * font) const2918 BView::GetFont(BFont* font) const
2919 {
2920 if (!fState->IsValid(B_VIEW_FONT_BIT)) {
2921 // we don't keep graphics state information, therefor
2922 // we need to ask the server for the origin after PopState()
2923 _CheckOwnerLockAndSwitchCurrent();
2924
2925 // TODO: add a font getter!
2926 fState->UpdateFrom(*fOwner->fLink);
2927 }
2928
2929 *font = fState->font;
2930 }
2931
2932
2933 void
GetFontHeight(font_height * height) const2934 BView::GetFontHeight(font_height* height) const
2935 {
2936 fState->font.GetHeight(height);
2937 }
2938
2939
2940 void
SetFontSize(float size)2941 BView::SetFontSize(float size)
2942 {
2943 BFont font;
2944 font.SetSize(size);
2945
2946 SetFont(&font, B_FONT_SIZE);
2947 }
2948
2949
2950 float
StringWidth(const char * string) const2951 BView::StringWidth(const char* string) const
2952 {
2953 return fState->font.StringWidth(string);
2954 }
2955
2956
2957 float
StringWidth(const char * string,int32 length) const2958 BView::StringWidth(const char* string, int32 length) const
2959 {
2960 return fState->font.StringWidth(string, length);
2961 }
2962
2963
2964 void
GetStringWidths(char * stringArray[],int32 lengthArray[],int32 numStrings,float widthArray[]) const2965 BView::GetStringWidths(char* stringArray[], int32 lengthArray[],
2966 int32 numStrings, float widthArray[]) const
2967 {
2968 fState->font.GetStringWidths(const_cast<const char**>(stringArray),
2969 const_cast<const int32*>(lengthArray), numStrings, widthArray);
2970 }
2971
2972
2973 void
TruncateString(BString * string,uint32 mode,float width) const2974 BView::TruncateString(BString* string, uint32 mode, float width) const
2975 {
2976 fState->font.TruncateString(string, mode, width);
2977 }
2978
2979
2980 void
ClipToPicture(BPicture * picture,BPoint where,bool sync)2981 BView::ClipToPicture(BPicture* picture, BPoint where, bool sync)
2982 {
2983 _ClipToPicture(picture, where, false, sync);
2984 }
2985
2986
2987 void
ClipToInversePicture(BPicture * picture,BPoint where,bool sync)2988 BView::ClipToInversePicture(BPicture* picture, BPoint where, bool sync)
2989 {
2990 _ClipToPicture(picture, where, true, sync);
2991 }
2992
2993
2994 void
GetClippingRegion(BRegion * region) const2995 BView::GetClippingRegion(BRegion* region) const
2996 {
2997 if (!region)
2998 return;
2999
3000 // NOTE: the client has no idea when the clipping in the server
3001 // changed, so it is always read from the server
3002 region->MakeEmpty();
3003
3004
3005 if (fOwner) {
3006 if (fIsPrinting && _CheckOwnerLock()) {
3007 region->Set(fState->print_rect);
3008 return;
3009 }
3010
3011 _CheckLockAndSwitchCurrent();
3012 fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION);
3013
3014 int32 code;
3015 if (fOwner->fLink->FlushWithReply(code) == B_OK
3016 && code == B_OK) {
3017 fOwner->fLink->ReadRegion(region);
3018 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT;
3019 }
3020 }
3021 }
3022
3023
3024 void
ConstrainClippingRegion(BRegion * region)3025 BView::ConstrainClippingRegion(BRegion* region)
3026 {
3027 if (_CheckOwnerLockAndSwitchCurrent()) {
3028 fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION);
3029
3030 if (region) {
3031 int32 count = region->CountRects();
3032 fOwner->fLink->Attach<int32>(count);
3033 if (count > 0)
3034 fOwner->fLink->AttachRegion(*region);
3035 } else {
3036 fOwner->fLink->Attach<int32>(-1);
3037 // '-1' means that in the app_server, there won't be any 'local'
3038 // clipping region (it will be NULL)
3039 }
3040
3041 _FlushIfNotInTransaction();
3042
3043 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
3044 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
3045 }
3046 }
3047
3048
3049 void
ClipToRect(BRect rect)3050 BView::ClipToRect(BRect rect)
3051 {
3052 _ClipToRect(rect, false);
3053 }
3054
3055
3056 void
ClipToInverseRect(BRect rect)3057 BView::ClipToInverseRect(BRect rect)
3058 {
3059 _ClipToRect(rect, true);
3060 }
3061
3062
3063 void
ClipToShape(BShape * shape)3064 BView::ClipToShape(BShape* shape)
3065 {
3066 _ClipToShape(shape, false);
3067 }
3068
3069
3070 void
ClipToInverseShape(BShape * shape)3071 BView::ClipToInverseShape(BShape* shape)
3072 {
3073 _ClipToShape(shape, true);
3074 }
3075
3076
3077 // #pragma mark - Drawing Functions
3078
3079
3080 void
DrawBitmapAsync(const BBitmap * bitmap,BRect bitmapRect,BRect viewRect,uint32 options)3081 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect,
3082 uint32 options)
3083 {
3084 if (bitmap == NULL || fOwner == NULL
3085 || !bitmapRect.IsValid() || !viewRect.IsValid())
3086 return;
3087
3088 _CheckLockAndSwitchCurrent();
3089
3090 ViewDrawBitmapInfo info;
3091 info.bitmapToken = bitmap->_ServerToken();
3092 info.options = options;
3093 info.viewRect = viewRect;
3094 info.bitmapRect = bitmapRect;
3095
3096 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
3097 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
3098
3099 _FlushIfNotInTransaction();
3100 }
3101
3102
3103 void
DrawBitmapAsync(const BBitmap * bitmap,BRect bitmapRect,BRect viewRect)3104 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect)
3105 {
3106 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0);
3107 }
3108
3109
3110 void
DrawBitmapAsync(const BBitmap * bitmap,BRect viewRect)3111 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect)
3112 {
3113 if (bitmap && fOwner) {
3114 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN),
3115 viewRect, 0);
3116 }
3117 }
3118
3119
3120 void
DrawBitmapAsync(const BBitmap * bitmap,BPoint where)3121 BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where)
3122 {
3123 if (bitmap == NULL || fOwner == NULL)
3124 return;
3125
3126 _CheckLockAndSwitchCurrent();
3127
3128 ViewDrawBitmapInfo info;
3129 info.bitmapToken = bitmap->_ServerToken();
3130 info.options = 0;
3131 info.bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN);
3132 info.viewRect = info.bitmapRect.OffsetToCopy(where);
3133
3134 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
3135 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
3136
3137 _FlushIfNotInTransaction();
3138 }
3139
3140
3141 void
DrawBitmapAsync(const BBitmap * bitmap)3142 BView::DrawBitmapAsync(const BBitmap* bitmap)
3143 {
3144 DrawBitmapAsync(bitmap, PenLocation());
3145 }
3146
3147
3148 void
DrawBitmap(const BBitmap * bitmap,BRect bitmapRect,BRect viewRect,uint32 options)3149 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect,
3150 uint32 options)
3151 {
3152 if (fOwner) {
3153 DrawBitmapAsync(bitmap, bitmapRect, viewRect, options);
3154 Sync();
3155 }
3156 }
3157
3158
3159 void
DrawBitmap(const BBitmap * bitmap,BRect bitmapRect,BRect viewRect)3160 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect)
3161 {
3162 if (fOwner) {
3163 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0);
3164 Sync();
3165 }
3166 }
3167
3168
3169 void
DrawBitmap(const BBitmap * bitmap,BRect viewRect)3170 BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect)
3171 {
3172 if (bitmap && fOwner) {
3173 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect,
3174 0);
3175 }
3176 }
3177
3178
3179 void
DrawBitmap(const BBitmap * bitmap,BPoint where)3180 BView::DrawBitmap(const BBitmap* bitmap, BPoint where)
3181 {
3182 if (fOwner) {
3183 DrawBitmapAsync(bitmap, where);
3184 Sync();
3185 }
3186 }
3187
3188
3189 void
DrawBitmap(const BBitmap * bitmap)3190 BView::DrawBitmap(const BBitmap* bitmap)
3191 {
3192 DrawBitmap(bitmap, PenLocation());
3193 }
3194
3195
3196 void
DrawTiledBitmapAsync(const BBitmap * bitmap,BRect viewRect,BPoint phase)3197 BView::DrawTiledBitmapAsync(const BBitmap* bitmap, BRect viewRect,
3198 BPoint phase)
3199 {
3200 if (bitmap == NULL || fOwner == NULL || !viewRect.IsValid())
3201 return;
3202
3203 _CheckLockAndSwitchCurrent();
3204
3205 ViewDrawBitmapInfo info;
3206 info.bitmapToken = bitmap->_ServerToken();
3207 info.options = B_TILE_BITMAP;
3208 info.viewRect = viewRect;
3209 info.bitmapRect = bitmap->Bounds().OffsetToCopy(phase);
3210
3211 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
3212 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
3213
3214 _FlushIfNotInTransaction();
3215 }
3216
3217
3218 void
DrawTiledBitmap(const BBitmap * bitmap,BRect viewRect,BPoint phase)3219 BView::DrawTiledBitmap(const BBitmap* bitmap, BRect viewRect, BPoint phase)
3220 {
3221 if (fOwner) {
3222 DrawTiledBitmapAsync(bitmap, viewRect, phase);
3223 Sync();
3224 }
3225 }
3226
3227
3228 void
DrawChar(char c)3229 BView::DrawChar(char c)
3230 {
3231 DrawString(&c, 1, PenLocation());
3232 }
3233
3234
3235 void
DrawChar(char c,BPoint location)3236 BView::DrawChar(char c, BPoint location)
3237 {
3238 DrawString(&c, 1, location);
3239 }
3240
3241
3242 void
DrawString(const char * string,escapement_delta * delta)3243 BView::DrawString(const char* string, escapement_delta* delta)
3244 {
3245 if (string == NULL)
3246 return;
3247
3248 DrawString(string, strlen(string), PenLocation(), delta);
3249 }
3250
3251
3252 void
DrawString(const char * string,BPoint location,escapement_delta * delta)3253 BView::DrawString(const char* string, BPoint location, escapement_delta* delta)
3254 {
3255 if (string == NULL)
3256 return;
3257
3258 DrawString(string, strlen(string), location, delta);
3259 }
3260
3261
3262 void
DrawString(const char * string,int32 length,escapement_delta * delta)3263 BView::DrawString(const char* string, int32 length, escapement_delta* delta)
3264 {
3265 DrawString(string, length, PenLocation(), delta);
3266 }
3267
3268
3269 void
DrawString(const char * string,int32 length,BPoint location,escapement_delta * delta)3270 BView::DrawString(const char* string, int32 length, BPoint location,
3271 escapement_delta* delta)
3272 {
3273 if (fOwner == NULL || string == NULL || length < 1)
3274 return;
3275
3276 _CheckLockAndSwitchCurrent();
3277
3278 ViewDrawStringInfo info;
3279 info.stringLength = length;
3280 info.location = location;
3281 if (delta != NULL)
3282 info.delta = *delta;
3283
3284 // quite often delta will be NULL
3285 if (delta)
3286 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA);
3287 else
3288 fOwner->fLink->StartMessage(AS_DRAW_STRING);
3289
3290 fOwner->fLink->Attach<ViewDrawStringInfo>(info);
3291 fOwner->fLink->Attach(string, length);
3292
3293 _FlushIfNotInTransaction();
3294
3295 // this modifies our pen location, so we invalidate the flag.
3296 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
3297 }
3298
3299
3300 void
DrawString(const char * string,const BPoint * locations,int32 locationCount)3301 BView::DrawString(const char* string, const BPoint* locations,
3302 int32 locationCount)
3303 {
3304 if (string == NULL)
3305 return;
3306
3307 DrawString(string, strlen(string), locations, locationCount);
3308 }
3309
3310
3311 void
DrawString(const char * string,int32 length,const BPoint * locations,int32 locationCount)3312 BView::DrawString(const char* string, int32 length, const BPoint* locations,
3313 int32 locationCount)
3314 {
3315 if (fOwner == NULL || string == NULL || length < 1 || locations == NULL)
3316 return;
3317
3318 _CheckLockAndSwitchCurrent();
3319
3320 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_OFFSETS);
3321
3322 fOwner->fLink->Attach<int32>(length);
3323 fOwner->fLink->Attach<int32>(locationCount);
3324 fOwner->fLink->Attach(string, length);
3325 fOwner->fLink->Attach(locations, locationCount * sizeof(BPoint));
3326
3327 _FlushIfNotInTransaction();
3328
3329 // this modifies our pen location, so we invalidate the flag.
3330 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
3331 }
3332
3333
3334 void
StrokeEllipse(BPoint center,float xRadius,float yRadius,::pattern pattern)3335 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius,
3336 ::pattern pattern)
3337 {
3338 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius,
3339 center.x + xRadius, center.y + yRadius), pattern);
3340 }
3341
3342
3343 void
StrokeEllipse(BRect rect,::pattern pattern)3344 BView::StrokeEllipse(BRect rect, ::pattern pattern)
3345 {
3346 if (fOwner == NULL)
3347 return;
3348
3349 _CheckLockAndSwitchCurrent();
3350 _UpdatePattern(pattern);
3351
3352 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE);
3353 fOwner->fLink->Attach<BRect>(rect);
3354
3355 _FlushIfNotInTransaction();
3356 }
3357
3358
3359 void
FillEllipse(BPoint center,float xRadius,float yRadius,::pattern pattern)3360 BView::FillEllipse(BPoint center, float xRadius, float yRadius,
3361 ::pattern pattern)
3362 {
3363 FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
3364 center.x + xRadius, center.y + yRadius), pattern);
3365 }
3366
3367
3368 void
FillEllipse(BPoint center,float xRadius,float yRadius,const BGradient & gradient)3369 BView::FillEllipse(BPoint center, float xRadius, float yRadius,
3370 const BGradient& gradient)
3371 {
3372 FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
3373 center.x + xRadius, center.y + yRadius), gradient);
3374 }
3375
3376
3377 void
FillEllipse(BRect rect,::pattern pattern)3378 BView::FillEllipse(BRect rect, ::pattern pattern)
3379 {
3380 if (fOwner == NULL)
3381 return;
3382
3383 _CheckLockAndSwitchCurrent();
3384 _UpdatePattern(pattern);
3385
3386 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE);
3387 fOwner->fLink->Attach<BRect>(rect);
3388
3389 _FlushIfNotInTransaction();
3390 }
3391
3392
3393 void
FillEllipse(BRect rect,const BGradient & gradient)3394 BView::FillEllipse(BRect rect, const BGradient& gradient)
3395 {
3396 if (fOwner == NULL)
3397 return;
3398
3399 _CheckLockAndSwitchCurrent();
3400
3401 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT);
3402 fOwner->fLink->Attach<BRect>(rect);
3403 fOwner->fLink->AttachGradient(gradient);
3404
3405 _FlushIfNotInTransaction();
3406 }
3407
3408
3409 void
StrokeArc(BPoint center,float xRadius,float yRadius,float startAngle,float arcAngle,::pattern pattern)3410 BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle,
3411 float arcAngle, ::pattern pattern)
3412 {
3413 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
3414 center.y + yRadius), startAngle, arcAngle, pattern);
3415 }
3416
3417
3418 void
StrokeArc(BRect rect,float startAngle,float arcAngle,::pattern pattern)3419 BView::StrokeArc(BRect rect, float startAngle, float arcAngle,
3420 ::pattern pattern)
3421 {
3422 if (fOwner == NULL)
3423 return;
3424
3425 _CheckLockAndSwitchCurrent();
3426 _UpdatePattern(pattern);
3427
3428 fOwner->fLink->StartMessage(AS_STROKE_ARC);
3429 fOwner->fLink->Attach<BRect>(rect);
3430 fOwner->fLink->Attach<float>(startAngle);
3431 fOwner->fLink->Attach<float>(arcAngle);
3432
3433 _FlushIfNotInTransaction();
3434 }
3435
3436
3437 void
FillArc(BPoint center,float xRadius,float yRadius,float startAngle,float arcAngle,::pattern pattern)3438 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle,
3439 float arcAngle, ::pattern pattern)
3440 {
3441 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
3442 center.y + yRadius), startAngle, arcAngle, pattern);
3443 }
3444
3445
3446 void
FillArc(BPoint center,float xRadius,float yRadius,float startAngle,float arcAngle,const BGradient & gradient)3447 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle,
3448 float arcAngle, const BGradient& gradient)
3449 {
3450 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
3451 center.y + yRadius), startAngle, arcAngle, gradient);
3452 }
3453
3454
3455 void
FillArc(BRect rect,float startAngle,float arcAngle,::pattern pattern)3456 BView::FillArc(BRect rect, float startAngle, float arcAngle,
3457 ::pattern pattern)
3458 {
3459 if (fOwner == NULL)
3460 return;
3461
3462 _CheckLockAndSwitchCurrent();
3463 _UpdatePattern(pattern);
3464
3465 fOwner->fLink->StartMessage(AS_FILL_ARC);
3466 fOwner->fLink->Attach<BRect>(rect);
3467 fOwner->fLink->Attach<float>(startAngle);
3468 fOwner->fLink->Attach<float>(arcAngle);
3469
3470 _FlushIfNotInTransaction();
3471 }
3472
3473
3474 void
FillArc(BRect rect,float startAngle,float arcAngle,const BGradient & gradient)3475 BView::FillArc(BRect rect, float startAngle, float arcAngle,
3476 const BGradient& gradient)
3477 {
3478 if (fOwner == NULL)
3479 return;
3480
3481 _CheckLockAndSwitchCurrent();
3482
3483 fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT);
3484 fOwner->fLink->Attach<BRect>(rect);
3485 fOwner->fLink->Attach<float>(startAngle);
3486 fOwner->fLink->Attach<float>(arcAngle);
3487 fOwner->fLink->AttachGradient(gradient);
3488
3489 _FlushIfNotInTransaction();
3490 }
3491
3492
3493 void
StrokeBezier(BPoint * controlPoints,::pattern pattern)3494 BView::StrokeBezier(BPoint* controlPoints, ::pattern pattern)
3495 {
3496 if (fOwner == NULL)
3497 return;
3498
3499 _CheckLockAndSwitchCurrent();
3500 _UpdatePattern(pattern);
3501
3502 fOwner->fLink->StartMessage(AS_STROKE_BEZIER);
3503 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
3504 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
3505 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
3506 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
3507
3508 _FlushIfNotInTransaction();
3509 }
3510
3511
3512 void
FillBezier(BPoint * controlPoints,::pattern pattern)3513 BView::FillBezier(BPoint* controlPoints, ::pattern pattern)
3514 {
3515 if (fOwner == NULL)
3516 return;
3517
3518 _CheckLockAndSwitchCurrent();
3519 _UpdatePattern(pattern);
3520
3521 fOwner->fLink->StartMessage(AS_FILL_BEZIER);
3522 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
3523 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
3524 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
3525 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
3526
3527 _FlushIfNotInTransaction();
3528 }
3529
3530
3531 void
FillBezier(BPoint * controlPoints,const BGradient & gradient)3532 BView::FillBezier(BPoint* controlPoints, const BGradient& gradient)
3533 {
3534 if (fOwner == NULL)
3535 return;
3536
3537 _CheckLockAndSwitchCurrent();
3538
3539 fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT);
3540 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
3541 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
3542 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
3543 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
3544 fOwner->fLink->AttachGradient(gradient);
3545
3546 _FlushIfNotInTransaction();
3547 }
3548
3549
3550 void
StrokePolygon(const BPolygon * polygon,bool closed,::pattern pattern)3551 BView::StrokePolygon(const BPolygon* polygon, bool closed, ::pattern pattern)
3552 {
3553 if (polygon == NULL)
3554 return;
3555
3556 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed,
3557 pattern);
3558 }
3559
3560
3561 void
StrokePolygon(const BPoint * pointArray,int32 numPoints,bool closed,::pattern pattern)3562 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed,
3563 ::pattern pattern)
3564 {
3565 BPolygon polygon(pointArray, numPoints);
3566
3567 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed,
3568 pattern);
3569 }
3570
3571
3572 void
StrokePolygon(const BPoint * pointArray,int32 numPoints,BRect bounds,bool closed,::pattern pattern)3573 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3574 bool closed, ::pattern pattern)
3575 {
3576 if (pointArray == NULL
3577 || numPoints <= 1
3578 || fOwner == NULL)
3579 return;
3580
3581 _CheckLockAndSwitchCurrent();
3582 _UpdatePattern(pattern);
3583
3584 BPolygon polygon(pointArray, numPoints);
3585 polygon.MapTo(polygon.Frame(), bounds);
3586
3587 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON,
3588 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool)
3589 + sizeof(int32)) == B_OK) {
3590 fOwner->fLink->Attach<BRect>(polygon.Frame());
3591 fOwner->fLink->Attach<bool>(closed);
3592 fOwner->fLink->Attach<int32>(polygon.fCount);
3593 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint));
3594
3595 _FlushIfNotInTransaction();
3596 } else {
3597 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3598 }
3599 }
3600
3601
3602 void
FillPolygon(const BPolygon * polygon,::pattern pattern)3603 BView::FillPolygon(const BPolygon* polygon, ::pattern pattern)
3604 {
3605 if (polygon == NULL
3606 || polygon->fCount <= 2
3607 || fOwner == NULL)
3608 return;
3609
3610 _CheckLockAndSwitchCurrent();
3611 _UpdatePattern(pattern);
3612
3613 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON,
3614 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
3615 == B_OK) {
3616 fOwner->fLink->Attach<BRect>(polygon->Frame());
3617 fOwner->fLink->Attach<int32>(polygon->fCount);
3618 fOwner->fLink->Attach(polygon->fPoints,
3619 polygon->fCount * sizeof(BPoint));
3620
3621 _FlushIfNotInTransaction();
3622 } else {
3623 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3624 }
3625 }
3626
3627
3628 void
FillPolygon(const BPolygon * polygon,const BGradient & gradient)3629 BView::FillPolygon(const BPolygon* polygon, const BGradient& gradient)
3630 {
3631 if (polygon == NULL
3632 || polygon->fCount <= 2
3633 || fOwner == NULL)
3634 return;
3635
3636 _CheckLockAndSwitchCurrent();
3637
3638 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT,
3639 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
3640 == B_OK) {
3641 fOwner->fLink->Attach<BRect>(polygon->Frame());
3642 fOwner->fLink->Attach<int32>(polygon->fCount);
3643 fOwner->fLink->Attach(polygon->fPoints,
3644 polygon->fCount * sizeof(BPoint));
3645 fOwner->fLink->AttachGradient(gradient);
3646
3647 _FlushIfNotInTransaction();
3648 } else {
3649 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3650 }
3651 }
3652
3653
3654 void
FillPolygon(const BPoint * pointArray,int32 numPoints,::pattern pattern)3655 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, ::pattern pattern)
3656 {
3657 if (pointArray == NULL)
3658 return;
3659
3660 BPolygon polygon(pointArray, numPoints);
3661 FillPolygon(&polygon, pattern);
3662 }
3663
3664
3665 void
FillPolygon(const BPoint * pointArray,int32 numPoints,const BGradient & gradient)3666 BView::FillPolygon(const BPoint* pointArray, int32 numPoints,
3667 const BGradient& gradient)
3668 {
3669 if (pointArray == NULL)
3670 return;
3671
3672 BPolygon polygon(pointArray, numPoints);
3673 FillPolygon(&polygon, gradient);
3674 }
3675
3676
3677 void
FillPolygon(const BPoint * pointArray,int32 numPoints,BRect bounds,::pattern pattern)3678 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3679 ::pattern pattern)
3680 {
3681 if (pointArray == NULL)
3682 return;
3683
3684 BPolygon polygon(pointArray, numPoints);
3685
3686 polygon.MapTo(polygon.Frame(), bounds);
3687 FillPolygon(&polygon, pattern);
3688 }
3689
3690
3691 void
FillPolygon(const BPoint * pointArray,int32 numPoints,BRect bounds,const BGradient & gradient)3692 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3693 const BGradient& gradient)
3694 {
3695 if (pointArray == NULL)
3696 return;
3697
3698 BPolygon polygon(pointArray, numPoints);
3699
3700 polygon.MapTo(polygon.Frame(), bounds);
3701 FillPolygon(&polygon, gradient);
3702 }
3703
3704
3705 void
StrokeRect(BRect rect,::pattern pattern)3706 BView::StrokeRect(BRect rect, ::pattern pattern)
3707 {
3708 if (fOwner == NULL)
3709 return;
3710
3711 _CheckLockAndSwitchCurrent();
3712 _UpdatePattern(pattern);
3713
3714 fOwner->fLink->StartMessage(AS_STROKE_RECT);
3715 fOwner->fLink->Attach<BRect>(rect);
3716
3717 _FlushIfNotInTransaction();
3718 }
3719
3720
3721 void
FillRect(BRect rect,::pattern pattern)3722 BView::FillRect(BRect rect, ::pattern pattern)
3723 {
3724 if (fOwner == NULL)
3725 return;
3726
3727 // NOTE: ensuring compatibility with R5,
3728 // invalid rects are not filled, they are stroked though!
3729 if (!rect.IsValid())
3730 return;
3731
3732 _CheckLockAndSwitchCurrent();
3733 _UpdatePattern(pattern);
3734
3735 fOwner->fLink->StartMessage(AS_FILL_RECT);
3736 fOwner->fLink->Attach<BRect>(rect);
3737
3738 _FlushIfNotInTransaction();
3739 }
3740
3741
3742 void
FillRect(BRect rect,const BGradient & gradient)3743 BView::FillRect(BRect rect, const BGradient& gradient)
3744 {
3745 if (fOwner == NULL)
3746 return;
3747
3748 // NOTE: ensuring compatibility with R5,
3749 // invalid rects are not filled, they are stroked though!
3750 if (!rect.IsValid())
3751 return;
3752
3753 _CheckLockAndSwitchCurrent();
3754
3755 fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT);
3756 fOwner->fLink->Attach<BRect>(rect);
3757 fOwner->fLink->AttachGradient(gradient);
3758
3759 _FlushIfNotInTransaction();
3760 }
3761
3762
3763 void
StrokeRoundRect(BRect rect,float xRadius,float yRadius,::pattern pattern)3764 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius,
3765 ::pattern pattern)
3766 {
3767 if (fOwner == NULL)
3768 return;
3769
3770 _CheckLockAndSwitchCurrent();
3771 _UpdatePattern(pattern);
3772
3773 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT);
3774 fOwner->fLink->Attach<BRect>(rect);
3775 fOwner->fLink->Attach<float>(xRadius);
3776 fOwner->fLink->Attach<float>(yRadius);
3777
3778 _FlushIfNotInTransaction();
3779 }
3780
3781
3782 void
FillRoundRect(BRect rect,float xRadius,float yRadius,::pattern pattern)3783 BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
3784 ::pattern pattern)
3785 {
3786 if (fOwner == NULL)
3787 return;
3788
3789 _CheckLockAndSwitchCurrent();
3790
3791 _UpdatePattern(pattern);
3792
3793 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT);
3794 fOwner->fLink->Attach<BRect>(rect);
3795 fOwner->fLink->Attach<float>(xRadius);
3796 fOwner->fLink->Attach<float>(yRadius);
3797
3798 _FlushIfNotInTransaction();
3799 }
3800
3801
3802 void
FillRoundRect(BRect rect,float xRadius,float yRadius,const BGradient & gradient)3803 BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
3804 const BGradient& gradient)
3805 {
3806 if (fOwner == NULL)
3807 return;
3808
3809 _CheckLockAndSwitchCurrent();
3810
3811 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT);
3812 fOwner->fLink->Attach<BRect>(rect);
3813 fOwner->fLink->Attach<float>(xRadius);
3814 fOwner->fLink->Attach<float>(yRadius);
3815 fOwner->fLink->AttachGradient(gradient);
3816
3817 _FlushIfNotInTransaction();
3818 }
3819
3820
3821 void
FillRegion(BRegion * region,::pattern pattern)3822 BView::FillRegion(BRegion* region, ::pattern pattern)
3823 {
3824 if (region == NULL || fOwner == NULL)
3825 return;
3826
3827 _CheckLockAndSwitchCurrent();
3828
3829 _UpdatePattern(pattern);
3830
3831 fOwner->fLink->StartMessage(AS_FILL_REGION);
3832 fOwner->fLink->AttachRegion(*region);
3833
3834 _FlushIfNotInTransaction();
3835 }
3836
3837
3838 void
FillRegion(BRegion * region,const BGradient & gradient)3839 BView::FillRegion(BRegion* region, const BGradient& gradient)
3840 {
3841 if (region == NULL || fOwner == NULL)
3842 return;
3843
3844 _CheckLockAndSwitchCurrent();
3845
3846 fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT);
3847 fOwner->fLink->AttachRegion(*region);
3848 fOwner->fLink->AttachGradient(gradient);
3849
3850 _FlushIfNotInTransaction();
3851 }
3852
3853
3854 void
StrokeTriangle(BPoint point1,BPoint point2,BPoint point3,BRect bounds,::pattern pattern)3855 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds,
3856 ::pattern pattern)
3857 {
3858 if (fOwner == NULL)
3859 return;
3860
3861 _CheckLockAndSwitchCurrent();
3862
3863 _UpdatePattern(pattern);
3864
3865 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE);
3866 fOwner->fLink->Attach<BPoint>(point1);
3867 fOwner->fLink->Attach<BPoint>(point2);
3868 fOwner->fLink->Attach<BPoint>(point3);
3869 fOwner->fLink->Attach<BRect>(bounds);
3870
3871 _FlushIfNotInTransaction();
3872 }
3873
3874
3875 void
StrokeTriangle(BPoint point1,BPoint point2,BPoint point3,::pattern pattern)3876 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3,
3877 ::pattern pattern)
3878 {
3879 if (fOwner) {
3880 // we construct the smallest rectangle that contains the 3 points
3881 // for the 1st point
3882 BRect bounds(point1, point1);
3883
3884 // for the 2nd point
3885 if (point2.x < bounds.left)
3886 bounds.left = point2.x;
3887
3888 if (point2.y < bounds.top)
3889 bounds.top = point2.y;
3890
3891 if (point2.x > bounds.right)
3892 bounds.right = point2.x;
3893
3894 if (point2.y > bounds.bottom)
3895 bounds.bottom = point2.y;
3896
3897 // for the 3rd point
3898 if (point3.x < bounds.left)
3899 bounds.left = point3.x;
3900
3901 if (point3.y < bounds.top)
3902 bounds.top = point3.y;
3903
3904 if (point3.x > bounds.right)
3905 bounds.right = point3.x;
3906
3907 if (point3.y > bounds.bottom)
3908 bounds.bottom = point3.y;
3909
3910 StrokeTriangle(point1, point2, point3, bounds, pattern);
3911 }
3912 }
3913
3914
3915 void
FillTriangle(BPoint point1,BPoint point2,BPoint point3,::pattern pattern)3916 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3917 ::pattern pattern)
3918 {
3919 if (fOwner) {
3920 // we construct the smallest rectangle that contains the 3 points
3921 // for the 1st point
3922 BRect bounds(point1, point1);
3923
3924 // for the 2nd point
3925 if (point2.x < bounds.left)
3926 bounds.left = point2.x;
3927
3928 if (point2.y < bounds.top)
3929 bounds.top = point2.y;
3930
3931 if (point2.x > bounds.right)
3932 bounds.right = point2.x;
3933
3934 if (point2.y > bounds.bottom)
3935 bounds.bottom = point2.y;
3936
3937 // for the 3rd point
3938 if (point3.x < bounds.left)
3939 bounds.left = point3.x;
3940
3941 if (point3.y < bounds.top)
3942 bounds.top = point3.y;
3943
3944 if (point3.x > bounds.right)
3945 bounds.right = point3.x;
3946
3947 if (point3.y > bounds.bottom)
3948 bounds.bottom = point3.y;
3949
3950 FillTriangle(point1, point2, point3, bounds, pattern);
3951 }
3952 }
3953
3954
3955 void
FillTriangle(BPoint point1,BPoint point2,BPoint point3,const BGradient & gradient)3956 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3957 const BGradient& gradient)
3958 {
3959 if (fOwner) {
3960 // we construct the smallest rectangle that contains the 3 points
3961 // for the 1st point
3962 BRect bounds(point1, point1);
3963
3964 // for the 2nd point
3965 if (point2.x < bounds.left)
3966 bounds.left = point2.x;
3967
3968 if (point2.y < bounds.top)
3969 bounds.top = point2.y;
3970
3971 if (point2.x > bounds.right)
3972 bounds.right = point2.x;
3973
3974 if (point2.y > bounds.bottom)
3975 bounds.bottom = point2.y;
3976
3977 // for the 3rd point
3978 if (point3.x < bounds.left)
3979 bounds.left = point3.x;
3980
3981 if (point3.y < bounds.top)
3982 bounds.top = point3.y;
3983
3984 if (point3.x > bounds.right)
3985 bounds.right = point3.x;
3986
3987 if (point3.y > bounds.bottom)
3988 bounds.bottom = point3.y;
3989
3990 FillTriangle(point1, point2, point3, bounds, gradient);
3991 }
3992 }
3993
3994
3995 void
FillTriangle(BPoint point1,BPoint point2,BPoint point3,BRect bounds,::pattern pattern)3996 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3997 BRect bounds, ::pattern pattern)
3998 {
3999 if (fOwner == NULL)
4000 return;
4001
4002 _CheckLockAndSwitchCurrent();
4003 _UpdatePattern(pattern);
4004
4005 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE);
4006 fOwner->fLink->Attach<BPoint>(point1);
4007 fOwner->fLink->Attach<BPoint>(point2);
4008 fOwner->fLink->Attach<BPoint>(point3);
4009 fOwner->fLink->Attach<BRect>(bounds);
4010
4011 _FlushIfNotInTransaction();
4012 }
4013
4014
4015 void
FillTriangle(BPoint point1,BPoint point2,BPoint point3,BRect bounds,const BGradient & gradient)4016 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds,
4017 const BGradient& gradient)
4018 {
4019 if (fOwner == NULL)
4020 return;
4021
4022 _CheckLockAndSwitchCurrent();
4023 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT);
4024 fOwner->fLink->Attach<BPoint>(point1);
4025 fOwner->fLink->Attach<BPoint>(point2);
4026 fOwner->fLink->Attach<BPoint>(point3);
4027 fOwner->fLink->Attach<BRect>(bounds);
4028 fOwner->fLink->AttachGradient(gradient);
4029
4030 _FlushIfNotInTransaction();
4031 }
4032
4033
4034 void
StrokeLine(BPoint toPoint,::pattern pattern)4035 BView::StrokeLine(BPoint toPoint, ::pattern pattern)
4036 {
4037 StrokeLine(PenLocation(), toPoint, pattern);
4038 }
4039
4040
4041 void
StrokeLine(BPoint start,BPoint end,::pattern pattern)4042 BView::StrokeLine(BPoint start, BPoint end, ::pattern pattern)
4043 {
4044 if (fOwner == NULL)
4045 return;
4046
4047 _CheckLockAndSwitchCurrent();
4048 _UpdatePattern(pattern);
4049
4050 ViewStrokeLineInfo info;
4051 info.startPoint = start;
4052 info.endPoint = end;
4053
4054 fOwner->fLink->StartMessage(AS_STROKE_LINE);
4055 fOwner->fLink->Attach<ViewStrokeLineInfo>(info);
4056
4057 _FlushIfNotInTransaction();
4058
4059 // this modifies our pen location, so we invalidate the flag.
4060 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
4061 }
4062
4063
4064 void
StrokeShape(BShape * shape,::pattern pattern)4065 BView::StrokeShape(BShape* shape, ::pattern pattern)
4066 {
4067 if (shape == NULL || fOwner == NULL)
4068 return;
4069
4070 shape_data* sd = BShape::Private(*shape).PrivateData();
4071 if (sd->opCount == 0 || sd->ptCount == 0)
4072 return;
4073
4074 _CheckLockAndSwitchCurrent();
4075 _UpdatePattern(pattern);
4076
4077 fOwner->fLink->StartMessage(AS_STROKE_SHAPE);
4078 fOwner->fLink->Attach<BRect>(shape->Bounds());
4079 fOwner->fLink->AttachShape(*shape);
4080
4081 _FlushIfNotInTransaction();
4082 }
4083
4084
4085 void
FillShape(BShape * shape,::pattern pattern)4086 BView::FillShape(BShape* shape, ::pattern pattern)
4087 {
4088 if (shape == NULL || fOwner == NULL)
4089 return;
4090
4091 shape_data* sd = BShape::Private(*shape).PrivateData();
4092 if (sd->opCount == 0 || sd->ptCount == 0)
4093 return;
4094
4095 _CheckLockAndSwitchCurrent();
4096 _UpdatePattern(pattern);
4097
4098 fOwner->fLink->StartMessage(AS_FILL_SHAPE);
4099 fOwner->fLink->Attach<BRect>(shape->Bounds());
4100 fOwner->fLink->AttachShape(*shape);
4101
4102 _FlushIfNotInTransaction();
4103 }
4104
4105
4106 void
FillShape(BShape * shape,const BGradient & gradient)4107 BView::FillShape(BShape* shape, const BGradient& gradient)
4108 {
4109 if (shape == NULL || fOwner == NULL)
4110 return;
4111
4112 shape_data* sd = BShape::Private(*shape).PrivateData();
4113 if (sd->opCount == 0 || sd->ptCount == 0)
4114 return;
4115
4116 _CheckLockAndSwitchCurrent();
4117
4118 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT);
4119 fOwner->fLink->Attach<BRect>(shape->Bounds());
4120 fOwner->fLink->AttachShape(*shape);
4121 fOwner->fLink->AttachGradient(gradient);
4122
4123 _FlushIfNotInTransaction();
4124 }
4125
4126
4127 void
BeginLineArray(int32 count)4128 BView::BeginLineArray(int32 count)
4129 {
4130 if (fOwner == NULL)
4131 return;
4132
4133 if (count <= 0)
4134 debugger("Calling BeginLineArray with a count <= 0");
4135
4136 _CheckLock();
4137
4138 if (fCommArray) {
4139 debugger("Can't nest BeginLineArray calls");
4140 // not fatal, but it helps during
4141 // development of your app and is in
4142 // line with R5...
4143 delete[] fCommArray->array;
4144 delete fCommArray;
4145 }
4146
4147 // TODO: since this method cannot return failure, and further AddLine()
4148 // calls with a NULL fCommArray would drop into the debugger anyway,
4149 // we allow the possible std::bad_alloc exceptions here...
4150 fCommArray = new _array_data_;
4151 fCommArray->count = 0;
4152
4153 // Make sure the fCommArray is initialized to reasonable values in cases of
4154 // bad_alloc. At least the exception can be caught and EndLineArray won't
4155 // crash.
4156 fCommArray->array = NULL;
4157 fCommArray->maxCount = 0;
4158
4159 fCommArray->array = new ViewLineArrayInfo[count];
4160 fCommArray->maxCount = count;
4161 }
4162
4163
4164 void
AddLine(BPoint start,BPoint end,rgb_color color)4165 BView::AddLine(BPoint start, BPoint end, rgb_color color)
4166 {
4167 if (fOwner == NULL)
4168 return;
4169
4170 if (!fCommArray)
4171 debugger("BeginLineArray must be called before using AddLine");
4172
4173 _CheckLock();
4174
4175 const uint32 &arrayCount = fCommArray->count;
4176 if (arrayCount < fCommArray->maxCount) {
4177 fCommArray->array[arrayCount].startPoint = start;
4178 fCommArray->array[arrayCount].endPoint = end;
4179 fCommArray->array[arrayCount].color = color;
4180
4181 fCommArray->count++;
4182 }
4183 }
4184
4185
4186 void
EndLineArray()4187 BView::EndLineArray()
4188 {
4189 if (fOwner == NULL)
4190 return;
4191
4192 if (fCommArray == NULL)
4193 debugger("Can't call EndLineArray before BeginLineArray");
4194
4195 _CheckLockAndSwitchCurrent();
4196
4197 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY);
4198 fOwner->fLink->Attach<int32>(fCommArray->count);
4199 fOwner->fLink->Attach(fCommArray->array,
4200 fCommArray->count * sizeof(ViewLineArrayInfo));
4201
4202 _FlushIfNotInTransaction();
4203
4204 _RemoveCommArray();
4205 }
4206
4207
4208 void
SetDiskMode(char * filename,long offset)4209 BView::SetDiskMode(char* filename, long offset)
4210 {
4211 // TODO: implement
4212 // One BeBook version has this to say about SetDiskMode():
4213 //
4214 // "Begins recording a picture to the file with the given filename
4215 // at the given offset. Subsequent drawing commands sent to the view
4216 // will be written to the file until EndPicture() is called. The
4217 // stored commands may be played from the file with DrawPicture()."
4218 }
4219
4220
4221 void
BeginPicture(BPicture * picture)4222 BView::BeginPicture(BPicture* picture)
4223 {
4224 if (_CheckOwnerLockAndSwitchCurrent()
4225 && picture && picture->fUsurped == NULL) {
4226 picture->Usurp(fCurrentPicture);
4227 fCurrentPicture = picture;
4228
4229 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE);
4230 }
4231 }
4232
4233
4234 void
AppendToPicture(BPicture * picture)4235 BView::AppendToPicture(BPicture* picture)
4236 {
4237 _CheckLockAndSwitchCurrent();
4238
4239 if (picture && picture->fUsurped == NULL) {
4240 int32 token = picture->Token();
4241
4242 if (token == -1) {
4243 BeginPicture(picture);
4244 } else {
4245 picture->SetToken(-1);
4246 picture->Usurp(fCurrentPicture);
4247 fCurrentPicture = picture;
4248 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE);
4249 fOwner->fLink->Attach<int32>(token);
4250 }
4251 }
4252 }
4253
4254
4255 BPicture*
EndPicture()4256 BView::EndPicture()
4257 {
4258 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) {
4259 int32 token;
4260
4261 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE);
4262
4263 int32 code;
4264 if (fOwner->fLink->FlushWithReply(code) == B_OK
4265 && code == B_OK
4266 && fOwner->fLink->Read<int32>(&token) == B_OK) {
4267 BPicture* picture = fCurrentPicture;
4268 fCurrentPicture = picture->StepDown();
4269 picture->SetToken(token);
4270
4271 // TODO do this more efficient e.g. use a shared area and let the
4272 // client write into it
4273 picture->_Download();
4274 return picture;
4275 }
4276 }
4277
4278 return NULL;
4279 }
4280
4281
4282 void
SetViewBitmap(const BBitmap * bitmap,BRect srcRect,BRect dstRect,uint32 followFlags,uint32 options)4283 BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
4284 uint32 followFlags, uint32 options)
4285 {
4286 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options);
4287 }
4288
4289
4290 void
SetViewBitmap(const BBitmap * bitmap,uint32 followFlags,uint32 options)4291 BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options)
4292 {
4293 BRect rect;
4294 if (bitmap)
4295 rect = bitmap->Bounds();
4296
4297 rect.OffsetTo(B_ORIGIN);
4298
4299 _SetViewBitmap(bitmap, rect, rect, followFlags, options);
4300 }
4301
4302
4303 void
ClearViewBitmap()4304 BView::ClearViewBitmap()
4305 {
4306 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
4307 }
4308
4309
4310 status_t
SetViewOverlay(const BBitmap * overlay,BRect srcRect,BRect dstRect,rgb_color * colorKey,uint32 followFlags,uint32 options)4311 BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect,
4312 rgb_color* colorKey, uint32 followFlags, uint32 options)
4313 {
4314 if (overlay == NULL || (overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0)
4315 return B_BAD_VALUE;
4316
4317 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags,
4318 options | AS_REQUEST_COLOR_KEY);
4319 if (status == B_OK) {
4320 // read the color that will be treated as transparent
4321 fOwner->fLink->Read<rgb_color>(colorKey);
4322 }
4323
4324 return status;
4325 }
4326
4327
4328 status_t
SetViewOverlay(const BBitmap * overlay,rgb_color * colorKey,uint32 followFlags,uint32 options)4329 BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey,
4330 uint32 followFlags, uint32 options)
4331 {
4332 if (overlay == NULL)
4333 return B_BAD_VALUE;
4334
4335 BRect rect = overlay->Bounds();
4336 rect.OffsetTo(B_ORIGIN);
4337
4338 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options);
4339 }
4340
4341
4342 void
ClearViewOverlay()4343 BView::ClearViewOverlay()
4344 {
4345 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
4346 }
4347
4348
4349 void
CopyBits(BRect src,BRect dst)4350 BView::CopyBits(BRect src, BRect dst)
4351 {
4352 if (fOwner == NULL)
4353 return;
4354
4355 if (!src.IsValid() || !dst.IsValid())
4356 return;
4357
4358 _CheckLockAndSwitchCurrent();
4359
4360 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS);
4361 fOwner->fLink->Attach<BRect>(src);
4362 fOwner->fLink->Attach<BRect>(dst);
4363
4364 _FlushIfNotInTransaction();
4365 }
4366
4367
4368 void
DrawPicture(const BPicture * picture)4369 BView::DrawPicture(const BPicture* picture)
4370 {
4371 if (picture == NULL)
4372 return;
4373
4374 DrawPictureAsync(picture, PenLocation());
4375 Sync();
4376 }
4377
4378
4379 void
DrawPicture(const BPicture * picture,BPoint where)4380 BView::DrawPicture(const BPicture* picture, BPoint where)
4381 {
4382 if (picture == NULL)
4383 return;
4384
4385 DrawPictureAsync(picture, where);
4386 Sync();
4387 }
4388
4389
4390 void
DrawPicture(const char * filename,long offset,BPoint where)4391 BView::DrawPicture(const char* filename, long offset, BPoint where)
4392 {
4393 if (!filename)
4394 return;
4395
4396 DrawPictureAsync(filename, offset, where);
4397 Sync();
4398 }
4399
4400
4401 void
DrawPictureAsync(const BPicture * picture)4402 BView::DrawPictureAsync(const BPicture* picture)
4403 {
4404 if (picture == NULL)
4405 return;
4406
4407 DrawPictureAsync(picture, PenLocation());
4408 }
4409
4410
4411 void
DrawPictureAsync(const BPicture * picture,BPoint where)4412 BView::DrawPictureAsync(const BPicture* picture, BPoint where)
4413 {
4414 if (picture == NULL)
4415 return;
4416
4417 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) {
4418 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE);
4419 fOwner->fLink->Attach<int32>(picture->Token());
4420 fOwner->fLink->Attach<BPoint>(where);
4421
4422 _FlushIfNotInTransaction();
4423 }
4424 }
4425
4426
4427 void
DrawPictureAsync(const char * filename,long offset,BPoint where)4428 BView::DrawPictureAsync(const char* filename, long offset, BPoint where)
4429 {
4430 if (!filename)
4431 return;
4432
4433 // TODO: Test
4434 BFile file(filename, B_READ_ONLY);
4435 if (file.InitCheck() < B_OK)
4436 return;
4437
4438 file.Seek(offset, SEEK_SET);
4439
4440 BPicture picture;
4441 if (picture.Unflatten(&file) < B_OK)
4442 return;
4443
4444 DrawPictureAsync(&picture, where);
4445 }
4446
4447
4448 void
BeginLayer(uint8 opacity)4449 BView::BeginLayer(uint8 opacity)
4450 {
4451 if (_CheckOwnerLockAndSwitchCurrent()) {
4452 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_LAYER);
4453 fOwner->fLink->Attach<uint8>(opacity);
4454 _FlushIfNotInTransaction();
4455 }
4456 }
4457
4458
4459 void
EndLayer()4460 BView::EndLayer()
4461 {
4462 if (_CheckOwnerLockAndSwitchCurrent()) {
4463 fOwner->fLink->StartMessage(AS_VIEW_END_LAYER);
4464 _FlushIfNotInTransaction();
4465 }
4466 }
4467
4468
4469 void
Invalidate(BRect invalRect)4470 BView::Invalidate(BRect invalRect)
4471 {
4472 if (fOwner == NULL)
4473 return;
4474
4475 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS.
4476 // On the server side, the invalid rect will be converted to a BRegion,
4477 // which rounds in a different manner, so that it really includes the
4478 // fractional coordinates of a BRect (ie ceilf(rect.right) &
4479 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the
4480 // different rounding here to stay compatible in both ways.
4481 invalRect.left = (int)invalRect.left;
4482 invalRect.top = (int)invalRect.top;
4483 invalRect.right = (int)invalRect.right;
4484 invalRect.bottom = (int)invalRect.bottom;
4485 if (!invalRect.IsValid())
4486 return;
4487
4488 _CheckLockAndSwitchCurrent();
4489
4490 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT);
4491 fOwner->fLink->Attach<BRect>(invalRect);
4492
4493 // TODO: determine why this check isn't working correctly.
4494 #if 0
4495 if (!fOwner->fUpdateRequested) {
4496 fOwner->fLink->Flush();
4497 fOwner->fUpdateRequested = true;
4498 }
4499 #else
4500 fOwner->fLink->Flush();
4501 #endif
4502 }
4503
4504
4505 void
Invalidate(const BRegion * region)4506 BView::Invalidate(const BRegion* region)
4507 {
4508 if (region == NULL || fOwner == NULL)
4509 return;
4510
4511 _CheckLockAndSwitchCurrent();
4512
4513 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION);
4514 fOwner->fLink->AttachRegion(*region);
4515
4516 // TODO: See above.
4517 #if 0
4518 if (!fOwner->fUpdateRequested) {
4519 fOwner->fLink->Flush();
4520 fOwner->fUpdateRequested = true;
4521 }
4522 #else
4523 fOwner->fLink->Flush();
4524 #endif
4525 }
4526
4527
4528 void
Invalidate()4529 BView::Invalidate()
4530 {
4531 Invalidate(Bounds());
4532 }
4533
4534
4535 void
DelayedInvalidate(bigtime_t delay)4536 BView::DelayedInvalidate(bigtime_t delay)
4537 {
4538 DelayedInvalidate(delay, Bounds());
4539 }
4540
4541
4542 void
DelayedInvalidate(bigtime_t delay,BRect invalRect)4543 BView::DelayedInvalidate(bigtime_t delay, BRect invalRect)
4544 {
4545 if (fOwner == NULL)
4546 return;
4547
4548 invalRect.left = (int)invalRect.left;
4549 invalRect.top = (int)invalRect.top;
4550 invalRect.right = (int)invalRect.right;
4551 invalRect.bottom = (int)invalRect.bottom;
4552 if (!invalRect.IsValid())
4553 return;
4554
4555 _CheckLockAndSwitchCurrent();
4556
4557 fOwner->fLink->StartMessage(AS_VIEW_DELAYED_INVALIDATE_RECT);
4558 fOwner->fLink->Attach<bigtime_t>(system_time() + delay);
4559 fOwner->fLink->Attach<BRect>(invalRect);
4560 fOwner->fLink->Flush();
4561 }
4562
4563
4564 void
InvertRect(BRect rect)4565 BView::InvertRect(BRect rect)
4566 {
4567 if (fOwner) {
4568 _CheckLockAndSwitchCurrent();
4569
4570 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT);
4571 fOwner->fLink->Attach<BRect>(rect);
4572
4573 _FlushIfNotInTransaction();
4574 }
4575 }
4576
4577
4578 // #pragma mark - View Hierarchy Functions
4579
4580
4581 void
AddChild(BView * child,BView * before)4582 BView::AddChild(BView* child, BView* before)
4583 {
4584 STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n",
4585 this->Name(),
4586 child != NULL && child->Name() ? child->Name() : "NULL",
4587 before != NULL && before->Name() ? before->Name() : "NULL"));
4588
4589 if (!_AddChild(child, before))
4590 return;
4591
4592 if (fLayoutData->fLayout)
4593 fLayoutData->fLayout->AddView(child);
4594 }
4595
4596
4597 bool
AddChild(BLayoutItem * child)4598 BView::AddChild(BLayoutItem* child)
4599 {
4600 if (!fLayoutData->fLayout)
4601 return false;
4602 return fLayoutData->fLayout->AddItem(child);
4603 }
4604
4605
4606 bool
_AddChild(BView * child,BView * before)4607 BView::_AddChild(BView* child, BView* before)
4608 {
4609 if (!child)
4610 return false;
4611
4612 if (child->fParent != NULL) {
4613 debugger("AddChild failed - the view already has a parent.");
4614 return false;
4615 }
4616
4617 if (child == this) {
4618 debugger("AddChild failed - cannot add a view to itself.");
4619 return false;
4620 }
4621
4622 bool lockedOwner = false;
4623 if (fOwner && !fOwner->IsLocked()) {
4624 fOwner->Lock();
4625 lockedOwner = true;
4626 }
4627
4628 if (!_AddChildToList(child, before)) {
4629 debugger("AddChild failed!");
4630 if (lockedOwner)
4631 fOwner->Unlock();
4632 return false;
4633 }
4634
4635 if (fOwner) {
4636 _CheckLockAndSwitchCurrent();
4637
4638 child->_SetOwner(fOwner);
4639 child->_CreateSelf();
4640 child->_Attach();
4641
4642 if (lockedOwner)
4643 fOwner->Unlock();
4644 }
4645
4646 InvalidateLayout();
4647
4648 return true;
4649 }
4650
4651
4652 bool
RemoveChild(BView * child)4653 BView::RemoveChild(BView* child)
4654 {
4655 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name()));
4656
4657 if (!child)
4658 return false;
4659
4660 if (child->fParent != this)
4661 return false;
4662
4663 return child->RemoveSelf();
4664 }
4665
4666
4667 int32
CountChildren() const4668 BView::CountChildren() const
4669 {
4670 _CheckLock();
4671
4672 uint32 count = 0;
4673 BView* child = fFirstChild;
4674
4675 while (child != NULL) {
4676 count++;
4677 child = child->fNextSibling;
4678 }
4679
4680 return count;
4681 }
4682
4683
4684 BView*
ChildAt(int32 index) const4685 BView::ChildAt(int32 index) const
4686 {
4687 _CheckLock();
4688
4689 BView* child = fFirstChild;
4690 while (child != NULL && index-- > 0) {
4691 child = child->fNextSibling;
4692 }
4693
4694 return child;
4695 }
4696
4697
4698 BView*
NextSibling() const4699 BView::NextSibling() const
4700 {
4701 return fNextSibling;
4702 }
4703
4704
4705 BView*
PreviousSibling() const4706 BView::PreviousSibling() const
4707 {
4708 return fPreviousSibling;
4709 }
4710
4711
4712 bool
RemoveSelf()4713 BView::RemoveSelf()
4714 {
4715 _RemoveLayoutItemsFromLayout(false);
4716
4717 return _RemoveSelf();
4718 }
4719
4720
4721 bool
_RemoveSelf()4722 BView::_RemoveSelf()
4723 {
4724 STRACE(("BView(%s)::_RemoveSelf()\n", Name()));
4725
4726 // Remove this child from its parent
4727
4728 BWindow* owner = fOwner;
4729 _CheckLock();
4730
4731 if (owner != NULL) {
4732 _UpdateStateForRemove();
4733 _Detach();
4734 }
4735
4736 BView* parent = fParent;
4737 if (!parent || !parent->_RemoveChildFromList(this))
4738 return false;
4739
4740 if (owner != NULL && !fTopLevelView) {
4741 // the top level view is deleted by the app_server automatically
4742 owner->fLink->StartMessage(AS_VIEW_DELETE);
4743 owner->fLink->Attach<int32>(_get_object_token_(this));
4744 }
4745
4746 parent->InvalidateLayout();
4747
4748 STRACE(("DONE: BView(%s)::_RemoveSelf()\n", Name()));
4749
4750 return true;
4751 }
4752
4753
4754 void
_RemoveLayoutItemsFromLayout(bool deleteItems)4755 BView::_RemoveLayoutItemsFromLayout(bool deleteItems)
4756 {
4757 if (fParent == NULL || fParent->fLayoutData->fLayout == NULL)
4758 return;
4759
4760 int32 index = fLayoutData->fLayoutItems.CountItems();
4761 while (index-- > 0) {
4762 BLayoutItem* item = fLayoutData->fLayoutItems.ItemAt(index);
4763 item->RemoveSelf();
4764 // Removes item from fLayoutItems list
4765 if (deleteItems)
4766 delete item;
4767 }
4768 }
4769
4770
4771 BView*
Parent() const4772 BView::Parent() const
4773 {
4774 if (fParent && fParent->fTopLevelView)
4775 return NULL;
4776
4777 return fParent;
4778 }
4779
4780
4781 BView*
FindView(const char * name) const4782 BView::FindView(const char* name) const
4783 {
4784 if (name == NULL)
4785 return NULL;
4786
4787 if (Name() != NULL && !strcmp(Name(), name))
4788 return const_cast<BView*>(this);
4789
4790 BView* child = fFirstChild;
4791 while (child != NULL) {
4792 BView* view = child->FindView(name);
4793 if (view != NULL)
4794 return view;
4795
4796 child = child->fNextSibling;
4797 }
4798
4799 return NULL;
4800 }
4801
4802
4803 void
MoveBy(float deltaX,float deltaY)4804 BView::MoveBy(float deltaX, float deltaY)
4805 {
4806 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY));
4807 }
4808
4809
4810 void
MoveTo(BPoint where)4811 BView::MoveTo(BPoint where)
4812 {
4813 MoveTo(where.x, where.y);
4814 }
4815
4816
4817 void
MoveTo(float x,float y)4818 BView::MoveTo(float x, float y)
4819 {
4820 if (x == fParentOffset.x && y == fParentOffset.y)
4821 return;
4822
4823 // BeBook says we should do this. And it makes sense.
4824 x = roundf(x);
4825 y = roundf(y);
4826
4827 if (fOwner) {
4828 _CheckLockAndSwitchCurrent();
4829 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO);
4830 fOwner->fLink->Attach<float>(x);
4831 fOwner->fLink->Attach<float>(y);
4832
4833 // fState->valid_flags |= B_VIEW_FRAME_BIT;
4834
4835 _FlushIfNotInTransaction();
4836 }
4837
4838 _MoveTo((int32)x, (int32)y);
4839 }
4840
4841
4842 void
ResizeBy(float deltaWidth,float deltaHeight)4843 BView::ResizeBy(float deltaWidth, float deltaHeight)
4844 {
4845 // BeBook says we should do this. And it makes sense.
4846 deltaWidth = roundf(deltaWidth);
4847 deltaHeight = roundf(deltaHeight);
4848
4849 if (deltaWidth == 0 && deltaHeight == 0)
4850 return;
4851
4852 if (fOwner) {
4853 _CheckLockAndSwitchCurrent();
4854 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO);
4855
4856 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth);
4857 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight);
4858
4859 // fState->valid_flags |= B_VIEW_FRAME_BIT;
4860
4861 _FlushIfNotInTransaction();
4862 }
4863
4864 _ResizeBy((int32)deltaWidth, (int32)deltaHeight);
4865 }
4866
4867
4868 void
ResizeTo(float width,float height)4869 BView::ResizeTo(float width, float height)
4870 {
4871 ResizeBy(width - fBounds.Width(), height - fBounds.Height());
4872 }
4873
4874
4875 void
ResizeTo(BSize size)4876 BView::ResizeTo(BSize size)
4877 {
4878 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height());
4879 }
4880
4881
4882 // #pragma mark - Inherited Methods (from BHandler)
4883
4884
4885 status_t
GetSupportedSuites(BMessage * data)4886 BView::GetSupportedSuites(BMessage* data)
4887 {
4888 if (data == NULL)
4889 return B_BAD_VALUE;
4890
4891 status_t status = data->AddString("suites", "suite/vnd.Be-view");
4892 BPropertyInfo propertyInfo(sViewPropInfo);
4893 if (status == B_OK)
4894 status = data->AddFlat("messages", &propertyInfo);
4895 if (status == B_OK)
4896 return BHandler::GetSupportedSuites(data);
4897 return status;
4898 }
4899
4900
4901 BHandler*
ResolveSpecifier(BMessage * message,int32 index,BMessage * specifier,int32 what,const char * property)4902 BView::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
4903 int32 what, const char* property)
4904 {
4905 if (message->what == B_WINDOW_MOVE_BY
4906 || message->what == B_WINDOW_MOVE_TO) {
4907 return this;
4908 }
4909
4910 BPropertyInfo propertyInfo(sViewPropInfo);
4911 status_t err = B_BAD_SCRIPT_SYNTAX;
4912 BMessage replyMsg(B_REPLY);
4913
4914 switch (propertyInfo.FindMatch(message, index, specifier, what, property)) {
4915 case 0:
4916 case 1:
4917 case 3:
4918 return this;
4919
4920 case 2:
4921 if (fShelf) {
4922 message->PopSpecifier();
4923 return fShelf;
4924 }
4925
4926 err = B_NAME_NOT_FOUND;
4927 replyMsg.AddString("message", "This window doesn't have a shelf");
4928 break;
4929
4930 case 4:
4931 {
4932 if (!fFirstChild) {
4933 err = B_NAME_NOT_FOUND;
4934 replyMsg.AddString("message", "This window doesn't have "
4935 "children.");
4936 break;
4937 }
4938 BView* child = NULL;
4939 switch (what) {
4940 case B_INDEX_SPECIFIER:
4941 {
4942 int32 index;
4943 err = specifier->FindInt32("index", &index);
4944 if (err == B_OK)
4945 child = ChildAt(index);
4946 break;
4947 }
4948 case B_REVERSE_INDEX_SPECIFIER:
4949 {
4950 int32 rindex;
4951 err = specifier->FindInt32("index", &rindex);
4952 if (err == B_OK)
4953 child = ChildAt(CountChildren() - rindex);
4954 break;
4955 }
4956 case B_NAME_SPECIFIER:
4957 {
4958 const char* name;
4959 err = specifier->FindString("name", &name);
4960 if (err == B_OK)
4961 child = FindView(name);
4962 break;
4963 }
4964 }
4965
4966 if (child != NULL) {
4967 message->PopSpecifier();
4968 return child;
4969 }
4970
4971 if (err == B_OK)
4972 err = B_BAD_INDEX;
4973
4974 replyMsg.AddString("message",
4975 "Cannot find view at/with specified index/name.");
4976 break;
4977 }
4978
4979 default:
4980 return BHandler::ResolveSpecifier(message, index, specifier, what,
4981 property);
4982 }
4983
4984 if (err < B_OK) {
4985 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4986
4987 if (err == B_BAD_SCRIPT_SYNTAX)
4988 replyMsg.AddString("message", "Didn't understand the specifier(s)");
4989 else
4990 replyMsg.AddString("message", strerror(err));
4991 }
4992
4993 replyMsg.AddInt32("error", err);
4994 message->SendReply(&replyMsg);
4995 return NULL;
4996 }
4997
4998
4999 void
MessageReceived(BMessage * message)5000 BView::MessageReceived(BMessage* message)
5001 {
5002 if (!message->HasSpecifiers()) {
5003 switch (message->what) {
5004 case B_INVALIDATE:
5005 {
5006 BRect rect;
5007 if (message->FindRect("be:area", &rect) == B_OK)
5008 Invalidate(rect);
5009 else
5010 Invalidate();
5011 break;
5012 }
5013
5014 case B_KEY_DOWN:
5015 {
5016 // TODO: cannot use "string" here if we support having different
5017 // font encoding per view (it's supposed to be converted by
5018 // BWindow::_HandleKeyDown() one day)
5019 const char* string;
5020 ssize_t bytes;
5021 if (message->FindData("bytes", B_STRING_TYPE,
5022 (const void**)&string, &bytes) == B_OK)
5023 KeyDown(string, bytes - 1);
5024 break;
5025 }
5026
5027 case B_KEY_UP:
5028 {
5029 // TODO: same as above
5030 const char* string;
5031 ssize_t bytes;
5032 if (message->FindData("bytes", B_STRING_TYPE,
5033 (const void**)&string, &bytes) == B_OK)
5034 KeyUp(string, bytes - 1);
5035 break;
5036 }
5037
5038 case B_VIEW_RESIZED:
5039 FrameResized(message->GetInt32("width", 0),
5040 message->GetInt32("height", 0));
5041 break;
5042
5043 case B_VIEW_MOVED:
5044 FrameMoved(fParentOffset);
5045 break;
5046
5047 case B_MOUSE_DOWN:
5048 {
5049 BPoint where;
5050 message->FindPoint("be:view_where", &where);
5051 MouseDown(where);
5052 break;
5053 }
5054
5055 case B_MOUSE_IDLE:
5056 {
5057 BPoint where;
5058 if (message->FindPoint("be:view_where", &where) != B_OK)
5059 break;
5060
5061 BToolTip* tip;
5062 if (GetToolTipAt(where, &tip))
5063 ShowToolTip(tip);
5064 else
5065 BHandler::MessageReceived(message);
5066 break;
5067 }
5068
5069 case B_MOUSE_MOVED:
5070 {
5071 uint32 eventOptions = fEventOptions | fMouseEventOptions;
5072 bool noHistory = eventOptions & B_NO_POINTER_HISTORY;
5073 bool dropIfLate = !(eventOptions & B_FULL_POINTER_HISTORY);
5074
5075 bigtime_t eventTime;
5076 if (message->FindInt64("when", (int64*)&eventTime) < B_OK)
5077 eventTime = system_time();
5078
5079 uint32 transit;
5080 message->FindInt32("be:transit", (int32*)&transit);
5081 // don't drop late messages with these important transit values
5082 if (transit == B_ENTERED_VIEW || transit == B_EXITED_VIEW)
5083 dropIfLate = false;
5084
5085 // TODO: The dropping code may have the following problem: On
5086 // slower computers, 20ms may just be to abitious a delay.
5087 // There, we might constantly check the message queue for a
5088 // newer message, not find any, and still use the only but later
5089 // than 20ms message, which of course makes the whole thing
5090 // later than need be. An adaptive delay would be kind of neat,
5091 // but would probably use additional BWindow members to count
5092 // the successful versus fruitless queue searches and the delay
5093 // value itself or something similar.
5094 if (noHistory
5095 || (dropIfLate && (system_time() - eventTime > 20000))) {
5096 // filter out older mouse moved messages in the queue
5097 BWindow* window = Window();
5098 window->_DequeueAll();
5099 BMessageQueue* queue = window->MessageQueue();
5100 queue->Lock();
5101
5102 BMessage* moved;
5103 for (int32 i = 0; (moved = queue->FindMessage(i)) != NULL;
5104 i++) {
5105 if (moved != message && moved->what == B_MOUSE_MOVED) {
5106 // there is a newer mouse moved message in the
5107 // queue, just ignore the current one, the newer one
5108 // will be handled here eventually
5109 queue->Unlock();
5110 return;
5111 }
5112 }
5113 queue->Unlock();
5114 }
5115
5116 BPoint where;
5117 uint32 buttons;
5118 message->FindPoint("be:view_where", &where);
5119 message->FindInt32("buttons", (int32*)&buttons);
5120
5121 if (transit == B_EXITED_VIEW || transit == B_OUTSIDE_VIEW)
5122 HideToolTip();
5123
5124 BMessage* dragMessage = NULL;
5125 if (message->HasMessage("be:drag_message")) {
5126 dragMessage = new BMessage();
5127 if (message->FindMessage("be:drag_message", dragMessage)
5128 != B_OK) {
5129 delete dragMessage;
5130 dragMessage = NULL;
5131 }
5132 }
5133
5134 MouseMoved(where, transit, dragMessage);
5135 delete dragMessage;
5136 break;
5137 }
5138
5139 case B_MOUSE_UP:
5140 {
5141 BPoint where;
5142 message->FindPoint("be:view_where", &where);
5143 fMouseEventOptions = 0;
5144 MouseUp(where);
5145 break;
5146 }
5147
5148 case B_MOUSE_WHEEL_CHANGED:
5149 {
5150 BScrollBar* horizontal = ScrollBar(B_HORIZONTAL);
5151 BScrollBar* vertical = ScrollBar(B_VERTICAL);
5152 if (horizontal == NULL && vertical == NULL) {
5153 // Pass the message to the next handler
5154 BHandler::MessageReceived(message);
5155 break;
5156 }
5157
5158 float deltaX = 0.0f;
5159 float deltaY = 0.0f;
5160
5161 if (horizontal != NULL)
5162 message->FindFloat("be:wheel_delta_x", &deltaX);
5163
5164 if (vertical != NULL)
5165 message->FindFloat("be:wheel_delta_y", &deltaY);
5166
5167 if (deltaX == 0.0f && deltaY == 0.0f)
5168 break;
5169
5170 if ((modifiers() & B_CONTROL_KEY) != 0)
5171 std::swap(horizontal, vertical);
5172
5173 if (horizontal != NULL && deltaX != 0.0f)
5174 ScrollWithMouseWheelDelta(horizontal, deltaX);
5175
5176 if (vertical != NULL && deltaY != 0.0f)
5177 ScrollWithMouseWheelDelta(vertical, deltaY);
5178
5179 break;
5180 }
5181
5182 // prevent message repeats
5183 case B_COLORS_UPDATED:
5184 case B_FONTS_UPDATED:
5185 break;
5186
5187 case B_SCREEN_CHANGED:
5188 case B_WORKSPACE_ACTIVATED:
5189 case B_WORKSPACES_CHANGED:
5190 {
5191 BWindow* window = Window();
5192 if (window == NULL)
5193 break;
5194
5195 // propagate message to child views
5196 int32 childCount = CountChildren();
5197 for (int32 i = 0; i < childCount; i++) {
5198 BView* view = ChildAt(i);
5199 if (view != NULL)
5200 window->PostMessage(message, view);
5201 }
5202 break;
5203 }
5204
5205 default:
5206 BHandler::MessageReceived(message);
5207 break;
5208 }
5209
5210 return;
5211 }
5212
5213 // Scripting message
5214
5215 BMessage replyMsg(B_REPLY);
5216 status_t err = B_BAD_SCRIPT_SYNTAX;
5217 int32 index;
5218 BMessage specifier;
5219 int32 what;
5220 const char* property;
5221
5222 if (message->GetCurrentSpecifier(&index, &specifier, &what, &property)
5223 != B_OK) {
5224 return BHandler::MessageReceived(message);
5225 }
5226
5227 BPropertyInfo propertyInfo(sViewPropInfo);
5228 switch (propertyInfo.FindMatch(message, index, &specifier, what,
5229 property)) {
5230 case 0:
5231 if (message->what == B_GET_PROPERTY) {
5232 err = replyMsg.AddRect("result", Frame());
5233 } else if (message->what == B_SET_PROPERTY) {
5234 BRect newFrame;
5235 err = message->FindRect("data", &newFrame);
5236 if (err == B_OK) {
5237 MoveTo(newFrame.LeftTop());
5238 ResizeTo(newFrame.Width(), newFrame.Height());
5239 }
5240 }
5241 break;
5242 case 1:
5243 if (message->what == B_GET_PROPERTY) {
5244 err = replyMsg.AddBool("result", IsHidden());
5245 } else if (message->what == B_SET_PROPERTY) {
5246 bool newHiddenState;
5247 err = message->FindBool("data", &newHiddenState);
5248 if (err == B_OK) {
5249 if (newHiddenState == true)
5250 Hide();
5251 else
5252 Show();
5253 }
5254 }
5255 break;
5256 case 3:
5257 err = replyMsg.AddInt32("result", CountChildren());
5258 break;
5259 default:
5260 return BHandler::MessageReceived(message);
5261 }
5262
5263 if (err != B_OK) {
5264 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
5265
5266 if (err == B_BAD_SCRIPT_SYNTAX)
5267 replyMsg.AddString("message", "Didn't understand the specifier(s)");
5268 else
5269 replyMsg.AddString("message", strerror(err));
5270
5271 replyMsg.AddInt32("error", err);
5272 }
5273
5274 message->SendReply(&replyMsg);
5275 }
5276
5277
5278 status_t
Perform(perform_code code,void * _data)5279 BView::Perform(perform_code code, void* _data)
5280 {
5281 switch (code) {
5282 case PERFORM_CODE_MIN_SIZE:
5283 ((perform_data_min_size*)_data)->return_value
5284 = BView::MinSize();
5285 return B_OK;
5286 case PERFORM_CODE_MAX_SIZE:
5287 ((perform_data_max_size*)_data)->return_value
5288 = BView::MaxSize();
5289 return B_OK;
5290 case PERFORM_CODE_PREFERRED_SIZE:
5291 ((perform_data_preferred_size*)_data)->return_value
5292 = BView::PreferredSize();
5293 return B_OK;
5294 case PERFORM_CODE_LAYOUT_ALIGNMENT:
5295 ((perform_data_layout_alignment*)_data)->return_value
5296 = BView::LayoutAlignment();
5297 return B_OK;
5298 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
5299 ((perform_data_has_height_for_width*)_data)->return_value
5300 = BView::HasHeightForWidth();
5301 return B_OK;
5302 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
5303 {
5304 perform_data_get_height_for_width* data
5305 = (perform_data_get_height_for_width*)_data;
5306 BView::GetHeightForWidth(data->width, &data->min, &data->max,
5307 &data->preferred);
5308 return B_OK;
5309 }
5310 case PERFORM_CODE_SET_LAYOUT:
5311 {
5312 perform_data_set_layout* data = (perform_data_set_layout*)_data;
5313 BView::SetLayout(data->layout);
5314 return B_OK;
5315 }
5316 case PERFORM_CODE_LAYOUT_INVALIDATED:
5317 {
5318 perform_data_layout_invalidated* data
5319 = (perform_data_layout_invalidated*)_data;
5320 BView::LayoutInvalidated(data->descendants);
5321 return B_OK;
5322 }
5323 case PERFORM_CODE_DO_LAYOUT:
5324 {
5325 BView::DoLayout();
5326 return B_OK;
5327 }
5328 case PERFORM_CODE_LAYOUT_CHANGED:
5329 {
5330 BView::LayoutChanged();
5331 return B_OK;
5332 }
5333 case PERFORM_CODE_GET_TOOL_TIP_AT:
5334 {
5335 perform_data_get_tool_tip_at* data
5336 = (perform_data_get_tool_tip_at*)_data;
5337 data->return_value
5338 = BView::GetToolTipAt(data->point, data->tool_tip);
5339 return B_OK;
5340 }
5341 case PERFORM_CODE_ALL_UNARCHIVED:
5342 {
5343 perform_data_all_unarchived* data =
5344 (perform_data_all_unarchived*)_data;
5345
5346 data->return_value = BView::AllUnarchived(data->archive);
5347 return B_OK;
5348 }
5349 case PERFORM_CODE_ALL_ARCHIVED:
5350 {
5351 perform_data_all_archived* data =
5352 (perform_data_all_archived*)_data;
5353
5354 data->return_value = BView::AllArchived(data->archive);
5355 return B_OK;
5356 }
5357 }
5358
5359 return BHandler::Perform(code, _data);
5360 }
5361
5362
5363 // #pragma mark - Layout Functions
5364
5365
5366 BSize
MinSize()5367 BView::MinSize()
5368 {
5369 // TODO: make sure this works correctly when some methods are overridden
5370 float width, height;
5371 GetPreferredSize(&width, &height);
5372
5373 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
5374 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
5375 : BSize(width, height)));
5376 }
5377
5378
5379 BSize
MaxSize()5380 BView::MaxSize()
5381 {
5382 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
5383 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
5384 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
5385 }
5386
5387
5388 BSize
PreferredSize()5389 BView::PreferredSize()
5390 {
5391 // TODO: make sure this works correctly when some methods are overridden
5392 float width, height;
5393 GetPreferredSize(&width, &height);
5394
5395 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
5396 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
5397 : BSize(width, height)));
5398 }
5399
5400
5401 BAlignment
LayoutAlignment()5402 BView::LayoutAlignment()
5403 {
5404 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
5405 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
5406 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
5407 }
5408
5409
5410 void
SetExplicitMinSize(BSize size)5411 BView::SetExplicitMinSize(BSize size)
5412 {
5413 fLayoutData->fMinSize = size;
5414 InvalidateLayout();
5415 }
5416
5417
5418 void
SetExplicitMaxSize(BSize size)5419 BView::SetExplicitMaxSize(BSize size)
5420 {
5421 fLayoutData->fMaxSize = size;
5422 InvalidateLayout();
5423 }
5424
5425
5426 void
SetExplicitPreferredSize(BSize size)5427 BView::SetExplicitPreferredSize(BSize size)
5428 {
5429 fLayoutData->fPreferredSize = size;
5430 InvalidateLayout();
5431 }
5432
5433
5434 void
SetExplicitSize(BSize size)5435 BView::SetExplicitSize(BSize size)
5436 {
5437 fLayoutData->fMinSize = size;
5438 fLayoutData->fMaxSize = size;
5439 fLayoutData->fPreferredSize = size;
5440 InvalidateLayout();
5441 }
5442
5443
5444 void
SetExplicitAlignment(BAlignment alignment)5445 BView::SetExplicitAlignment(BAlignment alignment)
5446 {
5447 fLayoutData->fAlignment = alignment;
5448 InvalidateLayout();
5449 }
5450
5451
5452 BSize
ExplicitMinSize() const5453 BView::ExplicitMinSize() const
5454 {
5455 return fLayoutData->fMinSize;
5456 }
5457
5458
5459 BSize
ExplicitMaxSize() const5460 BView::ExplicitMaxSize() const
5461 {
5462 return fLayoutData->fMaxSize;
5463 }
5464
5465
5466 BSize
ExplicitPreferredSize() const5467 BView::ExplicitPreferredSize() const
5468 {
5469 return fLayoutData->fPreferredSize;
5470 }
5471
5472
5473 BAlignment
ExplicitAlignment() const5474 BView::ExplicitAlignment() const
5475 {
5476 return fLayoutData->fAlignment;
5477 }
5478
5479
5480 bool
HasHeightForWidth()5481 BView::HasHeightForWidth()
5482 {
5483 return (fLayoutData->fLayout
5484 ? fLayoutData->fLayout->HasHeightForWidth() : false);
5485 }
5486
5487
5488 void
GetHeightForWidth(float width,float * min,float * max,float * preferred)5489 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
5490 {
5491 if (fLayoutData->fLayout)
5492 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
5493 }
5494
5495
5496 void
SetLayout(BLayout * layout)5497 BView::SetLayout(BLayout* layout)
5498 {
5499 if (layout == fLayoutData->fLayout)
5500 return;
5501
5502 if (layout && layout->Layout())
5503 debugger("BView::SetLayout() failed, layout is already in use.");
5504
5505 fFlags |= B_SUPPORTS_LAYOUT;
5506
5507 // unset and delete the old layout
5508 if (fLayoutData->fLayout) {
5509 fLayoutData->fLayout->RemoveSelf();
5510 fLayoutData->fLayout->SetOwner(NULL);
5511 delete fLayoutData->fLayout;
5512 }
5513
5514 fLayoutData->fLayout = layout;
5515
5516 if (fLayoutData->fLayout) {
5517 fLayoutData->fLayout->SetOwner(this);
5518
5519 // add all children
5520 int count = CountChildren();
5521 for (int i = 0; i < count; i++)
5522 fLayoutData->fLayout->AddView(ChildAt(i));
5523 }
5524
5525 InvalidateLayout();
5526 }
5527
5528
5529 BLayout*
GetLayout() const5530 BView::GetLayout() const
5531 {
5532 return fLayoutData->fLayout;
5533 }
5534
5535
5536 void
InvalidateLayout(bool descendants)5537 BView::InvalidateLayout(bool descendants)
5538 {
5539 // printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n",
5540 // this, descendants, fLayoutData->fLayoutValid,
5541 // fLayoutData->fLayoutInProgress);
5542
5543 if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress
5544 || fLayoutData->fLayoutInvalidationDisabled > 0) {
5545 return;
5546 }
5547 fLayoutData->fLayoutValid = false;
5548 fLayoutData->fMinMaxValid = false;
5549 LayoutInvalidated(descendants);
5550
5551 if (descendants) {
5552 for (BView* child = fFirstChild;
5553 child; child = child->fNextSibling) {
5554 child->InvalidateLayout(descendants);
5555 }
5556 }
5557
5558 if (fLayoutData->fLayout)
5559 fLayoutData->fLayout->InvalidateLayout(descendants);
5560 else
5561 _InvalidateParentLayout();
5562
5563 if (fTopLevelView
5564 && fOwner != NULL)
5565 fOwner->PostMessage(B_LAYOUT_WINDOW);
5566 }
5567
5568
5569 void
EnableLayoutInvalidation()5570 BView::EnableLayoutInvalidation()
5571 {
5572 if (fLayoutData->fLayoutInvalidationDisabled > 0)
5573 fLayoutData->fLayoutInvalidationDisabled--;
5574 }
5575
5576
5577 void
DisableLayoutInvalidation()5578 BView::DisableLayoutInvalidation()
5579 {
5580 fLayoutData->fLayoutInvalidationDisabled++;
5581 }
5582
5583
5584 bool
IsLayoutInvalidationDisabled()5585 BView::IsLayoutInvalidationDisabled()
5586 {
5587 if (fLayoutData->fLayoutInvalidationDisabled > 0)
5588 return true;
5589 return false;
5590 }
5591
5592
5593 bool
IsLayoutValid() const5594 BView::IsLayoutValid() const
5595 {
5596 return fLayoutData->fLayoutValid;
5597 }
5598
5599
5600 void
ResetLayoutInvalidation()5601 BView::ResetLayoutInvalidation()
5602 {
5603 fLayoutData->fMinMaxValid = true;
5604 }
5605
5606
5607 BLayoutContext*
LayoutContext() const5608 BView::LayoutContext() const
5609 {
5610 return fLayoutData->fLayoutContext;
5611 }
5612
5613
5614 void
Layout(bool force)5615 BView::Layout(bool force)
5616 {
5617 BLayoutContext context;
5618 _Layout(force, &context);
5619 }
5620
5621
5622 void
Relayout()5623 BView::Relayout()
5624 {
5625 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
5626 fLayoutData->fNeedsRelayout = true;
5627 if (fLayoutData->fLayout)
5628 fLayoutData->fLayout->RequireLayout();
5629
5630 // Layout() is recursive, that is if the parent view is currently laid
5631 // out, we don't call layout() on this view, but wait for the parent's
5632 // Layout() to do that for us.
5633 if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
5634 Layout(false);
5635 }
5636 }
5637
5638
5639 void
LayoutInvalidated(bool descendants)5640 BView::LayoutInvalidated(bool descendants)
5641 {
5642 // hook method
5643 }
5644
5645
5646 void
DoLayout()5647 BView::DoLayout()
5648 {
5649 if (fLayoutData->fLayout)
5650 fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext());
5651 }
5652
5653
5654 void
SetToolTip(const char * text)5655 BView::SetToolTip(const char* text)
5656 {
5657 if (text == NULL || text[0] == '\0') {
5658 SetToolTip((BToolTip*)NULL);
5659 return;
5660 }
5661
5662 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip))
5663 tip->SetText(text);
5664 else
5665 SetToolTip(new BTextToolTip(text));
5666 }
5667
5668
5669 void
SetToolTip(BToolTip * tip)5670 BView::SetToolTip(BToolTip* tip)
5671 {
5672 if (fToolTip == tip)
5673 return;
5674 else if (tip == NULL)
5675 HideToolTip();
5676
5677 if (fToolTip != NULL)
5678 fToolTip->ReleaseReference();
5679
5680 fToolTip = tip;
5681
5682 if (fToolTip != NULL)
5683 fToolTip->AcquireReference();
5684 }
5685
5686
5687 BToolTip*
ToolTip() const5688 BView::ToolTip() const
5689 {
5690 return fToolTip;
5691 }
5692
5693
5694 void
ShowToolTip(BToolTip * tip)5695 BView::ShowToolTip(BToolTip* tip)
5696 {
5697 if (tip == NULL)
5698 return;
5699
5700 BPoint where;
5701 GetMouse(&where, NULL, false);
5702
5703 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this);
5704 }
5705
5706
5707 void
HideToolTip()5708 BView::HideToolTip()
5709 {
5710 BToolTipManager::Manager()->HideTip();
5711 }
5712
5713
5714 bool
GetToolTipAt(BPoint point,BToolTip ** _tip)5715 BView::GetToolTipAt(BPoint point, BToolTip** _tip)
5716 {
5717 if (fToolTip != NULL) {
5718 *_tip = fToolTip;
5719 return true;
5720 }
5721
5722 *_tip = NULL;
5723 return false;
5724 }
5725
5726
5727 void
LayoutChanged()5728 BView::LayoutChanged()
5729 {
5730 // hook method
5731 }
5732
5733
5734 void
_Layout(bool force,BLayoutContext * context)5735 BView::_Layout(bool force, BLayoutContext* context)
5736 {
5737 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
5738 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
5739 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid,
5740 //fLayoutData->fLayoutInProgress);
5741 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
5742 fLayoutData->fLayoutValid = false;
5743
5744 if (fLayoutData->fLayoutInProgress)
5745 return;
5746
5747 BLayoutContext* oldContext = fLayoutData->fLayoutContext;
5748 fLayoutData->fLayoutContext = context;
5749
5750 fLayoutData->fLayoutInProgress = true;
5751 DoLayout();
5752 fLayoutData->fLayoutInProgress = false;
5753
5754 fLayoutData->fLayoutValid = true;
5755 fLayoutData->fMinMaxValid = true;
5756 fLayoutData->fNeedsRelayout = false;
5757
5758 // layout children
5759 for(BView* child = fFirstChild; child; child = child->fNextSibling) {
5760 if (!child->IsHidden(child))
5761 child->_Layout(force, context);
5762 }
5763
5764 LayoutChanged();
5765
5766 fLayoutData->fLayoutContext = oldContext;
5767
5768 // invalidate the drawn content, if requested
5769 if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
5770 Invalidate();
5771 }
5772 }
5773
5774
5775 void
_LayoutLeft(BLayout * deleted)5776 BView::_LayoutLeft(BLayout* deleted)
5777 {
5778 // If our layout is added to another layout (via BLayout::AddItem())
5779 // then we share ownership of our layout. In the event that our layout gets
5780 // deleted by the layout it has been added to, this method is called so
5781 // that we don't double-delete our layout.
5782 if (fLayoutData->fLayout == deleted)
5783 fLayoutData->fLayout = NULL;
5784 InvalidateLayout();
5785 }
5786
5787
5788 void
_InvalidateParentLayout()5789 BView::_InvalidateParentLayout()
5790 {
5791 if (!fParent)
5792 return;
5793
5794 BLayout* layout = fLayoutData->fLayout;
5795 BLayout* layoutParent = layout ? layout->Layout() : NULL;
5796 if (layoutParent) {
5797 layoutParent->InvalidateLayout();
5798 } else if (fLayoutData->fLayoutItems.CountItems() > 0) {
5799 int32 count = fLayoutData->fLayoutItems.CountItems();
5800 for (int32 i = 0; i < count; i++) {
5801 fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout();
5802 }
5803 } else {
5804 fParent->InvalidateLayout();
5805 }
5806 }
5807
5808
5809 // #pragma mark - Private Functions
5810
5811
5812 void
_InitData(BRect frame,const char * name,uint32 resizingMode,uint32 flags)5813 BView::_InitData(BRect frame, const char* name, uint32 resizingMode,
5814 uint32 flags)
5815 {
5816 // Info: The name of the view is set by BHandler constructor
5817
5818 STRACE(("BView::_InitData: enter\n"));
5819
5820 // initialize members
5821 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
5822 printf("%s BView::_InitData(): resizing mode or flags swapped\n", name);
5823
5824 // There are applications that swap the resize mask and the flags in the
5825 // BView constructor. This does not cause problems under BeOS as it just
5826 // ors the two fields to one 32bit flag.
5827 // For now we do the same but print the above warning message.
5828 // TODO: this should be removed at some point and the original
5829 // version restored:
5830 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
5831 fFlags = resizingMode | flags;
5832
5833 // handle rounding
5834 frame.left = roundf(frame.left);
5835 frame.top = roundf(frame.top);
5836 frame.right = roundf(frame.right);
5837 frame.bottom = roundf(frame.bottom);
5838
5839 fParentOffset.Set(frame.left, frame.top);
5840
5841 fOwner = NULL;
5842 fParent = NULL;
5843 fNextSibling = NULL;
5844 fPreviousSibling = NULL;
5845 fFirstChild = NULL;
5846
5847 fShowLevel = 0;
5848 fTopLevelView = false;
5849
5850 fCurrentPicture = NULL;
5851 fCommArray = NULL;
5852
5853 fVerScroller = NULL;
5854 fHorScroller = NULL;
5855
5856 fIsPrinting = false;
5857 fAttached = false;
5858
5859 // TODO: Since we cannot communicate failure, we don't use std::nothrow here
5860 // TODO: Maybe we could auto-delete those views on AddChild() instead?
5861 fState = new BPrivate::ViewState;
5862
5863 fBounds = frame.OffsetToCopy(B_ORIGIN);
5864 fShelf = NULL;
5865
5866 fEventMask = 0;
5867 fEventOptions = 0;
5868 fMouseEventOptions = 0;
5869
5870 fLayoutData = new LayoutData;
5871
5872 fToolTip = NULL;
5873
5874 if ((flags & B_SUPPORTS_LAYOUT) != 0) {
5875 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
5876 SetLowUIColor(ViewUIColor());
5877 SetHighUIColor(B_PANEL_TEXT_COLOR);
5878 }
5879 }
5880
5881
5882 void
_RemoveCommArray()5883 BView::_RemoveCommArray()
5884 {
5885 if (fCommArray) {
5886 delete [] fCommArray->array;
5887 delete fCommArray;
5888 fCommArray = NULL;
5889 }
5890 }
5891
5892
5893 void
_SetOwner(BWindow * newOwner)5894 BView::_SetOwner(BWindow* newOwner)
5895 {
5896 if (!newOwner)
5897 _RemoveCommArray();
5898
5899 if (fOwner != newOwner && fOwner) {
5900 if (fOwner->fFocus == this)
5901 MakeFocus(false);
5902
5903 if (fOwner->fLastMouseMovedView == this)
5904 fOwner->fLastMouseMovedView = NULL;
5905
5906 fOwner->RemoveHandler(this);
5907 if (fShelf)
5908 fOwner->RemoveHandler(fShelf);
5909 }
5910
5911 if (newOwner && newOwner != fOwner) {
5912 newOwner->AddHandler(this);
5913 if (fShelf)
5914 newOwner->AddHandler(fShelf);
5915
5916 if (fTopLevelView)
5917 SetNextHandler(newOwner);
5918 else
5919 SetNextHandler(fParent);
5920 }
5921
5922 fOwner = newOwner;
5923
5924 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling)
5925 child->_SetOwner(newOwner);
5926 }
5927
5928
5929 void
_ClipToPicture(BPicture * picture,BPoint where,bool invert,bool sync)5930 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
5931 {
5932 if (!_CheckOwnerLockAndSwitchCurrent())
5933 return;
5934
5935 if (picture == NULL) {
5936 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5937 fOwner->fLink->Attach<int32>(-1);
5938
5939 // NOTE: No need to sync here, since the -1 token cannot
5940 // become invalid on the server.
5941 } else {
5942 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5943 fOwner->fLink->Attach<int32>(picture->Token());
5944 fOwner->fLink->Attach<BPoint>(where);
5945 fOwner->fLink->Attach<bool>(invert);
5946
5947 // NOTE: "sync" defaults to true in public methods. If you know what
5948 // you are doing, i.e. if you know your BPicture stays valid, you
5949 // can avoid the performance impact of syncing. In a use-case where
5950 // the client creates BPictures on the stack, these BPictures may
5951 // have issued a AS_DELETE_PICTURE command to the ServerApp when Draw()
5952 // goes out of scope, and the command is processed earlier in the
5953 // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the
5954 // ServerWindow thread, which will then have the result that no
5955 // ServerPicture is found of the token.
5956 if (sync)
5957 Sync();
5958 }
5959 }
5960
5961
5962 void
_ClipToRect(BRect rect,bool inverse)5963 BView::_ClipToRect(BRect rect, bool inverse)
5964 {
5965 if (_CheckOwnerLockAndSwitchCurrent()) {
5966 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_RECT);
5967 fOwner->fLink->Attach<bool>(inverse);
5968 fOwner->fLink->Attach<BRect>(rect);
5969 _FlushIfNotInTransaction();
5970 }
5971 }
5972
5973
5974 void
_ClipToShape(BShape * shape,bool inverse)5975 BView::_ClipToShape(BShape* shape, bool inverse)
5976 {
5977 if (shape == NULL)
5978 return;
5979
5980 shape_data* sd = BShape::Private(*shape).PrivateData();
5981 if (sd->opCount == 0 || sd->ptCount == 0)
5982 return;
5983
5984 if (_CheckOwnerLockAndSwitchCurrent()) {
5985 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_SHAPE);
5986 fOwner->fLink->Attach<bool>(inverse);
5987 fOwner->fLink->AttachShape(*shape);
5988 _FlushIfNotInTransaction();
5989 }
5990 }
5991
5992
5993 bool
_RemoveChildFromList(BView * child)5994 BView::_RemoveChildFromList(BView* child)
5995 {
5996 if (child->fParent != this)
5997 return false;
5998
5999 if (fFirstChild == child) {
6000 // it's the first view in the list
6001 fFirstChild = child->fNextSibling;
6002 } else {
6003 // there must be a previous sibling
6004 child->fPreviousSibling->fNextSibling = child->fNextSibling;
6005 }
6006
6007 if (child->fNextSibling)
6008 child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
6009
6010 child->fParent = NULL;
6011 child->fNextSibling = NULL;
6012 child->fPreviousSibling = NULL;
6013
6014 return true;
6015 }
6016
6017
6018 bool
_AddChildToList(BView * child,BView * before)6019 BView::_AddChildToList(BView* child, BView* before)
6020 {
6021 if (!child)
6022 return false;
6023 if (child->fParent != NULL) {
6024 debugger("View already belongs to someone else");
6025 return false;
6026 }
6027 if (before != NULL && before->fParent != this) {
6028 debugger("Invalid before view");
6029 return false;
6030 }
6031
6032 if (before != NULL) {
6033 // add view before this one
6034 child->fNextSibling = before;
6035 child->fPreviousSibling = before->fPreviousSibling;
6036 if (child->fPreviousSibling != NULL)
6037 child->fPreviousSibling->fNextSibling = child;
6038
6039 before->fPreviousSibling = child;
6040 if (fFirstChild == before)
6041 fFirstChild = child;
6042 } else {
6043 // add view to the end of the list
6044 BView* last = fFirstChild;
6045 while (last != NULL && last->fNextSibling != NULL) {
6046 last = last->fNextSibling;
6047 }
6048
6049 if (last != NULL) {
6050 last->fNextSibling = child;
6051 child->fPreviousSibling = last;
6052 } else {
6053 fFirstChild = child;
6054 child->fPreviousSibling = NULL;
6055 }
6056
6057 child->fNextSibling = NULL;
6058 }
6059
6060 child->fParent = this;
6061 return true;
6062 }
6063
6064
6065 /*! \brief Creates the server counterpart of this view.
6066 This is only done for views that are part of the view hierarchy, ie. when
6067 they are attached to a window.
6068 RemoveSelf() deletes the server object again.
6069 */
6070 bool
_CreateSelf()6071 BView::_CreateSelf()
6072 {
6073 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
6074 // current view mechanism via _CheckLockAndSwitchCurrent() - the token
6075 // of the view and its parent are both send to the server.
6076
6077 if (fTopLevelView)
6078 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
6079 else
6080 fOwner->fLink->StartMessage(AS_VIEW_CREATE);
6081
6082 fOwner->fLink->Attach<int32>(_get_object_token_(this));
6083 fOwner->fLink->AttachString(Name());
6084 fOwner->fLink->Attach<BRect>(Frame());
6085 fOwner->fLink->Attach<BPoint>(LeftTop());
6086 fOwner->fLink->Attach<uint32>(ResizingMode());
6087 fOwner->fLink->Attach<uint32>(fEventMask);
6088 fOwner->fLink->Attach<uint32>(fEventOptions);
6089 fOwner->fLink->Attach<uint32>(Flags());
6090 fOwner->fLink->Attach<bool>(IsHidden(this));
6091 fOwner->fLink->Attach<rgb_color>(fState->view_color);
6092 if (fTopLevelView)
6093 fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
6094 else
6095 fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
6096 fOwner->fLink->Flush();
6097
6098 _CheckOwnerLockAndSwitchCurrent();
6099 fState->UpdateServerState(*fOwner->fLink);
6100
6101 // we create all its children, too
6102
6103 for (BView* child = fFirstChild; child != NULL;
6104 child = child->fNextSibling) {
6105 child->_CreateSelf();
6106 }
6107
6108 fOwner->fLink->Flush();
6109 return true;
6110 }
6111
6112
6113 /*! Sets the new view position.
6114 It doesn't contact the server, though - the only case where this
6115 is called outside of MoveTo() is as reaction of moving a view
6116 in the server (a.k.a. B_WINDOW_RESIZED).
6117 It also calls the BView's FrameMoved() hook.
6118 */
6119 void
_MoveTo(int32 x,int32 y)6120 BView::_MoveTo(int32 x, int32 y)
6121 {
6122 fParentOffset.Set(x, y);
6123
6124 if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
6125 BMessage moved(B_VIEW_MOVED);
6126 moved.AddInt64("when", system_time());
6127 moved.AddPoint("where", BPoint(x, y));
6128
6129 BMessenger target(this);
6130 target.SendMessage(&moved);
6131 }
6132 }
6133
6134
6135 /*! Computes the actual new frame size and recalculates the size of
6136 the children as well.
6137 It doesn't contact the server, though - the only case where this
6138 is called outside of ResizeBy() is as reaction of resizing a view
6139 in the server (a.k.a. B_WINDOW_RESIZED).
6140 It also calls the BView's FrameResized() hook.
6141 */
6142 void
_ResizeBy(int32 deltaWidth,int32 deltaHeight)6143 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
6144 {
6145 fBounds.right += deltaWidth;
6146 fBounds.bottom += deltaHeight;
6147
6148 if (Window() == NULL) {
6149 // we're not supposed to exercise the resizing code in case
6150 // we haven't been attached to a window yet
6151 return;
6152 }
6153
6154 // layout the children
6155 if ((fFlags & B_SUPPORTS_LAYOUT) != 0) {
6156 Relayout();
6157 } else {
6158 for (BView* child = fFirstChild; child; child = child->fNextSibling)
6159 child->_ParentResizedBy(deltaWidth, deltaHeight);
6160 }
6161
6162 if (fFlags & B_FRAME_EVENTS) {
6163 BMessage resized(B_VIEW_RESIZED);
6164 resized.AddInt64("when", system_time());
6165 resized.AddInt32("width", fBounds.IntegerWidth());
6166 resized.AddInt32("height", fBounds.IntegerHeight());
6167
6168 BMessenger target(this);
6169 target.SendMessage(&resized);
6170 }
6171 }
6172
6173
6174 /*! Relayouts the view according to its resizing mode. */
6175 void
_ParentResizedBy(int32 x,int32 y)6176 BView::_ParentResizedBy(int32 x, int32 y)
6177 {
6178 uint32 resizingMode = fFlags & _RESIZE_MASK_;
6179 BRect newFrame = Frame();
6180
6181 // follow with left side
6182 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
6183 newFrame.left += x;
6184 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
6185 newFrame.left += x / 2;
6186
6187 // follow with right side
6188 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
6189 newFrame.right += x;
6190 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
6191 newFrame.right += x / 2;
6192
6193 // follow with top side
6194 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
6195 newFrame.top += y;
6196 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
6197 newFrame.top += y / 2;
6198
6199 // follow with bottom side
6200 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
6201 newFrame.bottom += y;
6202 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
6203 newFrame.bottom += y / 2;
6204
6205 if (newFrame.LeftTop() != fParentOffset) {
6206 // move view
6207 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
6208 }
6209
6210 if (newFrame != Frame()) {
6211 // resize view
6212 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
6213 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
6214 _ResizeBy(widthDiff, heightDiff);
6215 }
6216 }
6217
6218
6219 void
_Activate(bool active)6220 BView::_Activate(bool active)
6221 {
6222 WindowActivated(active);
6223
6224 for (BView* child = fFirstChild; child != NULL;
6225 child = child->fNextSibling) {
6226 child->_Activate(active);
6227 }
6228 }
6229
6230
6231 void
_Attach()6232 BView::_Attach()
6233 {
6234 if (fOwner != NULL) {
6235 // unmask state flags to force [re]syncing with the app_server
6236 fState->valid_flags &= ~(B_VIEW_WHICH_VIEW_COLOR_BIT
6237 | B_VIEW_WHICH_LOW_COLOR_BIT | B_VIEW_WHICH_HIGH_COLOR_BIT);
6238
6239 if (fState->which_view_color != B_NO_COLOR)
6240 SetViewUIColor(fState->which_view_color,
6241 fState->which_view_color_tint);
6242
6243 if (fState->which_high_color != B_NO_COLOR)
6244 SetHighUIColor(fState->which_high_color,
6245 fState->which_high_color_tint);
6246
6247 if (fState->which_low_color != B_NO_COLOR)
6248 SetLowUIColor(fState->which_low_color,
6249 fState->which_low_color_tint);
6250 }
6251
6252 AttachedToWindow();
6253
6254 fAttached = true;
6255
6256 // after giving the view a chance to do this itself,
6257 // check for the B_PULSE_NEEDED flag and make sure the
6258 // window set's up the pulse messaging
6259 if (fOwner) {
6260 if (fFlags & B_PULSE_NEEDED) {
6261 _CheckLock();
6262 if (fOwner->fPulseRunner == NULL)
6263 fOwner->SetPulseRate(fOwner->PulseRate());
6264 }
6265
6266 if (!fOwner->IsHidden())
6267 Invalidate();
6268 }
6269
6270 for (BView* child = fFirstChild; child != NULL;
6271 child = child->fNextSibling) {
6272 // we need to check for fAttached as new views could have been
6273 // added in AttachedToWindow() - and those are already attached
6274 if (!child->fAttached)
6275 child->_Attach();
6276 }
6277
6278 AllAttached();
6279 }
6280
6281
6282 void
_ColorsUpdated(BMessage * message)6283 BView::_ColorsUpdated(BMessage* message)
6284 {
6285 if (fTopLevelView
6286 && fLayoutData->fLayout != NULL
6287 && !fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)) {
6288 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
6289 SetHighUIColor(B_PANEL_TEXT_COLOR);
6290 }
6291
6292 rgb_color color;
6293
6294 const char* colorName = ui_color_name(fState->which_view_color);
6295 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6296 fState->view_color = tint_color(color, fState->which_view_color_tint);
6297 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
6298 }
6299
6300 colorName = ui_color_name(fState->which_low_color);
6301 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6302 fState->low_color = tint_color(color, fState->which_low_color_tint);
6303 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
6304 }
6305
6306 colorName = ui_color_name(fState->which_high_color);
6307 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6308 fState->high_color = tint_color(color, fState->which_high_color_tint);
6309 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
6310 }
6311
6312 MessageReceived(message);
6313
6314 for (BView* child = fFirstChild; child != NULL;
6315 child = child->fNextSibling)
6316 child->_ColorsUpdated(message);
6317
6318 Invalidate();
6319 }
6320
6321
6322 void
_Detach()6323 BView::_Detach()
6324 {
6325 DetachedFromWindow();
6326 fAttached = false;
6327
6328 for (BView* child = fFirstChild; child != NULL;
6329 child = child->fNextSibling) {
6330 child->_Detach();
6331 }
6332
6333 AllDetached();
6334
6335 if (fOwner) {
6336 _CheckLock();
6337
6338 if (!fOwner->IsHidden())
6339 Invalidate();
6340
6341 // make sure our owner doesn't need us anymore
6342
6343 if (fOwner->CurrentFocus() == this) {
6344 MakeFocus(false);
6345 // MakeFocus() is virtual and might not be
6346 // passing through to the BView version,
6347 // but we need to make sure at this point
6348 // that we are not the focus view anymore.
6349 if (fOwner->CurrentFocus() == this)
6350 fOwner->_SetFocus(NULL, true);
6351 }
6352
6353 if (fOwner->fDefaultButton == this)
6354 fOwner->SetDefaultButton(NULL);
6355
6356 if (fOwner->fKeyMenuBar == this)
6357 fOwner->fKeyMenuBar = NULL;
6358
6359 if (fOwner->fLastMouseMovedView == this)
6360 fOwner->fLastMouseMovedView = NULL;
6361
6362 if (fOwner->fLastViewToken == _get_object_token_(this))
6363 fOwner->fLastViewToken = B_NULL_TOKEN;
6364
6365 _SetOwner(NULL);
6366 }
6367 }
6368
6369
6370 void
_Draw(BRect updateRect)6371 BView::_Draw(BRect updateRect)
6372 {
6373 if (IsHidden(this) || !(Flags() & B_WILL_DRAW))
6374 return;
6375
6376 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
6377 // -> View is simply not drawn at all
6378
6379 _SwitchServerCurrentView();
6380
6381 ConvertFromScreen(&updateRect);
6382
6383 // TODO: make states robust (the hook implementation could
6384 // mess things up if it uses non-matching Push- and PopState(),
6385 // we would not be guaranteed to still have the same state on
6386 // the stack after having called Draw())
6387 PushState();
6388 Draw(updateRect);
6389 PopState();
6390 Flush();
6391 }
6392
6393
6394 void
_DrawAfterChildren(BRect updateRect)6395 BView::_DrawAfterChildren(BRect updateRect)
6396 {
6397 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)
6398 || !(Flags() & B_DRAW_ON_CHILDREN))
6399 return;
6400
6401 _SwitchServerCurrentView();
6402
6403 ConvertFromScreen(&updateRect);
6404
6405 // TODO: make states robust (see above)
6406 PushState();
6407 DrawAfterChildren(updateRect);
6408 PopState();
6409 Flush();
6410 }
6411
6412
6413 void
_FontsUpdated(BMessage * message)6414 BView::_FontsUpdated(BMessage* message)
6415 {
6416 MessageReceived(message);
6417
6418 for (BView* child = fFirstChild; child != NULL;
6419 child = child->fNextSibling) {
6420 child->_FontsUpdated(message);
6421 }
6422 }
6423
6424
6425 void
_Pulse()6426 BView::_Pulse()
6427 {
6428 if ((Flags() & B_PULSE_NEEDED) != 0)
6429 Pulse();
6430
6431 for (BView* child = fFirstChild; child != NULL;
6432 child = child->fNextSibling) {
6433 child->_Pulse();
6434 }
6435 }
6436
6437
6438 void
_UpdateStateForRemove()6439 BView::_UpdateStateForRemove()
6440 {
6441 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no?
6442 if (!_CheckOwnerLockAndSwitchCurrent())
6443 return;
6444
6445 fState->UpdateFrom(*fOwner->fLink);
6446 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
6447 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD);
6448 //
6449 // status_t code;
6450 // if (fOwner->fLink->FlushWithReply(code) == B_OK
6451 // && code == B_OK) {
6452 // fOwner->fLink->Read<BPoint>(&fParentOffset);
6453 // fOwner->fLink->Read<BRect>(&fBounds);
6454 // fState->valid_flags |= B_VIEW_FRAME_BIT;
6455 // }
6456 // }
6457
6458 // update children as well
6459
6460 for (BView* child = fFirstChild; child != NULL;
6461 child = child->fNextSibling) {
6462 if (child->fOwner)
6463 child->_UpdateStateForRemove();
6464 }
6465 }
6466
6467
6468 inline void
_UpdatePattern(::pattern pattern)6469 BView::_UpdatePattern(::pattern pattern)
6470 {
6471 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
6472 return;
6473
6474 if (fOwner) {
6475 _CheckLockAndSwitchCurrent();
6476
6477 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN);
6478 fOwner->fLink->Attach< ::pattern>(pattern);
6479
6480 fState->valid_flags |= B_VIEW_PATTERN_BIT;
6481 }
6482
6483 fState->pattern = pattern;
6484 }
6485
6486
6487 void
_FlushIfNotInTransaction()6488 BView::_FlushIfNotInTransaction()
6489 {
6490 if (!fOwner->fInTransaction) {
6491 fOwner->Flush();
6492 }
6493 }
6494
6495
6496 BShelf*
_Shelf() const6497 BView::_Shelf() const
6498 {
6499 return fShelf;
6500 }
6501
6502
6503 void
_SetShelf(BShelf * shelf)6504 BView::_SetShelf(BShelf* shelf)
6505 {
6506 if (fShelf != NULL && fOwner != NULL)
6507 fOwner->RemoveHandler(fShelf);
6508
6509 fShelf = shelf;
6510
6511 if (fShelf != NULL && fOwner != NULL)
6512 fOwner->AddHandler(fShelf);
6513 }
6514
6515
6516 status_t
_SetViewBitmap(const BBitmap * bitmap,BRect srcRect,BRect dstRect,uint32 followFlags,uint32 options)6517 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
6518 uint32 followFlags, uint32 options)
6519 {
6520 if (!_CheckOwnerLockAndSwitchCurrent())
6521 return B_ERROR;
6522
6523 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
6524
6525 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP);
6526 fOwner->fLink->Attach<int32>(serverToken);
6527 fOwner->fLink->Attach<BRect>(srcRect);
6528 fOwner->fLink->Attach<BRect>(dstRect);
6529 fOwner->fLink->Attach<int32>(followFlags);
6530 fOwner->fLink->Attach<int32>(options);
6531
6532 status_t status = B_ERROR;
6533 fOwner->fLink->FlushWithReply(status);
6534
6535 return status;
6536 }
6537
6538
6539 bool
_CheckOwnerLockAndSwitchCurrent() const6540 BView::_CheckOwnerLockAndSwitchCurrent() const
6541 {
6542 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name()));
6543
6544 if (fOwner == NULL) {
6545 debugger("View method requires owner and doesn't have one.");
6546 return false;
6547 }
6548
6549 _CheckLockAndSwitchCurrent();
6550
6551 return true;
6552 }
6553
6554
6555 bool
_CheckOwnerLock() const6556 BView::_CheckOwnerLock() const
6557 {
6558 if (fOwner) {
6559 fOwner->check_lock();
6560 return true;
6561 } else {
6562 debugger("View method requires owner and doesn't have one.");
6563 return false;
6564 }
6565 }
6566
6567
6568 void
_CheckLockAndSwitchCurrent() const6569 BView::_CheckLockAndSwitchCurrent() const
6570 {
6571 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name()));
6572
6573 if (!fOwner)
6574 return;
6575
6576 fOwner->check_lock();
6577
6578 _SwitchServerCurrentView();
6579 }
6580
6581
6582 void
_CheckLock() const6583 BView::_CheckLock() const
6584 {
6585 if (fOwner)
6586 fOwner->check_lock();
6587 }
6588
6589
6590 void
_SwitchServerCurrentView() const6591 BView::_SwitchServerCurrentView() const
6592 {
6593 int32 serverToken = _get_object_token_(this);
6594
6595 if (fOwner->fLastViewToken != serverToken) {
6596 STRACE(("contacting app_server... sending token: %" B_PRId32 "\n",
6597 serverToken));
6598 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW);
6599 fOwner->fLink->Attach<int32>(serverToken);
6600
6601 fOwner->fLastViewToken = serverToken;
6602 }
6603 }
6604
6605
6606 status_t
ScrollWithMouseWheelDelta(BScrollBar * scrollBar,float delta)6607 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta)
6608 {
6609 if (scrollBar == NULL || delta == 0.0f)
6610 return B_BAD_VALUE;
6611
6612 float smallStep;
6613 float largeStep;
6614 scrollBar->GetSteps(&smallStep, &largeStep);
6615
6616 // pressing the shift key scrolls faster (following the pseudo-standard set
6617 // by other desktop environments).
6618 if ((modifiers() & B_SHIFT_KEY) != 0)
6619 delta *= largeStep;
6620 else
6621 delta *= smallStep * 3;
6622
6623 scrollBar->SetValue(scrollBar->Value() + delta);
6624
6625 return B_OK;
6626 }
6627
6628
6629 #if __GNUC__ == 2
6630
6631
6632 extern "C" void
_ReservedView1__5BView(BView * view,BRect rect)6633 _ReservedView1__5BView(BView* view, BRect rect)
6634 {
6635 view->BView::DrawAfterChildren(rect);
6636 }
6637
6638
6639 extern "C" void
_ReservedView2__5BView(BView * view)6640 _ReservedView2__5BView(BView* view)
6641 {
6642 // MinSize()
6643 perform_data_min_size data;
6644 view->Perform(PERFORM_CODE_MIN_SIZE, &data);
6645 }
6646
6647
6648 extern "C" void
_ReservedView3__5BView(BView * view)6649 _ReservedView3__5BView(BView* view)
6650 {
6651 // MaxSize()
6652 perform_data_max_size data;
6653 view->Perform(PERFORM_CODE_MAX_SIZE, &data);
6654 }
6655
6656
6657 extern "C" BSize
_ReservedView4__5BView(BView * view)6658 _ReservedView4__5BView(BView* view)
6659 {
6660 // PreferredSize()
6661 perform_data_preferred_size data;
6662 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data);
6663 return data.return_value;
6664 }
6665
6666
6667 extern "C" BAlignment
_ReservedView5__5BView(BView * view)6668 _ReservedView5__5BView(BView* view)
6669 {
6670 // LayoutAlignment()
6671 perform_data_layout_alignment data;
6672 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data);
6673 return data.return_value;
6674 }
6675
6676
6677 extern "C" bool
_ReservedView6__5BView(BView * view)6678 _ReservedView6__5BView(BView* view)
6679 {
6680 // HasHeightForWidth()
6681 perform_data_has_height_for_width data;
6682 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data);
6683 return data.return_value;
6684 }
6685
6686
6687 extern "C" void
_ReservedView7__5BView(BView * view,float width,float * min,float * max,float * preferred)6688 _ReservedView7__5BView(BView* view, float width, float* min, float* max,
6689 float* preferred)
6690 {
6691 // GetHeightForWidth()
6692 perform_data_get_height_for_width data;
6693 data.width = width;
6694 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data);
6695 if (min != NULL)
6696 *min = data.min;
6697 if (max != NULL)
6698 *max = data.max;
6699 if (preferred != NULL)
6700 *preferred = data.preferred;
6701 }
6702
6703
6704 extern "C" void
_ReservedView8__5BView(BView * view,BLayout * layout)6705 _ReservedView8__5BView(BView* view, BLayout* layout)
6706 {
6707 // SetLayout()
6708 perform_data_set_layout data;
6709 data.layout = layout;
6710 view->Perform(PERFORM_CODE_SET_LAYOUT, &data);
6711 }
6712
6713
6714 extern "C" void
_ReservedView9__5BView(BView * view,bool descendants)6715 _ReservedView9__5BView(BView* view, bool descendants)
6716 {
6717 // LayoutInvalidated()
6718 perform_data_layout_invalidated data;
6719 data.descendants = descendants;
6720 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
6721 }
6722
6723
6724 extern "C" void
_ReservedView10__5BView(BView * view)6725 _ReservedView10__5BView(BView* view)
6726 {
6727 // DoLayout()
6728 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL);
6729 }
6730
6731
6732 #endif // __GNUC__ == 2
6733
6734
6735 extern "C" bool
B_IF_GCC_2(_ReservedView11__5BView,_ZN5BView15_ReservedView11Ev)6736 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)(
6737 BView* view, BPoint point, BToolTip** _toolTip)
6738 {
6739 // GetToolTipAt()
6740 perform_data_get_tool_tip_at data;
6741 data.point = point;
6742 data.tool_tip = _toolTip;
6743 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data);
6744 return data.return_value;
6745 }
6746
6747
6748 extern "C" void
B_IF_GCC_2(_ReservedView12__5BView,_ZN5BView15_ReservedView12Ev)6749 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)(
6750 BView* view)
6751 {
6752 // LayoutChanged();
6753 view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL);
6754 }
6755
6756
_ReservedView13()6757 void BView::_ReservedView13() {}
_ReservedView14()6758 void BView::_ReservedView14() {}
_ReservedView15()6759 void BView::_ReservedView15() {}
_ReservedView16()6760 void BView::_ReservedView16() {}
6761
6762
BView(const BView & other)6763 BView::BView(const BView& other)
6764 :
6765 BHandler()
6766 {
6767 // this is private and not functional, but exported
6768 }
6769
6770
6771 BView&
operator =(const BView & other)6772 BView::operator=(const BView& other)
6773 {
6774 // this is private and not functional, but exported
6775 return *this;
6776 }
6777
6778
6779 void
_PrintToStream()6780 BView::_PrintToStream()
6781 {
6782 printf("BView::_PrintToStream()\n");
6783 printf("\tName: %s\n"
6784 "\tParent: %s\n"
6785 "\tFirstChild: %s\n"
6786 "\tNextSibling: %s\n"
6787 "\tPrevSibling: %s\n"
6788 "\tOwner(Window): %s\n"
6789 "\tToken: %" B_PRId32 "\n"
6790 "\tFlags: %" B_PRId32 "\n"
6791 "\tView origin: (%f,%f)\n"
6792 "\tView Bounds rectangle: (%f,%f,%f,%f)\n"
6793 "\tShow level: %d\n"
6794 "\tTopView?: %s\n"
6795 "\tBPicture: %s\n"
6796 "\tVertical Scrollbar %s\n"
6797 "\tHorizontal Scrollbar %s\n"
6798 "\tIs Printing?: %s\n"
6799 "\tShelf?: %s\n"
6800 "\tEventMask: %" B_PRId32 "\n"
6801 "\tEventOptions: %" B_PRId32 "\n",
6802 Name(),
6803 fParent ? fParent->Name() : "NULL",
6804 fFirstChild ? fFirstChild->Name() : "NULL",
6805 fNextSibling ? fNextSibling->Name() : "NULL",
6806 fPreviousSibling ? fPreviousSibling->Name() : "NULL",
6807 fOwner ? fOwner->Name() : "NULL",
6808 _get_object_token_(this),
6809 fFlags,
6810 fParentOffset.x, fParentOffset.y,
6811 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
6812 fShowLevel,
6813 fTopLevelView ? "YES" : "NO",
6814 fCurrentPicture? "YES" : "NULL",
6815 fVerScroller? "YES" : "NULL",
6816 fHorScroller? "YES" : "NULL",
6817 fIsPrinting? "YES" : "NO",
6818 fShelf? "YES" : "NO",
6819 fEventMask,
6820 fEventOptions);
6821
6822 printf("\tState status:\n"
6823 "\t\tLocalCoordianteSystem: (%f,%f)\n"
6824 "\t\tPenLocation: (%f,%f)\n"
6825 "\t\tPenSize: %f\n"
6826 "\t\tHighColor: [%d,%d,%d,%d]\n"
6827 "\t\tLowColor: [%d,%d,%d,%d]\n"
6828 "\t\tViewColor: [%d,%d,%d,%d]\n"
6829 "\t\tPattern: %" B_PRIx64 "\n"
6830 "\t\tDrawingMode: %d\n"
6831 "\t\tLineJoinMode: %d\n"
6832 "\t\tLineCapMode: %d\n"
6833 "\t\tMiterLimit: %f\n"
6834 "\t\tAlphaSource: %d\n"
6835 "\t\tAlphaFuntion: %d\n"
6836 "\t\tScale: %f\n"
6837 "\t\t(Print)FontAliasing: %s\n"
6838 "\t\tFont Info:\n",
6839 fState->origin.x, fState->origin.y,
6840 fState->pen_location.x, fState->pen_location.y,
6841 fState->pen_size,
6842 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
6843 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
6844 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
6845 *((uint64*)&(fState->pattern)),
6846 fState->drawing_mode,
6847 fState->line_join,
6848 fState->line_cap,
6849 fState->miter_limit,
6850 fState->alpha_source_mode,
6851 fState->alpha_function_mode,
6852 fState->scale,
6853 fState->font_aliasing? "YES" : "NO");
6854
6855 fState->font.PrintToStream();
6856
6857 // TODO: also print the line array.
6858 }
6859
6860
6861 void
_PrintTree()6862 BView::_PrintTree()
6863 {
6864 int32 spaces = 2;
6865 BView* c = fFirstChild; //c = short for: current
6866 printf( "'%s'\n", Name() );
6867 if (c != NULL) {
6868 while(true) {
6869 // action block
6870 {
6871 for (int i = 0; i < spaces; i++)
6872 printf(" ");
6873
6874 printf( "'%s'\n", c->Name() );
6875 }
6876
6877 // go deep
6878 if (c->fFirstChild) {
6879 c = c->fFirstChild;
6880 spaces += 2;
6881 } else {
6882 // go right
6883 if (c->fNextSibling) {
6884 c = c->fNextSibling;
6885 } else {
6886 // go up
6887 while (!c->fParent->fNextSibling && c->fParent != this) {
6888 c = c->fParent;
6889 spaces -= 2;
6890 }
6891
6892 // that enough! We've reached this view.
6893 if (c->fParent == this)
6894 break;
6895
6896 c = c->fParent->fNextSibling;
6897 spaces -= 2;
6898 }
6899 }
6900 }
6901 }
6902 }
6903
6904
6905 // #pragma mark -
6906
6907
6908 BLayoutItem*
LayoutItemAt(int32 index)6909 BView::Private::LayoutItemAt(int32 index)
6910 {
6911 return fView->fLayoutData->fLayoutItems.ItemAt(index);
6912 }
6913
6914
6915 int32
CountLayoutItems()6916 BView::Private::CountLayoutItems()
6917 {
6918 return fView->fLayoutData->fLayoutItems.CountItems();
6919 }
6920
6921
6922 void
RegisterLayoutItem(BLayoutItem * item)6923 BView::Private::RegisterLayoutItem(BLayoutItem* item)
6924 {
6925 fView->fLayoutData->fLayoutItems.AddItem(item);
6926 }
6927
6928
6929 void
DeregisterLayoutItem(BLayoutItem * item)6930 BView::Private::DeregisterLayoutItem(BLayoutItem* item)
6931 {
6932 fView->fLayoutData->fLayoutItems.RemoveItem(item);
6933 }
6934
6935
6936 bool
MinMaxValid()6937 BView::Private::MinMaxValid()
6938 {
6939 return fView->fLayoutData->fMinMaxValid;
6940 }
6941
6942
6943 bool
WillLayout()6944 BView::Private::WillLayout()
6945 {
6946 BView::LayoutData* data = fView->fLayoutData;
6947 if (data->fLayoutInProgress)
6948 return false;
6949 if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid)
6950 return true;
6951 return false;
6952 }
6953