Into the DecoraManager (allocating decorator and behavior)

The last Chapter function of _InitWindowStack() does a call to gDecorManager.AllocateDecorator(this).

Where,

DecorManager gDecorManager;

It is an global variable declared inside the file: src/servers/app/decorator/DecorManager.cpp

So gDecorManager.AllocateDecorator(this) is calling the function AllocateDecorator

Diagrammatically representation of Decorator classes.

            +----------------+
            |    Decorator   |
            +----------------+
                    |
                    |
                    V
            +----------------+
            |  TabDecorator  |
            +----------------+
                    |
                    |
                    V
            +----------------+
            | DefaultDecorator|
            +----------------+
                    |
                    |
                    V
            +----------------+
            |  SATDecorator  |
            +----------------+
  • Each box represents a class.
  • Arrows indicate inheritance relationships, with the derived class pointing to its base class.
  • Decorator is the base class, and each subsequent class inherits from the class above it.
  • SATDecorator is the most derived class, inheriting from DefaultDecorator, which inherits from TabDecorator, which in turn inherits from Decorator.

Let's explore this function:

#1 DecorManager :: AllocateDecorator(.)

It is defined in the file: src/servers/app/decorator/DecorManager.cpp

Decorator*
DecorManager::AllocateDecorator(Window* window)
{
	// Create a new instance of the current decorator.
	// Ownership is that of the caller

	if (!fCurrentDecor) {
		// We should *never* be here. If we do, it's a bug.
		debugger("DecorManager::AllocateDecorator has a NULL decorator");
		return NULL;
	}

	// Are we previewing a specific decorator?
	if (window == fPreviewWindow) {
		if (fPreviewDecor != NULL) {
			return fPreviewDecor->AllocateDecorator(window->Desktop(),
				window->GetDrawingEngine(), window->Frame(), window->Title(),
				window->Look(), window->Flags());
		} else {
			fPreviewWindow = NULL;
		}
	}

	return fCurrentDecor->AllocateDecorator(window->Desktop(),
		window->GetDrawingEngine(), window->Frame(), window->Title(),
		window->Look(), window->Flags());
}

This method is responsible for allocating a new decorator for a given window.

	if (!fCurrentDecor) {
		debugger("DecorManager::AllocateDecorator has a NULL decorator");
		return NULL;
	}

It checks if the fCurrentDecor member variable is NULL. If it is, it triggers a debugger breakpoint because having a NULL decorator at this point indicates a bug in the program.

	if (window == fPreviewWindow) {
		if (fPreviewDecor != NULL) {
			return fPreviewDecor->AllocateDecorator(window->Desktop(),
				window->GetDrawingEngine(), window->Frame(), window->Title(),
				window->Look(), window->Flags());
		} else {
			fPreviewWindow = NULL;
		}
	}

It checks if the given window is the same as the window currently being previewed (fPreviewWindow). If it is, and a preview decorator (fPreviewDecor) is available, it allocates and returns a decorator specific to the preview settings. If fPreviewDecor is NULL, it sets fPreviewWindow to NULL to indicate that there's no longer a preview in progress.

	return fCurrentDecor->AllocateDecorator(window->Desktop(),
		window->GetDrawingEngine(), window->Frame(), window->Title(),
		window->Look(), window->Flags());

If the window is not being previewed or if there's no specific preview decorator available, it allocates a decorator using the AllocateDecorator() method of the current decorator (fCurrentDecor). It passes parameters such as the desktop, drawing engine, frame, title, look, and flags of the window to the decorator for allocation.

#2 DecorAddOn :: AllocateDecorator(. . . . . .)

This function is defined in file: src/servers/app/decorator/DecorManager.cpp

Decorator*
DecorAddOn::AllocateDecorator(Desktop* desktop, DrawingEngine* engine,
	BRect rect, const char* title, window_look look, uint32 flags)
{
	if (!desktop->LockSingleWindow())
		return NULL;

	DesktopSettings settings(desktop);
	Decorator* decorator;
	decorator = _AllocateDecorator(settings, rect, desktop);
	desktop->UnlockSingleWindow();
	if (!decorator)
		return NULL;

	decorator->UpdateColors(settings);

	if (decorator->AddTab(settings, title, look, flags) == NULL) {
		delete decorator;
		return NULL;
	}

	decorator->SetDrawingEngine(engine);
	return decorator;
}

