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