Back to Portfolio
Tool DockUnreal Engine 5 Plugin · v1.0

Tool Dock

Embed external application windows — and in-process Qt/PySide widgets — into dockable Unreal Editor panels.

View on FAB

What You Need

Tool Dock reparents native window handles, which is a Win32 operation. There is no configuration, no account, and no external dependency — install it and it works.

EngineUnreal Engine 5.8+
PlatformWindows 10/11 (Win64 only)
Target AppsAny app with a normal top-level window
DependenciesNone — UE5 and Win32 only
💡
No setup required.Point it at Blender, Substance Painter, a standalone PySide tool, a browser window, or anything else with a normal top-level window. The application doesn't need to know Tool Dock exists.
⚠️
Windows only.The plugin's module is restricted to the Win64 platform. The embedding relies on Win32 window-ownership semantics that have no direct equivalent on macOS or Linux.

Install from FAB

Tool Dock is available on FAB, Epic's official plugin marketplace.

1
Get it on FAB
Visit the Tool Dock listing on FAB and add it to your account.
2
Install via the Unreal Editor
Open the FAB plugin manager inside Unreal Editor (Edit → Plugins → FAB), find Tool Dock, and click Install. The editor handles the rest.
3
Restart the editor
Restart when prompted. Tool Dock adds two entries under Window → Tools: Tool Dock and Attach Tool…
💡
Verify installation: If the menu entries don't appear, go to Edit → Plugins, search for “Tool Dock”, and enable it.

Getting Started

There are two ways to use Tool Dock, and they're independent — you can use either, or both at once.

The Shared Panelmulti-tab

One dock holding several windows as tabs, much like browser tabs. This is a normal saved-layout editor tab, so the editor remembers where you put it.

1
Open the panel
Go to Window → Tools → Tool Dock. An empty panel appears, docked wherever the editor last placed it.
2
Pick a window
Click the big + button in the middle of the empty panel, or the small + in the tab bar once you have tabs. A searchable list of every capturable window on your desktop appears.
3
Click an entry
The window is reparented into the panel immediately. Its native title bar disappears and it now resizes with the panel, docks with it, and hides when you switch to another editor tab.
💡
Only the activetab's window is actually rendered. Every other docked window is hidden until you switch to it, so you never get overlapping native windows fighting for the same screen space.

Dedicated Instancesone app per tab

Sometimes you don't want a shared dock — you want one specific app pinned to its own tab, with its own icon and title.

1
Open the quick-attach menu
Go to Window → Tools → Attach Tool… This is the same window picker as the + button, but it behaves differently.
2
Pick a window
Instead of adding a tab to the shared panel, a brand-new, independent editor tab opens containing only that one app — titled and iconed after it, with no tab bar and no + button.
3
Repeat as needed
You can open as many dedicated instances as you like, alongside each other and alongside the shared panel. A given window can only ever be docked in one place at a time.
⚠️
Dedicated instances don't survive an editor restart. Their tabs are registered on the fly when you open them and aren't part of the saved-layout system. Reopen them after restarting, or script it from a startup Python file using the scripting API.

Releasing a Window

“Releasing” restores a docked window to a normal, independent desktop window at its original size and position. It does not close or terminate the application. A window is released when you:

Close its tab
Click the × on the tab, or drag the tab off the panel and release.
Close the panel
Closing the Tool Dock panel releases everything docked in it.
Quit the editor
Every window still docked anywhere is released on editor shutdown.
Release is non-destructive.The window's original style, extended style, owner, and screen position are all restored — you get the window back exactly as if you'd never docked it.

Key Features

🪟
True Window Embedding
Reparents a native window handle into an editor panel via Win32. Not a screenshot, not a stream — the real application, fully interactive, running at full speed.
🗂️
Multi-Tab Shared Panel
Capture several windows into one dock and switch between them like browser tabs. Only the active tab's window renders, so nothing overlaps.
📌
Dedicated Instances
Pin one app to its own independent editor tab, titled and iconed after that app. Open as many as you like, each fully separate.
🖱️
Drag and Drop Capture
Drag any window by its title bar onto the panel and release to dock it. Detected cross-process through a WinEvent hook — no DLL injection.
🐍
In-Process Qt/PySide Support
Dock Qt widgets launched from Unreal's own Python, not just external applications. Pass a widget's winId() straight to the scripting API.
🔓
Non-Destructive Release
Releasing restores the window's original style, extended style, owner, and screen position. The application is never closed or terminated.
🎯
Custom Title Bar Aware
Apps that draw their own title bar start OS drags the plugin can detect. Tool Dock evicts them from the dock mid-gesture so the drag continues naturally.
🛡️
Safe by Construction
Every capture path funnels through one chokepoint that refuses to dock a Slate window and re-validates the handle immediately before reparenting.
⚙️
Filterable Capture List
Per-user settings control whether minimized and editor-owned windows are listed, plus a wildcard ignore list for transient window classes.