This method takes several parameters:

  • desktop: A pointer to the desktop where the window is located.
  • engine: A pointer to the drawing engine used for rendering graphics.
  • rect: The bounding rectangle of the window.
  • title: The title of the window.
  • look: The appearance style of the window.
  • flags: Additional flags specifying window behavior.
	if (!desktop->LockSingleWindow())
		return NULL;

It locks the desktop to ensure single-window access, preventing race conditions during the allocation process. If it fails to lock the desktop, it returns NULL.

Race conditions occur when multiple threads or processes access shared resources concurrently without proper synchronization, leading to unpredictable outcomes. In this case, simultaneous attempts to lock or unlock the desktop by multiple threads or processes could result in race conditions.

To mitigate this, proper synchronization mechanisms, such as mutexes or semaphores, should be used to ensure that only one thread or process accesses the desktop at a time. This would prevent race conditions and ensure the correctness of the code.

	DesktopSettings settings(desktop);
	Decorator* decorator;
	decorator = _AllocateDecorator(settings, rect, desktop);
	desktop->UnlockSingleWindow();
  • It creates a DesktopSettings object to capture the current settings of the desktop.
  • It then calls the _AllocateDecorator() method to allocate a decorator based on the desktop settings, window dimensions, and the desktop itself.
  • After allocation, it unlocks the desktop.
	if (!decorator)
		return NULL;

If the allocation of the decorator fails, it returns NULL

	decorator->UpdateColors(settings);

It updates the colors of the decorators based on the desktop settings.

	if (decorator->AddTab(settings, title, look, flags) == NULL) {
		delete decorator;
		return NULL;
	}

It attempts to add a tab to the decorator based on the window title, appearance style, and flags. If adding the tab fails, it deletes the decorator and returns NULL.

	decorator->SetDrawingEngine(engine);
	return decorator;

Finally, it sets the drawing engine for the decorator and returns the allocated decorator.

#3 DecorAddOn :: _AllocateDecorator(. . .)

This function is defined at: src/servers/app/decorator/DecorManager.cpp

Decorator*
DecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect,
	Desktop* desktop)
{
	return new (std::nothrow)SATDecorator(settings, rect, desktop);
}

This function creates a new instance of the SATDecorator class,

  • settings: A reference to the DesktopSettings object containing the desktop's settings.
  • rect: The bounding rectangle of the window.
  • desktop: A pointer to the Desktop object representing the desktop where the window is located.

It uses the new (std::nothrow) syntax, which returns a null pointer if memory allocation fails instead of throwing an exception.

Finally, it returns a pointer to the newly created SATDecorator object.

#4 SATDecorator::SATDecorator(. . .)

This constructor is defined in: src/servers/app/stackandtile/SATDecorator.cpp

SATDecorator::SATDecorator(DesktopSettings& settings, BRect frame,
							Desktop* desktop)
	:
	DefaultDecorator(settings, frame, desktop)
{
}

The constructor initializes the SATDecorator by calling the constructor of its base class, DefaultDecorator, passing the provided parameters:

  • settings: A reference to the DesktopSettings object containing the desktop's settings.
  • frame: The bounding rectangle of the window.
  • desktop: A pointer to the Desktop object representing the desktop where the window is located.

The member initializer list : DefaultDecorator(settings, frame, desktop) initializes the base class DefaultDecorator with the provided parameters.

#5 DefaultDecorator::DefaultDecorator(. . .)

This constructor is defined at: src/servers/app/decorator/DefaultDecorator.cpp

DefaultDecorator::DefaultDecorator(DesktopSettings& settings, BRect rect,
	Desktop* desktop)
	:
	TabDecorator(settings, rect, desktop)
{
	// TODO: If the decorator was created with a frame too small, it should
	// resize itself!

	STRACE(("DefaultDecorator:\n"));
	STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",
		rect.left, rect.top, rect.right, rect.bottom));
}

The constructor initializes the DefaultDecorator by calling the constructor of its base class, TabDecorator, passing the provided parameters:

  • settings: A reference to the DesktopSettings object containing the desktop's settings.
  • rect: The bounding rectangle of the window.
  • desktop: A pointer to the Desktop object representing the desktop where the window is located.

