In the Client BWindow
_InitData
function after getting the reply from the app server. There is the task for the view creation.
void
BWindow::_InitData(BRect frame, const char* title, window_look look,
window_feel feel, uint32 flags, uint32 workspace, int32 bitmapToken)
{
STRACE(("BWindow::InitData()\n"));
if (be_app == NULL) {
debugger("You need a valid BApplication object before interacting with "
"the app_server");
return;
}
frame.left = roundf(frame.left);
frame.top = roundf(frame.top);
frame.right = roundf(frame.right);
frame.bottom = roundf(frame.bottom);
fFrame = frame;
if (title == NULL)
title = "";
fTitle = strdup(title);
_SetName(title);
fFeel = feel;
fLook = look;
fFlags = flags | B_ASYNCHRONOUS_CONTROLS;
fInTransaction = bitmapToken >= 0;
fUpdateRequested = false;
fActive = false;
fShowLevel = 1;
fTopView = NULL;
fFocus = NULL;
fLastMouseMovedView = NULL;
fKeyMenuBar = NULL;
fDefaultButton = NULL;
// Shortcut 'Q' is handled in _HandleKeyDown() directly, as its message
// get sent to the application, and not one of our handlers.
// It is only installed for non-modal windows, though.
fNoQuitShortcut = IsModal();
if ((fFlags & B_NOT_CLOSABLE) == 0 && !IsModal()) {
// Modal windows default to non-closable, but you can add the
// shortcut manually, if a different behaviour is wanted
AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
}
// Edit modifier keys
AddShortcut('X', B_COMMAND_KEY, new BMessage(B_CUT), NULL);
AddShortcut('C', B_COMMAND_KEY, new BMessage(B_COPY), NULL);
AddShortcut('V', B_COMMAND_KEY, new BMessage(B_PASTE), NULL);
AddShortcut('A', B_COMMAND_KEY, new BMessage(B_SELECT_ALL), NULL);
// Window modifier keys
AddShortcut('M', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_MINIMIZE_), NULL);
AddShortcut('Z', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_ZOOM_), NULL);
AddShortcut('Z', B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_ZOOM_), NULL);
AddShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(B_HIDE_APPLICATION), NULL);
AddShortcut('F', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_SEND_TO_FRONT_), NULL);
AddShortcut('B', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_SEND_BEHIND_), NULL);
// We set the default pulse rate, but we don't start the pulse
fPulseRate = 500000;
fPulseRunner = NULL;
fIsFilePanel = false;
fMenuSem = -1;
fMinimized = false;
fMaxZoomHeight = 32768.0;
fMaxZoomWidth = 32768.0;
fMinHeight = 0.0;
fMinWidth = 0.0;
fMaxHeight = 32768.0;
fMaxWidth = 32768.0;
fLastViewToken = B_NULL_TOKEN;
// TODO: other initializations!
fOffscreen = false;
// Create the server-side window
port_id receivePort = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY,
"w<app_server");
if (receivePort < B_OK) {
// TODO: huh?
debugger("Could not create BWindow's receive port, used for "
"interacting with the app_server!");
delete this;
return;
}
STRACE(("BWindow::InitData(): contacting app_server...\n"));
// let app_server know that a window has been created.
fLink = new(std::nothrow) BPrivate::PortLink(
BApplication::Private::ServerLink()->SenderPort(), receivePort);
if (fLink == NULL) {
// Zombie!
return;
}
{
BPrivate::AppServerLink lockLink;
// we're talking to the server application using our own
// communication channel (fLink) - we better make sure no one
// interferes by locking that channel (which AppServerLink does
// implicetly)
if (bitmapToken < 0) {
fLink->StartMessage(AS_CREATE_WINDOW);
} else {
fLink->StartMessage(AS_CREATE_OFFSCREEN_WINDOW);
fLink->Attach<int32>(bitmapToken);
fOffscreen = true;
}
fLink->Attach<BRect>(fFrame);
fLink->Attach<uint32>((uint32)fLook);
fLink->Attach<uint32>((uint32)fFeel);
fLink->Attach<uint32>(fFlags);
fLink->Attach<uint32>(workspace);
fLink->Attach<int32>(_get_object_token_(this));
fLink->Attach<port_id>(receivePort);
fLink->Attach<port_id>(fMsgPort);
fLink->AttachString(title);
port_id sendPort;
int32 code;
if (fLink->FlushWithReply(code) == B_OK
&& code == B_OK
&& fLink->Read<port_id>(&sendPort) == B_OK) {
// read the frame size and its limits that were really
// enforced on the server side
fLink->Read<BRect>(&fFrame);
fLink->Read<float>(&fMinWidth);
fLink->Read<float>(&fMaxWidth);
fLink->Read<float>(&fMinHeight);
fLink->Read<float>(&fMaxHeight);
fMaxZoomWidth = fMaxWidth;
fMaxZoomHeight = fMaxHeight;
} else
sendPort = -1;
// Redirect our link to the new window connection
fLink->SetSenderPort(sendPort);
STRACE(("Server says that our send port is %ld\n", sendPort));
}
STRACE(("Window locked?: %s\n", IsLocked() ? "True" : "False"));
_CreateTopView();
}
In the last chapter we have explored all the function of this snippet but _CreateTopView()
is left. Now it's time to explore this one.
#1 _CreateTopView()
This function is defined at: src/kits/interface/Window.cpp
void
BWindow::_CreateTopView()
{
STRACE(("_CreateTopView(): enter\n"));
BRect frame = fFrame.OffsetToCopy(B_ORIGIN);
// TODO: what to do here about std::nothrow?
fTopView = new BView(frame, "fTopView", B_FOLLOW_ALL, B_WILL_DRAW);
fTopView->fTopLevelView = true;
//inhibit check_lock()
fLastViewToken = _get_object_token_(fTopView);
// set fTopView's owner, add it to window's eligible handler list
// and also set its next handler to be this window.
STRACE(("Calling setowner fTopView = %p this = %p.\n",
fTopView, this));
fTopView->_SetOwner(this);
// we can't use AddChild() because this is the top view
fTopView->_CreateSelf();
STRACE(("BuildTopView ended\n"));
}
In the _CreateTopView
function of the BWindow
class, a top-level BView
is created and initialized. Here's what happens in this function:
BRect frame = fFrame.OffsetToCopy(B_ORIGIN);
- It creates a BRect named frame by copying the window's frame and offsetting it to the origin (0,0).
fTopView = new BView(frame, "fTopView", B_FOLLOW_ALL, B_WILL_DRAW);
- It creates a new
BView
namedfTopView
using the frame calculated earlier. The view is given the name"fTopView",
follows all resizing of its parent, and will draw its content.
fTopView->fTopLevelView = true;
- It sets the
fTopLevelView
member variable of thefTopView
totrue
. This likely indicates that this view is the top-level view within the window.
//inhibit check_lock()
fLastViewToken = _get_object_token_(fTopView);
- It inhibits the check for locks on the view by setting the
fLastViewToken
member variable to the object token offTopView
.
fTopView->_SetOwner(this);
- It sets the owner of
fTopView
to the window itself by calling_SetOwner(this)
onfTopView
. This associates the window with the view.
fTopView->_CreateSelf();
- It then calls
_CreateSelf()
onfTopView
to initialize the view. This function likely performs internal setup and initialization for the view.
#2 BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags) Constructor
This constructor is defined at: src/kits/interface/View.cpp
BView::BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags)
:
BHandler(name)
{
_InitData(frame, name, resizingMode, flags);
}
The constructor BView::BView
initializes a BView
object with the provided parameters. Here's what it does:
- It calls the constructor of the base class
BHandler
with the provided name, initializing the handler part of theBView
. - It then calls the
_InitData
function with the provided frame, name, resizing mode, and flags. This function initializes the data members of theBView
object.
#3 _InitData(BRect frame, const char* name, uint32 resizingMode, uint32 flags)
This function is defined at: src/kits/interface/View.cpp
void
BView::_InitData(BRect frame, const char* name, uint32 resizingMode,
uint32 flags)
{
// Info: The name of the view is set by BHandler constructor
STRACE(("BView::_InitData: enter\n"));
// initialize members
if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
printf("%s BView::_InitData(): resizing mode or flags swapped\n", name);
// There are applications that swap the resize mask and the flags in the
// BView constructor. This does not cause problems under BeOS as it just
// ors the two fields to one 32bit flag.
// For now we do the same but print the above warning message.
// TODO: this should be removed at some point and the original
// version restored:
// fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
fFlags = resizingMode | flags;
// handle rounding
frame.left = roundf(frame.left);
frame.top = roundf(frame.top);
frame.right = roundf(frame.right);
frame.bottom = roundf(frame.bottom);
fParentOffset.Set(frame.left, frame.top);
fOwner = NULL;
fParent = NULL;
fNextSibling = NULL;
fPreviousSibling = NULL;
fFirstChild = NULL;
fShowLevel = 0;
fTopLevelView = false;
fCurrentPicture = NULL;
fCommArray = NULL;
fVerScroller = NULL;
fHorScroller = NULL;
fIsPrinting = false;
fAttached = false;
// TODO: Since we cannot communicate failure, we don't use std::nothrow here
// TODO: Maybe we could auto-delete those views on AddChild() instead?
fState = new BPrivate::ViewState;
fBounds = frame.OffsetToCopy(B_ORIGIN);
fShelf = NULL;
fEventMask = 0;
fEventOptions = 0;
fMouseEventOptions = 0;
fLayoutData = new LayoutData;
fToolTip = NULL;
if ((flags & B_SUPPORTS_LAYOUT) != 0) {
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
SetLowUIColor(ViewUIColor());
SetHighUIColor(B_PANEL_TEXT_COLOR);
}
}
fFlags = resizingMode | flags;
- It combines the resizing mode and flags to set the view's flags.
// handle rounding
frame.left = roundf(frame.left);
frame.top = roundf(frame.top);
frame.right = roundf(frame.right);
frame.bottom = roundf(frame.bottom);
- It rounds the coordinates of the frame to integer values using the
roundf
function.
#4 _CreateSelf()
This function is defined at: src/kits/interface/View.cpp
bool
BView::_CreateSelf()
{
// AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
// current view mechanism via _CheckLockAndSwitchCurrent() - the token
// of the view and its parent are both send to the server.
if (fTopLevelView)
fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
else
fOwner->fLink->StartMessage(AS_VIEW_CREATE);
fOwner->fLink->Attach<int32>(_get_object_token_(this));
fOwner->fLink->AttachString(Name());
fOwner->fLink->Attach<BRect>(Frame());
fOwner->fLink->Attach<BPoint>(LeftTop());
fOwner->fLink->Attach<uint32>(ResizingMode());
fOwner->fLink->Attach<uint32>(fEventMask);
fOwner->fLink->Attach<uint32>(fEventOptions);
fOwner->fLink->Attach<uint32>(Flags());
fOwner->fLink->Attach<bool>(IsHidden(this));
fOwner->fLink->Attach<rgb_color>(fState->view_color);
if (fTopLevelView)
fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
else
fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
fOwner->fLink->Flush();
_CheckOwnerLockAndSwitchCurrent();
fState->UpdateServerState(*fOwner->fLink);
// we create all its children, too
for (BView* child = fFirstChild; child != NULL;
child = child->fNextSibling) {
child->_CreateSelf();
}
fOwner->fLink->Flush();
return true;
}
Determining Creation Type:
- The function distinguishes between creating a top-level view (
fTopLevelView
) and creating a regular view. - For top-level view, a special message (
AS_VIEW_CREATE_ROOT
) is sent to the server. Otherwise, the standardAS_VIEW_CREATE
message is used.
Preparing Message:
- The function starts constructing the message to create the view by using the appropriate message type (
AS_VIEW_CREATE_ROOT
orAS_VIEW_CREATE
). - It attaches various parameters to the message, including:
- Token of the view: Identifies the view uniquely.
- Name of the view.
- Frame: Defines the position and size of the view.
- Position (Left-Top): Specifies the top-left corner of the view within its parent's coordinate system.
- Resizing mode: Determines how the view behaves when its parent is resized.
- Event mask: Specifies which types of events the view should receive.
- Event options: Additional options related to event handling.
- Flags: Various flags indicating properties and behavior of the view.
- Visibility: Indicates whether the view is hidden.
- View color: Specifies the color of the view.
- Token of the parent view: Identifies the parent view of the current view.
Sending Message:
- The constructed message, along with all attached parameters, is sent to the server via the owner's message link (fOwner->fLink).
- This communication with the server initializes the view's representation on the screen.
Updating Server State:
- After sending the creation message, the function updates the server-side state of the view based on any changes that occurred during creation.
- This ensures that the server's representation of the view is synchronized with the client-side representation.
Creating Children:
- The function iterates over all child views of the current view (
fFirstChild
) and recursively calls_CreateSelf()
for each child. - This process ensures that all child views are also created and properly initialized.
Finalizing Message:
- Once all child views are created, another flush operation is performed on the message link to ensure all pending messages are sent to the server.
Returning Success:
- Finally, the function returns
true
to indicate that the view creation process was successful.