Project 5: X11 Comparison - Bare-Metal X11 Client
Build the same simple colored window as Project 1, but using raw Xlib to feel the architectural differences between X11 and Wayland.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Intermediate |
| Time Estimate | 1 week |
| Main Programming Language | C (Alternatives: C++, Rust, Zig) |
| Alternative Programming Languages | C++, Rust, Zig |
| Coolness Level | Level 3: “Legacy wizard” |
| Business Potential | Level 1: Resume Gold |
| Prerequisites | Project 1 (Wayland client) |
| Key Topics | Xlib, X11 protocol, ICCCM/EWMH |
1. Learning Objectives
By completing this project, you will:
- Build and run a minimal X11 client using Xlib.
- Understand the X11 request/reply model and event loop.
- Handle Expose events and redraw the window contents.
- Set window properties using atoms (WM_NAME, WM_DELETE_WINDOW).
- Compare the X11 workflow to Wayland and articulate the differences.
2. All Theory Needed (Per-Concept Breakdown)
2.1 X11 Client-Server Architecture and Request/Reply
Fundamentals
X11 is a network-transparent display protocol with a client-server model. The X server owns the display, input devices, and window hierarchy. Clients connect over a socket and send requests (create window, draw, set properties). Some requests have replies, others are asynchronous. The server can also send events (Expose, KeyPress, ConfigureNotify). The model is flexible but complex: clients can inspect and manipulate global state, which is why X11 is powerful but also insecure by modern standards.
Deep Dive into the Concept
In X11, the X server is the authoritative owner of the display and window tree. Clients connect via XOpenDisplay, which establishes a connection to the server (local or remote). This connection is a socket, and X11 was designed to work across networks. Each X11 request is encoded and sent to the server, and the server may respond with a reply. The protocol is “chatty”: many requests require roundtrips. For example, fetching window attributes or property values requires synchronous replies. This is fundamentally different from Wayland, which is local-first and avoids synchronous queries.
The request/reply model impacts performance. Because requests can be batched, the client can send multiple requests without waiting. But when a reply is required, the client must flush and block until the server responds. This introduces latency, especially on remote connections. Xlib abstracts this by buffering requests and only flushing when necessary. The client can explicitly call XFlush or XSync to force communication. Understanding this buffering is critical: if you draw and forget to flush, the server may not process your requests immediately.
The X server also handles input events globally. Unlike Wayland, where clients only receive input when focused, X11 allows clients to listen for global events, query pointer position, and even inject events. This is powerful for debugging tools but is a security risk. It is one of the reasons Wayland moved input routing to the compositor.
Window creation in X11 is also global. Clients create windows with XCreateSimpleWindow, specifying a parent (usually the root window). The server maintains a hierarchy of windows, and the window manager interprets hints (ICCCM, EWMH) to decide decorations, focus, and placement. This is a multi-party model: the server, the client, and the window manager all participate. This complexity is another contrast to Wayland, where the compositor combines server and window manager responsibilities.
The X11 protocol includes atoms and properties, which act as a global key-value system. Clients set properties on windows to communicate metadata (titles, roles, hints). Because the server stores these properties, they are part of global state. This is essential for interoperability but adds complexity compared to Wayland’s explicit protocol objects.
Finally, because X11 is network-transparent, it must serialize and interpret all requests in a way that works across different architectures. This makes the protocol heavier and more general than Wayland’s local, binary message format. The tradeoff is clear: flexibility and network transparency vs security and simplicity. By building a minimal X11 client, you will feel this tradeoff in practice.
Another important piece is the X11 extension system. Core X11 is extended by optional protocols such as XRender, XInput2, XRandR, and XShm. Clients query these extensions at runtime and adjust behavior based on availability. This is powerful but adds branching logic and additional roundtrips. Sequence numbers are also part of the protocol: each request has a sequence ID, and errors or replies refer to it. This explicit tracking aids debugging but again highlights the low-level nature of X11 compared to Wayland’s more constrained, local-first design.
How This Fits on the Project
You will use Xlib’s connection and request model to create a window, select events, and draw. The request/reply model explains why you need to handle Expose events and flush drawing requests.
Definitions & Key Terms
- X Server -> Process that owns the display and input devices.
- Request/Reply -> Client sends request; server may reply.
- Root Window -> Top-level window representing the screen.
- Window Manager -> Client that controls window decorations and focus.
Mental Model Diagram (ASCII)
Client -> X server -> Screen
^ |
| +-> events (Expose, KeyPress)
+-> replies (GetProperty, QueryPointer)
How It Works (Step-by-Step)
- Client connects with
XOpenDisplay. - Client sends requests to create window and map it.
- Server sends Expose events when the window needs redraw.
- Client draws and flushes requests.
Minimal Concrete Example
Display *d = XOpenDisplay(NULL);
Window w = XCreateSimpleWindow(d, DefaultRootWindow(d), 10, 10, 400, 300, 1,
BlackPixel(d, 0), WhitePixel(d, 0));
XMapWindow(d, w);
XFlush(d);
Common Misconceptions
- “X11 is just like Wayland.” -> X11 is a network protocol with global state.
- “Drawing is immediate.” -> Requests are buffered until flushed.
- “Window manager is part of X server.” -> It is a separate client.
Check-Your-Understanding Questions
- Why does X11 have a request/reply model?
- What is the role of the window manager?
- Why must you flush drawing requests?
Check-Your-Understanding Answers
- It supports network transparency and synchronous queries.
- It enforces window policy: decorations, focus, placement.
- Requests are buffered; flushing ensures delivery.
Real-World Applications
- Legacy Linux desktops built entirely on X11.
- Remote display via SSH X11 forwarding.
Where You’ll Apply It
- See Sec. 3.1 What You Will Build (Xlib lifecycle).
- See Sec. 5.10 Phase 1 (window creation and map).
- Also used in: Project 1: Wayland Client for contrast.
References
- Xlib Programming Manual (O’Reilly).
- X11 protocol specification.
Key Insights
X11 trades simplicity for flexibility and network transparency.
Summary
Understanding X11’s client-server model explains why the API feels heavier than Wayland.
Homework/Exercises to Practice the Concept
- Connect to a remote X server over SSH and run your client.
- Use
XSyncand observe the difference vsXFlush. - Query the root window size.
Solutions to the Homework/Exercises
- Use
ssh -Xand run the program remotely. XSyncwaits for server replies;XFlushjust sends requests.- Use
DisplayWidthandDisplayHeight.
2.2 Xlib Event Loop and Expose Redraw
Fundamentals
In X11, the server does not retain window contents. When a window is covered and uncovered, the server sends an Expose event and expects the client to redraw. This is different from Wayland, where the compositor keeps the last buffer. The Xlib event loop processes events like Expose, KeyPress, and ConfigureNotify. Correct X11 clients must redraw in response to Expose events.
Deep Dive into the Concept
The X server owns the window tree and decides when a window needs repainting. When part of a window becomes visible, the server sends an Expose event. This means the client must redraw the affected region. If the client ignores Expose, the window appears blank or corrupted. This design reflects the server’s limited responsibility: it does not store or preserve the client’s pixels. Instead, the client must be able to redraw at any time. This is one of the core differences between X11 and Wayland.
Xlib provides an event loop with XNextEvent, which blocks until the next event. You typically use a loop: XNextEvent, switch on event type, handle Expose by drawing, handle KeyPress by exit or action, handle ClientMessage for window close. Because X11 is event-driven, the client should be prepared for multiple Expose events. Some Expose events may represent partial regions, and the count field indicates if more Expose events are coming. A common optimization is to only redraw when count == 0 (the last Expose in a batch). In a simple client, you can redraw on every Expose for simplicity.
Another difference is that X11 clients can also poll for events using XPending or integrate with file descriptors by using ConnectionNumber. This enables custom event loops with select or poll. For this project, a simple XNextEvent loop is sufficient.
X11 drawing uses a graphics context (GC). You create a GC with XCreateGC and set properties like foreground color. Drawing calls like XFillRectangle send requests to the server. These requests are buffered, so you should call XFlush after drawing to ensure the server processes them. In a tight Expose loop, you may rely on XNextEvent implicitly flushing, but explicit flushing is safer.
Understanding the Expose model explains why X11 applications must keep their UI state and be able to redraw. Toolkits handle this for you; bare Xlib exposes the raw mechanics. When you compare this with Wayland, you see why Wayland feels simpler: the compositor retains the last buffer, and the client only redraws when it wants to update content. X11 places more responsibility on the client for redraw management.
Historically, X11 provided optional “backing store” optimizations, but these were inconsistent across servers and drivers. As a result, most applications assume they must redraw on Expose. If you want to reduce flicker, you can implement double-buffering with an off-screen pixmap: draw into the pixmap, then copy it to the window during Expose. This approach mimics Wayland’s buffer model but uses explicit draw commands instead of shared memory buffers. It also illustrates why modern toolkits exist: they abstract away these repetitive patterns.
Expose events also carry geometry information. The XExposeEvent includes x, y, width, and height fields describing the damaged rectangle, plus a count field indicating if more Expose events are coming. Well-behaved clients can redraw only the damaged region rather than the whole window. For a simple solid-color fill, full redraw is fine, but understanding the region-based model helps you reason about performance in more complex applications. You may also see ConfigureNotify events when the window is resized; these often trigger a full redraw because the window dimensions changed.
How This Fits on the Project
You will implement an event loop that redraws the window on Expose events. This is the core of the X11 client.
Definitions & Key Terms
- Expose Event -> Notification that a window region must be redrawn.
- GC (Graphics Context) -> Drawing state (color, line width, etc.).
- ClientMessage -> Event used for WM_DELETE_WINDOW.
Mental Model Diagram (ASCII)
Expose event -> redraw -> XFlush
How It Works (Step-by-Step)
- Select events (ExposureMask, KeyPressMask).
- Enter event loop.
- On Expose, redraw window contents.
- On KeyPress or ClientMessage, exit.
Minimal Concrete Example
XSelectInput(d, w, ExposureMask | KeyPressMask);
while (running) {
XEvent ev; XNextEvent(d, &ev);
if (ev.type == Expose) draw_window();
}
Common Misconceptions
- “Expose is optional.” -> Without redraw, your window is blank.
- “The server retains pixels.” -> It does not; you must redraw.
- “Events come in order of user actions only.” -> The server can send Expose anytime.
Check-Your-Understanding Questions
- Why do Expose events exist?
- How does X11 redraw differ from Wayland rendering?
- Why might you wait until
count == 0?
Check-Your-Understanding Answers
- The server does not retain window contents.
- Wayland keeps the last buffer; X11 requires client redraw.
- To avoid redundant redraws for batched Expose events.
Real-World Applications
- Classic X11 apps rely on Expose to update UI.
- Remote X11 sessions can trigger frequent Expose events due to latency.
Where You’ll Apply It
- See Sec. 3.2 Functional Requirements (Expose handling).
- See Sec. 5.10 Phase 2 (event loop implementation).
- Also used in: Project 1: Wayland Client.
References
- Xlib Programming Manual (event loop chapter).
Key Insights
Expose-driven redraws are the heart of X11’s rendering model.
Summary
The X11 event loop forces you to redraw on demand, which is why X11 clients must maintain their own UI state.
Homework/Exercises to Practice the Concept
- Resize the window repeatedly and observe Expose events.
- Print Expose
countvalues to see batching. - Add a KeyPress handler for Escape to exit.
Solutions to the Homework/Exercises
- Expose events fire whenever the window is uncovered.
countdecreases to 0 when the batch ends.- Use
XLookupKeysymto detect Escape.
2.3 Atoms, Properties, ICCCM/EWMH
Fundamentals
X11 uses atoms as identifiers for property names. Properties are key/value data stored on windows. Window managers rely on standard properties defined by ICCCM and EWMH to know how to manage windows. For example, WM_NAME sets the window title, and WM_DELETE_WINDOW allows graceful close. Understanding atoms and properties is essential for interoperability.
Deep Dive into the Concept
Atoms in X11 are numeric IDs for strings. The server maintains a table mapping strings to atoms. Clients call XInternAtom to get an atom for a string, and then use that atom to set or query properties. Properties are stored on windows and are typed (e.g., string, integer, atom list). This mechanism is a global key/value store for metadata. It’s how clients communicate their intentions to the window manager.
ICCCM (Inter-Client Communication Conventions Manual) defines core properties and behaviors: WM_NAME for window title, WM_CLASS for class hints, WM_HINTS for input focus and initial state, and WM_PROTOCOLS for supported window manager protocols like WM_DELETE_WINDOW. EWMH (Extended Window Manager Hints) extends ICCCM with modern desktop concepts: _NET_WM_NAME, _NET_WM_PID, _NET_WM_STATE, and workspace properties.
To support a clean close action, you must register WM_DELETE_WINDOW. This involves setting the WM_PROTOCOLS property to include the WM_DELETE_WINDOW atom. When the user closes the window, the window manager sends a ClientMessage event with that atom. Your event loop must detect this and exit. If you do not register WM_DELETE_WINDOW, the window manager may force-close your app.
Properties also affect how the window manager decorates and places your window. For example, _NET_WM_WINDOW_TYPE can signal that a window is a dialog, dock, or toolbar. For this project, setting WM_NAME and WM_DELETE_WINDOW is enough. But understanding the property system is crucial to appreciate X11’s flexibility–and its complexity. Wayland avoids this by encoding semantics directly into protocols rather than global properties.
Atoms and properties are a key part of why X11 is difficult to secure. Any client can set properties on other windows, query global state, or listen to events. This is powerful but dangerous. The Wayland model avoids this by restricting clients to their own objects.
Properties also carry type and format metadata. When you set a property with XChangeProperty, you specify a type atom (such as XA_STRING or UTF8_STRING) and a format (8, 16, or 32 bits). The server stores raw bytes; it does not interpret the data. That means clients and window managers must agree on conventions. Modern desktops expect UTF-8 titles, so many toolkits set both WM_NAME (legacy) and _NET_WM_NAME (UTF-8) to maximize compatibility. This is a good example of how X11’s flexibility leads to extra compatibility work.
You can also subscribe to property changes using PropertyChangeMask, which triggers PropertyNotify events. This is how status bars and window management tools track changes such as window titles or workspace state. While this is not required for a minimal client, it reinforces the idea that properties are a global metadata bus in X11, and any client can observe or modify it.
When you read properties, you typically use XGetWindowProperty, which returns raw data along with the property’s type and format. This is another place where compatibility issues arise: a window manager might set _NET_WM_NAME as UTF-8, while an older client expects XA_STRING. Proper clients check the returned type and format and decode accordingly. You can also delete properties with XDeleteProperty, which is how clients clear state. These details are small, but they show how X11 relies on conventions rather than strict protocol-enforced semantics.
How This Fits on the Project
You will set the window title and register WM_DELETE_WINDOW so the window manager can close your app gracefully.
Definitions & Key Terms
- Atom -> Numeric identifier for a string.
- Property -> Key/value data stored on a window.
- ICCCM -> Core window manager conventions.
- EWMH -> Extended window manager hints.
Mental Model Diagram (ASCII)
Window properties
-----------------
WM_NAME -> "My X11 Window"
WM_PROTOCOLS -> [WM_DELETE_WINDOW]
How It Works (Step-by-Step)
- Intern atoms for WM_NAME and WM_DELETE_WINDOW.
- Set WM_NAME property for title.
- Set WM_PROTOCOLS to include WM_DELETE_WINDOW.
- Handle ClientMessage events to exit.
Minimal Concrete Example
Atom wmDelete = XInternAtom(d, "WM_DELETE_WINDOW", False);
XSetWMProtocols(d, w, &wmDelete, 1);
XStoreName(d, w, "My X11 Window");
Common Misconceptions
- “Window title is just a field.” -> It is a property stored on the server.
- “WM_DELETE_WINDOW happens automatically.” -> You must register it.
- “Atoms are strings.” -> They are numeric IDs for strings.
Check-Your-Understanding Questions
- Why does X11 use atoms?
- What is the role of ICCCM?
- How do you handle WM_DELETE_WINDOW?
Check-Your-Understanding Answers
- To efficiently reference property names.
- It defines standard behaviors for window managers.
- Register WM_DELETE_WINDOW and handle ClientMessage.
Real-World Applications
- Window managers rely on EWMH to integrate apps.
- Toolkits set dozens of properties to control behavior.
Where You’ll Apply It
- See Sec. 3.2 Functional Requirements (properties).
- See Sec. 5.10 Phase 2 (event loop with ClientMessage).
- Also used in: Project 1: Wayland Client as contrast.
References
- ICCCM and EWMH specs.
- Xlib Programming Manual.
Key Insights
Properties are X11’s metadata system; atoms are the lookup keys.
Summary
Atoms and properties are essential for making your window behave correctly in the X11 ecosystem.
Homework/Exercises to Practice the Concept
- Set WM_NAME and verify with
xprop. - Add
_NET_WM_PIDand verify. - Handle WM_DELETE_WINDOW and exit cleanly.
Solutions to the Homework/Exercises
- Run
xpropand check WM_NAME property. - Use
XChangePropertyto set PID. - Detect ClientMessage with WM_DELETE_WINDOW.
2.4 Graphics Contexts and Drawing Model
Fundamentals
X11 drawing is performed by sending requests to the X server using a graphics context (GC). The GC stores drawing state like color, line width, and fill style. Drawing calls like XFillRectangle or XDrawLine use the GC. The server performs the rendering. This is different from Wayland, where clients render into buffers themselves.
Deep Dive into the Concept
In X11, the server owns the frame buffer. When you call XFillRectangle, you send a request to the server: “fill this rectangle with the foreground color of GC.” The server executes this in its own process. This means clients do not directly manipulate pixel buffers (unless using extensions like XShm or XRender). The upside is that the server can centralize rendering; the downside is that network latency and roundtrips affect performance.
The GC is a server-side object. You create it with XCreateGC and set attributes like foreground/background color, line width, and font. These attributes persist across draw calls, so you can reuse the GC for multiple operations. This is efficient because it avoids resending attributes for every draw. However, it also means you must manage GC state carefully if you have multiple drawing styles.
For a minimal client, you can create one GC, set the foreground color to your desired background color, and call XFillRectangle on Expose. That will paint the window. If you want more complex graphics (text, lines), you adjust the GC or create multiple GCs. If you use XDrawString, the server uses the font associated with the GC. This is how X11 handles text rendering.
The server also supports backing pixmaps, which are off-screen buffers that you can render to and then copy to the window. This is used for double-buffering to reduce flicker. Without double-buffering, you may see drawing artifacts when Expose triggers multiple redraws. In this project, a simple solid fill is fine, but understanding pixmaps highlights the complexity of X11’s rendering model.
The contrast with Wayland is fundamental: in Wayland, clients own pixels and send buffers; in X11, the server owns pixels and clients send drawing commands. This affects performance, security, and architecture. By building a raw Xlib client, you experience the X11 model directly.
Color handling in X11 also involves visuals and colormaps. A visual defines how pixel values map to colors; a colormap provides the actual mapping. On modern systems, you usually use a TrueColor visual, where pixel values directly encode RGB channels. But in other visuals, you must allocate colors from a colormap. This complexity is mostly hidden for a simple XFillRectangle, but it becomes important if you use XImage or XPutImage to send pixel data directly. You need to ensure your pixel format matches the window’s depth and visual masks. Getting this wrong results in strange colors or crashes.
If you decide to use XPutImage, you are effectively emulating the Wayland buffer model by sending raw pixel data to the server. However, you must manage stride, byte order, and padding yourself. This is why many X11 applications rely on extensions like XShm for faster shared memory image transfer, which mirrors the shared buffer approach Wayland uses by default.
Graphics contexts also support additional drawing modes. You can set line styles, stipple patterns, and even the raster operation (ROP) function via XSetFunction to implement XOR drawing or invert effects. These were historically used for interactive rubber-band selection boxes and cursors. Modern toolkits rarely use these features directly, but they illustrate the breadth of server-side drawing state that a GC can encode. For a minimal client, you will use a simple fill, but knowing the GC can encode complex state explains why GC creation and management can become a significant part of X11 applications.
How This Fits on the Project
You will create a GC, draw a solid color rectangle, and flush requests on Expose events.
Definitions & Key Terms
- GC (Graphics Context) -> Server-side drawing state object.
- Pixmap -> Off-screen drawable buffer.
- Drawable -> Window or pixmap target for drawing.
Mental Model Diagram (ASCII)
Client -> XFillRectangle request -> X server -> screen
How It Works (Step-by-Step)
- Create a GC for the window.
- Set foreground color.
- On Expose, call
XFillRectangle. - Flush requests.
Minimal Concrete Example
GC gc = XCreateGC(d, w, 0, NULL);
XSetForeground(d, gc, 0x3366cc);
XFillRectangle(d, w, gc, 0, 0, width, height);
XFlush(d);
Common Misconceptions
- “Clients draw pixels directly.” -> The server draws in X11.
- “GC is just a struct.” -> It is a server-side object.
- “Double-buffering is automatic.” -> You must create pixmaps.
Check-Your-Understanding Questions
- What is the role of a GC?
- Why might you use a pixmap?
- How does X11 drawing differ from Wayland?
Check-Your-Understanding Answers
- It stores drawing state for server-side rendering.
- To render off-screen and avoid flicker.
- X11 sends draw commands; Wayland sends buffers.
Real-World Applications
- Traditional X11 apps rely on GC and server-side rendering.
- Toolkits manage pixmaps to reduce flicker.
Where You’ll Apply It
- See Sec. 3.2 Functional Requirements (drawing).
- See Sec. 5.10 Phase 2 (render loop).
- Also used in: Project 1: Wayland Client for contrast.
References
- Xlib Programming Manual (graphics chapter).
Key Insights
X11 drawing is a remote procedure call; Wayland drawing is buffer sharing.
Summary
Using GCs and draw commands exposes X11’s centralized rendering model.
Homework/Exercises to Practice the Concept
- Draw two rectangles with different colors using two GCs.
- Create a pixmap and copy it to the window.
- Measure flicker when resizing.
Solutions to the Homework/Exercises
- Use two GCs with different foreground colors.
- Use
XCreatePixmapandXCopyArea. - Flicker reduces with pixmaps.
3. Project Specification
3.1 What You Will Build
A minimal X11 client that:
- Connects to the X server
- Creates a window
- Handles Expose events to draw a solid background
- Sets WM_NAME and WM_DELETE_WINDOW
- Exits cleanly on close
Included:
- Basic event loop
- Xlib drawing
- Window properties
Excluded:
- Complex widgets or UI toolkit
- OpenGL rendering
3.2 Functional Requirements
- Connect:
XOpenDisplaymust succeed. - Create Window:
XCreateSimpleWindowandXMapWindow. - Expose Redraw: Redraw on Expose.
- Set Title: WM_NAME property.
- Close Handling: WM_DELETE_WINDOW support.
3.3 Non-Functional Requirements
- Performance: Redraw only on Expose.
- Reliability: No crashes on resize.
- Usability: Window appears with correct title and color.
3.4 Example Usage / Output
$ gcc -Wall -O2 -o x11_client x11_client.c -lX11
$ ./x11_client
X11 client starting...
Display: :0
Created window id=0x3c00007
Expose event: repainting
Press ESC or close the window to exit
3.5 Data Formats / Schemas / Protocols
- X11 protocol
- ICCCM/EWMH properties
3.6 Edge Cases
- DISPLAY not set
- Window manager does not support WM_DELETE_WINDOW
- Expose events arrive in bursts
3.7 Real World Outcome
You will see an X11 window identical to your Wayland window, and you will be able to compare the event flow and rendering model.
3.7.1 How to Run (Copy/Paste)
gcc -Wall -O2 -o x11_client x11_client.c -lX11
./x11_client
3.7.2 Golden Path Demo (Deterministic)
- Fill the window with a fixed color #3366cc.
- Title: “Bare-Metal X11 Client”.
3.7.3 Failure Demo (Deterministic)
- Run with
DISPLAYunset.
Expected behavior: XOpenDisplay returns NULL, exit code 5.
Exit codes:
0success5display connection failure
4. Solution Architecture
4.1 High-Level Design
Xlib client -> X server -> display
| |
| +-> events (Expose, KeyPress)
+-> requests (draw, properties)
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Display Connection | Connect to X server | Use $DISPLAY |
| Event Loop | Handle Expose/KeyPress | Simple XNextEvent |
| GC | Drawing state | Single GC for fill |
| Properties | Set title/close | WM_NAME + WM_DELETE_WINDOW |
4.3 Data Structures (No Full Code)
struct x11_state {
Display *dpy;
Window win;
GC gc;
Atom wm_delete;
};
4.4 Algorithm Overview
Key Algorithm: Expose Redraw Loop
- Wait for Expose.
- Fill rectangle with color.
- Flush.
Complexity Analysis:
- Time: O(width * height) per redraw
- Space: O(1)
5. Implementation Guide
5.1 Development Environment Setup
sudo apt install libx11-dev
5.2 Project Structure
x11-client/
+-- src/
| +-- main.c
+-- README.md
5.3 The Core Question You’re Answering
“Why did Linux move from the X11 model to Wayland’s model?”
5.4 Concepts You Must Understand First
- X11 client-server model
- Expose redraw
- Atoms and WM protocols
- GC-based drawing
5.5 Questions to Guide Your Design
- Which events must be selected for your client to function?
- How will you exit cleanly when the window manager closes the window?
- How does redraw timing differ from Wayland?
5.6 Thinking Exercise
Write down the differences in buffer ownership between X11 and Wayland.
5.7 The Interview Questions They’ll Ask
- “What is the biggest architectural difference between X11 and Wayland?”
- “Why does X11 require Expose handling?”
- “How do atoms work in X11?”
5.8 Hints in Layers
Hint 1: Start with XCreateSimpleWindow and XMapWindow.
Hint 2: Handle Expose before adding key handling.
Hint 3: Use WM_DELETE_WINDOW for graceful close.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Xlib fundamentals | Xlib Programming Manual | Ch. 1-3 |
| UNIX event loops | Advanced Programming in the UNIX Environment | Ch. 14-18 |
5.10 Implementation Phases
Phase 1: Window Creation (2-3 days)
Goals:
- Connect to display
- Create and map window
Tasks:
- Call
XOpenDisplay. - Create window and map it.
Checkpoint: Window appears on screen.
Phase 2: Event Loop & Drawing (2-3 days)
Goals:
- Handle Expose
- Draw solid color
Tasks:
- Select ExposureMask.
- Draw on Expose and flush.
Checkpoint: Window paints correctly.
Phase 3: Properties & Close (2-3 days)
Goals:
- Set title
- Handle WM_DELETE_WINDOW
Tasks:
- Set WM_NAME.
- Register WM_DELETE_WINDOW and handle ClientMessage.
Checkpoint: Window closes cleanly.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Rendering | XFillRectangle vs XPutImage | XFillRectangle | simplest |
| Event loop | blocking vs poll | blocking | minimal client |
| Properties | minimal vs full ICCCM | minimal | keep focus on comparison |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Connection Tests | Ensure display available | unset DISPLAY |
| Rendering Tests | Expose redraw | resize window |
| Property Tests | WM_NAME visible | check with xprop |
6.2 Critical Test Cases
- Expose Redraw: window paints after being covered.
- Close Handling: WM_DELETE_WINDOW exits cleanly.
- DISPLAY Missing: failure demo exits with code 5.
6.3 Test Data
Color: #3366cc
Title: Bare-Metal X11 Client
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| No Expose handling | Blank window | Redraw on Expose |
| No WM_DELETE_WINDOW | Forced close | Register WM_PROTOCOLS |
| Not flushing | Delayed drawing | Call XFlush |
7.2 Debugging Strategies
- Use
xpropto verify window properties. - Print event types to see flow.
7.3 Performance Traps
- Redrawing on every KeyPress even if content unchanged.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add a keybinding to toggle color.
- Draw a second rectangle.
8.2 Intermediate Extensions
- Add pixmap double-buffering.
- Measure latency with XSync.
8.3 Advanced Extensions
- Use XRender or XShm for faster drawing.
- Add EWMH window type hints.
9. Real-World Connections
9.1 Industry Applications
- Legacy desktop apps and remote display systems.
9.2 Related Open Source Projects
- Xlib examples and demos
9.3 Interview Relevance
- Explaining X11 vs Wayland is common in Linux graphics interviews.
10. Resources
10.1 Essential Reading
- Xlib Programming Manual (O’Reilly)
- X11 protocol specification
10.2 Video Resources
- X11 protocol walkthroughs
10.3 Tools & Documentation
xpropfor property inspectionxevfor event debugging
10.4 Related Projects in This Series
- Previous: Project 4: Layer Shell Panel
- Compare: Project 1: Wayland Client
11. Self-Assessment Checklist
11.1 Understanding
- I can explain the X11 client-server model.
- I can explain why Expose redraw is required.
- I can explain atoms and properties.
11.2 Implementation
- Window appears with correct color.
- Expose events trigger redraw.
- WM_DELETE_WINDOW closes the app.
11.3 Growth
- I can list at least three differences between X11 and Wayland.
- I can explain security implications of global input in X11.
12. Submission / Completion Criteria
Minimum Viable Completion:
- X11 window appears and repaints on Expose.
Full Completion:
- WM_DELETE_WINDOW handled and title set.
Excellence (Going Above & Beyond):
- Double-buffering with pixmaps and extra property hints.