Implement floating views
This commit is contained in:
		| @ -29,3 +29,4 @@ pub usingnamespace @import("command/spawn.zig"); | ||||
| pub usingnamespace @import("command/toggle_tags.zig"); | ||||
| pub usingnamespace @import("command/toggle_view_tags.zig"); | ||||
| pub usingnamespace @import("command/zoom.zig"); | ||||
| pub usingnamespace @import("command/toggle_float.zig"); | ||||
|  | ||||
							
								
								
									
										13
									
								
								src/command/toggle_float.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/command/toggle_float.zig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| const c = @import("../c.zig"); | ||||
|  | ||||
| const Arg = @import("../command.zig").Arg; | ||||
| const Seat = @import("../seat.zig").Seat; | ||||
|  | ||||
| /// Make the focused view float or stop floating, depending on its current | ||||
| /// state. | ||||
| pub fn toggleFloat(seat: *Seat, arg: Arg) void { | ||||
|     if (seat.focused_view) |view| { | ||||
|         view.setFloating(!view.floating); | ||||
|         view.output.root.arrange(); | ||||
|     } | ||||
| } | ||||
| @ -189,5 +189,13 @@ pub const Config = struct { | ||||
|             .command = command.sendToOutput, | ||||
|             .arg = .{ .direction = .Prev }, | ||||
|         }); | ||||
|  | ||||
|         // Mod+Space to toggle float | ||||
|         try self.keybinds.append(Keybind{ | ||||
|             .keysym = c.XKB_KEY_space, | ||||
|             .modifiers = mod, | ||||
|             .command = command.toggleFloat, | ||||
|             .arg = .{ .none = {} }, | ||||
|         }); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| @ -148,7 +148,12 @@ pub const Output = struct { | ||||
|         const visible_count = blk: { | ||||
|             var count: u32 = 0; | ||||
|             var it = ViewStack(View).pendingIterator(self.views.first, output_tags); | ||||
|             while (it.next() != null) count += 1; | ||||
|             while (it.next()) |node| { | ||||
|                 if (node.view.floating) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 count += 1; | ||||
|             } | ||||
|             break :blk count; | ||||
|         }; | ||||
|  | ||||
| @ -178,6 +183,9 @@ pub const Output = struct { | ||||
|         var it = ViewStack(View).pendingIterator(self.views.first, output_tags); | ||||
|         while (it.next()) |node| { | ||||
|             const view = &node.view; | ||||
|             if (view.floating) { | ||||
|                 continue; | ||||
|             } | ||||
|             if (i < master_count) { | ||||
|                 // Add the remainder to the first master to ensure every pixel of height is used | ||||
|                 const master_height = @divTrunc(layout_height, master_count); | ||||
|  | ||||
| @ -39,6 +39,26 @@ pub fn renderOutput(output: *Output) void { | ||||
|         if (view.current_box.width == 0 or view.current_box.height == 0) { | ||||
|             continue; | ||||
|         } | ||||
|         // Floating views are rendered on top of normal views | ||||
|         if (view.floating) { | ||||
|             continue; | ||||
|         } | ||||
|         renderView(output.*, view, &now); | ||||
|         renderBorders(output.*, view, &now); | ||||
|     } | ||||
|  | ||||
|     // Render floating views | ||||
|     it = ViewStack(View).reverseIterator(output.views.last, output.current_focused_tags); | ||||
|     while (it.next()) |node| { | ||||
|         const view = &node.view; | ||||
|         // This check prevents a race condition when a frame is requested | ||||
|         // between mapping of a view and the first configure being handled. | ||||
|         if (view.current_box.width == 0 or view.current_box.height == 0) { | ||||
|             continue; | ||||
|         } | ||||
|         if (!view.floating) { | ||||
|             continue; | ||||
|         } | ||||
|         renderView(output.*, view, &now); | ||||
|         renderBorders(output.*, view, &now); | ||||
|     } | ||||
|  | ||||
							
								
								
									
										32
									
								
								src/view.zig
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/view.zig
									
									
									
									
									
								
							| @ -14,9 +14,16 @@ pub const View = struct { | ||||
|  | ||||
|     mapped: bool, | ||||
|  | ||||
|     /// If the view is floating or not | ||||
|     floating: bool, | ||||
|  | ||||
|     current_box: Box, | ||||
|     pending_box: ?Box, | ||||
|  | ||||
|     /// The dimensions the view would have taken if we didn't force it to tile | ||||
|     natural_width: u32, | ||||
|     natural_height: u32, | ||||
|  | ||||
|     current_tags: u32, | ||||
|     pending_tags: ?u32, | ||||
|  | ||||
| @ -122,6 +129,22 @@ pub const View = struct { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// If true is passsed, make the view float. If false, return it to the tiled | ||||
|     /// layout. | ||||
|     pub fn setFloating(self: *Self, float: bool) void { | ||||
|         if (float and !self.floating) { | ||||
|             self.floating = true; | ||||
|             self.pending_box = Box{ | ||||
|                 .x = @intCast(i32, (self.output.usable_box.width - self.natural_width) / 2), | ||||
|                 .y = @intCast(i32, (self.output.usable_box.height - self.natural_height) / 2), | ||||
|                 .width = self.natural_width, | ||||
|                 .height = self.natural_height, | ||||
|             }; | ||||
|         } else if (!float and self.floating) { | ||||
|             self.floating = false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Move a view from one output to another, sending the required enter/leave | ||||
|     /// events. | ||||
|     pub fn sendToOutput(self: *Self, destination_output: *Output) void { | ||||
| @ -161,6 +184,15 @@ pub const View = struct { | ||||
|         c.wl_signal_add(&self.wlr_xdg_surface.surface.*.events.commit, &self.listen_commit); | ||||
|  | ||||
|         self.mapped = true; | ||||
|         self.floating = false; | ||||
|  | ||||
|         self.natural_width = @intCast(u32, self.wlr_xdg_surface.geometry.width); | ||||
|         self.natural_height = @intCast(u32, self.wlr_xdg_surface.geometry.height); | ||||
|  | ||||
|         if (self.natural_width == 0 and self.natural_height == 0) { | ||||
|             self.natural_width = @intCast(u32, self.wlr_xdg_surface.surface.*.current.width); | ||||
|             self.natural_height = @intCast(u32, self.wlr_xdg_surface.surface.*.current.height); | ||||
|         } | ||||
|  | ||||
|         // Focus the newly mapped view. Note: if a seat is focusing a different output | ||||
|         // it will continue to do so. | ||||
|  | ||||
		Reference in New Issue
	
	Block a user