4531 lines
115 KiB
C++
4531 lines
115 KiB
C++
/*
|
|
* Copyright 2001-2019, Haiku.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* DarkWyrm <bpmagic@columbus.rr.com>
|
|
* Adrian Oanca <adioanca@gmail.com>
|
|
* Stephan Aßmus <superstippi@gmx.de>
|
|
* Stefano Ceccherini <stefano.ceccherini@gmail.com>
|
|
* Axel Dörfler <axeld@pinc-software.de>
|
|
* Artur Wyszynski <harakash@gmail.com>
|
|
* Philippe Saint-Pierre <stpere@gmail.com>
|
|
* Brecht Machiels <brecht@mos6581.org>
|
|
* Julian Harnath <julian.harnath@rwth-aachen.de>
|
|
* Joseph Groover <looncraz@looncraz.net>
|
|
*/
|
|
|
|
|
|
/*! \class ServerWindow
|
|
|
|
The ServerWindow class handles all BWindow messaging; it forwards all
|
|
BWindow requests to the corresponding app_server classes, that is Desktop,
|
|
Window, and View.
|
|
Furthermore, it also sends app_server requests/notices to its BWindow. There
|
|
is one ServerWindow per BWindow.
|
|
*/
|
|
|
|
|
|
#include "ServerWindow.h"
|
|
|
|
#include <syslog.h>
|
|
#include <new>
|
|
|
|
#include <AppDefs.h>
|
|
#include <Autolock.h>
|
|
#include <Debug.h>
|
|
#include <DirectWindow.h>
|
|
#include <TokenSpace.h>
|
|
#include <View.h>
|
|
#include <GradientLinear.h>
|
|
#include <GradientRadial.h>
|
|
#include <GradientRadialFocus.h>
|
|
#include <GradientDiamond.h>
|
|
#include <GradientConic.h>
|
|
|
|
#include <MessagePrivate.h>
|
|
#include <PortLink.h>
|
|
#include <ShapePrivate.h>
|
|
#include <ServerProtocolStructs.h>
|
|
#include <StackOrHeapArray.h>
|
|
#include <ViewPrivate.h>
|
|
#include <WindowInfo.h>
|
|
#include <WindowPrivate.h>
|
|
|
|
#include "clipping.h"
|
|
#include "utf8_functions.h"
|
|
|
|
#include "AlphaMask.h"
|
|
#include "AppServer.h"
|
|
#include "AutoDeleter.h"
|
|
#include "BBitmapBuffer.h"
|
|
#include "BitmapManager.h"
|
|
#include "Desktop.h"
|
|
#include "DirectWindowInfo.h"
|
|
#include "DrawingEngine.h"
|
|
#include "DrawState.h"
|
|
#include "HWInterface.h"
|
|
#include "Layer.h"
|
|
#include "Overlay.h"
|
|
#include "ProfileMessageSupport.h"
|
|
#include "RenderingBuffer.h"
|
|
#include "ServerApp.h"
|
|
#include "ServerBitmap.h"
|
|
#include "ServerPicture.h"
|
|
#include "ServerProtocol.h"
|
|
#include "Window.h"
|
|
#include "WorkspacesView.h"
|
|
|
|
|
|
using std::nothrow;
|
|
|
|
|
|
//#define TRACE_SERVER_WINDOW
|
|
#ifdef TRACE_SERVER_WINDOW
|
|
# include <stdio.h>
|
|
# define STRACE(x) debug_printf x
|
|
#else
|
|
# define STRACE(x) ;
|
|
#endif
|
|
|
|
//#define TRACE_SERVER_WINDOW_MESSAGES
|
|
#ifdef TRACE_SERVER_WINDOW_MESSAGES
|
|
# include <stdio.h>
|
|
static const char* kDrawingModeMap[] = {
|
|
"B_OP_COPY",
|
|
"B_OP_OVER",
|
|
"B_OP_ERASE",
|
|
"B_OP_INVERT",
|
|
"B_OP_ADD",
|
|
"B_OP_SUBTRACT",
|
|
"B_OP_BLEND",
|
|
"B_OP_MIN",
|
|
"B_OP_MAX",
|
|
"B_OP_SELECT",
|
|
"B_OP_ALPHA",
|
|
|
|
"fix kDrawingModeMap",
|
|
"fix kDrawingModeMap",
|
|
"fix kDrawingModeMap",
|
|
"fix kDrawingModeMap",
|
|
"fix kDrawingModeMap",
|
|
};
|
|
# define DTRACE(x) debug_printf x
|
|
#else
|
|
# define DTRACE(x) ;
|
|
#endif
|
|
|
|
//#define TRACE_SERVER_GRADIENTS
|
|
#ifdef TRACE_SERVER_GRADIENTS
|
|
# include <OS.h>
|
|
# define GTRACE(x) debug_printf x
|
|
#else
|
|
# define GTRACE(x) ;
|
|
#endif
|
|
|
|
//#define PROFILE_MESSAGE_LOOP
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
struct profile { int32 code; int32 count; bigtime_t time; };
|
|
static profile sMessageProfile[AS_LAST_CODE];
|
|
static profile sRedrawProcessingTime;
|
|
//static profile sNextMessageTime;
|
|
#endif
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
static int
|
|
compare_message_profiles(const void* _a, const void* _b)
|
|
{
|
|
profile* a = (profile*)*(void**)_a;
|
|
profile* b = (profile*)*(void**)_b;
|
|
if (a->time < b->time)
|
|
return 1;
|
|
if (a->time > b->time)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
/*! Sets up the basic BWindow counterpart - you have to call Init() before
|
|
you can actually use it, though.
|
|
*/
|
|
ServerWindow::ServerWindow(const char* title, ServerApp* app,
|
|
port_id clientPort, port_id looperPort, int32 clientToken)
|
|
:
|
|
MessageLooper(title && *title ? title : "Unnamed Window"),
|
|
fTitle(NULL),
|
|
fDesktop(app->GetDesktop()),
|
|
fServerApp(app),
|
|
fWindowAddedToDesktop(false),
|
|
|
|
fClientTeam(app->ClientTeam()),
|
|
|
|
fMessagePort(-1),
|
|
fClientReplyPort(clientPort),
|
|
fClientLooperPort(looperPort),
|
|
|
|
fClientToken(clientToken),
|
|
|
|
fCurrentView(NULL),
|
|
fCurrentDrawingRegion(),
|
|
fCurrentDrawingRegionValid(false),
|
|
|
|
fIsDirectlyAccessing(false)
|
|
{
|
|
STRACE(("ServerWindow(%s)::ServerWindow()\n", title));
|
|
|
|
SetTitle(title);
|
|
fServerToken = BPrivate::gDefaultTokens.NewToken(B_SERVER_TOKEN, this);
|
|
|
|
BMessenger::Private(fFocusMessenger).SetTo(fClientTeam,
|
|
looperPort, B_PREFERRED_TOKEN);
|
|
BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
|
|
looperPort, clientToken);
|
|
|
|
fEventTarget.SetTo(fFocusMessenger);
|
|
|
|
fDeathSemaphore = create_sem(0, "window death");
|
|
}
|
|
|
|
|
|
/*! Tears down all connections the main app_server objects, and deletes some
|
|
internals.
|
|
*/
|
|
ServerWindow::~ServerWindow()
|
|
{
|
|
STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
|
|
|
|
if (!fWindow->IsOffscreenWindow()) {
|
|
fWindowAddedToDesktop = false;
|
|
fDesktop->RemoveWindow(fWindow.Get());
|
|
}
|
|
|
|
if (App() != NULL) {
|
|
App()->RemoveWindow(this);
|
|
fServerApp = NULL;
|
|
}
|
|
|
|
fWindow.Unset(); // TODO: is it really needed?
|
|
|
|
free(fTitle);
|
|
delete_port(fMessagePort);
|
|
|
|
BPrivate::gDefaultTokens.RemoveToken(fServerToken);
|
|
|
|
fDirectWindowInfo.Unset(); // TODO: is it really needed?
|
|
STRACE(("ServerWindow(%p) will exit NOW\n", this));
|
|
|
|
delete_sem(fDeathSemaphore);
|
|
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
BList profiles;
|
|
for (int32 i = 0; i < AS_LAST_CODE; i++) {
|
|
if (sMessageProfile[i].count == 0)
|
|
continue;
|
|
sMessageProfile[i].code = i;
|
|
profiles.AddItem(&sMessageProfile[i]);
|
|
}
|
|
|
|
profiles.SortItems(compare_message_profiles);
|
|
|
|
int32 count = profiles.CountItems();
|
|
for (int32 i = 0; i < count; i++) {
|
|
profile* p = (profile*)profiles.ItemAtFast(i);
|
|
printf("[%s] called %" B_PRId32 " times, %g secs (%" B_PRId64 " usecs "
|
|
"per call)\n", string_for_message_code(p->code), p->count, p->time / 1000000.0,
|
|
p->time / p->count);
|
|
}
|
|
if (sRedrawProcessingTime.count > 0) {
|
|
printf("average redraw processing time: %g secs, count: %" B_PRId32 " "
|
|
"(%" B_PRId64 " usecs per call)\n",
|
|
sRedrawProcessingTime.time / 1000000.0, sRedrawProcessingTime.count,
|
|
sRedrawProcessingTime.time / sRedrawProcessingTime.count);
|
|
}
|
|
// if (sNextMessageTime.count > 0) {
|
|
// printf("average NextMessage() time: %g secs, count: %ld (%lld usecs per call)\n",
|
|
// sNextMessageTime.time / 1000000.0, sNextMessageTime.count,
|
|
// sNextMessageTime.time / sNextMessageTime.count);
|
|
// }
|
|
#endif
|
|
}
|
|
|
|
|
|
status_t
|
|
ServerWindow::Init(BRect frame, window_look look, window_feel feel,
|
|
uint32 flags, uint32 workspace)
|
|
{
|
|
if (!App()->AddWindow(this)) {
|
|
fServerApp = NULL;
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
if (fTitle == NULL)
|
|
return B_NO_MEMORY;
|
|
|
|
// fMessagePort is the port to which the app sends messages for the server
|
|
fMessagePort = create_port(100, fTitle);
|
|
if (fMessagePort < B_OK)
|
|
return fMessagePort;
|
|
|
|
fLink.SetSenderPort(fClientReplyPort);
|
|
fLink.SetReceiverPort(fMessagePort);
|
|
|
|
// We cannot call MakeWindow in the constructor, since it
|
|
// is a virtual function!
|
|
fWindow.SetTo(MakeWindow(frame, fTitle, look, feel, flags, workspace));
|
|
if (!fWindow.IsSet() || fWindow->InitCheck() != B_OK) {
|
|
fWindow.Unset();
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
if (!fWindow->IsOffscreenWindow()) {
|
|
fDesktop->AddWindow(fWindow.Get());
|
|
fWindowAddedToDesktop = true;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
/*! Returns the ServerWindow's Window, if it exists and has been
|
|
added to the Desktop already.
|
|
In other words, you cannot assume this method will always give you
|
|
a valid pointer.
|
|
*/
|
|
Window*
|
|
ServerWindow::Window() const
|
|
{
|
|
if (!fWindowAddedToDesktop)
|
|
return NULL;
|
|
|
|
return fWindow.Get();
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::_PrepareQuit()
|
|
{
|
|
if (fThread == find_thread(NULL)) {
|
|
// make sure we're hidden
|
|
fDesktop->LockSingleWindow();
|
|
_Hide();
|
|
fDesktop->UnlockSingleWindow();
|
|
} else if (fThread >= B_OK)
|
|
PostMessage(AS_INTERNAL_HIDE_WINDOW);
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::_GetLooperName(char* name, size_t length)
|
|
{
|
|
const char *title = Title();
|
|
if (title == NULL || !title[0])
|
|
title = "Unnamed Window";
|
|
|
|
snprintf(name, length, "w:%" B_PRId32 ":%s", ClientTeam(), title);
|
|
}
|
|
|
|
|
|
/*! Shows the window's Window.
|
|
*/
|
|
void
|
|
ServerWindow::_Show()
|
|
{
|
|
// NOTE: if you do something else, other than sending a port message, PLEASE lock
|
|
STRACE(("ServerWindow %s: _Show\n", Title()));
|
|
|
|
if (fQuitting || fWindow->IsMinimized() || !fWindow->IsHidden()
|
|
|| fWindow->IsOffscreenWindow() || fWindow->TopView() == NULL)
|
|
return;
|
|
|
|
// TODO: Maybe we need to dispatch a message to the desktop to show/hide us
|
|
// instead of doing it from this thread.
|
|
fDesktop->UnlockSingleWindow();
|
|
fDesktop->ShowWindow(fWindow.Get());
|
|
if (fDirectWindowInfo.IsSet() && fDirectWindowInfo->IsFullScreen())
|
|
_ResizeToFullScreen();
|
|
|
|
fDesktop->LockSingleWindow();
|
|
}
|
|
|
|
|
|
/*! Hides the window's Window. You need to have all windows locked when
|
|
calling this function.
|
|
*/
|
|
void
|
|
ServerWindow::_Hide()
|
|
{
|
|
STRACE(("ServerWindow %s: _Hide\n", Title()));
|
|
|
|
if (fWindow->IsHidden() || fWindow->IsOffscreenWindow())
|
|
return;
|
|
|
|
fDesktop->UnlockSingleWindow();
|
|
fDesktop->HideWindow(fWindow.Get());
|
|
fDesktop->LockSingleWindow();
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::RequestRedraw()
|
|
{
|
|
PostMessage(AS_REDRAW, 0);
|
|
// we don't care if this fails - it's only a notification, and if
|
|
// it fails, there are obviously enough messages in the queue
|
|
// already
|
|
|
|
atomic_add(&fRedrawRequested, 1);
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::SetTitle(const char* newTitle)
|
|
{
|
|
char* oldTitle = fTitle;
|
|
|
|
if (newTitle == NULL)
|
|
newTitle = "";
|
|
|
|
fTitle = strdup(newTitle);
|
|
if (fTitle == NULL) {
|
|
// out of memory condition
|
|
fTitle = oldTitle;
|
|
return;
|
|
}
|
|
|
|
free(oldTitle);
|
|
|
|
if (Thread() >= B_OK) {
|
|
char name[B_OS_NAME_LENGTH];
|
|
_GetLooperName(name, sizeof(name));
|
|
rename_thread(Thread(), name);
|
|
}
|
|
|
|
if (fWindow.IsSet())
|
|
fDesktop->SetWindowTitle(fWindow.Get(), newTitle);
|
|
}
|
|
|
|
|
|
//! Requests that the ServerWindow's BWindow quit
|
|
void
|
|
ServerWindow::NotifyQuitRequested()
|
|
{
|
|
// NOTE: if you do something else, other than sending a port message,
|
|
// PLEASE lock
|
|
STRACE(("ServerWindow %s: Quit\n", fTitle));
|
|
|
|
BMessage msg(B_QUIT_REQUESTED);
|
|
SendMessageToClient(&msg);
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::NotifyMinimize(bool minimize)
|
|
{
|
|
if (fWindow->Feel() != B_NORMAL_WINDOW_FEEL)
|
|
return;
|
|
|
|
// The client is responsible for the actual minimization
|
|
|
|
BMessage msg(B_MINIMIZE);
|
|
msg.AddInt64("when", real_time_clock_usecs());
|
|
msg.AddBool("minimize", minimize);
|
|
|
|
SendMessageToClient(&msg);
|
|
}
|
|
|
|
|
|
//! Sends a message to the client to perform a Zoom
|
|
void
|
|
ServerWindow::NotifyZoom()
|
|
{
|
|
// NOTE: if you do something else, other than sending a port message,
|
|
// PLEASE lock
|
|
BMessage msg(B_ZOOM);
|
|
SendMessageToClient(&msg);
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::GetInfo(window_info& info)
|
|
{
|
|
info.team = ClientTeam();
|
|
info.server_token = ServerToken();
|
|
|
|
info.thread = Thread();
|
|
info.client_token = ClientToken();
|
|
info.client_port = fClientLooperPort;
|
|
info.workspaces = fWindow->Workspaces();
|
|
|
|
// logic taken from Switcher comments and experiments
|
|
if (fWindow->IsHidden())
|
|
info.layer = 0;
|
|
else if (fWindow->IsVisible()) {
|
|
if (fWindow->Feel() == kDesktopWindowFeel)
|
|
info.layer = 2;
|
|
else if (fWindow->IsFloating() || fWindow->IsModal())
|
|
info.layer = 4;
|
|
else
|
|
info.layer = 3;
|
|
} else
|
|
info.layer = 1;
|
|
|
|
info.feel = fWindow->Feel();
|
|
info.flags = fWindow->Flags();
|
|
info.window_left = (int)floor(fWindow->Frame().left);
|
|
info.window_top = (int)floor(fWindow->Frame().top);
|
|
info.window_right = (int)floor(fWindow->Frame().right);
|
|
info.window_bottom = (int)floor(fWindow->Frame().bottom);
|
|
|
|
info.show_hide_level = fWindow->ShowLevel();
|
|
info.is_mini = fWindow->IsMinimized();
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::ResyncDrawState()
|
|
{
|
|
_UpdateDrawState(fCurrentView);
|
|
}
|
|
|
|
|
|
View*
|
|
ServerWindow::_CreateView(BPrivate::LinkReceiver& link, View** _parent)
|
|
{
|
|
// NOTE: no need to check for a lock. This is a private method.
|
|
|
|
int32 token;
|
|
BRect frame;
|
|
uint32 resizeMask;
|
|
uint32 eventMask;
|
|
uint32 eventOptions;
|
|
uint32 flags;
|
|
bool hidden;
|
|
int32 parentToken;
|
|
char* name = NULL;
|
|
rgb_color viewColor;
|
|
BPoint scrollingOffset;
|
|
|
|
link.Read<int32>(&token);
|
|
link.ReadString(&name);
|
|
link.Read<BRect>(&frame);
|
|
link.Read<BPoint>(&scrollingOffset);
|
|
link.Read<uint32>(&resizeMask);
|
|
link.Read<uint32>(&eventMask);
|
|
link.Read<uint32>(&eventOptions);
|
|
link.Read<uint32>(&flags);
|
|
link.Read<bool>(&hidden);
|
|
link.Read<rgb_color>(&viewColor);
|
|
link.Read<int32>(&parentToken);
|
|
|
|
STRACE(("ServerWindow(%s)::_CreateView()-> view %s, token %" B_PRId32 "\n",
|
|
fTitle, name, token));
|
|
|
|
View* newView;
|
|
|
|
if ((flags & kWorkspacesViewFlag) != 0) {
|
|
newView = new (nothrow) WorkspacesView(frame, scrollingOffset, name,
|
|
token, resizeMask, flags);
|
|
} else {
|
|
newView = new (nothrow) View(frame, scrollingOffset, name, token,
|
|
resizeMask, flags);
|
|
}
|
|
|
|
free(name);
|
|
|
|
if (newView == NULL)
|
|
return NULL;
|
|
|
|
if (newView->InitCheck() != B_OK) {
|
|
delete newView;
|
|
return NULL;
|
|
}
|
|
|
|
// there is no way of setting this, other than manually :-)
|
|
newView->SetViewColor(viewColor);
|
|
newView->SetHidden(hidden);
|
|
newView->SetEventMask(eventMask, eventOptions);
|
|
|
|
if (eventMask != 0 || eventOptions != 0) {
|
|
// fDesktop->UnlockSingleWindow();
|
|
// fDesktop->LockAllWindows();
|
|
fDesktop->UnlockAllWindows();
|
|
// TODO: possible deadlock
|
|
fDesktop->EventDispatcher().AddListener(EventTarget(),
|
|
newView->Token(), eventMask, eventOptions);
|
|
fDesktop->LockAllWindows();
|
|
// fDesktop->UnlockAllWindows();
|
|
// fDesktop->LockSingleWindow();
|
|
}
|
|
|
|
// Initialize the view with the current application plain font.
|
|
// NOTE: This might be out of sync with the global app_server plain
|
|
// font, but that is so on purpose! The client needs to resync itself
|
|
// with the app_server fonts upon notification, but if we just use
|
|
// the current font here, the be_plain_font on the client may still
|
|
// hold old values. So this needs to be an update initiated by the
|
|
// client application.
|
|
newView->CurrentState()->SetFont(App()->PlainFont());
|
|
|
|
if (_parent) {
|
|
View *parent;
|
|
if (App()->ViewTokens().GetToken(parentToken, B_HANDLER_TOKEN,
|
|
(void**)&parent) != B_OK
|
|
|| parent->Window()->ServerWindow() != this) {
|
|
debug_printf("View token not found!\n");
|
|
parent = NULL;
|
|
}
|
|
|
|
*_parent = parent;
|
|
}
|
|
|
|
return newView;
|
|
}
|
|
|
|
|
|
/*! Dispatches all window messages, and those view messages that
|
|
don't need a valid fCurrentView (ie. view creation).
|
|
*/
|
|
void
|
|
ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
|
|
{
|
|
switch (code) {
|
|
case AS_SHOW_OR_HIDE_WINDOW:
|
|
{
|
|
int32 showLevel;
|
|
if (link.Read<int32>(&showLevel) == B_OK) {
|
|
DTRACE(("ServerWindow %s: Message AS_SHOW_OR_HIDE_WINDOW, "
|
|
"show level: %" B_PRId32 "\n", Title(), showLevel));
|
|
|
|
fWindow->SetShowLevel(showLevel);
|
|
if (showLevel <= 0)
|
|
_Show();
|
|
else
|
|
_Hide();
|
|
}
|
|
break;
|
|
}
|
|
// Only for internal use within this class
|
|
case AS_INTERNAL_HIDE_WINDOW:
|
|
_Hide();
|
|
break;
|
|
case AS_MINIMIZE_WINDOW:
|
|
{
|
|
bool minimize;
|
|
if (link.Read<bool>(&minimize) == B_OK) {
|
|
DTRACE(("ServerWindow %s: Message AS_MINIMIZE_WINDOW, "
|
|
"minimize: %d\n", Title(), minimize));
|
|
|
|
fDesktop->UnlockSingleWindow();
|
|
fDesktop->MinimizeWindow(fWindow.Get(), minimize);
|
|
fDesktop->LockSingleWindow();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_ACTIVATE_WINDOW:
|
|
{
|
|
bool activate = true;
|
|
if (link.Read<bool>(&activate) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: activate: "
|
|
"%d\n", Title(), activate));
|
|
|
|
fDesktop->UnlockSingleWindow();
|
|
|
|
if (activate)
|
|
fDesktop->SelectWindow(fWindow.Get());
|
|
else
|
|
fDesktop->SendWindowBehind(fWindow.Get(), NULL);
|
|
|
|
fDesktop->LockSingleWindow();
|
|
break;
|
|
}
|
|
case AS_SEND_BEHIND:
|
|
{
|
|
// Has the all-window lock
|
|
int32 token;
|
|
team_id teamID;
|
|
status_t status = B_ERROR;
|
|
|
|
link.Read<int32>(&token);
|
|
if (link.Read<team_id>(&teamID) == B_OK) {
|
|
::Window* behindOf = fDesktop->FindWindowByClientToken(token,
|
|
teamID);
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_SEND_BEHIND %s\n",
|
|
Title(), behindOf != NULL ? behindOf->Title() : "NULL"));
|
|
|
|
if (behindOf != NULL || token == -1) {
|
|
fDesktop->SendWindowBehind(fWindow.Get(), behindOf);
|
|
status = B_OK;
|
|
} else
|
|
status = B_NAME_NOT_FOUND;
|
|
}
|
|
|
|
fLink.StartMessage(status);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
|
|
case B_QUIT_REQUESTED:
|
|
DTRACE(("ServerWindow %s received quit request\n", Title()));
|
|
NotifyQuitRequested();
|
|
break;
|
|
|
|
case AS_ENABLE_UPDATES:
|
|
DTRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES\n", Title()));
|
|
fWindow->EnableUpdateRequests();
|
|
break;
|
|
|
|
case AS_DISABLE_UPDATES:
|
|
DTRACE(("ServerWindow %s: Message AS_DISABLE_UPDATES\n", Title()));
|
|
fWindow->DisableUpdateRequests();
|
|
break;
|
|
|
|
case AS_NEEDS_UPDATE:
|
|
DTRACE(("ServerWindow %s: Message AS_NEEDS_UPDATE: %d\n",
|
|
Title(), fWindow->NeedsUpdate()));
|
|
if (fWindow->NeedsUpdate())
|
|
fLink.StartMessage(B_OK);
|
|
else
|
|
fLink.StartMessage(B_ERROR);
|
|
fLink.Flush();
|
|
break;
|
|
|
|
case AS_SET_WINDOW_TITLE:
|
|
{
|
|
char* newTitle;
|
|
if (link.ReadString(&newTitle) == B_OK) {
|
|
DTRACE(("ServerWindow %s: Message AS_SET_WINDOW_TITLE: %s\n",
|
|
Title(), newTitle));
|
|
|
|
SetTitle(newTitle);
|
|
free(newTitle);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_ADD_TO_SUBSET:
|
|
{
|
|
// Has the all-window lock
|
|
DTRACE(("ServerWindow %s: Message AS_ADD_TO_SUBSET\n", Title()));
|
|
status_t status = B_ERROR;
|
|
|
|
int32 token;
|
|
if (link.Read<int32>(&token) == B_OK) {
|
|
::Window* window = fDesktop->FindWindowByClientToken(token,
|
|
App()->ClientTeam());
|
|
if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL) {
|
|
status = B_BAD_VALUE;
|
|
} else {
|
|
status = fDesktop->AddWindowToSubset(fWindow.Get(), window)
|
|
? B_OK : B_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
fLink.StartMessage(status);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_REMOVE_FROM_SUBSET:
|
|
{
|
|
// Has the all-window lock
|
|
DTRACE(("ServerWindow %s: Message AS_REM_FROM_SUBSET\n", Title()));
|
|
status_t status = B_ERROR;
|
|
|
|
int32 token;
|
|
if (link.Read<int32>(&token) == B_OK) {
|
|
::Window* window = fDesktop->FindWindowByClientToken(token,
|
|
App()->ClientTeam());
|
|
if (window != NULL) {
|
|
fDesktop->RemoveWindowFromSubset(fWindow.Get(), window);
|
|
status = B_OK;
|
|
} else
|
|
status = B_BAD_VALUE;
|
|
}
|
|
|
|
fLink.StartMessage(status);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
|
|
case AS_SET_LOOK:
|
|
{
|
|
// Has the all-window look
|
|
DTRACE(("ServerWindow %s: Message AS_SET_LOOK\n", Title()));
|
|
|
|
status_t status = B_ERROR;
|
|
int32 look;
|
|
if (link.Read<int32>(&look) == B_OK) {
|
|
// test if look is valid
|
|
status = Window::IsValidLook((window_look)look)
|
|
? B_OK : B_BAD_VALUE;
|
|
}
|
|
|
|
if (status == B_OK && !fWindow->IsOffscreenWindow())
|
|
fDesktop->SetWindowLook(fWindow.Get(), (window_look)look);
|
|
|
|
fLink.StartMessage(status);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_SET_FEEL:
|
|
{
|
|
// Has the all-window look
|
|
DTRACE(("ServerWindow %s: Message AS_SET_FEEL\n", Title()));
|
|
|
|
status_t status = B_ERROR;
|
|
int32 feel;
|
|
if (link.Read<int32>(&feel) == B_OK) {
|
|
// test if feel is valid
|
|
status = Window::IsValidFeel((window_feel)feel)
|
|
? B_OK : B_BAD_VALUE;
|
|
}
|
|
|
|
if (status == B_OK && !fWindow->IsOffscreenWindow())
|
|
fDesktop->SetWindowFeel(fWindow.Get(), (window_feel)feel);
|
|
|
|
fLink.StartMessage(status);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_SET_FLAGS:
|
|
{
|
|
// Has the all-window look
|
|
DTRACE(("ServerWindow %s: Message AS_SET_FLAGS\n", Title()));
|
|
|
|
status_t status = B_ERROR;
|
|
uint32 flags;
|
|
if (link.Read<uint32>(&flags) == B_OK) {
|
|
// test if flags are valid
|
|
status = (flags & ~Window::ValidWindowFlags()) == 0
|
|
? B_OK : B_BAD_VALUE;
|
|
}
|
|
|
|
if (status == B_OK && !fWindow->IsOffscreenWindow())
|
|
fDesktop->SetWindowFlags(fWindow.Get(), flags);
|
|
|
|
fLink.StartMessage(status);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
#if 0
|
|
case AS_SET_ALIGNMENT:
|
|
{
|
|
// TODO: Implement AS_SET_ALIGNMENT
|
|
DTRACE(("ServerWindow %s: Message Set_Alignment unimplemented\n",
|
|
Title()));
|
|
break;
|
|
}
|
|
case AS_GET_ALIGNMENT:
|
|
{
|
|
// TODO: Implement AS_GET_ALIGNMENT
|
|
DTRACE(("ServerWindow %s: Message Get_Alignment unimplemented\n",
|
|
Title()));
|
|
break;
|
|
}
|
|
#endif
|
|
case AS_IS_FRONT_WINDOW:
|
|
{
|
|
bool isFront = fDesktop->FrontWindow() == fWindow.Get();
|
|
DTRACE(("ServerWindow %s: Message AS_IS_FRONT_WINDOW: %d\n",
|
|
Title(), isFront));
|
|
fLink.StartMessage(isFront ? B_OK : B_ERROR);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
|
|
case AS_GET_WORKSPACES:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_GET_WORKSPACES\n", Title()));
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<uint32>(fWindow->Workspaces());
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_SET_WORKSPACES:
|
|
{
|
|
// Has the all-window lock (but would actually not need to lock at
|
|
// all)
|
|
uint32 newWorkspaces;
|
|
if (link.Read<uint32>(&newWorkspaces) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %" B_PRIx32 "\n",
|
|
Title(), newWorkspaces));
|
|
|
|
fDesktop->SetWindowWorkspaces(fWindow.Get(), newWorkspaces);
|
|
break;
|
|
}
|
|
case AS_WINDOW_RESIZE:
|
|
{
|
|
// Has the all-window look
|
|
float xResizeTo;
|
|
float yResizeTo;
|
|
link.Read<float>(&xResizeTo);
|
|
if (link.Read<float>(&yResizeTo) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_WINDOW_RESIZE %.1f, %.1f\n",
|
|
Title(), xResizeTo, yResizeTo));
|
|
|
|
// comment this code for the time being, as some apps rely
|
|
// on the programmatically resize behavior during user resize
|
|
// if (fWindow->IsResizing()) {
|
|
// While the user resizes the window, we ignore
|
|
// pragmatically set window bounds
|
|
// fLink.StartMessage(B_BUSY);
|
|
// } else {
|
|
fDesktop->ResizeWindowBy(fWindow.Get(),
|
|
xResizeTo - fWindow->Frame().Width(),
|
|
yResizeTo - fWindow->Frame().Height());
|
|
fLink.StartMessage(B_OK);
|
|
// }
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_WINDOW_MOVE:
|
|
{
|
|
// Has the all-window look
|
|
float xMoveTo;
|
|
float yMoveTo;
|
|
link.Read<float>(&xMoveTo);
|
|
if (link.Read<float>(&yMoveTo) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_WINDOW_MOVE: %.1f, %.1f\n",
|
|
Title(), xMoveTo, yMoveTo));
|
|
|
|
if (fWindow->IsDragging()) {
|
|
// While the user moves the window, we ignore
|
|
// pragmatically set window positions
|
|
fLink.StartMessage(B_BUSY);
|
|
} else {
|
|
fDesktop->MoveWindowBy(fWindow.Get(),
|
|
xMoveTo - fWindow->Frame().left,
|
|
yMoveTo - fWindow->Frame().top);
|
|
fLink.StartMessage(B_OK);
|
|
}
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_SET_SIZE_LIMITS:
|
|
{
|
|
// Has the all-window look
|
|
|
|
// Attached Data:
|
|
// 1) float minimum width
|
|
// 2) float maximum width
|
|
// 3) float minimum height
|
|
// 4) float maximum height
|
|
|
|
// TODO: for now, move the client to int32 as well!
|
|
int32 minWidth, maxWidth, minHeight, maxHeight;
|
|
float value;
|
|
link.Read<float>(&value); minWidth = (int32)value;
|
|
link.Read<float>(&value); maxWidth = (int32)value;
|
|
link.Read<float>(&value); minHeight = (int32)value;
|
|
link.Read<float>(&value); maxHeight = (int32)value;
|
|
/*
|
|
link.Read<int32>(&minWidth);
|
|
link.Read<int32>(&maxWidth);
|
|
link.Read<int32>(&minHeight);
|
|
link.Read<int32>(&maxHeight);
|
|
*/
|
|
DTRACE(("ServerWindow %s: Message AS_SET_SIZE_LIMITS: "
|
|
"x: %" B_PRId32 "-%" B_PRId32 ", y: %" B_PRId32 "-%" B_PRId32
|
|
"\n", Title(), minWidth, maxWidth, minHeight, maxHeight));
|
|
|
|
fWindow->SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
|
|
|
|
// and now, sync the client to the limits that we were able to enforce
|
|
fWindow->GetSizeLimits(&minWidth, &maxWidth,
|
|
&minHeight, &maxHeight);
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<BRect>(fWindow->Frame());
|
|
fLink.Attach<float>((float)minWidth);
|
|
fLink.Attach<float>((float)maxWidth);
|
|
fLink.Attach<float>((float)minHeight);
|
|
fLink.Attach<float>((float)maxHeight);
|
|
|
|
fLink.Flush();
|
|
|
|
fDesktop->NotifySizeLimitsChanged(fWindow.Get(), minWidth, maxWidth,
|
|
minHeight, maxHeight);
|
|
break;
|
|
}
|
|
|
|
case AS_SET_DECORATOR_SETTINGS:
|
|
{
|
|
// Has the all-window look
|
|
DTRACE(("ServerWindow %s: Message AS_SET_DECORATOR_SETTINGS\n",
|
|
Title()));
|
|
|
|
int32 size;
|
|
if (fWindow.IsSet() && link.Read<int32>(&size) == B_OK) {
|
|
char buffer[size];
|
|
if (link.Read(buffer, size) == B_OK) {
|
|
BMessage settings;
|
|
if (settings.Unflatten(buffer) == B_OK)
|
|
fDesktop->SetWindowDecoratorSettings(
|
|
fWindow.Get(), settings);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_GET_DECORATOR_SETTINGS:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_GET_DECORATOR_SETTINGS\n",
|
|
Title()));
|
|
|
|
bool success = false;
|
|
|
|
BMessage settings;
|
|
if (fWindow->GetDecoratorSettings(&settings)) {
|
|
int32 size = settings.FlattenedSize();
|
|
char buffer[size];
|
|
if (settings.Flatten(buffer, size) == B_OK) {
|
|
success = true;
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<int32>(size);
|
|
fLink.Attach(buffer, size);
|
|
}
|
|
}
|
|
|
|
if (!success)
|
|
fLink.StartMessage(B_ERROR);
|
|
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
|
|
case AS_SYSTEM_FONT_CHANGED:
|
|
{
|
|
// Has the all-window look
|
|
fDesktop->FontsChanged(fWindow.Get());
|
|
break;
|
|
}
|
|
|
|
// Forward to client
|
|
case B_FONTS_UPDATED:
|
|
{
|
|
// TODO: would knowing which font was changed be useful?
|
|
BMessage message(code);
|
|
SendMessageToClient(&message);
|
|
break;
|
|
}
|
|
|
|
case AS_REDRAW:
|
|
// Nothing to do here - the redraws are actually handled by looking
|
|
// at the fRedrawRequested member variable in _MessageLooper().
|
|
break;
|
|
|
|
case AS_SYNC:
|
|
DTRACE(("ServerWindow %s: Message AS_SYNC\n", Title()));
|
|
// the synchronisation works by the fact that the client
|
|
// window is waiting for this reply, after having received it,
|
|
// client and server queues are in sync (earlier, the client
|
|
// may have pushed drawing commands at the server and now it
|
|
// knows they have all been carried out)
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Flush();
|
|
break;
|
|
|
|
case AS_BEGIN_UPDATE:
|
|
DTRACE(("ServerWindow %s: Message AS_BEGIN_UPDATE\n", Title()));
|
|
fWindow->BeginUpdate(fLink);
|
|
break;
|
|
|
|
case AS_END_UPDATE:
|
|
DTRACE(("ServerWindow %s: Message AS_END_UPDATE\n", Title()));
|
|
fWindow->EndUpdate();
|
|
break;
|
|
|
|
case AS_GET_MOUSE:
|
|
{
|
|
// Has the all-window look
|
|
DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
|
|
|
|
// Returns
|
|
// 1) BPoint mouse location
|
|
// 2) int32 button state
|
|
|
|
BPoint where;
|
|
int32 buttons;
|
|
fDesktop->GetLastMouseState(&where, &buttons);
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<BPoint>(where);
|
|
fLink.Attach<int32>(buttons);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
|
|
// BDirectWindow communication
|
|
|
|
case AS_DIRECT_WINDOW_GET_SYNC_DATA:
|
|
{
|
|
status_t status = _EnableDirectWindowMode();
|
|
|
|
fLink.StartMessage(status);
|
|
if (status == B_OK) {
|
|
struct direct_window_sync_data syncData;
|
|
fDirectWindowInfo->GetSyncData(syncData);
|
|
|
|
fLink.Attach(&syncData, sizeof(syncData));
|
|
}
|
|
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_DIRECT_WINDOW_SET_FULLSCREEN:
|
|
{
|
|
// Has the all-window look
|
|
bool enable;
|
|
link.Read<bool>(&enable);
|
|
|
|
status_t status = B_OK;
|
|
if (fDirectWindowInfo.IsSet())
|
|
_DirectWindowSetFullScreen(enable);
|
|
else
|
|
status = B_BAD_TYPE;
|
|
|
|
fLink.StartMessage(status);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
|
|
// View creation and destruction (don't need a valid fCurrentView)
|
|
|
|
case AS_SET_CURRENT_VIEW:
|
|
{
|
|
int32 token;
|
|
if (link.Read<int32>(&token) != B_OK)
|
|
break;
|
|
|
|
View *current;
|
|
if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
|
|
(void**)¤t) != B_OK
|
|
|| current->Window()->ServerWindow() != this) {
|
|
// TODO: if this happens, we probably want to kill the app and
|
|
// clean up
|
|
debug_printf("ServerWindow %s: Message "
|
|
"\n\n\nAS_SET_CURRENT_VIEW: view not found, token %"
|
|
B_PRId32 "\n", fTitle, token);
|
|
current = NULL;
|
|
} else {
|
|
DTRACE(("\n\n\nServerWindow %s: Message AS_SET_CURRENT_VIEW: %s, "
|
|
"token %" B_PRId32 "\n", fTitle, current->Name(), token));
|
|
_SetCurrentView(current);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_CREATE_ROOT:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE_ROOT\n", fTitle));
|
|
|
|
// Start receiving top_view data -- pass NULL as the parent view.
|
|
// This should be the *only* place where this happens.
|
|
if (fCurrentView != NULL) {
|
|
debug_printf("ServerWindow %s: Message "
|
|
"AS_VIEW_CREATE_ROOT: fCurrentView already set!!\n",
|
|
fTitle);
|
|
break;
|
|
}
|
|
|
|
_SetCurrentView(_CreateView(link, NULL));
|
|
fWindow->SetTopView(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_CREATE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE: View name: "
|
|
"%s\n", fTitle, fCurrentView->Name()));
|
|
|
|
View* parent = NULL;
|
|
View* newView = _CreateView(link, &parent);
|
|
if (parent != NULL && newView != NULL)
|
|
parent->AddChild(newView);
|
|
else {
|
|
delete newView;
|
|
debug_printf("ServerWindow %s: Message AS_VIEW_CREATE: "
|
|
"parent or newView NULL!!\n", fTitle);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_TALK_TO_DESKTOP_LISTENER:
|
|
{
|
|
if (fDesktop->MessageForListener(fWindow.Get(), fLink.Receiver(),
|
|
fLink.Sender()))
|
|
break;
|
|
// unhandled message at least send an error if needed
|
|
if (link.NeedsReply()) {
|
|
fLink.StartMessage(B_ERROR);
|
|
fLink.Flush();
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
if (fCurrentView == NULL) {
|
|
debug_printf("ServerWindow %s received unexpected code - "
|
|
"message '%s' before top_view attached.\n",
|
|
Title(), string_for_message_code(code));
|
|
if (link.NeedsReply()) {
|
|
fLink.StartMessage(B_ERROR);
|
|
fLink.Flush();
|
|
}
|
|
return;
|
|
}
|
|
|
|
_DispatchViewMessage(code, link);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
Dispatches all view messages that need a valid fCurrentView.
|
|
*/
|
|
void
|
|
ServerWindow::_DispatchViewMessage(int32 code,
|
|
BPrivate::LinkReceiver &link)
|
|
{
|
|
if (_DispatchPictureMessage(code, link))
|
|
return;
|
|
|
|
switch (code) {
|
|
case AS_VIEW_SCROLL:
|
|
{
|
|
float dh;
|
|
float dv;
|
|
link.Read<float>(&dh);
|
|
if (link.Read<float>(&dv) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SCROLL: View name: "
|
|
"%s, %.1f x %.1f\n", fTitle, fCurrentView->Name(), dh, dv));
|
|
fWindow->ScrollViewBy(fCurrentView, dh, dv);
|
|
break;
|
|
}
|
|
case AS_VIEW_COPY_BITS:
|
|
{
|
|
BRect src;
|
|
BRect dst;
|
|
|
|
link.Read<BRect>(&src);
|
|
if (link.Read<BRect>(&dst) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_COPY_BITS: View name: "
|
|
"%s, BRect(%.1f, %.1f, %.1f, %.1f) -> "
|
|
"BRect(%.1f, %.1f, %.1f, %.1f)\n", fTitle,
|
|
fCurrentView->Name(), src.left, src.top, src.right, src.bottom,
|
|
dst.left, dst.top, dst.right, dst.bottom));
|
|
|
|
BRegion contentRegion;
|
|
// TODO: avoid copy operation maybe?
|
|
fWindow->GetContentRegion(&contentRegion);
|
|
fCurrentView->CopyBits(src, dst, contentRegion);
|
|
break;
|
|
}
|
|
case AS_VIEW_DELETE:
|
|
{
|
|
// Received when a view is detached from a window
|
|
|
|
int32 token;
|
|
if (link.Read<int32>(&token) != B_OK)
|
|
break;
|
|
|
|
View *view;
|
|
if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
|
|
(void**)&view) == B_OK
|
|
&& view->Window()->ServerWindow() == this) {
|
|
View* parent = view->Parent();
|
|
|
|
DTRACE(("ServerWindow %s: AS_VIEW_DELETE view: %p, "
|
|
"parent: %p\n", fTitle, view, parent));
|
|
|
|
if (parent != NULL) {
|
|
parent->RemoveChild(view);
|
|
|
|
if (view->EventMask() != 0) {
|
|
// TODO: possible deadlock (event dispatcher already
|
|
// locked itself, waits for Desktop write lock, but
|
|
// we have it, now we are trying to lock the event
|
|
// dispatcher -> deadlock)
|
|
fDesktop->UnlockSingleWindow();
|
|
fDesktop->EventDispatcher().RemoveListener(
|
|
EventTarget(), token);
|
|
fDesktop->LockSingleWindow();
|
|
}
|
|
|
|
if (fCurrentView == view || fCurrentView->HasParent(view))
|
|
_SetCurrentView(parent);
|
|
|
|
delete view;
|
|
} // else we don't delete the root view
|
|
}
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_STATE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_STATE: "
|
|
"View name: %s\n", fTitle, fCurrentView->Name()));
|
|
|
|
fCurrentView->CurrentState()->ReadFromLink(link);
|
|
// TODO: When is this used?!?
|
|
fCurrentView->RebuildClipping(true);
|
|
_UpdateDrawState(fCurrentView);
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_FONT_STATE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FONT_STATE: "
|
|
"View name: %s\n", fTitle, fCurrentView->Name()));
|
|
|
|
fCurrentView->CurrentState()->ReadFontFromLink(link);
|
|
fWindow->GetDrawingEngine()->SetFont(
|
|
fCurrentView->CurrentState());
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_STATE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_STATE: "
|
|
"View name: %s\n", fTitle, fCurrentView->Name()));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
|
|
// attach state data
|
|
fCurrentView->CurrentState()->WriteToLink(fLink.Sender());
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_EVENT_MASK:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_EVENT_MASK: "
|
|
"View name: %s\n", fTitle, fCurrentView->Name()));
|
|
uint32 eventMask, options;
|
|
|
|
link.Read<uint32>(&eventMask);
|
|
if (link.Read<uint32>(&options) == B_OK) {
|
|
fCurrentView->SetEventMask(eventMask, options);
|
|
|
|
fDesktop->UnlockSingleWindow();
|
|
// TODO: possible deadlock!
|
|
if (eventMask != 0 || options != 0) {
|
|
fDesktop->EventDispatcher().AddListener(EventTarget(),
|
|
fCurrentView->Token(), eventMask, options);
|
|
} else {
|
|
fDesktop->EventDispatcher().RemoveListener(EventTarget(),
|
|
fCurrentView->Token());
|
|
}
|
|
fDesktop->LockSingleWindow();
|
|
}
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_MOUSE_EVENT_MASK:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_MOUSE_EVENT_MASK: "
|
|
"View name: %s\n", fTitle, fCurrentView->Name()));
|
|
uint32 eventMask, options;
|
|
|
|
link.Read<uint32>(&eventMask);
|
|
if (link.Read<uint32>(&options) == B_OK) {
|
|
fDesktop->UnlockSingleWindow();
|
|
// TODO: possible deadlock
|
|
if (eventMask != 0 || options != 0) {
|
|
if (options & B_LOCK_WINDOW_FOCUS)
|
|
fDesktop->SetFocusLocked(fWindow.Get());
|
|
fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
|
|
fCurrentView->Token(), eventMask, options);
|
|
} else {
|
|
fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
|
|
fCurrentView->Token());
|
|
}
|
|
fDesktop->LockSingleWindow();
|
|
}
|
|
|
|
// TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
|
|
break;
|
|
}
|
|
case AS_VIEW_MOVE_TO:
|
|
{
|
|
float x, y;
|
|
link.Read<float>(&x);
|
|
if (link.Read<float>(&y) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_MOVE_TO: View name: "
|
|
"%s, x: %.1f, y: %.1f\n", fTitle, fCurrentView->Name(), x, y));
|
|
|
|
float offsetX = x - fCurrentView->Frame().left;
|
|
float offsetY = y - fCurrentView->Frame().top;
|
|
|
|
BRegion dirty;
|
|
fCurrentView->MoveBy(offsetX, offsetY, &dirty);
|
|
|
|
// TODO: think about how to avoid this hack:
|
|
// the parent clipping needs to be updated, it is not
|
|
// done in MoveBy() since it would cause
|
|
// too much computations when children are resized because
|
|
// follow modes
|
|
if (View* parent = fCurrentView->Parent())
|
|
parent->RebuildClipping(false);
|
|
|
|
fWindow->MarkContentDirty(dirty);
|
|
break;
|
|
}
|
|
case AS_VIEW_RESIZE_TO:
|
|
{
|
|
float newWidth, newHeight;
|
|
link.Read<float>(&newWidth);
|
|
if (link.Read<float>(&newHeight) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_TO: View name: "
|
|
"%s, width: %.1f, height: %.1f\n", fTitle,
|
|
fCurrentView->Name(), newWidth, newHeight));
|
|
|
|
float deltaWidth = newWidth - fCurrentView->Frame().Width();
|
|
float deltaHeight = newHeight - fCurrentView->Frame().Height();
|
|
|
|
BRegion dirty;
|
|
fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty);
|
|
|
|
// TODO: see above
|
|
if (View* parent = fCurrentView->Parent())
|
|
parent->RebuildClipping(false);
|
|
|
|
fWindow->MarkContentDirty(dirty);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_COORD:
|
|
{
|
|
// our offset in the parent -> will be originX and originY
|
|
// in BView
|
|
BPoint parentOffset = fCurrentView->Frame().LeftTop();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_COORD: "
|
|
"View: %s -> x: %.1f, y: %.1f\n", Title(),
|
|
fCurrentView->Name(), parentOffset.x, parentOffset.y));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<BPoint>(parentOffset);
|
|
fLink.Attach<BRect>(fCurrentView->Bounds());
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_ORIGIN:
|
|
{
|
|
float x, y;
|
|
link.Read<float>(&x);
|
|
if (link.Read<float>(&y) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_ORIGIN: "
|
|
"View: %s -> x: %.1f, y: %.1f\n", Title(),
|
|
fCurrentView->Name(), x, y));
|
|
|
|
fCurrentView->SetDrawingOrigin(BPoint(x, y));
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_ORIGIN:
|
|
{
|
|
BPoint drawingOrigin = fCurrentView->DrawingOrigin();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_ORIGIN: "
|
|
"View: %s -> x: %.1f, y: %.1f\n", Title(),
|
|
fCurrentView->Name(), drawingOrigin.x, drawingOrigin.y));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<BPoint>(drawingOrigin);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_RESIZE_MODE:
|
|
{
|
|
uint32 resizeMode;
|
|
if (link.Read<uint32>(&resizeMode) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_MODE: "
|
|
"View: %s -> %" B_PRId32 "\n", Title(), fCurrentView->Name(),
|
|
resizeMode));
|
|
|
|
fCurrentView->SetResizeMode(resizeMode);
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_FLAGS:
|
|
{
|
|
uint32 flags;
|
|
link.Read<uint32>(&flags);
|
|
|
|
// The views clipping changes when the B_DRAW_ON_CHILDREN flag is
|
|
// toggled.
|
|
bool updateClipping = (flags & B_DRAW_ON_CHILDREN)
|
|
^ (fCurrentView->Flags() & B_DRAW_ON_CHILDREN);
|
|
|
|
fCurrentView->SetFlags(flags);
|
|
_UpdateDrawState(fCurrentView);
|
|
|
|
if (updateClipping) {
|
|
fCurrentView->RebuildClipping(false);
|
|
fCurrentDrawingRegionValid = false;
|
|
}
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FLAGS: "
|
|
"View: %s -> flags: %" B_PRIu32 "\n", Title(),
|
|
fCurrentView->Name(), flags));
|
|
break;
|
|
}
|
|
case AS_VIEW_HIDE:
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_HIDE: View: %s\n",
|
|
Title(), fCurrentView->Name()));
|
|
fCurrentView->SetHidden(true);
|
|
break;
|
|
|
|
case AS_VIEW_SHOW:
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SHOW: View: %s\n",
|
|
Title(), fCurrentView->Name()));
|
|
fCurrentView->SetHidden(false);
|
|
break;
|
|
|
|
case AS_VIEW_SET_LINE_MODE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LINE_MODE: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
ViewSetLineModeInfo info;
|
|
if (link.Read<ViewSetLineModeInfo>(&info) != B_OK)
|
|
break;
|
|
|
|
fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
|
|
fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
|
|
fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
|
|
|
|
fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
|
|
info.lineJoin, info.miterLimit);
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_LINE_MODE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LINE_MODE: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
ViewSetLineModeInfo info;
|
|
info.lineJoin = fCurrentView->CurrentState()->LineJoinMode();
|
|
info.lineCap = fCurrentView->CurrentState()->LineCapMode();
|
|
info.miterLimit = fCurrentView->CurrentState()->MiterLimit();
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<ViewSetLineModeInfo>(info);
|
|
fLink.Flush();
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_FILL_RULE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
int32 fillRule;
|
|
if (link.Read<int32>(&fillRule) != B_OK)
|
|
break;
|
|
|
|
fCurrentView->CurrentState()->SetFillRule(fillRule);
|
|
fWindow->GetDrawingEngine()->SetFillRule(fillRule);
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_FILL_RULE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
int32 fillRule = fCurrentView->CurrentState()->FillRule();
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<int32>(fillRule);
|
|
fLink.Flush();
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_PUSH_STATE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: "
|
|
"%s\n", Title(), fCurrentView->Name()));
|
|
|
|
fCurrentView->PushState();
|
|
// TODO: is this necessary?
|
|
// _UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
case AS_VIEW_POP_STATE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_POP_STATE: View: %s\n",
|
|
Title(), fCurrentView->Name()));
|
|
|
|
fCurrentView->PopState();
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_SCALE:
|
|
{
|
|
float scale;
|
|
if (link.Read<float>(&scale) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_SCALE: "
|
|
"View: %s -> scale: %.2f\n", Title(), fCurrentView->Name(),
|
|
scale));
|
|
|
|
fCurrentView->SetScale(scale);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_SCALE:
|
|
{
|
|
float scale = fCurrentView->CurrentState()->Scale();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_SCALE: "
|
|
"View: %s -> scale: %.2f\n",
|
|
Title(), fCurrentView->Name(), scale));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<float>(scale);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_TRANSFORM:
|
|
{
|
|
BAffineTransform transform;
|
|
if (link.Read<BAffineTransform>(&transform) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_TRANSFORM: "
|
|
"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
|
|
Title(), fCurrentView->Name(), transform.sx, transform.shy,
|
|
transform.shx, transform.sy, transform.tx, transform.ty));
|
|
|
|
fCurrentView->CurrentState()->SetTransform(transform);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_TRANSFORM:
|
|
{
|
|
BAffineTransform transform
|
|
= fCurrentView->CurrentState()->Transform();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_TRANSFORM: "
|
|
"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
|
|
Title(), fCurrentView->Name(), transform.sx, transform.shy,
|
|
transform.shx, transform.sy, transform.tx, transform.ty));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<BAffineTransform>(transform);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_AFFINE_TRANSLATE:
|
|
{
|
|
double x, y;
|
|
link.Read<double>(&x);
|
|
link.Read<double>(&y);
|
|
BAffineTransform current =
|
|
fCurrentView->CurrentState()->Transform();
|
|
current.PreTranslateBy(x, y);
|
|
fCurrentView->CurrentState()->SetTransform(current);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_AFFINE_SCALE:
|
|
{
|
|
double x, y;
|
|
link.Read<double>(&x);
|
|
link.Read<double>(&y);
|
|
BAffineTransform current =
|
|
fCurrentView->CurrentState()->Transform();
|
|
current.PreScaleBy(x, y);
|
|
fCurrentView->CurrentState()->SetTransform(current);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_AFFINE_ROTATE:
|
|
{
|
|
double angleRadians;
|
|
link.Read<double>(&angleRadians);
|
|
BAffineTransform current =
|
|
fCurrentView->CurrentState()->Transform();
|
|
current.PreRotateBy(angleRadians);
|
|
fCurrentView->CurrentState()->SetTransform(current);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_PEN_LOC:
|
|
{
|
|
BPoint location;
|
|
if (link.Read<BPoint>(&location) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_LOC: "
|
|
"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(), location.x, location.y));
|
|
|
|
fCurrentView->CurrentState()->SetPenLocation(location);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_PEN_LOC:
|
|
{
|
|
BPoint location = fCurrentView->CurrentState()->PenLocation();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_LOC: "
|
|
"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(), location.x, location.y));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<BPoint>(location);
|
|
fLink.Flush();
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_PEN_SIZE:
|
|
{
|
|
float penSize;
|
|
if (link.Read<float>(&penSize) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_SIZE: "
|
|
"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
|
|
|
|
fCurrentView->CurrentState()->SetPenSize(penSize);
|
|
fWindow->GetDrawingEngine()->SetPenSize(
|
|
fCurrentView->CurrentState()->PenSize());
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_PEN_SIZE:
|
|
{
|
|
float penSize = fCurrentView->CurrentState()->UnscaledPenSize();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_SIZE: "
|
|
"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<float>(penSize);
|
|
fLink.Flush();
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_VIEW_COLOR:
|
|
{
|
|
rgb_color color;
|
|
if (link.Read(&color, sizeof(rgb_color)) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_COLOR: "
|
|
"View: %s -> rgb_color(%d, %d, %d, %d)\n", Title(),
|
|
fCurrentView->Name(), color.red, color.green, color.blue,
|
|
color.alpha));
|
|
|
|
fCurrentView->SetViewColor(color);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_VIEW_COLOR:
|
|
{
|
|
rgb_color color = fCurrentView->ViewColor();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_COLOR: "
|
|
"View: %s -> rgb_color(%d, %d, %d, %d)\n",
|
|
Title(), fCurrentView->Name(), color.red, color.green,
|
|
color.blue, color.alpha));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<rgb_color>(color);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_HIGH_COLOR:
|
|
{
|
|
rgb_color color;
|
|
if (link.Read(&color, sizeof(rgb_color)) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_HIGH_COLOR: "
|
|
"View: %s -> rgb_color(%d, %d, %d, %d)\n",
|
|
Title(), fCurrentView->Name(), color.red, color.green,
|
|
color.blue, color.alpha));
|
|
|
|
fCurrentView->CurrentState()->SetHighColor(color);
|
|
fWindow->GetDrawingEngine()->SetHighColor(color);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_HIGH_UI_COLOR:
|
|
{
|
|
color_which which = B_NO_COLOR;
|
|
float tint = B_NO_TINT;
|
|
|
|
if (link.Read<color_which>(&which) != B_OK
|
|
|| link.Read<float>(&tint) != B_OK )
|
|
break;
|
|
|
|
fCurrentView->CurrentState()->SetHighUIColor(which, tint);
|
|
|
|
// TODO: should we do more color_which validity checking?
|
|
if (which != B_NO_COLOR) {
|
|
DesktopSettings settings(fDesktop);
|
|
rgb_color color = tint_color(settings.UIColor(which), tint);
|
|
|
|
fCurrentView->CurrentState()->SetHighColor(color);
|
|
fWindow->GetDrawingEngine()->SetHighColor(color);
|
|
}
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_LOW_UI_COLOR:
|
|
{
|
|
color_which which = B_NO_COLOR;
|
|
float tint = B_NO_TINT;
|
|
|
|
if (link.Read<color_which>(&which) != B_OK
|
|
|| link.Read<float>(&tint) != B_OK )
|
|
break;
|
|
|
|
fCurrentView->CurrentState()->SetLowUIColor(which, tint);
|
|
|
|
// TODO: should we do more color_which validity checking?
|
|
if (which != B_NO_COLOR) {
|
|
DesktopSettings settings(fDesktop);
|
|
rgb_color color = tint_color(settings.UIColor(which), tint);
|
|
|
|
fCurrentView->CurrentState()->SetLowColor(color);
|
|
fWindow->GetDrawingEngine()->SetLowColor(color);
|
|
}
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_VIEW_UI_COLOR:
|
|
{
|
|
color_which which = B_NO_COLOR;
|
|
float tint = B_NO_TINT;
|
|
|
|
if (link.Read<color_which>(&which) != B_OK
|
|
|| link.Read<float>(&tint) != B_OK )
|
|
break;
|
|
|
|
// TODO: should we do more color_which validity checking?
|
|
fCurrentView->SetViewUIColor(which, tint);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_HIGH_UI_COLOR:
|
|
{
|
|
float tint;
|
|
color_which which = fCurrentView->CurrentState()->HighUIColor(&tint);
|
|
rgb_color color = fCurrentView->CurrentState()->HighColor();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_UI_COLOR: "
|
|
"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
|
|
" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
|
|
color.red, color.green, color.blue, color.alpha));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<color_which>(which);
|
|
fLink.Attach<float>(tint);
|
|
fLink.Attach<rgb_color>(color);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_LOW_UI_COLOR:
|
|
{
|
|
float tint;
|
|
color_which which = fCurrentView->CurrentState()->LowUIColor(&tint);
|
|
rgb_color color = fCurrentView->CurrentState()->LowColor();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_UI_COLOR: "
|
|
"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
|
|
" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
|
|
color.red, color.green, color.blue, color.alpha));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<color_which>(which);
|
|
fLink.Attach<float>(tint);
|
|
fLink.Attach<rgb_color>(color);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_VIEW_UI_COLOR:
|
|
{
|
|
float tint;
|
|
color_which which = fCurrentView->ViewUIColor(&tint);
|
|
rgb_color color = fCurrentView->ViewColor();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_UI_COLOR: "
|
|
"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
|
|
" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
|
|
color.red, color.green, color.blue, color.alpha));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<color_which>(which);
|
|
fLink.Attach<float>(tint);
|
|
fLink.Attach<rgb_color>(color);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_HIGH_COLOR:
|
|
{
|
|
rgb_color color = fCurrentView->CurrentState()->HighColor();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_COLOR: "
|
|
"View: %s -> rgb_color(%d, %d, %d, %d)\n",
|
|
Title(), fCurrentView->Name(), color.red, color.green,
|
|
color.blue, color.alpha));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<rgb_color>(color);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_LOW_COLOR:
|
|
{
|
|
rgb_color color;
|
|
if (link.Read(&color, sizeof(rgb_color)) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LOW_COLOR: "
|
|
"View: %s -> rgb_color(%d, %d, %d, %d)\n",
|
|
Title(), fCurrentView->Name(), color.red, color.green,
|
|
color.blue, color.alpha));
|
|
|
|
fCurrentView->CurrentState()->SetLowColor(color);
|
|
fWindow->GetDrawingEngine()->SetLowColor(color);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_LOW_COLOR:
|
|
{
|
|
rgb_color color = fCurrentView->CurrentState()->LowColor();
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_COLOR: "
|
|
"View: %s -> rgb_color(%d, %d, %d, %d)\n",
|
|
Title(), fCurrentView->Name(), color.red, color.green,
|
|
color.blue, color.alpha));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<rgb_color>(color);
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_PATTERN:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PATTERN: "
|
|
"View: %s\n", fTitle, fCurrentView->Name()));
|
|
|
|
pattern pat;
|
|
if (link.Read(&pat, sizeof(pattern)) != B_OK)
|
|
break;
|
|
|
|
fCurrentView->CurrentState()->SetPattern(Pattern(pat));
|
|
fWindow->GetDrawingEngine()->SetPattern(pat);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_BLENDING_MODE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_BLEND_MODE: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
|
|
ViewBlendingModeInfo info;
|
|
if (link.Read<ViewBlendingModeInfo>(&info) != B_OK)
|
|
break;
|
|
|
|
fCurrentView->CurrentState()->SetBlendingMode(
|
|
info.sourceAlpha, info.alphaFunction);
|
|
fWindow->GetDrawingEngine()->SetBlendingMode(
|
|
info.sourceAlpha, info.alphaFunction);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_BLENDING_MODE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_BLEND_MODE: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
|
|
ViewBlendingModeInfo info;
|
|
info.sourceAlpha = fCurrentView->CurrentState()->AlphaSrcMode();
|
|
info.alphaFunction = fCurrentView->CurrentState()->AlphaFncMode();
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<ViewBlendingModeInfo>(info);
|
|
fLink.Flush();
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_DRAWING_MODE:
|
|
{
|
|
int8 drawingMode;
|
|
if (link.Read<int8>(&drawingMode) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_DRAW_MODE: "
|
|
"View: %s -> %s\n", Title(), fCurrentView->Name(),
|
|
kDrawingModeMap[drawingMode]));
|
|
|
|
fCurrentView->CurrentState()->SetDrawingMode(
|
|
(drawing_mode)drawingMode);
|
|
fWindow->GetDrawingEngine()->SetDrawingMode(
|
|
(drawing_mode)drawingMode);
|
|
break;
|
|
}
|
|
case AS_VIEW_GET_DRAWING_MODE:
|
|
{
|
|
int8 drawingMode
|
|
= (int8)(fCurrentView->CurrentState()->GetDrawingMode());
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_DRAW_MODE: "
|
|
"View: %s -> %s\n", Title(), fCurrentView->Name(),
|
|
kDrawingModeMap[drawingMode]));
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<int8>(drawingMode);
|
|
fLink.Flush();
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_VIEW_BITMAP:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_BITMAP: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
|
|
int32 bitmapToken, resizingMode, options;
|
|
BRect srcRect, dstRect;
|
|
|
|
link.Read<int32>(&bitmapToken);
|
|
link.Read<BRect>(&srcRect);
|
|
link.Read<BRect>(&dstRect);
|
|
link.Read<int32>(&resizingMode);
|
|
status_t status = link.Read<int32>(&options);
|
|
|
|
rgb_color colorKey = {0};
|
|
|
|
if (status == B_OK) {
|
|
BReference<ServerBitmap> bitmap(fServerApp->GetBitmap(bitmapToken), true);
|
|
if (bitmapToken == -1 || bitmap != NULL) {
|
|
bool wasOverlay = fCurrentView->ViewBitmap() != NULL
|
|
&& fCurrentView->ViewBitmap()->Overlay() != NULL;
|
|
|
|
fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect,
|
|
resizingMode, options);
|
|
|
|
// TODO: if we revert the view color overlay handling
|
|
// in View::Draw() to the BeOS version, we never
|
|
// need to invalidate the view for overlays.
|
|
|
|
// Invalidate view - but only if this is a non-overlay
|
|
// switch
|
|
if (bitmap == NULL || bitmap->Overlay() == NULL
|
|
|| !wasOverlay) {
|
|
BRegion dirty((BRect)fCurrentView->Bounds());
|
|
fWindow->InvalidateView(fCurrentView, dirty);
|
|
}
|
|
|
|
if (bitmap != NULL && bitmap->Overlay() != NULL) {
|
|
bitmap->Overlay()->SetFlags(options);
|
|
colorKey = bitmap->Overlay()->Color();
|
|
}
|
|
} else
|
|
status = B_BAD_VALUE;
|
|
}
|
|
|
|
fLink.StartMessage(status);
|
|
if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
|
|
// Attach color key for the overlay bitmap
|
|
fLink.Attach<rgb_color>(colorKey);
|
|
}
|
|
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
case AS_VIEW_PRINT_ALIASING:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_PRINT_ALIASING: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
|
|
bool fontAliasing;
|
|
if (link.Read<bool>(&fontAliasing) == B_OK) {
|
|
fCurrentView->CurrentState()->SetForceFontAliasing(fontAliasing);
|
|
_UpdateDrawState(fCurrentView);
|
|
}
|
|
break;
|
|
}
|
|
case AS_VIEW_CLIP_TO_PICTURE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_CLIP_TO_PICTURE: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
|
|
int32 pictureToken;
|
|
BPoint where;
|
|
bool inverse = false;
|
|
|
|
link.Read<int32>(&pictureToken);
|
|
if (pictureToken < 0) {
|
|
fCurrentView->SetAlphaMask(NULL);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
link.Read<BPoint>(&where);
|
|
if (link.Read<bool>(&inverse) != B_OK)
|
|
break;
|
|
|
|
BReference<ServerPicture> picture(fServerApp->GetPicture(pictureToken), true);
|
|
if (picture == NULL)
|
|
break;
|
|
|
|
BReference<AlphaMask> const mask(new(std::nothrow) PictureAlphaMask(
|
|
fCurrentView->GetAlphaMask(), picture,
|
|
*fCurrentView->CurrentState(), where, inverse), true);
|
|
fCurrentView->SetAlphaMask(mask);
|
|
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_GET_CLIP_REGION:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_GET_CLIP_REGION: "
|
|
"View: %s\n", Title(), fCurrentView->Name()));
|
|
|
|
// if this view is hidden, it has no visible region
|
|
fLink.StartMessage(B_OK);
|
|
if (!fWindow->IsVisible() || !fCurrentView->IsVisible()) {
|
|
BRegion empty;
|
|
fLink.AttachRegion(empty);
|
|
} else {
|
|
_UpdateCurrentDrawingRegion();
|
|
BRegion region(fCurrentDrawingRegion);
|
|
fCurrentView->ScreenToLocalTransform().Apply(®ion);
|
|
fLink.AttachRegion(region);
|
|
}
|
|
fLink.Flush();
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_CLIP_REGION:
|
|
{
|
|
int32 rectCount;
|
|
status_t status = link.Read<int32>(&rectCount);
|
|
// a negative count means no
|
|
// region for the current draw state,
|
|
// but an *empty* region is actually valid!
|
|
// even if it means no drawing is allowed
|
|
|
|
if (status < B_OK)
|
|
break;
|
|
|
|
if (rectCount >= 0) {
|
|
// we are supposed to set the clipping region
|
|
BRegion region;
|
|
if (rectCount > 0 && link.ReadRegion(®ion) < B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
|
|
"View: %s -> rect count: %" B_PRId32 ", frame = "
|
|
"BRect(%.1f, %.1f, %.1f, %.1f)\n",
|
|
Title(), fCurrentView->Name(), rectCount,
|
|
region.Frame().left, region.Frame().top,
|
|
region.Frame().right, region.Frame().bottom));
|
|
|
|
fCurrentView->SetUserClipping(®ion);
|
|
} else {
|
|
// we are supposed to unset the clipping region
|
|
// passing NULL sets this states region to that
|
|
// of the previous state
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
|
|
"View: %s -> unset\n", Title(), fCurrentView->Name()));
|
|
|
|
fCurrentView->SetUserClipping(NULL);
|
|
}
|
|
fCurrentDrawingRegionValid = false;
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_CLIP_TO_RECT:
|
|
{
|
|
bool inverse;
|
|
BRect rect;
|
|
|
|
link.Read<bool>(&inverse);
|
|
link.Read<BRect>(&rect);
|
|
|
|
bool needDrawStateUpdate = fCurrentView->ClipToRect(
|
|
rect, inverse);
|
|
fCurrentDrawingRegionValid = false;
|
|
|
|
if (needDrawStateUpdate)
|
|
_UpdateDrawState(fCurrentView);
|
|
|
|
_UpdateCurrentDrawingRegion();
|
|
|
|
BRegion region(fCurrentDrawingRegion);
|
|
fCurrentView->ScreenToLocalTransform().Apply(®ion);
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_CLIP_TO_SHAPE:
|
|
{
|
|
bool inverse;
|
|
link.Read<bool>(&inverse);
|
|
|
|
shape_data shape;
|
|
link.Read<int32>(&shape.opCount);
|
|
link.Read<int32>(&shape.ptCount);
|
|
shape.opSize = shape.opCount * sizeof(uint32);
|
|
shape.ptSize = shape.ptCount * sizeof(BPoint);
|
|
shape.opList = new(nothrow) uint32[shape.opCount];
|
|
shape.ptList = new(nothrow) BPoint[shape.ptCount];
|
|
if (link.Read(shape.opList, shape.opSize) >= B_OK
|
|
&& link.Read(shape.ptList, shape.ptSize) >= B_OK) {
|
|
fCurrentView->ClipToShape(&shape, inverse);
|
|
_UpdateDrawState(fCurrentView);
|
|
}
|
|
|
|
delete[] shape.opList;
|
|
delete[] shape.ptList;
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_INVALIDATE_RECT:
|
|
{
|
|
// NOTE: looks like this call is NOT affected by origin and scale
|
|
// on R5 so this implementation is "correct"
|
|
BRect invalidRect;
|
|
if (link.Read<BRect>(&invalidRect) == B_OK) {
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_RECT: "
|
|
"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(), invalidRect.left, invalidRect.top,
|
|
invalidRect.right, invalidRect.bottom));
|
|
|
|
View* view = NULL;
|
|
if (link.Read<View*>(&view) != B_OK)
|
|
view = fCurrentView;
|
|
|
|
// make sure the view is still available!
|
|
if (view != fCurrentView
|
|
&& !fWindow->TopView()->HasView(view))
|
|
break;
|
|
|
|
BRegion dirty(invalidRect);
|
|
fWindow->InvalidateView(view, dirty);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_DELAYED_INVALIDATE_RECT:
|
|
{
|
|
bigtime_t time = 0;
|
|
BRect invalidRect;
|
|
if (link.Read<bigtime_t>(&time) == B_OK
|
|
&& link.Read<BRect>(&invalidRect) == B_OK) {
|
|
DTRACE(("ServerWindow %s: Message "
|
|
"AS_VIEW_DELAYED_INVALIDATE_RECT: "
|
|
"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f) at time %llu\n",
|
|
Title(), fCurrentView->Name(), invalidRect.left,
|
|
invalidRect.top, invalidRect.right, invalidRect.bottom,
|
|
time));
|
|
|
|
DelayedMessage delayed(AS_VIEW_INVALIDATE_RECT, time, true);
|
|
delayed.AddTarget(MessagePort());
|
|
delayed.SetMerge(DM_MERGE_DUPLICATES);
|
|
|
|
if (delayed.Attach<BRect>(invalidRect) == B_OK
|
|
&& delayed.Attach<View*>(fCurrentView) == B_OK)
|
|
delayed.Flush();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_INVALIDATE_REGION:
|
|
{
|
|
// NOTE: looks like this call is NOT affected by origin and scale
|
|
// on R5 so this implementation is "correct"
|
|
BRegion region;
|
|
if (link.ReadRegion(®ion) < B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_REGION: "
|
|
"View: %s -> rect count: %" B_PRId32 ", frame: BRect(%.1f, "
|
|
"%.1f, %.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(), region.CountRects(),
|
|
region.Frame().left, region.Frame().top,
|
|
region.Frame().right, region.Frame().bottom));
|
|
|
|
fWindow->InvalidateView(fCurrentView, region);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_DRAG_IMAGE:
|
|
{
|
|
// TODO: flesh out AS_VIEW_DRAG_IMAGE
|
|
DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
|
|
|
|
int32 bitmapToken;
|
|
drawing_mode dragMode;
|
|
BPoint offset;
|
|
int32 bufferSize;
|
|
|
|
link.Read<int32>(&bitmapToken);
|
|
link.Read<int32>((int32*)&dragMode);
|
|
link.Read<BPoint>(&offset);
|
|
link.Read<int32>(&bufferSize);
|
|
|
|
if (bufferSize > 0) {
|
|
char* buffer = new (nothrow) char[bufferSize];
|
|
BMessage dragMessage;
|
|
if (link.Read(buffer, bufferSize) == B_OK
|
|
&& dragMessage.Unflatten(buffer) == B_OK) {
|
|
BReference<ServerBitmap> bitmap(
|
|
fServerApp->GetBitmap(bitmapToken), true);
|
|
// TODO: possible deadlock
|
|
fDesktop->UnlockSingleWindow();
|
|
fDesktop->EventDispatcher().SetDragMessage(dragMessage,
|
|
bitmap, offset);
|
|
fDesktop->LockSingleWindow();
|
|
}
|
|
delete[] buffer;
|
|
}
|
|
// sync the client (it can now delete the bitmap)
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Flush();
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_DRAG_RECT:
|
|
{
|
|
// TODO: flesh out AS_VIEW_DRAG_RECT
|
|
DTRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
|
|
|
|
BRect dragRect;
|
|
BPoint offset;
|
|
int32 bufferSize;
|
|
|
|
link.Read<BRect>(&dragRect);
|
|
link.Read<BPoint>(&offset);
|
|
link.Read<int32>(&bufferSize);
|
|
|
|
if (bufferSize > 0) {
|
|
char* buffer = new (nothrow) char[bufferSize];
|
|
BMessage dragMessage;
|
|
if (link.Read(buffer, bufferSize) == B_OK
|
|
&& dragMessage.Unflatten(buffer) == B_OK) {
|
|
// TODO: possible deadlock
|
|
fDesktop->UnlockSingleWindow();
|
|
fDesktop->EventDispatcher().SetDragMessage(dragMessage,
|
|
NULL /* should be dragRect */, offset);
|
|
fDesktop->LockSingleWindow();
|
|
}
|
|
delete[] buffer;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_BEGIN_RECT_TRACK:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_RECT_TRACK\n",
|
|
Title()));
|
|
BRect dragRect;
|
|
uint32 style;
|
|
|
|
link.Read<BRect>(&dragRect);
|
|
link.Read<uint32>(&style);
|
|
|
|
// TODO: implement rect tracking (used sometimes for selecting
|
|
// a group of things, also sometimes used to appear to drag
|
|
// something, but without real drag message)
|
|
break;
|
|
}
|
|
case AS_VIEW_END_RECT_TRACK:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_END_RECT_TRACK\n",
|
|
Title()));
|
|
// TODO: implement rect tracking
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_BEGIN_PICTURE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n",
|
|
Title()));
|
|
BReference<ServerPicture> picture(App()->CreatePicture(), true);
|
|
if (picture != NULL) {
|
|
picture->SyncState(fCurrentView);
|
|
fCurrentView->SetPicture(picture);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_APPEND_TO_PICTURE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n",
|
|
Title()));
|
|
|
|
int32 token;
|
|
link.Read<int32>(&token);
|
|
|
|
BReference<ServerPicture> picture(App()->GetPicture(token), true);
|
|
if (picture != NULL)
|
|
picture->SyncState(fCurrentView);
|
|
|
|
fCurrentView->SetPicture(picture);
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_END_PICTURE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n",
|
|
Title()));
|
|
|
|
ServerPicture* picture = fCurrentView->Picture();
|
|
if (picture != NULL) {
|
|
fCurrentView->SetPicture(NULL);
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<int32>(picture->Token());
|
|
} else
|
|
fLink.StartMessage(B_ERROR);
|
|
|
|
fLink.Flush();
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_BEGIN_LAYER:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_LAYER\n",
|
|
Title()));
|
|
|
|
uint8 opacity;
|
|
link.Read<uint8>(&opacity);
|
|
|
|
Layer* layer = new(std::nothrow) Layer(opacity);
|
|
if (layer == NULL)
|
|
break;
|
|
|
|
if (opacity != 255) {
|
|
fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
|
|
fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
|
|
B_ALPHA_COMPOSITE);
|
|
fCurrentView->CurrentState()->SetDrawingModeLocked(true);
|
|
}
|
|
|
|
fCurrentView->SetPicture(layer);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// The drawing code handles allocation failures using exceptions;
|
|
// so we need to account for that here.
|
|
try {
|
|
_DispatchViewDrawingMessage(code, link);
|
|
} catch (std::bad_alloc&) {
|
|
// Cancel any message we were in the middle of sending.
|
|
fLink.CancelMessage();
|
|
|
|
if (link.NeedsReply()) {
|
|
// As done in _DispatchViewDrawingMessage, send just a
|
|
// single status_t as the reply.
|
|
fLink.StartMessage(B_NO_MEMORY);
|
|
fLink.Flush();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*! Dispatches all view drawing messages.
|
|
The desktop clipping must be read locked when entering this method.
|
|
Requires a valid fCurrentView.
|
|
*/
|
|
void
|
|
ServerWindow::_DispatchViewDrawingMessage(int32 code,
|
|
BPrivate::LinkReceiver &link)
|
|
{
|
|
if (!fCurrentView->IsVisible() || !fWindow->IsVisible()) {
|
|
if (link.NeedsReply()) {
|
|
debug_printf("ServerWindow::DispatchViewDrawingMessage() got "
|
|
"message %" B_PRId32 " that needs a reply!\n", code);
|
|
// the client is now blocking and waiting for a reply!
|
|
fLink.StartMessage(B_ERROR);
|
|
fLink.Flush();
|
|
}
|
|
return;
|
|
}
|
|
|
|
DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
|
|
if (!drawingEngine) {
|
|
// ?!?
|
|
debug_printf("ServerWindow %s: no drawing engine!!\n", Title());
|
|
if (link.NeedsReply()) {
|
|
// the client is now blocking and waiting for a reply!
|
|
fLink.StartMessage(B_ERROR);
|
|
fLink.Flush();
|
|
}
|
|
return;
|
|
}
|
|
|
|
_UpdateCurrentDrawingRegion();
|
|
if (fCurrentDrawingRegion.CountRects() <= 0 && code != AS_VIEW_END_LAYER) {
|
|
// If the command is AS_VIEW_END_LAYER, then we continue even if
|
|
// the clipping region is empty. The layer itself might set a valid
|
|
// clipping while its contents are drawn, and even if it doesn't,
|
|
// we must still play back its picture so that we don't leak
|
|
// nested layer instances.
|
|
|
|
DTRACE(("ServerWindow %s: _DispatchViewDrawingMessage(): View: %s, "
|
|
"INVALID CLIPPING!\n", Title(), fCurrentView->Name()));
|
|
if (link.NeedsReply()) {
|
|
// the client is now blocking and waiting for a reply!
|
|
fLink.StartMessage(B_ERROR);
|
|
fLink.Flush();
|
|
}
|
|
return;
|
|
}
|
|
|
|
drawingEngine->LockParallelAccess();
|
|
// NOTE: the region is not copied, Painter keeps a pointer,
|
|
// that's why you need to use the clipping only for as long
|
|
// as you have it locked
|
|
drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
|
|
|
|
switch (code) {
|
|
case AS_STROKE_LINE:
|
|
{
|
|
ViewStrokeLineInfo info;
|
|
if (link.Read<ViewStrokeLineInfo>(&info) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE_LINE: View: %s -> "
|
|
"BPoint(%.1f, %.1f) - BPoint(%.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(),
|
|
info.startPoint.x, info.startPoint.y,
|
|
info.endPoint.x, info.endPoint.y));
|
|
|
|
BPoint penPos = info.endPoint;
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(&info.startPoint);
|
|
transform.Apply(&info.endPoint);
|
|
drawingEngine->StrokeLine(info.startPoint, info.endPoint);
|
|
|
|
// We update the pen here because many DrawingEngine calls which
|
|
// do not update the pen position actually call StrokeLine
|
|
|
|
// TODO: Decide where to put this, for example, it cannot be done
|
|
// for DrawString(), also there needs to be a decision, if the pen
|
|
// location is in View coordinates (I think it should be) or in
|
|
// screen coordinates.
|
|
fCurrentView->CurrentState()->SetPenLocation(penPos);
|
|
break;
|
|
}
|
|
case AS_VIEW_INVERT_RECT:
|
|
{
|
|
BRect rect;
|
|
if (link.Read<BRect>(&rect) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_INVERT_RECT: View: %s -> "
|
|
"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(), rect.left, rect.top, rect.right,
|
|
rect.bottom));
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(&rect);
|
|
drawingEngine->InvertRect(rect);
|
|
break;
|
|
}
|
|
case AS_STROKE_RECT:
|
|
{
|
|
BRect rect;
|
|
if (link.Read<BRect>(&rect) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE_RECT: View: %s -> "
|
|
"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(), rect.left, rect.top, rect.right,
|
|
rect.bottom));
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(&rect);
|
|
drawingEngine->StrokeRect(rect);
|
|
break;
|
|
}
|
|
case AS_FILL_RECT:
|
|
{
|
|
BRect rect;
|
|
if (link.Read<BRect>(&rect) != B_OK)
|
|
break;
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_FILL_RECT: View: %s -> "
|
|
"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(), rect.left, rect.top, rect.right,
|
|
rect.bottom));
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(&rect);
|
|
drawingEngine->FillRect(rect);
|
|
break;
|
|
}
|
|
case AS_FILL_RECT_GRADIENT:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
|
|
GTRACE(("ServerWindow %s: Message AS_FILL_RECT_GRADIENT: View: %s "
|
|
"-> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
|
|
fCurrentView->Name(), rect.left, rect.top, rect.right,
|
|
rect.bottom));
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(&rect);
|
|
transform.Apply(gradient);
|
|
drawingEngine->FillRect(rect, *gradient);
|
|
delete gradient;
|
|
break;
|
|
}
|
|
case AS_VIEW_DRAW_BITMAP:
|
|
{
|
|
ViewDrawBitmapInfo info;
|
|
if (link.Read<ViewDrawBitmapInfo>(&info) != B_OK)
|
|
break;
|
|
|
|
#if 0
|
|
if (strcmp(fServerApp->SignatureLeaf(), "x-vnd.videolan-vlc") == 0)
|
|
info.options |= B_FILTER_BITMAP_BILINEAR;
|
|
#endif
|
|
|
|
BReference<ServerBitmap> bitmap(fServerApp->GetBitmap(info.bitmapToken), true);
|
|
if (bitmap != NULL) {
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: "
|
|
"View: %s, bitmap: %" B_PRId32 " (size %" B_PRId32 " x "
|
|
"%" B_PRId32 "), BRect(%.1f, %.1f, %.1f, %.1f) -> "
|
|
"BRect(%.1f, %.1f, %.1f, %.1f)\n",
|
|
fTitle, fCurrentView->Name(), info.bitmapToken,
|
|
bitmap->Width(), bitmap->Height(),
|
|
info.bitmapRect.left, info.bitmapRect.top,
|
|
info.bitmapRect.right, info.bitmapRect.bottom,
|
|
info.viewRect.left, info.viewRect.top,
|
|
info.viewRect.right, info.viewRect.bottom));
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(&info.viewRect);
|
|
|
|
// TODO: Unbreak...
|
|
// if ((info.options & B_WAIT_FOR_RETRACE) != 0)
|
|
// fDesktop->HWInterface()->WaitForRetrace(20000);
|
|
|
|
drawingEngine->DrawBitmap(bitmap, info.bitmapRect,
|
|
info.viewRect, info.options);
|
|
}
|
|
break;
|
|
}
|
|
case AS_STROKE_ARC:
|
|
case AS_FILL_ARC:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
|
|
|
|
float angle, span;
|
|
BRect r;
|
|
|
|
link.Read<BRect>(&r);
|
|
link.Read<float>(&angle);
|
|
if (link.Read<float>(&span) != B_OK)
|
|
break;
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(&r);
|
|
drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC);
|
|
break;
|
|
}
|
|
case AS_FILL_ARC_GRADIENT:
|
|
{
|
|
GTRACE(("ServerWindow %s: Message AS_FILL_ARC_GRADIENT\n",
|
|
Title()));
|
|
|
|
float angle, span;
|
|
BRect r;
|
|
link.Read<BRect>(&r);
|
|
link.Read<float>(&angle);
|
|
link.Read<float>(&span);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(&r);
|
|
transform.Apply(gradient);
|
|
drawingEngine->FillArc(r, angle, span, *gradient);
|
|
delete gradient;
|
|
break;
|
|
}
|
|
case AS_STROKE_BEZIER:
|
|
case AS_FILL_BEZIER:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n",
|
|
Title()));
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
BPoint pts[4];
|
|
status_t status;
|
|
for (int32 i = 0; i < 4; i++) {
|
|
status = link.Read<BPoint>(&(pts[i]));
|
|
transform.Apply(&pts[i]);
|
|
}
|
|
if (status != B_OK)
|
|
break;
|
|
|
|
drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER);
|
|
break;
|
|
}
|
|
case AS_FILL_BEZIER_GRADIENT:
|
|
{
|
|
GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n",
|
|
Title()));
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
BPoint pts[4];
|
|
for (int32 i = 0; i < 4; i++) {
|
|
link.Read<BPoint>(&(pts[i]));
|
|
transform.Apply(&pts[i]);
|
|
}
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
transform.Apply(gradient);
|
|
drawingEngine->FillBezier(pts, *gradient);
|
|
delete gradient;
|
|
break;
|
|
}
|
|
case AS_STROKE_ELLIPSE:
|
|
case AS_FILL_ELLIPSE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n",
|
|
Title()));
|
|
|
|
BRect rect;
|
|
if (link.Read<BRect>(&rect) != B_OK)
|
|
break;
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(&rect);
|
|
drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE);
|
|
break;
|
|
}
|
|
case AS_FILL_ELLIPSE_GRADIENT:
|
|
{
|
|
GTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE_GRADIENT\n",
|
|
Title()));
|
|
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(&rect);
|
|
transform.Apply(gradient);
|
|
drawingEngine->FillEllipse(rect, *gradient);
|
|
delete gradient;
|
|
break;
|
|
}
|
|
case AS_STROKE_ROUNDRECT:
|
|
case AS_FILL_ROUNDRECT:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n",
|
|
Title()));
|
|
|
|
BRect rect;
|
|
float xRadius;
|
|
float yRadius;
|
|
link.Read<BRect>(&rect);
|
|
link.Read<float>(&xRadius);
|
|
if (link.Read<float>(&yRadius) != B_OK)
|
|
break;
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(&rect);
|
|
float scale = fCurrentView->CurrentState()->CombinedScale();
|
|
drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale,
|
|
code == AS_FILL_ROUNDRECT);
|
|
break;
|
|
}
|
|
case AS_FILL_ROUNDRECT_GRADIENT:
|
|
{
|
|
GTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT_GRADIENT\n",
|
|
Title()));
|
|
|
|
BRect rect;
|
|
float xrad,yrad;
|
|
link.Read<BRect>(&rect);
|
|
link.Read<float>(&xrad);
|
|
link.Read<float>(&yrad);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(&rect);
|
|
transform.Apply(gradient);
|
|
drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient);
|
|
delete gradient;
|
|
break;
|
|
}
|
|
case AS_STROKE_TRIANGLE:
|
|
case AS_FILL_TRIANGLE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n",
|
|
Title()));
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
BPoint pts[3];
|
|
BRect rect;
|
|
|
|
for (int32 i = 0; i < 3; i++) {
|
|
link.Read<BPoint>(&(pts[i]));
|
|
transform.Apply(&pts[i]);
|
|
}
|
|
|
|
if (link.Read<BRect>(&rect) != B_OK)
|
|
break;
|
|
|
|
transform.Apply(&rect);
|
|
drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE);
|
|
break;
|
|
}
|
|
case AS_FILL_TRIANGLE_GRADIENT:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n",
|
|
Title()));
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
BPoint pts[3];
|
|
BRect rect;
|
|
for (int32 i = 0; i < 3; i++) {
|
|
link.Read<BPoint>(&(pts[i]));
|
|
transform.Apply(&pts[i]);
|
|
}
|
|
link.Read<BRect>(&rect);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
transform.Apply(&rect);
|
|
transform.Apply(gradient);
|
|
drawingEngine->FillTriangle(pts, rect, *gradient);
|
|
delete gradient;
|
|
break;
|
|
}
|
|
case AS_STROKE_POLYGON:
|
|
case AS_FILL_POLYGON:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n",
|
|
Title()));
|
|
|
|
BRect polyFrame;
|
|
bool isClosed = true;
|
|
int32 pointCount;
|
|
|
|
link.Read<BRect>(&polyFrame);
|
|
if (code == AS_STROKE_POLYGON)
|
|
link.Read<bool>(&isClosed);
|
|
link.Read<int32>(&pointCount);
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
BPoint* pointList = new(nothrow) BPoint[pointCount];
|
|
if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
|
|
for (int32 i = 0; i < pointCount; i++)
|
|
transform.Apply(&pointList[i]);
|
|
transform.Apply(&polyFrame);
|
|
|
|
drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
|
|
code == AS_FILL_POLYGON, isClosed && pointCount > 2);
|
|
}
|
|
delete[] pointList;
|
|
break;
|
|
}
|
|
case AS_FILL_POLYGON_GRADIENT:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON_GRADIENT\n",
|
|
Title()));
|
|
|
|
BRect polyFrame;
|
|
bool isClosed = true;
|
|
int32 pointCount;
|
|
link.Read<BRect>(&polyFrame);
|
|
link.Read<int32>(&pointCount);
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
BPoint* pointList = new(nothrow) BPoint[pointCount];
|
|
BGradient* gradient;
|
|
if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK
|
|
&& link.ReadGradient(&gradient) == B_OK) {
|
|
for (int32 i = 0; i < pointCount; i++)
|
|
transform.Apply(&pointList[i]);
|
|
transform.Apply(&polyFrame);
|
|
transform.Apply(gradient);
|
|
|
|
drawingEngine->FillPolygon(pointList, pointCount,
|
|
polyFrame, *gradient, isClosed && pointCount > 2);
|
|
delete gradient;
|
|
}
|
|
delete[] pointList;
|
|
break;
|
|
}
|
|
case AS_STROKE_SHAPE:
|
|
case AS_FILL_SHAPE:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n",
|
|
Title()));
|
|
|
|
BRect shapeFrame;
|
|
int32 opCount;
|
|
int32 ptCount;
|
|
|
|
link.Read<BRect>(&shapeFrame);
|
|
link.Read<int32>(&opCount);
|
|
link.Read<int32>(&ptCount);
|
|
|
|
uint32* opList = new(nothrow) uint32[opCount];
|
|
BPoint* ptList = new(nothrow) BPoint[ptCount];
|
|
if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
|
|
link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
|
|
|
|
// this might seem a bit weird, but under R5, the shapes
|
|
// are always offset by the current pen location
|
|
BPoint screenOffset
|
|
= fCurrentView->CurrentState()->PenLocation();
|
|
shapeFrame.OffsetBy(screenOffset);
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(&screenOffset);
|
|
transform.Apply(&shapeFrame);
|
|
|
|
drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount,
|
|
ptList, code == AS_FILL_SHAPE, screenOffset,
|
|
fCurrentView->Scale());
|
|
}
|
|
|
|
delete[] opList;
|
|
delete[] ptList;
|
|
break;
|
|
}
|
|
case AS_FILL_SHAPE_GRADIENT:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE_GRADIENT\n",
|
|
Title()));
|
|
|
|
BRect shapeFrame;
|
|
int32 opCount;
|
|
int32 ptCount;
|
|
|
|
link.Read<BRect>(&shapeFrame);
|
|
link.Read<int32>(&opCount);
|
|
link.Read<int32>(&ptCount);
|
|
|
|
uint32* opList = new(nothrow) uint32[opCount];
|
|
BPoint* ptList = new(nothrow) BPoint[ptCount];
|
|
BGradient* gradient;
|
|
if (link.Read(opList, opCount * sizeof(uint32)) == B_OK
|
|
&& link.Read(ptList, ptCount * sizeof(BPoint)) == B_OK
|
|
&& link.ReadGradient(&gradient) == B_OK) {
|
|
|
|
// this might seem a bit weird, but under R5, the shapes
|
|
// are always offset by the current pen location
|
|
BPoint screenOffset
|
|
= fCurrentView->CurrentState()->PenLocation();
|
|
shapeFrame.OffsetBy(screenOffset);
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(&screenOffset);
|
|
transform.Apply(&shapeFrame);
|
|
transform.Apply(gradient);
|
|
drawingEngine->FillShape(shapeFrame, opCount, opList,
|
|
ptCount, ptList, *gradient, screenOffset,
|
|
fCurrentView->Scale());
|
|
delete gradient;
|
|
}
|
|
|
|
delete[] opList;
|
|
delete[] ptList;
|
|
break;
|
|
}
|
|
case AS_FILL_REGION:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
|
|
|
|
BRegion region;
|
|
if (link.ReadRegion(®ion) < B_OK)
|
|
break;
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(®ion);
|
|
drawingEngine->FillRegion(region);
|
|
|
|
break;
|
|
}
|
|
case AS_FILL_REGION_GRADIENT:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_FILL_REGION_GRADIENT\n",
|
|
Title()));
|
|
|
|
BRegion region;
|
|
link.ReadRegion(®ion);
|
|
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(®ion);
|
|
transform.Apply(gradient);
|
|
drawingEngine->FillRegion(region, *gradient);
|
|
delete gradient;
|
|
break;
|
|
}
|
|
case AS_STROKE_LINEARRAY:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n",
|
|
Title()));
|
|
|
|
// Attached Data:
|
|
// 1) int32 Number of lines in the array
|
|
// 2) LineArrayData
|
|
|
|
int32 lineCount;
|
|
if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
|
|
break;
|
|
|
|
// To speed things up, try to use a stack allocation and only
|
|
// fall back to the heap if there are enough lines...
|
|
ViewLineArrayInfo* lineData;
|
|
const int32 kStackBufferLineDataCount = 64;
|
|
ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
|
|
if (lineCount > kStackBufferLineDataCount) {
|
|
lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
|
|
if (lineData == NULL)
|
|
break;
|
|
} else
|
|
lineData = lineDataStackBuffer;
|
|
|
|
// Read them all in one go
|
|
size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
|
|
if (link.Read(lineData, dataSize) != B_OK) {
|
|
if (lineData != lineDataStackBuffer)
|
|
delete[] lineData;
|
|
break;
|
|
}
|
|
|
|
// Convert to screen coords and draw
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
for (int32 i = 0; i < lineCount; i++) {
|
|
transform.Apply(&lineData[i].startPoint);
|
|
transform.Apply(&lineData[i].endPoint);
|
|
}
|
|
drawingEngine->StrokeLineArray(lineCount, lineData);
|
|
|
|
if (lineData != lineDataStackBuffer)
|
|
delete[] lineData;
|
|
break;
|
|
}
|
|
case AS_DRAW_STRING:
|
|
case AS_DRAW_STRING_WITH_DELTA:
|
|
{
|
|
ViewDrawStringInfo info;
|
|
if (link.Read<ViewDrawStringInfo>(&info) != B_OK
|
|
|| info.stringLength <= 0) {
|
|
break;
|
|
}
|
|
|
|
// NOTE: Careful, the + 1 is for termination!
|
|
BStackOrHeapArray<char, 4096> string(
|
|
(info.stringLength + 1 + 63) / 64 * 64);
|
|
if (!string.IsValid())
|
|
break;
|
|
|
|
escapement_delta* delta = NULL;
|
|
if (code == AS_DRAW_STRING_WITH_DELTA) {
|
|
// In this case, info.delta will contain valid values.
|
|
delta = &info.delta;
|
|
}
|
|
|
|
if (link.Read(string, info.stringLength) != B_OK)
|
|
break;
|
|
|
|
// Terminate the string, if nothing else, it's important
|
|
// for the DTRACE call below...
|
|
string[info.stringLength] = '\0';
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s "
|
|
"-> %s\n", Title(), fCurrentView->Name(), string));
|
|
|
|
fCurrentView->PenToScreenTransform().Apply(&info.location);
|
|
BPoint penLocation = drawingEngine->DrawString(string,
|
|
info.stringLength, info.location, delta);
|
|
|
|
fCurrentView->ScreenToPenTransform().Apply(&penLocation);
|
|
fCurrentView->CurrentState()->SetPenLocation(penLocation);
|
|
|
|
break;
|
|
}
|
|
case AS_DRAW_STRING_WITH_OFFSETS:
|
|
{
|
|
int32 stringLength;
|
|
if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
|
|
break;
|
|
|
|
int32 glyphCount;
|
|
if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
|
|
break;
|
|
|
|
// NOTE: Careful, the + 1 is for termination!
|
|
BStackOrHeapArray<char, 512> string(
|
|
(stringLength + 1 + 63) / 64 * 64);
|
|
BStackOrHeapArray<BPoint, 512> locations(glyphCount);
|
|
if (!string.IsValid() || !locations.IsValid())
|
|
break;
|
|
|
|
if (link.Read(string, stringLength) != B_OK)
|
|
break;
|
|
// Count UTF8 glyphs and make sure we have enough locations
|
|
if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
|
|
break;
|
|
if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
|
|
break;
|
|
// Terminate the string, if nothing else, it's important
|
|
// for the DTRACE call below...
|
|
string[stringLength] = '\0';
|
|
|
|
DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s "
|
|
"-> %s\n", Title(), fCurrentView->Name(), string));
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
for (int32 i = 0; i < glyphCount; i++)
|
|
transform.Apply(&locations[i]);
|
|
|
|
BPoint penLocation = drawingEngine->DrawString(string,
|
|
stringLength, locations);
|
|
|
|
fCurrentView->ScreenToPenTransform().Apply(&penLocation);
|
|
fCurrentView->CurrentState()->SetPenLocation(penLocation);
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_DRAW_PICTURE:
|
|
{
|
|
int32 token;
|
|
link.Read<int32>(&token);
|
|
|
|
BPoint where;
|
|
if (link.Read<BPoint>(&where) == B_OK) {
|
|
BReference<ServerPicture> picture(App()->GetPicture(token), true);
|
|
if (picture != NULL) {
|
|
// Setting the drawing origin outside of the
|
|
// state makes sure that everything the picture
|
|
// does is relative to the global picture offset.
|
|
fCurrentView->PushState();
|
|
fCurrentView->SetDrawingOrigin(where);
|
|
|
|
fCurrentView->PushState();
|
|
picture->Play(fCurrentView);
|
|
fCurrentView->PopState();
|
|
|
|
fCurrentView->PopState();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_END_LAYER:
|
|
{
|
|
DTRACE(("ServerWindow %s: Message AS_VIEW_END_LAYER\n",
|
|
Title()));
|
|
|
|
fCurrentView->BlendAllLayers();
|
|
fCurrentView->SetPicture(NULL);
|
|
fCurrentView->CurrentState()->SetDrawingModeLocked(false);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
debug_printf("ServerWindow %s received unexpected code: %s\n",
|
|
Title(), string_for_message_code(code));
|
|
|
|
if (link.NeedsReply()) {
|
|
// the client is now blocking and waiting for a reply!
|
|
fLink.StartMessage(B_ERROR);
|
|
fLink.Flush();
|
|
}
|
|
break;
|
|
}
|
|
|
|
drawingEngine->UnlockParallelAccess();
|
|
}
|
|
|
|
|
|
bool
|
|
ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link)
|
|
{
|
|
ServerPicture* picture = fCurrentView->Picture();
|
|
if (picture == NULL)
|
|
return false;
|
|
|
|
switch (code) {
|
|
case AS_VIEW_SET_ORIGIN:
|
|
{
|
|
float x, y;
|
|
link.Read<float>(&x);
|
|
link.Read<float>(&y);
|
|
|
|
fCurrentView->SetDrawingOrigin(BPoint(x, y));
|
|
picture->WriteSetOrigin(BPoint(x, y));
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_INVERT_RECT:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
picture->WriteInvertRect(rect);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_PUSH_STATE:
|
|
{
|
|
fCurrentView->PushState();
|
|
picture->WritePushState();
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_POP_STATE:
|
|
{
|
|
fCurrentView->PopState();
|
|
picture->WritePopState();
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_DRAWING_MODE:
|
|
{
|
|
int8 drawingMode;
|
|
link.Read<int8>(&drawingMode);
|
|
|
|
picture->WriteSetDrawingMode((drawing_mode)drawingMode);
|
|
|
|
fCurrentView->CurrentState()->SetDrawingMode(
|
|
(drawing_mode)drawingMode);
|
|
fWindow->GetDrawingEngine()->SetDrawingMode(
|
|
(drawing_mode)drawingMode);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_PEN_LOC:
|
|
{
|
|
BPoint location;
|
|
link.Read<BPoint>(&location);
|
|
picture->WriteSetPenLocation(location);
|
|
|
|
fCurrentView->CurrentState()->SetPenLocation(location);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_PEN_SIZE:
|
|
{
|
|
float penSize;
|
|
link.Read<float>(&penSize);
|
|
picture->WriteSetPenSize(penSize);
|
|
|
|
fCurrentView->CurrentState()->SetPenSize(penSize);
|
|
fWindow->GetDrawingEngine()->SetPenSize(
|
|
fCurrentView->CurrentState()->PenSize());
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_LINE_MODE:
|
|
{
|
|
|
|
ViewSetLineModeInfo info;
|
|
link.Read<ViewSetLineModeInfo>(&info);
|
|
|
|
picture->WriteSetLineMode(info.lineCap, info.lineJoin,
|
|
info.miterLimit);
|
|
|
|
fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
|
|
fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
|
|
fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
|
|
|
|
fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
|
|
info.lineJoin, info.miterLimit);
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_FILL_RULE:
|
|
{
|
|
int32 fillRule;
|
|
if (link.Read<int32>(&fillRule) != B_OK)
|
|
break;
|
|
|
|
picture->WriteSetFillRule(fillRule);
|
|
|
|
fCurrentView->CurrentState()->SetFillRule(fillRule);
|
|
fWindow->GetDrawingEngine()->SetFillRule(fillRule);
|
|
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_SCALE:
|
|
{
|
|
float scale;
|
|
if (link.Read<float>(&scale) != B_OK)
|
|
break;
|
|
|
|
picture->WriteSetScale(scale);
|
|
|
|
fCurrentView->SetScale(scale);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
case AS_VIEW_SET_TRANSFORM:
|
|
{
|
|
BAffineTransform transform;
|
|
if (link.Read<BAffineTransform>(&transform) != B_OK)
|
|
break;
|
|
|
|
picture->WriteSetTransform(transform);
|
|
|
|
fCurrentView->CurrentState()->SetTransform(transform);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_AFFINE_TRANSLATE:
|
|
{
|
|
double x, y;
|
|
link.Read<double>(&x);
|
|
link.Read<double>(&y);
|
|
|
|
picture->WriteTranslateBy(x, y);
|
|
|
|
BAffineTransform current =
|
|
fCurrentView->CurrentState()->Transform();
|
|
current.PreTranslateBy(x, y);
|
|
fCurrentView->CurrentState()->SetTransform(current);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_AFFINE_SCALE:
|
|
{
|
|
double x, y;
|
|
link.Read<double>(&x);
|
|
link.Read<double>(&y);
|
|
|
|
picture->WriteScaleBy(x, y);
|
|
|
|
BAffineTransform current =
|
|
fCurrentView->CurrentState()->Transform();
|
|
current.PreScaleBy(x, y);
|
|
fCurrentView->CurrentState()->SetTransform(current);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_AFFINE_ROTATE:
|
|
{
|
|
double angleRadians;
|
|
link.Read<double>(&angleRadians);
|
|
|
|
picture->WriteRotateBy(angleRadians);
|
|
|
|
BAffineTransform current =
|
|
fCurrentView->CurrentState()->Transform();
|
|
current.PreRotateBy(angleRadians);
|
|
fCurrentView->CurrentState()->SetTransform(current);
|
|
_UpdateDrawState(fCurrentView);
|
|
break;
|
|
}
|
|
|
|
|
|
case AS_VIEW_SET_PATTERN:
|
|
{
|
|
pattern pat;
|
|
link.Read(&pat, sizeof(pattern));
|
|
picture->WriteSetPattern(pat);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_FONT_STATE:
|
|
{
|
|
uint16 mask = fCurrentView->CurrentState()->ReadFontFromLink(link);
|
|
fWindow->GetDrawingEngine()->SetFont(
|
|
fCurrentView->CurrentState());
|
|
|
|
picture->WriteFontState(fCurrentView->CurrentState()->Font(), mask);
|
|
break;
|
|
}
|
|
|
|
case AS_FILL_RECT:
|
|
case AS_STROKE_RECT:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
|
|
picture->WriteDrawRect(rect, code == AS_FILL_RECT);
|
|
break;
|
|
}
|
|
|
|
case AS_FILL_REGION:
|
|
{
|
|
// There is no B_PIC_FILL_REGION op, we have to
|
|
// implement it using B_PIC_FILL_RECT
|
|
BRegion region;
|
|
if (link.ReadRegion(®ion) < B_OK)
|
|
break;
|
|
for (int32 i = 0; i < region.CountRects(); i++)
|
|
picture->WriteDrawRect(region.RectAt(i), true);
|
|
break;
|
|
}
|
|
|
|
case AS_STROKE_ROUNDRECT:
|
|
case AS_FILL_ROUNDRECT:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
|
|
BPoint radii;
|
|
link.Read<float>(&radii.x);
|
|
link.Read<float>(&radii.y);
|
|
|
|
picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
|
|
break;
|
|
}
|
|
|
|
case AS_STROKE_ELLIPSE:
|
|
case AS_FILL_ELLIPSE:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
|
|
break;
|
|
}
|
|
|
|
case AS_STROKE_ARC:
|
|
case AS_FILL_ARC:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
float startTheta, arcTheta;
|
|
link.Read<float>(&startTheta);
|
|
link.Read<float>(&arcTheta);
|
|
|
|
BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
|
|
BPoint center = rect.LeftTop() + radii;
|
|
|
|
picture->WriteDrawArc(center, radii, startTheta, arcTheta,
|
|
code == AS_FILL_ARC);
|
|
break;
|
|
}
|
|
|
|
case AS_STROKE_TRIANGLE:
|
|
case AS_FILL_TRIANGLE:
|
|
{
|
|
// There is no B_PIC_FILL/STROKE_TRIANGLE op,
|
|
// we implement it using B_PIC_FILL/STROKE_POLYGON
|
|
BPoint points[3];
|
|
|
|
for (int32 i = 0; i < 3; i++) {
|
|
link.Read<BPoint>(&(points[i]));
|
|
}
|
|
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
|
|
picture->WriteDrawPolygon(3, points,
|
|
true, code == AS_FILL_TRIANGLE);
|
|
break;
|
|
}
|
|
case AS_STROKE_POLYGON:
|
|
case AS_FILL_POLYGON:
|
|
{
|
|
BRect polyFrame;
|
|
bool isClosed = true;
|
|
int32 pointCount;
|
|
const bool fill = (code == AS_FILL_POLYGON);
|
|
|
|
link.Read<BRect>(&polyFrame);
|
|
if (code == AS_STROKE_POLYGON)
|
|
link.Read<bool>(&isClosed);
|
|
link.Read<int32>(&pointCount);
|
|
|
|
BPoint* pointList = new(nothrow) BPoint[pointCount];
|
|
if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
|
|
picture->WriteDrawPolygon(pointCount, pointList,
|
|
isClosed && pointCount > 2, fill);
|
|
}
|
|
delete[] pointList;
|
|
break;
|
|
}
|
|
|
|
case AS_STROKE_BEZIER:
|
|
case AS_FILL_BEZIER:
|
|
{
|
|
BPoint points[4];
|
|
for (int32 i = 0; i < 4; i++) {
|
|
link.Read<BPoint>(&(points[i]));
|
|
}
|
|
picture->WriteDrawBezier(points, code == AS_FILL_BEZIER);
|
|
break;
|
|
}
|
|
|
|
//case AS_STROKE_RECT_GRADIENT:
|
|
case AS_FILL_RECT_GRADIENT:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
picture->WriteDrawRectGradient(rect, *gradient, code == AS_FILL_RECT_GRADIENT);
|
|
break;
|
|
}
|
|
|
|
//case AS_STROKE_ARC_GRADIENT:
|
|
case AS_FILL_ARC_GRADIENT:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
float startTheta, arcTheta;
|
|
link.Read<float>(&startTheta);
|
|
link.Read<float>(&arcTheta);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
|
|
BPoint center = rect.LeftTop() + radii;
|
|
|
|
picture->WriteDrawArcGradient(center, radii, startTheta, arcTheta, *gradient,
|
|
code == AS_FILL_ARC_GRADIENT);
|
|
break;
|
|
}
|
|
|
|
//case AS_STROKE_BEZIER_GRADIENT:
|
|
case AS_FILL_BEZIER_GRADIENT:
|
|
{
|
|
BPoint points[4];
|
|
for (int32 i = 0; i < 4; i++) {
|
|
link.Read<BPoint>(&(points[i]));
|
|
}
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
picture->WriteDrawBezierGradient(points, *gradient, code == AS_FILL_BEZIER_GRADIENT);
|
|
break;
|
|
}
|
|
|
|
//case AS_STROKE_ELLIPSE_GRADIENT:
|
|
case AS_FILL_ELLIPSE_GRADIENT:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
picture->WriteDrawEllipseGradient(rect, *gradient, code == AS_FILL_ELLIPSE_GRADIENT);
|
|
break;
|
|
}
|
|
|
|
//case AS_STROKE_ROUNDRECT_GRADIENT:
|
|
case AS_FILL_ROUNDRECT_GRADIENT:
|
|
{
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
|
|
BPoint radii;
|
|
link.Read<float>(&radii.x);
|
|
link.Read<float>(&radii.y);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
picture->WriteDrawRoundRectGradient(rect, radii, *gradient, code == AS_FILL_ROUNDRECT_GRADIENT);
|
|
break;
|
|
}
|
|
|
|
//case AS_STROKE_TRIANGLE_GRADIENT:
|
|
case AS_FILL_TRIANGLE_GRADIENT:
|
|
{
|
|
// There is no B_PIC_FILL/STROKE_TRIANGLE op,
|
|
// we implement it using B_PIC_FILL/STROKE_POLYGON
|
|
BPoint points[3];
|
|
|
|
for (int32 i = 0; i < 3; i++) {
|
|
link.Read<BPoint>(&(points[i]));
|
|
}
|
|
|
|
BRect rect;
|
|
link.Read<BRect>(&rect);
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
picture->WriteDrawPolygonGradient(3, points,
|
|
true, *gradient, code == AS_FILL_TRIANGLE_GRADIENT);
|
|
break;
|
|
}
|
|
|
|
//case AS_STROKE_POLYGON_GRADIENT:
|
|
case AS_FILL_POLYGON_GRADIENT:
|
|
{
|
|
BRect polyFrame;
|
|
bool isClosed = true;
|
|
int32 pointCount;
|
|
const bool fill = (code == AS_FILL_POLYGON_GRADIENT);
|
|
|
|
link.Read<BRect>(&polyFrame);
|
|
if (code == AS_STROKE_POLYGON)
|
|
link.Read<bool>(&isClosed);
|
|
link.Read<int32>(&pointCount);
|
|
|
|
ArrayDeleter<BPoint> pointList(new(nothrow) BPoint[pointCount]);
|
|
if (link.Read(pointList.Get(), pointCount * sizeof(BPoint)) != B_OK)
|
|
break;
|
|
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
picture->WriteDrawPolygonGradient(pointCount, pointList.Get(),
|
|
isClosed && pointCount > 2, *gradient, fill);
|
|
break;
|
|
}
|
|
|
|
//case AS_STROKE_SHAPE_GRADIENT:
|
|
case AS_FILL_SHAPE_GRADIENT:
|
|
{
|
|
BRect shapeFrame;
|
|
int32 opCount;
|
|
int32 ptCount;
|
|
|
|
link.Read<BRect>(&shapeFrame);
|
|
link.Read<int32>(&opCount);
|
|
link.Read<int32>(&ptCount);
|
|
|
|
ArrayDeleter<uint32> opList(new(std::nothrow) uint32[opCount]);
|
|
ArrayDeleter<BPoint> ptList(new(std::nothrow) BPoint[ptCount]);
|
|
if (!opList.IsSet() || !ptList.IsSet()
|
|
|| link.Read(opList.Get(), opCount * sizeof(uint32)) != B_OK
|
|
|| link.Read(ptList.Get(), ptCount * sizeof(BPoint)) != B_OK)
|
|
break;
|
|
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
// This might seem a bit weird, but under BeOS, the shapes
|
|
// are always offset by the current pen location
|
|
BPoint penLocation
|
|
= fCurrentView->CurrentState()->PenLocation();
|
|
for (int32 i = 0; i < ptCount; i++) {
|
|
ptList.Get()[i] += penLocation;
|
|
}
|
|
const bool fill = (code == AS_FILL_SHAPE_GRADIENT);
|
|
picture->WriteDrawShapeGradient(opCount, opList.Get(), ptCount, ptList.Get(), *gradient, fill);
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_FILL_REGION_GRADIENT:
|
|
{
|
|
// There is no B_PIC_FILL_REGION op, we have to
|
|
// implement it using B_PIC_FILL_RECT
|
|
BRegion region;
|
|
if (link.ReadRegion(®ion) < B_OK)
|
|
break;
|
|
|
|
BGradient* gradient;
|
|
if (link.ReadGradient(&gradient) != B_OK)
|
|
break;
|
|
ObjectDeleter<BGradient> gradientDeleter(gradient);
|
|
|
|
for (int32 i = 0; i < region.CountRects(); i++)
|
|
picture->WriteDrawRectGradient(region.RectAt(i), *gradient, true);
|
|
break;
|
|
}
|
|
|
|
case AS_STROKE_LINE:
|
|
{
|
|
ViewStrokeLineInfo info;
|
|
link.Read<ViewStrokeLineInfo>(&info);
|
|
|
|
picture->WriteStrokeLine(info.startPoint, info.endPoint);
|
|
|
|
BPoint penPos = info.endPoint;
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
transform.Apply(&info.endPoint);
|
|
fCurrentView->CurrentState()->SetPenLocation(penPos);
|
|
break;
|
|
}
|
|
|
|
case AS_STROKE_LINEARRAY:
|
|
{
|
|
int32 lineCount;
|
|
if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
|
|
break;
|
|
|
|
// To speed things up, try to use a stack allocation and only
|
|
// fall back to the heap if there are enough lines...
|
|
ViewLineArrayInfo* lineData;
|
|
const int32 kStackBufferLineDataCount = 64;
|
|
ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
|
|
if (lineCount > kStackBufferLineDataCount) {
|
|
lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
|
|
if (lineData == NULL)
|
|
break;
|
|
} else
|
|
lineData = lineDataStackBuffer;
|
|
|
|
// Read them all in one go
|
|
size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
|
|
if (link.Read(lineData, dataSize) != B_OK) {
|
|
if (lineData != lineDataStackBuffer)
|
|
delete[] lineData;
|
|
break;
|
|
}
|
|
|
|
picture->WritePushState();
|
|
|
|
for (int32 i = 0; i < lineCount; i++) {
|
|
picture->WriteSetHighColor(lineData[i].color);
|
|
picture->WriteStrokeLine(lineData[i].startPoint,
|
|
lineData[i].endPoint);
|
|
}
|
|
|
|
picture->WritePopState();
|
|
|
|
if (lineData != lineDataStackBuffer)
|
|
delete[] lineData;
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_LOW_COLOR:
|
|
case AS_VIEW_SET_HIGH_COLOR:
|
|
{
|
|
rgb_color color;
|
|
link.Read(&color, sizeof(rgb_color));
|
|
|
|
if (code == AS_VIEW_SET_HIGH_COLOR) {
|
|
picture->WriteSetHighColor(color);
|
|
fCurrentView->CurrentState()->SetHighColor(color);
|
|
fWindow->GetDrawingEngine()->SetHighColor(color);
|
|
} else {
|
|
picture->WriteSetLowColor(color);
|
|
fCurrentView->CurrentState()->SetLowColor(color);
|
|
fWindow->GetDrawingEngine()->SetLowColor(color);
|
|
}
|
|
} break;
|
|
|
|
case AS_DRAW_STRING:
|
|
case AS_DRAW_STRING_WITH_DELTA:
|
|
{
|
|
ViewDrawStringInfo info;
|
|
if (link.Read<ViewDrawStringInfo>(&info) != B_OK)
|
|
break;
|
|
|
|
char* string = (char*)malloc(info.stringLength + 1);
|
|
if (string == NULL)
|
|
break;
|
|
|
|
if (code != AS_DRAW_STRING_WITH_DELTA) {
|
|
// In this case, info.delta will NOT contain valid values.
|
|
info.delta = (escapement_delta){ 0, 0 };
|
|
}
|
|
|
|
if (link.Read(string, info.stringLength) != B_OK) {
|
|
free(string);
|
|
break;
|
|
}
|
|
// Terminate the string
|
|
string[info.stringLength] = '\0';
|
|
|
|
picture->WriteDrawString(info.location, string, info.stringLength,
|
|
info.delta);
|
|
|
|
// We need to update the pen location
|
|
fCurrentView->PenToScreenTransform().Apply(&info.location);
|
|
DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
|
|
if (drawingEngine->LockParallelAccess()) {
|
|
BPoint penLocation = drawingEngine->DrawStringDry(
|
|
string, info.stringLength, info.location, &info.delta);
|
|
|
|
fCurrentView->ScreenToPenTransform().Apply(&penLocation);
|
|
fCurrentView->CurrentState()->SetPenLocation(penLocation);
|
|
|
|
drawingEngine->UnlockParallelAccess();
|
|
}
|
|
|
|
free(string);
|
|
break;
|
|
}
|
|
|
|
case AS_DRAW_STRING_WITH_OFFSETS:
|
|
{
|
|
int32 stringLength;
|
|
if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
|
|
break;
|
|
|
|
int32 glyphCount;
|
|
if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
|
|
break;
|
|
|
|
// NOTE: Careful, the + 1 is for termination!
|
|
BStackOrHeapArray<char, 512> string(
|
|
(stringLength + 1 + 63) / 64 * 64);
|
|
BStackOrHeapArray<BPoint, 512> locations(glyphCount);
|
|
if (!string.IsValid() || !locations.IsValid())
|
|
break;
|
|
|
|
if (link.Read(string, stringLength) != B_OK)
|
|
break;
|
|
// Count UTF8 glyphs and make sure we have enough locations
|
|
if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
|
|
break;
|
|
if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
|
|
break;
|
|
// Terminate the string
|
|
string[stringLength] = '\0';
|
|
|
|
const SimpleTransform transform =
|
|
fCurrentView->PenToScreenTransform();
|
|
for (int32 i = 0; i < glyphCount; i++)
|
|
transform.Apply(&locations[i]);
|
|
|
|
picture->WriteDrawString(string, stringLength, locations,
|
|
glyphCount);
|
|
|
|
DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
|
|
if (drawingEngine->LockParallelAccess()) {
|
|
// Update pen location
|
|
BPoint penLocation = drawingEngine->DrawStringDry(
|
|
string, stringLength, locations);
|
|
|
|
fCurrentView->ScreenToPenTransform().Apply(&penLocation);
|
|
fCurrentView->CurrentState()->SetPenLocation(penLocation);
|
|
|
|
drawingEngine->UnlockParallelAccess();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_STROKE_SHAPE:
|
|
case AS_FILL_SHAPE:
|
|
{
|
|
BRect shapeFrame;
|
|
int32 opCount;
|
|
int32 ptCount;
|
|
|
|
link.Read<BRect>(&shapeFrame);
|
|
link.Read<int32>(&opCount);
|
|
link.Read<int32>(&ptCount);
|
|
|
|
BStackOrHeapArray<uint32, 512> opList(opCount);
|
|
BStackOrHeapArray<BPoint, 512> ptList(ptCount);
|
|
if (!opList.IsValid() || !ptList.IsValid()
|
|
|| link.Read(opList, opCount * sizeof(uint32)) < B_OK
|
|
|| link.Read(ptList, ptCount * sizeof(BPoint)) < B_OK) {
|
|
break;
|
|
}
|
|
picture->WriteDrawShape(opCount, opList, ptCount,
|
|
ptList, code == AS_FILL_SHAPE);
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_DRAW_BITMAP:
|
|
{
|
|
ViewDrawBitmapInfo info;
|
|
link.Read<ViewDrawBitmapInfo>(&info);
|
|
|
|
BReference<ServerBitmap> bitmap(App()->GetBitmap(info.bitmapToken), true);
|
|
if (bitmap == NULL)
|
|
break;
|
|
|
|
picture->WriteDrawBitmap(info.bitmapRect, info.viewRect,
|
|
bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(),
|
|
bitmap->ColorSpace(), info.options, bitmap->Bits(),
|
|
bitmap->BitsLength());
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_DRAW_PICTURE:
|
|
{
|
|
int32 token;
|
|
link.Read<int32>(&token);
|
|
|
|
BPoint where;
|
|
if (link.Read<BPoint>(&where) == B_OK) {
|
|
BReference<ServerPicture> pictureToDraw(App()->GetPicture(token), true);
|
|
if (pictureToDraw != NULL) {
|
|
// We need to make a copy of the picture, since it can
|
|
// change after it has been drawn
|
|
BReference<ServerPicture> copy(App()->CreatePicture(pictureToDraw), true);
|
|
picture->NestPicture(copy);
|
|
picture->WriteDrawPicture(where, copy->Token());
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_SET_CLIP_REGION:
|
|
{
|
|
int32 rectCount;
|
|
status_t status = link.Read<int32>(&rectCount);
|
|
// a negative count means no
|
|
// region for the current draw state,
|
|
// but an *empty* region is actually valid!
|
|
// even if it means no drawing is allowed
|
|
|
|
if (status < B_OK)
|
|
break;
|
|
|
|
if (rectCount >= 0) {
|
|
// we are supposed to set the clipping region
|
|
BRegion region;
|
|
if (rectCount > 0 && link.ReadRegion(®ion) < B_OK)
|
|
break;
|
|
picture->WriteSetClipping(region);
|
|
} else {
|
|
// we are supposed to clear the clipping region
|
|
picture->WriteClearClipping();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_CLIP_TO_PICTURE:
|
|
{
|
|
int32 pictureToken;
|
|
BPoint where;
|
|
bool inverse = false;
|
|
|
|
link.Read<int32>(&pictureToken);
|
|
if (pictureToken < 0)
|
|
break;
|
|
|
|
link.Read<BPoint>(&where);
|
|
if (link.Read<bool>(&inverse) != B_OK)
|
|
break;
|
|
|
|
BReference<ServerPicture> pictureToClip(fServerApp->GetPicture(pictureToken), true);
|
|
if (pictureToClip != NULL) {
|
|
// We need to make a copy of the picture, since it can
|
|
// change after it has been drawn
|
|
BReference<ServerPicture> copy(App()->CreatePicture(pictureToClip), true);
|
|
picture->NestPicture(copy);
|
|
picture->WriteClipToPicture(copy->Token(), where, inverse);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_CLIP_TO_RECT:
|
|
{
|
|
bool inverse;
|
|
BRect rect;
|
|
link.Read<bool>(&inverse);
|
|
link.Read<BRect>(&rect);
|
|
picture->WriteClipToRect(rect, inverse);
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_CLIP_TO_SHAPE:
|
|
{
|
|
bool inverse;
|
|
link.Read<bool>(&inverse);
|
|
|
|
shape_data shape;
|
|
link.Read<int32>(&shape.opCount);
|
|
link.Read<int32>(&shape.ptCount);
|
|
shape.opSize = shape.opCount * sizeof(uint32);
|
|
shape.ptSize = shape.ptCount * sizeof(BPoint);
|
|
shape.opList = new(nothrow) uint32[shape.opCount];
|
|
shape.ptList = new(nothrow) BPoint[shape.ptCount];
|
|
if (link.Read(shape.opList, shape.opSize) >= B_OK
|
|
&& link.Read(shape.ptList, shape.ptSize) >= B_OK) {
|
|
picture->WriteClipToShape(shape.opCount, shape.opList,
|
|
shape.ptCount, shape.ptList, inverse);
|
|
}
|
|
|
|
delete[] shape.opList;
|
|
delete[] shape.ptList;
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_BEGIN_PICTURE:
|
|
{
|
|
BReference <ServerPicture> newPicture(App()->CreatePicture(), true);
|
|
if (newPicture != NULL) {
|
|
newPicture->PushPicture(picture);
|
|
newPicture->SyncState(fCurrentView);
|
|
fCurrentView->SetPicture(newPicture);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_APPEND_TO_PICTURE:
|
|
{
|
|
int32 token;
|
|
link.Read<int32>(&token);
|
|
|
|
BReference<ServerPicture> appendPicture(App()->GetPicture(token), true);
|
|
if (appendPicture != NULL) {
|
|
//picture->SyncState(fCurrentView);
|
|
appendPicture->AppendPicture(picture);
|
|
}
|
|
|
|
fCurrentView->SetPicture(appendPicture);
|
|
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_END_PICTURE:
|
|
{
|
|
BReference<ServerPicture> poppedPicture(picture->PopPicture(), true);
|
|
fCurrentView->SetPicture(poppedPicture);
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<int32>(picture->Token());
|
|
fLink.Flush();
|
|
return true;
|
|
}
|
|
|
|
case AS_VIEW_BEGIN_LAYER:
|
|
{
|
|
uint8 opacity;
|
|
link.Read<uint8>(&opacity);
|
|
|
|
Layer* layer = dynamic_cast<Layer*>(picture);
|
|
if (layer == NULL)
|
|
break;
|
|
|
|
Layer* nextLayer = new(std::nothrow) Layer(opacity);
|
|
if (nextLayer == NULL)
|
|
break;
|
|
|
|
if (opacity != 255) {
|
|
fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
|
|
fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
|
|
B_ALPHA_COMPOSITE);
|
|
fCurrentView->CurrentState()->SetDrawingModeLocked(true);
|
|
}
|
|
|
|
nextLayer->PushLayer(layer);
|
|
fCurrentView->SetPicture(nextLayer);
|
|
break;
|
|
}
|
|
|
|
case AS_VIEW_END_LAYER:
|
|
{
|
|
Layer* layer = dynamic_cast<Layer*>(picture);
|
|
if (layer == NULL)
|
|
break;
|
|
|
|
BReference<Layer> previousLayer(layer->PopLayer(), true);
|
|
if (previousLayer == NULL) {
|
|
// End last layer
|
|
return false;
|
|
}
|
|
fCurrentView->SetPicture(previousLayer);
|
|
|
|
previousLayer->WriteBlendLayer(layer);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
case AS_VIEW_SET_BLENDING_MODE:
|
|
{
|
|
ViewBlendingModeInfo info;
|
|
link.Read<ViewBlendingModeInfo>(&info);
|
|
|
|
picture->BeginOp(B_PIC_SET_BLENDING_MODE);
|
|
picture->AddInt16((int16)info.sourceAlpha);
|
|
picture->AddInt16((int16)info.alphaFunction);
|
|
picture->EndOp();
|
|
|
|
fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha,
|
|
info.alphaFunction);
|
|
fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha,
|
|
info.alphaFunction);
|
|
break;
|
|
}*/
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if (link.NeedsReply()) {
|
|
fLink.StartMessage(B_ERROR);
|
|
fLink.Flush();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/*! \brief Message-dispatching loop for the ServerWindow
|
|
|
|
Watches the ServerWindow's message port and dispatches as necessary
|
|
*/
|
|
void
|
|
ServerWindow::_MessageLooper()
|
|
{
|
|
// Send a reply to our window - it is expecting fMessagePort
|
|
// port and some other info.
|
|
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Attach<port_id>(fMessagePort);
|
|
|
|
int32 minWidth, maxWidth, minHeight, maxHeight;
|
|
fWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
|
|
|
|
fLink.Attach<BRect>(fWindow->Frame());
|
|
fLink.Attach<float>((float)minWidth);
|
|
fLink.Attach<float>((float)maxWidth);
|
|
fLink.Attach<float>((float)minHeight);
|
|
fLink.Attach<float>((float)maxHeight);
|
|
fLink.Flush();
|
|
|
|
BPrivate::LinkReceiver& receiver = fLink.Receiver();
|
|
bool quitLoop = false;
|
|
|
|
while (!quitLoop) {
|
|
//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
|
|
// fMessagePort));
|
|
|
|
int32 code;
|
|
status_t status = receiver.GetNextMessage(code);
|
|
if (status != B_OK) {
|
|
// that shouldn't happen, it's our port
|
|
printf("Someone deleted our message port!\n");
|
|
|
|
// try to let our client die happily
|
|
NotifyQuitRequested();
|
|
break;
|
|
}
|
|
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
bigtime_t start = system_time();
|
|
#endif
|
|
|
|
Lock();
|
|
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
bigtime_t diff = system_time() - start;
|
|
if (diff > 10000) {
|
|
printf("ServerWindow %s: lock acquisition took %" B_PRId64 " usecs\n",
|
|
Title(), diff);
|
|
}
|
|
#endif
|
|
|
|
int32 messagesProcessed = 0;
|
|
bigtime_t processingStart = system_time();
|
|
bool lockedDesktopSingleWindow = false;
|
|
|
|
while (true) {
|
|
if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
|
|
// this means the client has been killed
|
|
DTRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message "
|
|
"code\n", Title()));
|
|
|
|
if (code == AS_DELETE_WINDOW) {
|
|
fLink.StartMessage(B_OK);
|
|
fLink.Flush();
|
|
}
|
|
|
|
if (lockedDesktopSingleWindow)
|
|
fDesktop->UnlockSingleWindow();
|
|
|
|
quitLoop = true;
|
|
|
|
// ServerWindow's destructor takes care of pulling this object
|
|
// off the desktop.
|
|
ASSERT(fWindow->IsHidden());
|
|
break;
|
|
}
|
|
|
|
// Acquire the appropriate lock
|
|
bool needsAllWindowsLocked = _MessageNeedsAllWindowsLocked(code);
|
|
if (needsAllWindowsLocked) {
|
|
// We may already still hold the read-lock from the previous
|
|
// inner-loop iteration.
|
|
if (lockedDesktopSingleWindow) {
|
|
fDesktop->UnlockSingleWindow();
|
|
lockedDesktopSingleWindow = false;
|
|
}
|
|
fDesktop->LockAllWindows();
|
|
} else {
|
|
// We never keep the write-lock across inner-loop iterations,
|
|
// so there is nothing else to do besides read-locking unless
|
|
// we already have the read-lock from the previous iteration.
|
|
if (!lockedDesktopSingleWindow) {
|
|
fDesktop->LockSingleWindow();
|
|
lockedDesktopSingleWindow = true;
|
|
}
|
|
}
|
|
|
|
if (atomic_and(&fRedrawRequested, 0) != 0) {
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
bigtime_t redrawStart = system_time();
|
|
#endif
|
|
fWindow->RedrawDirtyRegion();
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
diff = system_time() - redrawStart;
|
|
atomic_add(&sRedrawProcessingTime.count, 1);
|
|
# ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
|
|
atomic_add64(&sRedrawProcessingTime.time, diff);
|
|
# else
|
|
sRedrawProcessingTime.time += diff;
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
bigtime_t dispatchStart = system_time();
|
|
#endif
|
|
_DispatchMessage(code, receiver);
|
|
|
|
#ifdef PROFILE_MESSAGE_LOOP
|
|
if (code >= 0 && code < AS_LAST_CODE) {
|
|
diff = system_time() - dispatchStart;
|
|
atomic_add(&sMessageProfile[code].count, 1);
|
|
#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
|
|
atomic_add64(&sMessageProfile[code].time, diff);
|
|
#else
|
|
sMessageProfile[code].time += diff;
|
|
#endif
|
|
if (diff > 10000) {
|
|
printf("ServerWindow %s: message %" B_PRId32 " took %"
|
|
B_PRId64 " usecs\n", Title(), code, diff);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (needsAllWindowsLocked)
|
|
fDesktop->UnlockAllWindows();
|
|
|
|
// Only process up to 70 waiting messages at once (we have the
|
|
// Desktop locked), but don't hold the lock longer than 10 ms
|
|
if (!receiver.HasMessages() || ++messagesProcessed > 70
|
|
|| system_time() - processingStart > 10000) {
|
|
if (lockedDesktopSingleWindow)
|
|
fDesktop->UnlockSingleWindow();
|
|
break;
|
|
}
|
|
|
|
// next message
|
|
status_t status = receiver.GetNextMessage(code);
|
|
if (status != B_OK) {
|
|
// that shouldn't happen, it's our port
|
|
printf("Someone deleted our message port!\n");
|
|
if (lockedDesktopSingleWindow)
|
|
fDesktop->UnlockSingleWindow();
|
|
|
|
// try to let our client die happily
|
|
NotifyQuitRequested();
|
|
break;
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
}
|
|
|
|
// We were asked to quit the message loop - either on request or because of
|
|
// an error.
|
|
Quit();
|
|
// does not return
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::ScreenChanged(const BMessage* message)
|
|
{
|
|
SendMessageToClient(message);
|
|
|
|
if (fDirectWindowInfo.IsSet() && fDirectWindowInfo->IsFullScreen())
|
|
_ResizeToFullScreen();
|
|
}
|
|
|
|
|
|
status_t
|
|
ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
|
|
{
|
|
if (target == B_NULL_TOKEN)
|
|
target = fClientToken;
|
|
|
|
BMessenger reply;
|
|
BMessage::Private messagePrivate((BMessage*)msg);
|
|
return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
|
|
0, false, reply);
|
|
}
|
|
|
|
|
|
Window*
|
|
ServerWindow::MakeWindow(BRect frame, const char* name,
|
|
window_look look, window_feel feel, uint32 flags, uint32 workspace)
|
|
{
|
|
// The non-offscreen ServerWindow uses the DrawingEngine instance from
|
|
// the desktop.
|
|
return new(std::nothrow) ::Window(frame, name, look, feel, flags,
|
|
workspace, this, fDesktop->HWInterface()->CreateDrawingEngine());
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
|
|
{
|
|
ASSERT_MULTI_LOCKED(fDesktop->WindowLocker());
|
|
|
|
if (!fDirectWindowInfo.IsSet())
|
|
return;
|
|
|
|
STRACE(("HandleDirectConnection(bufferState = %" B_PRId32 ", driverState = "
|
|
"%" B_PRId32 ")\n", bufferState, driverState));
|
|
|
|
status_t status = fDirectWindowInfo->SetState(
|
|
(direct_buffer_state)bufferState, (direct_driver_state)driverState,
|
|
fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(),
|
|
fWindow->VisibleContentRegion());
|
|
|
|
if (status != B_OK) {
|
|
char errorString[256];
|
|
snprintf(errorString, sizeof(errorString),
|
|
"%s killed for a problem in DirectConnected(): %s",
|
|
App()->Signature(), strerror(status));
|
|
syslog(LOG_ERR, errorString);
|
|
|
|
// The client application didn't release the semaphore
|
|
// within the given timeout. Or something else went wrong.
|
|
// Deleting this member should make it crash.
|
|
fDirectWindowInfo.Unset();
|
|
} else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START)
|
|
fIsDirectlyAccessing = true;
|
|
else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP)
|
|
fIsDirectlyAccessing = false;
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::_SetCurrentView(View* view)
|
|
{
|
|
if (fCurrentView == view)
|
|
return;
|
|
|
|
fCurrentView = view;
|
|
fCurrentDrawingRegionValid = false;
|
|
_UpdateDrawState(fCurrentView);
|
|
|
|
#if 0
|
|
#if DELAYED_BACKGROUND_CLEARING
|
|
if (fCurrentView && fCurrentView->IsBackgroundDirty()
|
|
&& fWindow->InUpdate()) {
|
|
DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
|
|
if (drawingEngine->LockParallelAccess()) {
|
|
fWindow->GetEffectiveDrawingRegion(fCurrentView,
|
|
fCurrentDrawingRegion);
|
|
fCurrentDrawingRegionValid = true;
|
|
BRegion dirty(fCurrentDrawingRegion);
|
|
|
|
BRegion content;
|
|
fWindow->GetContentRegion(&content);
|
|
|
|
fCurrentView->Draw(drawingEngine, &dirty, &content, false);
|
|
|
|
drawingEngine->UnlockParallelAccess();
|
|
}
|
|
}
|
|
#endif
|
|
#endif // 0
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::_UpdateDrawState(View* view)
|
|
{
|
|
// switch the drawing state
|
|
// TODO: is it possible to scroll a view while it
|
|
// is being drawn? probably not... otherwise the
|
|
// "offsets" passed below would need to be updated again
|
|
DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
|
|
if (view != NULL && drawingEngine != NULL) {
|
|
BPoint leftTop(0, 0);
|
|
if (view->GetAlphaMask() != NULL) {
|
|
view->LocalToScreenTransform().Apply(&leftTop);
|
|
view->GetAlphaMask()->SetCanvasGeometry(leftTop, view->Bounds());
|
|
leftTop = BPoint(0, 0);
|
|
}
|
|
view->PenToScreenTransform().Apply(&leftTop);
|
|
drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::_UpdateCurrentDrawingRegion()
|
|
{
|
|
if (!fCurrentDrawingRegionValid
|
|
|| fWindow->DrawingRegionChanged(fCurrentView)) {
|
|
fWindow->GetEffectiveDrawingRegion(fCurrentView, fCurrentDrawingRegion);
|
|
fCurrentDrawingRegionValid = true;
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
ServerWindow::_MessageNeedsAllWindowsLocked(uint32 code) const
|
|
{
|
|
switch (code) {
|
|
case AS_SET_WINDOW_TITLE:
|
|
case AS_ADD_TO_SUBSET:
|
|
case AS_REMOVE_FROM_SUBSET:
|
|
case AS_VIEW_CREATE_ROOT:
|
|
case AS_VIEW_CREATE:
|
|
case AS_SEND_BEHIND:
|
|
case AS_SET_LOOK:
|
|
case AS_SET_FEEL:
|
|
case AS_SET_FLAGS:
|
|
case AS_SET_WORKSPACES:
|
|
case AS_WINDOW_MOVE:
|
|
case AS_WINDOW_RESIZE:
|
|
case AS_SET_SIZE_LIMITS:
|
|
case AS_SYSTEM_FONT_CHANGED:
|
|
case AS_SET_DECORATOR_SETTINGS:
|
|
case AS_GET_MOUSE:
|
|
case AS_DIRECT_WINDOW_SET_FULLSCREEN:
|
|
// case AS_VIEW_SET_EVENT_MASK:
|
|
// case AS_VIEW_SET_MOUSE_EVENT_MASK:
|
|
case AS_TALK_TO_DESKTOP_LISTENER:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::_ResizeToFullScreen()
|
|
{
|
|
BRect screenFrame;
|
|
|
|
{
|
|
AutoReadLocker _(fDesktop->ScreenLocker());
|
|
const Screen* screen = fWindow->Screen();
|
|
if (screen == NULL)
|
|
return;
|
|
|
|
screenFrame = fWindow->Screen()->Frame();
|
|
}
|
|
|
|
fDesktop->MoveWindowBy(fWindow.Get(),
|
|
screenFrame.left - fWindow->Frame().left,
|
|
screenFrame.top - fWindow->Frame().top);
|
|
fDesktop->ResizeWindowBy(fWindow.Get(),
|
|
screenFrame.Width() - fWindow->Frame().Width(),
|
|
screenFrame.Height() - fWindow->Frame().Height());
|
|
}
|
|
|
|
|
|
status_t
|
|
ServerWindow::_EnableDirectWindowMode()
|
|
{
|
|
if (fDirectWindowInfo.IsSet()) {
|
|
// already in direct window mode
|
|
return B_ERROR;
|
|
}
|
|
|
|
if (fDesktop->HWInterface()->FrontBuffer() == NULL) {
|
|
// direct window mode not supported
|
|
return B_UNSUPPORTED;
|
|
}
|
|
|
|
fDirectWindowInfo.SetTo(new(std::nothrow) DirectWindowInfo);
|
|
if (!fDirectWindowInfo.IsSet())
|
|
return B_NO_MEMORY;
|
|
|
|
status_t status = fDirectWindowInfo->InitCheck();
|
|
if (status != B_OK) {
|
|
fDirectWindowInfo.Unset();
|
|
|
|
return status;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
void
|
|
ServerWindow::_DirectWindowSetFullScreen(bool enable)
|
|
{
|
|
window_feel feel = kWindowScreenFeel;
|
|
|
|
if (enable) {
|
|
fDesktop->HWInterface()->SetCursorVisible(false);
|
|
|
|
fDirectWindowInfo->EnableFullScreen(fWindow->Frame(), fWindow->Feel());
|
|
_ResizeToFullScreen();
|
|
} else {
|
|
const BRect& originalFrame = fDirectWindowInfo->OriginalFrame();
|
|
|
|
fDirectWindowInfo->DisableFullScreen();
|
|
|
|
// Resize window back to its original size
|
|
fDesktop->MoveWindowBy(fWindow.Get(),
|
|
originalFrame.left - fWindow->Frame().left,
|
|
originalFrame.top - fWindow->Frame().top);
|
|
fDesktop->ResizeWindowBy(fWindow.Get(),
|
|
originalFrame.Width() - fWindow->Frame().Width(),
|
|
originalFrame.Height() - fWindow->Frame().Height());
|
|
|
|
fDesktop->HWInterface()->SetCursorVisible(true);
|
|
}
|
|
|
|
fDesktop->SetWindowFeel(fWindow.Get(), feel);
|
|
}
|