Receive Client View Creation Message

In the last chapter we flushed the message AS_CREATE_ROOT for the view root and AS_VIEW_CREATE for the normal view. These messages are received by ServerWindow in _DispatchMessage function.

void
ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
{
	switch (code) {
		
		// other cases...
		
		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;
		}
		
		// Other cases...
  1. AS_VIEW_CREATE_ROOT:
    1. This case handles the creation of a top-level view, meaning a view that does not have a parent. It's the first view to be created in the window.
    2. The function checks if fCurrentView is already set. If it is, it prints a debug message and breaks the execution.
    3. If fCurrentView is not set, it calls _CreateView() passing NULL as the parent view, indicating that this is the root/top-level view.
    4. The newly created view is then set as the current view (fCurrentView) and is also set as the top view of the window (fWindow->SetTopView()).
  2. AS_VIEW_CREATE:
    1. This case handles the creation of a regular view, i.e., a view that has a parent.
    2. The function begins by printing a debug message indicating the reception of the AS_VIEW_CREATE message and the name of the current view.
    3. It then calls _CreateView() passing a pointer to a parent view (&parent) as an argument. This function returns the newly created view.
    4. If both the parent and the new view are not NULL, indicating successful creation, it adds the new view as a child to the parent view using the AddChild() method.
    5. If either the parent or the new view is NULL, it prints a debug message indicating the failure of view creation and deletes the new view to avoid memory leaks.

#1 _CreateView(link, NULL)

This function is defined: src/servers/app/ServerWindow.cpp

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;
}

This function _CreateView is responsible for creating views within the ServerWindow.

  1. Reading Data from Message:
    1. It reads various pieces of information about the view from the incoming message received via the link. This includes:
      1. token: An identifier for the view.
      2. name: The name of the view.
      3. frame: The position and size of the view.
      4. scrollingOffset: The scrolling offset of the view.
      5. resizeMask: Resizing behavior flags.
      6. eventMask and eventOptions: Event handling flags.
      7. flags: Additional flags for the view.
      8. hidden: Whether the view is initially hidden.
      9. viewColor: The color of the view.
      10. parentToken: Token of the parent view.
    2.