Skip to content

fix(linux): hacer que el widget sea visible en todos los escritorios virtuales (paridad con macOS) #227

Open

Description

@Rafaeldelinares

Contexto y motivación

Quorb está concebido como una tira de estado y control continua. En Linux, al cambiar de escritorio virtual (workspaces en KDE Plasma, GNOME, etc.), la tira desaparece porque el gestor de ventanas la confina al escritorio donde se inició el proceso.

En #112 se incorporó set_visible_on_all_workspaces(true) en src-tauri/src/lib.rs:1083 con un gate #[cfg(target_os = "macos")] bajo la asunción de que en Linux bastaba con always_on_top («Windows/Linux have no Spaces and always-on-top already covers it»).

Sin embargo, en Linux (X11 / KDE / GNOME) always_on_top (_NET_WM_STATE_ABOVE) solo mantiene la ventana flotando por encima dentro del mismo escritorio virtual, pero no acompaña al usuario al cambiar de workspace. Para acompañar entre escritorios se requiere declarar la ventana como sticky (_NET_WM_STATE_STICKY / _NET_WM_DESKTOP = 0xFFFFFFFF).

Diagnóstico técnico

En el motor de ventanas de Quorb (tao 0.37.1), set_visible_on_all_workspaces(true) ya está plenamente implementado para Linux (tao/src/platform_impl/linux/window.rs:762 y event_loop.rs:424):

WindowRequest::SetVisibleOnAllWorkspaces(visible) => {
    if visible {
        window.stick();
    } else {
        window.unstick();
    }
}

La llamada a window.stick() de GTK envía al gestor de ventanas los mensajes EWMH oficiales para que la ventana se proyecte en todos los escritorios.

Alcance propuesto (Centrado en Linux)

Nos centramos exclusivamente en implementar y verificar esta paridad en Linux:

  1. Linux (X11 / XWayland):
    • Ampliar el gate en src-tauri/src/lib.rs:
      #[cfg(any(target_os = "macos", target_os = "linux"))]
      for label in [WIDGET, DETAIL, OVERLAY] {
          if let Some(w) = app.get_webview_window(label) {
              if let Err(e) = w.set_visible_on_all_workspaces(true) {
                  eprintln!("No pude marcar «{label}» visible en todos los escritorios: {e}");
              }
          }
      }
    • Otorga paridad inmediata con macOS sin dependencias nuevas ni cambios en la capa de frontend.
  2. Linux (Wayland nativo):
    • xdg-shell por diseño no ofrece a clientes regulares una petición para declararse sticky sin protocolos privilegiados de compositor (wlr-layer-shell). Con el camino X11/XWayland (GDK_BACKEND=x11), queda cubierto en el entorno operativo de Linux.

Pregunta para el mantenedor / Decisión de producto

