XWayland: GOOOOOOOOOAAAAAAAAAAAAAAALLLLLLLLLLLLLLLLLLLLLLLLLLLL

As I sit here doing supersets of donut-eating, XWayland support in Enlightenment is currently “done”. The work was started, if you want to get overly technical, almost a year ago, at which point a module stub was added to a branch by Chris “devilhorns” Michael and then promptly forgotten about by everyone of import.

 

I’d provide a list of things that work or don’t work, but really…there’s nothing that doesn’t work. It’s a totally flawless implementation with zero bugs of any kind. This branch merge is so good that it’s made all pre-existing bugs in our issue tracker obsolete. A really tremendous job, if you ask me–or even if you refuse to ask me.

I do recommend not leaving your XWayland-running machine alone long enough for the screensaver to take effect, since there’s currently no way to un-effect it and your screen will have a giant black rectangle over it until you restart. But I prefer to look at this as a productivity-boosting positive: now everyone will be strongly motivated to take fewer and shorter breaks while working. That’s Enlightenment for you, always striving to be the most efficient desktop environment around BY ANY MEANS NECESSARY.

 

Let’s talk a bit about the implementation. This was not some kind of one-day, “I tried this and it worked lol?”, trivial thing to write. Some background is definitely necessary for most readers though, so I’ve created a small infographic that should be about as clear as most of the related documentation on the topic:

Now that you’re nearly as much of an expert as I am on the subject, let’s delve into how E implements this.

 

As I’ve mentioned in previous posts, the current Enlightenment compositor architecture is such that each display server backend is discrete–that is, the X11 and Wayland compositors exist separately, each handling only its respective protocol functionality, and then there is a general compositing infrastructure which handles rendering based on cues from the protocol backend. This is a plus because it means that the backends can be fired up to form Voltrona composite display server compositor, or, a compositor which handles both Wayland and X11 clients.

In the early days of Wayland support in Enlightenment 19+, this was used for adding Wayland clients into an X11 session–something that literally nobody wanted, especially me. After abusing it at a conference demo in 2013, this functionality was never ever used again until I eventually disabled it last year and then scrapped it altogether a couple days ago. The main reason was that it was simply too annoying to maintain this sort of functionality. Running with X11 as the main session requires the handling of input regions for all windows and doing shape cutting into the compositor canvas and even if I had a flowchart app I probably couldn’t be motivated to diagram out the exact algorithm that I wrote to do this while in a crumpet-fueled haze in London a few years ago.

Fast forwarding to some point in the last year or so, I was told that XWayland support needed to happen. Or maybe I told someone else that. I’ll go on record stating that it was definitely said by someone, possibly to another entity which may or may not have been my cat. As soon as it was determined that XWayland support was needed, I immediately dropped everything that I was doing and started working on literally any other project. It wasn’t procrastinating, however–those compositor effects needed to be implemented. Probably.

 

The key point of XWayland support is creating the XWayland process. This happens in a module and is Not Difficult. The difficulty arises later, when attempting to display and interact with X11 windows in the Wayland session.

Why is this Difficult, you ask? Well, casual reader, as you’ll recall from the diagram above, XWayland involves managing an XWindow while rendering a Wayland surface. Both of these things represent the same on-screen window, and they come from separate display server protocols; what could possibly go wrong in a multi-backend compositing environment?

Indeed, the issue was exactly as you’ve guessed. Both the XWindow and the Wayland surface created canvas objects in their respective compositors, and both of these objects showed up as the same window on the screen. Helpfully, however, neither of them would receive any input events, and they also could not be closed. I’d typically provide a screenshot here, but I don’t want to post potato-cam photos on the blog so you’ll have to imagine what this looked like and how furious I was.

I then determined, thanks in part to Derek “Mower Enthusiast” Foreman, that input should be handled only on the Wayland compositor side. Also render. Definitely only rendering on the Wayland side. To summarize, the compositor should be rendering and handling input through Wayland methods, but then doing just about everything else using X11.

Take X11 infos, push them into Wayland. Thanks, Patrick.

 

This is accomplished by first, getting the new XWindow, reparenting as necessary for non-overrides, and then linking it to the Wayland surface using the WL_SURFACE_ID atom. The XWindow and the Wayland surface, at this point, each have their own client object, so the data from the X11 client is copied onto the Wayland client and then the X11 client is deleted. The Wayland client takes over the hash table entries for the related XWindow, and magically everything works as expected.

 

I guess now that this is done, the only thing left to do is release E17?

Advertisements

Record-shattering Storm of Blog Posts Sighted Off Coast of GFY Island

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:

 

Powersaving: It’s Not For Everyone

It was recommended to me that I blog about some work I did the other day, so here I go.

 

Users may have noticed that urgent windows had a tendency to push cpu usage up pretty high due to animations–something which would occur even if the window wasn’t visible. This was caused by two factors:

  • Window frame animations:

With the changes to the compositor for E19, various effects became possible, such as the icon pulsing effect on window frames for urgent windows. Unfortunately, this runs on an animator timer within edje, and it will continue to perform animation calculations even when the window is not visible.

  • Pager animations

I had some fun with animations for the new pager gadget, and part of this was to mimic the pulsing animation used in the window frame. This had a similar issue: if the gadget was not visible, it would continue to animate. Furthermore, the image of the window would force the window to render when it would otherwise be deferred.

 

After some work, both of these cases have been fixed. Window frames are now completely frozen for all hidden windows, preventing them from waking up the cpu unnecessarily. Shelves and gadgets now propagate their visibility states so that objects which may animate, such as the contents of the pager, can appropriately freeze when they are not visible.

 

As one extremely French user put it, these commits “…didn’t actually trigger any problem” and “seems we get some improvemnt”. Also, “you should blog about it”.