git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitbae9452a32a1ae8e63d4c1c418583315678ae8b4
parentef1510f0c4
authorIsaac Freund <[email protected]>
date2021-04-27 18:28
river: always render floating views above layout views

 river/Cursor.zig | 23 ++++++++++++++++++++---
 river/render.zig | 27 +++++++++++++++++++++------
 2 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/river/Cursor.zig b/river/Cursor.zig
index 69cc2dc..44cf8f3 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -423,8 +423,9 @@ fn handleRequestSetCursor(
 }
 
 /// Find the topmost surface under the output layout coordinates lx/ly
-/// returns the surface if found and sets the sx/sy parametes to the
+/// returns the surface if found and sets the sx/sy parameters to the
 /// surface coordinates.
+/// This function must be kept in sync with the rendering order in render.zig.
 fn surfaceAt(self: Self, lx: f64, ly: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
     const root = self.seat.input_manager.server.root;
     const wlr_output = root.output_layout.outputAt(lx, ly) orelse return null;
@@ -490,15 +491,31 @@ fn layerSurfaceAt(layer: std.TailQueue(LayerSurface), ox: f64, oy: f64, sx: *f64
 
 /// Find the topmost visible view surface (incl. popups) at ox,oy.
 fn viewSurfaceAt(output: Output, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
-    // Focused views are rendered on top, so look for them first.
+    // focused, floating views
     var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
     while (it.next()) |view| {
-        if (view.current.focus == 0) continue;
+        if (view.current.focus == 0 or !view.current.float) continue;
         if (view.surfaceAt(ox, oy, sx, sy)) |found| return found;
     }
 
+    // non-focused, floating views
     it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
     while (it.next()) |view| {
+        if (view.current.focus != 0 or !view.current.float) continue;
+        if (view.surfaceAt(ox, oy, sx, sy)) |found| return found;
+    }
+
+    // focused, non-floating views
+    it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
+    while (it.next()) |view| {
+        if (view.current.focus == 0 or view.current.float) continue;
+        if (view.surfaceAt(ox, oy, sx, sy)) |found| return found;
+    }
+
+    // non-focused, non-floating views
+    it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
+    while (it.next()) |view| {
+        if (view.current.focus != 0 or view.current.float) continue;
         if (view.surfaceAt(ox, oy, sx, sy)) |found| return found;
     }
 
diff --git a/river/render.zig b/river/render.zig
index 578a685..7357ed0 100644
--- a/river/render.zig
+++ b/river/render.zig
@@ -45,6 +45,7 @@ const SurfaceRenderData = struct {
     opacity: f32,
 };
 
+/// The rendering order in this function must be kept in sync with Cursor.surfaceAt()
 pub fn renderOutput(output: *Output) void {
     const config = &output.root.server.config;
     const renderer = output.wlr_output.backend.getRenderer().?;
@@ -76,22 +77,36 @@ pub fn renderOutput(output: *Output) void {
         renderLayer(output, output.getLayer(.background).*, &now, .toplevels);
         renderLayer(output, output.getLayer(.bottom).*, &now, .toplevels);
 
-        // The first view in the list is "on top" so iterate in reverse.
+        // The first view in the list is "on top" so always iterate in reverse.
+
+        // non-focused, non-floating views
         it = ViewStack(View).iter(output.views.last, .reverse, output.current.tags, renderFilter);
         while (it.next()) |view| {
-            // Focused views are rendered on top of normal views, skip them for now
-            if (view.current.focus != 0) continue;
+            if (view.current.focus != 0 or view.current.float) continue;
+            renderView(output, view, &now);
+            if (view.draw_borders) renderBorders(output, view, &now);
+        }
 
+        // focused, non-floating views
+        it = ViewStack(View).iter(output.views.last, .reverse, output.current.tags, renderFilter);
+        while (it.next()) |view| {
+            if (view.current.focus == 0 or view.current.float) continue;
             renderView(output, view, &now);
             if (view.draw_borders) renderBorders(output, view, &now);
         }
 
-        // Render focused views
+        // non-focused, floating views
         it = ViewStack(View).iter(output.views.last, .reverse, output.current.tags, renderFilter);
         while (it.next()) |view| {
-            // Skip unfocused views since we already rendered them
-            if (view.current.focus == 0) continue;
+            if (view.current.focus != 0 or !view.current.float) continue;
+            renderView(output, view, &now);
+            if (view.draw_borders) renderBorders(output, view, &now);
+        }
 
+        // focused, floating views
+        it = ViewStack(View).iter(output.views.last, .reverse, output.current.tags, renderFilter);
+        while (it.next()) |view| {
+            if (view.current.focus == 0 or !view.current.float) continue;
             renderView(output, view, &now);
             if (view.draw_borders) renderBorders(output, view, &now);
         }