1 #include "e.h"
2
3 #define REMEMBER_HIERARCHY 1
4 #define REMEMBER_SIMPLE 0
5
6 E_API int E_EVENT_REMEMBER_UPDATE = -1;
7 E_API E_Config_DD *e_remember_edd = NULL; //created in e_config.c
8
9 typedef struct _E_Remember_List E_Remember_List;
10
11 struct _E_Remember_List
12 {
13 Eina_List *list;
14 };
15
16 /* local subsystem functions */
17 static void _e_remember_free(E_Remember *rem);
18 static void _e_remember_update(E_Client *ec, E_Remember *rem);
19 static E_Remember *_e_remember_find(E_Client *ec, int check_usable, Eina_Bool sr);
20 static void _e_remember_cb_hook_pre_post_fetch(void *data, E_Client *ec);
21 static void _e_remember_cb_hook_eval_post_new_client(void *data, E_Client *ec);
22 static void _e_remember_init_edd(void);
23 static Eina_Bool _e_remember_restore_cb(void *data, int type, void *event);
24
25 /* local subsystem globals */
26 static Eina_List *hooks = NULL;
27 static E_Config_DD *e_remember_list_edd = NULL;
28 static E_Remember_List *remembers = NULL;
29 static Eina_List *handlers = NULL;
30 static Ecore_Idler *remember_idler = NULL;
31 static Eina_List *remember_idler_list = NULL;
32
33 /* static Eina_List *e_remember_restart_list = NULL; */
34
35 /* externally accessible functions */
36 EINTERN int
e_remember_init(E_Startup_Mode mode)37 e_remember_init(E_Startup_Mode mode)
38 {
39 Eina_List *ll, *l = NULL;
40 E_Remember *rem;
41 E_Client_Hook *h;
42
43 if (mode == E_STARTUP_START)
44 {
45 EINA_LIST_FOREACH_SAFE(e_config->remembers, l, ll, rem)
46 {
47 if ((rem->apply & E_REMEMBER_APPLY_RUN) && (rem->prop.command))
48 {
49 if (!e_util_exe_safe_run(rem->prop.command, NULL))
50 {
51 e_util_dialog_show(_("Run Error"),
52 _("Enlightenment was unable to fork a child process:<ps/>"
53 "<ps/>"
54 "%s<ps/>"),
55 rem->prop.command);
56 }
57 }
58 if (rem->apply & E_REMEMBER_APPLY_UUID)
59 {
60 e_config->remembers = eina_list_remove_list(e_config->remembers, l);
61 _e_remember_free(rem);
62 }
63 }
64 }
65 E_EVENT_REMEMBER_UPDATE = ecore_event_type_new();
66
67 h = e_client_hook_add(E_CLIENT_HOOK_EVAL_PRE_POST_FETCH,
68 _e_remember_cb_hook_pre_post_fetch, NULL);
69 if (h) hooks = eina_list_append(hooks, h);
70 h = e_client_hook_add(E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT,
71 _e_remember_cb_hook_eval_post_new_client, NULL);
72 if (h) hooks = eina_list_append(hooks, h);
73 h = e_client_hook_add(E_CLIENT_HOOK_UNIGNORE,
74 _e_remember_cb_hook_pre_post_fetch, NULL);
75 h = e_client_hook_add(E_CLIENT_HOOK_UNIGNORE,
76 _e_remember_cb_hook_eval_post_new_client, NULL);
77 if (h) hooks = eina_list_append(hooks, h);
78
79 _e_remember_init_edd();
80 remembers = e_config_domain_load("e_remember_restart", e_remember_list_edd);
81
82 if (remembers)
83 {
84 handlers = eina_list_append
85 (handlers, ecore_event_handler_add
86 (E_EVENT_MODULE_INIT_END, _e_remember_restore_cb, NULL));
87 }
88
89 return 1;
90 }
91
92 EINTERN int
e_remember_shutdown(void)93 e_remember_shutdown(void)
94 {
95 E_FREE_LIST(hooks, e_client_hook_del);
96
97 E_CONFIG_DD_FREE(e_remember_edd);
98 E_CONFIG_DD_FREE(e_remember_list_edd);
99
100 E_FREE_LIST(handlers, ecore_event_handler_del);
101 if (remember_idler) ecore_idler_del(remember_idler);
102 remember_idler = NULL;
103 remember_idler_list = eina_list_free(remember_idler_list);
104
105 return 1;
106 }
107
108 E_API void
e_remember_internal_save(void)109 e_remember_internal_save(void)
110 {
111 const Eina_List *l;
112 E_Client *ec;
113 E_Remember *rem;
114
115 //printf("internal save %d\n", restart);
116 if (!remembers)
117 remembers = E_NEW(E_Remember_List, 1);
118 else
119 {
120 EINA_LIST_FREE(remembers->list, rem)
121 _e_remember_free(rem);
122 remember_idler_list = eina_list_free(remember_idler_list);
123 }
124
125 EINA_LIST_FOREACH(e_comp->clients, l, ec)
126 {
127 if ((!ec->internal) || e_client_util_ignored_get(ec)) continue;
128
129 rem = E_NEW(E_Remember, 1);
130 if (!rem) break;
131
132 e_remember_default_match_set(rem, ec);
133 rem->apply = (E_REMEMBER_APPLY_POS | E_REMEMBER_APPLY_SIZE |
134 E_REMEMBER_APPLY_BORDER | E_REMEMBER_APPLY_LAYER |
135 E_REMEMBER_APPLY_SHADE | E_REMEMBER_APPLY_ZONE |
136 E_REMEMBER_APPLY_DESKTOP | E_REMEMBER_APPLY_LOCKS |
137 E_REMEMBER_APPLY_SKIP_WINLIST |
138 E_REMEMBER_APPLY_SKIP_PAGER |
139 E_REMEMBER_APPLY_SKIP_TASKBAR |
140 E_REMEMBER_APPLY_OFFER_RESISTANCE |
141 E_REMEMBER_APPLY_OPACITY |
142 E_REMEMBER_APPLY_VOLUME);
143 _e_remember_update(ec, rem);
144
145 remembers->list = eina_list_append(remembers->list, rem);
146 }
147
148 e_config_domain_save("e_remember_restart", e_remember_list_edd, remembers);
149 }
150
151 static Eina_Bool
_e_remember_restore_idler_cb(void * d EINA_UNUSED)152 _e_remember_restore_idler_cb(void *d EINA_UNUSED)
153 {
154 E_Remember *rem;
155 E_Action *act_fm = NULL, *act;
156 Eina_Bool done = EINA_FALSE;
157
158 EINA_LIST_FREE(remember_idler_list, rem)
159 {
160 if (!rem->class) continue;
161 if (rem->no_reopen) continue;
162 if (done) break;
163
164 if (!strncmp(rem->class, "e_fwin::", 8))
165 {
166 if (!act_fm)
167 act_fm = e_action_find("fileman");
168 if (!act_fm) continue;
169 /* at least '/' */
170 if (!rem->class[9]) continue;
171
172 act_fm->func.go(NULL, rem->class + 8);
173 }
174 else if (!strncmp(rem->class, "_config::", 9))
175 {
176 char *param = NULL;
177 char path[1024];
178 const char *p;
179
180 p = rem->class + 9;
181 if ((param = strstr(p, "::")))
182 {
183 snprintf(path, (param - p) + sizeof(char), "%s", p);
184 param = param + 2;
185 }
186 else
187 snprintf(path, sizeof(path), "%s", p);
188
189 if (e_configure_registry_exists(path))
190 {
191 e_configure_registry_call(path, NULL, param);
192 }
193 }
194 else if (!strcmp(rem->class, "_configure"))
195 {
196 /* TODO this is just for settings panel. it could also
197 use e_configure_registry_item_add */
198 /* ..or make a general path for window that are started
199 by actions */
200
201 act = e_action_find("configuration");
202 if (act)
203 act->func.go(NULL, NULL);
204 }
205 done = EINA_TRUE;
206 }
207 if (!done) remember_idler = NULL;
208
209 return done;
210 }
211
212 static Eina_Bool
_e_remember_restore_cb(void * data EINA_UNUSED,int type EINA_UNUSED,void * event EINA_UNUSED)213 _e_remember_restore_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
214 {
215 handlers = eina_list_free(handlers);
216 if (!remembers->list) return ECORE_CALLBACK_PASS_ON;
217 remember_idler_list = eina_list_clone(remembers->list);
218 remember_idler = ecore_idler_add(_e_remember_restore_idler_cb, NULL);
219 return ECORE_CALLBACK_PASS_ON;
220 }
221
222 E_API E_Remember *
e_remember_new(void)223 e_remember_new(void)
224 {
225 E_Remember *rem;
226
227 rem = E_NEW(E_Remember, 1);
228 if (!rem) return NULL;
229 e_config->remembers = eina_list_prepend(e_config->remembers, rem);
230 return rem;
231 }
232
233 E_API int
e_remember_usable_get(E_Remember * rem)234 e_remember_usable_get(E_Remember *rem)
235 {
236 if ((rem->apply_first_only) && (rem->used_count > 0)) return 0;
237 return 1;
238 }
239
240 E_API void
e_remember_use(E_Remember * rem)241 e_remember_use(E_Remember *rem)
242 {
243 rem->used_count++;
244 if (rem->version < E_REMEMBER_VERSION)
245 {
246 /* upgrade remembers as they get used */
247 switch (rem->version)
248 {
249 case 0:
250 rem->prop.opacity = 255; //don't let people wreck themselves with old configs
251 //fall through
252 default: break;
253 }
254 rem->version = E_REMEMBER_VERSION;
255 e_config_save_queue();
256 }
257 }
258
259 E_API void
e_remember_unuse(E_Remember * rem)260 e_remember_unuse(E_Remember *rem)
261 {
262 if (rem->used_count) rem->used_count--;
263 }
264
265 E_API void
e_remember_del(E_Remember * rem)266 e_remember_del(E_Remember *rem)
267 {
268 E_Client *ec;
269
270 E_CLIENT_FOREACH(ec)
271 {
272 if ((ec->remember != rem) && (ec->sr_remember != rem)) continue;
273
274 if (ec->remember == rem)
275 ec->remember = NULL;
276 else
277 ec->sr_remember = NULL;
278 e_remember_unuse(rem);
279 }
280
281 _e_remember_free(rem);
282 }
283
284 E_API void
e_remember_apply(E_Remember * rem,E_Client * ec)285 e_remember_apply(E_Remember *rem, E_Client *ec)
286 {
287 int temporary = 0;
288 if (ec->internal && remembers && ec->icccm.class && ec->icccm.class[0])
289 {
290 Eina_List *l;
291 EINA_LIST_FOREACH(remembers->list, l, rem)
292 {
293 if (rem->class && !strcmp(rem->class, ec->icccm.class))
294 break;
295 }
296 if (rem)
297 {
298 temporary = 1;
299 remembers->list = eina_list_remove(remembers->list, rem);
300 remember_idler_list = eina_list_remove(remember_idler_list, rem);
301 if (!remembers->list)
302 e_config_domain_save("e_remember_restart",
303 e_remember_list_edd, remembers);
304 }
305 else rem = ec->remember;
306 }
307
308 if (!rem)
309 return;
310 rem->applying = 1;
311 if (rem->apply & E_REMEMBER_APPLY_ZONE)
312 {
313 E_Zone *zone;
314
315 zone = e_comp_zone_number_get(rem->prop.zone);
316 if (zone)
317 e_client_zone_set(ec, zone);
318 }
319 if (rem->apply & E_REMEMBER_APPLY_DESKTOP)
320 {
321 E_Desk *desk;
322
323 desk = e_desk_at_xy_get(ec->zone, rem->prop.desk_x, rem->prop.desk_y);
324 if (desk)
325 {
326 if (ec->desk != desk)
327 ec->hidden = 0;
328 e_client_desk_set(ec, desk);
329 if (e_config->desk_auto_switch)
330 e_desk_show(desk);
331 }
332 }
333 if (rem->apply & E_REMEMBER_APPLY_BORDER)
334 {
335 eina_stringshare_replace(&ec->bordername, NULL);
336 ec->bordername = eina_stringshare_ref(rem->prop.border);
337 ec->border.changed = 1;
338 EC_CHANGED(ec);
339 }
340 if (rem->apply & E_REMEMBER_APPLY_SIZE)
341 {
342 int w, h;
343 int uzx = 0, uzy = 0, uzw = 0, uzh = 0;
344
345 e_zone_useful_geometry_get(ec->zone, &uzx, &uzy, &uzw, &uzh);
346
347 w = ec->client.w;
348 h = ec->client.h;
349 if (rem->prop.pos_w) ec->client.w = rem->prop.pos_w;
350 if (rem->prop.pos_h) ec->client.h = rem->prop.pos_h;
351 if (uzw != rem->prop.res_x)
352 {
353 if (ec->client.w > (uzw - rem->prop.frame_w))
354 ec->client.w = uzw - rem->prop.frame_w;
355 }
356 if (uzh != rem->prop.res_y)
357 {
358 if (ec->client.h > (uzh - rem->prop.frame_h))
359 ec->client.h = uzh - rem->prop.frame_h;
360 }
361 if (ec->icccm.min_w > ec->client.w)
362 ec->client.w = ec->icccm.min_w;
363 if ((ec->icccm.max_w > 0) && (ec->icccm.max_w < ec->client.w))
364 ec->client.w = ec->icccm.max_w;
365 if (ec->icccm.min_h > ec->client.h)
366 ec->client.h = ec->icccm.min_h;
367 if ((ec->icccm.max_h > 0) && (ec->icccm.max_h < ec->client.h))
368 ec->client.h = ec->icccm.max_h;
369 e_comp_object_frame_wh_adjust(ec->frame, ec->client.w, ec->client.h,
370 &ec->w, &ec->h);
371 if (rem->prop.maximize)
372 {
373 ec->saved.x = rem->prop.pos_x;
374 ec->saved.y = rem->prop.pos_y;
375 ec->saved.w = ec->client.w;
376 ec->saved.h = ec->client.h;
377 ec->maximized = rem->prop.maximize | e_config->maximize_policy;
378 ec->changes.need_maximize = 1;
379 }
380 if ((w != ec->client.w) || (h != ec->client.h))
381 {
382 ec->changes.size = 1;
383 ec->changes.shape = 1;
384 EC_CHANGED(ec);
385 }
386 }
387 if ((rem->apply & E_REMEMBER_APPLY_POS) && (!ec->re_manage))
388 {
389 int uzx = 0, uzy = 0, uzw = 0, uzh = 0;
390
391 e_zone_useful_geometry_get(ec->zone, &uzx, &uzy, &uzw, &uzh);
392 ec->x = rem->prop.pos_x;
393 ec->y = rem->prop.pos_y;
394 if (uzw != rem->prop.res_x)
395 {
396 int px;
397
398 px = uzw - (ec->w + rem->prop.frame_w);
399 if (px < 1) px = 0;
400 else px = (3 * ec->x) / px;
401 if (px < 1)
402 {
403 if (uzw >= (rem->prop.res_x / 3))
404 ec->x = rem->prop.pos_x;
405 else
406 ec->x = ((rem->prop.pos_x - 0) * uzw) /
407 (rem->prop.res_x / 3);
408 }
409 else if (px == 1)
410 {
411 if (uzw >= (rem->prop.res_x / 3))
412 ec->x = (uzw / 2) +
413 (px - (rem->prop.res_x / 2)) -
414 (ec->w / 2);
415 else
416 ec->x = (uzw / 2) +
417 (((px - (rem->prop.res_x / 2)) * uzw) /
418 (rem->prop.res_x / 3)) -
419 (ec->w / 2);
420 }
421 else // >= 2
422 {
423 if (uzw >= (rem->prop.res_x / 3))
424 ec->x = uzw +
425 rem->prop.pos_x - rem->prop.res_x +
426 (rem->prop.w - ec->client.w);
427 else
428 ec->x = uzw +
429 (((rem->prop.pos_x - rem->prop.res_x) * uzw) /
430 (rem->prop.res_x / 3)) +
431 (rem->prop.w - ec->client.w);
432 }
433 if ((rem->prop.pos_x >= 0) && (ec->x < 0))
434 ec->x = 0;
435 else if (((rem->prop.pos_x + rem->prop.w) < rem->prop.res_x) &&
436 ((ec->x + ec->client.w + rem->prop.frame_w) > (uzw - (uzx - ec->zone->x))))
437 ec->x = (uzw - (uzx - ec->zone->x)) - ec->client.w - rem->prop.frame_w;
438 }
439 if (uzh != rem->prop.res_y)
440 {
441 int py;
442
443 py = uzh - (ec->h + rem->prop.frame_h);
444 if (py < 1) py = 0;
445 else py = (3 * ec->y) / py;
446 if (py < 1)
447 {
448 if (uzh >= (rem->prop.res_y / 3))
449 ec->y = rem->prop.pos_y;
450 else
451 ec->y = ((rem->prop.pos_y - 0) * uzh) /
452 (rem->prop.res_y / 3);
453 }
454 else if (py == 1)
455 {
456 if (uzh >= (rem->prop.res_y / 3))
457 ec->y = (uzh / 2) +
458 (py - (rem->prop.res_y / 2)) -
459 (ec->h / 2);
460 else
461 ec->y = (uzh / 2) +
462 (((py - (rem->prop.res_y / 2)) * uzh) /
463 (rem->prop.res_y / 3)) -
464 (ec->h / 2);
465 }
466 else // >= 2
467 {
468 if (uzh >= (rem->prop.res_y / 3))
469 ec->y = uzh +
470 rem->prop.pos_y - rem->prop.res_y +
471 (rem->prop.h - ec->client.h);
472 else
473 ec->y = uzh +
474 (((rem->prop.pos_y - rem->prop.res_y) * uzh) /
475 (rem->prop.res_y / 3)) +
476 (rem->prop.h - ec->client.h);
477 }
478 if ((rem->prop.pos_y >= 0) && (ec->y < 0))
479 ec->y = 0;
480 else if (((rem->prop.pos_y + rem->prop.h) < rem->prop.res_y) &&
481 ((ec->y + ec->client.h + rem->prop.frame_h) > (uzh - (uzy - ec->zone->y))))
482 ec->y = (uzh - (uzy - ec->zone->y)) - ec->client.h - rem->prop.frame_h;
483 }
484 // if (ec->zone->w != rem->prop.res_x)
485 // ec->x = (rem->prop.pos_x * ec->zone->w) / rem->prop.res_x;
486 // if (ec->zone->h != rem->prop.res_y)
487 // ec->y = (rem->prop.pos_y * ec->zone->h) / rem->prop.res_y;
488 if (
489 /* upper left */
490 (!E_INSIDE(ec->x, ec->y, 0, 0, ec->zone->w, ec->zone->h)) &&
491 /* upper right */
492 (!E_INSIDE(ec->x + ec->w, ec->y, 0, 0, ec->zone->w, ec->zone->h)) &&
493 /* lower left */
494 (!E_INSIDE(ec->x, ec->y + ec->h, 0, 0, ec->zone->w, ec->zone->h)) &&
495 /* lower right */
496 (!E_INSIDE(ec->x + ec->w, ec->y + ec->h, 0, 0, ec->zone->w, ec->zone->h))
497 )
498 {
499 e_comp_object_util_center_pos_get(ec->frame, &ec->x, &ec->y);
500 rem->prop.pos_x = ec->x;
501 rem->prop.pos_y = ec->y;
502 }
503 ec->x += uzx;
504 ec->y += uzy;
505 ec->placed = 1;
506 ec->changes.pos = 1;
507 EC_CHANGED(ec);
508 }
509 if (rem->apply & E_REMEMBER_APPLY_LAYER)
510 {
511 evas_object_layer_set(ec->frame, rem->prop.layer);
512 }
513 if (rem->apply & E_REMEMBER_APPLY_FULLSCREEN)
514 {
515 if (rem->prop.fullscreen)
516 e_client_fullscreen(ec, e_config->fullscreen_policy);
517 }
518 if (rem->apply & E_REMEMBER_APPLY_STICKY)
519 {
520 if (rem->prop.sticky) e_client_stick(ec);
521 }
522 if (rem->apply & E_REMEMBER_APPLY_SHADE)
523 {
524 if (rem->prop.shaded >= 100)
525 e_client_shade(ec, rem->prop.shaded - 100);
526 else if (rem->prop.shaded >= 50)
527 e_client_unshade(ec, rem->prop.shaded - 50);
528 }
529 if (rem->apply & E_REMEMBER_APPLY_LOCKS)
530 {
531 ec->lock_user_location = rem->prop.lock_user_location;
532 ec->lock_client_location = rem->prop.lock_client_location;
533 ec->lock_user_size = rem->prop.lock_user_size;
534 ec->lock_client_size = rem->prop.lock_client_size;
535 ec->lock_user_stacking = rem->prop.lock_user_stacking;
536 ec->lock_client_stacking = rem->prop.lock_client_stacking;
537 ec->lock_user_iconify = rem->prop.lock_user_iconify;
538 ec->lock_client_iconify = rem->prop.lock_client_iconify;
539 ec->lock_user_desk = rem->prop.lock_user_desk;
540 ec->lock_client_desk = rem->prop.lock_client_desk;
541 ec->lock_user_sticky = rem->prop.lock_user_sticky;
542 ec->lock_client_sticky = rem->prop.lock_client_sticky;
543 ec->lock_user_shade = rem->prop.lock_user_shade;
544 ec->lock_client_shade = rem->prop.lock_client_shade;
545 ec->lock_user_maximize = rem->prop.lock_user_maximize;
546 ec->lock_client_maximize = rem->prop.lock_client_maximize;
547 ec->lock_user_fullscreen = rem->prop.lock_user_fullscreen;
548 ec->lock_client_fullscreen = rem->prop.lock_client_fullscreen;
549 ec->lock_border = rem->prop.lock_border;
550 ec->lock_close = rem->prop.lock_close;
551 ec->lock_focus_in = rem->prop.lock_focus_in;
552 ec->lock_focus_out = rem->prop.lock_focus_out;
553 ec->lock_life = rem->prop.lock_life;
554 }
555 if (rem->apply & E_REMEMBER_APPLY_SKIP_WINLIST)
556 ec->user_skip_winlist = rem->prop.skip_winlist;
557 if (rem->apply & E_REMEMBER_APPLY_SKIP_PAGER)
558 ec->netwm.state.skip_pager = rem->prop.skip_pager;
559 if (rem->apply & E_REMEMBER_APPLY_SKIP_TASKBAR)
560 ec->netwm.state.skip_taskbar = rem->prop.skip_taskbar;
561 if (rem->apply & E_REMEMBER_APPLY_ICON_PREF)
562 ec->icon_preference = rem->prop.icon_preference;
563 if (rem->apply & E_REMEMBER_APPLY_OFFER_RESISTANCE)
564 ec->offer_resistance = rem->prop.offer_resistance;
565 if (rem->apply & E_REMEMBER_SET_FOCUS_ON_START)
566 ec->want_focus = 1;
567 if (rem->apply & E_REMEMBER_APPLY_OPACITY)
568 ec->netwm.opacity = rem->prop.opacity;
569 if (rem->apply & E_REMEMBER_APPLY_VOLUME)
570 {
571 if (!ec->volume_control_enabled)
572 {
573 ec->volume_control_enabled = EINA_TRUE;
574 ec->volume = rem->prop.volume;
575 ec->volume_min = rem->prop.volume_min;
576 ec->volume_max = rem->prop.volume_max;
577 ec->mute = rem->prop.mute;
578 }
579 else
580 {
581 e_client_volume_set(ec, rem->prop.volume);
582 e_client_volume_mute_set(ec, rem->prop.mute);
583 }
584 }
585
586 rem->applying = 0;
587 if (temporary)
588 _e_remember_free(rem);
589 }
590
591 E_API E_Remember *
e_remember_find_usable(E_Client * ec)592 e_remember_find_usable(E_Client *ec)
593 {
594 E_Remember *rem;
595
596 rem = _e_remember_find(ec, 1, 0);
597 return rem;
598 }
599
600 E_API E_Remember *
e_remember_find(E_Client * ec)601 e_remember_find(E_Client *ec)
602 {
603 E_Remember *rem;
604
605 rem = _e_remember_find(ec, 0, 0);
606 return rem;
607 }
608
609 E_API E_Remember *
e_remember_sr_find(E_Client * ec)610 e_remember_sr_find(E_Client *ec)
611 {
612 return _e_remember_find(ec, 1, 1);
613 }
614
615 E_API void
e_remember_match_update(E_Remember * rem)616 e_remember_match_update(E_Remember *rem)
617 {
618 int max_count = 0;
619
620 if (rem->match & E_REMEMBER_MATCH_NAME) max_count += 2;
621 if (rem->match & E_REMEMBER_MATCH_CLASS) max_count += 2;
622 if (rem->match & E_REMEMBER_MATCH_TITLE) max_count += 2;
623 if (rem->match & E_REMEMBER_MATCH_ROLE) max_count += 2;
624 if (rem->match & E_REMEMBER_MATCH_TYPE) max_count += 2;
625 if (rem->match & E_REMEMBER_MATCH_TRANSIENT) max_count += 2;
626 if (rem->apply_first_only) max_count++;
627
628 if (max_count != rem->max_score)
629 {
630 /* The number of matches for this remember has changed so we
631 * need to remove from list and insert back into the appropriate
632 * location. */
633 Eina_List *l = NULL;
634 E_Remember *r;
635
636 rem->max_score = max_count;
637 e_config->remembers = eina_list_remove(e_config->remembers, rem);
638
639 EINA_LIST_FOREACH(e_config->remembers, l, r)
640 {
641 if (r->max_score <= rem->max_score) break;
642 }
643
644 if (l)
645 e_config->remembers = eina_list_prepend_relative_list(e_config->remembers, rem, l);
646 else
647 e_config->remembers = eina_list_append(e_config->remembers, rem);
648 }
649 }
650
651 E_API int
e_remember_default_match_set(E_Remember * rem,E_Client * ec)652 e_remember_default_match_set(E_Remember *rem, E_Client *ec)
653 {
654 const char *title, *clasz, *name, *role;
655 int match;
656
657 eina_stringshare_replace(&rem->name, NULL);
658 eina_stringshare_replace(&rem->class, NULL);
659 eina_stringshare_replace(&rem->title, NULL);
660 eina_stringshare_replace(&rem->role, NULL);
661
662 name = ec->icccm.name;
663 if (!name || name[0] == 0) name = NULL;
664 clasz = ec->icccm.class;
665 if (!clasz || clasz[0] == 0) clasz = NULL;
666 role = ec->icccm.window_role;
667 if (!role || role[0] == 0) role = NULL;
668
669 match = E_REMEMBER_MATCH_TRANSIENT;
670 if (ec->icccm.transient_for != 0)
671 rem->transient = 1;
672 else
673 rem->transient = 0;
674
675 if (name && clasz)
676 {
677 match |= E_REMEMBER_MATCH_NAME | E_REMEMBER_MATCH_CLASS;
678 rem->name = eina_stringshare_ref(name);
679 rem->class = eina_stringshare_ref(clasz);
680 }
681 else if ((title = e_client_util_name_get(ec)) && title[0])
682 {
683 match |= E_REMEMBER_MATCH_TITLE;
684 rem->title = eina_stringshare_ref(title);
685 }
686 if (role)
687 {
688 match |= E_REMEMBER_MATCH_ROLE;
689 rem->role = eina_stringshare_ref(role);
690 }
691 if (ec->netwm.type != E_WINDOW_TYPE_UNKNOWN)
692 {
693 match |= E_REMEMBER_MATCH_TYPE;
694 rem->type = ec->netwm.type;
695 }
696
697 rem->match = match;
698
699 return match;
700 }
701
702 E_API void
e_remember_update(E_Client * ec)703 e_remember_update(E_Client *ec)
704 {
705 if (((!ec->remember) || ec->remember->keep_settings) && (!ec->sr_remember)) return;
706 if (ec->remember) _e_remember_update(ec, ec->remember);
707 if (ec->sr_remember) _e_remember_update(ec, ec->sr_remember);
708 e_config_save_queue();
709 }
710
711 static void
_e_remember_event_free(void * d EINA_UNUSED,void * event)712 _e_remember_event_free(void *d EINA_UNUSED, void *event)
713 {
714 E_Event_Remember_Update *ev = event;
715 UNREFD(ev->ec, 10);
716 e_object_unref(E_OBJECT(ev->ec));
717 free(ev);
718 }
719
720 static void
_e_remember_update(E_Client * ec,E_Remember * rem)721 _e_remember_update(E_Client *ec, E_Remember *rem)
722 {
723 if (rem->applying) return;
724 if (rem->apply & E_REMEMBER_APPLY_POS ||
725 rem->apply & E_REMEMBER_APPLY_SIZE)
726 {
727 int uzx = 0, uzy = 0, uxw = 0, uzh = 0;
728
729 e_zone_useful_geometry_get(ec->zone, &uzx, &uzy, &uxw, &uzh);
730 if (ec->fullscreen || ec->maximized)
731 {
732 rem->prop.pos_x = ec->saved.x - uzx;
733 rem->prop.pos_y = ec->saved.y - uzy;
734 rem->prop.pos_w = ec->saved.w;
735 rem->prop.pos_h = ec->saved.h;
736 rem->prop.frame_w = ec->w - ec->client.w;
737 rem->prop.frame_h = ec->h - ec->client.h;
738 }
739 else
740 {
741 rem->prop.pos_x = ec->x - uzx;
742 rem->prop.pos_y = ec->y - uzy;
743 rem->prop.res_x = uxw;
744 rem->prop.res_y = uzh;
745 rem->prop.pos_w = ec->client.w;
746 rem->prop.pos_h = ec->client.h;
747 rem->prop.w = ec->client.w;
748 rem->prop.h = ec->client.h;
749 rem->prop.frame_w = ec->w - ec->client.w;
750 rem->prop.frame_h = ec->h - ec->client.h;
751 }
752 rem->prop.maximize = ec->maximized & E_MAXIMIZE_DIRECTION;
753 }
754 if (rem->apply & E_REMEMBER_APPLY_LAYER)
755 {
756 if (ec->fullscreen)
757 rem->prop.layer = ec->saved.layer;
758 else
759 rem->prop.layer = ec->layer;
760 }
761 if (rem->apply & E_REMEMBER_APPLY_LOCKS)
762 {
763 rem->prop.lock_user_location = ec->lock_user_location;
764 rem->prop.lock_client_location = ec->lock_client_location;
765 rem->prop.lock_user_size = ec->lock_user_size;
766 rem->prop.lock_client_size = ec->lock_client_size;
767 rem->prop.lock_user_stacking = ec->lock_user_stacking;
768 rem->prop.lock_client_stacking = ec->lock_client_stacking;
769 rem->prop.lock_user_iconify = ec->lock_user_iconify;
770 rem->prop.lock_client_iconify = ec->lock_client_iconify;
771 rem->prop.lock_user_desk = ec->lock_user_desk;
772 rem->prop.lock_client_desk = ec->lock_client_desk;
773 rem->prop.lock_user_sticky = ec->lock_user_sticky;
774 rem->prop.lock_client_sticky = ec->lock_client_sticky;
775 rem->prop.lock_user_shade = ec->lock_user_shade;
776 rem->prop.lock_client_shade = ec->lock_client_shade;
777 rem->prop.lock_user_maximize = ec->lock_user_maximize;
778 rem->prop.lock_client_maximize = ec->lock_client_maximize;
779 rem->prop.lock_user_fullscreen = ec->lock_user_fullscreen;
780 rem->prop.lock_client_fullscreen = ec->lock_client_fullscreen;
781 rem->prop.lock_border = ec->lock_border;
782 rem->prop.lock_close = ec->lock_close;
783 rem->prop.lock_focus_in = ec->lock_focus_in;
784 rem->prop.lock_focus_out = ec->lock_focus_out;
785 rem->prop.lock_life = ec->lock_life;
786 }
787 if (rem->apply & E_REMEMBER_APPLY_SHADE)
788 {
789 if (ec->shaded)
790 rem->prop.shaded = (100 + ec->shade_dir);
791 else
792 rem->prop.shaded = (50 + ec->shade_dir);
793 }
794 if (rem->apply & E_REMEMBER_APPLY_ZONE)
795 {
796 rem->prop.zone = ec->zone->num;
797 }
798 if (rem->apply & E_REMEMBER_APPLY_SKIP_WINLIST)
799 rem->prop.skip_winlist = ec->user_skip_winlist;
800 if (rem->apply & E_REMEMBER_APPLY_STICKY)
801 rem->prop.sticky = ec->sticky;
802 if (rem->apply & E_REMEMBER_APPLY_SKIP_PAGER)
803 rem->prop.skip_pager = ec->netwm.state.skip_pager;
804 if (rem->apply & E_REMEMBER_APPLY_SKIP_TASKBAR)
805 rem->prop.skip_taskbar = ec->netwm.state.skip_taskbar;
806 if (rem->apply & E_REMEMBER_APPLY_ICON_PREF)
807 rem->prop.icon_preference = ec->icon_preference;
808 if (rem->apply & E_REMEMBER_APPLY_DESKTOP)
809 e_desk_xy_get(ec->desk, &rem->prop.desk_x, &rem->prop.desk_y);
810 if (rem->apply & E_REMEMBER_APPLY_FULLSCREEN)
811 rem->prop.fullscreen = ec->fullscreen;
812 if (rem->apply & E_REMEMBER_APPLY_OFFER_RESISTANCE)
813 rem->prop.offer_resistance = ec->offer_resistance;
814 if (rem->apply & E_REMEMBER_APPLY_OPACITY)
815 rem->prop.opacity = ec->netwm.opacity;
816 if (rem->apply & E_REMEMBER_APPLY_BORDER)
817 {
818 if (ec->borderless)
819 eina_stringshare_replace(&rem->prop.border, "borderless");
820 else
821 eina_stringshare_replace(&rem->prop.border, ec->bordername);
822 }
823 if (rem->apply & E_REMEMBER_APPLY_UUID)
824 {
825 eina_stringshare_refplace(&rem->uuid, ec->uuid);
826 rem->pid = ec->netwm.pid;
827 rem->apply_first_only = 1;
828 }
829 if (rem->apply & E_REMEMBER_APPLY_VOLUME)
830 {
831 rem->prop.volume = ec->volume;
832 rem->prop.volume_min = ec->volume_min;
833 rem->prop.volume_max = ec->volume_max;
834 rem->prop.mute = ec->mute;
835 }
836
837 rem->no_reopen = ec->internal_no_reopen;
838 {
839 E_Event_Remember_Update *ev;
840
841 ev = malloc(sizeof(E_Event_Remember_Update));
842 if (!ev) return;
843 ev->ec = ec;
844 REFD(ec, 10);
845 e_object_ref(E_OBJECT(ec));
846 ecore_event_add(E_EVENT_REMEMBER_UPDATE, ev, _e_remember_event_free, NULL);
847 }
848 }
849
850 /* local subsystem functions */
851 static E_Remember *
_e_remember_find(E_Client * ec,int check_usable,Eina_Bool sr)852 _e_remember_find(E_Client *ec, int check_usable, Eina_Bool sr)
853 {
854 Eina_List *l = NULL;
855 E_Remember *rem;
856
857 #if REMEMBER_SIMPLE
858 EINA_LIST_FOREACH(e_config->remembers, l, rem)
859 {
860 int required_matches;
861 int matches;
862 const char *title = "";
863
864 matches = 0;
865 required_matches = 0;
866 if (rem->match & E_REMEMBER_MATCH_NAME) required_matches++;
867 if (rem->match & E_REMEMBER_MATCH_CLASS) required_matches++;
868 if (rem->match & E_REMEMBER_MATCH_TITLE) required_matches++;
869 if (rem->match & E_REMEMBER_MATCH_ROLE) required_matches++;
870 if (rem->match & E_REMEMBER_MATCH_TYPE) required_matches++;
871 if (rem->match & E_REMEMBER_MATCH_TRANSIENT) required_matches++;
872
873 if (ec->netwm.name) title = ec->netwm.name;
874 else title = ec->icccm.title;
875
876 if ((rem->match & E_REMEMBER_MATCH_NAME) &&
877 ((!e_util_strcmp(rem->name, ec->icccm.name)) ||
878 (e_util_both_str_empty(rem->name, ec->icccm.name))))
879 matches++;
880 if ((rem->match & E_REMEMBER_MATCH_CLASS) &&
881 ((!e_util_strcmp(rem->class, ec->icccm.class)) ||
882 (e_util_both_str_empty(rem->class, ec->icccm.class))))
883 matches++;
884 if ((rem->match & E_REMEMBER_MATCH_TITLE) &&
885 ((!e_util_strcmp(rem->title, title)) ||
886 (e_util_both_str_empty(rem->title, title))))
887 matches++;
888 if ((rem->match & E_REMEMBER_MATCH_ROLE) &&
889 ((!e_util_strcmp(rem->role, ec->icccm.window_role)) ||
890 (e_util_both_str_empty(rem->role, ec->icccm.window_role))))
891 matches++;
892 if ((rem->match & E_REMEMBER_MATCH_TYPE) &&
893 (rem->type == ec->netwm.type))
894 matches++;
895 if ((rem->match & E_REMEMBER_MATCH_TRANSIENT) &&
896 (((rem->transient) && (ec->icccm.transient_for != 0)) ||
897 ((!rem->transient) && (ec->icccm.transient_for == 0))))
898 matches++;
899 if (matches >= required_matches)
900 return rem;
901 }
902 return NULL;
903 #endif
904 #if REMEMBER_HIERARCHY
905 /* This search method finds the best possible match available and is
906 * based on the fact that the list is sorted, with those remembers
907 * with the most possible matches at the start of the list. This
908 * means, as soon as a valid match is found, it is a match
909 * within the set of best possible matches. */
910 EINA_LIST_FOREACH(e_config->remembers, l, rem)
911 {
912 const char *title = "";
913
914 if ((check_usable) && (!e_remember_usable_get(rem)))
915 continue;
916
917 if (sr)
918 {
919 if (!eina_streq(rem->uuid, ec->uuid)) continue;
920 if (rem->uuid)
921 {
922 if (rem->pid != ec->netwm.pid) continue;
923 return rem;
924 }
925 }
926 else if (rem->apply & E_REMEMBER_APPLY_UUID) continue;
927
928 if (ec->netwm.name) title = ec->netwm.name;
929 else title = ec->icccm.title;
930
931 /* For each type of match, check whether the match is
932 * required, and if it is, check whether there's a match. If
933 * it fails, then go to the next remember */
934 if (rem->match & E_REMEMBER_MATCH_NAME &&
935 !e_util_glob_match(ec->icccm.name, rem->name))
936 continue;
937 if (rem->match & E_REMEMBER_MATCH_CLASS &&
938 !e_util_glob_match(ec->icccm.class, rem->class))
939 continue;
940 if (rem->match & E_REMEMBER_MATCH_TITLE &&
941 !e_util_glob_match(title, rem->title))
942 continue;
943 if (rem->match & E_REMEMBER_MATCH_ROLE &&
944 e_util_strcmp(rem->role, ec->icccm.window_role) &&
945 !e_util_both_str_empty(rem->role, ec->icccm.window_role))
946 continue;
947 if (rem->match & E_REMEMBER_MATCH_TYPE &&
948 rem->type != (int)ec->netwm.type)
949 continue;
950 if (rem->match & E_REMEMBER_MATCH_TRANSIENT &&
951 !(rem->transient && ec->icccm.transient_for != 0) &&
952 !(!rem->transient) && (ec->icccm.transient_for == 0))
953 continue;
954
955 return rem;
956 }
957
958 return NULL;
959 #endif
960 }
961
962 static void
_e_remember_free(E_Remember * rem)963 _e_remember_free(E_Remember *rem)
964 {
965 e_config->remembers = eina_list_remove(e_config->remembers, rem);
966 if (rem->name) eina_stringshare_del(rem->name);
967 if (rem->class) eina_stringshare_del(rem->class);
968 if (rem->title) eina_stringshare_del(rem->title);
969 if (rem->role) eina_stringshare_del(rem->role);
970 if (rem->prop.border) eina_stringshare_del(rem->prop.border);
971 if (rem->prop.command) eina_stringshare_del(rem->prop.command);
972 if (rem->prop.desktop_file) eina_stringshare_del(rem->prop.desktop_file);
973 eina_stringshare_del(rem->uuid);
974 free(rem);
975 }
976
977 static void
_e_remember_cb_hook_eval_post_new_client(void * data EINA_UNUSED,E_Client * ec)978 _e_remember_cb_hook_eval_post_new_client(void *data EINA_UNUSED, E_Client *ec)
979 {
980 // remember only when window was modified
981 // if (!ec->new_client) return;
982 if (e_client_util_ignored_get(ec)) return;
983 if ((ec->internal) && (!ec->remember) &&
984 (e_config->remember_internal_windows) &&
985 (!ec->internal_no_remember) &&
986 (ec->icccm.class && ec->icccm.class[0]))
987 {
988 E_Remember *rem;
989
990 if (!strncmp(ec->icccm.class, "e_fwin", 6))
991 {
992 if (!e_config->remember_internal_fm_windows) return;
993 }
994 else
995 {
996 if (!e_config->remember_internal_windows)
997 return;
998 }
999
1000 rem = e_remember_new();
1001 if (!rem) return;
1002
1003 e_remember_default_match_set(rem, ec);
1004
1005 rem->apply = E_REMEMBER_APPLY_POS | E_REMEMBER_APPLY_SIZE | E_REMEMBER_APPLY_BORDER;
1006
1007 e_remember_use(rem);
1008 ec->remember = rem;
1009 e_remember_update(ec);
1010 }
1011 }
1012
1013 static void
_e_remember_cb_hook_pre_post_fetch(void * data EINA_UNUSED,E_Client * ec)1014 _e_remember_cb_hook_pre_post_fetch(void *data EINA_UNUSED, E_Client *ec)
1015 {
1016 E_Remember *rem = NULL;
1017
1018 if ((!ec->new_client) || ec->internal_no_remember || e_client_util_ignored_get(ec)) return;
1019
1020 if (!ec->remember)
1021 {
1022 rem = e_remember_find_usable(ec);
1023 if (rem)
1024 {
1025 ec->remember = rem;
1026 e_remember_use(rem);
1027 }
1028 }
1029
1030 e_remember_apply(rem, ec);
1031 }
1032
1033 static void
_e_remember_init_edd(void)1034 _e_remember_init_edd(void)
1035 {
1036 e_remember_list_edd = E_CONFIG_DD_NEW("E_Remember_List", E_Remember_List);
1037 #undef T
1038 #undef D
1039 #define T E_Remember_List
1040 #define D e_remember_list_edd
1041 E_CONFIG_LIST(D, T, list, e_remember_edd);
1042 #undef T
1043 #undef D
1044 }
1045
1046