The member initializer list : TabDecorator(settings, rect, desktop) initializes the base class TabDecorator with the provided parameters.

#6 TabDecorator::TabDecorator(. . .)

This constructor is defined at: src/servers/app/decorators/TabDecorator.cpp

TabDecorator::TabDecorator(DesktopSettings& settings, BRect frame,
							Desktop* desktop)
	:
	Decorator(settings, frame, desktop),
	fOldMovingTab(0, 0, -1, -1)
{
	STRACE(("TabDecorator:\n"));
	STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",
		frame.left, frame.top, frame.right, frame.bottom));

	// TODO: If the decorator was created with a frame too small, it should
	// resize itself!
}

The constructor initializes the TabDecorator by calling the constructor of its base class, Decorator, passing the provided parameters:

  • settings: A reference to the DesktopSettings object containing the desktop's settings.
  • frame: The bounding rectangle of the window.
  • desktop: A pointer to the Desktop object representing the desktop where the window is located.

The member initializer list : Decorator(settings, frame, desktop) initializes the base class Decorator with the provided parameters.

It also initializes the member variable fOldMovingTab with a BRect object initialized to (0, 0, -1, -1). This variable is used to track the previous position of a moving tab within the decorator.

#7 Decorator:: Decorator(. . .)

This constructor is defined in: src/servers/app/decorator/Decorator.cpp

Decorator::Decorator(DesktopSettings& settings, BRect frame,
					Desktop* desktop)
	:
	fLocker("Decorator"),

	fDrawingEngine(NULL),
	fDrawState(),

	fTitleBarRect(),
	fFrame(frame),
	fResizeRect(),
	fBorderRect(),
	fOutlineBorderRect(),

	fLeftBorder(),
	fTopBorder(),
	fBottomBorder(),
	fRightBorder(),

	fLeftOutlineBorder(),
	fTopOutlineBorder(),
	fBottomOutlineBorder(),
	fRightOutlineBorder(),

	fBorderWidth(-1),
	fOutlineBorderWidth(-1),

	fTopTab(NULL),

	fDesktop(desktop),
	fFootprintValid(false)
{
	memset(&fRegionHighlights, HIGHLIGHT_NONE, sizeof(fRegionHighlights));
}

The constructor initializes the Decorator by initializing its member variables and objects:

  • fLocker: Initializes the BLocker object with the name "Decorator", used for thread synchronization.
  • fDrawingEngine: Initializes a pointer to the DrawingEngine object as NULL.
  • fDrawState: Initializes the DrawState object.
  • fTitleBarRect, fFrame, fResizeRect, fBorderRect, fOutlineBorderRect: Initialize BRect objects representing different regions of the decorator.
  • fLeftBorder, fTopBorder, fBottomBorder, fRightBorder: Initialize BDimensions objects representing the dimensions of different borders of the decorator.
  • fLeftOutlineBorder, fTopOutlineBorder, fBottomOutlineBorder, fRightOutlineBorder: Initialize BOutline objects representing the outline borders of the decorator.
  • fBorderWidth, fOutlineBorderWidth: Initialize the widths of the borders.
  • fTopTab: Initializes a pointer to the top tab object as NULL.
  • fDesktop: Stores a pointer to the desktop where the decorator resides.
  • fFootprintValid: Indicates whether the footprint of the decorator is valid or not.

memset(&fRegionHighlights, HIGHLIGHT_NONE, sizeof(fRegionHighlights)): Initializes the fRegionHighlights array with the HIGHLIGHT_NONE value.

#8 Decorator::UpdateColors(settings)

As we know that SATDecorator is the most derived class. So it's UpdateColors(settings) will be called.

void
SATDecorator::UpdateColors(DesktopSettings& settings)
{
	DefaultDecorator::UpdateColors(settings);

	// Called during construction, and during any changes
	fHighlightTabColor		= tint_color(fFocusTabColor, B_DARKEN_2_TINT);
	fHighlightTabColorLight	= tint_color(fHighlightTabColor,
								(B_LIGHTEN_MAX_TINT + B_LIGHTEN_2_TINT) / 2);
	fHighlightTabColorBevel	= tint_color(fHighlightTabColor, B_LIGHTEN_2_TINT);
	fHighlightTabColorShadow= tint_color(fHighlightTabColor,
								(B_DARKEN_1_TINT + B_NO_TINT) / 2);
}

