From 83073de44c953a7152dc4bf0765ec40c0ecb388c Mon Sep 17 00:00:00 2001 From: Ville Hakulinen Date: Sat, 4 Jul 2020 22:53:27 +0300 Subject: Fix external window handling --- src/ui/grid/context.rs | 74 +++++++++++++++++++------------------------------- src/ui/grid/grid.rs | 24 ++++++++-------- src/ui/grid/row.rs | 4 +-- src/ui/state.rs | 26 +++++++++++++++++- src/ui/window.rs | 7 ++++- 5 files changed, 74 insertions(+), 61 deletions(-) diff --git a/src/ui/grid/context.rs b/src/ui/grid/context.rs index d5abef9..eb870f4 100644 --- a/src/ui/grid/context.rs +++ b/src/ui/grid/context.rs @@ -1,12 +1,8 @@ use cairo; +use gtk::prelude::*; use gtk::DrawingArea; use pango; -use gdk::prelude::*; -use gtk::prelude::*; - -use log::warn; - use crate::ui::color::{Color, Highlight, HlDefs}; use crate::ui::font::Font; use crate::ui::grid::render; @@ -69,9 +65,15 @@ impl Context { cell_metrics.line_space = line_space; cell_metrics.update(&pango_context); - let w = cell_metrics.width as usize * cols; - let h = cell_metrics.height as usize * rows; - let surface = create_surface_clamp(win, w as i32, h as i32); + let w = cell_metrics.width * cols as f64; + let h = cell_metrics.height * rows as f64; + let surface = win + .create_similar_surface( + cairo::Content::Color, + w.ceil() as i32, + h.ceil() as i32, + ) + .unwrap(); let cairo_context = cairo::Context::new(&surface); @@ -90,7 +92,7 @@ impl Context { .create_similar_surface( cairo::Content::ColorAlpha, (cell_metrics.width * 2.0) as i32, // times two for double width chars. - cell_metrics.height as i32 + cell_metrics.ascent as i32, + (cell_metrics.height + cell_metrics.ascent).ceil() as i32, ) .unwrap(); cairo::Context::new(&surface) @@ -133,9 +135,15 @@ impl Context { self.cell_metrics.update(&pctx); - let w = self.cell_metrics.width as usize * cols; - let h = self.cell_metrics.height as usize * rows; - let surface = create_surface_clamp(win, w as i32, h as i32); + let w = self.cell_metrics.width * cols as f64; + let h = self.cell_metrics.height * rows as f64; + let surface = win + .create_similar_surface( + cairo::Content::Color, + w.ceil() as i32, + h.ceil() as i32, + ) + .unwrap(); let ctx = cairo::Context::new(&surface); // Fill the context with default bg color. @@ -187,9 +195,9 @@ impl Context { let surface = win .create_similar_surface( cairo::Content::ColorAlpha, - (self.cell_metrics.width * 2.0) as i32, // times two for double width chars. - self.cell_metrics.height as i32 - + self.cell_metrics.ascent as i32, + (self.cell_metrics.width * 2.0).ceil() as i32, // times two for double width chars. + (self.cell_metrics.height + self.cell_metrics.ascent).ceil() + as i32, ) .unwrap(); cairo::Context::new(&surface) @@ -202,7 +210,11 @@ impl Context { .rows .get(self.cursor.0 as usize) .and_then(|row| { - Some(row.cell_at(self.cursor.1 as usize).double_width) + Some( + row.cell_at(self.cursor.1 as usize) + .map(|c| c.double_width) + .unwrap_or(false), + ) }) .unwrap_or(false); @@ -259,33 +271,3 @@ impl CellMetrics { f64::from(fm.get_underline_thickness()) / scale * 2.0; } } - -/// Creates a new surface from `win`. Clamps width and height to the size of `win`. -/// When clamping, warn level log messages are emitted. -fn create_surface_clamp(win: &gdk::Window, w: i32, h: i32) -> cairo::Surface { - let max_height = win.get_height(); - let max_width = win.get_width(); - - let width = if w > max_width { - warn!( - "Want to allocate surface with width {}, clamping to {}", - w, max_width - ); - max_width - } else { - w - }; - - let height = if h > max_height { - warn!( - "Want to allocate surface with height {}, clamping to {}", - h, max_height - ); - max_height - } else { - h - }; - - win.create_similar_surface(cairo::Content::Color, width, height) - .unwrap() -} diff --git a/src/ui/grid/grid.rs b/src/ui/grid/grid.rs index 3cf563e..a698cbb 100644 --- a/src/ui/grid/grid.rs +++ b/src/ui/grid/grid.rs @@ -118,22 +118,24 @@ impl Grid { // cairo context. if ctx.cursor_blink_on == 0 { if let Some(row) = ctx.rows.get(ctx.cursor.0 as usize) { - let cell = row.cell_at(ctx.cursor.1 as usize); - render::cursor_cell( - &ctx.cursor_context, - &self.da.get_pango_context().unwrap(), - &cell, - &ctx.cell_metrics, - hl_defs, - ); + if let Some(cell) = row.cell_at(ctx.cursor.1 as usize) { + render::cursor_cell( + &ctx.cursor_context, + &self.da.get_pango_context().unwrap(), + &cell, + &ctx.cell_metrics, + hl_defs, + ); + } } } // Update cursor color. if let Some(row) = ctx.rows.get(ctx.cursor.0 as usize) { - let cell = row.cell_at(ctx.cursor.1 as usize); - let hl = hl_defs.get(&cell.hl_id).unwrap(); - ctx.cursor_color = hl.foreground.unwrap_or(hl_defs.default_fg); + if let Some(cell) = row.cell_at(ctx.cursor.1 as usize) { + let hl = hl_defs.get(&cell.hl_id).unwrap(); + ctx.cursor_color = hl.foreground.unwrap_or(hl_defs.default_fg); + } } while let Some(area) = ctx.queue_draw_area.pop() { diff --git a/src/ui/grid/row.rs b/src/ui/grid/row.rs index 721e753..fa29964 100644 --- a/src/ui/grid/row.rs +++ b/src/ui/grid/row.rs @@ -53,8 +53,8 @@ impl Row { /// Returns a leaf at a position. #[inline] - pub fn cell_at(&self, at: usize) -> &Cell { - self.cells.get(at).unwrap() + pub fn cell_at(&self, at: usize) -> Option<&Cell> { + self.cells.get(at) } #[allow(unused)] // Not used currently, but tested. diff --git a/src/ui/state.rs b/src/ui/state.rs index db053e5..bbf2c56 100644 --- a/src/ui/state.rs +++ b/src/ui/state.rs @@ -160,6 +160,17 @@ impl UIState { let win = window.get_window().unwrap(); if let Some(grid) = self.grids.get(&e.grid) { grid.resize(&win, e.width, e.height, &self.hl_defs); + + // If the grid is in a window (which is likely), resize the window + // to match the grid's size. + if let Some(ref w) = + self.windows.values().find(|w| w.grid_id == grid.id) + { + let grid_metrics = grid.get_grid_metrics(); + let width = grid_metrics.cols * grid_metrics.cell_width; + let height = grid_metrics.rows * grid_metrics.cell_height; + w.resize((width.ceil() as i32, height.ceil() as i32)); + } } else { let grid = Grid::new( e.grid, @@ -625,7 +636,20 @@ impl UIState { let width = grid_metrics.cols * grid_metrics.cell_width; let height = grid_metrics.rows * grid_metrics.cell_height; - window.set_external(&parent_win, (width as i32, height as i32)); + window.set_external( + &parent_win, + (width.ceil() as i32, height.ceil() as i32), + ); + + // NOTE(ville): Without this, "new" grids (e.g. once added to a external + // window without appearing in the main grid first) won't get proper + // font/linespace values. + grid.resize( + &parent_win.get_window().unwrap(), + grid_metrics.cols as u64, + grid_metrics.rows as u64, + &self.hl_defs, + ); } fn window_hide(&mut self, grid_id: i64) { diff --git a/src/ui/window.rs b/src/ui/window.rs index 637a364..0615df9 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -101,16 +101,21 @@ impl Window { } } + pub fn resize(&self, size: (i32, i32)) { + self.frame.set_size_request(size.0, size.1); + } + pub fn set_external(&mut self, parent: >k::Window, size: (i32, i32)) { if self.external_win.is_some() { return; } + self.frame.set_size_request(size.0, size.1); + let win = gtk::Window::new(gtk::WindowType::Toplevel); self.fixed.remove(&self.frame); win.add(&self.frame); - win.set_default_size(size.0, size.1); win.set_accept_focus(false); win.set_deletable(false); win.set_resizable(false); -- cgit v1.2.3