Scripting API

Exposed to Python as unreal.ToolDockLibrary, and to Blueprint under the Tool Dock node category. All calls must be made from the game thread; calling from a background thread logs an error and returns False.

open_tool_dock()bool
Opens the shared Tool Dock panel, or brings it to the front when it is already open.
close_tool_dock()bool
Closes the shared panel, releasing every window docked in it back to the desktop. The applications themselves are not closed.
is_tool_dock_open()bool
True when the shared panel is currently present in the editor layout.
attach_process_to_new_tool_dock(process_id)bool
Finds the given process's main window and opens a dedicated instance for it. Prefers the largest non-minimized window the process owns.
  • process_idPID of an external application, e.g. from subprocess.Popen(...).pid
attach_window_to_new_tool_dock(window_handle)bool
Opens a dedicated instance for an exact native window handle. Use this — not the PID variant — for in-process Qt/PySide widgets.
  • window_handleNative window handle (HWND on Windows), e.g. int(widget.winId())

Which “attach” function should I use?

This is the one thing worth getting right up front. The two attach functions are not interchangeable.

💡
You have a process ID and the target is an external application you launched yourself — use attach_process_to_new_tool_dock. It searches that process's top-level windows and picks the best main-window candidate, preferring the largest non-minimized one.
⚠️
You have an in-process Qt/PySide widget running inside the editor's own Python — use attach_window_to_new_tool_dock instead. PID search deliberately skips in-process windows, and winId() is a window handle, not a process id — passing it to the PID-based function will never match anything.

Attach an external app by PID

pythonExternal application
import subprocess
import unreal

process = subprocess.Popen(["C:/Program Files/Blender Foundation/blender.exe"])

# Give the app a moment to create its main window before searching for it.
unreal.ToolDockLibrary.attach_process_to_new_tool_dock(process.pid)

Attach an in-process PySide widget by handle

pythonIn-process Qt widget
import unreal
from PySide6 import QtWidgets

widget = QtWidgets.QWidget()
widget.setWindowTitle("My Pipeline Tool")
widget.show()

# winId() is a window handle, not a PID - use the handle-based function.
unreal.ToolDockLibrary.attach_window_to_new_tool_dock(int(widget.winId()))

Open the shared panel

pythonShared panel
import unreal

if not unreal.ToolDockLibrary.is_tool_dock_open():
    unreal.ToolDockLibrary.open_tool_dock()

Settings

Edit → Project Settings → Plugins → Tool Dock

