Upon opening Firefox today to do some extremely-corporate reporting today, I became unreasonably and irrationally infuriated with the urlbar popup. How could this happen, some might ask. Why don’t you spend time on non-trivial things, others might say. No, postulating that at least two people are talking about the release blog is too generous; it’s unlikely that anyone other than my mother reads this blog these days.

Here we see the bar with its popup. Yes, it may have a more technical name, but I am unaware of it at this time. So bar and popup.

The issue I have has nothing to do with the application, so fear not, Firefox developers: you are safe for now. My fury was instead directed at the E compositor and the effects that we apply to the popup when it appears. For a rectangular window like this which clearly has an origin (the urlbar), why would we pop it up as though it was unanchored? This kind of bush league compositing might work for regular windows or compositors that I’m not actively working on, but I refuse to let my workspace be contaminated by such pedestrian effects.

And so I set out to add features for handling this sort of thing, ideally features which would be extensible and able to be reused for other related things. The code was simple; in fact, the code for adding a configuration GUI was longer and more complex than the actual implementation for the feature. Let’s check out some code:

diff --git a/src/bin/e_comp_object.c b/src/bin/e_comp_object.c index fa9d7ee..1a23c3b 100644 --- a/src/bin/e_comp_object.c +++ b/src/bin/e_comp_object.c @@ -75,6 +75,7 @@ typedef struct _E_Comp_Object Eina_Stringshare *frame_theme; Eina_Stringshare *frame_name; + Eina_Stringshare *visibility_effect; //effect when toggling visibility Evas_Object *smart_obj; // smart object Evas_Object *clip; // clipper over effect object @@ -503,6 +504,8 @@ _e_comp_object_shadow_setup(E_Comp_Object *cw) if (!ok) ok = e_theme_edje_object_set(cw->shobj, "base/theme/comp", buf); } + if (ok && m->visibility_effect) + eina_stringshare_refplace(&cw->visibility_effect, m->visibility_effect); if (ok) break; } }

This is where the compositor pulls the new effect’s name out of the config. It gets saved to the canvas object for later use.

@@ -654,14 +657,16 @@ _e_comp_object_done_defer(void *data, Evas_Object *obj EINA_UNUSED, const char * if (cw->animating) { cw->animating--; - e_comp->animating--; + if (!cw->animating) + e_comp->animating--; /* remove ref from animation start, account for possibility of deletion from unref */ if (!e_object_unref(E_OBJECT(cw->ec))) return; } + if (cw->animating) return; /* hide only after animation finishes to guarantee a full run of the animation */ - if (cw->defer_hide && (!strcmp(emission, "e,action,hide,done"))) + if (cw->defer_hide && ((!strcmp(emission, "e,action,hide,done")) || (!strcmp(emission, "e,action,done")))) evas_object_hide(cw->smart_obj); - else if (!cw->animating) + else e_comp_shape_queue(); }

This callback controls animation refcounting; when the animating flag is 0, the object is no longer animating and can be used normally. Since there are now going to be two references, the appropriate logic adjustments must be made to avoid toggling visibility at the wrong time.

@@ -1291,6 +1296,14 @@ _e_comp_intercept_hide(void *data, Evas_Object *obj) e_comp->animating++; cw->animating++; e_object_ref(E_OBJECT(cw->ec)); + if (cw->visibility_effect) + { + cw->animating++; + e_object_ref(E_OBJECT(cw->ec)); + e_comp_object_effect_set(obj, cw->visibility_effect); + e_comp_object_effect_params_set(obj, 0, (int[]){0}, 1); + e_comp_object_effect_start(obj, _e_comp_object_done_defer, cw); + } } cw->defer_hide = !!cw->animating; if (!cw->animating)

When hiding the window, the original compositor animation triggers first; this is the one which determines how the object fades in and out. After, the new effect begins, starting from the visible/default state (0) and hitting the deferred refcounting callback upon animation completion.

@@ -2026,6 +2039,14 @@ _e_comp_smart_show(Evas_Object *obj) e_comp->animating++; cw->animating++; e_object_ref(E_OBJECT(cw->ec)); + if (cw->visibility_effect) + { + cw->animating++; + e_object_ref(E_OBJECT(cw->ec)); + e_comp_object_effect_set(obj, cw->visibility_effect); + e_comp_object_effect_params_set(obj, 0, (int[]){1}, 1); + e_comp_object_effect_start(obj, _e_comp_object_done_defer, cw); + } } /* ensure some random effect doesn't lock the client offscreen */ if (!cw->animating)

And lastly, when showing the object it’s the same as hiding, except that the object starts from the hidden state (1).

The result looks a bit nicer:



Anyone wanting to replicate the effect can add the highlighted entry in this image to their composite match settings: