haiku/src/servers/app/RootLayer.cpp
Axel Dörfler 485b948731 Removed "Active" stuff from Workspaces state.
As a side effect, the desktop is now clickable again.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15173 a95241bf-73f2-0310-859d-f6bbb57e9c96
2005-11-26 20:22:30 +00:00

1068 lines
27 KiB
C++

/*
* Copyright 2001-2005, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Gabe Yoder <gyoder@stny.rr.com>
* DarkWyrm <bpmagic@columbus.rr.com>
* Adrian Oanca <adioanca@gmail.com>
* Stephan Aßmus <superstippi@gmx.de>
* Axel Dörfler, axeld@pinc-software.de
*/
/** Class used for the top layer of each workspace's Layer tree */
#include "Decorator.h"
#include "DrawingEngine.h"
#include "HWInterface.h"
#include "Layer.h"
#include "RootLayer.h"
#include "ServerApp.h"
#include "ServerConfig.h"
#include "ServerProtocol.h"
#include "ServerScreen.h"
#include "ServerWindow.h"
#include "WindowLayer.h"
#include "Workspace.h"
#include "WorkspacesLayer.h"
#include <File.h>
#include <List.h>
#include <Message.h>
#include <PortLink.h>
#include <Window.h>
#include <stdio.h>
#if DISPLAY_HAIKU_LOGO
#include "ServerBitmap.h"
#include "HaikuLogo.h"
static const float kGoldenProportion = (sqrtf(5.0) - 1.0) / 2.0;
#endif
//#define DEBUG_ROOTLAYER
#define APPSERVER_ROOTLAYER_SHOW_WORKSPACE_NUMBER
#ifdef DEBUG_ROOTLAYER
#define STRACE(a) printf a
#else
#define STRACE(a) /* nothing */
#endif
static RGBColor kDefaultWorkspaceColor = RGBColor(51, 102, 152);
static int32 kMaxWorkspaceCount = 32;
RootLayer::RootLayer(const char *name, int32 workspaceCount,
Desktop *desktop, DrawingEngine *driver)
: Layer(BRect(0, 0, 0, 0), name, 0, B_FOLLOW_ALL, B_WILL_DRAW, driver),
fDesktop(desktop),
fDragMessage(NULL),
fMouseEventLayer(NULL),
fSavedEventMask(0),
fSavedEventOptions(0),
fAllRegionsLock("root layer region lock"),
fDirtyForRedraw(),
fActiveWksIndex(0),
fWsCount(0),
fWorkspace(new Workspace*[kMaxWorkspaceCount]),
fWorkspacesLayer(NULL),
fWMState()
{
//NOTE: be careful about this one.
fRootLayer = this;
// Some stuff that will go away in the future but fills some gaps right now
#if ON_SCREEN_DEBUGGING_INFO
fDebugInfo.SetTo("");
#endif
#if DISPLAY_HAIKU_LOGO
fLogoBitmap = new UtilityBitmap(BRect(0.0, 0.0, kLogoWidth - 1.0,
kLogoHeight - 1.0),
kLogoFormat, 0);
if (fLogoBitmap->IsValid()) {
int32 size = min_c(sizeof(kLogoBits), fLogoBitmap->BitsLength());
memcpy(fLogoBitmap->Bits(), kLogoBits, size);
} else {
delete fLogoBitmap;
fLogoBitmap = NULL;
}
#endif // DISPLAY_HAIKU_LOGO
fHidden = false;
memset(fWorkspace, 0, sizeof(Workspace*) * kMaxWorkspaceCount);
SetWorkspaceCount(workspaceCount);
// TODO: this should eventually be replaced by a method to convert the monitor
// number to an index in the name, i.e. workspace_settings_1 for screen #1
// ReadWorkspaceData(WORKSPACE_DATA_LIST);
// init the first, default workspace
fWorkspace[fActiveWksIndex] = new Workspace(fActiveWksIndex, 0xFF00FF00,
kDefaultWorkspaceColor);
fDrawState->SetHighColor(RGBColor(255, 255, 255));
fDrawState->SetLowColor(fWorkspace[fActiveWksIndex]->BGColor());
#if ON_SCREEN_DEBUGGING_INFO
DebugInfoManager::Default()->SetRootLayer(this);
#endif
fFrame = desktop->VirtualScreen().Frame();
// RootLayer starts with valid visible regions
fFullVisible.Set(Bounds());
fVisible.Set(Bounds());
// first make sure we are actualy visible
MarkForRebuild(Bounds());
MarkForRedraw(Bounds());
TriggerRebuild();
TriggerRedraw();
}
RootLayer::~RootLayer()
{
delete fDragMessage;
for (int32 i = 0; i < fWsCount; i++)
delete fWorkspace[i];
delete[] fWorkspace;
fFirstChild = NULL;
// this prevents the Layer destructor from freeing our children again
// (the Desktop destructor already took care of that)
// RootLayer object just uses Screen objects, it is not allowed to delete them.
#if DISPLAY_HAIKU_LOGO
delete fLogoBitmap;
#endif
}
void
RootLayer::MoveBy(float x, float y)
{
}
void
RootLayer::ResizeBy(float x, float y)
{
if (x == 0 && y == 0)
return;
// TODO: we should be able to update less here
//BRect previous = fFrame;
fFrame.right += x;
fFrame.bottom += y;
fFullVisible.Set(Bounds());
fVisible.Set(Bounds());
BRegion region(fFrame);
MarkForRebuild(region);
TriggerRebuild();
//region.Exclude(previous);
MarkForRedraw(region);
TriggerRedraw();
}
void
RootLayer::AddWindowLayer(WindowLayer* windowLayer)
{
if (!windowLayer->IsHidden()) {
CRITICAL("RootLayer::AddWindowLayer - windowLayer must be hidden\n");
return;
}
// Subset modals also need to have a main window before appearing in workspace list.
int32 feel = windowLayer->Feel();
if (feel != B_FLOATING_SUBSET_WINDOW_FEEL && feel != B_MODAL_SUBSET_WINDOW_FEEL) {
uint32 workspaces = windowLayer->Workspaces();
// add to current workspace
if (workspaces == 0)
fWorkspace[fActiveWksIndex]->AddWindowLayer(windowLayer);
else {
// add to desired workspaces
for (int32 i = 0; i < fWsCount; i++) {
if (fWorkspace[i] && (workspaces & (0x00000001UL << i)))
fWorkspace[i]->AddWindowLayer(windowLayer);
}
}
}
// we _DO_NOT_ need to invalidate here. At this point our WindowLayer is hidden!
// set some internals
windowLayer->SetRootLayer(this);
windowLayer->fParent = this;
}
void
RootLayer::RemoveWindowLayer(WindowLayer* windowLayer)
{
// Note: removing a subset window is also permited/performed.
if (!windowLayer->IsHidden())
{
CRITICAL("RootLayer::RemoveWindowLayer - windowLayer must be hidden\n");
return;
}
// security measure: in case of windows whose workspace count is 0(current workspace),
// we don't know the exact workspaces to remove it from. And how all modal and floating
// windows have 0 as a workspace index, this action is fully justified.
for (int32 i = 0; i < fWsCount; i++) {
if (fWorkspace[i])
fWorkspace[i]->RemoveWindowLayer(windowLayer);
}
// we _DO_NOT_ need to invalidate here. At this point our WindowLayer is hidden!
LayerRemoved(windowLayer);
// set some internals
windowLayer->SetRootLayer(NULL);
windowLayer->fParent = NULL;
}
void
RootLayer::AddSubsetWindowLayer(WindowLayer *windowLayer, WindowLayer *toWindowLayer)
{
// SUBSET windows _must_ have their workspaceIndex set to 0x0
if (windowLayer->Workspaces() != 0UL)
{
CRITICAL("SUBSET windows _must_ have their workspaceIndex set to 0x0\n");
return;
}
// there is no point in continuing - this subset window won't be shown,
// from 'toWindowLayer's point of view
if (windowLayer->IsHidden() || toWindowLayer->IsHidden())
{
return;
}
bool invalidate = false;
bool invalid;
Workspace::State oldWMState;
ActiveWorkspace()->GetState(&oldWMState);
// we try to add WindowLayers to all workspaces. If they are not needed, nothing will be done.
// If they are needed, Workspace automaticaly allocates space and inserts them.
for (int32 i = 0; i < fWsCount; i++) {
invalid = false;
if (fWorkspace[i] && fWorkspace[i]->HasWindowLayer(toWindowLayer))
invalid = fWorkspace[i]->ShowWindowLayer(windowLayer, false);
if (fActiveWksIndex == i)
invalidate = invalid;
}
if (invalidate)
RevealNewWMState(oldWMState);
}
void
RootLayer::RemoveSubsetWindowLayer(WindowLayer *windowLayer, WindowLayer *fromWindowLayer)
{
// there is no point in continuing - this subset window is not visible
// at least not visible from 'fromWindowLayer's point of view.
if (windowLayer->IsHidden() || fromWindowLayer->IsHidden())
return;
bool invalidate = false;
bool invalid;
Workspace::State oldWMState;
ActiveWorkspace()->GetState(&oldWMState);
// we try to remove from all workspaces. If windowLayer is not in there, nothing will be done.
for (int32 i = 0; i < fWsCount; i++) {
invalid = false;
if (fWorkspace[i] && fWorkspace[i]->HasWindowLayer(fromWindowLayer))
invalid = fWorkspace[i]->HideWindowLayer(windowLayer);
if (fActiveWksIndex == i)
invalidate = invalid;
}
if (invalidate)
RevealNewWMState(oldWMState);
}
// NOTE: This must be called by RootLayer's thread!!!!
bool RootLayer::SetActiveWorkspace(int32 index)
{
STRACE(("RootLayer(%s)::SetActiveWorkspace(%ld)\n", Name(), index));
// nice try!
if (index >= fWsCount || index == fActiveWksIndex || index < 0)
return false;
// you cannot switch workspaces on R5 if there is an event mask BView
// if (fNotifyLayer && fNotifyLayer->Owner())
// return false;
// if you're dragging something you are allowed to change workspaces only if
// the Layer being dragged is a B_NORMAL_WINDOW_FEEL WindowLayer.
WindowLayer *draggedWindowLayer = dynamic_cast<WindowLayer*>(fMouseEventLayer);
if (fMouseEventLayer != NULL) {
if (draggedWindowLayer) {
if (draggedWindowLayer->Feel() != B_NORMAL_WINDOW_FEEL)
return false;
} else
return false;
}
// if fWorkspace[index] object does not exist, create and add allowed WindowLayers
if (!fWorkspace[index]) {
// TODO: we NEED datas from a file!!!
fWorkspace[index] = new Workspace(index, 0xFF00FF00, kDefaultWorkspaceColor);
// we need to lock the window list here so no other window can be created
fDesktop->Lock();
const BObjectList<WindowLayer>& windowList = fDesktop->WindowList();
int32 windowCount = windowList.CountItems();
for (int32 i = 0; i < windowCount; i++) {
WindowLayer* windowLayer = windowList.ItemAt(i);
// is WindowLayer on this workspace?
if (windowLayer->Workspaces() & (0x00000001UL << index)) {
fWorkspace[index]->AddWindowLayer(windowLayer);
if (!windowLayer->IsHidden())
fWorkspace[index]->ShowWindowLayer(windowLayer);
}
}
fDesktop->Unlock();
}
// adjust our DrawData to workspace colors
rgb_color bg = fWorkspace[index]->BGColor().GetColor32();
if ((bg.red + bg.green + bg.blue) / 3 > 128)
fDrawState->SetHighColor(RGBColor(0, 0, 0));
else
fDrawState->SetHighColor(RGBColor(255, 255, 255));
fDrawState->SetLowColor(fWorkspace[index]->BGColor());
// save some datas
int32 exIndex = ActiveWorkspaceIndex();
Workspace::State oldWMState;
ActiveWorkspace()->GetState(&oldWMState);
// send the workspace changed message for the old workspace
{
Layer *layer;
for (int32 i = 0; (layer = static_cast<Layer*>(fWMState.WindowList.ItemAt(i++))); ) {
layer->WorkspaceActivated(fActiveWksIndex, false);
}
}
fActiveWksIndex = index;
if (draggedWindowLayer && !ActiveWorkspace()->HasWindowLayer(draggedWindowLayer)) {
// Workspace class expects a window to be hidden when it's about to be removed.
// As we surely know this windows is visible, we simply set fHidden to true and then
// change it back when adding windowLayer to the current workspace.
draggedWindowLayer->fHidden = true;
fWorkspace[exIndex]->HideWindowLayer(draggedWindowLayer);
fWorkspace[exIndex]->RemoveWindowLayer(draggedWindowLayer);
draggedWindowLayer->fHidden = false;
ActiveWorkspace()->AddWindowLayer(draggedWindowLayer);
ActiveWorkspace()->ShowWindowLayer(draggedWindowLayer);
// TODO: can you call SetWindowLayerWorskpaces() instead of this?
uint32 wks = draggedWindowLayer->Workspaces();
BMessage changedMsg(B_WORKSPACES_CHANGED);
changedMsg.AddInt64("when", real_time_clock_usecs());
changedMsg.AddInt32("old", wks);
wks &= ~(0x00000001 << exIndex);
wks |= (0x00000001 << fActiveWksIndex);
changedMsg.AddInt32("new", wks);
draggedWindowLayer->QuietlySetWorkspaces(wks);
draggedWindowLayer->Window()->SendMessageToClient(&changedMsg, B_NULL_TOKEN);
}
RevealNewWMState(oldWMState);
// send the workspace changed message for the new workspace
{
Layer *layer;
for (int32 i = 0; (layer = static_cast<Layer*>(fWMState.WindowList.ItemAt(i++))); ) {
layer->WorkspaceActivated(fActiveWksIndex, true);
}
}
// workspace changed
return true;
}
void
RootLayer::SetWindowLayerWorskpaces(WindowLayer *windowLayer, uint32 oldIndex, uint32 newIndex)
{
// if the active notify Layer is somehow related to windowLayer, then
// this window/WindowLayer is not allowed to leave this workspace.
// TODO: this looks wrong: I doubt the window is supposed to open in two workspaces then
// if (fNotifyLayer && (fNotifyLayer == windowLayer || fNotifyLayer->Owner() == windowLayer))
// newIndex |= (0x00000001UL << fActiveWksIndex);
uint32 localOldIndex = oldIndex;
uint32 localNewIndex = newIndex;
bool invalidate = false;
bool invalid;
// if we're in the current workspace only, reflect that in the workspace index
if (localOldIndex == 0UL)
localOldIndex |= (0x00000001UL << fActiveWksIndex);
if (localNewIndex == 0UL)
localNewIndex |= (0x00000001UL << fActiveWksIndex);
// you *cannot* set workspaces index for a window other than a normal one!
// Note: See ServerWindow class.
if (windowLayer->Feel() != B_NORMAL_WINDOW_FEEL || localOldIndex == localNewIndex)
return;
Workspace::State oldWMState;
ActiveWorkspace()->GetState(&oldWMState);
for (int32 i = 0; i < 32; i++) {
if (fWorkspace[i]) {
invalid = false;
if (!(localNewIndex & (0x00000001UL << i)) && fWorkspace[i]->HasWindowLayer(windowLayer)) {
if (!windowLayer->IsHidden()) {
// a little trick to force Workspace to properly pick the next front.
windowLayer->fHidden = true;
invalid = fWorkspace[i]->HideWindowLayer(windowLayer);
windowLayer->fHidden = false;
}
fWorkspace[i]->RemoveWindowLayer(windowLayer);
}
if ((localNewIndex & (0x00000001UL << i)) && !fWorkspace[i]->HasWindowLayer(windowLayer)) {
fWorkspace[i]->AddWindowLayer(windowLayer);
if (!windowLayer->IsHidden())
invalid = fWorkspace[i]->ShowWindowLayer(windowLayer);
}
if (fActiveWksIndex == i)
invalidate = invalid;
}
}
windowLayer->WorkspacesChanged(oldIndex, newIndex);
if (invalidate)
RevealNewWMState(oldWMState);
}
void
RootLayer::SetWorkspaceCount(int32 wksCount)
{
if (wksCount < 1)
wksCount = 1;
if (wksCount > kMaxWorkspaceCount)
wksCount = kMaxWorkspaceCount;
for (int32 i = wksCount; i < fWsCount; i++) {
delete fWorkspace[i];
fWorkspace[i] = NULL;
}
fWsCount = wksCount;
}
void
RootLayer::ReadWorkspaceData(const char *path)
{
BMessage msg, settings;
BFile file(path,B_READ_ONLY);
char string[20];
if (file.InitCheck() == B_OK && msg.Unflatten(&file) == B_OK) {
int32 count;
if (msg.FindInt32("workspace_count", &count)!=B_OK)
count = 9;
SetWorkspaceCount(count);
for (int32 i = 0; i < count; i++) {
Workspace *ws=(Workspace*)fWorkspace[i];
if (!ws)
continue;
sprintf(string,"workspace %ld",i);
if (msg.FindMessage(string,&settings) == B_OK) {
ws->GetSettings(settings);
settings.MakeEmpty();
} else
ws->GetDefaultSettings();
}
} else {
SetWorkspaceCount(9);
for (int32 i = 0; i < 9; i++) {
Workspace *ws=(Workspace*)fWorkspace[i];
if (!ws)
continue;
ws->GetDefaultSettings();
}
}
}
void
RootLayer::SaveWorkspaceData(const char *path)
{
BMessage msg,dummy;
BFile file(path, B_READ_WRITE | B_CREATE_FILE);
if (file.InitCheck() != B_OK) {
printf("ERROR: Couldn't save workspace data in RootLayer\n");
return;
}
char string[20];
int32 count = fWsCount;
if (msg.Unflatten(&file) == B_OK) {
// if we were successful in unflattening the file, it means we're
// going to need to save over the existing data
for(int32 i = 0; i < count; i++) {
sprintf(string,"workspace %ld",i);
if(msg.FindMessage(string,&dummy)==B_OK)
msg.RemoveName(string);
}
}
for (int32 i = 0; i < count; i++) {
sprintf(string,"workspace %ld",i);
Workspace *ws = (Workspace*)fWorkspace[i];
if (!ws) {
dummy.MakeEmpty();
ws->PutSettings(&dummy,i);
msg.AddMessage(string,&dummy);
} else {
// We're not supposed to have this happen, but we'll suck it up, anyway. :P
Workspace::PutDefaultSettings(&msg,i);
}
}
}
void
RootLayer::HideWindowLayer(WindowLayer* windowLayer)
{
BAutolock _(fAllRegionsLock);
bool invalidate = false;
bool invalid;
Workspace::State oldWMState;
ActiveWorkspace()->GetState(&oldWMState);
windowLayer->Hide(false);
for (int32 i = 0; i < fWsCount; i++) {
invalid = false;
if (fWorkspace[i] && fWorkspace[i]->HasWindowLayer(windowLayer))
invalid = fWorkspace[i]->HideWindowLayer(windowLayer);
if (fActiveWksIndex == i) {
invalidate = invalid;
if (dynamic_cast<class WorkspacesLayer *>(windowLayer->FirstChild()) != NULL)
SetWorkspacesLayer(NULL);
}
}
if (invalidate)
RevealNewWMState(oldWMState);
}
void
RootLayer::ShowWindowLayer(WindowLayer* windowLayer)
{
BAutolock _(fAllRegionsLock);
bool invalidate = false;
bool invalid;
Workspace::State oldWMState;
ActiveWorkspace()->GetState(&oldWMState);
windowLayer->Show(false);
for (int32 i = 0; i < fWsCount; i++) {
invalid = false;
if (fWorkspace[i]
&& (fWorkspace[i]->HasWindowLayer(windowLayer)
|| windowLayer->Feel() == B_MODAL_SUBSET_WINDOW_FEEL
// subset modals are a bit like floating windows, they are being added
// and removed from workspace when there's at least a normal window
// that uses them.
|| windowLayer->Level() == B_FLOATING_APP))
// floating windows are inserted/removed on-the-fly so this window,
// although needed may not be in workspace's list.
{
invalid = fWorkspace[i]->ShowWindowLayer(windowLayer);
// ToDo: this won't work with FFM
fWorkspace[i]->AttemptToSetFocus(windowLayer);
}
if (fActiveWksIndex == i) {
invalidate = invalid;
if (dynamic_cast<class WorkspacesLayer *>(windowLayer->FirstChild()) != NULL)
SetWorkspacesLayer(windowLayer->FirstChild());
}
}
if (invalidate)
RevealNewWMState(oldWMState);
}
void
RootLayer::ChangeWindowLayerFeel(WindowLayer *windowLayer, int32 newFeel)
{
BAutolock _(fAllRegionsLock);
bool isVisible = false;
bool isVisibleInActiveWorkspace = false;
Workspace::State oldWMState;
ActiveWorkspace()->GetState(&oldWMState);
if (!windowLayer->IsHidden()) {
isVisible = true;
isVisibleInActiveWorkspace = ActiveWorkspace()->HasWindowLayer(windowLayer);
// just hide, don't invalidate
windowLayer->Hide(false);
// all workspaces must be up-to-date with this change of feel.
for (int32 i = 0; i < kMaxWorkspaceCount; i++) {
if (fWorkspace[i]) {
fWorkspace[i]->HideWindowLayer(windowLayer);
fWorkspace[i]->RemoveWindowLayer(windowLayer);
}
}
}
fDesktop->SetWindowLayerFeel(windowLayer, newFeel);
if (isVisible) {
// just show, don't invalidate
windowLayer->Show(false);
// all workspaces must be up-to-date with this change of feel.
for (int32 i = 0; i < kMaxWorkspaceCount; i++) {
if (fWorkspace[i]) {
fWorkspace[i]->AddWindowLayer(windowLayer);
fWorkspace[i]->ShowWindowLayer(windowLayer);
}
}
if (isVisibleInActiveWorkspace)
RevealNewWMState(oldWMState);
}
}
void
RootLayer::RevealNewWMState(Workspace::State &oldWMState)
{
// clear fWMState
fWMState.Focus = NULL;
fWMState.Front = NULL;
fWMState.WindowList.MakeEmpty();
ActiveWorkspace()->GetState(&fWMState);
// send window activation messages
if (oldWMState.Focus != fWMState.Focus) {
if (oldWMState.Focus)
oldWMState.Focus->Activated(false);
if (fWMState.Focus) {
fWMState.Focus->Activated(true);
fDesktop->EventDispatcher().SetFocus(&fWMState.Focus->Window()->FocusMessenger());
} else
fDesktop->EventDispatcher().SetFocus(NULL);
}
// calculate the region that must be invalidated/redrawn
bool redraw = false;
// first, if the focus window changed, make sure the decorators reflect this state.
BRegion dirtyRegion;
if (oldWMState.Focus != fWMState.Focus) {
if (oldWMState.Focus) {
dirtyRegion.Include(&oldWMState.Focus->VisibleRegion());
redraw = true;
}
if (fWMState.Focus) {
dirtyRegion.Include(&fWMState.Focus->VisibleRegion());
redraw = true;
}
if (redraw) {
MarkForRedraw(dirtyRegion);
}
}
bool invalidate = false;
// check to see if window count changed over states
if (oldWMState.WindowList.CountItems() != fWMState.WindowList.CountItems()) {
invalidate = true;
} else if (memcmp(oldWMState.WindowList.Items(), fWMState.WindowList.Items(),
fWMState.WindowList.CountItems()*sizeof(void*)) != 0) {
invalidate = true;
}
if (invalidate) {
// clear visible areas for windows not visible anymore.
int32 oldWindowCount = oldWMState.WindowList.CountItems();
int32 newWindowCount = fWMState.WindowList.CountItems();
BList oldStrippedList, newStrippedList;
for (int32 i = 0; i < oldWindowCount; ++i) {
Layer *layer = static_cast<Layer*>(oldWMState.WindowList.ItemAtFast(i));
if (!layer)
continue;
bool stillPresent = false;
for (int32 j = 0; j < newWindowCount; ++j) {
if (layer == fWMState.WindowList.ItemAtFast(j)) {
stillPresent = true;
break;
}
}
if (!stillPresent) {
MarkForRebuild(layer->FullVisible());
MarkForRedraw(layer->FullVisible());
layer->_ClearVisibleRegions();
} else
oldStrippedList.AddItem(layer);
}
fFirstChild = NULL;
fLastChild = NULL;
// for new windows, invalidate(rebuild & redraw) the maximum that it can occupy.
for (int32 i = 0; i < newWindowCount; ++i) {
Layer *layer = static_cast<Layer*>(fWMState.WindowList.ItemAtFast(i));
if (!layer)
continue;
// insert layer into RootLayer list
if (i == 0)
fFirstChild = layer;
if (fLastChild != NULL)
fLastChild->fNextSibling = layer;
layer->fPreviousSibling = fLastChild;
layer->fNextSibling = NULL;
fLastChild = layer;
bool isNewWindow = true;
for (int32 j = 0; j < oldWindowCount; ++j) {
if (layer == oldWMState.WindowList.ItemAtFast(j)) {
isNewWindow = false;
break;
}
}
if (isNewWindow) {
BRegion invalid;
// invalidate the maximum area which this layer/window can occupy.
layer->GetOnScreenRegion(invalid);
MarkForRebuild(invalid);
MarkForRedraw(invalid);
} else
newStrippedList.AddItem(layer);
}
// if a window came in front ot others, invalidate its previously hidden area.
oldWindowCount = oldStrippedList.CountItems();
newWindowCount = newStrippedList.CountItems();
for (int32 i = 0; i < oldWindowCount; ++i) {
Layer *layer = static_cast<Layer*>(oldStrippedList.ItemAtFast(i));
if (!layer)
continue;
if (i < newStrippedList.IndexOf(layer)) {
BRegion invalid;
// start by invalidating the maximum area which this layer/window can occupy.
layer->GetOnScreenRegion(invalid);
// no reason to invalidate what's currently visible.
invalid.Exclude(&layer->FullVisible());
MarkForRebuild(invalid);
MarkForRedraw(invalid);
}
}
/*
// for debugging
GetDrawingEngine()->ConstrainClippingRegion(&fDirtyForRedraw);
RGBColor c(rand()%255,rand()%255,rand()%255);
GetDrawingEngine()->FillRect(BRect(0,0,800,600), c);
snooze(2000000);
GetDrawingEngine()->ConstrainClippingRegion(NULL);
*/
// redraw of focus change is automaticaly done
redraw = false;
// trigger region rebuilding and redraw
TriggerRebuild();
TriggerRedraw();
} else if (redraw) {
MarkForRedraw(dirtyRegion);
TriggerRedraw();
}
}
bool
RootLayer::SetActive(WindowLayer* newActive, bool activate)
{
bool returnValue = false;
uint32 workspaceIndex = newActive->Workspaces();
if (workspaceIndex == 0)
workspaceIndex = 0x00000001UL << fActiveWksIndex;
for (int32 i = 0; i < kMaxWorkspaceCount; i++) {
if (fWorkspace[i] && (workspaceIndex & (0x00000001UL << i))) {
if (i == fActiveWksIndex) {
Workspace::State oldWMState;
ActiveWorkspace()->GetState(&oldWMState);
if (activate)
returnValue = ActiveWorkspace()->AttemptToActivate(newActive);
else
returnValue = ActiveWorkspace()->AttemptToMoveToBack(newActive);
RevealNewWMState(oldWMState);
} else {
fWorkspace[i]->AttemptToActivate(newActive);
// NOTE: for multiple monitor support, if a workspaces is mapped to
// a Screen, we must invalidate/redraw to see the change.
}
}
}
// If this WindowLayer does not appear in current workspace,
// change to the first one who does.
if (activate && !(workspaceIndex & (0x00000001UL << fActiveWksIndex))) {
// find an workspace index in which this Layer appears
for (int32 i = 0; i < kMaxWorkspaceCount; i++) {
if (workspaceIndex & (0x00000001UL << i)) {
SetActiveWorkspace(i);
returnValue = Active() == newActive;
break;
}
}
}
return returnValue;
}
Layer*
RootLayer::_ChildAt(BPoint where)
{
if (VisibleRegion().Contains(where))
return NULL;
for (Layer* child = LastChild(); child; child = child->PreviousLayer()) {
if (child->FullVisible().Contains(where))
return child;
}
return NULL;
}
// #pragma mark - Input related methods
void
RootLayer::MouseEventHandler(BMessage *event)
{
BPoint where;
if (event->FindPoint("where", &where) != B_OK)
return;
Layer* layer = fMouseEventLayer;
if (layer == NULL) {
layer = _ChildAt(where);
if (layer == NULL)
return;
}
switch (event->what) {
case B_MOUSE_DOWN:
layer->MouseDown(event, where);
break;
case B_MOUSE_UP:
layer->MouseUp(event, where);
SetMouseEventLayer(NULL);
break;
case B_MOUSE_MOVED:
layer->MouseMoved(event, where);
break;
}
}
void
RootLayer::SetMouseEventLayer(Layer* layer)
{
fMouseEventLayer = layer;
}
void
RootLayer::LayerRemoved(Layer* layer)
{
if (fMouseEventLayer == layer)
fMouseEventLayer = NULL;
}
void
RootLayer::SetDragMessage(BMessage* msg)
{
if (fDragMessage) {
delete fDragMessage;
fDragMessage = NULL;
}
if (msg)
fDragMessage = new BMessage(*msg);
}
BMessage *
RootLayer::DragMessage(void) const
{
return fDragMessage;
}
// PRIVATE methods
void
RootLayer::Draw(const BRect &r)
{
fDriver->FillRect(r, fWorkspace[fActiveWksIndex]->BGColor());
#ifdef APPSERVER_ROOTLAYER_SHOW_WORKSPACE_NUMBER
char string[30];
sprintf(string, "Workspace %ld", fActiveWksIndex + 1);
fDriver->DrawString(string, strlen(string), BPoint(5, 15),
fDrawState);
#endif // APPSERVER_ROOTLAYER_SHOW_WORKSPACE_NUMBER
#if ON_SCREEN_DEBUGGING_INFO
BPoint location(5, 40);
float textHeight = 15.0; // be lazy
const char* p = fDebugInfo.String();
const char* start = p;
while (*p) {
p++;
if (*p == 0 || *p == '\n') {
fDriver->DrawString(start, p - start, location,
fDrawState);
// NOTE: Eventually, this will be below the screen!
location.y += textHeight;
start = p + 1;
}
}
#endif // ON_SCREEN_DEBUGGING_INFO
#if DISPLAY_HAIKU_LOGO
if (fLogoBitmap) {
BPoint logoPos;
logoPos.x = floorf(min_c(fFrame.left + fFrame.Width() * kGoldenProportion,
fFrame.right - (kLogoWidth + kLogoHeight / 2.0)));
logoPos.y = floorf(fFrame.bottom - kLogoHeight * 1.5);
BRect bitmapBounds = fLogoBitmap->Bounds();
fDriver->DrawBitmap(fLogoBitmap, bitmapBounds,
bitmapBounds.OffsetToCopy(logoPos), fDrawState);
}
#endif // DISPLAY_HAIKU_LOGO
}
#if ON_SCREEN_DEBUGGING_INFO
void
RootLayer::AddDebugInfo(const char* string)
{
if (Lock()) {
fDebugInfo << string;
MarkForRedraw(VisibleRegion());
TriggerRedraw();
Unlock();
}
}
#endif // ON_SCREEN_DEBUGGING_INFO
void
RootLayer::MarkForRedraw(const BRegion &dirty)
{
BAutolock locker(fAllRegionsLock);
fDirtyForRedraw.Include(&dirty);
}
void
RootLayer::TriggerRedraw()
{
BAutolock locker(fAllRegionsLock);
/*
// for debugging
GetDrawingEngine()->ConstrainClippingRegion(&fDirtyForRedraw);
RGBColor c(rand()%255,rand()%255,rand()%255);
GetDrawingEngine()->FillRect(BRect(0,0,800,600), c);
snooze(2000000);
GetDrawingEngine()->ConstrainClippingRegion(NULL);
*/
_AllRedraw(fDirtyForRedraw);
fDirtyForRedraw.MakeEmpty();
}