1/*
2 * Functions related to the window ring.
3 *
4 * Invariants:
5 * - If a window is not on the ring, its TwmWindow::ring.next and .prev
6 *   are both NULL.
7 * - If a window is on the ring, they are both not NULL and point to a
8 *   window which is also on the ring.
9 * - Corollary: if a window is the only one on the ring, .next and .prev
10 *   point to itself.
11 * - Functions which act on the "current" ring window, i.e. the window
12 *   that has most recently been entered and is on the ring, use
13 *   Scr->RingLeader.
14 * - If RingLeader is NULL, fall back to Scr->Ring.
15 * - If Ring is NULL, the ring is empty (and RingLeader is also NULL).
16 */
17
18#include "ctwm.h"
19
20#include <assert.h>
21
22#include "screen.h"
23#include "win_ring.h"
24
25void
26UnlinkWindowFromRing(TwmWindow *win)
27{
28	TwmWindow *prev = win->ring.prev;
29	TwmWindow *next = win->ring.next;
30
31	// We call this unconditionally at various window deletion times, and
32	// if it's not on the ring, there's nothing to do.  e.g., if we don't
33	// have any WindowRing config enabled...
34	if(!WindowIsOnRing(win)) {
35		return;
36	}
37
38	// But if it is, prev/next should always exist.
39	assert(prev != NULL);
40	assert(next != NULL);
41
42	/*
43	* 1. Unlink window
44	* 2. If window was only thing in ring, null out ring
45	* 3. If window was ring leader, set to next (or null)
46	*
47	* If the window is the only one in the ring, prev == next == win,
48	* so the unlinking effectively is a NOP, but that doesn't matter.
49	*/
50	prev->ring.next = next;
51	next->ring.prev = prev;
52
53	win->ring.next = win->ring.prev = NULL;
54
55	if(Scr->Ring == win) {
56		Scr->Ring = (next != win ? next : NULL);
57	}
58
59	if(!Scr->Ring || Scr->RingLeader == win) {
60		Scr->RingLeader = Scr->Ring;
61	}
62}
63
64static void
65AddWindowToRingUnchecked(TwmWindow *win, TwmWindow *after)
66{
67	TwmWindow *before = after->ring.next;
68
69	win->ring.next = before;
70	win->ring.prev = after;
71
72	after->ring.next = win;
73	before->ring.prev = win;
74}
75
76void
77AddWindowToRing(TwmWindow *win)
78{
79	assert(win->ring.next == NULL);
80	assert(win->ring.prev == NULL);
81
82	if(Scr->Ring) {
83		AddWindowToRingUnchecked(win, Scr->Ring);
84	}
85	else {
86		win->ring.next = win->ring.prev = Scr->Ring = win;
87	}
88}
89