From 47312fa5a6b8eecc62bd7e5f989923f17f5dc6a8 Mon Sep 17 00:00:00 2001 From: nots1dd Date: Wed, 16 Oct 2024 15:30:34 +0530 Subject: [PATCH] [FEAT] integrated session lock protocol --- client_state.h | 19 ++++++ log.h | 128 ++++++++++++++++++++++-------------- main.c | 99 +++++++++++++++------------- muvilock | Bin 0 -> 92240 bytes session_lock_handle.h | 140 ++++++++++++++++++++++++++++++--------- wl_output_handle.h | 72 ++++++++++++++++++++ wl_registry_handle.h | 15 +++++ xdg_surface_handle.h | 148 ++++++++++++++++++++++++++++-------------- 8 files changed, 451 insertions(+), 170 deletions(-) create mode 100755 muvilock create mode 100644 wl_output_handle.h diff --git a/client_state.h b/client_state.h index ce879f7..f092559 100644 --- a/client_state.h +++ b/client_state.h @@ -5,6 +5,15 @@ #include #include +// Define a structure to store output-related information +struct output_state { + uint32_t id; + int32_t width; + int32_t height; + int32_t refresh_rate; + struct wl_output *wl_output; +}; + struct pointer_event { uint32_t event_mask; // Masks for various event types @@ -31,6 +40,7 @@ struct client_state struct wl_compositor* wl_compositor; // Compositor interface struct xdg_wm_base* xdg_wm_base; // XDG window manager base interface struct wl_seat* wl_seat; // Input device seat + struct wl_output *wl_output; /* Objects */ struct wl_surface* wl_surface; // Wayland surface struct xdg_surface* xdg_surface; // XDG surface @@ -52,6 +62,15 @@ struct client_state char password[256]; int password_index; bool authenticated; + bool locked; + /* SESSION LOCK */ + bool surface_created; + bool surface_dirty; + struct ext_session_lock_manager_v1 *ext_session_lock_manager_v1; + struct ext_session_lock_v1 *ext_session_lock_v1; + struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1; + /* wl_output */ + struct output_state output_state; }; #endif diff --git a/log.h b/log.h index 0883b5e..19a493f 100644 --- a/log.h +++ b/log.h @@ -12,14 +12,14 @@ /* Define log importance levels */ enum log_importance { - LOG_LEVEL_SILENT, - LOG_LEVEL_ERROR, - LOG_LEVEL_WARN, - LOG_LEVEL_INFO, - LOG_LEVEL_AUTH, - LOG_LEVEL_SUCCESS, - LOG_LEVEL_DEBUG, - LOG_IMPORTANCE_LAST // Keep this as the last element to define the range + LOG_LEVEL_SILENT, + LOG_LEVEL_ERROR, + LOG_LEVEL_WARN, + LOG_LEVEL_INFO, + LOG_LEVEL_AUTH, + LOG_LEVEL_SUCCESS, + LOG_LEVEL_DEBUG, + LOG_IMPORTANCE_LAST // Keep this as the last element to define the range }; /* Current log importance level */ @@ -27,68 +27,100 @@ static enum log_importance log_importance = LOG_LEVEL_DEBUG; /* Define verbosity colors */ static const char* verbosity_colors[] = { - [LOG_LEVEL_SILENT] = "", - [LOG_LEVEL_ERROR] = "\x1B[1;31m", // Red - [LOG_LEVEL_WARN] = "\x1B[1;33m", // Yellow - [LOG_LEVEL_INFO] = "\x1B[1;34m", // Blue - [LOG_LEVEL_DEBUG] = "\x1B[1;30m", // Dark Gray - [LOG_LEVEL_AUTH] = "\x1B[1;35m", // Pink (Magenta) - [LOG_LEVEL_SUCCESS] = "\x1B[1;32m" // Green + [LOG_LEVEL_SILENT] = "", + [LOG_LEVEL_ERROR] = "\x1B[1;31m", // Red + [LOG_LEVEL_WARN] = "\x1B[1;33m", // Yellow + [LOG_LEVEL_INFO] = "\x1B[1;34m", // Blue + [LOG_LEVEL_DEBUG] = "\x1B[1;30m", // Dark Gray + [LOG_LEVEL_AUTH] = "\x1B[1;35m", // Pink (Magenta) + [LOG_LEVEL_SUCCESS] = "\x1B[1;32m" // Green }; +/* Log file pointer */ +static FILE* log_file = NULL; + /* Function to initialize logging with a specified verbosity level */ void log_init(enum log_importance verbosity) { - if (verbosity < LOG_IMPORTANCE_LAST) - { - log_importance = verbosity; - } + if (verbosity < LOG_IMPORTANCE_LAST) + { + log_importance = verbosity; + } + + // Open the log file for appending, create it if it does not exist + log_file = fopen("casuality.log", "a"); + if (log_file == NULL) + { + fprintf(stderr, "Failed to open log file: %s\n", strerror(errno)); + } } /* Logging function */ void log_message(enum log_importance verbosity, const char* fmt, ...) { - if (verbosity > log_importance) - { - return; - } + if (verbosity > log_importance) + { + return; + } + + va_list args; + va_start(args, fmt); + + // Prefix the time to the log message + time_t t = time(NULL); + struct tm* tm_info = localtime(&t); + char buffer[26]; + strftime(buffer, sizeof(buffer), "[%F %T] - ", tm_info); + + // Log to console + fprintf(stderr, "%s", buffer); - va_list args; - va_start(args, fmt); + unsigned c = (verbosity < LOG_IMPORTANCE_LAST) ? verbosity : LOG_IMPORTANCE_LAST - 1; - // Prefix the time to the log message - time_t t = time(NULL); - struct tm* tm_info = localtime(&t); - char buffer[26]; - strftime(buffer, sizeof(buffer), "[%F %T] - ", tm_info); - fprintf(stderr, "%s", buffer); + if (isatty(STDERR_FILENO)) + { + fprintf(stderr, "%s", verbosity_colors[c]); + } - unsigned c = (verbosity < LOG_IMPORTANCE_LAST) ? verbosity : LOG_IMPORTANCE_LAST - 1; + vfprintf(stderr, fmt, args); - if (isatty(STDERR_FILENO)) - { - fprintf(stderr, "%s", verbosity_colors[c]); - } + if (isatty(STDERR_FILENO)) + { + fprintf(stderr, "\x1B[0m"); // Reset color + } - vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); - if (isatty(STDERR_FILENO)) - { - fprintf(stderr, "\x1B[0m"); // Reset color - } + // Also log to the file + if (log_file != NULL) + { + fprintf(log_file, "%s", buffer); + vfprintf(log_file, fmt, args); + fprintf(log_file, "\n"); + fflush(log_file); // Flush to ensure it is written immediately + } - fprintf(stderr, "\n"); - va_end(args); + va_end(args); } /* Optional function to strip leading './' from file paths */ const char* strip_path(const char* filepath) { - while (*filepath == '.' || *filepath == '/') - { - ++filepath; - } - return filepath; + while (*filepath == '.' || *filepath == '/') + { + ++filepath; + } + return filepath; +} + +/* Function to clean up logging resources */ +void log_cleanup() +{ + if (log_file != NULL) + { + fclose(log_file); + log_file = NULL; + } } #endif // LOG_H diff --git a/main.c b/main.c index 320b2dc..13e034c 100644 --- a/main.c +++ b/main.c @@ -12,9 +12,10 @@ #include "wl_seat_handle.h" #include "xdg_surface_handle.h" #include "xdg_wm_base_handle.h" +#include "wl_output_handle.h" #include #include -/*#include "session_lock_handle.h"*/ +#include "session_lock_handle.h" /********************************************** * @WAYLAND CLIENT EXAMPLE CODE @@ -97,56 +98,66 @@ * the Wayland compositor through various protocols and listeners. **********************************************/ -int main(int argc, char* argv[]) -{ - struct client_state state = {0}; - /* struct session_lock_state lock_state = { 0 }; // Add this line for session lock state */ +int main(int argc, char* argv[]) { + struct client_state state = {0}; - // Connect to the Wayland display - state.wl_display = wl_display_connect(NULL); - state.username = getlogin(); - log_message(LOG_LEVEL_INFO, "Found User @ %s", state.username); - state.firstEnterPress = true; - if (!state.wl_display) - { - fprintf(stderr, "Failed to connect to Wayland display\n"); - return -1; - } + // Initialize and connect to the Wayland display + state.wl_display = wl_display_connect(NULL); + state.username = getlogin(); + log_message(LOG_LEVEL_INFO, "Found User @ %s", state.username); - // Get the registry and set up listeners - state.wl_registry = wl_display_get_registry(state.wl_display); - state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - wl_registry_add_listener(state.wl_registry, &wl_registry_listener, &state); - wl_display_roundtrip(state.wl_display); + if (!state.wl_display) { + log_message(LOG_LEVEL_ERROR, "Failed to connect to Wayland display\n"); + return -1; + } - // Bind session lock protocol - /* bind_session_lock(&lock_state); // Call the binding function */ + // Get the registry and set up listeners + state.wl_registry = wl_display_get_registry(state.wl_display); + state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - // Create a Wayland surface and set it up as an XDG surface - state.wl_surface = wl_compositor_create_surface(state.wl_compositor); - state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.wl_surface); - xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state); - state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface); - xdg_toplevel_set_title(state.xdg_toplevel, "Something man"); + // Add listeners for registry objects + wl_registry_add_listener(state.wl_registry, &wl_registry_listener, &state); - state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - state.xkb_keymap = - xkb_keymap_new_from_names(state.xkb_context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); - state.xkb_state = xkb_state_new(state.xkb_keymap); + // Roundtrip to process the registry and get the compositor, shm, seat, etc. + wl_display_roundtrip(state.wl_display); - // Add keyboard listener for capturing password input - wl_seat_add_listener(state.wl_seat, &wl_seat_listener, &state); + // Create the Wayland surface and initialize XDG shell surface + state.wl_surface = wl_compositor_create_surface(state.wl_compositor); + state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.wl_surface); + + // Add listeners for XDG surface events + xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state); - wl_surface_commit(state.wl_surface); + // Create the XDG toplevel (window management) + state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface); + xdg_toplevel_set_title(state.xdg_toplevel, "Screen Lock"); - // Continue running the event loop until the user authenticates - while (!state.authenticated && wl_display_dispatch(state.wl_display)) - { - /* Process events */ - } + // Initialize XKB for handling keyboard input + state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + state.xkb_keymap = xkb_keymap_new_from_names(state.xkb_context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); + state.xkb_state = xkb_state_new(state.xkb_keymap); - // Clean up Wayland resources before exiting - wl_display_disconnect(state.wl_display); - log_message(LOG_LEVEL_SUCCESS, "Unlocking..."); - return 0; + // Initialize pointer and keyboard state + state.authenticated = false; // Initialize authentication state + + // Add listeners for seat (input devices like keyboard) + wl_seat_add_listener(state.wl_seat, &wl_seat_listener, &state); + + // Commit the surface to make it visible + wl_surface_commit(state.wl_surface); + + // Enter event loop for handling lock state and input + while (!state.authenticated && wl_display_dispatch(state.wl_display) != -1) { + // Check if the session needs to be locked + if (!state.surface_created) { + initiate_session_lock(&state); + } + } + + // Disconnect from the Wayland display + unlock_and_destroy_session_lock(&state); + wl_display_roundtrip(state.wl_display); + wl_display_disconnect(state.wl_display); + log_message(LOG_LEVEL_SUCCESS, "Unlocking..."); + return 0; } diff --git a/muvilock b/muvilock new file mode 100755 index 0000000000000000000000000000000000000000..664ab66fea8a516e0c2a42eaa630236f9916933f GIT binary patch literal 92240 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 #include +#include "xdg_surface_handle.h" // For rendering the lock screen +#include "wl_keyboard_handle.h" // Include the keyboard handler +#include "wl_pointer_handle.h" // Include the pointer handler -// Protocol-specific headers (you should replace this with the actual protocol header) -#include "protocols/ext-session-lock-client-protocol.h" // Include the protocol definitions here -#include "protocols/src/ext-session-lock-client-protocol.c" +// Include the ext-session-lock protocol headers -struct session_lock_state -{ - struct wl_display* display; // Wayland display connection - struct wl_registry* registry; // Registry for global objects - struct wl_seat* wl_seat; // Input device seat - struct wl_session_lock* session_lock; // Session lock interface +static void ext_session_lock_v1_handle_locked(void *data, struct ext_session_lock_v1 *lock) { + struct client_state *state = data; + state->locked = true; +} + +static void ext_session_lock_v1_handle_finished(void *data, struct ext_session_lock_v1 *lock) { + log_message(LOG_LEVEL_ERROR, "Failed to lock session -- " + "is another lockscreen running?"); + exit(2); +} + +static const struct ext_session_lock_v1_listener ext_session_lock_v1_listener = { + .locked = ext_session_lock_v1_handle_locked, + .finished = ext_session_lock_v1_handle_finished, }; -// Listener for session lock events -static void session_lock_locked(void* data, struct wl_session_lock* lock) -{ - log_message(LOG_LEVEL_INFO, "Session locked"); +// Function for rendering the lock screen +void render_lock_screen(struct client_state *state) { + // Ensure surface exists + if (!state->wl_surface) { + log_message(LOG_LEVEL_ERROR, "No surface to render lock screen"); + return; + } + + // Create and draw lock screen buffer + struct wl_buffer *buffer = draw_lock_screen(state); + if (!buffer) { + log_message(LOG_LEVEL_ERROR, "Failed to create buffer for lock screen"); + return; + } + + // Attach the buffer to the surface and commit + wl_surface_attach(state->wl_surface, buffer, 0, 0); + wl_surface_damage(state->wl_surface, 0, 0, state->output_state.width, state->output_state.height); // Notify the compositor + wl_surface_commit(state->wl_surface); } -static void session_lock_unlocked(void* data, struct wl_session_lock* lock) -{ - log_message(LOG_LEVEL_INFO, "Session unlocked"); +// Listener callback for ext-session-lock surface configuration +static void ext_session_lock_surface_v1_handle_configure(void *data, + struct ext_session_lock_surface_v1 *lock_surface, uint32_t serial, + uint32_t width, uint32_t height) { + + struct client_state *state = data; + state->output_state.width = width; + state->output_state.height = height; + + // Acknowledge the configuration + ext_session_lock_surface_v1_ack_configure(lock_surface, serial); + + // Mark surface as dirty for re-rendering + state->surface_dirty = true; + + // Render the lock screen once the surface is configured + render_lock_screen(state); } -// Listener structure for session lock events -static const struct wl_session_lock_listener session_lock_listener = { - .locked = session_lock_locked, - .unlocked = session_lock_unlocked, +// Listener for the session lock surface +static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener = { + .configure = ext_session_lock_surface_v1_handle_configure, }; -// Function to bind to the session lock protocol -void bind_session_lock(struct session_lock_state* state) -{ - state->session_lock = - wl_registry_bind(state->registry, - /* name */ 1, // This should be the actual name of the session lock - &wl_session_lock_interface, // Use the actual interface here - 1 // version - ); - - wl_session_lock_add_listener(state->session_lock, &session_lock_listener, state); +// Function to create the lock surface +static void create_lock_surface(struct client_state *state) { + // Create a Wayland surface for the lock screen + state->wl_surface = wl_compositor_create_surface(state->wl_compositor); + assert(state->wl_surface); + + // Ensure that output is set correctly in client_state + if (!state->output_state.wl_output) { + log_message(LOG_LEVEL_ERROR, "No output available for lock surface"); + return; + } + + // Create the ext-session-lock surface + state->ext_session_lock_surface_v1 = ext_session_lock_v1_get_lock_surface( + state->ext_session_lock_v1, state->wl_surface, state->output_state.wl_output); + assert(state->ext_session_lock_surface_v1); + + // Add listener for configure events + ext_session_lock_surface_v1_add_listener( + state->ext_session_lock_surface_v1, &ext_session_lock_surface_v1_listener, state); + + // Use the existing keyboard listener + wl_keyboard_add_listener(state->wl_keyboard, &wl_keyboard_listener, state); + + // Use the existing pointer listener + wl_pointer_add_listener(state->wl_pointer, &wl_pointer_listener, state); + + // Mark the surface as created + state->surface_created = true; +} + +// Function to initiate the session lock process +static void initiate_session_lock(struct client_state *state) { + // Lock the session + state->ext_session_lock_v1 = ext_session_lock_manager_v1_lock(state->ext_session_lock_manager_v1); + assert(state->ext_session_lock_v1); + + // Create the lock surface and trigger lock screen rendering + create_lock_surface(state); +} + +// Function to unlock and destroy the session lock +static void unlock_and_destroy_session_lock(struct client_state *state) { + if (state->ext_session_lock_v1) { + ext_session_lock_v1_unlock_and_destroy(state->ext_session_lock_v1); + state->ext_session_lock_v1 = NULL; + log_message(LOG_LEVEL_INFO, "Session unlocked and lock object destroyed."); + } } #endif // SESSION_LOCK_HANDLE_H diff --git a/wl_output_handle.h b/wl_output_handle.h new file mode 100644 index 0000000..f5e475a --- /dev/null +++ b/wl_output_handle.h @@ -0,0 +1,72 @@ +#ifndef WL_OUTPUT_HANDLE_H +#define WL_OUTPUT_HANDLE_H + +#include "client_state.h" +#include +#include +#include "log.h" + +// This function will be called whenever output geometry changes +static void handle_output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, + int32_t physical_width, int32_t physical_height, int32_t subpixel, + const char *make, const char *model, int32_t transform) { + struct client_state *state = data; + log_message(LOG_LEVEL_INFO, "Output: %s %s @ (%d, %d) [%d x %d] mm", make, model, x, y, physical_width, physical_height); +} + +// This function will be called whenever output mode changes +static void handle_output_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, + int32_t height, int32_t refresh_rate) { + struct client_state *state = data; + + // Update state with the output mode (width, height, refresh rate) + state->output_state.width = width; + state->output_state.height = height; + state->output_state.refresh_rate = refresh_rate; + + log_message(LOG_LEVEL_INFO, "Output mode: %dx%d @ %d Hz", width, height, refresh_rate); +} + +// This function will be called when the output scale changes +static void handle_output_scale(void *data, struct wl_output *wl_output, int32_t factor) { + log_message(LOG_LEVEL_INFO, "Output scale factor: %d", factor); +} + +// This function will be called when the compositor sends a "done" event +static void handle_output_done(void *data, struct wl_output *wl_output) { + log_message(LOG_LEVEL_INFO, "Output configuration done."); +} + +// This function will be called to get the output name +static void handle_output_name(void *data, struct wl_output *wl_output, const char *name) { + log_message(LOG_LEVEL_INFO, "Output name: %s", name); +} + +// This function will be called to get the output description +static void handle_output_description(void *data, struct wl_output *wl_output, const char *description) { + log_message(LOG_LEVEL_INFO, "Output description: %s", description); +} + +// Output listener struct +static const struct wl_output_listener wl_output_listener = { + .geometry = handle_output_geometry, + .mode = handle_output_mode, + .done = handle_output_done, + .scale = handle_output_scale, + .name = handle_output_name, + .description = handle_output_description, +}; + +// Function to register an output object and set up the listener +static void register_output(struct client_state *state, struct wl_registry *registry, uint32_t id, uint32_t version) { + // Ensure the wl_output is already bound + if (state->output_state.wl_output) { + log_message(LOG_LEVEL_ERROR, "Output is already bound. Cannot register output listener again."); + return; + } + + // Bind the wl_output and add the listener + log_message(LOG_LEVEL_INFO, "Registered output with ID: %d", id); +} + +#endif // WL_OUTPUT_HANDLE_H diff --git a/wl_registry_handle.h b/wl_registry_handle.h index 4625067..3925b76 100644 --- a/wl_registry_handle.h +++ b/wl_registry_handle.h @@ -3,7 +3,10 @@ #include "log.h" #include "wl_seat_handle.h" +#include "wl_output_handle.h" #include "xdg_wm_base_handle.h" +#include "protocols/ext-session-lock-client-protocol.h" +#include "protocols/src/ext-session-lock-client-protocol.c" #include static void registry_global(void* data, struct wl_registry* wl_registry, uint32_t name, @@ -36,6 +39,18 @@ static void registry_global(void* data, struct wl_registry* wl_registry, uint32_ wl_seat_add_listener(state->wl_seat, &wl_seat_listener, state); log_message(LOG_LEVEL_INFO, "Seat interface bound."); } + else if (strcmp(interface, ext_session_lock_manager_v1_interface.name) == 0) + { + state->ext_session_lock_manager_v1 = wl_registry_bind(wl_registry, name, + &ext_session_lock_manager_v1_interface, 1); + log_message(LOG_LEVEL_INFO, "ext_session_lock_manager interface bound."); + } + else if (strcmp(interface, wl_output_interface.name) == 0) + { + state->output_state.wl_output = wl_registry_bind(wl_registry, name, &wl_output_interface, version); + wl_output_add_listener(state->output_state.wl_output, &wl_output_listener, state); + log_message(LOG_LEVEL_INFO, "Output interface bound."); + } else { log_message(LOG_LEVEL_WARN, "Unknown interface: %s", interface); diff --git a/xdg_surface_handle.h b/xdg_surface_handle.h index 66d37cc..241432e 100644 --- a/xdg_surface_handle.h +++ b/xdg_surface_handle.h @@ -2,61 +2,115 @@ #define XDG_SURFACE_HANDLER_H #include +#include +#include "client_state.h" +#include "log.h" -static struct wl_buffer* draw_frame(struct client_state* state) -{ - const int width = 640, height = 480; - int stride = width * 4; - int size = stride * height; - - int fd = allocate_shm_file(size); - if (fd == -1) - { - return NULL; - } - - uint32_t* data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) - { +static struct wl_buffer* draw_lock_screen(struct client_state* state) { + const int width = state->output_state.width; + const int height = state->output_state.height; + int stride = width * 4; + int size = stride * height; + + int fd = allocate_shm_file(size); + if (fd == -1) { + log_message(LOG_LEVEL_ERROR, "Failed to allocate shared memory file"); + return NULL; + } + + uint32_t* data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + log_message(LOG_LEVEL_ERROR, "Memory mapping failed: %s", strerror(errno)); + close(fd); + return NULL; + } + + struct wl_shm_pool* pool = wl_shm_create_pool(state->wl_shm, fd, size); + if (!pool) { + log_message(LOG_LEVEL_ERROR, "Failed to create SHM pool: %s", strerror(errno)); + munmap(data, size); + close(fd); + return NULL; + } + + struct wl_buffer* buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888); + if (!buffer) { + log_message(LOG_LEVEL_ERROR, "Failed to create buffer: %s", strerror(errno)); + wl_shm_pool_destroy(pool); + munmap(data, size); + close(fd); + return NULL; + } + + // Draw a gradient background + for (int y = 0; y < height; ++y) { + // Calculate the color for this row + uint8_t r = 102 + (y * 153) / height; // Gradient from 102 to 255 + uint8_t g = 102 + (y * 153) / height; // Gradient from 102 to 255 + uint8_t b = 102 + (y * 153) / height; // Gradient from 102 to 255 + uint32_t color = (0xFF << 24) | (r << 16) | (g << 8) | b; // ARGB format + + for (int x = 0; x < width; ++x) { + data[y * width + x] = color; + } + } + + // Draw password prompt box + int box_width = 300; + int box_height = 50; + int box_x = (width - box_width) / 2; + int box_y = (height - box_height) / 2; + + // Draw password box background + for (int y = box_y; y < box_y + box_height; ++y) { + for (int x = box_x; x < box_x + box_width; ++x) { + data[y * width + x] = 0xFF222222; // Darker gray for password box + } + } + + // Display the password input + int password_length = strlen(state->password); + int text_x = box_x + 10; // Padding from left + int text_y = box_y + (box_height - 20) / 2; // Center vertically + + // Draw each character of the password + for (int i = 0; i < password_length; i++) { + uint32_t color = 0xFFFFFFFF; // White for password text + int char_x = text_x + (i * 15); // Assuming a fixed-width font of 15 pixels + // Here, you can implement your own character drawing logic + // For demonstration, we just fill a pixel area for each character + for (int dy = -5; dy < 5; dy++) { + for (int dx = -5; dx < 5; dx++) { + if (char_x + dx >= box_x && char_x + dx < box_x + box_width && + text_y + dy >= box_y && text_y + dy < box_y + box_height) { + data[(text_y + dy) * width + (char_x + dx)] = color; + } + } + } + } + + munmap(data, size); + wl_shm_pool_destroy(pool); close(fd); - return NULL; - } - - struct wl_shm_pool* pool = wl_shm_create_pool(state->wl_shm, fd, size); - struct wl_buffer* buffer = - wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888); - wl_shm_pool_destroy(pool); - close(fd); - - /* Draw checkerboxed background */ - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - if ((x + y / 8 * 8) % 16 < 8) - data[y * width + x] = 0xFF666666; - else - data[y * width + x] = 0xFFEEEEEE; - } - } - - munmap(data, size); - wl_buffer_add_listener(buffer, &wl_buffer_listener, NULL); - return buffer; + return buffer; } -static void xdg_surface_configure(void* data, struct xdg_surface* xdg_surface, uint32_t serial) -{ - struct client_state* state = data; - xdg_surface_ack_configure(xdg_surface, serial); +static void xdg_surface_configure(void* data, struct xdg_surface* xdg_surface, uint32_t serial) { + struct client_state* state = data; + xdg_surface_ack_configure(xdg_surface, serial); + + struct wl_buffer* buffer = draw_lock_screen(state); + if (!buffer) { + log_message(LOG_LEVEL_ERROR, "Failed to create buffer for lock screen"); + return; + } - struct wl_buffer* buffer = draw_frame(state); - wl_surface_attach(state->wl_surface, buffer, 0, 0); - wl_surface_commit(state->wl_surface); + wl_surface_attach(state->wl_surface, buffer, 0, 0); + wl_surface_commit(state->wl_surface); } static const struct xdg_surface_listener xdg_surface_listener = { - .configure = xdg_surface_configure, + .configure = xdg_surface_configure, }; #endif