]> git.lizzy.rs Git - bspwm.git/blob - history.c
Keep normal windows below fullscreen windows
[bspwm.git] / history.c
1 /* Copyright (c) 2012-2014, 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  * The views and conclusions contained in the software and documentation are those
25  * of the authors and should not be interpreted as representing official policies,
26  * either expressed or implied, of the FreeBSD Project.
27  */
28
29 #include <stdlib.h>
30 #include "bspwm.h"
31 #include "query.h"
32
33 history_t *make_history(monitor_t *m, desktop_t *d, node_t *n)
34 {
35         history_t *h = malloc(sizeof(history_t));
36         h->loc = (coordinates_t) {m, d, n};
37         h->prev = h->next = NULL;
38         h->latest = true;
39         return h;
40 }
41
42 void history_add(monitor_t *m, desktop_t *d, node_t *n)
43 {
44         if (!record_history)
45                 return;
46         history_needle = NULL;
47         history_t *h = make_history(m, d, n);
48         if (history_head == NULL) {
49                 history_head = history_tail = h;
50         } else if ((n != NULL && history_tail->loc.node != n) || (n == NULL && d != history_tail->loc.desktop)) {
51                 for (history_t *hh = history_tail; hh != NULL; hh = hh->prev)
52                         if ((n != NULL && hh->loc.node == n) || (n == NULL && d == hh->loc.desktop))
53                                 hh->latest = false;
54                 history_tail->next = h;
55                 h->prev = history_tail;
56                 history_tail = h;
57         } else {
58                 free(h);
59         }
60 }
61
62 void history_transfer_node(monitor_t *m, desktop_t *d, node_t *n)
63 {
64         for (history_t *h = history_head; h != NULL; h = h->next)
65                 if (h->loc.node == n) {
66                         h->loc.monitor = m;
67                         h->loc.desktop = d;
68                 }
69 }
70
71 void history_transfer_desktop(monitor_t *m, desktop_t *d)
72 {
73         for (history_t *h = history_head; h != NULL; h = h->next)
74                 if (h->loc.desktop == d)
75                         h->loc.monitor = m;
76 }
77
78 void history_swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2)
79 {
80         for (history_t *h = history_head; h != NULL; h = h->next)
81                 if (h->loc.node == n1) {
82                         h->loc.monitor = m2;
83                         h->loc.desktop = d2;
84                 } else if (h->loc.node == n2) {
85                         h->loc.monitor = m1;
86                         h->loc.desktop = d1;
87                 }
88 }
89
90 void history_swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
91 {
92         for (history_t *h = history_head; h != NULL; h = h->next)
93                 if (h->loc.desktop == d1)
94                         h->loc.monitor = m2;
95                 else if (h->loc.desktop == d2)
96                         h->loc.monitor = m1;
97 }
98
99 void history_remove(desktop_t *d, node_t *n)
100 {
101    /* removing from the newest to the oldest is required */
102    /* for maintaining the *latest* attribute */
103         history_t *b = history_tail;
104         while (b != NULL) {
105                 if ((n != NULL && n == b->loc.node) || (n == NULL && d == b->loc.desktop)) {
106                         history_t *a = b->next;
107                         history_t *c = b->prev;
108                         if (a != NULL) {
109                                 /* remove duplicate entries */
110                                 while (c != NULL && ((a->loc.node != NULL && a->loc.node == c->loc.node) ||
111                                        (a->loc.node == NULL && a->loc.desktop == c->loc.desktop))) {
112                                         history_t *d = c->prev;
113                                         if (history_head == c)
114                                                 history_head = history_tail;
115                                         if (history_needle == c)
116                                                 history_needle = history_tail;
117                                         free(c);
118                                         c = d;
119                                 }
120                                 a->prev = c;
121                         }
122                         if (c != NULL)
123                                 c->next = a;
124                         if (history_tail == b)
125                                 history_tail = c;
126                         if (history_head == b)
127                                 history_head = a;
128                         if (history_needle == b)
129                                 history_needle = c;
130                         free(b);
131                         b = c;
132                 } else {
133                         b = b->prev;
134                 }
135         }
136 }
137
138 void empty_history(void)
139 {
140         history_t *h = history_head;
141         while (h != NULL) {
142                 history_t *next = h->next;
143                 free(h);
144                 h = next;
145         }
146         history_head = history_tail = NULL;
147 }
148
149 node_t *history_get_node(desktop_t *d, node_t *n)
150 {
151         for (history_t *h = history_tail; h != NULL; h = h->prev)
152                 if (h->latest && h->loc.node != NULL && h->loc.node != n && h->loc.desktop == d)
153                         return h->loc.node;
154         return NULL;
155 }
156
157 desktop_t *history_get_desktop(monitor_t *m, desktop_t *d)
158 {
159         for (history_t *h = history_tail; h != NULL; h = h->prev)
160                 if (h->latest && h->loc.desktop != d && h->loc.monitor == m)
161                         return h->loc.desktop;
162         return NULL;
163 }
164
165 monitor_t *history_get_monitor(monitor_t *m)
166 {
167         for (history_t *h = history_tail; h != NULL; h = h->prev)
168                 if (h->latest && h->loc.monitor != m)
169                         return h->loc.monitor;
170         return NULL;
171 }
172
173 bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, client_select_t sel)
174 {
175         if (history_needle == NULL || record_history)
176                 history_needle = history_tail;
177
178         history_t *h;
179         for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
180                 if (!h->latest ||
181                     h->loc.node == NULL ||
182                     h->loc.node == ref->node ||
183                     !node_matches(&h->loc, ref, sel))
184                         continue;
185                 if (!record_history)
186                         history_needle = h;
187                 *dst = h->loc;
188                 return true;
189         }
190         return false;
191 }
192
193 bool history_find_desktop(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, desktop_select_t sel)
194 {
195         if (history_needle == NULL || record_history)
196                 history_needle = history_tail;
197
198         history_t *h;
199         for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
200                 if (!h->latest ||
201                     h->loc.desktop == ref->desktop ||
202                     !desktop_matches(&h->loc, ref, sel))
203                         continue;
204                 if (!record_history)
205                         history_needle = h;
206                 *dst = h->loc;
207                 return true;
208         }
209         return false;
210 }
211
212 bool history_find_monitor(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, desktop_select_t sel)
213 {
214         if (history_needle == NULL || record_history)
215                 history_needle = history_tail;
216
217         history_t *h;
218         for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
219                 if (!h->latest ||
220                     h->loc.monitor == ref->monitor ||
221                     !desktop_matches(&h->loc, ref, sel))
222                         continue;
223                 if (!record_history)
224                         history_needle = h;
225                 *dst = h->loc;
226                 return true;
227         }
228         return false;
229 }
230
231 int history_rank(desktop_t *d, node_t *n)
232 {
233         int i = 0;
234         history_t *h = history_tail;
235         while (h != NULL && (!h->latest || h->loc.node != n || h->loc.desktop != d)) {
236                 h = h->prev;
237                 i++;
238         }
239         if (h == NULL)
240                 return -1;
241         else
242                 return i;
243 }