fortrangoingonforty/fortty / 8eb0c8f

Browse files

Fix Wayland compositor timeout on inactive workspaces

- Skip rendering when window loses focus to prevent glfwSwapBuffers
from blocking on Wayland frame callbacks
- Add glfwGetWindowAttrib binding and window_is_focused() function
- Track focus state to ensure initial render and clean unfocus state
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
8eb0c8fbbbe0f2727ac071ba13586c53ecf9b269
Parents
11fd979
Tree
cd92a27

3 changed files

StatusFile+-
M src/fortty.f90 13 2
M src/window/glfw_bindings.f90 13 0
M src/window/window.f90 10 0
src/fortty.f90modified
@@ -40,6 +40,7 @@ program fortty
4040
   integer :: cell_width, cell_height, ascender  ! From font metrics
4141
   real(8) :: current_time, last_time, blink_timer
4242
   logical :: cursor_blink_visible, any_pty_alive
43
+  logical :: was_focused, is_focused
4344
   type(selection_t) :: sel
4445
   integer :: font_delta, new_font_size, base_font_size
4546
   character(len=256) :: font_path_saved, fallback_path_saved
@@ -236,6 +237,9 @@ program fortty
236237
   blink_timer = 0.0d0
237238
   cursor_blink_visible = .true.
238239
 
240
+  ! Initialize focus tracking (assume focused initially to ensure first render)
241
+  was_focused = .true.
242
+
239243
   ! Main event loop - exit when window closes or all tabs closed
240244
   any_pty_alive = tab_manager_has_tabs(tab_mgr)
241245
   do while (.not. window_should_close(win) .and. any_pty_alive)
@@ -416,8 +420,15 @@ program fortty
416420
       end if
417421
     end if
418422
 
419
-    ! Render and swap
420
-    call do_render()
423
+    ! Render and swap - but only if window has focus or just regained focus
424
+    ! On Wayland, glfwSwapBuffers blocks waiting for frame callbacks when
425
+    ! the window is on an inactive workspace, causing compositor timeout.
426
+    ! Skip rendering when unfocused to keep event loop responsive.
427
+    is_focused = window_is_focused(win)
428
+    if (is_focused .or. was_focused) then
429
+      call do_render()
430
+    end if
431
+    was_focused = is_focused
421432
   end do
422433
 
423434
   ! Cleanup
src/window/glfw_bindings.f90modified
@@ -16,6 +16,11 @@ module glfw_bindings
1616
   integer(c_int), parameter :: GLFW_OPENGL_FORWARD_COMPAT = int(Z'00022006', c_int)
1717
   integer(c_int), parameter :: GLFW_TRANSPARENT_FRAMEBUFFER = int(Z'0002000A', c_int)
1818
 
19
+  ! Window attributes (for glfwGetWindowAttrib)
20
+  integer(c_int), parameter :: GLFW_FOCUSED = int(Z'00020001', c_int)
21
+  integer(c_int), parameter :: GLFW_ICONIFIED = int(Z'00020002', c_int)
22
+  integer(c_int), parameter :: GLFW_VISIBLE = int(Z'00020004', c_int)
23
+
1924
   ! Key constants
2025
   integer(c_int), parameter :: GLFW_KEY_ESCAPE = 256
2126
   integer(c_int), parameter :: GLFW_KEY_ENTER = 257
@@ -351,6 +356,14 @@ module glfw_bindings
351356
       type(c_ptr), value :: window
352357
       type(c_funptr), value :: callback
353358
     end function glfwSetWindowRefreshCallback
359
+
360
+    ! int glfwGetWindowAttrib(GLFWwindow* window, int attrib)
361
+    integer(c_int) function glfwGetWindowAttrib(window, attrib) &
362
+        bind(C, name="glfwGetWindowAttrib")
363
+      import :: c_ptr, c_int
364
+      type(c_ptr), value :: window
365
+      integer(c_int), value :: attrib
366
+    end function glfwGetWindowAttrib
354367
   end interface
355368
 
356369
 end module glfw_bindings
src/window/window.f90modified
@@ -19,6 +19,7 @@ module window_mod
1919
   public :: window_set_render_callback, window_is_resizing
2020
   public :: window_get_tab_action, window_clear_tab_action
2121
   public :: window_get_pane_action, window_clear_pane_action
22
+  public :: window_is_focused
2223
 
2324
   ! Tab action constants
2425
   integer, parameter, public :: TAB_ACTION_NONE = 0
@@ -189,6 +190,15 @@ contains
189190
     should = glfwWindowShouldClose(win%handle) /= GLFW_FALSE
190191
   end function window_should_close
191192
 
193
+  ! Check if window has focus - used to skip rendering on Wayland when
194
+  ! window is on inactive workspace (prevents compositor timeout)
195
+  function window_is_focused(win) result(focused)
196
+    type(window_t), intent(in) :: win
197
+    logical :: focused
198
+
199
+    focused = glfwGetWindowAttrib(win%handle, GLFW_FOCUSED) /= GLFW_FALSE
200
+  end function window_is_focused
201
+
192202
   subroutine window_swap_buffers(win)
193203
     type(window_t), intent(in) :: win
194204