]> Dogcows Code - chaz/openbox/blob - plugins/placement/history.c
Keyboard navigatable menus
[chaz/openbox] / 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 "parser/parse.h"
7 #include "history.h"
8 #include <glib.h>
9 #include <string.h>
10 #ifdef HAVE_STDLIB_H
11 # include <stdlib.h>
12 #endif
13
14 #define PLACED (1 << 0)
15
16 #define HAVE_POSITION (1 << 1)
17 #define HAVE_SIZE (1 << 2)
18 #define HAVE_DESKTOP (1 << 3)
19
20 struct HistoryItem {
21 char *name;
22 char *class;
23 char *role;
24
25 int flags;
26
27 int x, y;
28 int w, h;
29 guint desk;
30 };
31
32 static GSList *history_list = NULL;
33 static char *history_path = NULL;
34
35 static struct HistoryItem *history_find(const char *name, const char *class,
36 const char *role)
37 {
38 GSList *it;
39 struct HistoryItem *hi = NULL;
40
41 /* find the client */
42 for (it = history_list; it != NULL; it = it->next) {
43 hi = it->data;
44 if (!strcmp(hi->name, name) &&
45 !strcmp(hi->class, class) &&
46 !strcmp(hi->role, role))
47 return hi;
48 }
49 return NULL;
50 }
51
52 gboolean place_history(ObClient *c)
53 {
54 struct HistoryItem *hi;
55 int x, y, w, h;
56
57 hi = history_find(c->name, c->class, c->role);
58
59 if (hi && !(hi->flags & PLACED)) {
60 hi->flags |= PLACED;
61 if (ob_state() != OB_STATE_STARTING) {
62 if (hi->flags & HAVE_POSITION ||
63 hi->flags & HAVE_SIZE) {
64 if (hi->flags & HAVE_POSITION) {
65 x = hi->x;
66 y = hi->y;
67 /* get where the client should be */
68 frame_frame_gravity(c->frame, &x, &y);
69 } else {
70 x = c->area.x;
71 y = c->area.y;
72 }
73 if (hi->flags & HAVE_SIZE) {
74 w = hi->w * c->size_inc.width;
75 h = hi->h * c->size_inc.height;
76 } else {
77 w = c->area.width;
78 h = c->area.height;
79 }
80 client_configure(c, OB_CORNER_TOPLEFT, x, y, w, h,
81 TRUE, TRUE);
82 }
83 if (hi->flags & HAVE_DESKTOP) {
84 client_set_desktop(c, hi->desk, FALSE);
85 }
86 }
87 return hi->flags & HAVE_POSITION;
88 }
89
90 return FALSE;
91 }
92
93 static void set_history(ObClient *c)
94 {
95 struct HistoryItem *hi;
96
97 hi = history_find(c->name, c->class, c->role);
98
99 if (hi == NULL) {
100 hi = g_new(struct HistoryItem, 1);
101 history_list = g_slist_append(history_list, hi);
102 hi->name = g_strdup(c->name);
103 hi->class = g_strdup(c->class);
104 hi->role = g_strdup(c->role);
105 hi->flags = HAVE_POSITION;
106 }
107
108 if (hi->flags & HAVE_POSITION) {
109 hi->x = c->frame->area.x;
110 hi->y = c->frame->area.y;
111 }
112
113 hi->flags &= ~PLACED;
114 }
115
116 static void event(ObEvent *e, void *foo)
117 {
118 g_assert(e->type == Event_Client_Destroy);
119
120 set_history(e->data.c.client);
121 }
122
123 /*
124
125 <entry name="name" class="class" role="role">
126 <x>0</x>
127 <y>0</y>
128 <width>300</width>
129 <height>200</height>
130 <desktop>1</desktop>
131 </entry>
132
133 */
134
135 static void save_history()
136 {
137 xmlDocPtr doc;
138 xmlNodePtr root, node;
139 char *s;
140 GSList *it;
141
142 doc = xmlNewDoc(NULL);
143 root = xmlNewNode(NULL, (const xmlChar*) "openbox_history");
144 xmlDocSetRootElement(doc, root);
145
146 for (it = history_list; it; it = g_slist_next(it)) {
147 struct HistoryItem *hi = it->data;
148 g_message("adding %s", hi->name);
149 node = xmlNewChild(root, NULL, (const xmlChar*) "entry", NULL);
150 xmlNewProp(node, (const xmlChar*) "name", (const xmlChar*) hi->name);
151 xmlNewProp(node, (const xmlChar*) "class", (const xmlChar*) hi->class);
152 xmlNewProp(node, (const xmlChar*) "role", (const xmlChar*) hi->role);
153 if (hi->flags & HAVE_POSITION) {
154 s = g_strdup_printf("%d", hi->x);
155 xmlNewTextChild(node, NULL,
156 (const xmlChar*) "x", (const xmlChar*) s);
157 g_free(s);
158 s = g_strdup_printf("%d", hi->y);
159 xmlNewTextChild(node, NULL,
160 (const xmlChar*) "y", (const xmlChar*) s);
161 g_free(s);
162 }
163 if (hi->flags & HAVE_SIZE) {
164 s = g_strdup_printf("%d", hi->w);
165 xmlNewTextChild(node, NULL,
166 (const xmlChar*) "width", (const xmlChar*) s);
167 g_free(s);
168 s = g_strdup_printf("%d", hi->h);
169 xmlNewTextChild(node, NULL,
170 (const xmlChar*) "height", (const xmlChar*) s);
171 g_free(s);
172 }
173 if (hi->flags & HAVE_DESKTOP) {
174 s = g_strdup_printf("%d", hi->desk < 0 ? hi->desk : hi->desk + 1);
175 xmlNewTextChild(node, NULL,
176 (const xmlChar*) "desktop", (const xmlChar*) s);
177 g_free(s);
178 }
179 }
180
181 xmlIndentTreeOutput = 1;
182 xmlSaveFormatFile(history_path, doc, 1);
183
184 xmlFree(doc);
185 }
186
187 static void load_history()
188 {
189 xmlDocPtr doc;
190 xmlNodePtr node, n;
191 char *name;
192 char *class;
193 char *role;
194 struct HistoryItem *hi;
195
196 if (!parse_load(history_path, "openbox_history", &doc, &node))
197 return;
198
199 node = parse_find_node("entry", node->xmlChildrenNode);
200 while (node) {
201 name = class = role = NULL;
202 if (parse_attr_string("name", node, &name) &&
203 parse_attr_string("class", node, &class) &&
204 parse_attr_string("role", node, &role)) {
205
206 hi = history_find(name, class, role);
207 if (!hi) {
208 hi = g_new(struct HistoryItem, 1);
209 hi->name = g_strdup(name);
210 hi->class = g_strdup(class);
211 hi->role = g_strdup(role);
212 hi->flags = 0;
213 }
214 if ((n = parse_find_node("x", node->xmlChildrenNode))) {
215 hi->x = parse_int(doc, n);
216 if ((n = parse_find_node("y", node->xmlChildrenNode))) {
217 hi->y = parse_int(doc, n);
218 hi->flags |= HAVE_POSITION;
219 }
220 }
221 if ((n = parse_find_node("width", node->xmlChildrenNode))) {
222 hi->w = parse_int(doc, n);
223 if ((n = parse_find_node("height", node->xmlChildrenNode))) {
224 hi->h = parse_int(doc, n);
225 hi->flags |= HAVE_SIZE;
226 }
227 }
228 if ((n = parse_find_node("desktop", node->xmlChildrenNode))) {
229 hi->desk = parse_int(doc, n);
230 if (hi->desk > 0) --hi->desk;
231 hi->flags |= HAVE_DESKTOP;
232 }
233
234 history_list = g_slist_append(history_list, hi);
235 }
236 g_free(name); g_free(class); g_free(role);
237 node = parse_find_node("entry", node->next);
238 }
239 xmlFree(doc);
240 }
241
242 void history_startup()
243 {
244 char *path;
245
246 history_list = NULL;
247
248 path = g_build_filename(g_get_home_dir(), ".openbox", "history", NULL);
249 history_path = g_strdup_printf("%s.%d", path, ob_screen);
250 g_free(path);
251
252 load_history(); /* load from the historydb file */
253
254 dispatch_register(Event_Client_Destroy, (EventHandler)event, NULL);
255 }
256
257 void history_shutdown()
258 {
259 GSList *it;
260
261 save_history(); /* save to the historydb file */
262 for (it = history_list; it != NULL; it = it->next) {
263 struct HistoryItem *hi = it->data;
264 g_free(hi->name);
265 g_free(hi->class);
266 g_free(hi->role);
267 g_free(hi);
268 }
269 g_slist_free(history_list);
270
271 dispatch_register(0, (EventHandler)event, NULL);
272
273 g_free(history_path);
274 }
This page took 0.049789 seconds and 4 git commands to generate.