more build fixes
[dana/openbox.git] / plugins / placement / history.c
1 #include "../../kernel/openbox.h"
2 #include "../../kernel/dispatch.h"
3 #include "../../kernel/frame.h"
4 #include "../../kernel/client.h"
5 #include <glib.h>
6 #include <string.h>
7 #ifdef HAVE_STDLIB_H
8 #  include <stdlib.h>
9 #endif
10
11 struct HistoryItem {
12     char *name;
13     char *class;
14     char *role;
15     int x;
16     int y;
17     gboolean placed;
18 };
19
20 static GSList *history = NULL;
21 static char *history_path = NULL;
22
23 static struct HistoryItem *find_history(Client *c)
24 {
25     GSList *it;
26     struct HistoryItem *hi = NULL;
27
28     /* find the client */
29     for (it = history; it != NULL; it = it->next) {
30         hi = it->data;
31         g_assert(hi->name != NULL);
32         g_assert(hi->class != NULL);
33         g_assert(hi->role != NULL);
34         g_assert(c->name != NULL);
35         g_assert(c->class != NULL);
36         g_assert(c->role != NULL);
37         if (!strcmp(hi->name, c->name) &&
38             !strcmp(hi->class, c->class) &&
39             !strcmp(hi->role, c->role))
40             return hi;
41     }
42     return NULL;
43 }
44
45 gboolean place_history(Client *c)
46 {
47     struct HistoryItem *hi;
48     int x, y;
49
50     hi = find_history(c);
51
52     if (hi != NULL && !hi->placed) {
53         hi->placed = TRUE;
54         if (ob_state != State_Starting) {
55             x = hi->x;
56             y = hi->y;
57
58             frame_frame_gravity(c->frame, &x, &y); /* get where the client
59                                                       should be */
60             client_configure(c, Corner_TopLeft, x, y,
61                              c->area.width, c->area.height,
62                              TRUE, TRUE);
63         }
64         return TRUE;
65     }
66
67     return FALSE;
68 }
69
70 static void strip_tabs(char *s)
71 {
72     while (*s != '\0') {
73         if (*s == '\t')
74             *s = ' ';
75         ++s;
76     }
77 }
78
79 static void set_history(Client *c)
80 {
81     struct HistoryItem *hi;
82
83     hi = find_history(c);
84
85     if (hi == NULL) {
86         hi = g_new(struct HistoryItem, 1);
87         history = g_slist_append(history, hi);
88         hi->name = g_strdup(c->name);
89         strip_tabs(hi->name);
90         hi->class = g_strdup(c->class);
91         strip_tabs(hi->class);
92         hi->role = g_strdup(c->role);
93         strip_tabs(hi->role);
94     }
95
96     hi->x = c->frame->area.x;
97     hi->y = c->frame->area.y;
98     hi->placed = FALSE;
99 }
100
101 static void event(ObEvent *e, void *foo)
102 {
103     g_assert(e->type == Event_Client_Destroy);
104
105     set_history(e->data.c.client);
106 }
107
108 static void save_history()
109 {
110     GError *err = NULL;
111     GIOChannel *io;
112     GString *buf;
113     GSList *it;
114     struct HistoryItem *hi;
115     gsize ret;
116
117     io = g_io_channel_new_file(history_path, "w", &err);
118     if (io != NULL) {
119         for (it = history; it != NULL; it = it->next) {
120             hi = it->data;
121             buf = g_string_sized_new(0);
122             buf=g_string_append(buf, hi->name);
123             g_string_append_c(buf, '\t');
124             buf=g_string_append(buf, hi->class);
125             g_string_append_c(buf, '\t');
126             buf=g_string_append(buf, hi->role);
127             g_string_append_c(buf, '\t');
128             g_string_append_printf(buf, "%d", hi->x);
129             buf=g_string_append_c(buf, '\t');
130             g_string_append_printf(buf, "%d", hi->y);
131             buf=g_string_append_c(buf, '\n');
132             if (g_io_channel_write_chars(io, buf->str, buf->len, &ret, &err) !=
133                 G_IO_STATUS_NORMAL)
134                 break;
135             g_string_free(buf, TRUE);
136         }
137         g_io_channel_unref(io);
138     }
139 }
140
141 static void load_history()
142 {
143     GError *err = NULL;
144     GIOChannel *io;
145     char *buf = NULL;
146     char *b, *c;
147     struct HistoryItem *hi = NULL;
148
149     io = g_io_channel_new_file(history_path, "r", &err);
150     if (io != NULL) {
151         while (g_io_channel_read_line(io, &buf, NULL, NULL, &err) ==
152                G_IO_STATUS_NORMAL) {
153             hi = g_new0(struct HistoryItem, 1);
154
155             b = buf;
156             if ((c = strchr(b, '\t')) == NULL) break;
157             *c = '\0';
158             hi->name = g_strdup(b);
159
160             b = c + 1;
161             if ((c = strchr(b, '\t')) == NULL) break;
162             *c = '\0';
163             hi->class = g_strdup(b);
164
165             b = c + 1;
166             if ((c = strchr(b, '\t')) == NULL) break;
167             *c = '\0';
168             hi->role = g_strdup(b);
169
170             b = c + 1;
171             if ((c = strchr(b, '\t')) == NULL) break;
172             *c = '\0';
173             hi->x = atoi(b);
174
175             b = c + 1;
176             if ((c = strchr(b, '\n')) == NULL) break;
177             *c = '\0';
178             hi->y = atoi(b);
179
180             hi->placed = FALSE;
181
182             g_free(buf);
183             buf = NULL;
184
185             history = g_slist_append(history, hi);
186             hi = NULL;
187         }
188         g_io_channel_unref(io);
189     }
190         
191     g_free(buf);
192
193     if (hi != NULL) {
194         g_free(hi->name);
195         g_free(hi->class);
196         g_free(hi->role);
197     }
198     g_free(hi);
199 }
200
201 void history_startup()
202 {
203     char *path;
204
205     history = NULL;
206
207     path = g_build_filename(g_get_home_dir(), ".openbox", "history", NULL);
208     history_path = g_strdup_printf("%s.%d", path, ob_screen);
209     g_free(path);
210
211     load_history(); /* load from the historydb file */
212
213     dispatch_register(Event_Client_Destroy, (EventHandler)event, NULL);
214 }
215
216 void history_shutdown()
217 {
218     GSList *it;
219
220     save_history(); /* save to the historydb file */
221     for (it = history; it != NULL; it = it->next)
222         g_free(it->data);
223     g_slist_free(history);
224
225     dispatch_register(0, (EventHandler)event, NULL);
226
227     g_free(history_path);
228 }