136aa2198SStefano Ceccherini/*
236aa2198SStefano Ceccherini * Copyright 2001-2006, Haiku, Inc.
336aa2198SStefano Ceccherini * Distributed under the terms of the MIT License.
436aa2198SStefano Ceccherini *
536aa2198SStefano Ceccherini * Authors:
636aa2198SStefano Ceccherini *		Marc Flerackers (mflerackers@androme.be)
736aa2198SStefano Ceccherini *		Stefano Ceccherini (burton666@libero.it)
836aa2198SStefano Ceccherini */
936aa2198SStefano Ceccherini
106d27f962SAxel Dörfler
114b44b026SStefano Ceccherini#include <Application.h>
124b44b026SStefano Ceccherini#include <Looper.h>
134b44b026SStefano Ceccherini#include <MenuItem.h>
144b44b026SStefano Ceccherini#include <PopUpMenu.h>
154b44b026SStefano Ceccherini#include <Window.h>
164b44b026SStefano Ceccherini
17277a78abSStefano Ceccherini#include <new>
184b44b026SStefano Ceccherini
1939fbf550SOliver Tappe#include <binary_compatibility/Interface.h>
2039fbf550SOliver Tappe
213ec18e87SMarcus Overhagen
226d27f962SAxel Dörflerstruct popup_menu_data {
2301b1b8bdSJohn Scipione	BPopUpMenu* object;
2401b1b8bdSJohn Scipione	BWindow* window;
2501b1b8bdSJohn Scipione	BMenuItem* selected;
266d27f962SAxel Dörfler
274b44b026SStefano Ceccherini	BPoint where;
284b44b026SStefano Ceccherini	BRect rect;
296d27f962SAxel Dörfler
304b44b026SStefano Ceccherini	bool async;
3114260ebbSStefano Ceccherini	bool autoInvoke;
3214260ebbSStefano Ceccherini	bool startOpened;
3314260ebbSStefano Ceccherini	bool useRect;
346d27f962SAxel Dörfler
354b44b026SStefano Ceccherini	sem_id lock;
364b44b026SStefano Ceccherini};
372847a12dSAxel Dörfler
382847a12dSAxel Dörfler
396f33360fSJohn ScipioneBPopUpMenu::BPopUpMenu(const char* name, bool radioMode, bool labelFromMarked,
4001b1b8bdSJohn Scipione	menu_layout layout)
4101b1b8bdSJohn Scipione	:
426f33360fSJohn Scipione	BMenu(name, layout),
432847a12dSAxel Dörfler	fUseWhere(false),
442847a12dSAxel Dörfler	fAutoDestruct(false),
452847a12dSAxel Dörfler	fTrackThread(-1)
462847a12dSAxel Dörfler{
472847a12dSAxel Dörfler	if (radioMode)
482847a12dSAxel Dörfler		SetRadioMode(true);
492847a12dSAxel Dörfler
506f33360fSJohn Scipione	if (labelFromMarked)
512847a12dSAxel Dörfler		SetLabelFromMarked(true);
522847a12dSAxel Dörfler}
532847a12dSAxel Dörfler
542847a12dSAxel Dörfler
5501b1b8bdSJohn ScipioneBPopUpMenu::BPopUpMenu(BMessage* archive)
5601b1b8bdSJohn Scipione	:
5701b1b8bdSJohn Scipione	BMenu(archive),
582847a12dSAxel Dörfler	fUseWhere(false),
592847a12dSAxel Dörfler	fAutoDestruct(false),
602847a12dSAxel Dörfler	fTrackThread(-1)
612847a12dSAxel Dörfler{
622847a12dSAxel Dörfler}
632847a12dSAxel Dörfler
642847a12dSAxel Dörfler
652847a12dSAxel DörflerBPopUpMenu::~BPopUpMenu()
662847a12dSAxel Dörfler{
674b44b026SStefano Ceccherini	if (fTrackThread >= 0) {
684b44b026SStefano Ceccherini		status_t status;
694b44b026SStefano Ceccherini		while (wait_for_thread(fTrackThread, &status) == B_INTERRUPTED)
7099939029SKarsten Heimrich			;
714b44b026SStefano Ceccherini	}
722847a12dSAxel Dörfler}
732847a12dSAxel Dörfler
742847a12dSAxel Dörfler
752847a12dSAxel Dörflerstatus_t
7601b1b8bdSJohn ScipioneBPopUpMenu::Archive(BMessage* data, bool deep) const
772847a12dSAxel Dörfler{
782847a12dSAxel Dörfler	return BMenu::Archive(data, deep);
792847a12dSAxel Dörfler}
802847a12dSAxel Dörfler
812847a12dSAxel Dörfler
8201b1b8bdSJohn ScipioneBArchivable*
8301b1b8bdSJohn ScipioneBPopUpMenu::Instantiate(BMessage* data)
842847a12dSAxel Dörfler{
852847a12dSAxel Dörfler	if (validate_instantiation(data, "BPopUpMenu"))
862847a12dSAxel Dörfler		return new BPopUpMenu(data);
872847a12dSAxel Dörfler
882847a12dSAxel Dörfler	return NULL;
892847a12dSAxel Dörfler}
902847a12dSAxel Dörfler
912847a12dSAxel Dörfler
9201b1b8bdSJohn ScipioneBMenuItem*
936d27f962SAxel DörflerBPopUpMenu::Go(BPoint where, bool deliversMessage, bool openAnyway, bool async)
942847a12dSAxel Dörfler{
95cd1cef8aSStefano Ceccherini	return _Go(where, deliversMessage, openAnyway, NULL, async);
962847a12dSAxel Dörfler}
972847a12dSAxel Dörfler
982847a12dSAxel Dörfler
9901b1b8bdSJohn ScipioneBMenuItem*
1002847a12dSAxel DörflerBPopUpMenu::Go(BPoint where, bool deliversMessage, bool openAnyway,
1012847a12dSAxel Dörfler	BRect clickToOpen, bool async)
1022847a12dSAxel Dörfler{
103cd1cef8aSStefano Ceccherini	return _Go(where, deliversMessage, openAnyway, &clickToOpen, async);
1042847a12dSAxel Dörfler}
1052847a12dSAxel Dörfler
1062847a12dSAxel Dörfler
1072847a12dSAxel Dörflervoid
10801b1b8bdSJohn ScipioneBPopUpMenu::MessageReceived(BMessage* message)
1092847a12dSAxel Dörfler{
11001b1b8bdSJohn Scipione	BMenu::MessageReceived(message);
1112847a12dSAxel Dörfler}
1122847a12dSAxel Dörfler
1132847a12dSAxel Dörfler
1142847a12dSAxel Dörflervoid
1152847a12dSAxel DörflerBPopUpMenu::MouseDown(BPoint point)
1162847a12dSAxel Dörfler{
1174b44b026SStefano Ceccherini	BView::MouseDown(point);
1182847a12dSAxel Dörfler}
1192847a12dSAxel Dörfler
1202847a12dSAxel Dörfler
1212847a12dSAxel Dörflervoid
1222847a12dSAxel DörflerBPopUpMenu::MouseUp(BPoint point)
1232847a12dSAxel Dörfler{
1244b44b026SStefano Ceccherini	BView::MouseUp(point);
1252847a12dSAxel Dörfler}
1262847a12dSAxel Dörfler
1272847a12dSAxel Dörfler
1282847a12dSAxel Dörflervoid
12901b1b8bdSJohn ScipioneBPopUpMenu::MouseMoved(BPoint point, uint32 code, const BMessage* message)
1302847a12dSAxel Dörfler{
13101b1b8bdSJohn Scipione	BView::MouseMoved(point, code, message);
1322847a12dSAxel Dörfler}
1332847a12dSAxel Dörfler
1342847a12dSAxel Dörfler
1352847a12dSAxel Dörflervoid
1362847a12dSAxel DörflerBPopUpMenu::AttachedToWindow()
1372847a12dSAxel Dörfler{
1382847a12dSAxel Dörfler	BMenu::AttachedToWindow();
1392847a12dSAxel Dörfler}
1402847a12dSAxel Dörfler
1412847a12dSAxel Dörfler
1422847a12dSAxel Dörflervoid
1432847a12dSAxel DörflerBPopUpMenu::DetachedFromWindow()
1442847a12dSAxel Dörfler{
1452847a12dSAxel Dörfler	BMenu::DetachedFromWindow();
1462847a12dSAxel Dörfler}
1472847a12dSAxel Dörfler
1482847a12dSAxel Dörfler
1492847a12dSAxel Dörflervoid
1502847a12dSAxel DörflerBPopUpMenu::FrameMoved(BPoint newPosition)
1512847a12dSAxel Dörfler{
1522847a12dSAxel Dörfler	BMenu::FrameMoved(newPosition);
1532847a12dSAxel Dörfler}
1542847a12dSAxel Dörfler
1552847a12dSAxel Dörfler
1562847a12dSAxel Dörflervoid
1572847a12dSAxel DörflerBPopUpMenu::FrameResized(float newWidth, float newHeight)
1582847a12dSAxel Dörfler{
1592847a12dSAxel Dörfler	BMenu::FrameResized(newWidth, newHeight);
1602847a12dSAxel Dörfler}
1612847a12dSAxel Dörfler
1622847a12dSAxel Dörfler
16301b1b8bdSJohn ScipioneBHandler*
16401b1b8bdSJohn ScipioneBPopUpMenu::ResolveSpecifier(BMessage* message, int32 index,
16501b1b8bdSJohn Scipione	BMessage* specifier, int32 form, const char* property)
1662847a12dSAxel Dörfler{
16701b1b8bdSJohn Scipione	return BMenu::ResolveSpecifier(message, index, specifier, form, property);
1682847a12dSAxel Dörfler}
1692847a12dSAxel Dörfler
1702847a12dSAxel Dörfler
1712847a12dSAxel Dörflerstatus_t
17201b1b8bdSJohn ScipioneBPopUpMenu::GetSupportedSuites(BMessage* data)
1732847a12dSAxel Dörfler{
1742847a12dSAxel Dörfler	return BMenu::GetSupportedSuites(data);
1752847a12dSAxel Dörfler}
1762847a12dSAxel Dörfler
1772847a12dSAxel Dörfler
1782847a12dSAxel Dörflerstatus_t
17939fbf550SOliver TappeBPopUpMenu::Perform(perform_code code, void* _data)
18039fbf550SOliver Tappe{
18139fbf550SOliver Tappe	switch (code) {
18239fbf550SOliver Tappe		case PERFORM_CODE_MIN_SIZE:
18339fbf550SOliver Tappe			((perform_data_min_size*)_data)->return_value
18439fbf550SOliver Tappe				= BPopUpMenu::MinSize();
18539fbf550SOliver Tappe			return B_OK;
18639fbf550SOliver Tappe		case PERFORM_CODE_MAX_SIZE:
18739fbf550SOliver Tappe			((perform_data_max_size*)_data)->return_value
18839fbf550SOliver Tappe				= BPopUpMenu::MaxSize();
18939fbf550SOliver Tappe			return B_OK;
19039fbf550SOliver Tappe		case PERFORM_CODE_PREFERRED_SIZE:
19139fbf550SOliver Tappe			((perform_data_preferred_size*)_data)->return_value
19239fbf550SOliver Tappe				= BPopUpMenu::PreferredSize();
19339fbf550SOliver Tappe			return B_OK;
19439fbf550SOliver Tappe		case PERFORM_CODE_LAYOUT_ALIGNMENT:
19539fbf550SOliver Tappe			((perform_data_layout_alignment*)_data)->return_value
19639fbf550SOliver Tappe				= BPopUpMenu::LayoutAlignment();
19739fbf550SOliver Tappe			return B_OK;
19839fbf550SOliver Tappe		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
19939fbf550SOliver Tappe			((perform_data_has_height_for_width*)_data)->return_value
20039fbf550SOliver Tappe				= BPopUpMenu::HasHeightForWidth();
20139fbf550SOliver Tappe			return B_OK;
20239fbf550SOliver Tappe		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
20339fbf550SOliver Tappe		{
20439fbf550SOliver Tappe			perform_data_get_height_for_width* data
20539fbf550SOliver Tappe				= (perform_data_get_height_for_width*)_data;
20639fbf550SOliver Tappe			BPopUpMenu::GetHeightForWidth(data->width, &data->min, &data->max,
20739fbf550SOliver Tappe				&data->preferred);
20839fbf550SOliver Tappe			return B_OK;
20901b1b8bdSJohn Scipione		}
21039fbf550SOliver Tappe		case PERFORM_CODE_SET_LAYOUT:
21139fbf550SOliver Tappe		{
21239fbf550SOliver Tappe			perform_data_set_layout* data = (perform_data_set_layout*)_data;
21339fbf550SOliver Tappe			BPopUpMenu::SetLayout(data->layout);
21439fbf550SOliver Tappe			return B_OK;
21539fbf550SOliver Tappe		}
216eee4243dSAlex Wilson		case PERFORM_CODE_LAYOUT_INVALIDATED:
21739fbf550SOliver Tappe		{
218eee4243dSAlex Wilson			perform_data_layout_invalidated* data
219eee4243dSAlex Wilson				= (perform_data_layout_invalidated*)_data;
220eee4243dSAlex Wilson			BPopUpMenu::LayoutInvalidated(data->descendants);
22139fbf550SOliver Tappe			return B_OK;
22239fbf550SOliver Tappe		}
22339fbf550SOliver Tappe		case PERFORM_CODE_DO_LAYOUT:
22439fbf550SOliver Tappe		{
22539fbf550SOliver Tappe			BPopUpMenu::DoLayout();
22639fbf550SOliver Tappe			return B_OK;
22739fbf550SOliver Tappe		}
22839fbf550SOliver Tappe	}
22939fbf550SOliver Tappe
23039fbf550SOliver Tappe	return BMenu::Perform(code, _data);
2312847a12dSAxel Dörfler}
2322847a12dSAxel Dörfler
2332847a12dSAxel Dörfler
2342847a12dSAxel Dörflervoid
2352847a12dSAxel DörflerBPopUpMenu::ResizeToPreferred()
2362847a12dSAxel Dörfler{
2372847a12dSAxel Dörfler	BMenu::ResizeToPreferred();
2382847a12dSAxel Dörfler}
2392847a12dSAxel Dörfler
2402847a12dSAxel Dörfler
2412847a12dSAxel Dörflervoid
24201b1b8bdSJohn ScipioneBPopUpMenu::GetPreferredSize(float* _width, float* _height)
2432847a12dSAxel Dörfler{
2442847a12dSAxel Dörfler	BMenu::GetPreferredSize(_width, _height);
2452847a12dSAxel Dörfler}
2462847a12dSAxel Dörfler
2472847a12dSAxel Dörfler
2482847a12dSAxel Dörflervoid
2492847a12dSAxel DörflerBPopUpMenu::MakeFocus(bool state)
2502847a12dSAxel Dörfler{
2512847a12dSAxel Dörfler	BMenu::MakeFocus(state);
2522847a12dSAxel Dörfler}
2532847a12dSAxel Dörfler
2542847a12dSAxel Dörfler
2552847a12dSAxel Dörflervoid
2562847a12dSAxel DörflerBPopUpMenu::AllAttached()
2572847a12dSAxel Dörfler{
2582847a12dSAxel Dörfler	BMenu::AllAttached();
2592847a12dSAxel Dörfler}
2602847a12dSAxel Dörfler
2612847a12dSAxel Dörfler
2622847a12dSAxel Dörflervoid
2632847a12dSAxel DörflerBPopUpMenu::AllDetached()
2642847a12dSAxel Dörfler{
2652847a12dSAxel Dörfler	BMenu::AllDetached();
2662847a12dSAxel Dörfler}
2672847a12dSAxel Dörfler
2682847a12dSAxel Dörfler
2692847a12dSAxel Dörflervoid
2706f33360fSJohn ScipioneBPopUpMenu::SetAsyncAutoDestruct(bool on)
2712847a12dSAxel Dörfler{
2726f33360fSJohn Scipione	fAutoDestruct = on;
2732847a12dSAxel Dörfler}
2742847a12dSAxel Dörfler
2752847a12dSAxel Dörfler
2762847a12dSAxel Dörflerbool
2772847a12dSAxel DörflerBPopUpMenu::AsyncAutoDestruct() const
2782847a12dSAxel Dörfler{
2792847a12dSAxel Dörfler	return fAutoDestruct;
2802847a12dSAxel Dörfler}
2812847a12dSAxel Dörfler
2822847a12dSAxel Dörfler
2832847a12dSAxel DörflerBPoint
2842847a12dSAxel DörflerBPopUpMenu::ScreenLocation()
2852847a12dSAxel Dörfler{
286bb169747SStefano Ceccherini	// This case is when the BPopUpMenu is standalone
2872847a12dSAxel Dörfler	if (fUseWhere)
2882847a12dSAxel Dörfler		return fWhere;
2896d27f962SAxel Dörfler
290bb169747SStefano Ceccherini	// This case is when the BPopUpMenu is inside a BMenuField
29101b1b8bdSJohn Scipione	BMenuItem* superItem = Superitem();
29201b1b8bdSJohn Scipione	BMenu* superMenu = Supermenu();
29301b1b8bdSJohn Scipione	BMenuItem* selectedItem = FindItem(superItem->Label());
294797d1a66SStefano Ceccherini	BPoint point = superItem->Frame().LeftTop();
2952847a12dSAxel Dörfler
296797d1a66SStefano Ceccherini	superMenu->ConvertToScreen(&point);
2972847a12dSAxel Dörfler
2983bf528b5SJessica Hamilton	if (selectedItem != NULL) {
2993bf528b5SJessica Hamilton		while (selectedItem->Menu() != this
3003bf528b5SJessica Hamilton			&& selectedItem->Menu()->Superitem() != NULL) {
3013bf528b5SJessica Hamilton			selectedItem = selectedItem->Menu()->Superitem();
3023bf528b5SJessica Hamilton		}
3032847a12dSAxel Dörfler		point.y -= selectedItem->Frame().top;
3043bf528b5SJessica Hamilton	}
3052847a12dSAxel Dörfler
3062847a12dSAxel Dörfler	return point;
3072847a12dSAxel Dörfler}
3082847a12dSAxel Dörfler
3092847a12dSAxel Dörfler
3106d27f962SAxel Dörfler//	#pragma mark - private methods
3112847a12dSAxel Dörfler
3122847a12dSAxel Dörfler
3132847a12dSAxel Dörflervoid BPopUpMenu::_ReservedPopUpMenu1() {}
3142847a12dSAxel Dörflervoid BPopUpMenu::_ReservedPopUpMenu2() {}
3152847a12dSAxel Dörflervoid BPopUpMenu::_ReservedPopUpMenu3() {}
3162847a12dSAxel Dörfler
3172847a12dSAxel Dörfler
31801b1b8bdSJohn ScipioneBPopUpMenu&
31901b1b8bdSJohn ScipioneBPopUpMenu::operator=(const BPopUpMenu& other)
3202847a12dSAxel Dörfler{
3212847a12dSAxel Dörfler	return *this;
3222847a12dSAxel Dörfler}
3232847a12dSAxel Dörfler
3242847a12dSAxel Dörfler
32501b1b8bdSJohn ScipioneBMenuItem*
326cd1cef8aSStefano CeccheriniBPopUpMenu::_Go(BPoint where, bool autoInvoke, bool startOpened,
32701b1b8bdSJohn Scipione	BRect* _specialRect, bool async)
3282847a12dSAxel Dörfler{
329633645bcSRene Gollent	if (fTrackThread >= B_OK) {
330633645bcSRene Gollent		// we already have an active menu, wait for it to go away before
331633645bcSRene Gollent		// spawning another
332633645bcSRene Gollent		status_t unused;
333633645bcSRene Gollent		while (wait_for_thread(fTrackThread, &unused) == B_INTERRUPTED)
334633645bcSRene Gollent			;
335633645bcSRene Gollent	}
33601b1b8bdSJohn Scipione
33701b1b8bdSJohn Scipione	popup_menu_data* data = new (std::nothrow) popup_menu_data;
33801b1b8bdSJohn Scipione	if (data == NULL)
339277a78abSStefano Ceccherini		return NULL;
3406d27f962SAxel Dörfler
3414b44b026SStefano Ceccherini	sem_id sem = create_sem(0, "window close lock");
342277a78abSStefano Ceccherini	if (sem < B_OK) {
343277a78abSStefano Ceccherini		delete data;
34499939029SKarsten Heimrich		return NULL;
345277a78abSStefano Ceccherini	}
3466d27f962SAxel Dörfler
347277a78abSStefano Ceccherini	// Get a pointer to the window from which Go() was called
34801b1b8bdSJohn Scipione	BWindow* window
34901b1b8bdSJohn Scipione		= dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
3509deb82dfSStefano Ceccherini	data->window = window;
3519deb82dfSStefano Ceccherini
35226b54010SStefano Ceccherini	// Asynchronous menu: we set the BWindow menu's semaphore
35326b54010SStefano Ceccherini	// and let BWindow block when needed
35401b1b8bdSJohn Scipione	if (async && window != NULL)
3554b44b026SStefano Ceccherini		_set_menu_sem_(window, sem);
3566d27f962SAxel Dörfler
3574b44b026SStefano Ceccherini	data->object = this;
35814260ebbSStefano Ceccherini	data->autoInvoke = autoInvoke;
35914260ebbSStefano Ceccherini	data->useRect = _specialRect != NULL;
3604b44b026SStefano Ceccherini	if (_specialRect != NULL)
3614b44b026SStefano Ceccherini		data->rect = *_specialRect;
3624b44b026SStefano Ceccherini	data->async = async;
3634b44b026SStefano Ceccherini	data->where = where;
36414260ebbSStefano Ceccherini	data->startOpened = startOpened;
365277a78abSStefano Ceccherini	data->selected = NULL;
3664b44b026SStefano Ceccherini	data->lock = sem;
3676d27f962SAxel Dörfler
3684b44b026SStefano Ceccherini	// Spawn the tracking thread
36901b1b8bdSJohn Scipione	fTrackThread = spawn_thread(_thread_entry, "popup", B_DISPLAY_PRIORITY,
37001b1b8bdSJohn Scipione		data);
371946d88f9SAxel Dörfler	if (fTrackThread < B_OK) {
3724b44b026SStefano Ceccherini		// Something went wrong. Cleanup and return NULL
3734b44b026SStefano Ceccherini		delete_sem(sem);
3746d27f962SAxel Dörfler		if (async && window != NULL)
3759deb82dfSStefano Ceccherini			_set_menu_sem_(window, B_BAD_SEM_ID);
3764b44b026SStefano Ceccherini		delete data;
3774b44b026SStefano Ceccherini		return NULL;
3784b44b026SStefano Ceccherini	}
37926b54010SStefano Ceccherini
380946d88f9SAxel Dörfler	resume_thread(fTrackThread);
381946d88f9SAxel Dörfler
382cd1cef8aSStefano Ceccherini	if (!async)
383cd1cef8aSStefano Ceccherini		return _WaitMenu(data);
3846d27f962SAxel Dörfler
385cd1cef8aSStefano Ceccherini	return 0;
3862847a12dSAxel Dörfler}
3872847a12dSAxel Dörfler
3882847a12dSAxel Dörfler
389cd1cef8aSStefano Ceccherini/* static */
3902847a12dSAxel Dörflerint32
39101b1b8bdSJohn ScipioneBPopUpMenu::_thread_entry(void* menuData)
3922847a12dSAxel Dörfler{
39301b1b8bdSJohn Scipione	popup_menu_data* data = static_cast<popup_menu_data*>(menuData);
39401b1b8bdSJohn Scipione	BPopUpMenu* menu = data->object;
39501b1b8bdSJohn Scipione	BRect* rect = NULL;
39699939029SKarsten Heimrich
39714260ebbSStefano Ceccherini	if (data->useRect)
3984b44b026SStefano Ceccherini		rect = &data->rect;
3996d27f962SAxel Dörfler
40001b1b8bdSJohn Scipione	data->selected = menu->_StartTrack(data->where, data->autoInvoke,
40101b1b8bdSJohn Scipione		data->startOpened, rect);
4026d27f962SAxel Dörfler
40399939029SKarsten Heimrich	// Reset the window menu semaphore
4049deb82dfSStefano Ceccherini	if (data->async && data->window)
4059deb82dfSStefano Ceccherini		_set_menu_sem_(data->window, B_BAD_SEM_ID);
4066d27f962SAxel Dörfler
407cb8bdc4eSStefano Ceccherini	delete_sem(data->lock);
4086d27f962SAxel Dörfler
40999939029SKarsten Heimrich	// Commit suicide if needed
41099939029SKarsten Heimrich	if (data->async && menu->fAutoDestruct) {
411fc82227aSStefano Ceccherini		menu->fTrackThread = -1;
412fc82227aSStefano Ceccherini		delete menu;
413fc82227aSStefano Ceccherini	}
4146d27f962SAxel Dörfler
4154b44b026SStefano Ceccherini	if (data->async)
4164b44b026SStefano Ceccherini		delete data;
4176d27f962SAxel Dörfler
4184b44b026SStefano Ceccherini	return 0;
4192847a12dSAxel Dörfler}
4202847a12dSAxel Dörfler
4212847a12dSAxel Dörfler
42201b1b8bdSJohn ScipioneBMenuItem*
42301b1b8bdSJohn ScipioneBPopUpMenu::_StartTrack(BPoint where, bool autoInvoke, bool startOpened,
42401b1b8bdSJohn Scipione	BRect* _specialRect)
4252847a12dSAxel Dörfler{
42627ec1ee4SStefano Ceccherini	// I know, this doesn't look senseful, but don't be fooled,
42727ec1ee4SStefano Ceccherini	// fUseWhere is used in ScreenLocation(), which is a virtual
42827ec1ee4SStefano Ceccherini	// called by BMenu::Track()
429bb169747SStefano Ceccherini	fWhere = where;
43027ec1ee4SStefano Ceccherini	fUseWhere = true;
4316d27f962SAxel Dörfler
43201b1b8bdSJohn Scipione	// Determine when mouse-down-up will be taken as a 'press',
43301b1b8bdSJohn Scipione	// rather than a 'click'
434f71910c0SRyan Leavengood	bigtime_t clickMaxTime = 0;
435f71910c0SRyan Leavengood	get_click_speed(&clickMaxTime);
436f71910c0SRyan Leavengood	clickMaxTime += system_time();
43701b1b8bdSJohn Scipione
4384b44b026SStefano Ceccherini	// Show the menu's window
4394b44b026SStefano Ceccherini	Show();
440cd9af8e7SRene Gollent	snooze(50000);
44101b1b8bdSJohn Scipione	BMenuItem* result = Track(startOpened, _specialRect);
442f71910c0SRyan Leavengood
443f71910c0SRyan Leavengood	// If it was a click, keep the menu open and tracking
44401b1b8bdSJohn Scipione	if (system_time() <= clickMaxTime)
445f71910c0SRyan Leavengood		result = Track(true, _specialRect);
4464b44b026SStefano Ceccherini	if (result != NULL && autoInvoke)
4474b44b026SStefano Ceccherini		result->Invoke();
4486d27f962SAxel Dörfler
4494b44b026SStefano Ceccherini	fUseWhere = false;
4506d27f962SAxel Dörfler
4514b44b026SStefano Ceccherini	Hide();
4529deb82dfSStefano Ceccherini	be_app->ShowCursor();
4539deb82dfSStefano Ceccherini
4544b44b026SStefano Ceccherini	return result;
4552847a12dSAxel Dörfler}
4562847a12dSAxel Dörfler
457cd1cef8aSStefano Ceccherini
45801b1b8bdSJohn ScipioneBMenuItem*
45901b1b8bdSJohn ScipioneBPopUpMenu::_WaitMenu(void* _data)
460cd1cef8aSStefano Ceccherini{
461ecc07039SJohn Scipione	popup_menu_data* data = static_cast<popup_menu_data*>(_data);
46201b1b8bdSJohn Scipione	BWindow* window = data->window;
463cd1cef8aSStefano Ceccherini	sem_id sem = data->lock;
464cd1cef8aSStefano Ceccherini	if (window != NULL) {
465cd1cef8aSStefano Ceccherini		while (acquire_sem_etc(sem, 1, B_TIMEOUT, 50000) != B_BAD_SEM_ID)
466cd1cef8aSStefano Ceccherini			window->UpdateIfNeeded();
467cd1cef8aSStefano Ceccherini	}
468cd1cef8aSStefano Ceccherini
469cd1cef8aSStefano Ceccherini 	status_t unused;
470cd1cef8aSStefano Ceccherini	while (wait_for_thread(fTrackThread, &unused) == B_INTERRUPTED)
471cd1cef8aSStefano Ceccherini		;
47299939029SKarsten Heimrich
473cd1cef8aSStefano Ceccherini	fTrackThread = -1;
47499939029SKarsten Heimrich
47501b1b8bdSJohn Scipione	BMenuItem* selected = data->selected;
476cd1cef8aSStefano Ceccherini		// data->selected is filled by the tracking thread
47799939029SKarsten Heimrich
478cd1cef8aSStefano Ceccherini	delete data;
47999939029SKarsten Heimrich
480cd1cef8aSStefano Ceccherini	return selected;
481cd1cef8aSStefano Ceccherini}
482