]> git.lizzy.rs Git - bspwm.git/blob - history.c
Add link to the `examples` directory
[bspwm.git] / history.c
1 /* Copyright (c) 2012, Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  *    list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include <stdlib.h>
26 #include "bspwm.h"
27 #include "query.h"
28
29 history_t *make_history(monitor_t *m, desktop_t *d, node_t *n)
30 {
31         history_t *h = malloc(sizeof(history_t));
32         h->loc = (coordinates_t) {m, d, n};
33         h->prev = h->next = NULL;
34         h->latest = true;
35         return h;
36 }
37
38 void history_add(monitor_t *m, desktop_t *d, node_t *n)
39 {
40         if (!record_history)
41                 return;
42         history_needle = NULL;
43         history_t *h = make_history(m, d, n);
44         if (history_head == NULL) {
45                 history_head = history_tail = h;
46         } else if ((n != NULL && history_tail->loc.node != n) || (n == NULL && d != history_tail->loc.desktop)) {
47                 for (history_t *hh = history_tail; hh != NULL; hh = hh->prev)
48                         if ((n != NULL && hh->loc.node == n) || (n == NULL && d == hh->loc.desktop))
49                                 hh->latest = false;
50                 history_tail->next = h;
51                 h->prev = history_tail;
52                 history_tail = h;
53         } else {
54                 free(h);
55         }
56 }
57
58 void history_transfer_node(monitor_t *m, desktop_t *d, node_t *n)
59 {
60         for (history_t *h = history_head; h != NULL; h = h->next)
61                 if (h->loc.node == n) {
62                         h->loc.monitor = m;
63                         h->loc.desktop = d;
64                 }
65 }
66
67 void history_transfer_desktop(monitor_t *m, desktop_t *d)
68 {
69         for (history_t *h = history_head; h != NULL; h = h->next)
70                 if (h->loc.desktop == d)
71                         h->loc.monitor = m;
72 }
73
74 void history_swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2)
75 {
76         for (history_t *h = history_head; h != NULL; h = h->next)
77                 if (h->loc.node == n1) {
78                         h->loc.monitor = m2;
79                         h->loc.desktop = d2;
80                 } else if (h->loc.node == n2) {
81                         h->loc.monitor = m1;
82                         h->loc.desktop = d1;
83                 }
84 }
85
86 void history_swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
87 {
88         for (history_t *h = history_head; h != NULL; h = h->next)
89                 if (h->loc.desktop == d1)
90                         h->loc.monitor = m2;
91                 else if (h->loc.desktop == d2)
92                         h->loc.monitor = m1;
93 }
94
95 void history_remove(desktop_t *d, node_t *n)
96 {
97    /* removing from the newest to the oldest is required */
98    /* for maintaining the *latest* attribute */
99         history_t *b = history_tail;
100         while (b != NULL) {
101                 if ((n != NULL && n == b->loc.node) || (n == NULL && d == b->loc.desktop)) {
102                         history_t *a = b->next;
103                         history_t *c = b->prev;
104                         if (a != NULL) {
105                                 /* remove duplicate entries */
106                                 while (c != NULL && ((a->loc.node != NULL && a->loc.node == c->loc.node) ||
107                                        (a->loc.node == NULL && a->loc.desktop == c->loc.desktop))) {
108                                         history_t *d = c->prev;
109                                         if (history_head == c)
110                                                 history_head = history_tail;
111                                         if (history_needle == c)
112                                                 history_needle = history_tail;
113                                         free(c);
114                                         c = d;
115                                 }
116                                 a->prev = c;
117                         }
118                         if (c != NULL)
119                                 c->next = a;
120                         if (history_tail == b)
121                                 history_tail = c;
122                         if (history_head == b)
123                                 history_head = a;
124                         if (history_needle == b)
125                                 history_needle = c;
126                         free(b);
127                         b = c;
128                 } else {
129                         b = b->prev;
130                 }
131         }
132 }
133
134 void empty_history(void)
135 {
136         history_t *h = history_head;
137         while (h != NULL) {
138                 history_t *next = h->next;
139                 free(h);
140                 h = next;
141         }
142         history_head = history_tail = NULL;
143 }
144
145 node_t *history_get_node(desktop_t *d, node_t *n)
146 {
147         for (history_t *h = history_tail; h != NULL; h = h->prev)
148                 if (h->latest && h->loc.node != NULL && h->loc.node != n && h->loc.desktop == d)
149                         return h->loc.node;
150         return NULL;
151 }
152
153 desktop_t *history_get_desktop(monitor_t *m, desktop_t *d)
154 {
155         for (history_t *h = history_tail; h != NULL; h = h->prev)
156                 if (h->latest && h->loc.desktop != d && h->loc.monitor == m)
157                         return h->loc.desktop;
158         return NULL;
159 }
160
161 monitor_t *history_get_monitor(monitor_t *m)
162 {
163         for (history_t *h = history_tail; h != NULL; h = h->prev)
164                 if (h->latest && h->loc.monitor != m)
165                         return h->loc.monitor;
166         return NULL;
167 }
168
169 bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, client_select_t sel)
170 {
171         if (history_needle == NULL || record_history)
172                 history_needle = history_tail;
173
174         history_t *h;
175         for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
176                 if (!h->latest ||
177                     h->loc.node == NULL ||
178                     h->loc.node == ref->node ||
179                     !node_matches(&h->loc, ref, sel))
180                         continue;
181                 if (!record_history)
182                         history_needle = h;
183                 *dst = h->loc;
184                 return true;
185         }
186         return false;
187 }
188
189 bool history_find_desktop(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, desktop_select_t sel)
190 {
191         if (history_needle == NULL || record_history)
192                 history_needle = history_tail;
193
194         history_t *h;
195         for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
196                 if (!h->latest ||
197                     h->loc.desktop == ref->desktop ||
198                     !desktop_matches(&h->loc, ref, sel))
199                         continue;
200                 if (!record_history)
201                         history_needle = h;
202                 *dst = h->loc;
203                 return true;
204         }
205         return false;
206 }
207
208 bool history_find_monitor(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, desktop_select_t sel)
209 {
210         if (history_needle == NULL || record_history)
211                 history_needle = history_tail;
212
213         history_t *h;
214         for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
215                 if (!h->latest ||
216                     h->loc.monitor == ref->monitor ||
217                     !desktop_matches(&h->loc, ref, sel))
218                         continue;
219                 if (!record_history)
220                         history_needle = h;
221                 *dst = h->loc;
222                 return true;
223         }
224         return false;
225 }
226
227 int history_rank(desktop_t *d, node_t *n)
228 {
229         int i = 0;
230         history_t *h = history_tail;
231         while (h != NULL && (!h->latest || h->loc.node != n || h->loc.desktop != d)) {
232                 h = h->prev;
233                 i++;
234         }
235         if (h == NULL)
236                 return -1;
237         else
238                 return i;
239 }