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