* Early work in progress of toying around with the idea to show some useful

panels when touching the screen border with the mouse while holding down the
  CTRL key.
* Right now, a simple running applications list is shown on the top/bottom, and
  a list of the windows of the current app on the left/right edge which you can
  click to front.
* Imagine you could configure this to show various panels like a shelf, a
  query window, workspaces, recent files, favourite files, folder contents,
  have a clipboard for files, ...
* Just wanted to have it in SVN even if it's only barely useful right now - I
  would be glad to hear your opinions on this, and if it's worthwhile to
  continue working on this.
-alpha


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41754 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2011-05-25 23:19:15 +00:00
parent 2cc7e38c93
commit dc3bd077cd
17 changed files with 1972 additions and 0 deletions
+1
View File
@@ -55,6 +55,7 @@ HaikuSubInclude showimage ;
HaikuSubInclude soundrecorder ;
HaikuSubInclude stylededit ;
HaikuSubInclude sudoku ;
HaikuSubInclude switcher ;
HaikuSubInclude terminal ;
HaikuSubInclude text_search ;
HaikuSubInclude tracker ;
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "ApplicationsView.h"
#include "LaunchButton.h"
#include "Switcher.h"
static const uint32 kMsgActivateApp = 'AcAp';
ApplicationsView::ApplicationsView(uint32 location)
:
BGroupView((location & (kTopEdge | kBottomEdge)) != 0
? B_HORIZONTAL : B_VERTICAL)
{
}
ApplicationsView::~ApplicationsView()
{
}
void
ApplicationsView::AttachedToWindow()
{
// TODO: make this dynamic!
BList teamList;
be_roster->GetAppList(&teamList);
for (int32 i = 0; i < teamList.CountItems(); i++) {
app_info appInfo;
team_id team = (team_id)teamList.ItemAt(i);
if (be_roster->GetRunningAppInfo(team, &appInfo) == B_OK)
_AddTeam(appInfo);
}
}
void
ApplicationsView::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgActivateApp:
be_roster->ActivateApp(message->FindInt32("team"));
break;
default:
BGroupView::MessageReceived(message);
break;
}
}
void
ApplicationsView::_AddTeam(app_info& info)
{
if ((info.flags & B_BACKGROUND_APP) != 0)
return;
BMessage* message = new BMessage(kMsgActivateApp);
message->AddInt32("team", info.team);
LaunchButton* button = new LaunchButton(info.signature, NULL, message,
this);
button->SetTo(&info.ref);
AddChild(button);
}
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef APPLICATIONS_VIEW_H
#define APPLICATIONS_VIEW_H
#include <GroupView.h>
#include <Roster.h>
class ApplicationsView : public BGroupView {
public:
ApplicationsView(uint32 location);
virtual ~ApplicationsView();
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
private:
void _AddTeam(app_info& info);
};
#endif // APPLICATIONS_VIEW_H
+226
View File
@@ -0,0 +1,226 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "CaptureWindow.h"
#include <stdio.h>
#include <Roster.h>
#include <Screen.h>
#include "Switcher.h"
static const bigtime_t kUpdateDelay = 50000;
// 50 ms
class CaptureView : public BView {
public:
CaptureView();
virtual ~CaptureView();
void AddMoveOutNotification(BMessage* message);
virtual void MouseMoved(BPoint point, uint32 transit,
const BMessage* dragMessage);
virtual void KeyDown(const char* bytes, int32 numBytes);
private:
void _UpdateLast(const BPoint& point);
void _Notify(uint32 location, team_id team);
void _SendMovedOutNotification();
static team_id _CurrentTeam();
private:
uint32 fModifierMask;
BPoint fLastPoint;
team_id fLastTeam;
bigtime_t fLastEvent;
uint32 fMovedOutWhat;
BMessenger fMovedOutMessenger;
BRect fMovedOutFrame;
};
CaptureView::CaptureView()
:
BView("main", 0),
fModifierMask(B_CONTROL_KEY),
fMovedOutWhat(0)
{
SetEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS, B_NO_POINTER_HISTORY);
_UpdateLast(BPoint(-1, -1));
}
CaptureView::~CaptureView()
{
}
void
CaptureView::AddMoveOutNotification(BMessage* message)
{
if (fMovedOutWhat != 0)
_SendMovedOutNotification();
if (message->FindMessenger("target", &fMovedOutMessenger) == B_OK
&& message->FindRect("frame", &fMovedOutFrame) == B_OK)
fMovedOutWhat = (uint32)message->FindInt32("what");
}
void
CaptureView::MouseMoved(BPoint point, uint32 transit,
const BMessage* dragMessage)
{
ConvertToScreen(&point);
if (fMovedOutWhat != 0 && !fMovedOutFrame.Contains(point))
_SendMovedOutNotification();
uint32 modifiers = ::modifiers();
if ((modifiers & fModifierMask) == 0) {
_UpdateLast(point);
return;
}
// TODO: we will need to iterate over all existing screens to find the
// right one!
BScreen screen;
BRect screenFrame = screen.Frame();
uint32 location = kNowhere;
if (point.x <= screenFrame.left && fLastPoint.x > screenFrame.left)
location = kLeftEdge;
else if (point.x >= screenFrame.right && fLastPoint.x < screenFrame.right)
location = kRightEdge;
else if (point.y <= screenFrame.top && fLastPoint.y > screenFrame.top)
location = kTopEdge;
else if (point.y >= screenFrame.bottom && fLastPoint.y < screenFrame.bottom)
location = kBottomEdge;
if (location != kNowhere)
_Notify(location, fLastTeam);
_UpdateLast(point);
}
void
CaptureView::KeyDown(const char* bytes, int32 numBytes)
{
if ((::modifiers() & (B_CONTROL_KEY | B_SHIFT_KEY | B_OPTION_KEY
| B_COMMAND_KEY)) != (B_COMMAND_KEY | B_CONTROL_KEY))
return;
uint32 location = kNowhere;
switch (bytes[0]) {
case '1':
location = kLeftEdge;
break;
case '2':
location = kRightEdge;
break;
case '3':
location = kTopEdge;
break;
case '4':
location = kBottomEdge;
break;
}
if (location != kNowhere)
_Notify(location, _CurrentTeam());
}
void
CaptureView::_UpdateLast(const BPoint& point)
{
fLastPoint = point;
bigtime_t now = system_time();
// We update the currently active application only, if the mouse did
// not move over it for a certain time - this is necessary only for
// focus follow mouse.
if (now > fLastEvent + kUpdateDelay)
fLastTeam = _CurrentTeam();
fLastEvent = now;
}
void
CaptureView::_Notify(uint32 location, team_id team)
{
if (location == kNowhere)
return;
BMessage message(kMsgLocationTrigger);
message.AddInt32("location", location);
message.AddInt32("team", team);
be_app->PostMessage(&message);
}
void
CaptureView::_SendMovedOutNotification()
{
BMessage movedOut(fMovedOutWhat);
fMovedOutMessenger.SendMessage(&movedOut);
fMovedOutWhat = 0;
}
/*static*/ team_id
CaptureView::_CurrentTeam()
{
app_info appInfo;
status_t status = be_roster->GetActiveAppInfo(&appInfo);
if (status == B_OK)
return appInfo.team;
return status;
}
// #pragma mark -
CaptureWindow::CaptureWindow()
:
BWindow(BRect(0, 0, 100, 100), "mouse capture", B_NO_BORDER_WINDOW_LOOK,
B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS, B_ALL_WORKSPACES)
{
fCaptureView = new CaptureView();
AddChild(fCaptureView);
}
CaptureWindow::~CaptureWindow()
{
}
void
CaptureWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgHideWhenMouseMovedOut:
fCaptureView->AddMoveOutNotification(message);
break;
default:
BWindow::MessageReceived(message);
break;
}
}
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef CAPTURE_WINDOW_H
#define CAPTURE_WINDOW_H
#include <Window.h>
class CaptureView;
class CaptureWindow : public BWindow {
public:
CaptureWindow();
virtual ~CaptureWindow();
virtual void MessageReceived(BMessage* message);
private:
CaptureView* fCaptureView;
};
#endif // CAPTURE_WINDOW_H
+245
View File
@@ -0,0 +1,245 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "GroupListView.h"
#include <map>
#include <Window.h>
class RendererLayoutItem : public BAbstractLayout {
public:
RendererLayoutItem(BView* owner, int32 index, void* item,
ListItemRenderer*& renderer)
:
fOwner(owner),
fIndex(index),
fItem(item),
fRenderer(renderer)
{
}
ListItemRenderer* Renderer() const
{
fRenderer->SetTo(fOwner, fItem);
return fRenderer;
}
int32 Index() const
{
return fIndex;
}
void* Item() const
{
return fItem;
}
virtual BSize BaseMinSize()
{
fRenderer->SetTo(fOwner, fItem);
return fRenderer->MinSize();
}
virtual BSize BasePreferredSize()
{
fRenderer->SetTo(fOwner, fItem);
return fRenderer->PreferredSize();
}
protected:
virtual void DerivedLayoutItems()
{
// shouldn't ever be called?
}
private:
BView* fOwner;
int32 fIndex;
void* fItem;
ListItemRenderer*& fRenderer;
};
GroupListView::GroupListView(const char* name, GroupListModel* model,
enum orientation orientation, float spacing)
:
BView(NULL, B_WILL_DRAW, new BGroupLayout(orientation, spacing)),
fModel(NULL),
fItemRenderer(NULL),
fGroupRenderer(NULL),
fSelectionMessage(NULL)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
SetModel(model);
}
GroupListView::~GroupListView()
{
delete fModel;
delete fItemRenderer;
delete fGroupRenderer;
delete fSelectionMessage;
}
void
GroupListView::SetModel(GroupListModel* model)
{
// TODO: remove all previous
// TODO: add change mechanism
// TODO: use a "virtual" BGroupLayout (ie. one that create its layout items
// on the fly).
fModel = model;
std::map<addr_t, BGroupLayout*> groupMap;
int32 groupCount = model->CountGroups();
for (int groupIndex = 0; groupIndex < groupCount; groupIndex++) {
BGroupLayout* groupItem = new BGroupLayout(B_VERTICAL, 0);
groupItem->SetVisible(false);
AddChild(groupItem);
void* group = model->GroupAt(groupIndex);
groupMap[(addr_t)group] = groupItem;
groupItem->AddItem(new RendererLayoutItem(this, groupIndex, group,
fGroupRenderer));
}
int32 itemCount = model->CountItems();
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++) {
void* group = model->GroupForItemAt(itemIndex);
if (group == NULL)
continue;
BGroupLayout* groupItem = groupMap[(addr_t)group];
if (groupItem == NULL)
continue;
groupItem->SetVisible(true);
RendererLayoutItem* rendererItem = new RendererLayoutItem(this,
itemIndex, model->ItemAt(itemIndex), fItemRenderer);
groupItem->AddItem(rendererItem);
}
}
void
GroupListView::SetItemRenderer(ListItemRenderer* renderer)
{
fItemRenderer = renderer;
InvalidateLayout();
}
void
GroupListView::SetGroupRenderer(ListItemRenderer* renderer)
{
fGroupRenderer = renderer;
InvalidateLayout();
}
void
GroupListView::SetSelectionMessage(BMessage* message, BMessenger target)
{
fSelectionMessage = message;
fSelectionTarget = target;
}
void
GroupListView::AttachedToWindow()
{
}
void
GroupListView::MessageReceived(BMessage* message)
{
switch (message->what) {
default:
BView::MessageReceived(message);
break;
}
}
void
GroupListView::MouseDown(BPoint point)
{
if (fSelectionMessage == NULL)
return;
BLayoutItem* item = _ItemAt(GetLayout(), point);
if (RendererLayoutItem* rendererItem
= dynamic_cast<RendererLayoutItem*>(item)) {
BMessage message(*fSelectionMessage);
int32 buttons = 0;
if (Window()->CurrentMessage() != NULL)
buttons = Window()->CurrentMessage()->FindInt32("buttons");
if (buttons != 0)
message.AddInt32("buttons", buttons);
message.AddInt32("index", rendererItem->Index());
message.AddPointer(rendererItem->Renderer() == fGroupRenderer
? "group" : "item", rendererItem->Item());
fSelectionTarget.SendMessage(&message);
}
}
void
GroupListView::Draw(BRect updateRect)
{
_Draw(GetLayout(), updateRect);
}
void
GroupListView::_Draw(BLayoutItem* item, BRect updateRect)
{
if (RendererLayoutItem* rendererItem
= dynamic_cast<RendererLayoutItem*>(item)) {
ListItemRenderer* renderer = rendererItem->Renderer();
renderer->Draw(this, rendererItem->Frame(), rendererItem->Index(),
false);
} else if (BLayout* layout = dynamic_cast<BLayout*>(item)) {
for (int i = 0; i < layout->CountItems(); i++) {
item = layout->ItemAt(i);
if (!item->IsVisible() || !item->Frame().Intersects(updateRect))
continue;
_Draw(item, updateRect);
}
}
}
BLayoutItem*
GroupListView::_ItemAt(BLayoutItem* item, BPoint point)
{
if (RendererLayoutItem* rendererItem
= dynamic_cast<RendererLayoutItem*>(item))
return rendererItem;
if (BLayout* layout = dynamic_cast<BLayout*>(item)) {
for (int i = 0; i < layout->CountItems(); i++) {
item = layout->ItemAt(i);
if (!item->IsVisible() || !item->Frame().Contains(point))
continue;
return _ItemAt(item, point);
}
}
return item;
}
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef GROUP_LIST_VIEW_H
#define GROUP_LIST_VIEW_H
#include <GroupView.h>
#include <Roster.h>
class GroupListModel {
public:
virtual int32 CountItems() = 0;
virtual void* ItemAt(int32 index) = 0;
virtual int32 CountGroups() = 0;
virtual void* GroupAt(int32 index) = 0;
virtual void* GroupForItemAt(int32 index) = 0;
};
template<typename ItemType, typename GroupType>
class TypedGroupListModel : public GroupListModel {
public:
virtual ItemType* ItemAt(int32 index) = 0;
virtual GroupType* GroupAt(int32 index) = 0;
virtual GroupType* GroupForItemAt(int32 index) = 0;
};
class ListItemRenderer {
public:
virtual void SetTo(BView* owner, void* item) = 0;
virtual BSize MinSize() = 0;
virtual BSize MaxSize() = 0;
virtual BSize PreferredSize() = 0;
virtual void Draw(BView* owner, BRect frame, int32 index,
bool selected) = 0;
};
class GroupListView : public BView {
public:
GroupListView(const char* name,
GroupListModel* model = NULL,
enum orientation orientation = B_VERTICAL,
float spacing = 0);
virtual ~GroupListView();
GroupListModel* Model() const
{ return fModel; }
virtual void SetModel(GroupListModel* model);
ListItemRenderer* ItemRenderer() const
{ return fItemRenderer; }
virtual void SetItemRenderer(ListItemRenderer* renderer);
ListItemRenderer* GroupRenderer() const
{ return fGroupRenderer; }
virtual void SetGroupRenderer(ListItemRenderer* renderer);
BMessage* SelectionMessage() const
{ return fSelectionMessage; }
virtual void SetSelectionMessage(BMessage* message,
BMessenger target);
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint point);
virtual void Draw(BRect updateRect);
private:
void _Draw(BLayoutItem* item, BRect updateRect);
BLayoutItem* _ItemAt(BLayoutItem* item, BPoint point);
private:
GroupListModel* fModel;
ListItemRenderer* fItemRenderer;
ListItemRenderer* fGroupRenderer;
BMessage* fSelectionMessage;
BMessenger fSelectionTarget;
};
#endif // GROUP_LIST_VIEW_H
+16
View File
@@ -0,0 +1,16 @@
SubDir HAIKU_TOP src apps switcher ;
UsePrivateHeaders app interface shared ;
Application Switcher :
ApplicationsView.cpp
CaptureWindow.cpp
GroupListView.cpp
LaunchButton.cpp
PanelWindow.cpp
Switcher.cpp
WindowsView.cpp
: be translation $(TARGET_LIBSUPC++) $(HAIKU_LOCALE_LIBS) libshared.a
: Switcher.rdef
;
+397
View File
@@ -0,0 +1,397 @@
/*
* Copyright 2006-2009, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "LaunchButton.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <AppDefs.h>
#include <AppFileInfo.h>
#include <Application.h>
#include <Bitmap.h>
#include <Catalog.h>
#include <File.h>
#include <Node.h>
#include <NodeInfo.h>
#include <Region.h>
#include <Roster.h>
#include <Window.h>
#define DEFAULT_ICON_SIZE 64
#undef B_TRANSLATE_CONTEXT
#define B_TRANSLATE_CONTEXT "LaunchBox"
static const float kDragStartDist = 10.0;
static const float kDragBitmapAlphaScale = 0.6;
bigtime_t LaunchButton::sClickSpeed = 0;
bool LaunchButton::sIgnoreDoubleClick = true;
LaunchButton::LaunchButton(const char* name, const char* label,
BMessage* message, BHandler* target)
:
BIconButton(name, label, message, target),
fRef(NULL),
fAppSig(NULL),
fDescription(""),
fAnticipatingDrop(false),
fLastClickTime(0),
fIconSize(DEFAULT_ICON_SIZE)
{
if (sClickSpeed == 0 || get_click_speed(&sClickSpeed) != B_OK)
sClickSpeed = 500000;
}
LaunchButton::~LaunchButton()
{
delete fRef;
free(fAppSig);
}
void
LaunchButton::AttachedToWindow()
{
BIconButton::AttachedToWindow();
_UpdateToolTip();
}
void
LaunchButton::Draw(BRect updateRect)
{
if (fAnticipatingDrop) {
rgb_color color = fRef ? ui_color(B_KEYBOARD_NAVIGATION_COLOR)
: (rgb_color){ 0, 130, 60, 255 };
SetHighColor(color);
// limit clipping region to exclude the blue rect we just drew
BRect r(Bounds());
StrokeRect(r);
r.InsetBy(1.0, 1.0);
BRegion region(r);
ConstrainClippingRegion(&region);
}
if (IsValid()) {
BIconButton::Draw(updateRect);
} else {
rgb_color background = LowColor();
rgb_color lightShadow = tint_color(background,
(B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
rgb_color shadow = tint_color(background, B_DARKEN_1_TINT);
rgb_color light = tint_color(background, B_LIGHTEN_1_TINT);
BRect r(Bounds());
_DrawFrame(r, shadow, light, lightShadow, lightShadow);
r.InsetBy(2.0, 2.0);
SetHighColor(lightShadow);
FillRect(r);
}
}
void
LaunchButton::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_SIMPLE_DATA:
case B_REFS_RECEIVED: {
entry_ref ref;
if (message->FindRef("refs", &ref) == B_OK) {
if (fRef) {
if (ref != *fRef) {
BEntry entry(fRef, true);
if (entry.IsDirectory()) {
message->PrintToStream();
// copy stuff into the directory
} else {
message->what = B_REFS_RECEIVED;
team_id team;
if (fAppSig)
team = be_roster->TeamFor(fAppSig);
else
team = be_roster->TeamFor(fRef);
if (team < 0) {
if (fAppSig)
be_roster->Launch(fAppSig, message, &team);
else
be_roster->Launch(fRef, message, &team);
} else {
app_info appInfo;
if (team >= 0
&& be_roster->GetRunningAppInfo(team,
&appInfo) == B_OK) {
BMessenger messenger(appInfo.signature,
team);
if (messenger.IsValid())
messenger.SendMessage(message);
}
}
}
}
} else {
SetTo(&ref);
}
}
break;
}
case B_PASTE:
case B_MODIFIERS_CHANGED:
default:
BIconButton::MessageReceived(message);
break;
}
}
void
LaunchButton::MouseDown(BPoint where)
{
bigtime_t now = system_time();
bool callInherited = true;
if (sIgnoreDoubleClick && now - fLastClickTime < sClickSpeed)
callInherited = false;
fLastClickTime = now;
if (BMessage* message = Window()->CurrentMessage()) {
uint32 buttons;
message->FindInt32("buttons", (int32*)&buttons);
if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0 && IsInside()) {
// context menu?
} else
fDragStart = where;
}
if (callInherited)
BIconButton::MouseDown(where);
}
void
LaunchButton::MouseUp(BPoint where)
{
if (fAnticipatingDrop) {
fAnticipatingDrop = false;
Invalidate();
}
BIconButton::MouseUp(where);
}
void
LaunchButton::MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage)
{
if ((dragMessage && (transit == B_ENTERED_VIEW || transit == B_INSIDE_VIEW))
&& ((dragMessage->what == B_SIMPLE_DATA
|| dragMessage->what == B_REFS_RECEIVED) || fRef)) {
if (!fAnticipatingDrop) {
fAnticipatingDrop = true;
Invalidate();
}
}
if (!dragMessage || (transit == B_EXITED_VIEW || transit == B_OUTSIDE_VIEW)) {
if (fAnticipatingDrop) {
fAnticipatingDrop = false;
Invalidate();
}
}
BIconButton::MouseMoved(where, transit, dragMessage);
}
BSize
LaunchButton::MinSize()
{
return PreferredSize();
}
BSize
LaunchButton::PreferredSize()
{
float minWidth = fIconSize;
float minHeight = fIconSize;
float hPadding = max_c(6.0, ceilf(minHeight / 3.0));
float vPadding = max_c(6.0, ceilf(minWidth / 3.0));
if (Label() != NULL && Label()[0] != '\0') {
font_height fh;
GetFontHeight(&fh);
minHeight += ceilf(fh.ascent + fh.descent) + vPadding;
minWidth += StringWidth(Label()) + vPadding;
}
return BSize(minWidth + hPadding, minHeight + vPadding);
}
BSize
LaunchButton::MaxSize()
{
return PreferredSize();
}
// #pragma mark -
void
LaunchButton::SetTo(const entry_ref* ref)
{
free(fAppSig);
fAppSig = NULL;
delete fRef;
if (ref) {
fRef = new entry_ref(*ref);
// follow links
BEntry entry(fRef, true);
entry.GetRef(fRef);
_UpdateIcon(fRef);
// see if this is an application
BFile file(ref, B_READ_ONLY);
BAppFileInfo info;
if (info.SetTo(&file) == B_OK) {
char mimeSig[B_MIME_TYPE_LENGTH];
if (info.GetSignature(mimeSig) == B_OK) {
SetTo(mimeSig, false);
} else {
fprintf(stderr, "no MIME signature for '%s'\n", fRef->name);
}
} else {
fprintf(stderr, "no BAppFileInfo for '%s'\n", fRef->name);
}
} else {
fRef = NULL;
ClearIcon();
}
_UpdateToolTip();
}
entry_ref*
LaunchButton::Ref() const
{
return fRef;
}
void
LaunchButton::SetTo(const char* appSig, bool updateIcon)
{
if (appSig) {
free(fAppSig);
fAppSig = strdup(appSig);
if (updateIcon) {
entry_ref ref;
if (be_roster->FindApp(fAppSig, &ref) == B_OK)
SetTo(&ref);
}
}
_UpdateToolTip();
}
void
LaunchButton::SetDescription(const char* text)
{
fDescription.SetTo(text);
_UpdateToolTip();
}
void
LaunchButton::SetIconSize(uint32 size)
{
if (fIconSize == size)
return;
fIconSize = size;
_UpdateIcon(fRef);
InvalidateLayout();
Invalidate();
}
void
LaunchButton::SetIgnoreDoubleClick(bool refuse)
{
sIgnoreDoubleClick = refuse;
}
// #pragma mark -
void
LaunchButton::_UpdateToolTip()
{
// TODO: This works around a bug in the tool tip management.
// Remove when fixed (although no harm done...)
HideToolTip();
SetToolTip(static_cast<BToolTip*>(NULL));
if (fRef) {
BString helper(fRef->name);
if (fDescription.CountChars() > 0) {
if (fDescription != helper)
helper << "\n\n" << fDescription.String();
} else {
BFile file(fRef, B_READ_ONLY);
BAppFileInfo appFileInfo;
version_info info;
if (appFileInfo.SetTo(&file) == B_OK
&& appFileInfo.GetVersionInfo(&info,
B_APP_VERSION_KIND) == B_OK
&& strlen(info.short_info) > 0
&& helper.Compare(info.short_info) != 0) {
helper << "\n\n" << info.short_info;
}
}
SetToolTip(helper.String());
}
}
void
LaunchButton::_UpdateIcon(const entry_ref* ref)
{
BBitmap* icon = new BBitmap(BRect(0.0, 0.0, fIconSize - 1,
fIconSize - 1), B_RGBA32);
// NOTE: passing an invalid/unknown icon_size argument will cause
// the BNodeInfo to ignore it and just use the bitmap bounds.
if (BNodeInfo::GetTrackerIcon(ref, icon, (icon_size)fIconSize) == B_OK)
SetIcon(icon);
delete icon;
}
void
LaunchButton::_DrawFrame(BRect r, rgb_color col1, rgb_color col2,
rgb_color col3, rgb_color col4)
{
BeginLineArray(8);
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col1);
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col1);
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col2);
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col2);
r.InsetBy(1.0, 1.0);
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col3);
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col3);
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col4);
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col4);
EndLineArray();
}
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright 2006-2011, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef LAUNCH_BUTTON_H
#define LAUNCH_BUTTON_H
#include <IconButton.h>
#include <List.h>
#include <String.h>
enum {
MSG_ADD_SLOT = 'adsl',
MSG_CLEAR_SLOT = 'clsl',
MSG_REMOVE_SLOT = 'rmsl',
MSG_LAUNCH = 'lnch',
};
class LaunchButton : public BIconButton {
public:
LaunchButton(const char* name,
const char* label = NULL,
BMessage* message = NULL,
BHandler* target = NULL);
virtual ~LaunchButton();
// BIconButton interface
virtual void AttachedToWindow();
virtual void Draw(BRect updateRect);
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
virtual BSize MinSize();
virtual BSize PreferredSize();
virtual BSize MaxSize();
// LaunchButton
void SetTo(const entry_ref* ref);
entry_ref* Ref() const;
void SetTo(const char* appSig, bool updateIcon);
const char* AppSignature() const
{ return fAppSig; }
void SetDescription(const char* text);
const char* Description() const
{ return fDescription.String(); }
void SetIconSize(uint32 size);
uint32 IconSize() const
{ return fIconSize; }
static void SetIgnoreDoubleClick(bool refuse);
static bool IgnoreDoubleClick()
{ return sIgnoreDoubleClick; }
private:
void _UpdateToolTip();
void _UpdateIcon(const entry_ref* ref);
void _DrawFrame(BRect frame,
rgb_color left, rgb_color top,
rgb_color right, rgb_color bottom);
private:
entry_ref* fRef;
char* fAppSig;
BString fDescription;
bool fAnticipatingDrop;
bigtime_t fLastClickTime;
BPoint fDragStart;
uint32 fIconSize;
static bigtime_t sClickSpeed;
static bool sIgnoreDoubleClick;
};
#endif // LAUNCH_BUTTON_H
+183
View File
@@ -0,0 +1,183 @@
/*
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "PanelWindow.h"
#include <stdio.h>
#include <GroupLayout.h>
#include <MessageRunner.h>
#include <Screen.h>
#include "ApplicationsView.h"
#include "GroupListView.h"
#include "Switcher.h"
#include "WindowsView.h"
static const uint32 kMsgShow = 'SHOW';
static const uint32 kMsgHide = 'HIDE';
static const int32 kMinShowState = 0;
static const int32 kMaxShowState = 4;
static const bigtime_t kMoveDelay = 15000;
// 25 ms
PanelWindow::PanelWindow(uint32 location, uint32 which, team_id team)
:
BWindow(BRect(-16000, -16000, -15900, -15900), "panel",
B_BORDERED_WINDOW_LOOK, B_FLOATING_ALL_WINDOW_FEEL,
B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS | B_AVOID_FOCUS,
B_ALL_WORKSPACES),
fLocation(location),
fShowState(kMinShowState)
{
SetLayout(new BGroupLayout(B_HORIZONTAL));
BView* child = _ViewFor(location, which, team);
if (child != NULL)
AddChild(child);
Run();
PostMessage(kMsgShow);
}
PanelWindow::~PanelWindow()
{
BMessage message(kMsgLocationFree);
message.AddInt32("location", fLocation);
be_app->PostMessage(&message);
}
void
PanelWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgShow:
case kMsgHide:
_UpdateShowState(message->what);
break;
default:
BWindow::MessageReceived(message);
break;
}
}
BView*
PanelWindow::_ViewFor(uint32 location, uint32 which, team_id team) const
{
switch (which) {
case kShowApplications:
return new ApplicationsView(location);
case kShowApplicationWindows:
return new WindowsView(team, location);
default:
return NULL;
}
}
void
PanelWindow::_UpdateShowState(uint32 how)
{
if ((how == kMsgShow && fShowState >= kMaxShowState)
|| (how == kMsgHide && fShowState <= kMinShowState))
return;
fShowState += how == kMsgShow ? 1 : -1;
// Compute start and end position depending on the location
// TODO: multi-screen support
BScreen screen;
BRect screenFrame = screen.Frame();
BPoint from;
BPoint to;
switch (fLocation) {
case kLeftEdge:
case kRightEdge:
from.y = screenFrame.top
+ (screenFrame.Height() - Bounds().Height()) / 2.f;
to.y = from.y;
break;
case kTopEdge:
case kBottomEdge:
from.x = screenFrame.left
+ (screenFrame.Width() - Bounds().Width()) / 2.f;
to.x = from.x;
break;
}
switch (fLocation) {
case kLeftEdge:
from.x = screenFrame.left - Bounds().Width();
to.x = screenFrame.left;
break;
case kRightEdge:
from.x = screenFrame.right;
to.x = screenFrame.right - Bounds().Width();
break;
case kTopEdge:
from.y = screenFrame.top - Bounds().Height();
to.y = screenFrame.top;
break;
case kBottomEdge:
from.y = screenFrame.bottom;
to.y = screenFrame.bottom - Bounds().Height();
break;
}
MoveTo(from.x + _Factor() * (to.x - from.x),
from.y + _Factor() * (to.y - from.y));
if (kMsgShow && IsHidden())
Show();
else if (fShowState == 0 && kMsgHide && !IsHidden())
Quit();
if ((how == kMsgShow && fShowState < kMaxShowState)
|| (how == kMsgHide && fShowState > kMinShowState)) {
BMessage move(how);
BMessageRunner::StartSending(this, &move, kMoveDelay, 1);
} else if (how == kMsgShow) {
// Hide the window once the mouse left its frame
BMessage hide(kMsgHideWhenMouseMovedOut);
hide.AddMessenger("target", this);
hide.AddInt32("what", kMsgHide);
// The window might not span over the whole screen, but one dimension
// should be ignored for the cursor movements
BRect frame = Frame();
switch (fLocation) {
case kLeftEdge:
case kRightEdge:
frame.top = screenFrame.top;
frame.bottom = screenFrame.bottom;
break;
case kTopEdge:
case kBottomEdge:
frame.left = screenFrame.left;
frame.right = screenFrame.right;
break;
}
hide.AddRect("frame", frame);
be_app->PostMessage(&hide);
}
}
float
PanelWindow::_Factor()
{
float factor = 1.f * fShowState / kMaxShowState;
return 1 - (factor - 1) * (factor - 1);
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PANEL_WINDOW_H
#define PANEL_WINDOW_H
#include <Window.h>
class PanelWindow : public BWindow {
public:
PanelWindow(uint32 location, uint32 which,
team_id team);
virtual ~PanelWindow();
virtual void MessageReceived(BMessage* message);
private:
BView* _ViewFor(uint32 location, uint32 which,
team_id team) const;
void _UpdateShowState(uint32 how);
float _Factor();
private:
uint32 fLocation;
int32 fShowState;
};
#endif // PANEL_WINDOW_H
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "Switcher.h"
#include <stdlib.h>
#include <Application.h>
#include <Catalog.h>
#include "CaptureWindow.h"
#include "PanelWindow.h"
#undef B_TRANSLATE_CONTEXT
#define B_TRANSLATE_CONTEXT "Switcher"
const char* kSignature = "application/x-vnd.Haiku-Switcher";
Switcher::Switcher()
:
BApplication(kSignature),
fOccupiedLocations(0)
{
}
Switcher::~Switcher()
{
}
void
Switcher::ReadyToRun()
{
CaptureWindow* window = new CaptureWindow();
window->Run();
fCaptureMessenger = window;
}
void
Switcher::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgLocationTrigger:
{
uint32 location = (uint32)message->FindInt32("location");
if ((location & fOccupiedLocations) == 0) {
// TODO: make function configurable
uint32 which = kShowApplicationWindows;
if ((location & (kTopEdge | kBottomEdge)) != 0)
which = kShowApplications;
new PanelWindow(location, which,
(team_id)message->FindInt32("team"));
fOccupiedLocations |= location;
}
break;
}
case kMsgLocationFree:
{
uint32 location;
if (message->FindInt32("location", (int32*)&location) == B_OK)
fOccupiedLocations &= ~location;
break;
}
case kMsgHideWhenMouseMovedOut:
fCaptureMessenger.SendMessage(message);
break;
default:
BApplication::MessageReceived(message);
break;
}
}
// #pragma mark -
int
main(int /*argc*/, char** /*argv*/)
{
Switcher app;
app.Run();
return 0;
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef SWITCHER_H
#define SWITCHER_H
#include <Application.h>
class BMessage;
enum {
kNowhere = 0,
kTopEdge = 0x01,
kBottomEdge = 0x02,
kLeftEdge = 0x04,
kRightEdge = 0x08,
// TODO: not yet supported
kTopLeftCorner = 0x10,
kTopRightCorner = 0x20,
kBottomLeftCorner = 0x40,
kBottomRightCorner = 0x80
};
enum {
kShowApplications,
kShowApplicationWindows,
kShowWorkspaceWindows,
kShowAllWindows,
kShowWorkspaces,
kShowShelf,
kShowFavorites,
kShowRecentFiles,
kShowFilesClipboard,
kShowFolder,
kShowQuery
};
static const uint32 kMsgLocationTrigger = 'LoTr';
static const uint32 kMsgLocationFree = 'LoFr';
static const uint32 kMsgHideWhenMouseMovedOut = 'HwMo';
class Switcher : public BApplication {
public:
Switcher();
virtual ~Switcher();
virtual void ReadyToRun();
virtual void MessageReceived(BMessage* message);
private:
BMessenger fCaptureMessenger;
uint32 fOccupiedLocations;
};
extern const char* kSignature;
#endif // SWITCHER_H
+18
View File
@@ -0,0 +1,18 @@
resource app_signature "application/x-vnd.Haiku-Switcher";
//resource app_name_catalog_entry "x-vnd.Haiku-Switcher:System name:Switcher";
resource app_version {
major = 1,
middle = 0,
minor = 0,
variety = B_APPV_BETA,
internal = 0,
short_info = "Switcher",
long_info = "Switcher ©2011 Haiku, Inc."
};
resource app_flags B_SINGLE_LAUNCH | B_BACKGROUND_APP;
+356
View File
@@ -0,0 +1,356 @@
/*
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "WindowsView.h"
#include <stdlib.h>
#include <LayoutBuilder.h>
#include <ObjectList.h>
#include <StringView.h>
#include <MessengerPrivate.h>
#include <WindowInfo.h>
#include <WindowPrivate.h>
#include "GroupListView.h"
#include "LaunchButton.h"
#include "Switcher.h"
static const uint32 kMsgActivateWindow = 'AcWn';
class WindowModel : public TypedGroupListModel<client_window_info, void> {
public:
WindowModel(team_id team)
:
fWindows(true),
fWorkspaces(0),
fWorkspaceCount(0)
{
// TODO: more than one team via signature!
int32 count;
int32* tokens = get_token_list(team, &count);
for (int32 i = 0; i < count; i++) {
client_window_info* info = get_window_info(tokens[i]);
if (!_WindowShouldBeListed(info)) {
free(info);
continue;
}
fWorkspaces |= info->workspaces;
fWindows.AddItem(info);
}
free(tokens);
for (uint32 i = 0; i < 32; i++) {
if ((fWorkspaces & (1UL << i)) != 0)
fWorkspaceCount++;
}
fWindows.SortItems(&_CompareWindowInfo);
}
virtual ~WindowModel()
{
}
void BringToFront(int32 index)
{
client_window_info* info = fWindows.ItemAt(index);
if (info == NULL)
return;
do_window_action(info->server_token, B_BRING_TO_FRONT, BRect(), false);
}
void Close(int32 index)
{
client_window_info* info = fWindows.ItemAt(index);
if (info == NULL)
return;
BMessenger window;
BMessenger::Private(window).SetTo(info->team, info->client_port,
info->client_token);
window.SendMessage(B_QUIT_REQUESTED);
}
virtual int32 CountItems()
{
return fWindows.CountItems();
}
virtual client_window_info* ItemAt(int32 index)
{
return fWindows.ItemAt(index);
}
virtual int32 CountGroups()
{
return fWorkspaceCount;
}
virtual void* GroupAt(int32 index)
{
return (void*)(_NthSetBit(index, fWorkspaces) + 1);
}
virtual void* GroupForItemAt(int32 index)
{
client_window_info* info = ItemAt(index);
return (void*)(_NthSetBit(0, info->workspaces) + 1);
}
private:
bool _WindowShouldBeListed(client_window_info* info)
{
return info != NULL
&& (info->feel == B_NORMAL_WINDOW_FEEL
|| info->feel == kWindowScreenFeel)
&& (info->show_hide_level <= 0 || info->is_mini);
}
int32 _NthSetBit(int32 index, uint32 mask)
{
for (uint32 i = 0; i < 32; i++) {
if ((mask & (1UL << i)) != 0) {
if (index-- == 0)
return i;
}
}
return 0;
}
static int _CompareWindowInfo(const client_window_info* a,
const client_window_info* b)
{
return strcasecmp(a->name, b->name);
}
private:
BObjectList<client_window_info> fWindows;
uint32 fWorkspaces;
int32 fWorkspaceCount;
};
class StringItemRenderer : public ListItemRenderer {
public:
StringItemRenderer()
{
}
virtual ~StringItemRenderer()
{
}
void SetText(BView* owner, const BString& text)
{
fText = text;
owner->TruncateString(&fText, B_TRUNCATE_MIDDLE, 200);
SetWidth((int32)ceilf(owner->StringWidth(fText.String())));
font_height fontHeight;
owner->GetFontHeight(&fontHeight);
SetBaselineOffset(
2 + (int32)ceilf(fontHeight.ascent + fontHeight.leading / 2));
SetHeight((int32)ceilf(fontHeight.ascent)
+ (int32)ceilf(fontHeight.descent)
+ (int32)ceilf(fontHeight.leading) + 4);
}
virtual void SetWidth(int32 width)
{
fWidth = width;
}
virtual void SetHeight(int32 height)
{
fHeight = height;
}
virtual void SetBaselineOffset(int32 offset)
{
fBaselineOffset = offset;
}
const BString& Text() const
{
return fText;
}
virtual BSize MinSize()
{
return BSize(fWidth, fHeight);
}
virtual BSize MaxSize()
{
return BSize(B_SIZE_UNLIMITED, fHeight);
}
virtual BSize PreferredSize()
{
return BSize(fWidth, fHeight);
}
virtual void Draw(BView* owner, BRect frame, int32 index, bool selected)
{
owner->SetLowColor(owner->ViewColor());
owner->MovePenTo(frame.left, frame.top + fBaselineOffset);
owner->DrawString(fText);
}
private:
BString fText;
int32 fWidth;
int32 fHeight;
int32 fBaselineOffset;
};
class WorkspaceRenderer : public StringItemRenderer {
public:
virtual void SetTo(BView* owner, void* item)
{
fWorkspace = (uint32)item;
if ((uint32)current_workspace() == fWorkspace - 1)
SetText(owner, "Current workspace");
else {
BString text("Workspace ");
text << fWorkspace;
SetText(owner, text);
}
}
virtual void Draw(BView* owner, BRect frame, int32 index, bool selected)
{
owner->SetHighColor(tint_color(owner->ViewColor(), B_DARKEN_2_TINT));
StringItemRenderer::Draw(owner, frame, index, false);
}
private:
uint32 fWorkspace;
};
class WindowRenderer : public StringItemRenderer {
public:
virtual void SetTo(BView* owner, void* item)
{
fInfo = (client_window_info*)item;
SetText(owner, fInfo->name);
}
virtual void SetWidth(int32 width)
{
StringItemRenderer::SetWidth(width + 20);
}
virtual void Draw(BView* owner, BRect frame, int32 index, bool selected)
{
owner->SetHighColor(0, 0, 0);
frame.left += 20;
StringItemRenderer::Draw(owner, frame, index, selected);
}
private:
client_window_info* fInfo;
};
// #pragma mark -
WindowsView::WindowsView(team_id team, uint32 location)
:
BGridView("windows")
{
app_info info;
be_roster->GetRunningAppInfo(team, &info);
LaunchButton* launchButton = new LaunchButton(info.signature, NULL, NULL,
this);
launchButton->SetTo(&info.ref);
BStringView* nameView = new BStringView("name", info.ref.name);
BFont font(be_plain_font);
font.SetSize(font.Size() * 2);
font.SetFace(B_BOLD_FACE);
nameView->SetFont(&font);
fListView = new GroupListView("list", new WindowModel(team),
_Orientation(location));
fListView->SetItemRenderer(new WindowRenderer());
fListView->SetGroupRenderer(new WorkspaceRenderer());
GridLayout()->SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING);
if (_Orientation(location) == B_HORIZONTAL) {
BLayoutBuilder::Grid<>(this)
.Add(launchButton, 0, 0)
.Add(nameView, 1, 0)
.Add(fListView, 2, 0);
} else {
BLayoutBuilder::Grid<>(this)
.Add(launchButton, 0, 0)
.Add(nameView, 1, 0)
.Add(fListView, 0, 1, 2);
}
}
WindowsView::~WindowsView()
{
}
void
WindowsView::AttachedToWindow()
{
fListView->SetSelectionMessage(new BMessage(kMsgActivateWindow), this);
}
void
WindowsView::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgActivateWindow:
{
int32 index;
if (message->FindInt32("index", &index) == B_OK
&& message->HasPointer("item")) {
WindowModel* model = (WindowModel*)fListView->Model();
if (message->FindInt32("buttons") == B_SECONDARY_MOUSE_BUTTON)
model->Close(index);
else
model->BringToFront(index);
}
break;
}
default:
BGridView::MessageReceived(message);
break;
}
}
orientation
WindowsView::_Orientation(uint32 location)
{
return (location & (kTopEdge | kBottomEdge)) != 0
? B_HORIZONTAL : B_VERTICAL;
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef WINDOWS_VIEW_H
#define WINDOWS_VIEW_H
#include <GridView.h>
class GroupListView;
class WindowsView : public BGridView {
public:
WindowsView(team_id team, uint32 location);
virtual ~WindowsView();
protected:
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
private:
orientation _Orientation(uint32 location);
private:
GroupListView* fListView;
};
#endif // WINDOWS_VIEW_H