xref: /haiku/src/kits/interface/Dragger.cpp (revision 47102c074278637c3b33935b451d53f7ad176658)
1 /*
2  * Copyright 2001-2012, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Rene Gollent (rene@gollent.com)
8  *		Alexandre Deckner (alex@zappotek.com)
9  */
10 
11 
12 //!	BDragger represents a replicant "handle".
13 
14 
15 #include <pthread.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 
19 #include <Alert.h>
20 #include <Beep.h>
21 #include <Bitmap.h>
22 #include <Dragger.h>
23 #include <MenuItem.h>
24 #include <Message.h>
25 #include <PopUpMenu.h>
26 #include <Shelf.h>
27 #include <SystemCatalog.h>
28 #include <Window.h>
29 
30 #include <AutoLocker.h>
31 
32 #include <AppServerLink.h>
33 #include <DragTrackingFilter.h>
34 #include <binary_compatibility/Interface.h>
35 #include <ServerProtocol.h>
36 #include <ViewPrivate.h>
37 
38 #include "ZombieReplicantView.h"
39 
40 using BPrivate::gSystemCatalog;
41 
42 #undef B_TRANSLATION_CONTEXT
43 #define B_TRANSLATION_CONTEXT "Dragger"
44 
45 #undef B_TRANSLATE
46 #define B_TRANSLATE(str) \
47 	gSystemCatalog.GetString(B_TRANSLATE_MARK(str), "Dragger")
48 
49 
50 static const uint32 kMsgDragStarted = 'Drgs';
51 
52 static const unsigned char kHandBitmap[] = {
53 	255, 255,   0,   0,   0, 255, 255, 255,
54 	255, 255,   0, 131, 131,   0, 255, 255,
55 	  0,   0,   0,   0, 131, 131,   0,   0,
56 	  0, 131,   0,   0, 131, 131,   0,   0,
57 	  0, 131, 131, 131, 131, 131,   0,   0,
58 	255,   0, 131, 131, 131, 131,   0,   0,
59 	255, 255,   0,   0,   0,   0,   0,   0,
60 	255, 255, 255, 255, 255, 255,   0,   0
61 };
62 
63 
64 namespace {
65 
66 struct DraggerManager {
67 	bool	visible;
68 	bool	visibleInitialized;
69 	BList	list;
70 
DraggerManager__anonc9b609ce0111::DraggerManager71 	DraggerManager()
72 		:
73 		visible(false),
74 		visibleInitialized(false),
75 		fLock("BDragger static")
76 	{
77 	}
78 
Lock__anonc9b609ce0111::DraggerManager79 	bool Lock()
80 	{
81 		return fLock.Lock();
82 	}
83 
Unlock__anonc9b609ce0111::DraggerManager84 	void Unlock()
85 	{
86 		fLock.Unlock();
87 	}
88 
Default__anonc9b609ce0111::DraggerManager89 	static DraggerManager* Default()
90 	{
91 		if (sDefaultInstance == NULL)
92 			pthread_once(&sDefaultInitOnce, &_InitSingleton);
93 
94 		return sDefaultInstance;
95 	}
96 
97 private:
_InitSingleton__anonc9b609ce0111::DraggerManager98 	static void _InitSingleton()
99 	{
100 		sDefaultInstance = new DraggerManager;
101 	}
102 
103 private:
104 	BLocker					fLock;
105 
106 	static pthread_once_t	sDefaultInitOnce;
107 	static DraggerManager*	sDefaultInstance;
108 };
109 
110 pthread_once_t DraggerManager::sDefaultInitOnce = PTHREAD_ONCE_INIT;
111 DraggerManager* DraggerManager::sDefaultInstance = NULL;
112 
113 }	// unnamed namespace
114 
115 
BDragger(BRect frame,BView * target,uint32 resizingMode,uint32 flags)116 BDragger::BDragger(BRect frame, BView* target, uint32 resizingMode,
117 	uint32 flags)
118 	:
119 	BView(frame, "_dragger_", resizingMode, flags),
120 	fTarget(target),
121 	fRelation(TARGET_UNKNOWN),
122 	fShelf(NULL),
123 	fTransition(false),
124 	fIsZombie(false),
125 	fErrCount(0),
126 	fPopUpIsCustom(false),
127 	fPopUp(NULL)
128 {
129 	_InitData();
130 }
131 
132 
BDragger(BView * target,uint32 flags)133 BDragger::BDragger(BView* target, uint32 flags)
134 	:
135 	BView("_dragger_", flags),
136 	fTarget(target),
137 	fRelation(TARGET_UNKNOWN),
138 	fShelf(NULL),
139 	fTransition(false),
140 	fIsZombie(false),
141 	fErrCount(0),
142 	fPopUpIsCustom(false),
143 	fPopUp(NULL)
144 {
145 	_InitData();
146 }
147 
148 
BDragger(BMessage * data)149 BDragger::BDragger(BMessage* data)
150 	:
151 	BView(data),
152 	fTarget(NULL),
153 	fRelation(TARGET_UNKNOWN),
154 	fShelf(NULL),
155 	fTransition(false),
156 	fIsZombie(false),
157 	fErrCount(0),
158 	fPopUpIsCustom(false),
159 	fPopUp(NULL)
160 {
161 	data->FindInt32("_rel", (int32*)&fRelation);
162 
163 	_InitData();
164 
165 	BMessage popupMsg;
166 	if (data->FindMessage("_popup", &popupMsg) == B_OK) {
167 		BArchivable* archivable = instantiate_object(&popupMsg);
168 
169 		if (archivable) {
170 			fPopUp = dynamic_cast<BPopUpMenu*>(archivable);
171 			fPopUpIsCustom = true;
172 		}
173 	}
174 }
175 
176 
~BDragger()177 BDragger::~BDragger()
178 {
179 	delete fPopUp;
180 	delete fBitmap;
181 }
182 
183 
184 BArchivable	*
Instantiate(BMessage * data)185 BDragger::Instantiate(BMessage* data)
186 {
187 	if (validate_instantiation(data, "BDragger"))
188 		return new BDragger(data);
189 	return NULL;
190 }
191 
192 
193 status_t
Archive(BMessage * data,bool deep) const194 BDragger::Archive(BMessage* data, bool deep) const
195 {
196 	status_t ret = BView::Archive(data, deep);
197 	if (ret != B_OK)
198 		return ret;
199 
200 	BMessage popupMsg;
201 
202 	if (fPopUp != NULL && fPopUpIsCustom) {
203 		bool windowLocked = fPopUp->Window()->Lock();
204 
205 		ret = fPopUp->Archive(&popupMsg, deep);
206 
207 		if (windowLocked) {
208 			fPopUp->Window()->Unlock();
209 				// TODO: Investigate, in some (rare) occasions the menu window
210 				//		 has already been unlocked
211 		}
212 
213 		if (ret == B_OK)
214 			ret = data->AddMessage("_popup", &popupMsg);
215 	}
216 
217 	if (ret == B_OK)
218 		ret = data->AddInt32("_rel", fRelation);
219 	return ret;
220 }
221 
222 
223 void
AttachedToWindow()224 BDragger::AttachedToWindow()
225 {
226 	if (fIsZombie) {
227 		SetLowColor(kZombieColor);
228 		SetViewColor(kZombieColor);
229 	} else {
230 		SetFlags(Flags() | B_TRANSPARENT_BACKGROUND);
231 		SetLowColor(B_TRANSPARENT_COLOR);
232 		SetViewColor(B_TRANSPARENT_COLOR);
233 	}
234 
235 	_DetermineRelationship();
236 	_AddToList();
237 
238 	AddFilter(new DragTrackingFilter(this, kMsgDragStarted));
239 }
240 
241 
242 void
DetachedFromWindow()243 BDragger::DetachedFromWindow()
244 {
245 	_RemoveFromList();
246 }
247 
248 
249 void
Draw(BRect update)250 BDragger::Draw(BRect update)
251 {
252 	BRect bounds(Bounds());
253 
254 	if (AreDraggersDrawn() && (fShelf == NULL || fShelf->AllowsDragging())) {
255 		BPoint where = bounds.RightBottom() - BPoint(fBitmap->Bounds().Width(),
256 			fBitmap->Bounds().Height());
257 		SetDrawingMode(B_OP_OVER);
258 		DrawBitmap(fBitmap, where);
259 		SetDrawingMode(B_OP_COPY);
260 
261 		if (fIsZombie) {
262 			// TODO: should draw it differently ?
263 		}
264 	}
265 }
266 
267 
268 void
MouseDown(BPoint where)269 BDragger::MouseDown(BPoint where)
270 {
271 	if (fTarget == NULL || !AreDraggersDrawn())
272 		return;
273 
274 	uint32 buttons;
275 	Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
276 
277 	if (fShelf != NULL && (buttons & B_SECONDARY_MOUSE_BUTTON) != 0)
278 		_ShowPopUp(fTarget, where);
279 }
280 
281 
282 void
MouseUp(BPoint point)283 BDragger::MouseUp(BPoint point)
284 {
285 	BView::MouseUp(point);
286 }
287 
288 
289 void
MouseMoved(BPoint point,uint32 code,const BMessage * msg)290 BDragger::MouseMoved(BPoint point, uint32 code, const BMessage* msg)
291 {
292 	BView::MouseMoved(point, code, msg);
293 }
294 
295 
296 void
MessageReceived(BMessage * msg)297 BDragger::MessageReceived(BMessage* msg)
298 {
299 	switch (msg->what) {
300 		case B_TRASH_TARGET:
301 			if (fShelf != NULL)
302 				Window()->PostMessage(kDeleteReplicant, fTarget, NULL);
303 			else {
304 				BAlert* alert = new BAlert(B_TRANSLATE("Warning"),
305 					B_TRANSLATE("Can't delete this replicant from its original "
306 					"application. Life goes on."),
307 					B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_FROM_WIDEST,
308 					B_WARNING_ALERT);
309 				alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
310 				alert->Go(NULL);
311 			}
312 			break;
313 
314 		case _SHOW_DRAG_HANDLES_:
315 			// This code is used whenever the "are draggers drawn" option is
316 			// changed.
317 			if (fRelation == TARGET_IS_CHILD) {
318 				Invalidate(Bounds());
319 			} else {
320 				if ((fShelf != NULL && fShelf->AllowsDragging()
321 						&& AreDraggersDrawn())
322 					|| AreDraggersDrawn()) {
323 					Show();
324 				} else
325 					Hide();
326 			}
327 			break;
328 
329 		case kMsgDragStarted:
330 			if (fTarget != NULL) {
331 				BMessage archive(B_ARCHIVED_OBJECT);
332 
333 				if (fRelation == TARGET_IS_PARENT)
334 					fTarget->Archive(&archive);
335 				else if (fRelation == TARGET_IS_CHILD)
336 					Archive(&archive);
337 				else if (fTarget->Archive(&archive)) {
338 					BMessage archivedSelf(B_ARCHIVED_OBJECT);
339 
340 					if (Archive(&archivedSelf))
341 						archive.AddMessage("__widget", &archivedSelf);
342 				}
343 
344 				archive.AddInt32("be:actions", B_TRASH_TARGET);
345 				BPoint offset;
346 				drawing_mode mode;
347 				BBitmap* bitmap = DragBitmap(&offset, &mode);
348 				if (bitmap != NULL)
349 					DragMessage(&archive, bitmap, mode, offset, this);
350 				else {
351 					DragMessage(&archive, ConvertFromScreen(
352 						fTarget->ConvertToScreen(fTarget->Bounds())), this);
353 				}
354 			}
355 			break;
356 
357 		default:
358 			BView::MessageReceived(msg);
359 			break;
360 	}
361 }
362 
363 
364 void
FrameMoved(BPoint newPosition)365 BDragger::FrameMoved(BPoint newPosition)
366 {
367 	BView::FrameMoved(newPosition);
368 }
369 
370 
371 void
FrameResized(float newWidth,float newHeight)372 BDragger::FrameResized(float newWidth, float newHeight)
373 {
374 	BView::FrameResized(newWidth, newHeight);
375 }
376 
377 
378 status_t
ShowAllDraggers()379 BDragger::ShowAllDraggers()
380 {
381 	BPrivate::AppServerLink link;
382 	link.StartMessage(AS_SET_SHOW_ALL_DRAGGERS);
383 	link.Attach<bool>(true);
384 
385 	status_t status = link.Flush();
386 	if (status == B_OK) {
387 		DraggerManager* manager = DraggerManager::Default();
388 		AutoLocker<DraggerManager> locker(manager);
389 		manager->visible = true;
390 		manager->visibleInitialized = true;
391 	}
392 
393 	return status;
394 }
395 
396 
397 status_t
HideAllDraggers()398 BDragger::HideAllDraggers()
399 {
400 	BPrivate::AppServerLink link;
401 	link.StartMessage(AS_SET_SHOW_ALL_DRAGGERS);
402 	link.Attach<bool>(false);
403 
404 	status_t status = link.Flush();
405 	if (status == B_OK) {
406 		DraggerManager* manager = DraggerManager::Default();
407 		AutoLocker<DraggerManager> locker(manager);
408 		manager->visible = false;
409 		manager->visibleInitialized = true;
410 	}
411 
412 	return status;
413 }
414 
415 
416 bool
AreDraggersDrawn()417 BDragger::AreDraggersDrawn()
418 {
419 	DraggerManager* manager = DraggerManager::Default();
420 	AutoLocker<DraggerManager> locker(manager);
421 
422 	if (!manager->visibleInitialized) {
423 		BPrivate::AppServerLink link;
424 		link.StartMessage(AS_GET_SHOW_ALL_DRAGGERS);
425 
426 		status_t status;
427 		if (link.FlushWithReply(status) == B_OK && status == B_OK) {
428 			link.Read<bool>(&manager->visible);
429 			manager->visibleInitialized = true;
430 		} else
431 			return false;
432 	}
433 
434 	return manager->visible;
435 }
436 
437 
438 BHandler*
ResolveSpecifier(BMessage * message,int32 index,BMessage * specifier,int32 form,const char * property)439 BDragger::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
440 	int32 form, const char* property)
441 {
442 	return BView::ResolveSpecifier(message, index, specifier, form, property);
443 }
444 
445 
446 status_t
GetSupportedSuites(BMessage * data)447 BDragger::GetSupportedSuites(BMessage* data)
448 {
449 	return BView::GetSupportedSuites(data);
450 }
451 
452 
453 status_t
Perform(perform_code code,void * _data)454 BDragger::Perform(perform_code code, void* _data)
455 {
456 	switch (code) {
457 		case PERFORM_CODE_MIN_SIZE:
458 			((perform_data_min_size*)_data)->return_value
459 				= BDragger::MinSize();
460 			return B_OK;
461 		case PERFORM_CODE_MAX_SIZE:
462 			((perform_data_max_size*)_data)->return_value
463 				= BDragger::MaxSize();
464 			return B_OK;
465 		case PERFORM_CODE_PREFERRED_SIZE:
466 			((perform_data_preferred_size*)_data)->return_value
467 				= BDragger::PreferredSize();
468 			return B_OK;
469 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
470 			((perform_data_layout_alignment*)_data)->return_value
471 				= BDragger::LayoutAlignment();
472 			return B_OK;
473 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
474 			((perform_data_has_height_for_width*)_data)->return_value
475 				= BDragger::HasHeightForWidth();
476 			return B_OK;
477 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
478 		{
479 			perform_data_get_height_for_width* data
480 				= (perform_data_get_height_for_width*)_data;
481 			BDragger::GetHeightForWidth(data->width, &data->min, &data->max,
482 				&data->preferred);
483 			return B_OK;
484 }
485 		case PERFORM_CODE_SET_LAYOUT:
486 		{
487 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
488 			BDragger::SetLayout(data->layout);
489 			return B_OK;
490 		}
491 		case PERFORM_CODE_LAYOUT_INVALIDATED:
492 		{
493 			perform_data_layout_invalidated* data
494 				= (perform_data_layout_invalidated*)_data;
495 			BDragger::LayoutInvalidated(data->descendants);
496 			return B_OK;
497 		}
498 		case PERFORM_CODE_DO_LAYOUT:
499 		{
500 			BDragger::DoLayout();
501 			return B_OK;
502 		}
503 	}
504 
505 	return BView::Perform(code, _data);
506 }
507 
508 
509 void
ResizeToPreferred()510 BDragger::ResizeToPreferred()
511 {
512 	BView::ResizeToPreferred();
513 }
514 
515 
516 void
GetPreferredSize(float * _width,float * _height)517 BDragger::GetPreferredSize(float* _width, float* _height)
518 {
519 	BView::GetPreferredSize(_width, _height);
520 }
521 
522 
523 void
MakeFocus(bool state)524 BDragger::MakeFocus(bool state)
525 {
526 	BView::MakeFocus(state);
527 }
528 
529 
530 void
AllAttached()531 BDragger::AllAttached()
532 {
533 	BView::AllAttached();
534 }
535 
536 
537 void
AllDetached()538 BDragger::AllDetached()
539 {
540 	BView::AllDetached();
541 }
542 
543 
544 status_t
SetPopUp(BPopUpMenu * menu)545 BDragger::SetPopUp(BPopUpMenu* menu)
546 {
547 	if (menu != NULL && menu != fPopUp) {
548 		delete fPopUp;
549 		fPopUp = menu;
550 		fPopUpIsCustom = true;
551 		return B_OK;
552 	}
553 	return B_ERROR;
554 }
555 
556 
557 BPopUpMenu*
PopUp() const558 BDragger::PopUp() const
559 {
560 	if (fPopUp == NULL && fTarget)
561 		const_cast<BDragger*>(this)->_BuildDefaultPopUp();
562 
563 	return fPopUp;
564 }
565 
566 
567 bool
InShelf() const568 BDragger::InShelf() const
569 {
570 	return fShelf != NULL;
571 }
572 
573 
574 BView*
Target() const575 BDragger::Target() const
576 {
577 	return fTarget;
578 }
579 
580 
581 BBitmap*
DragBitmap(BPoint * offset,drawing_mode * mode)582 BDragger::DragBitmap(BPoint* offset, drawing_mode* mode)
583 {
584 	return NULL;
585 }
586 
587 
588 bool
IsVisibilityChanging() const589 BDragger::IsVisibilityChanging() const
590 {
591 	return fTransition;
592 }
593 
594 
_ReservedDragger2()595 void BDragger::_ReservedDragger2() {}
_ReservedDragger3()596 void BDragger::_ReservedDragger3() {}
_ReservedDragger4()597 void BDragger::_ReservedDragger4() {}
598 
599 
600 BDragger&
operator =(const BDragger &)601 BDragger::operator=(const BDragger&)
602 {
603 	return *this;
604 }
605 
606 
607 /*static*/ void
_UpdateShowAllDraggers(bool visible)608 BDragger::_UpdateShowAllDraggers(bool visible)
609 {
610 	DraggerManager* manager = DraggerManager::Default();
611 	AutoLocker<DraggerManager> locker(manager);
612 
613 	manager->visibleInitialized = true;
614 	manager->visible = visible;
615 
616 	for (int32 i = manager->list.CountItems(); i-- > 0;) {
617 		BDragger* dragger = (BDragger*)manager->list.ItemAt(i);
618 		BMessenger target(dragger);
619 		target.SendMessage(_SHOW_DRAG_HANDLES_);
620 	}
621 }
622 
623 
624 void
_InitData()625 BDragger::_InitData()
626 {
627 	fBitmap = new BBitmap(BRect(0.0f, 0.0f, 7.0f, 7.0f), B_CMAP8, false, false);
628 	fBitmap->SetBits(kHandBitmap, fBitmap->BitsLength(), 0, B_CMAP8);
629 }
630 
631 
632 void
_AddToList()633 BDragger::_AddToList()
634 {
635 	DraggerManager* manager = DraggerManager::Default();
636 	AutoLocker<DraggerManager> locker(manager);
637 	manager->list.AddItem(this);
638 
639 	bool allowsDragging = true;
640 	if (fShelf)
641 		allowsDragging = fShelf->AllowsDragging();
642 
643 	if (!AreDraggersDrawn() || !allowsDragging) {
644 		// The dragger is not shown - but we can't hide us in case we're the
645 		// parent of the actual target view (because then you couldn't see
646 		// it anymore).
647 		if (fRelation != TARGET_IS_CHILD && !IsHidden(this))
648 			Hide();
649 	}
650 }
651 
652 
653 void
_RemoveFromList()654 BDragger::_RemoveFromList()
655 {
656 	DraggerManager* manager = DraggerManager::Default();
657 	AutoLocker<DraggerManager> locker(manager);
658 	manager->list.RemoveItem(this);
659 }
660 
661 
662 status_t
_DetermineRelationship()663 BDragger::_DetermineRelationship()
664 {
665 	if (fTarget != NULL) {
666 		if (fTarget == Parent())
667 			fRelation = TARGET_IS_PARENT;
668 		else if (fTarget == ChildAt(0))
669 			fRelation = TARGET_IS_CHILD;
670 		else
671 			fRelation = TARGET_IS_SIBLING;
672 	} else {
673 		if (fRelation == TARGET_IS_PARENT)
674 			fTarget = Parent();
675 		else if (fRelation == TARGET_IS_CHILD)
676 			fTarget = ChildAt(0);
677 		else
678 			return B_ERROR;
679 	}
680 
681 	if (fRelation == TARGET_IS_PARENT) {
682 		BRect bounds(Frame());
683 		BRect parentBounds(Parent()->Bounds());
684 		if (!parentBounds.Contains(bounds)) {
685 			MoveTo(parentBounds.right - bounds.Width(),
686 				parentBounds.bottom - bounds.Height());
687 		}
688 	}
689 
690 	return B_OK;
691 }
692 
693 
694 status_t
_SetViewToDrag(BView * target)695 BDragger::_SetViewToDrag(BView* target)
696 {
697 	if (target->Window() != Window())
698 		return B_ERROR;
699 
700 	fTarget = target;
701 
702 	if (Window() != NULL)
703 		_DetermineRelationship();
704 
705 	return B_OK;
706 }
707 
708 
709 void
_SetShelf(BShelf * shelf)710 BDragger::_SetShelf(BShelf* shelf)
711 {
712 	fShelf = shelf;
713 }
714 
715 
716 void
_SetZombied(bool state)717 BDragger::_SetZombied(bool state)
718 {
719 	fIsZombie = state;
720 
721 	if (state) {
722 		SetLowColor(kZombieColor);
723 		SetViewColor(kZombieColor);
724 	}
725 }
726 
727 
728 void
_BuildDefaultPopUp()729 BDragger::_BuildDefaultPopUp()
730 {
731 	fPopUp = new BPopUpMenu("Shelf", false, false, B_ITEMS_IN_COLUMN);
732 
733 	// About
734 	BMessage* msg = new BMessage(B_ABOUT_REQUESTED);
735 
736 	const char* name = fTarget->Name();
737 	if (name != NULL)
738 		msg->AddString("target", name);
739 
740 	BString about(B_TRANSLATE("About %app" B_UTF8_ELLIPSIS));
741 	about.ReplaceFirst("%app", name);
742 
743 	fPopUp->AddItem(new BMenuItem(about.String(), msg));
744 	fPopUp->AddSeparatorItem();
745 	fPopUp->AddItem(new BMenuItem(B_TRANSLATE("Remove replicant"),
746 		new BMessage(kDeleteReplicant)));
747 }
748 
749 
750 void
_ShowPopUp(BView * target,BPoint where)751 BDragger::_ShowPopUp(BView* target, BPoint where)
752 {
753 	BPoint point = ConvertToScreen(where);
754 
755 	if (fPopUp == NULL && fTarget != NULL)
756 		_BuildDefaultPopUp();
757 
758 	fPopUp->SetTargetForItems(fTarget);
759 
760 	float menuWidth, menuHeight;
761 	fPopUp->GetPreferredSize(&menuWidth, &menuHeight);
762 	BRect rect(0, 0, menuWidth, menuHeight);
763 	rect.InsetBy(-0.5, -0.5);
764 	rect.OffsetTo(point);
765 
766 	fPopUp->Go(point, true, false, rect, true);
767 }
768 
769 
770 #if __GNUC__ < 3
771 
772 extern "C" BBitmap*
_ReservedDragger1__8BDragger(BDragger * dragger,BPoint * offset,drawing_mode * mode)773 _ReservedDragger1__8BDragger(BDragger* dragger, BPoint* offset,
774 	drawing_mode* mode)
775 {
776 	return dragger->BDragger::DragBitmap(offset, mode);
777 }
778 
779 #endif
780