Skip to main content

The Object Model

Understanding SomeWM's object model is the foundation for everything else. Once you grasp how screens, tags, clients, and widgets relate, configuration becomes intuitive.

The Core Objects

Screen

A screen represents a physical or virtual display. If you have two monitors, you have two screens.

-- Get the primary screen
local s = screen.primary

-- Get all screens
for s in screen do
print(s.index, s.geometry.width .. "x" .. s.geometry.height)
end

-- Get the currently focused screen
local focused = awful.screen.focused()

Each screen has:

  • Geometry - position and size (s.geometry)
  • Workarea - usable space after subtracting panels (s.workarea)
  • Tags - the virtual workspaces for this screen
  • Wibars - the panels attached to this screen

Tag

A tag is a virtual workspace. Windows are assigned to tags, and you view tags to see those windows. Unlike traditional workspaces, a window can belong to multiple tags simultaneously.

-- Get tags for a screen
local tags = screen.primary.tags

-- View a specific tag
tags[2]:view_only()

-- Toggle a tag's visibility (show multiple tags at once)
awful.tag.viewtoggle(tags[3])

-- Create tags for a screen
awful.tag({"1", "2", "3", "web", "code"}, s, awful.layout.suit.tile)

Key tag concepts:

  • Selected tags are currently visible on their screen
  • A screen can show multiple selected tags at once
  • Each screen has its own independent set of tags

Client

A client is a window - any application window you can see and interact with. Terminals, browsers, editors - they're all clients.

-- Get the focused client
local c = client.focus

-- Get all clients
for _, c in ipairs(client.get()) do
print(c.name)
end

-- Common client properties
c.floating = true -- float above tiled windows
c.maximized = true -- fill the screen
c.minimized = true -- hide from view
c.ontop = true -- stay above other windows

Clients belong to:

  • One screen - the display they're on
  • One or more tags - the workspaces they appear in

Wibox and Wibar

A wibox is a box that holds widgets. A wibar is a wibox that's docked to a screen edge (top, bottom, left, or right).

-- Create a wibar at the top of a screen
s.mywibar = awful.wibar {
position = "top",
screen = s,
}

-- Create a floating wibox anywhere
local popup = wibox {
width = 200,
height = 100,
visible = true,
}

Widget

A widget is a visual element inside a wibox. Widgets come in three flavors:

TypePurposeExamples
PrimitivesDisplay contenttextbox, imagebox, progressbar
ContainersModify one widgetbackground, margin, constraint
LayoutsArrange multiple widgetsfixed, flex, align

Widgets compose by nesting:

-- A textbox inside a margin inside a background
wibox.widget {
{
{
text = "Hello",
widget = wibox.widget.textbox,
},
margins = 8,
widget = wibox.container.margin,
},
bg = "#333333",
widget = wibox.container.background,
}

The Hierarchy

Here's how everything fits together:

Screen 1                          Screen 2
├── Tag "1" (selected) ├── Tag "1"
│ ├── Client: Firefox │ └── Client: Slack
│ └── Client: Terminal │
├── Tag "2" ├── Tag "2" (selected)
│ └── Client: VS Code │ └── Client: Spotify
├── Tag "3" (empty) │
│ └── Wibar (top)
└── Wibar (top) └── [widgets...]
├── Taglist widget
├── Tasklist widget
└── Clock widget

Key points:

  • Each screen has its own tags and wibars
  • Each tag belongs to exactly one screen
  • Each client belongs to one screen but can have multiple tags
  • Wibars are attached to a screen edge
  • Widgets live inside wibars (or standalone wiboxes)

Focus vs Selection

These terms are easy to confuse but mean different things:

TermApplies toMeaning
FocusedClientsReceives keyboard input. Only ONE client is focused globally.
SelectedTagsCurrently visible. Multiple tags can be selected per screen.
-- The focused client (receives keyboard input)
local c = client.focus

-- Selected tags on a screen (currently visible)
local selected = screen.primary.selected_tags

-- The focused screen (where the focused client is)
local s = awful.screen.focused()

Focus flow

When you type, keystrokes go to:

  1. The focused client (if any)
  2. Global keybindings (if not consumed by the client)

The focused client is always on a selected tag of some screen.

Common Operations

Now that you understand the objects, here's how common operations map to them:

"I want to..."ObjectAPI
Switch workspaceTagtag:view_only()
View multiple workspacesTagawful.tag.viewtoggle(tag)
Move window to workspaceClient + Tagc:move_to_tag(tag)
Move window to screenClient + Screenc:move_to_screen(s)
Close windowClientc:kill()
Toggle floatingClientc.floating = not c.floating
Add widget to barWibarModify wibar's widget property
Focus next windowClientawful.client.focus.byidx(1)
Focus next screenScreenawful.screen.focus_relative(1)

Accessing Objects

From anywhere

-- All clients
client.get()

-- All screens
for s in screen do ... end

-- Primary screen
screen.primary

-- Currently focused
client.focus
awful.screen.focused()

From a client

local c = client.focus

c.screen -- the screen this client is on
c:tags() -- tags this client belongs to
c.first_tag -- the first tag (useful for single-tag clients)

From a screen

local s = awful.screen.focused()

s.tags -- all tags for this screen
s.selected_tags -- currently visible tags
s.clients -- all clients on this screen
s.geometry -- screen dimensions
s.workarea -- usable area (minus panels)

From a tag

local t = awful.screen.focused().selected_tag

t.screen -- the screen this tag belongs to
t:clients() -- clients with this tag
t.selected -- is this tag currently visible?
t.layout -- current layout for this tag

Signals: Reacting to Changes

Objects emit signals when things change. Connect to signals to react:

-- React when a client is created
client.connect_signal("manage", function(c)
-- c is the new client
print("New client: " .. c.name)
end)

-- React when focus changes
client.connect_signal("focus", function(c)
c.border_color = "#ff0000"
end)

-- React when a screen is added (monitor plugged in)
screen.connect_signal("added", function(s)
-- Set up tags and wibar for new screen
end)

Common signals:

ObjectSignalWhen
clientmanageNew client created
clientfocus / unfocusFocus changes
clientproperty::nameWindow title changes
screenadded / removedMonitor (dis)connected
tagproperty::selectedTag visibility changes

Next Steps

Now that you understand the object model:

  • Architecture - How the layers communicate
  • Basics - Hands-on practice with these concepts
  • Widgets - Build widgets that use these objects