diff --git a/.gitignore b/.gitignore index 7d6d080..5078010 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build fuzz_corpus fuzzing-directory PROGRESS.md +TODO.md diff --git a/nedm.c b/nedm.c index 064b052..0441ed5 100644 --- a/nedm.c +++ b/nedm.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -119,12 +120,20 @@ handle_signal(int signal, void *const data) { case SIGINT: /* Fallthrough */ case SIGTERM: - display_terminate(server); + if(server && server->wl_display) { + // Only terminate if we're sure the server is in a valid state + display_terminate(server); + } return 0; case SIGALRM: { - struct nedm_output *output; - wl_list_for_each(output, &server->outputs, link) { - message_clear(output); + // Only clear messages if server is running and valid + if(server && server->running && !wl_list_empty(&server->outputs)) { + struct nedm_output *output; + wl_list_for_each(output, &server->outputs, link) { + if(output) { + message_clear(output); + } + } } return 0; } @@ -137,6 +146,7 @@ handle_signal(int signal, void *const data) { } } + static void usage(FILE *file, const char *const cage) { fprintf(file, @@ -418,6 +428,14 @@ main(int argc, char *argv[]) { wl_event_loop_add_signal(event_loop, SIGPIPE, handle_signal, &server); server.event_loop = event_loop; + // Let wlroots handle device selection automatically for better compatibility + const char *force_drm_device = getenv("WLR_DRM_DEVICES"); + if (force_drm_device) { + wlr_log(WLR_INFO, "Using user-specified DRM devices: %s", force_drm_device); + } else { + wlr_log(WLR_DEBUG, "Using automatic DRM device selection"); + } + backend = wlr_backend_autocreate(event_loop, &server.session); server.headless_backend = wlr_headless_backend_create(event_loop); if(!backend) { @@ -427,6 +445,15 @@ main(int argc, char *argv[]) { } server.backend = backend; + // Session is handled automatically by wlroots - no custom handlers needed + if (server.session) { + server.session_is_active = true; // Start active + wlr_log(WLR_INFO, "Session available - VT switching handled by wlroots"); + } else { + wlr_log(WLR_DEBUG, "No session available - running without VT switching"); + server.session_is_active = true; // Fallback for sessionless operation + } + if(!drop_permissions()) { ret = 1; goto end; @@ -812,6 +839,8 @@ end: seat_destroy(server.seat); } + // Session cleanup handled automatically by wlroots + if(sigint_source != NULL) { wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); diff --git a/output.c b/output.c index 3547b89..c7305ee 100644 --- a/output.c +++ b/output.c @@ -71,6 +71,10 @@ output_clear(struct nedm_output *output) { struct nedm_view *view, *view_tmp; if(server->running) { for(unsigned int i = 0; i < server->nws; ++i) { + if(!output->workspaces || !output->workspaces[i] || + !output->workspaces[i]->focused_tile) { + continue; + } bool first = true; for(struct nedm_tile *tile = output->workspaces[i]->focused_tile; @@ -79,20 +83,23 @@ output_clear(struct nedm_output *output) { first = false; workspace_tile_update_view(tile, NULL); } - struct nedm_workspace *ws = - server->curr_output - ->workspaces[server->curr_output->curr_workspace]; + struct nedm_workspace *ws = NULL; + if(server->curr_output && server->curr_output->workspaces && + server->curr_output->curr_workspace < server->nws && + server->curr_output->workspaces[server->curr_output->curr_workspace]) { + ws = server->curr_output->workspaces[server->curr_output->curr_workspace]; + } wl_list_for_each_safe(view, view_tmp, &output->workspaces[i]->views, link) { wl_list_remove(&view->link); if(wl_list_empty(&server->outputs)) { view->impl->destroy(view); - } else { + } else if(ws) { wl_list_insert(&ws->views, &view->link); wlr_scene_node_reparent(&view->scene_tree->node, ws->scene); view->workspace = ws; view->tile = ws->focused_tile; - if(server->seat->focused_view == NULL) { + if(server->seat && server->seat->focused_view == NULL) { seat_set_focus(server->seat, view); } } @@ -197,8 +204,13 @@ output_destroy(struct nedm_output *output) { wlr_log(WLR_ERROR, "Failed to allocate memory for output name in output_destroy"); } + // Note: Don't terminate when outputs become empty - this is normal during: + // - VT switches (outputs temporarily disabled) + // - Output hotplug events + // - Multi-GPU switching + // Modern compositors handle this gracefully and wait for outputs to return if(wl_list_empty(&server->outputs) && server->running) { - wl_display_terminate(server->wl_display); + wlr_log(WLR_DEBUG, "No outputs available - waiting for outputs to return"); } } @@ -612,9 +624,13 @@ output_make_workspace_fullscreen(struct nedm_output *output, uint32_t ws) { if(ws >= server->nws) { return; } - struct nedm_view *current_view = output->workspaces[ws]->focused_tile->view; + struct nedm_view *current_view = NULL; + if(output->workspaces && ws < output->server->nws && + output->workspaces[ws] && output->workspaces[ws]->focused_tile) { + current_view = output->workspaces[ws]->focused_tile->view; + } - if(current_view == NULL) { + if(current_view == NULL && output->workspaces[ws]) { struct nedm_view *it = NULL; wl_list_for_each(it, &output->workspaces[ws]->views, link) { if(view_is_visible(it)) { diff --git a/seat.c b/seat.c index 39e0b21..ba8c8ee 100644 --- a/seat.c +++ b/seat.c @@ -803,7 +803,10 @@ process_cursor_motion(struct nedm_seat *seat, uint32_t time) { break; } } - if(c_outp) { + if(c_outp && nedm_outp->workspaces && + nedm_outp->curr_workspace < nedm_outp->server->nws && + nedm_outp->workspaces[nedm_outp->curr_workspace] && + nedm_outp->workspaces[nedm_outp->curr_workspace]->focused_tile) { struct nedm_tile *c_tile; bool first = true; for(c_tile = nedm_outp->workspaces[nedm_outp->curr_workspace]->focused_tile; @@ -1184,10 +1187,15 @@ seat_set_focus(struct nedm_seat *seat, struct nedm_view *view) { /* Focusing the background */ if(view == NULL) { - workspace_tile_update_view( - server->curr_output->workspaces[server->curr_output->curr_workspace] - ->focused_tile, - NULL); + if(server->curr_output && server->curr_output->workspaces && + server->curr_output->curr_workspace < server->nws && + server->curr_output->workspaces[server->curr_output->curr_workspace] && + server->curr_output->workspaces[server->curr_output->curr_workspace]->focused_tile) { + workspace_tile_update_view( + server->curr_output->workspaces[server->curr_output->curr_workspace] + ->focused_tile, + NULL); + } seat->focused_view = NULL; if(prev_view != NULL) { view_activate(prev_view, false); diff --git a/server.c b/server.c index 6e68338..c49979e 100644 --- a/server.c +++ b/server.c @@ -66,3 +66,13 @@ server_show_info(struct nedm_server *server) { free(input_str); return ret; } + +bool +server_session_is_active(struct nedm_server *server) { + if (!server) { + return false; + } + // wlroots handles session state automatically + // Just return our tracked state for output termination logic + return server->session_is_active; +} diff --git a/server.h b/server.h index 20bbcad..b2ede85 100644 --- a/server.h +++ b/server.h @@ -44,6 +44,8 @@ struct nedm_server { struct wl_list output_priorities; struct wlr_backend *headless_backend; struct wlr_session *session; + struct wl_listener session_active; + bool session_is_active; struct wlr_renderer *renderer; struct wlr_allocator *allocator; @@ -90,5 +92,7 @@ int get_mode_index_from_name(char *const *modes, const char *mode_name); char * server_show_info(struct nedm_server *server); +bool +server_session_is_active(struct nedm_server *server); #endif diff --git a/view.c b/view.c index 60dcbc8..ed68d67 100644 --- a/view.c +++ b/view.c @@ -131,13 +131,16 @@ view_unmap(struct nedm_view *view) { #endif { struct nedm_view *prev = view_get_prev_view(view); - if(view == view->server->seat->focused_view) { - seat_set_focus(view->server->seat, prev); - } else if(view->server->seat->seat->keyboard_state.focused_surface == - view->wlr_surface) { - wlr_seat_keyboard_clear_focus(view->server->seat->seat); - seat_set_focus(view->server->seat, - view->server->seat->focused_view); + if(view->server && view->server->seat) { + if(view == view->server->seat->focused_view) { + seat_set_focus(view->server->seat, prev); + } else if(view->server->seat->seat && + view->server->seat->seat->keyboard_state.focused_surface == + view->wlr_surface) { + wlr_seat_keyboard_clear_focus(view->server->seat->seat); + seat_set_focus(view->server->seat, + view->server->seat->focused_view); + } } struct nedm_tile *view_tile = view_get_tile(view); if(view_tile != NULL) { @@ -146,11 +149,13 @@ view_unmap(struct nedm_view *view) { } #if NEDM_HAS_XWAYLAND else { - if(view->server->seat->seat->keyboard_state.focused_surface == NULL || - view->server->seat->seat->keyboard_state.focused_surface == - view->wlr_surface) { - seat_set_focus(view->server->seat, - view->server->seat->focused_view); + if(view->server && view->server->seat && view->server->seat->seat) { + if(view->server->seat->seat->keyboard_state.focused_surface == NULL || + view->server->seat->seat->keyboard_state.focused_surface == + view->wlr_surface) { + seat_set_focus(view->server->seat, + view->server->seat->focused_view); + } } } #endif @@ -193,7 +198,9 @@ view_map(struct nedm_view *view, struct wlr_surface *surface, { wl_list_insert(&ws->views, &view->link); } - seat_set_focus(output->server->seat, view); + if(output && output->server && output->server->seat) { + seat_set_focus(output->server->seat, view); + } int tile_id = 0; if(view->tile == NULL) { tile_id = -1; @@ -219,9 +226,17 @@ view_destroy(struct nedm_view *view) { wlr_scene_node_destroy(&view->scene_tree->node); view->impl->destroy(view); - view_activate(curr_output->workspaces[curr_output->curr_workspace] - ->focused_tile->view, - true); + + // Safely activate the focused view if it exists + if(curr_output && curr_output->workspaces && + curr_output->curr_workspace < curr_output->server->nws && + curr_output->workspaces[curr_output->curr_workspace] && + curr_output->workspaces[curr_output->curr_workspace]->focused_tile && + curr_output->workspaces[curr_output->curr_workspace]->focused_tile->view) { + view_activate(curr_output->workspaces[curr_output->curr_workspace] + ->focused_tile->view, + true); + } } void