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