SettingDefaultDescription
Minimized FilterShow MinimizedWhether minimized windows appear in the capture list. Set to Hide Minimized to declutter if you keep a lot of windows minimized.
Include In Process WindowsOnWhether top-level windows owned by the editor's own process — Qt/PySide widgets launched from Python — are offered for capture at all. Slate's own windows are always excluded regardless.
Ignored Window Classes5 defaultsWin32 class names never offered for capture. Supports a trailing wildcard, so Chrome_WidgetWin_* ignores every Chrome window.
Enable Drag And Drop CaptureOnWhether dragging a window onto the panel by its title bar captures it. Turning this off leaves the + button as the only way to capture.
💡
The default ignored classes cover common editor-process noise: the splash screen (SplashScreenClass), tooltips (tooltips_class32), common dialogs (#32770), and IME windows (IME, MSCTFIME UI). Add to this list if some other transient window keeps showing up.
These settings are stored per-user in EditorPerProjectUserSettings, so changing them doesn't affect your teammates.

Tutorials

Walkthroughs covering every feature. Click a tutorial to jump to it.


← Back to Tutorials
Tutorial 1

Installation

Installing Tool Dock from FAB and confirming the editor picked it up.
1
Install from the FAB plugin manager
Open Edit → Plugins → FAB, find Tool Dock, and click Install to Engine.
2
Enable the plugin
If it isn't enabled automatically, search for Tool Dock under Edit → Plugins and tick the checkbox.
The plugin manager with Tool Dock enabledTool Dock enabled in the Plugins browser
3
Confirm the menu entries
After restarting, Window → Tools contains Tool Dock and Attach Tool…
The Tools menu with Tool Dock and Attach Tool…The two entries under Window → Tools

← Back to Tutorials
Tutorial 2

Your First Capture

Opening the shared panel and pulling an external application into it.
1
Open the panel
Window → Tools → Tool Dock. The empty state explains both ways to capture.
The empty Tool Dock panelThe empty Tool Dock panel
2
Open the capture menu
Click the + badge. Entries are split into In Editor and Not In Editor.
The capture menu, split by categoryThe capture menu, split by category
3
Search to narrow the list
The search box matches on title, process name, PID, and window class. Sections whose rows are all filtered out hide their heading too.
Filtering the capture list by processFiltering the capture list by process
4
Click an entry to dock it
The window loses its frame and snaps into the panel as a new tab.
An external app docked in the panelAn external app docked in the panel
5
Resize and re-dock freely
The embedded window tracks the panel every frame. Drag the panel to another part of the layout, or float it, and the window follows.
Screenshot pendingThe docked window tracking a panel resize/assets/tutorials/tool-dock/capture-05-resize.png

← Back to Tutorials
Tutorial 3

Working with Tabs

Switching, reordering, and closing tabs in the shared multi-tab panel.
1
Capture a second window
Use the small + at the end of the tab bar. Each captured window becomes its own tab.
Two windows docked as separate tabsTwo windows docked as separate tabs
2
Switch between tabs
Click a tab to activate it. Only the active tab's window is visible — the rest are hidden so their native popups can't paint over the foreground.
Switching to the second tabSwitching to the second tab
3
Reorder by dragging
Drag one tab onto another to swap their positions. The drop target highlights as you hover it.
Dragging a tab onto its neighbourDragging a tab onto its neighbour
4
Close a tab
The × releases the window back to the desktop and removes the tab. The app keeps running.
The per-tab close buttonThe per-tab close button
5
Or drag a tab out to release it
Dragging a tab clear of the bar shows an unlink hint. Releasing there does the same thing as clicking ×.
The release hint shown while dragging outThe release hint shown while dragging out

← Back to Tutorials
Tutorial 4

Drag and Drop Capture

Docking a window by dragging it onto the panel by its title bar.
1
Grab the window's title bar
Start a normal OS window drag on any capturable application.
2
Hover the panel
A Drop to dockoverlay appears over the panel, naming the window you're dragging.
The drop overlay while hovering the panelThe drop overlay while hovering the panel
3
Release to capture
The window docks as a new tab exactly as if you'd picked it from the + menu.
The window docked after releaseThe window docked after release
4
In-process windows look slightly different
Dragging an editor-owned Qt window blocks the editor's render loop for the whole gesture, so the hint is drawn as a native DWM-composited window instead of the usual Slate overlay. Capture on release works identically.
The native drop hint used for in-process dragsThe native drop hint used for in-process drags

← Back to Tutorials
Tutorial 5

Dedicated Instances

Pinning one application to its own independent editor tab via Attach Tool…
1
Open Attach Tool…
Window → Tools → Attach Tool… opens the same picker as the + button.
The Attach Tool… submenuThe Attach Tool… submenu
2
Pick an application
A brand-new editor tab opens holding only that app.
A dedicated instance in its own tabA dedicated instance in its own tab
3
Note the tab identity
The tab takes its icon from the app's .exe and its label from the window title, so it reads like a first-class tool tab.
The tab using the app's own iconThe tab using the app's own icon
4
Open several at once
Dedicated instances are fully independent of each other and of the shared panel. Dock them side by side like any other editor tabs.
Two dedicated instances docked side by sideTwo dedicated instances docked side by side
5
They close themselves
If the app's window goes away — closed externally, or the capture failed — the tab closes itself rather than lingering empty.
The tab closing after its app exitsThe tab closing after its app exits

← Back to Tutorials
Tutorial 6

Docking a PySide Tool

Embedding a Qt widget created from Unreal's own Python interpreter.
1
Create and show your widget
Build the widget as you normally would from the editor's Python console or a startup script.
A PySide widget floating over the editorA PySide widget floating over the editor
2
Capture it from the menu
Editor-owned widgets also show up under In Editor in the + menu, as long as Include In Process Windows is on.
The widget listed under In EditorThe widget listed under In Editor
3
Work with it docked
The widget is fully interactive and keeps its own event loop. Nothing about your tool's code needs to change.
The PySide tool docked in the editorThe PySide tool docked in the editor
4
Release it like anything else
Closing the tab restores the widget to a normal floating window, owned by the editor as it was before.
The widget floating again after releaseThe widget floating again after release

← Back to Tutorials
Tutorial 7

Tuning the Capture List

Using Project Settings to control which windows are offered for capture.
1
Open the settings
Edit → Project Settings → Plugins → Tool Dock.
The Tool Dock settings panelThe Tool Dock settings panel
2
Hide minimized windows
Set Minimized Filter to Hide Minimized if your capture list is cluttered.
The minimized filter in actionThe minimized filter in action
3
Add an ignored class
Add a Win32 class name — with an optional trailing * — to keep a noisy application out of the list for good.
Adding a wildcard ignore patternAdding a wildcard ignore pattern
4
Turn off drag-to-dock
Clear Enable Drag And Drop Captureif you'd rather always go through the + button.
Disabling drag-and-drop captureDrag-and-drop capture disabled

Changelog

All notable changes to Tool Dock, organized by version.

v1.0.0Latest

First public release. Embed external application windows and in-process Qt/PySide widgets into dockable Unreal Editor panels.

Added
  • newShared multi-tab Tool Dock panel, with tab switching, drag-to-reorder, and per-tab release.
  • newDedicated single-app instances via Window → Tools → Attach Tool…, each in its own editor tab titled and iconed after the target application.
  • newDrag-and-drop capture: drag any window onto the panel by its title bar, detected cross-process through a WinEvent hook with no DLL injection.
  • newPython and Blueprint scripting API exposed as unreal.ToolDockLibrary, with both PID-based and handle-based attach entry points.
  • newSearchable capture menu matching on title, process name, PID, and window class, with per-category sections that hide when fully filtered.
  • newPer-user settings for minimized-window filtering, in-process window inclusion, wildcard class ignore patterns, and drag-to-dock toggling.
  • newAnti-cheat detection: window styles are read back after being written, and a blocked capture rolls itself back and notifies the user.

FAQ

A window I expect to see isn't in the capture list.

Work through these in order:

  • Check Settings — it may be filtered out by Include In Process Windows, Minimized Filter, or an Ignored Window Classes pattern.
  • Check it isn't already docked somewhere. Already-docked windows are excluded from every picker, across the shared panel and all dedicated instances.
  • Windows on another virtual desktop are cloaked by the OS and deliberately skipped.
  • Windows with no title text, and tool-styled windows with no owner, are treated as transient popups and filtered.
Capture fails with an anti-cheat warning.

Some applications are protected by kernel-level anti-cheat drivers that silently swallow the SetWindowLongPtr style change Tool Dock relies on. The plugin reads the styles back after writing them, notices they didn't take, rolls its change back and tells you — rather than leaving you with a half-captured window. This is a hard block that no external tool can work around.

attach_process_to_new_tool_dock returns False for my PySide widget.

Use attach_window_to_new_tool_dockwith the widget's winId() instead. PID search intentionally skips in-process windows — and winId() is a window handle, not a process id, so passing it to the PID-based function will never match anything.

Does docking close or restart the application?

No. Tool Dock never launches, closes, or terminates anything. It only changes an existing window's style and owner. Release puts the original style, extended style, owner, and screen position back, and you get a normal desktop window again — the application never knows it moved.

Do docked windows survive an editor restart?

Partially. The shared Tool Dock panel is a normal saved-layout tab, so its presence and position persist. The windows that were docked insideit do not — the target application isn't necessarily still running when the editor comes back up.

Dedicated instances don't persist either: their tabs are registered on the fly when you open them and are not part of the saved-layout system. Reopen them after a restart, or script it from a startup Python file.

A released window ended up somewhere strange on screen.

Tool Dock clamps the restored rectangle to the current virtual desktop bounds, so a window can never be stranded fully off-screen. An unusual multi-monitor change while a window was docked can still produce a surprising result. Drag it back into view; its position isn't tracked once released.

Why does dragging a docked app by its own title bar undock it?

That's deliberate. Apps that draw a custom title bar start a real OS move loop (WM_NCLBUTTONDOWN with HTCAPTION). Tool Dock detects the resulting drift and evicts the window from the dock in place, restoring its frame so the drag you already started continues naturally on a free-floating window. Resizing does not undock — that gesture is told apart and cancelled so the panel re-snaps.

Is macOS or Linux supported?

No. Tool Dock is Windows-only and its module is restricted to the Win64 platform. The embedding relies on Win32 window ownership semantics that have no direct equivalent elsewhere.

Disclaimer

Tool Dock is not affiliated with, endorsed by, or sponsored by any of the applications it can embed. It does not launch, modify, close, or terminate third-party software — it only changes an existing window's style and owner, and restores both on release.

Applications protected by kernel-level anti-cheat drivers cannot be captured. This is a hard block enforced by those drivers and no external tool can work around it; Tool Dock detects the refusal, rolls its own change back, and reports it rather than failing silently.

The developer will endeavor to keep this plugin up to date, however operating system behaviour and third-party applications may change at any time without notice and continued compatibility cannot be guaranteed.