phase 3: multi-output support — handle all wlr_outputs (not just first), per-output scene_output/bg_rect/frame_listener, refresh heads on hotplug
This commit is contained in:
parent
3fc416a9b6
commit
b33774db14
|
|
@ -576,6 +576,8 @@ wl_display_open(const char *name)
|
|||
wl_list_init(&wl_state.or_list);
|
||||
wl_list_init(&wl_state.frame_list);
|
||||
wl_list_init(&wl_state.layer_list);
|
||||
wl_list_init(&wl_state.outputs);
|
||||
wl_state.output_count = 0;
|
||||
{
|
||||
int ki;
|
||||
for (ki = 0; ki < 3; ki++)
|
||||
|
|
@ -834,7 +836,6 @@ wl_display_close(void)
|
|||
do { if ((l).link.next) wl_list_remove(&(l).link); } while (0)
|
||||
|
||||
/* Output frame and new-output listeners */
|
||||
WL_LISTENER_REMOVE(wl_state.output_frame_listener);
|
||||
WL_LISTENER_REMOVE(wl_state.backend_new_output_listener);
|
||||
/* XDG shell and decoration listeners */
|
||||
WL_LISTENER_REMOVE(wl_state.xdg_new_surface_listener);
|
||||
|
|
@ -911,10 +912,18 @@ wl_display_close(void)
|
|||
wl_state.headless_inner = NULL;
|
||||
wl_state.wl_backend_inner = NULL;
|
||||
wl_state.display = NULL;
|
||||
/* Clean up per-output state */
|
||||
{
|
||||
struct wl_wlr_output_state *ost, *tmp;
|
||||
wl_list_for_each_safe(ost, tmp, &wl_state.outputs, link) {
|
||||
wl_list_remove(&ost->link);
|
||||
wfree(ost);
|
||||
}
|
||||
}
|
||||
wl_state.output_count = 0;
|
||||
wl_state.output = NULL;
|
||||
wl_state.frame_timer = NULL;
|
||||
wl_state.output_layout = NULL;
|
||||
wl_state.scene_output = NULL;
|
||||
wl_state.scene = NULL;
|
||||
wl_state.allocator = NULL;
|
||||
wl_state.started = 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
|
|
@ -13,6 +14,9 @@
|
|||
#include <wlr/backend/wayland.h>
|
||||
#include "wl_types.h"
|
||||
|
||||
/* Forward declaration for screen head refresh */
|
||||
extern void wl_screen_refresh_heads(WScreen *scr);
|
||||
|
||||
|
||||
void
|
||||
handle_output_frame(struct wl_listener *listener, void *data)
|
||||
|
|
@ -22,19 +26,24 @@ handle_output_frame(struct wl_listener *listener, void *data)
|
|||
return;
|
||||
if (wl_state.session && !wl_state.session->active)
|
||||
return;
|
||||
if (!wl_state.scene_output)
|
||||
|
||||
/* Find the per-output state for this frame listener */
|
||||
struct wl_wlr_output_state *ost =
|
||||
wl_container_of(listener, ost, frame_listener);
|
||||
if (!ost || !ost->scene_output)
|
||||
return;
|
||||
|
||||
static int frame_count = 0;
|
||||
++frame_count;
|
||||
if (wl_state.allocator) {
|
||||
wlr_scene_output_commit(wl_state.scene_output, NULL);
|
||||
wlr_scene_output_commit(ost->scene_output, NULL);
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_scene_output_send_frame_done(wl_state.scene_output, &now);
|
||||
wlr_scene_output_send_frame_done(ost->scene_output, &now);
|
||||
} else {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_scene_output_send_frame_done(wl_state.scene_output, &now);
|
||||
wlr_scene_output_send_frame_done(ost->scene_output, &now);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,10 +57,9 @@ handle_backend_new_output(struct wl_listener *listener, void *data)
|
|||
struct wlr_output *output = data;
|
||||
(void)listener;
|
||||
|
||||
if (wl_state.output)
|
||||
return;
|
||||
|
||||
wl_state.output = output;
|
||||
struct wl_wlr_output_state *ost = wmalloc(sizeof(*ost));
|
||||
memset(ost, 0, sizeof(*ost));
|
||||
ost->output = output;
|
||||
|
||||
if (wl_state.allocator && wl_state.renderer)
|
||||
wlr_output_init_render(output, wl_state.allocator, wl_state.renderer);
|
||||
|
|
@ -89,15 +97,15 @@ handle_backend_new_output(struct wl_listener *listener, void *data)
|
|||
wlr_wl_output_set_title(output, "Window Maker");
|
||||
|
||||
if (wl_state.scene) {
|
||||
wl_state.scene_output = wlr_scene_output_create(wl_state.scene, output);
|
||||
wl_state.output_frame_listener.notify = handle_output_frame;
|
||||
wl_signal_add(&output->events.frame, &wl_state.output_frame_listener);
|
||||
ost->scene_output = wlr_scene_output_create(wl_state.scene, output);
|
||||
ost->frame_listener.notify = handle_output_frame;
|
||||
wl_signal_add(&output->events.frame, &ost->frame_listener);
|
||||
wwarning("wl_backend: scene output created for %s (%dx%d)",
|
||||
output->name, output->width, output->height);
|
||||
|
||||
{
|
||||
float bg[4] = { 0x50/255.0f, 0x50/255.0f, 0x75/255.0f, 1.0f };
|
||||
wl_state.bg_rect = wlr_scene_rect_create(
|
||||
ost->bg_rect = wlr_scene_rect_create(
|
||||
wl_state.level_trees[WL_LAYER_BACKGROUND],
|
||||
(int)output->width, (int)output->height, bg);
|
||||
wwarning("wl_backend: root background created (%dx%d)",
|
||||
|
|
@ -113,6 +121,20 @@ handle_backend_new_output(struct wl_listener *listener, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
wl_list_insert(&wl_state.outputs, &ost->link);
|
||||
wl_state.output_count++;
|
||||
|
||||
/* For backward compat, keep wl_state.output pointing to the first output */
|
||||
if (!wl_state.output) {
|
||||
wl_state.output = output;
|
||||
wl_state.scene_output = ost->scene_output;
|
||||
wl_state.bg_rect = ost->bg_rect;
|
||||
}
|
||||
|
||||
wwarning("wl_backend: new output %s (%dx%d)",
|
||||
output->name, output->width, output->height);
|
||||
|
||||
/* Refresh screen heads to include the new output */
|
||||
if (wl_state.scr)
|
||||
wl_screen_refresh_heads(wl_state.scr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ void *W_RegisterBacking(unsigned long id, void *img);
|
|||
|
||||
/* Rebuild scr->heads from the wlr_output_layout. Called during screen
|
||||
* init and on output hotplug. */
|
||||
static void
|
||||
void
|
||||
wl_screen_refresh_heads(WScreen *scr)
|
||||
{
|
||||
/* Free old head array if any */
|
||||
|
|
|
|||
|
|
@ -137,6 +137,15 @@ struct wl_ctx_entry {
|
|||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Per-output state — one entry per active wlr_output */
|
||||
struct wl_wlr_output_state {
|
||||
struct wlr_output *output;
|
||||
struct wlr_scene_output *scene_output;
|
||||
struct wlr_scene_rect *bg_rect;
|
||||
struct wl_listener frame_listener;
|
||||
struct wl_list link; /* wl_compositor_state.outputs */
|
||||
};
|
||||
|
||||
/* Global compositor state */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
|
|
@ -144,7 +153,9 @@ struct wl_compositor_state {
|
|||
struct wl_display *display;
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_output *output; /* headless output (screen 0) */
|
||||
struct wlr_output *output; /* first/primary output (backward compat) */
|
||||
struct wl_list outputs; /* wl_wlr_output_state.link */
|
||||
int output_count;
|
||||
struct wlr_output_layout *output_layout; /* Phase 34 */
|
||||
/* Phase 35: core Wayland protocol globals */
|
||||
struct wlr_compositor *compositor;
|
||||
|
|
@ -210,9 +221,8 @@ struct wl_compositor_state {
|
|||
struct wlr_session *session; /* DRM session (standalone only) */
|
||||
struct wlr_allocator *allocator;
|
||||
struct wlr_scene *scene;
|
||||
struct wlr_scene_output *scene_output;
|
||||
struct wlr_scene_output *scene_output; /* first output's scene (backward compat) */
|
||||
struct wl_listener backend_new_output_listener;
|
||||
struct wl_listener output_frame_listener;
|
||||
char socket_name[64];
|
||||
char host_wayland_display[64]; /* saved from env before overwrite */
|
||||
int started; /* non-zero after successful display_open */
|
||||
|
|
|
|||
Loading…
Reference in New Issue