The UpdateColors function in the SATDecorator class updates colors used within the decorator, leveraging color updates from its base class DefaultDecorator and then customizing further.

DefaultDecorator::UpdateColors(settings);: Calls the UpdateColors function of the DefaultDecorator class, ensuring that any color updates specific to DefaultDecorator are applied first.

Then, it customizes some colors further:

  • fHighlightTabColor: Calculates a new highlight color for tabs by darkening the fFocusTabColor.
  • fHighlightTabColorLight: Adjusts the highlight tab color to be a lighter shade by applying a tint to fHighlightTabColor.
  • fHighlightTabColorBevel: Adjusts the highlight tab color to create a bevel effect by applying a lighter tint.
  • fHighlightTabColorShadow: Adjusts the highlight tab color to create a shadow effect by applying a darker tint.

These color adjustments likely aim to create visual effects, such as shading and highlighting, to enhance the appearance of tabs within the decorator.

#9 DefaultDecorator::UpdateColors(settings)

Defined in: src/servers/app/decorator/DefaultDecorator.cpp

void
DefaultDecorator::UpdateColors(DesktopSettings& settings)
{
	TabDecorator::UpdateColors(settings);
}

The UpdateColors function in the DefaultDecorator class is calling the UpdateColors function of its immediate base class TabDecorator.

#10 TabDecorator::UpdateColors(settings)

Defined in file at: src/servers/app/decorator/TabDecorator.cpp

void
TabDecorator::UpdateColors(DesktopSettings& settings)
{
	// Desktop is write locked, so be quick about it.
	fFocusFrameColor		= settings.UIColor(B_WINDOW_BORDER_COLOR);
	fFocusTabColor			= settings.UIColor(B_WINDOW_TAB_COLOR);
	fFocusTabColorLight		= tint_color(fFocusTabColor,
								(B_LIGHTEN_MAX_TINT + B_LIGHTEN_2_TINT) / 2);
	fFocusTabColorBevel		= tint_color(fFocusTabColor, B_LIGHTEN_2_TINT);
	fFocusTabColorShadow	= tint_color(fFocusTabColor,
								(B_DARKEN_1_TINT + B_NO_TINT) / 2);
	fFocusTextColor			= settings.UIColor(B_WINDOW_TEXT_COLOR);

	fNonFocusFrameColor		= settings.UIColor(B_WINDOW_INACTIVE_BORDER_COLOR);
	fNonFocusTabColor		= settings.UIColor(B_WINDOW_INACTIVE_TAB_COLOR);
	fNonFocusTabColorLight	= tint_color(fNonFocusTabColor,
								(B_LIGHTEN_MAX_TINT + B_LIGHTEN_2_TINT) / 2);
	fNonFocusTabColorBevel	= tint_color(fNonFocusTabColor, B_LIGHTEN_2_TINT);
	fNonFocusTabColorShadow	= tint_color(fNonFocusTabColor,
								(B_DARKEN_1_TINT + B_NO_TINT) / 2);
	fNonFocusTextColor = settings.UIColor(B_WINDOW_INACTIVE_TEXT_COLOR);
}

The UpdateColors function in the TabDecorator class updates various colors used by the decorator based on the provided DesktopSettings.

fFocusFrameColor: Sets the color for the frame of the decorator when it's in focus.

fFocusTabColor: Sets the color for tabs when the decorator is in focus.

fFocusTabColorLight: Calculates a lighter shade of the focus tab color.

fFocusTabColorBevel: Calculates a bevel effect for the focus tab color.

fFocusTabColorShadow: Calculates a shadow effect for the focus tab color.

fFocusTextColor: Sets the text color for text within the decorator when it's in focus.

fNonFocusFrameColor: Sets the color for the frame of the decorator when it's not in focus.

fNonFocusTabColor: Sets the color for tabs when the decorator is not in focus.

fNonFocusTabColorLight: Calculates a lighter shade of the non-focus tab color.

fNonFocusTabColorBevel: Calculates a bevel effect for the non-focus tab color.

fNonFocusTabColorShadow: Calculates a shadow effect for the non-focus tab color.

fNonFocusTextColor: Sets the text color for text within the decorator when it's not in focus.