Deskbar: Make Vulcan Death Grip work in mini-mode

Refactor so that ExpandoMenuBar and TeamMenu both call the menu item
TeamMenuItem::HandleMouseDown() method to do the actual work and then
send a message to cleanup.

Fixes #17761

Change-Id: I0e13e5fc6c90236936120ff0dda1246123576d37
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6311
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
John Scipione 2023-04-08 01:26:39 -04:00 committed by waddlesplash
parent 6347519ab1
commit 4f97a431b9
6 changed files with 197 additions and 75 deletions

View File

@ -71,9 +71,6 @@ All rights reserved.
#include "WindowMenuItem.h"
const uint32 kMinimizeTeam = 'mntm';
const uint32 kBringTeamToFront = 'bftm';
bool TExpandoMenuBar::sDoMonitor = false;
thread_id TExpandoMenuBar::sMonThread = B_ERROR;
BLocker TExpandoMenuBar::sMonLocker("expando monitor");
@ -222,8 +219,7 @@ TExpandoMenuBar::MessageReceived(BMessage* message)
break;
TShowHideMenuItem::TeamShowHideCommon(B_MINIMIZE_WINDOW,
item->Teams(),
item->Menu()->ConvertToScreen(item->Frame()),
item->Teams(), item->Menu()->ConvertToScreen(item->Frame()),
true);
break;
}
@ -251,80 +247,57 @@ TExpandoMenuBar::MessageReceived(BMessage* message)
void
TExpandoMenuBar::MouseDown(BPoint where)
{
BMessage* message = Window()->CurrentMessage();
BMenuItem* menuItem;
TTeamMenuItem* item = TeamItemAtPoint(where, &menuItem);
fLastClickedItem = item;
if (fBarView == NULL || fBarView->Dragging())
return BMenuBar::MouseDown(where);
if (message == NULL || item == NULL || fBarView == NULL
|| fBarView->Dragging()) {
BMenuBar::MouseDown(where);
return;
}
BMessage* message = Window()->CurrentMessage();
BMenuItem* item = ItemAtPoint(where);
fLastClickedItem = item;
if (message == NULL || item == NULL)
return BMenuBar::MouseDown(where);
int32 modifiers = 0;
int32 buttons = 0;
message->FindInt32("modifiers", &modifiers);
message->FindInt32("buttons", &buttons);
// check for three finger salute, a.k.a. Vulcan Death Grip
if ((modifiers & B_COMMAND_KEY) != 0
&& (modifiers & B_CONTROL_KEY) != 0
&& (modifiers & B_SHIFT_KEY) != 0) {
const BList* teams = item->Teams();
int32 teamCount = teams->CountItems();
team_id teamID;
for (int32 team = 0; team < teamCount; team++) {
teamID = (addr_t)teams->ItemAt(team);
kill_team(teamID);
RemoveTeam(teamID, false);
// remove the team from display immediately
}
return;
// absorb the message
} else if (item != NULL
&& (modifiers & B_SHIFT_KEY) == 0
// close window item
if ((modifiers & B_SHIFT_KEY) != 0
&& (buttons & B_TERTIARY_MOUSE_BUTTON) != 0) {
be_roster->Launch(item->Signature());
return;
// absorb the message
} else {
TWindowMenuItem* wndItem = dynamic_cast<TWindowMenuItem*>(menuItem);
if (wndItem != NULL
&& (modifiers & B_SHIFT_KEY) != 0
&& (buttons & B_TERTIARY_MOUSE_BUTTON) != 0) {
// close window
client_window_info* info;
BMessenger wnd;
info = get_window_info(wndItem->ID());
if (info == NULL) return;
BMessenger::Private(wnd).SetTo(
info->team, info->client_port, info->client_token);
free(info); info = NULL;
wnd.SendMessage(B_QUIT_REQUESTED);
return;
// absorb the message
TWindowMenuItem* wItem = dynamic_cast<TWindowMenuItem*>(item);
if (wItem != NULL) {
// we have a window item
BMessenger messenger;
client_window_info* info = get_window_info(wItem->ID());
if (info != NULL) {
BMessenger::Private(messenger).SetTo(info->team,
info->client_port, info->client_token);
messenger.SendMessage(B_QUIT_REQUESTED);
free(info);
return;
// absorb the message
}
}
}
// control click - show all/hide all shortcut
if ((modifiers & B_CONTROL_KEY) != 0) {
// show/hide item's teams
BMessage showMessage((modifiers & B_SHIFT_KEY) != 0
? kMinimizeTeam : kBringTeamToFront);
showMessage.AddInt32("itemIndex", IndexOf(item));
Window()->PostMessage(&showMessage, this);
// below depends on item being a team item
TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(item);
if (teamItem == NULL)
return BMenuBar::MouseDown(where);
// check for three finger salute, a.k.a. Vulcan Death Grip
if (teamItem->HandleMouseDown(where))
return;
// absorb the message
}
// check if within expander bounds to expand window items
if (Vertical() && static_cast<TBarApp*>(be_app)->Settings()->superExpando
&& item->ExpanderBounds().Contains(where)) {
&& teamItem->ExpanderBounds().Contains(where)) {
// start the animation here, finish on mouse up
item->SetArrowDirection(BControlLook::B_RIGHT_DOWN_ARROW);
teamItem->SetArrowDirection(BControlLook::B_RIGHT_DOWN_ARROW);
SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
Invalidate(item->ExpanderBounds());
Invalidate(teamItem->ExpanderBounds());
return;
// absorb the message
}
@ -335,9 +308,8 @@ TExpandoMenuBar::MouseDown(BPoint where)
get_click_speed(&clickSpeed);
bigtime_t delta = system_time() - fLastClickTime;
if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1
&& item == menuItem && item == fLastClickedItem
&& delta <= clickSpeed) {
be_roster->ActivateApp((addr_t)item->Teams()->ItemAt(0));
&& item == fLastClickedItem && delta <= clickSpeed) {
be_roster->ActivateApp((addr_t)teamItem->Teams()->ItemAt(0));
// activate this team
return;
// absorb the message
@ -489,15 +461,18 @@ TExpandoMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message)
void
TExpandoMenuBar::MouseUp(BPoint where)
{
TTeamMenuItem* lastItem = dynamic_cast<TTeamMenuItem*>(fLastClickedItem);
fLastClickedItem = NULL;
if (fBarView != NULL && fBarView->Dragging()) {
_FinishedDrag(true);
return;
// absorb the message
}
if (fLastClickedItem == NULL)
return BMenuBar::MouseUp(where);
TTeamMenuItem* lastItem = dynamic_cast<TTeamMenuItem*>(fLastClickedItem);
fLastClickedItem = NULL;
if (Vertical() && static_cast<TBarApp*>(be_app)->Settings()->superExpando
&& lastItem != NULL && lastItem->ExpanderBounds().Contains(where)) {
lastItem->ToggleExpandState(true);
@ -507,6 +482,7 @@ TExpandoMenuBar::MouseUp(BPoint where)
Invalidate(lastItem->ExpanderBounds());
}
BMenuBar::MouseUp(where);
}
@ -626,6 +602,21 @@ TExpandoMenuBar::InDeskbarMenu(BPoint loc) const
}
BMenuItem*
TExpandoMenuBar::ItemAtPoint(BPoint point)
{
int32 itemCount = CountItems();
for (int32 index = 0; index < itemCount; index++) {
BMenuItem* item = ItemAt(index);
if (item != NULL && item->Frame().Contains(point))
return item;
}
// no item found
return NULL;
}
/*! Returns the team menu item that belongs to the item under the
specified \a point.
If \a _item is given, it will return the exact menu item under
@ -637,13 +628,12 @@ TExpandoMenuBar::TeamItemAtPoint(BPoint point, BMenuItem** _item)
TTeamMenuItem* lastApp = NULL;
int32 itemCount = CountItems();
for (int32 i = 0; i < itemCount; i++) {
BMenuItem* item = ItemAt(i);
for (int32 index = 0; index < itemCount; index++) {
BMenuItem* item = ItemAt(index);
if (item != NULL && item->Frame().Contains(point)) {
if (dynamic_cast<TTeamMenuItem*>(item) != NULL)
lastApp = (TTeamMenuItem*)item;
if (dynamic_cast<TTeamMenuItem*>(item) != NULL)
lastApp = (TTeamMenuItem*)item;
if (item && item->Frame().Contains(point)) {
if (_item != NULL)
*_item = item;

View File

@ -83,6 +83,7 @@ public:
void BuildItems();
BMenuItem* ItemAtPoint(BPoint point);
TTeamMenuItem* TeamItemAtPoint(BPoint location,
BMenuItem** _item = NULL);
bool InDeskbarMenu(BPoint) const;

View File

@ -191,3 +191,64 @@ TTeamMenu::DetachedFromWindow()
BMessenger self(this);
TBarApp::Unsubscribe(self);
}
void
TTeamMenu::MessageReceived(BMessage* message)
{
TTeamMenuItem* item = NULL;
switch (message->what) {
case B_SOME_APP_QUIT:
case kRemoveTeam:
{
int32 itemIndex = -1;
message->FindInt32("itemIndex", &itemIndex);
team_id team = -1;
message->FindInt32("team", &team);
item = dynamic_cast<TTeamMenuItem*>(ItemAt(itemIndex));
if (item != NULL && item->Teams()->HasItem((void*)(addr_t)team)) {
item->Teams()->RemoveItem(team);
RemoveItem(itemIndex);
delete item;
}
break;
}
default:
BMenu::MessageReceived(message);
break;
}
}
void
TTeamMenu::MouseDown(BPoint where)
{
if (fBarView == NULL || fBarView->Dragging())
return BMenu::MouseDown(where);
BMenuItem* item = ItemAtPoint(where);
if (item == NULL)
return BMenu::MouseDown(where);
TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(item);
if (teamItem == NULL || !teamItem->HandleMouseDown(where))
BMenu::MouseDown(where);
}
BMenuItem*
TTeamMenu::ItemAtPoint(BPoint point)
{
int32 itemCount = CountItems();
for (int32 index = 0; index < itemCount; index++) {
BMenuItem* item = ItemAt(index);
if (item != NULL && item->Frame().Contains(point))
return item;
}
// no item found
return NULL;
}

View File

@ -50,8 +50,12 @@ class TTeamMenu : public BMenu {
public:
TTeamMenu(TBarView* barView = NULL);
void AttachedToWindow();
void DetachedFromWindow();
virtual void AttachedToWindow();
virtual void DetachedFromWindow();
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint where);
BMenuItem* ItemAtPoint(BPoint point);
static int CompareByName(const void* first,
const void* second);

View File

@ -50,6 +50,7 @@ All rights reserved.
#include <Region.h>
#include <Roster.h>
#include <Resources.h>
#include <Window.h>
#include "BarApp.h"
#include "BarMenuBar.h"
@ -94,6 +95,67 @@ TTeamMenuItem::~TTeamMenuItem()
}
/*! Vulcan Death Grip and other team mouse button handling
\returns true if handled, false otherwise
*/
bool
TTeamMenuItem::HandleMouseDown(BPoint where)
{
BMenu* menu = Menu();
if (menu == NULL)
return false;
BWindow* window = menu->Window();
if (window == NULL)
return false;
BMessage* message = window->CurrentMessage();
if (message == NULL)
return false;
int32 modifiers = 0;
int32 buttons = 0;
message->FindInt32("modifiers", &modifiers);
message->FindInt32("buttons", &buttons);
// check for three finger salute, a.k.a. Vulcan Death Grip
if ((modifiers & B_COMMAND_KEY) != 0
&& (modifiers & B_CONTROL_KEY) != 0
&& (modifiers & B_SHIFT_KEY) != 0) {
BMessage appMessage(B_SOME_APP_QUIT);
int32 teamCount = fTeam->CountItems();
BMessage quitMessage(teamCount == 1 ? B_SOME_APP_QUIT : kRemoveTeam);
quitMessage.AddInt32("itemIndex", menu->IndexOf(this));
for (int32 index = 0; index < teamCount; index++) {
team_id team = (addr_t)fTeam->ItemAt(index);
appMessage.AddInt32("be:team", team);
quitMessage.AddInt32("team", team);
kill_team(team);
}
be_app->PostMessage(&appMessage);
TExpandoMenuBar* expando = dynamic_cast<TExpandoMenuBar*>(menu);
window->PostMessage(&quitMessage, expando != NULL ? expando : menu);
return true;
} else if ((modifiers & B_SHIFT_KEY) == 0
&& (buttons & B_TERTIARY_MOUSE_BUTTON) != 0) {
// launch new team
be_roster->Launch(Signature());
return true;
} else if ((modifiers & B_CONTROL_KEY) != 0) {
// control click - show all/hide all shortcut
BMessage showMessage((modifiers & B_SHIFT_KEY) != 0
? kMinimizeTeam : kBringTeamToFront);
showMessage.AddInt32("itemIndex", menu->IndexOf(this));
window->PostMessage(&showMessage, menu);
return true;
}
return false;
}
status_t
TTeamMenuItem::Invoke(BMessage* message)
{

View File

@ -46,6 +46,9 @@ All rights reserved.
const float kSwitchWidth = 12.0f;
const uint32 kMinimizeTeam = 'mntm';
const uint32 kBringTeamToFront = 'bftm';
class BBitmap;
class TBarView;
@ -60,6 +63,7 @@ public:
float height = -1.0f);
virtual ~TTeamMenuItem();
bool HandleMouseDown(BPoint where);
status_t Invoke(BMessage* message = NULL);
void SetOverrideWidth(float width)