¿Preferís que este comportamiento sea predeterminado e inherente al widget (igual que en macOS desde #112), o considerás necesario que esté sujeto a un interruptor en Ajustes (ej. Ajustes > Comportamiento > Mostrar en todos los escritorios virtuales)?

Abrimos el hilo para acordar la dirección antes de preparar la PR.

Activity

  1. egdev6 commented on Nov 1, 2026

    @egdev6
    Owner

    Gracias por el análisis, @Rafaeldelinares. Lo revisé contra main y el diagnóstico es correcto: en src-tauri/src/lib.rs:1083 el marcado como visible en todos los escritorios solo se aplica en macOS, y el comentario de lib.rs:1036-1041 asume que en Linux basta con mantener la ventana siempre encima, que no la hace acompañar al cambiar de escritorio. En tao 0.37.1 la llamada en Linux usa gtk::Window::stick(), que también funciona antes de que la ventana tenga GdkWindow, así que no debería repetir el problema de set_ignore_cursor_events. En Wayland nativo no tendrá efecto, como indicas; queda cubierto el camino X11/XWayland.

    Sobre la decisión de producto: prefiero que sea el comportamiento predeterminado, sin opción en Ajustes, igual que en macOS desde #112. Una tira de estado que desaparece al cambiar de escritorio va contra su propósito. Si más adelante alguien necesita desactivarlo, se puede valorar entonces una opción.

    Para la PR, además de ampliar el gate a Linux:

    • Actualizar el comentario de lib.rs:1036-1041 y el mensaje de error, que menciona Spaces.
    • Probar manualmente en KDE y GNOME con X11/XWayland: comprobar _NET_WM_STATE_STICKY con xprop y cambiar de escritorio con el panel transitorio, el panel anclado y el overlay.

    Adelante con la PR cuando quieras. ¡Gracias!

  2. Rafaeldelinares commented on Nov 8, 2026

    @Rafaeldelinares
    ContributorAuthor

    @egdev6 Fui a hacer la validación manual que pediste y antes que nada te debo una corrección sobre la PR #232: escribí que "al alternar entre escritorios virtuales (KDE Plasma 6 / X11) la tira permanece fija y visible", y eso no estaba medido. Solo había comprobado con xprop que quedaba _NET_WM_STATE_STICKY. Midiendo el cambio de escritorio de verdad, en KDE Plasma con XWayland la tira no acompaña. Perdón por haberte hecho integrar con esa afirmación.

    Lo bueno es que encontré la causa, que no está en Quorb, y probé una salida. Te dejo todo con evidencia para que decidas.

    Entorno: CachyOS (kernel 7.2.4-3-cachyos), KDE Plasma 6.7.5 / KWin 6.7.5 en sesión Wayland con 3 escritorios, Quorb main 79ee3cd (incluye #232 y #223) con GDK_BACKEND=x11, GTK 3.24.52. El cambio de escritorio lo hago por D-Bus (org.kde.KWin.setCurrentDesktop) y el estado lo leo de KWin (onAllDesktops) y con xprop.

    1. Lo que pasa hoy en main

    comprobación resultado
    _NET_WM_STATE de la tira incluye _NET_WM_STATE_STICKY
    _NET_WM_DESKTOP 0 (no 0xFFFFFFFF)
    KWin onAllDesktops false, solo en "Escritorio 1" (3/3 arranques)
    reglas de ventana de KWin ninguna (kwinrulesrc vacío)

    main sin script: la tira en el escritorio 1 y ausente en el escritorio 2

    2. La causa: KWin ignora a propósito los escritorios de los clientes X11

    El commit de KWin 55fd1912 ("Provide fake virtual desktop information to X clients", septiembre de 2025) pone esa información detrás de KWIN_XWAYLAND_ENABLE_NETWM_DESKTOP=1, que por defecto no está definida:

    If the KWIN_XWAYLAND_ENABLE_NETWM_DESKTOP=1 environment variable is not set, kwin will report a 1x1 desktop grid, windows will be told that they are on a single desktop.

    En ese modo WinInfo::changeDesktop() descarta los pedidos de los clientes, incluido "todos los escritorios". En esta máquina se ve directamente: con 3 escritorios reales, XWayland recibe _NET_NUMBER_OF_DESKTOPS = 1 y _NET_DESKTOP_NAMES = "Desktop 1".

    Para descartar que fuera algo de Quorb o de cuándo se llama a stick(), lo repetí con una ventana GTK3 mínima:

    variante KWin onAllDesktops
    A. stick() antes de show() (lo que hace Quorb vía tao) false
    B. stick() con la ventana ya mapeada false
    C. A + siempre encima, sin barra de tareas y sin decoración false
    D. mensaje _NET_WM_DESKTOP = 0xFFFFFFFF con la ventana mapeada false
    E. el mismo mensaje antes de show() false
    F. control: siempre encima con la ventana mapeada se aplica

    KWin atiende otros pedidos del cliente (F), pero ningún pedido de escritorio. Así que el código de #232 es correcto según EWMH y seguirá sirviendo en gestores X11 que lo respeten. En KWin con XWayland no alcanza.

    3. Prototipo: marcar las ventanas desde KWin

    Como prueba de concepto, sin tocar Quorb, cargué en KWin por D-Bus (org.kde.kwin.Scripting.loadScript) un script que pone onAllDesktops = true en las ventanas de Quorb, también en las que se crean después:

    Script de KWin del prototipo
    function apply(w) {
      if (!/quorb/i.test(String(w.resourceClass) + " " + String(w.resourceName))) return;
      w.onAllDesktops = true;
    }
    workspace.windowList().forEach(apply);
    workspace.windowAdded.connect(apply);

    Con eso se cumplen los tres casos que pediste. En todas las capturas KWin reporta onAllDesktops: true estando en el escritorio 2:

    con script: la tira en los escritorios 1, 2 y 3

    con script: panel de detalle transitorio y anclado en el escritorio 2

    con script: overlay de confeti en el escritorio 2

    Un detalle del prototipo: también marcó Ajustes, porque filtra por clase. Una versión real tendría que limitarse a la tira, el detalle y el overlay, igual que el gate de #232.

    Opciones que veo

    1. Documentar el workaround: definir KWIN_XWAYLAND_ENABLE_NETWM_DESKTOP=1 en el entorno de Plasma y volver a iniciar sesión. No requiere código. No lo probé porque implica reiniciar la sesión.
    2. Pedírselo a KWin desde Quorb cuando la sesión es KDE, con un script como el del prototipo. Funciona sin que el usuario haga nada, pero es específico de KDE y supone que la app cargue un script en el compositor. Esa decisión de diseño es tuya.
    3. Wayland nativo: no hay un protocolo estándar para "todos los escritorios" (ver KDE 460873). La única vía sería layer-shell, que cambia la arquitectura. Lo veo fuera de alcance.

    Sin validar: una sesión Plasma X11 real (esta máquina no la tiene instalada) y GNOME.

    ¿Cuál de estas vías preferís? Si te sirve, pruebo la 1 y te traigo el resultado antes de que decidas.

  3. egdev6 commented on Nov 9, 2026

    @egdev6
    Owner

    Gracias por corregir la validación y por investigar con tanto detalle, @Rafaeldelinares.

    El cambio de #232 ya solicita la visibilidad para la tira, el detalle y el overlay en src-tauri/src/lib.rs:1131-1136, pero tu prueba muestra que eso no basta en KWin/XWayland. Además, _NET_WM_STATE_STICKY por sí solo no acredita que la ventana esté en todos los escritorios.

    He comprobado que KWin eliminó la variable KWIN_XWAYLAND_ENABLE_NETWM_DESKTOP en este cambio, incluido en el upstream de 6.7.5. Salvo que CachyOS la haya recuperado con un parche, no esperaría que funcione, así que no hace falta reiniciar la sesión para probarla.

    Por ahora prefiero no cargar scripts automáticamente en el compositor. Mantengamos la issue abierta y el comportamiento predeterminado acordado. ¿Podrías probar, si te resulta posible, una regla de KWin creada por el usuario y comprobar si permite seleccionar solo la tira, el detalle y el overlay, sin afectar a Ajustes? La validación sería cambiar realmente de escritorio con el detalle transitorio y anclado y el overlay, comprobando onAllDesktops. Plasma X11 y GNOME quedan pendientes para cuando haya un entorno disponible.

    Gracias de nuevo por la transparencia y las pruebas.

  4. added a commit that references this issue on Nov 10, 2026
  5. Rafaeldelinares commented on Nov 10, 2026

    @Rafaeldelinares
    ContributorAuthor

    @egdev6 Tienes razón con la variable: la di por buena porque vi el commit que la introducía y no busqué si después la habían quitado. En esta máquina lo confirmé: KWIN_XWAYLAND_ENABLE_NETWM_DESKTOP no aparece en libkwin.so.6.7.5 ni en kwin_wayland. Gracias por revisarlo.

    Probé la regla de KWin creada por el usuario. Con el título se puede seleccionar solo la tira, el detalle y el overlay, sin tocar Ajustes, y funciona sin cargar nada en el compositor.

    Entorno: CachyOS, KDE Plasma 6.7.5 / KWin 6.7.5 en sesión Wayland con 3 escritorios, Quorb main 79ee3cd con GDK_BACKEND=x11. Cambio de escritorio real por D-Bus (org.kde.KWin.setCurrentDesktop), estado leído de KWin (onAllDesktops). Cada captura incluye el paginador de Plasma para que se vea qué escritorio está activo. Fuera de la prueba, la configuración de reglas de la máquina quedó como estaba.

    La regla

    wmclass=[Qq]uorb
    wmclassmatch=3          # expresión regular
    wmclasscomplete=false
    title=^Quorb( · .+)?$
    titlematch=3            # expresión regular
    desktops=\0
    desktopsrule=2          # forzar: todos los escritorios

    En la interfaz equivale a Preferencias del sistema → Gestión de ventanas → Reglas de ventanas: clase de ventana [Qq]uorb (expresión regular), título ^Quorb( · .+)?$ (expresión regular) y Escritorio virtual: Forzar → Todos los escritorios.

    Dos detalles que encontré al armarla:

    • La clase distingue mayúsculas. Con quorb como subcadena la regla no se aplicaba, porque KWin ve la clase como Quorb…. Por eso uso [Qq]uorb.
    • El título funciona en los dos idiomas. La tira, el detalle y el overlay empiezan por el nombre de la app (Quorb, Quorb · detalle/details, Quorb · efectos/effects, según i18n.rs). Ajustes empieza por la palabra traducida (Ajustes · Quorb/Settings · Quorb), así que queda fuera. Las ventanas no exponen WM_WINDOW_ROLE, por lo que el título es lo más estable que hay.

    Resultados

    caso cambio de escritorio resultado
    solo afecta a Quorb — ✅ ninguna otra ventana quedó en todos los escritorios
    tira — ✅ onAllDesktops: true
    detalle transitorio (hover) 2 → 3 ✅ acompaña, onAllDesktops: true
    detalle anclado (clic) 1 → 2 ✅ en 2 de 3 corridas (ver abajo)
    overlay 2 → 3 ✅ según KWin en 1 de 3 corridas (ver abajo)
    Ajustes no afectado 2 → 3 y 1 → 2 ✅ onAllDesktops: false en las 3 corridas, se queda en su escritorio

    regla: detalle transitorio acompaña del escritorio 2 al 3

    regla: detalle anclado acompaña del escritorio 1 al 2

    regla: Ajustes se queda en el escritorio 2 mientras la tira y el detalle pasan al 3

    Lo que no quedó limpio

    • Detalle anclado, 1 de 3 corridas. En la primera (2 → 3), al llegar al escritorio de destino el panel ya no estaba y KWin dejó de listar la ventana, es decir, se ocultó y no se quedó en el otro escritorio. En las otras dos (1 → 2), sin tocar nada durante el cambio, se mantuvo y la zona del panel salió idéntica píxel a píxel antes y después. No sé si en esa primera hubo alguna interacción o si Quorb lo cerró por otro motivo.
    • Overlay sin foto. En la primera corrida KWin listaba Quorb · efectos con onAllDesktops: true ya en el escritorio de destino. En las otras dos el efecto terminó antes de que llegara a medirlo: el confeti dura 4,2 s (DURATION en Overlay.tsx) y cada captura tarda alrededor de un segundo. Por eso no tengo foto del confeti con la regla. Podría conseguirla con un efecto propio en vídeo más largo, si te parece necesario.

    Plasma X11 y GNOME siguen pendientes, como dijiste.

    ¿Quieres que la regla se documente en docs/build-linux.md como el camino para KDE en XWayland, o prefieres dejarla registrada solo aquí por ahora?

  6. egdev6 commented on Nov 10, 2026

    @egdev6
    Owner

    @Rafaeldelinares, gracias por la actualización y por distinguir lo observado de lo que no llegó a medirse. La regla aporta evidencia útil como workaround manual para CachyOS con Plasma/KWin 6.7.5 en Wayland y Quorb vía XWayland, no como solución general para KDE o Linux. Mantendría la issue abierta.

    Los resultados que aportas apoyan el seguimiento del detalle transitorio y la exclusión de Ajustes. La desaparición del anclado en una corrida sigue sin causa identificada. En el overlay, las otras dos corridas terminaron antes de medirlo: no las contaría como dos fallos de visibilidad. Plasma X11 y GNOME siguen sin validar.

    Antes de decidir su incorporación a docs/build-linux.md, queda un matiz del alcance: el selector inicial de idioma también se crea con título Quorb (src-tauri/src/lib.rs:1031–1034). Confirmé que ese título coincide con ^Quorb( · .+)?$, igual que los títulos ES/EN de tira, detalle y overlay; Ajustes queda fuera. Si el selector comparte la clase que ve KWin, la regla también podría afectarlo. ¿Puedes comprobar su clase y si la regla lo alcanza, cuando sea posible sin alterar tu configuración habitual?

    La propuesta de documentación es razonable si se presenta como regla optativa creada por el usuario, con el entorno probado y estas limitaciones explícitas, sin afirmar que solo afecta a tres ventanas hasta aclarar el selector. No implica cargar scripts automáticamente ni recuperar la variable eliminada. La decisión de incorporarla queda pendiente; no doy por resuelta la issue. Esta revisión contrastó el código y la expresión de títulos, no repitió las pruebas reales de KWin ni verificó visualmente las capturas.

  7. added a commit that references this issue on Nov 10, 2026
  8. Rafaeldelinares commented on Nov 10, 2026

    @Rafaeldelinares
    ContributorAuthor

    @egdev6 Lo comprobé y tenías razón: la regla también alcanza al selector de idioma del primer arranque. Corrijo lo que escribí en el comentario anterior: no selecciona "solo la tira, el detalle y el overlay". Ajustes sí queda fuera.

    Entorno: el mismo de antes (CachyOS, KDE Plasma 6.7.5 / KWin 6.7.5 en Wayland, Quorb main 79ee3cd con GDK_BACKEND=x11). Para forzar el primer arranque sin tocar mi configuración, lancé Quorb con XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_CACHE_HOME y XDG_STATE_HOME apuntando a un directorio temporal, que borré al terminar. La regla la puse solo durante la prueba y después restauré la configuración de KWin.

    comprobación resultado
    clase (WM_CLASS) quorb-79ee3cd / Quorb-79ee3cd, la misma que la tira, el detalle y el overlay
    título Quorb, coincide con ^Quorb( · .+)?$
    tipo y tamaño _NET_WM_WINDOW_TYPE_NORMAL, 420×268 con decoraciones
    sin la regla onAllDesktops: false
    con la regla onAllDesktops: true, y acompaña al cambiar del escritorio 1 al 2

    En ese momento el selector es la única ventana de Quorb; la tira todavía no existe.

    la regla alcanza al selector de idioma: visible en el escritorio 1 y en el 2

    Con la clase y el título actuales, la regla no puede distinguir el selector: las ventanas no exponen WM_WINDOW_ROLE y el selector comparte clase y título con la tira. Veo dos formas de tratarlo:

    1. Documentarlo como limitación: la regla también afecta al selector de idioma, que solo aparece en el primer arranque en Linux. No requiere código.
    2. Dar al selector un título propio (por ejemplo Quorb · idioma, o uno neutro, porque se muestra antes de elegir idioma) y ajustar la expresión para excluirlo. Es un cambio pequeño en open_locale_picker.

    ¿Cuál prefieres? Si vas por la documentación, la redactaría como regla optativa creada por el usuario, con el entorno probado y estas limitaciones explícitas, como indicaste.

  9. egdev6 commented on Nov 11, 2026

    @egdev6
    Owner

    @Rafaeldelinares gracias por comprobarlo y por corregir el alcance, quedó muy claro.

    Vamos por la opción 2: un título propio para el selector de idioma y una expresión que lo excluya. Un detalle: con un título como Quorb · idioma, la expresión actual ^Quorb( · .+)?$ lo seguiría seleccionando, así que hacen falta los dos cambios juntos (el título en open_locale_picker y la expresión documentada). Como el selector aparece antes de elegir idioma, conviene un título que no dependa de la traducción, para que la expresión sea estable.

    En docs/build-linux.md, presentá la regla como optativa y creada por el usuario, con el entorno probado (CachyOS, Plasma/KWin 6.7.5 en Wayland, Quorb por XWayland) y las limitaciones medidas: el detalle anclado desapareció en una de tres pruebas, el overlay solo se pudo medir en una, y Plasma X11 y GNOME no están verificados. La issue sigue abierta, porque es un apaño manual y no un arreglo general.

  10. Rafaeldelinares commented on Nov 11, 2026

    @Rafaeldelinares
    ContributorAuthor

    @egdev6 Perfecto, vamos con la opción 2. ¿Me asignas #227? Lo implemento en cuanto lo vea asignado. Este es el plan, por si quieres ajustar algo antes:

    Título del selector (open_locale_picker, hoy .title("Quorb") en src-tauri/src/lib.rs:1061): propongo Idioma / Language · {canal}, un texto fijo y bilingüe que no pasa por la traducción. Sigue el mismo patrón que Ajustes (Ajustes · Quorb): primero la palabra y al final el nombre de la app. Así la expresión que empieza por el nombre de la app lo excluye, y no hay que tocarla si mañana se añade otro idioma. La alternativa sería enumerar en la expresión los títulos traducidos del detalle y del overlay (detalle|details|efectos|effects), pero cada idioma nuevo obligaría a actualizar la documentación.

    Expresión documentada: al revisarlo encontré que el canal Beta titula las ventanas Quorb Beta, Quorb Beta · detalle, etc. (locale_relabel en lib.rs), así que ^Quorb( · .+)?$ no lo cubre. Documentaría ^Quorb( Beta)?( · .+)?$, que deja fuera a Ajustes y al selector en los dos canales.

    Código: el título como constante, con un test que comprueba que no empieza por el nombre del canal, para que la regla documentada no pueda volver a alcanzarlo sin que falle un test. Como cambia un texto visible, regeneraré el inventario i18n después del commit del código.

    Documentación (docs/build-linux.md): la regla como optativa y creada por el usuario, en formato de archivo y con los pasos en Preferencias del sistema, con el entorno probado (CachyOS, Plasma/KWin 6.7.5 en Wayland, Quorb por XWayland) y las limitaciones medidas: el anclado desapareció en una de tres pruebas, el overlay solo se pudo medir en una, y Plasma X11 y GNOME no están verificados. Dejaré claro que es un apaño manual y no un arreglo general.

    Validación: repetiré la medición del selector con la regla y la configuración aislada, comprobando que queda con onAllDesktops: false, además de una pasada rápida de tira, detalle y Ajustes. Todo irá con capturas en la PR.

  11. egdev6 commented on Nov 11, 2026

    @egdev6
    Owner

    @Rafaeldelinares te asigno #227. El plan está bien encaminado; algunos ajustes antes de empezar:

    • Solo canal estable. En main no existe un canal Beta: channel.rs define únicamente el perfil estable y rechaza cualquier otro identificador. Quorb Beta solo aparece como dato de prueba en el test de locale_relabel. Documenta la regla para el canal estable, sin el ( Beta)?, para no describir un caso que no se puede compilar ni medir.
    • Título del selector. Idioma / Language · Quorb me parece bien: es fijo, no depende de la traducción y deja fuera al selector con la expresión actual ^Quorb( · .+)?$. Ten en cuenta que esa expresión no se vuelve más estricta; el selector queda fuera porque su título deja de empezar por Quorb. Así conviene explicarlo en la documentación.
    • Test. En lugar de comprobar solo que el título no empieza por el nombre del canal, prefiero un test que use la expresión documentada y la compruebe contra la tabla completa de títulos: debe coincidir con la tira, el detalle y el overlay en ES/EN, y no con Ajustes ni con el selector. Así, si alguien cambia la regla o un título, falla el test.

    La documentación y la nueva medición, como propones: regla optativa creada por el usuario, entorno probado y limitaciones medidas. La issue se mantiene abierta como apaño manual, no como arreglo general.

  12. added a commit that references this issue on Nov 11, 2026
  13. added a commit that references this issue on Nov 11, 2026
  14. added a commit that references this issue on Nov 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions