diff options
Diffstat (limited to 'src/platform')
| -rw-r--r-- | src/platform/linux_platform.h | 105 | ||||
| -rw-r--r-- | src/platform/macos_platform.cc | 480 | ||||
| -rw-r--r-- | src/platform/macos_platform.h | 118 | ||||
| -rw-r--r-- | src/platform/platform.h | 91 | ||||
| -rw-r--r-- | src/platform/platform_factory.cc | 214 | ||||
| -rw-r--r-- | src/platform/platform_factory.h | 37 | ||||
| -rw-r--r-- | src/platform/wayland_platform.cc | 507 | ||||
| -rw-r--r-- | src/platform/wayland_platform.h | 227 | ||||
| -rw-r--r-- | src/platform/wayland_platform_stub.cc | 114 | ||||
| -rw-r--r-- | src/platform/windows_platform.cc | 585 | ||||
| -rw-r--r-- | src/platform/windows_platform.h | 140 | ||||
| -rw-r--r-- | src/platform/x11_platform.cc | 1005 | ||||
| -rw-r--r-- | src/platform/x11_platform.h | 210 |
13 files changed, 3833 insertions, 0 deletions
diff --git a/src/platform/linux_platform.h b/src/platform/linux_platform.h new file mode 100644 index 0000000..1237c85 --- /dev/null +++ b/src/platform/linux_platform.h @@ -0,0 +1,105 @@ +#ifndef SRDWM_LINUX_PLATFORM_H +#define SRDWM_LINUX_PLATFORM_H + +#include "platform.h" +#include <memory> +#include <string> + +// Forward declarations for X11 +#ifdef __linux__ +struct _XDisplay; +typedef struct _XDisplay Display; +typedef unsigned long SRDWindow; +typedef unsigned long Atom; + +// Forward declarations for Wayland +struct wl_display; +struct wl_registry; +struct wl_compositor; +struct wl_shell; +struct wl_seat; +struct wl_keyboard; +struct wl_pointer; +#endif + +class LinuxPlatform : public Platform { +public: + enum class Backend { + Auto, + X11, + Wayland + }; + + explicit LinuxPlatform(Backend backend = Backend::Auto); + ~LinuxPlatform() override; + + // Platform interface implementation + bool initialize() override; + void shutdown() override; + + bool poll_events(std::vector<Event>& events) override; + void process_event(const Event& event) override; + + std::unique_ptr<SRDWindow> create_window(const std::string& title, int x, int y, int width, int height) override; + void destroy_window(SRDWindow* window) override; + void set_window_position(SRDWindow* window, int x, int y) override; + void set_window_size(SRDWindow* window, int width, int height) override; + void set_window_title(SRDWindow* window, const std::string& title) override; + void focus_window(SRDWindow* window) override; + void minimize_window(SRDWindow* window) override; + void maximize_window(SRDWindow* window) override; + void close_window(SRDWindow* window) override; + + std::vector<Monitor> get_monitors() override; + Monitor get_primary_monitor() override; + + void grab_keyboard() override; + void ungrab_keyboard() override; + void grab_pointer() override; + void ungrab_pointer() override; + + std::string get_platform_name() const override; + bool is_wayland() const override; + bool is_x11() const override; + bool is_windows() const override; + bool is_macos() const override; + +private: + Backend backend_; + bool initialized_; + + // X11 specific members + Display* x11_display_; + SRDWindow x11_root_; + Atom x11_wm_delete_window_; + Atom x11_wm_protocols_; + + // Wayland specific members + wl_display* wayland_display_; + wl_registry* wayland_registry_; + wl_compositor* wayland_compositor_; + wl_shell* wayland_shell_; + wl_seat* wayland_seat_; + wl_keyboard* wayland_keyboard_; + wl_pointer* wayland_pointer_; + + // Common members + std::vector<Monitor> monitors_; + + // Private methods + bool initialize_x11(); + bool initialize_wayland(); + void shutdown_x11(); + void shutdown_wayland(); + + bool detect_backend(); + void setup_x11_atoms(); + void setup_wayland_registry(); + + // Event processing + void process_x11_event(XEvent& event, std::vector<Event>& events); + void process_wayland_event(wl_display* display, std::vector<Event>& events); +}; + +#endif // SRDWM_LINUX_PLATFORM_H + diff --git a/src/platform/macos_platform.cc b/src/platform/macos_platform.cc new file mode 100644 index 0000000..d489cb7 --- /dev/null +++ b/src/platform/macos_platform.cc @@ -0,0 +1,480 @@ +#include "macos_platform.h" +#include <iostream> +#include <CoreGraphics/CoreGraphics.h> +#include <ApplicationServices/ApplicationServices.h> +#include <Carbon/Carbon.h> + +// Static member initialization +MacOSPlatform* MacOSPlatform::instance_ = nullptr; + +MacOSPlatform::MacOSPlatform() + : event_tap_(nullptr) { + + instance_ = this; +} + +MacOSPlatform::~MacOSPlatform() { + shutdown(); + if (instance_ == this) { + instance_ = nullptr; + } +} + +bool MacOSPlatform::initialize() { + std::cout << "Initializing macOS platform..." << std::endl; + + // Request accessibility permissions + if (!request_accessibility_permissions()) { + std::cerr << "Failed to get accessibility permissions" << std::endl; + return false; + } + + // Setup event tap + setup_event_tap(); + + // Setup window monitoring + setup_window_monitoring(); + + std::cout << "macOS platform initialized successfully" << std::endl; + return true; +} + +void MacOSPlatform::shutdown() { + std::cout << "Shutting down macOS platform..." << std::endl; + + // Clean up event tap + if (event_tap_) { + CGEventTapEnable(event_tap_, false); + CFRelease(event_tap_); + event_tap_ = nullptr; + } + + // Clean up windows + for (auto& pair : window_map_) { + if (pair.second) { + delete pair.second; + } + } + window_map_.clear(); + + std::cout << "macOS platform shutdown complete" << std::endl; +} + +// SRDWindow decoration implementations (macOS limitations) +void MacOSPlatform::set_window_decorations(SRDWindow* window, bool enabled) { + std::cout << "MacOSPlatform: Set window decorations " << (enabled ? "enabled" : "disabled") << std::endl; + + if (!window) return; + + decorations_enabled_ = enabled; + + // macOS doesn't support custom window decorations like other platforms + // We can only work with native window properties + // For now, we'll just log the request + + // TODO: Implement using accessibility APIs to modify window properties + // This would involve using AXUIElementRef to modify window attributes + std::cout << "Decoration state set to: " << (enabled ? "enabled" : "disabled") << std::endl; +} + +void MacOSPlatform::set_window_border_color(SRDWindow* window, int r, int g, int b) { + std::cout << "MacOSPlatform: Set border color RGB(" << r << "," << g << "," << b << ")" << std::endl; + + if (!window) return; + + // macOS doesn't support custom border colors through public APIs + // This would require private APIs or overlay windows + // For now, we'll just log the request + + // TODO: Implement using private APIs or overlay windows + // This could involve: + // 1. Creating transparent overlay windows around the target window + // 2. Using private Core Graphics APIs (not recommended for production) + // 3. Using accessibility APIs to modify window properties + + std::cout << "Border color set to RGB(" << r << "," << g << "," << b << ")" << std::endl; +} + +void MacOSPlatform::set_window_border_width(SRDWindow* window, int width) { + std::cout << "MacOSPlatform: Set border width " << width << std::endl; + + if (!window) return; + + // macOS doesn't support custom border widths through public APIs + // This would require private APIs or overlay windows + // For now, we'll just log the request + + // TODO: Implement using private APIs or overlay windows + // This could involve: + // 1. Creating transparent overlay windows around the target window + // 2. Using private Core Graphics APIs (not recommended for production) + // 3. Using accessibility APIs to modify window properties + + std::cout << "Border width set to " << width << std::endl; +} + +bool MacOSPlatform::get_window_decorations(SRDWindow* window) const { + if (!window) return false; + + return decorations_enabled_; +} + +void MacOSPlatform::create_overlay_window(SRDWindow* window) { + std::cout << "MacOSPlatform: Create overlay window for window " << window->getId() << std::endl; + + if (!window) return; + + // TODO: Implement overlay window creation for custom decorations + // This would involve: + // 1. Creating a transparent window using Core Graphics + // 2. Positioning it over the target window + // 3. Drawing custom borders/titlebar on it + // 4. Handling mouse events for window management + + // For now, we'll just log the request + std::cout << "Overlay window creation requested" << std::endl; +} + +void MacOSPlatform::destroy_overlay_window(SRDWindow* window) { + std::cout << "MacOSPlatform: Destroy overlay window for window " << window->getId() << std::endl; + + if (!window) return; + + // TODO: Implement overlay window destruction + // This would involve: + // 1. Finding the overlay window for this window + // 2. Destroying the overlay window + // 3. Cleaning up any associated resources + + // For now, we'll just log the request + std::cout << "Overlay window destruction requested" << std::endl; +} + +bool MacOSPlatform::request_accessibility_permissions() { + std::cout << "Requesting accessibility permissions..." << std::endl; + + // Check if accessibility is enabled + const void* keys[] = { kAXTrustedCheckOptionPrompt }; + const void* values[] = { kCFBooleanTrue }; + + CFDictionaryRef options = CFDictionaryCreate( + kCFAllocatorDefault, keys, values, 1, nullptr, nullptr); + + bool trusted = AXIsProcessTrustedWithOptions(options); + CFRelease(options); + + if (trusted) { + std::cout << "Accessibility permissions granted" << std::endl; + } else { + std::cout << "Accessibility permissions denied" << std::endl; + } + + return trusted; +} + +void MacOSPlatform::setup_event_tap() { + std::cout << "Setting up event tap..." << std::endl; + + // Create event tap for global events + event_tap_ = CGEventTapCreate( + kCGSessionEventTap, + kCGHeadInsertEventTap, + kCGEventTapOptionDefault, + CGEventMaskBit(kCGEventKeyDown) | + CGEventMaskBit(kCGEventKeyUp) | + CGEventMaskBit(kCGEventLeftMouseDown) | + CGEventMaskBit(kCGEventLeftMouseUp) | + CGEventMaskBit(kCGEventRightMouseDown) | + CGEventMaskBit(kCGEventRightMouseUp) | + CGEventMaskBit(kCGEventMouseMoved), + event_tap_callback, + this); + + if (event_tap_) { + CFRunLoopSourceRef run_loop_source = + CFMachPortCreateRunLoopSource(kCFAllocatorDefault, event_tap_, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source, kCFRunLoopCommonModes); + CGEventTapEnable(event_tap_, true); + + std::cout << "Event tap setup complete" << std::endl; + } else { + std::cerr << "Failed to create event tap" << std::endl; + } +} + +void MacOSPlatform::setup_window_monitoring() { + std::cout << "Setting up window monitoring..." << std::endl; + + // Monitor window creation/destruction + CGSRDWindowListCopySRDWindowInfo(kCGSRDWindowListOptionOnScreenOnly | + kCGSRDWindowListExcludeDesktopElements, + kCGNullSRDWindowID); + + std::cout << "SRDWindow monitoring setup complete" << std::endl; +} + +bool MacOSPlatform::poll_events(std::vector<Event>& events) { + if (!initialized_ || !event_tap_) return false; + + events.clear(); + + // macOS events are handled through the event tap callback + // The event tap callback handles event conversion + // For now, we'll just return any pending events + + // TODO: Implement proper event queue processing + // This would involve processing events from the event tap callback + + return false; +} + +void MacOSPlatform::process_event(const Event& event) { + // TODO: Implement event processing +} + +std::unique_ptr<SRDWindow> MacOSPlatform::create_window(const std::string& title, int x, int y, int width, int height) { + std::cout << "Creating macOS window: " << title << std::endl; + + // TODO: Implement actual window creation using Core Graphics/AppKit + // For now, create a placeholder window object + + auto window = std::make_unique<SRDWindow>(); + // TODO: Set window properties + + std::cout << "macOS window creation requested" << std::endl; + return window; +} + +void MacOSPlatform::destroy_window(SRDWindow* window) { + std::cout << "Destroying macOS window" << std::endl; + + // TODO: Implement window destruction +} + +void MacOSPlatform::set_window_position(SRDWindow* window, int x, int y) { + // TODO: Implement window positioning using accessibility APIs +} + +void MacOSPlatform::set_window_size(SRDWindow* window, int width, int height) { + // TODO: Implement window resizing using accessibility APIs +} + +void MacOSPlatform::set_window_title(SRDWindow* window, const std::string& title) { + // TODO: Implement title setting +} + +void MacOSPlatform::focus_window(SRDWindow* window) { + // TODO: Implement window focusing +} + +void MacOSPlatform::minimize_window(SRDWindow* window) { + // TODO: Implement window minimization +} + +void MacOSPlatform::maximize_window(SRDWindow* window) { + // TODO: Implement window maximization +} + +void MacOSPlatform::close_window(SRDWindow* window) { + // TODO: Implement window closing +} + +std::vector<Monitor> MacOSPlatform::get_monitors() { + std::vector<Monitor> monitors; + + // Get display information using Core Graphics + uint32_t display_count = 0; + CGGetActiveDisplayList(0, nullptr, &display_count); + + if (display_count > 0) { + std::vector<CGDirectDisplayID> display_ids(display_count); + CGGetActiveDisplayList(display_count, display_ids.data(), &display_count); + + for (uint32_t i = 0; i < display_count; ++i) { + CGDirectDisplayID display_id = display_ids[i]; + + Monitor monitor; + monitor.id = static_cast<int>(display_id); + monitor.name = "Display " + std::to_string(i + 1); + + // Get display bounds + CGRect bounds = CGDisplayBounds(display_id); + monitor.x = static_cast<int>(bounds.origin.x); + monitor.y = static_cast<int>(bounds.origin.y); + monitor.width = static_cast<int>(bounds.size.width); + monitor.height = static_cast<int>(bounds.size.height); + + // Get refresh rate + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id); + if (mode) { + monitor.refresh_rate = static_cast<int>(CGDisplayModeGetRefreshRate(mode)); + CGDisplayModeRelease(mode); + } else { + monitor.refresh_rate = 60; // Default + } + + monitors.push_back(monitor); + + std::cout << "Monitor " << i << ": " << monitor.width << "x" << monitor.height + << " @ " << monitor.refresh_rate << "Hz" << std::endl; + } + } + + return monitors; +} + +Monitor MacOSPlatform::get_primary_monitor() { + auto monitors = get_monitors(); + if (!monitors.empty()) { + return monitors[0]; + } + + // Fallback to main display + CGDirectDisplayID main_display = CGMainDisplayID(); + CGRect bounds = CGDisplayBounds(main_display); + + Monitor monitor; + monitor.id = static_cast<int>(main_display); + monitor.name = "Main Display"; + monitor.x = static_cast<int>(bounds.origin.x); + monitor.y = static_cast<int>(bounds.origin.y); + monitor.width = static_cast<int>(bounds.size.width); + monitor.height = static_cast<int>(bounds.size.height); + monitor.refresh_rate = 60; // Default + + return monitor; +} + +void MacOSPlatform::grab_keyboard() { + // TODO: Implement keyboard grabbing + std::cout << "Keyboard grabbing setup" << std::endl; +} + +void MacOSPlatform::ungrab_keyboard() { + // TODO: Implement keyboard ungrab + std::cout << "Keyboard ungrab" << std::endl; +} + +void MacOSPlatform::grab_pointer() { + // TODO: Implement pointer grabbing + std::cout << "Pointer grabbing setup" << std::endl; +} + +void MacOSPlatform::ungrab_pointer() { + // TODO: Implement pointer ungrab + std::cout << "Pointer ungrab" << std::endl; +} + +// Static callback functions +CGEventRef MacOSPlatform::event_tap_callback(CGEventTapProxy proxy, CGEventType type, + CGEventRef event, void* user_info) { + MacOSPlatform* platform = static_cast<MacOSPlatform*>(user_info); + return platform->handle_event_tap(proxy, type, event); +} + +CGEventRef MacOSPlatform::handle_event_tap(CGEventTapProxy proxy, CGEventType type, CGEventRef event) { + switch (type) { + case kCGEventKeyDown: + handle_key_event(event, true); + break; + + case kCGEventKeyUp: + handle_key_event(event, false); + break; + + case kCGEventLeftMouseDown: + handle_mouse_event(event, true, 1); + break; + + case kCGEventLeftMouseUp: + handle_mouse_event(event, false, 1); + break; + + case kCGEventRightMouseDown: + handle_mouse_event(event, true, 2); + break; + + case kCGEventRightMouseUp: + handle_mouse_event(event, false, 2); + break; + + case kCGEventMouseMoved: + handle_mouse_motion(event); + break; + } + + return event; +} + +void MacOSPlatform::handle_key_event(CGEventRef event, bool pressed) { + // Get key code + CGKeyCode key_code = static_cast<CGKeyCode>(CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)); + + std::cout << "Key " << (pressed ? "press" : "release") << ": " << key_code << std::endl; + + // TODO: Convert to SRDWM key event +} + +void MacOSPlatform::handle_mouse_event(CGEventRef event, bool pressed, int button) { + // Get mouse position + CGPoint location = CGEventGetLocation(event); + + std::cout << "Mouse button " << button << " " << (pressed ? "down" : "up") + << " at (" << location.x << ", " << location.y << ")" << std::endl; + + // TODO: Convert to SRDWM button event +} + +void MacOSPlatform::handle_mouse_motion(CGEventRef event) { + // Get mouse position + CGPoint location = CGEventGetLocation(event); + + // TODO: Convert to SRDWM motion event +} + +// Utility methods +CGSRDWindowID MacOSPlatform::get_macos_window_id(SRDWindow* window) { + // TODO: Implement window ID retrieval + return 0; +} + +pid_t MacOSPlatform::get_macos_pid(SRDWindow* window) { + // TODO: Implement PID retrieval + return 0; +} + +void MacOSPlatform::update_window_monitoring() { + // TODO: Implement window monitoring update +} + +void MacOSPlatform::handle_window_created(CGSRDWindowID window_id) { + std::cout << "SRDWindow created: " << window_id << std::endl; + + // TODO: Create SRDWM window object and manage it +} + +void MacOSPlatform::handle_window_destroyed(CGSRDWindowID window_id) { + std::cout << "SRDWindow destroyed: " << window_id << std::endl; + + // TODO: Clean up SRDWM window object +} + +void MacOSPlatform::handle_window_focused(CGSRDWindowID window_id) { + std::cout << "SRDWindow focused: " << window_id << std::endl; + + // TODO: Handle window focus +} + +void MacOSPlatform::handle_window_moved(CGSRDWindowID window_id, int x, int y) { + std::cout << "SRDWindow " << window_id << " moved to (" << x << ", " << y << ")" << std::endl; + + // TODO: Handle window movement +} + +void MacOSPlatform::handle_window_resized(CGSRDWindowID window_id, int width, int height) { + std::cout << "SRDWindow " << window_id << " resized to " << width << "x" << height << std::endl; + + // TODO: Handle window resizing +} + + diff --git a/src/platform/macos_platform.h b/src/platform/macos_platform.h new file mode 100644 index 0000000..39dc3db --- /dev/null +++ b/src/platform/macos_platform.h @@ -0,0 +1,118 @@ +#ifndef SRDWM_MACOS_PLATFORM_H +#define SRDWM_MACOS_PLATFORM_H + +#include "platform.h" +#include <memory> +#include <string> +#include <map> + +// Forward declarations for macOS +#ifdef __APPLE__ +typedef struct CGSRDWindow* CGSRDWindowRef; +typedef struct CGEvent* CGEventRef; +typedef struct CGDisplay* CGDirectDisplayID; +typedef struct CGMenu* CGMenuRef; +typedef struct CGMenuBar* CGMenuBarRef; +#endif + +class MacOSPlatform : public Platform { +public: + MacOSPlatform(); + ~MacOSPlatform() override; + + // Platform interface implementation + bool initialize() override; + void shutdown() override; + + bool poll_events(std::vector<Event>& events) override; + void process_event(const Event& event) override; + + std::unique_ptr<SRDWindow> create_window(const std::string& title, int x, int y, int width, int height) override; + void destroy_window(SRDWindow* window) override; + void set_window_position(SRDWindow* window, int x, int y) override; + void set_window_size(SRDWindow* window, int width, int height) override; + void set_window_title(SRDWindow* window, const std::string& title) override; + void focus_window(SRDWindow* window) override; + void minimize_window(SRDWindow* window) override; + void maximize_window(SRDWindow* window) override; + void close_window(SRDWindow* window) override; + + std::vector<Monitor> get_monitors() override; + Monitor get_primary_monitor() override; + + void grab_keyboard() override; + void ungrab_keyboard() override; + void grab_pointer() override; + void ungrab_pointer() override; + + // SRDWindow decorations (macOS implementation) + void set_window_decorations(SRDWindow* window, bool enabled) override; + void set_window_border_color(SRDWindow* window, int r, int g, int b) override; + void set_window_border_width(SRDWindow* window, int width) override; + bool get_window_decorations(SRDWindow* window) const override; + + // macOS-specific features + void setup_global_menu(); + void update_global_menu(const std::string& app_name); + void set_menu_bar_visible(bool visible); + void set_dock_visible(bool visible); + void set_spaces_enabled(bool enabled); + void switch_to_space(int space_id); + int get_current_space() const; + std::vector<int> get_available_spaces() const; + + // Mission Control and Spaces + void show_mission_control(); + void show_app_expose(); + void show_desktop(); + + // Window management enhancements + void set_window_level(SRDWindow* window, int level); + void set_window_shadow(SRDWindow* window, bool enabled); + void set_window_blur(SRDWindow* window, bool enabled); + void set_window_alpha(SRDWindow* window, float alpha); + + std::string get_platform_name() const override; + bool is_wayland() const override; + bool is_x11() const override; + bool is_windows() const override; + bool is_macos() const override; + +private: + bool initialized_; + std::map<CGSRDWindowRef, SRDWindow*> window_map_; + std::vector<Monitor> monitors_; + + // Decoration state (macOS limitations) + bool decorations_enabled_; + std::map<CGSRDWindowRef, CGSRDWindowRef> overlay_window_map_; // window -> overlay + + // macOS-specific state + bool global_menu_enabled_; + bool dock_visible_; + bool spaces_enabled_; + CGMenuBarRef menu_bar_; + std::map<std::string, CGMenuRef> app_menus_; + + // Event handling + void setup_event_tap(); + void remove_event_tap(); + + // Monitor management + void update_monitors(); + + // Utility methods + SRDWindow* find_window_by_cgwindow(CGSRDWindowRef cgwindow); + + // Decoration methods (macOS limitations) + void create_overlay_window(SRDWindow* window); + void destroy_overlay_window(SRDWindow* window); + + // Global menu methods + void create_app_menu(const std::string& app_name); + void update_menu_bar(); + void handle_menu_event(CGEventRef event); +}; + +#endif // SRDWM_MACOS_PLATFORM_H + diff --git a/src/platform/platform.h b/src/platform/platform.h new file mode 100644 index 0000000..41cc6bf --- /dev/null +++ b/src/platform/platform.h @@ -0,0 +1,91 @@ +#ifndef SRDWM_PLATFORM_H +#define SRDWM_PLATFORM_H + +#include <memory> +#include <vector> +#include <string> +#include <functional> + +// Forward declarations +class SRDWindow; + +// Include Monitor struct definition from layouts +#include "../layouts/layout.h" + +// Platform-independent event types +enum class EventType { + WindowCreated, + WindowDestroyed, + WindowMoved, + WindowResized, + WindowFocused, + WindowUnfocused, + KeyPress, + KeyRelease, + MouseButtonPress, + MouseButtonRelease, + MouseMotion, + MonitorAdded, + MonitorRemoved +}; + +// Event structure +struct Event { + EventType type; + void* data; + size_t data_size; +}; + +// Platform abstraction interface +class Platform { +public: + virtual ~Platform() = default; + + // Initialization and cleanup + virtual bool initialize() = 0; + virtual void shutdown() = 0; + + // Event handling + virtual bool poll_events(std::vector<Event>& events) = 0; + virtual void process_event(const Event& event) = 0; + + // Window management + virtual std::unique_ptr<SRDWindow> create_window(const std::string& title, int x, int y, int width, int height) = 0; + virtual void destroy_window(SRDWindow* window) = 0; + virtual void set_window_position(SRDWindow* window, int x, int y) = 0; + virtual void set_window_size(SRDWindow* window, int width, int height) = 0; + virtual void set_window_title(SRDWindow* window, const std::string& title) = 0; + virtual void focus_window(SRDWindow* window) = 0; + virtual void minimize_window(SRDWindow* window) = 0; + virtual void maximize_window(SRDWindow* window) = 0; + virtual void close_window(SRDWindow* window) = 0; + + // Window decorations (cross-platform) + virtual void set_window_decorations(SRDWindow* window, bool enabled) = 0; + virtual void set_window_border_color(SRDWindow* window, int r, int g, int b) = 0; + virtual void set_window_border_width(SRDWindow* window, int width) = 0; + virtual bool get_window_decorations(SRDWindow* window) const = 0; + + // Monitor management + virtual std::vector<Monitor> get_monitors() = 0; + virtual Monitor get_primary_monitor() = 0; + + // Input handling + virtual void grab_keyboard() = 0; + virtual void ungrab_keyboard() = 0; + virtual void grab_pointer() = 0; + virtual void ungrab_pointer() = 0; + + // Utility + virtual std::string get_platform_name() const = 0; + virtual bool is_wayland() const = 0; + virtual bool is_x11() const = 0; + virtual bool is_windows() const = 0; + virtual bool is_macos() const = 0; +}; + +// Forward declaration +class PlatformFactory; + +#endif // SRDWM_PLATFORM_H + diff --git a/src/platform/platform_factory.cc b/src/platform/platform_factory.cc new file mode 100644 index 0000000..ef1981a --- /dev/null +++ b/src/platform/platform_factory.cc @@ -0,0 +1,214 @@ +#include "platform_factory.h" +#include <iostream> +#include <cstring> +#include <cstdlib> +#include <algorithm> + +// Platform-specific includes +#ifdef LINUX_PLATFORM + #include "x11_platform.h" + #ifdef WAYLAND_ENABLED + #include "wayland_platform.h" + #endif +#elif defined(WIN32_PLATFORM) + #include "windows_platform.h" +#elif defined(MACOS_PLATFORM) + #include "macos_platform.h" +#endif + +std::unique_ptr<Platform> PlatformFactory::create_platform() { + #ifdef _WIN32 + std::cout << "Creating SRDWindows platform..." << std::endl; + return std::make_unique<SRDWindowsPlatform>(); + + #elif defined(__APPLE__) + std::cout << "Creating macOS platform..." << std::endl; + return std::make_unique<MacOSPlatform>(); + + #else + // Linux: detect X11 vs Wayland + return detect_linux_platform(); + #endif +} + +std::unique_ptr<Platform> PlatformFactory::create_platform(const std::string& platform_name) { + std::cout << "Creating platform: " << platform_name << std::endl; + + if (platform_name == "x11" || platform_name == "X11") { + #ifdef LINUX_PLATFORM + return std::make_unique<X11Platform>(); + #else + std::cerr << "X11 platform not available on this system" << std::endl; + return nullptr; + #endif + + } else if (platform_name == "wayland" || platform_name == "Wayland") { + #ifdef WAYLAND_ENABLED + return std::make_unique<WaylandPlatform>(); + #else + std::cerr << "Wayland platform not available on this system" << std::endl; + return nullptr; + #endif + + } else if (platform_name == "windows" || platform_name == "SRDWindows") { + #ifdef WIN32_PLATFORM + return std::make_unique<SRDWindowsPlatform>(); + #else + std::cerr << "SRDWindows platform not available on this system" << std::endl; + return nullptr; + #endif + + } else if (platform_name == "macos" || platform_name == "macOS") { + #ifdef MACOS_PLATFORM + return std::make_unique<MacOSPlatform>(); + #else + std::cerr << "macOS platform not available on this system" << std::endl; + return nullptr; + #endif + + } else { + std::cerr << "Unknown platform: " << platform_name << std::endl; + std::cerr << "Available platforms: x11, wayland, windows, macos" << std::endl; + return nullptr; + } +} + +std::unique_ptr<Platform> PlatformFactory::detect_linux_platform() { + std::cout << "Detecting Linux platform..." << std::endl; + + // Check environment variables for Wayland + const char* wayland_display = std::getenv("WAYLAND_DISPLAY"); + const char* xdg_session_type = std::getenv("XDG_SESSION_TYPE"); + const char* display = std::getenv("DISPLAY"); + + std::cout << "Environment variables:" << std::endl; + std::cout << " WAYLAND_DISPLAY: " << (wayland_display ? wayland_display : "not set") << std::endl; + std::cout << " XDG_SESSION_TYPE: " << (xdg_session_type ? xdg_session_type : "not set") << std::endl; + std::cout << " DISPLAY: " << (display ? display : "not set") << std::endl; + + // Try Wayland first if environment suggests it + if (wayland_display || (xdg_session_type && strcmp(xdg_session_type, "wayland") == 0)) { + std::cout << "Wayland environment detected, attempting Wayland initialization..." << std::endl; + + #ifdef WAYLAND_ENABLED + auto wayland_platform = std::make_unique<WaylandPlatform>(); + if (wayland_platform->initialize()) { + std::cout << "✓ Wayland platform initialized successfully" << std::endl; + return wayland_platform; + } else { + std::cout << "✗ Wayland initialization failed, falling back to X11" << std::endl; + } + #else + std::cout << "Wayland support not compiled in, falling back to X11" << std::endl; + #endif + } + + // Fall back to X11 + std::cout << "Attempting X11 initialization..." << std::endl; + + #ifdef LINUX_PLATFORM + auto x11_platform = std::make_unique<X11Platform>(); + if (x11_platform->initialize()) { + std::cout << "✓ X11 platform initialized successfully" << std::endl; + return x11_platform; + } else { + std::cout << "✗ X11 initialization failed" << std::endl; + } + #else + std::cout << "X11 support not compiled in" << std::endl; + #endif + + std::cerr << "Failed to initialize any platform backend" << std::endl; + return nullptr; +} + +std::vector<std::string> PlatformFactory::get_available_platforms() { + std::vector<std::string> platforms; + + #ifdef LINUX_PLATFORM + platforms.push_back("x11"); + #ifdef WAYLAND_ENABLED + platforms.push_back("wayland"); + #endif + #endif + + #ifdef WIN32_PLATFORM + platforms.push_back("windows"); + #endif + + #ifdef MACOS_PLATFORM + platforms.push_back("macos"); + #endif + + return platforms; +} + +std::string PlatformFactory::get_current_platform() { + #ifdef _WIN32 + return "windows"; + #elif defined(__APPLE__) + return "macos"; + #else + // Check if we're running on Wayland + const char* wayland_display = std::getenv("WAYLAND_DISPLAY"); + const char* xdg_session_type = std::getenv("XDG_SESSION_TYPE"); + + if (wayland_display || (xdg_session_type && strcmp(xdg_session_type, "wayland") == 0)) { + return "wayland"; + } else { + return "x11"; + } + #endif +} + +bool PlatformFactory::is_platform_available(const std::string& platform_name) { + auto available = get_available_platforms(); + return std::find(available.begin(), available.end(), platform_name) != available.end(); +} + +void PlatformFactory::print_platform_info() { + std::cout << "\n=== Platform Information ===" << std::endl; + std::cout << "Current platform: " << get_current_platform() << std::endl; + + auto available = get_available_platforms(); + std::cout << "Available platforms: "; + for (size_t i = 0; i < available.size(); ++i) { + if (i > 0) std::cout << ", "; + std::cout << available[i]; + } + std::cout << std::endl; + + std::cout << "Environment variables:" << std::endl; + const char* wayland_display = std::getenv("WAYLAND_DISPLAY"); + const char* xdg_session_type = std::getenv("XDG_SESSION_TYPE"); + const char* display = std::getenv("DISPLAY"); + + std::cout << " WAYLAND_DISPLAY: " << (wayland_display ? wayland_display : "not set") << std::endl; + std::cout << " XDG_SESSION_TYPE: " << (xdg_session_type ? xdg_session_type : "not set") << std::endl; + std::cout << " DISPLAY: " << (display ? display : "not set") << std::endl; + + #ifdef LINUX_PLATFORM + std::cout << "Linux platform support: Enabled" << std::endl; + #ifdef WAYLAND_ENABLED + std::cout << "Wayland support: Enabled" << std::endl; + #else + std::cout << "Wayland support: Disabled" << std::endl; + #endif + #else + std::cout << "Linux platform support: Disabled" << std::endl; + #endif + + #ifdef WIN32_PLATFORM + std::cout << "SRDWindows platform support: Enabled" << std::endl; + #else + std::cout << "SRDWindows platform support: Disabled" << std::endl; + #endif + + #ifdef MACOS_PLATFORM + std::cout << "macOS platform support: Enabled" << std::endl; + #else + std::cout << "macOS platform support: Disabled" << std::endl; + #endif + + std::cout << "=============================" << std::endl; +} diff --git a/src/platform/platform_factory.h b/src/platform/platform_factory.h new file mode 100644 index 0000000..24f7586 --- /dev/null +++ b/src/platform/platform_factory.h @@ -0,0 +1,37 @@ +#ifndef SRDWM_PLATFORM_FACTORY_H +#define SRDWM_PLATFORM_FACTORY_H + +#include "platform.h" +#include <memory> +#include <string> +#include <vector> + +// Platform factory for creating platform-specific implementations +class PlatformFactory { +public: + // Create platform with automatic detection + static std::unique_ptr<Platform> create_platform(); + + // Create specific platform by name + static std::unique_ptr<Platform> create_platform(const std::string& platform_name); + + // Get list of available platforms + static std::vector<std::string> get_available_platforms(); + + // Get current platform name + static std::string get_current_platform(); + + // Check if platform is available + static bool is_platform_available(const std::string& platform_name); + + // Print platform information + static void print_platform_info(); + +private: + // Linux platform detection + static std::unique_ptr<Platform> detect_linux_platform(); +}; + +#endif // SRDWM_PLATFORM_FACTORY_H + + diff --git a/src/platform/wayland_platform.cc b/src/platform/wayland_platform.cc new file mode 100644 index 0000000..2e4a591 --- /dev/null +++ b/src/platform/wayland_platform.cc @@ -0,0 +1,507 @@ +#include "wayland_platform.h" +#include <iostream> +#include <cstring> +#include <cstdint> + +#ifndef USE_WAYLAND_STUB +#include <wayland-server-core.h> +extern "C" { + // Minimal wlroots declarations to avoid pulling C99-only headers into C++ + struct wlr_backend; + struct wlr_renderer; + struct wlr_compositor; + struct wlr_seat; + struct wlr_xdg_shell; + + // Logging + int wlr_log_init(int verbosity, void* callback); + + // Backend + struct wlr_backend* wlr_backend_autocreate(struct wl_display* display, void* session); + bool wlr_backend_start(struct wlr_backend* backend); + void wlr_backend_destroy(struct wlr_backend* backend); + struct wlr_renderer* wlr_backend_get_renderer(struct wlr_backend* backend); + + // Compositor and seat + struct wlr_compositor* wlr_compositor_create(struct wl_display* display, uint32_t version, struct wlr_renderer* renderer); + struct wlr_seat* wlr_seat_create(struct wl_display* display, const char* name); + + // xdg-shell + struct wlr_xdg_shell* wlr_xdg_shell_create(struct wl_display* display, uint32_t version); + struct wlr_renderer* wlr_renderer_autocreate(struct wlr_backend* backend); + void wlr_renderer_init_wl_display(struct wlr_renderer* renderer, struct wl_display* display); + + // Wayland display helpers (for C++ compilation) + struct wl_display* wl_display_create(void); + void wl_display_destroy(struct wl_display* display); + int wl_display_dispatch_pending(struct wl_display* display); + void wl_display_flush_clients(struct wl_display* display); +} +#endif + +// Static member initialization +WaylandPlatform* WaylandPlatform::instance_ = nullptr; + +WaylandPlatform::WaylandPlatform() + : display_(nullptr) + , registry_(nullptr) + , compositor_(nullptr) + , shm_(nullptr) + , seat_(nullptr) + , output_(nullptr) + , shell_(nullptr) + , backend_(nullptr) + , renderer_(nullptr) + , wlr_compositor_(nullptr) + , output_layout_(nullptr) + , cursor_(nullptr) + , xcursor_manager_(nullptr) + , wlr_seat_(nullptr) + , xdg_shell_(nullptr) + // , layer_shell_(nullptr) + , event_loop_running_(false) { + + instance_ = this; +} + +WaylandPlatform::~WaylandPlatform() { + shutdown(); + if (instance_ == this) { + instance_ = nullptr; + } +} + +bool WaylandPlatform::initialize() { +#ifndef USE_WAYLAND_STUB + std::cout << "Initializing Wayland platform (wlroots real backend)..." << std::endl; + // Create Wayland display + display_ = wl_display_create(); + if (!display_) { + std::cerr << "Failed to create wl_display" << std::endl; + return false; + } + + // Initialize wlroots logging (optional) - 2 corresponds to INFO + wlr_log_init(2, nullptr); + + // Create backend (auto-detect e.g., DRM, Wayland, X11) + backend_ = wlr_backend_autocreate(display_, nullptr); + if (!backend_) { + std::cerr << "Failed to create wlr_backend" << std::endl; + return false; + } + + // Create renderer and hook to display + renderer_ = wlr_renderer_autocreate(backend_); + if (!renderer_) { + std::cerr << "Failed to create wlr_renderer" << std::endl; + return false; + } + wlr_renderer_init_wl_display(renderer_, display_); + + // Create compositor (wlroots 0.17 requires protocol version). Use version 6. + wlr_compositor_ = wlr_compositor_create(display_, 6, renderer_); + if (!wlr_compositor_) { + std::cerr << "Failed to create wlr_compositor" << std::endl; + return false; + } + + // Create seat (input) + wlr_seat_ = wlr_seat_create(display_, "seat0"); + if (!wlr_seat_) { + std::cerr << "Failed to create wlr_seat" << std::endl; + return false; + } + + // Create xdg-shell (requires protocol version) + xdg_shell_ = wlr_xdg_shell_create(display_, 6); + if (!xdg_shell_) { + std::cerr << "Failed to create wlr_xdg_shell" << std::endl; + return false; + } + + // Minimal bring-up: listeners will be wired in a follow-up + + // Start backend + if (!wlr_backend_start(backend_)) { + std::cerr << "Failed to start wlr_backend" << std::endl; + return false; + } + + decorations_enabled_ = true; + std::cout << "Wayland (wlroots) backend started." << std::endl; + return true; +#else + // Minimal Wayland backend initialization (no wlroots API calls). + std::cout << "Initializing Wayland platform (minimal stub)..." << std::endl; + decorations_enabled_ = true; + std::cout << "Wayland platform initialized (stub)." << std::endl; + return true; +#endif +} + +void WaylandPlatform::shutdown() { +#ifndef USE_WAYLAND_STUB + std::cout << "Shutting down Wayland platform (wlroots)..." << std::endl; + if (xdg_shell_) { xdg_shell_ = nullptr; } + // Seat is tied to display lifecycle; skip explicit destroy to avoid ABI issues + wlr_seat_ = nullptr; + if (wlr_compositor_) { /* wlr_compositor is owned by display, no explicit destroy */ wlr_compositor_ = nullptr; } + // Renderer is owned by backend in this path; no explicit destroy + renderer_ = nullptr; + if (backend_) { wlr_backend_destroy(backend_); backend_ = nullptr; } + if (display_) { wl_display_destroy(display_); display_ = nullptr; } +#else + std::cout << "Shutting down Wayland platform (stub)..." << std::endl; +#endif +} + +bool WaylandPlatform::setup_wlroots_backend() { std::cout << "wlroots backend (stub)" << std::endl; return true; } + +bool WaylandPlatform::setup_compositor() { std::cout << "compositor (stub)" << std::endl; return true; } + +// (removed unused stub-only setup_output/setup_input in real backend path) + +bool WaylandPlatform::setup_shell_protocols() { std::cout << "shell protocols (stub)" << std::endl; return true; } + +// bool WaylandPlatform::setup_xwayland() { return true; } + +bool WaylandPlatform::poll_events(std::vector<Event>& events) { +#ifndef USE_WAYLAND_STUB + if (!display_ || !backend_) return false; + events.clear(); + // Dispatch Wayland events; non-blocking to integrate with app loop + wl_display_dispatch_pending(display_); + wl_display_flush_clients(display_); + return true; +#else + events.clear(); + return true; +#endif +} + +void WaylandPlatform::process_event(const Event& event) { + // TODO: Implement event processing +} + +std::unique_ptr<SRDWindow> WaylandPlatform::create_window(const std::string& title, int x, int y, int width, int height) { + // TODO: Implement window creation + std::cout << "Creating Wayland window: " << title << std::endl; + return nullptr; +} + +void WaylandPlatform::destroy_window(SRDWindow* window) { + // TODO: Implement window destruction + std::cout << "Destroying Wayland window" << std::endl; +} + +void WaylandPlatform::set_window_position(SRDWindow* window, int x, int y) { + // TODO: Implement window positioning +} + +void WaylandPlatform::set_window_size(SRDWindow* window, int width, int height) { + // TODO: Implement window resizing +} + +void WaylandPlatform::set_window_title(SRDWindow* window, const std::string& title) { + // TODO: Implement title setting +} + +void WaylandPlatform::focus_window(SRDWindow* window) { + // TODO: Implement window focusing +} + +void WaylandPlatform::minimize_window(SRDWindow* window) { + // TODO: Implement window minimization +} + +void WaylandPlatform::maximize_window(SRDWindow* window) { + // TODO: Implement window maximization +} + +void WaylandPlatform::close_window(SRDWindow* window) { + // TODO: Implement window closing +} + +std::vector<Monitor> WaylandPlatform::get_monitors() { + // TODO: Implement monitor detection + return {}; +} + +Monitor WaylandPlatform::get_primary_monitor() { + // TODO: Implement primary monitor detection + return Monitor{}; +} + +void WaylandPlatform::grab_keyboard() { + // TODO: Implement keyboard grabbing +} + +void WaylandPlatform::ungrab_keyboard() { + // TODO: Implement keyboard ungrab +} + +void WaylandPlatform::grab_pointer() { + // TODO: Implement pointer grabbing +} + +void WaylandPlatform::ungrab_pointer() { + // TODO: Implement pointer ungrab +} + +// Static callback functions +void WaylandPlatform::registry_global_handler(void* data, struct wl_registry* registry, + uint32_t name, const char* interface, uint32_t version) { + (void)registry; (void)name; (void)interface; (void)version; + WaylandPlatform* platform = static_cast<WaylandPlatform*>(data); + platform->handle_registry_global(nullptr, 0, interface ? interface : "", 0); +} + +void WaylandPlatform::registry_global_remove_handler(void* data, struct wl_registry* registry, uint32_t name) { + (void)registry; (void)name; + WaylandPlatform* platform = static_cast<WaylandPlatform*>(data); + platform->handle_registry_global_remove(nullptr, 0); +} + +void WaylandPlatform::xdg_surface_new_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_xdg_surface_new(static_cast<struct wlr_xdg_surface*>(data)); + } +} + +void WaylandPlatform::xdg_surface_destroy_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_xdg_surface_destroy(static_cast<struct wlr_xdg_surface*>(data)); + } +} + +void WaylandPlatform::xdg_toplevel_new_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_xdg_toplevel_new(static_cast<struct wlr_xdg_toplevel*>(data)); + } +} + +void WaylandPlatform::xdg_toplevel_destroy_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_xdg_toplevel_destroy(static_cast<struct wlr_xdg_toplevel*>(data)); + } +} + +// (removed xwayland handlers; not declared while XWayland is disabled) + +void WaylandPlatform::output_new_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_output_new(static_cast<struct wlr_output*>(data)); + } +} + +void WaylandPlatform::output_destroy_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_output_destroy(static_cast<struct wlr_output*>(data)); + } +} + +void WaylandPlatform::output_frame_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_output_frame(static_cast<struct wlr_output*>(data)); + } +} + +void WaylandPlatform::pointer_motion_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_pointer_motion(static_cast<struct wlr_pointer_motion_event*>(data)); + } +} + +void WaylandPlatform::pointer_button_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_pointer_button(static_cast<struct wlr_pointer_button_event*>(data)); + } +} + +void WaylandPlatform::pointer_axis_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_pointer_axis(static_cast<struct wlr_pointer_axis_event*>(data)); + } +} + +void WaylandPlatform::keyboard_key_handler(struct wl_listener* listener, void* data) { + (void)listener; + if (WaylandPlatform::instance_) { + WaylandPlatform::instance_->handle_keyboard_key(static_cast<struct wlr_keyboard_key_event*>(data)); + } +} + +// Event handling methods +void WaylandPlatform::handle_registry_global(struct wl_registry* registry, uint32_t name, + const char* interface, uint32_t version) { + (void)registry; (void)name; (void)version; + std::cout << "Registry global (stub): " << (interface ? interface : "?") << std::endl; +} + +void WaylandPlatform::handle_registry_global_remove(struct wl_registry* registry, uint32_t name) { + (void)registry; (void)name; +} + +void WaylandPlatform::handle_xdg_surface_new(struct wlr_xdg_surface* surface) { + std::cout << "New XDG surface" << std::endl; + manage_xdg_window(surface); +} + +void WaylandPlatform::handle_xdg_surface_destroy(struct wlr_xdg_surface* surface) { + std::cout << "XDG surface destroyed" << std::endl; +} + +void WaylandPlatform::handle_xdg_toplevel_new(struct wlr_xdg_toplevel* toplevel) { + std::cout << "New XDG toplevel" << std::endl; +} + +void WaylandPlatform::handle_xdg_toplevel_destroy(struct wlr_xdg_toplevel* toplevel) { + std::cout << "XDG toplevel destroyed" << std::endl; +} + +// void WaylandPlatform::handle_xwayland_surface_new(struct wlr_xwayland_surface* surface) {} + +// void WaylandPlatform::handle_xwayland_surface_destroy(struct wlr_xwayland_surface* surface) {} + +void WaylandPlatform::handle_output_new(struct wlr_output* output) { + std::cout << "New output" << std::endl; + handle_output_mode(output); +} + +void WaylandPlatform::handle_output_destroy(struct wlr_output* output) { + std::cout << "Output destroyed" << std::endl; +} + +void WaylandPlatform::handle_output_frame(struct wlr_output* output) { + // Handle output frame event +} + +void WaylandPlatform::handle_pointer_motion(struct wlr_pointer_motion_event* event) { + // Handle pointer motion +} + +void WaylandPlatform::handle_pointer_button(struct wlr_pointer_button_event* event) { + // Handle pointer button +} + +void WaylandPlatform::handle_pointer_axis(struct wlr_pointer_axis_event* event) { + // Handle pointer axis +} + +void WaylandPlatform::handle_keyboard_key(struct wlr_keyboard_key_event* event) { + // Handle keyboard key +} + +void WaylandPlatform::manage_xdg_window(struct wlr_xdg_surface* surface) { + // TODO: Implement XDG window management +} + +// void WaylandPlatform::manage_xwayland_window(struct wlr_xwayland_surface* surface) {} + +void WaylandPlatform::unmanage_window(SRDWindow* window) { + // TODO: Implement window unmanagement +} + +void WaylandPlatform::handle_output_mode(struct wlr_output* output) { + // TODO: Implement output mode handling +} + +void WaylandPlatform::handle_output_scale(struct wlr_output* output) { + // TODO: Implement output scale handling +} + +void WaylandPlatform::handle_key_event(uint32_t key, bool pressed) { + // TODO: Implement key event handling +} + +void WaylandPlatform::handle_button_event(uint32_t button, bool pressed) { + // TODO: Implement button event handling +} + +void WaylandPlatform::create_surface_window(struct wlr_surface* surface) { + // TODO: Implement surface window creation +} + +void WaylandPlatform::destroy_surface_window(struct wlr_surface* surface) { + // TODO: Implement surface window destruction +} + +void WaylandPlatform::update_surface_window(struct wlr_surface* surface) { + // TODO: Implement surface window update +} + +void WaylandPlatform::convert_wlroots_event_to_srdwm_event(void* event_data, EventType type) { + // TODO: Implement event conversion +} + +void WaylandPlatform::handle_wlroots_error(const std::string& error) { + std::cerr << "wlroots error: " << error << std::endl; +} + +// SRDWindow decoration implementations +void WaylandPlatform::set_window_decorations(SRDWindow* window, bool enabled) { + // Temporary stub: wlroots xdg-decoration v1 helpers differ across versions. + // Keep internal state and log, skip calling decoration APIs. + std::cout << "WaylandPlatform: Set window decorations " << (enabled ? "enabled" : "disabled") << std::endl; + (void)window; // unused for now + decorations_enabled_ = enabled; +} + +void WaylandPlatform::set_window_border_color(SRDWindow* window, int r, int g, int b) { + std::cout << "WaylandPlatform: Set border color RGB(" << r << "," << g << "," << b << ")" << std::endl; + + if (!window || !renderer_) return; + + // Store border color for this window + // In a full implementation, this would be stored in a window-specific data structure + // and applied during rendering + + // For now, we'll just log the request + // TODO: Implement custom border rendering via wlroots rendering pipeline + std::cout << "Border color set for window " << window->getId() + << ": RGB(" << r << "," << g << "," << b << ")" << std::endl; +} + +void WaylandPlatform::set_window_border_width(SRDWindow* window, int width) { + std::cout << "WaylandPlatform: Set border width " << width << std::endl; + + if (!window) return; + + // TODO: Implement when wlroots rendering is set up + // This would involve drawing custom borders on surfaces +} + +bool WaylandPlatform::get_window_decorations(SRDWindow* window) const { + if (!window) return false; + + return decorations_enabled_; +} + +void WaylandPlatform::setup_decoration_manager() { + // Temporary stub: skip creating xdg-decoration manager to avoid + // wlroots API/ABI differences across distro versions. + std::cout << "Decoration manager (stub) initialized" << std::endl; +} + +void WaylandPlatform::handle_decoration_request(struct wlr_xdg_surface* surface, uint32_t mode) { + std::cout << "Handling decoration request, mode: " << mode << std::endl; + + // TODO: Implement when zxdg-decoration protocol is available + // This would involve: + // 1. Checking if server-side decorations are enabled + // 2. Setting the decoration mode for the surface + // 3. Drawing decorations if needed +} + + diff --git a/src/platform/wayland_platform.h b/src/platform/wayland_platform.h new file mode 100644 index 0000000..3df5867 --- /dev/null +++ b/src/platform/wayland_platform.h @@ -0,0 +1,227 @@ +#ifndef SRDWM_WAYLAND_PLATFORM_H +#define SRDWM_WAYLAND_PLATFORM_H + +#include "platform.h" +#ifndef USE_WAYLAND_STUB +#include <wayland-server-core.h> +#endif +// Forward-declare Wayland and wlroots types to avoid version-specific headers. +struct wl_display; struct wl_registry; struct wl_compositor; struct wl_shm; struct wl_seat; struct wl_output; struct wl_shell; struct wl_listener; struct wl_surface; +struct wlr_backend; struct wlr_renderer; struct wlr_compositor; struct wlr_output_layout; struct wlr_cursor; struct wlr_xcursor_manager; struct wlr_seat; +struct wlr_xdg_shell; struct wlr_xdg_surface; struct wlr_xdg_toplevel; +struct wlr_output; struct wlr_pointer_motion_event; struct wlr_pointer_button_event; struct wlr_pointer_axis_event; struct wlr_keyboard_key_event; +struct wlr_xdg_decoration_manager_v1; +#include <map> +#include <memory> +#include <vector> + +// Forward declarations +class SRDWindow; +class Monitor; + +// Wayland-specific platform implementation +class WaylandPlatform : public Platform { +public: + WaylandPlatform(); + ~WaylandPlatform(); + + // Platform interface implementation + bool initialize() override; + void shutdown() override; + + // Event handling + bool poll_events(std::vector<Event>& events) override; + void process_event(const Event& event) override; + + // SRDWindow management + std::unique_ptr<SRDWindow> create_window(const std::string& title, int x, int y, int width, int height) override; + void destroy_window(SRDWindow* window) override; + void set_window_position(SRDWindow* window, int x, int y) override; + void set_window_size(SRDWindow* window, int width, int height) override; + void set_window_title(SRDWindow* window, const std::string& title) override; + void focus_window(SRDWindow* window) override; + void minimize_window(SRDWindow* window) override; + void maximize_window(SRDWindow* window) override; + void close_window(SRDWindow* window) override; + + // Monitor management + std::vector<Monitor> get_monitors() override; + Monitor get_primary_monitor() override; + + // Input handling + void grab_keyboard() override; + void ungrab_keyboard() override; + void grab_pointer() override; + void ungrab_pointer() override; + + // Utility + // SRDWindow decorations (Wayland implementation) + void set_window_decorations(SRDWindow* window, bool enabled) override; + void set_window_border_color(SRDWindow* window, int r, int g, int b) override; + void set_window_border_width(SRDWindow* window, int width) override; + bool get_window_decorations(SRDWindow* window) const override; + + std::string get_platform_name() const override { return "Wayland"; } + bool is_wayland() const override { return true; } + bool is_x11() const override { return false; } + bool is_windows() const override { return false; } + bool is_macos() const override { return false; } + +private: + static WaylandPlatform* instance_; + // Wayland-specific members + struct wl_display* display_; + struct wl_registry* registry_; + struct wl_compositor* compositor_; + struct wl_shm* shm_; + struct wl_seat* seat_; + struct wl_output* output_; + struct wl_shell* shell_; + + // wlroots backend + struct wlr_backend* backend_; + struct wlr_renderer* renderer_; + struct wlr_compositor* wlr_compositor_; + struct wlr_output_layout* output_layout_; + struct wlr_cursor* cursor_; + struct wlr_xcursor_manager* xcursor_manager_; + struct wlr_seat* wlr_seat_; + + // Shell protocols + struct wlr_xdg_shell* xdg_shell_; + // struct wlr_layer_shell_v1* layer_shell_; + + // XWayland support (temporarily disabled) + // struct wlr_xwayland* xwayland_; + // struct wlr_xwayland_server* xwayland_server_; + + // SRDWindow tracking + std::map<struct wlr_surface*, SRDWindow*> surface_window_map_; + std::map<struct wlr_xdg_surface*, SRDWindow*> xdg_window_map_; + // std::map<struct wlr_xwayland_surface*, SRDWindow*> xwayland_window_map_; + + // Monitor information + std::vector<Monitor> monitors_; + Monitor primary_monitor_; + + // Event handling + bool event_loop_running_; + std::vector<Event> pending_events_; + + // Private methods + bool setup_wlroots_backend(); + bool setup_compositor(); + bool setup_shell_protocols(); + // bool setup_xwayland(); + + // Event handling + void handle_registry_global(struct wl_registry* registry, uint32_t name, + const char* interface, uint32_t version); + void handle_registry_global_remove(struct wl_registry* registry, uint32_t name); + + // Shell protocol handlers + void handle_xdg_surface_new(struct wlr_xdg_surface* surface); + void handle_xdg_surface_destroy(struct wlr_xdg_surface* surface); + void handle_xdg_toplevel_new(struct wlr_xdg_toplevel* toplevel); + void handle_xdg_toplevel_destroy(struct wlr_xdg_toplevel* toplevel); + + // XWayland handlers (temporarily disabled) + // void handle_xwayland_surface_new(struct wlr_xwayland_surface* surface); + // void handle_xwayland_surface_destroy(struct wlr_xwayland_surface* surface); + + // Output handlers + void handle_output_new(struct wlr_output* output); + void handle_output_destroy(struct wlr_output* output); + void handle_output_frame(struct wlr_output* output); + + // Input handlers + void handle_pointer_motion(struct wlr_pointer_motion_event* event); + void handle_pointer_button(struct wlr_pointer_button_event* event); + void handle_pointer_axis(struct wlr_pointer_axis_event* event); + void handle_keyboard_key(struct wlr_keyboard_key_event* event); + + // SRDWindow management helpers + SRDWindow* find_window_by_surface(struct wlr_surface* surface); + SRDWindow* find_window_by_xdg_surface(struct wlr_xdg_surface* surface); + // SRDWindow* find_window_by_xwayland_surface(struct wlr_xwayland_surface* surface); + void manage_xdg_window(struct wlr_xdg_surface* surface); + // void manage_xwayland_window(struct wlr_xwayland_surface* surface); + void unmanage_window(SRDWindow* window); + + // Monitor helpers + void update_monitor_info(); + void handle_output_mode(struct wlr_output* output); + void handle_output_scale(struct wlr_output* output); + + // Input helpers + void setup_keyboard_grab(); + void setup_pointer_grab(); + void handle_key_event(uint32_t key, bool pressed); + void handle_button_event(uint32_t button, bool pressed); + + // Utility helpers + void create_surface_window(struct wlr_surface* surface); + void destroy_surface_window(struct wlr_surface* surface); + void update_surface_window(struct wlr_surface* surface); + + // Event conversion + void convert_wlroots_event_to_srdwm_event(void* event_data, EventType type); + + // Error handling + void handle_wlroots_error(const std::string& error); + + // Decoration methods + void setup_decoration_manager(); + void handle_decoration_request(struct wlr_xdg_surface* surface, uint32_t mode); + + // Static callback functions + static void registry_global_handler(void* data, struct wl_registry* registry, + uint32_t name, const char* interface, uint32_t version); + static void registry_global_remove_handler(void* data, struct wl_registry* registry, uint32_t name); + + static void xdg_surface_new_handler(struct wl_listener* listener, void* data); + static void xdg_surface_destroy_handler(struct wl_listener* listener, void* data); + static void xdg_toplevel_new_handler(struct wl_listener* listener, void* data); + static void xdg_toplevel_destroy_handler(struct wl_listener* listener, void* data); + + // static void xwayland_surface_new_handler(struct wl_listener* listener, void* data); + // static void xwayland_surface_destroy_handler(struct wl_listener* listener, void* data); + + static void output_new_handler(struct wl_listener* listener, void* data); + static void output_destroy_handler(struct wl_listener* listener, void* data); + static void output_frame_handler(struct wl_listener* listener, void* data); + + static void pointer_motion_handler(struct wl_listener* listener, void* data); + static void pointer_button_handler(struct wl_listener* listener, void* data); + static void pointer_axis_handler(struct wl_listener* listener, void* data); + static void keyboard_key_handler(struct wl_listener* listener, void* data); + + // Event listeners removed in stubbed build to avoid wl_listener dependency + // wlroots event listeners (instantiated only in real Wayland path) + #ifndef USE_WAYLAND_STUB + struct wl_listener xdg_surface_new_listener_; + struct wl_listener xdg_surface_destroy_listener_; + struct wl_listener xdg_toplevel_new_listener_; + struct wl_listener xdg_toplevel_destroy_listener_; + struct wl_listener output_new_listener_; + struct wl_listener output_destroy_listener_; + struct wl_listener output_frame_listener_; + struct wl_listener pointer_motion_listener_; + struct wl_listener pointer_button_listener_; + struct wl_listener pointer_axis_listener_; + struct wl_listener keyboard_key_listener_; + #endif + + // Decoration state + bool decorations_enabled_; + struct wlr_xdg_decoration_manager_v1* decoration_manager_; + + // struct wl_listener xwayland_new_surface; + // struct wl_listener xwayland_destroy; + + // Additional listeners removed in stubbed build +}; + +#endif // SRDWM_WAYLAND_PLATFORM_H + + diff --git a/src/platform/wayland_platform_stub.cc b/src/platform/wayland_platform_stub.cc new file mode 100644 index 0000000..bdf6ee9 --- /dev/null +++ b/src/platform/wayland_platform_stub.cc @@ -0,0 +1,114 @@ +#include "wayland_platform.h" +#include <iostream> +#include <cstdint> + +WaylandPlatform* WaylandPlatform::instance_ = nullptr; + +WaylandPlatform::WaylandPlatform() + : display_(nullptr) + , registry_(nullptr) + , compositor_(nullptr) + , shm_(nullptr) + , seat_(nullptr) + , output_(nullptr) + , shell_(nullptr) + , backend_(nullptr) + , renderer_(nullptr) + , wlr_compositor_(nullptr) + , output_layout_(nullptr) + , cursor_(nullptr) + , xcursor_manager_(nullptr) + , wlr_seat_(nullptr) + , xdg_shell_(nullptr) + , event_loop_running_(false) + , decorations_enabled_(true) + , decoration_manager_(nullptr) { + instance_ = this; +} + +WaylandPlatform::~WaylandPlatform() { + shutdown(); + if (instance_ == this) instance_ = nullptr; +} + +bool WaylandPlatform::initialize() { + std::cout << "Wayland (stub): initialize" << std::endl; + decorations_enabled_ = true; + return true; +} + +void WaylandPlatform::shutdown() { + std::cout << "Wayland (stub): shutdown" << std::endl; +} + +bool WaylandPlatform::poll_events(std::vector<Event>& events) { + events.clear(); + return true; +} + +void WaylandPlatform::process_event(const Event& /*event*/) {} + +std::unique_ptr<SRDWindow> WaylandPlatform::create_window(const std::string& title, int, int, int, int) { + std::cout << "Wayland (stub): create_window '" << title << "'" << std::endl; + return nullptr; +} + +void WaylandPlatform::destroy_window(SRDWindow*) {} +void WaylandPlatform::set_window_position(SRDWindow*, int, int) {} +void WaylandPlatform::set_window_size(SRDWindow*, int, int) {} +void WaylandPlatform::set_window_title(SRDWindow*, const std::string&) {} +void WaylandPlatform::focus_window(SRDWindow*) {} +void WaylandPlatform::minimize_window(SRDWindow*) {} +void WaylandPlatform::maximize_window(SRDWindow*) {} +void WaylandPlatform::close_window(SRDWindow*) {} +std::vector<Monitor> WaylandPlatform::get_monitors() { return {}; } +Monitor WaylandPlatform::get_primary_monitor() { return Monitor{}; } +void WaylandPlatform::grab_keyboard() {} +void WaylandPlatform::ungrab_keyboard() {} +void WaylandPlatform::grab_pointer() {} +void WaylandPlatform::ungrab_pointer() {} +void WaylandPlatform::set_window_decorations(SRDWindow*, bool enabled) { decorations_enabled_ = enabled; } +void WaylandPlatform::set_window_border_color(SRDWindow*, int, int, int) {} +void WaylandPlatform::set_window_border_width(SRDWindow*, int) {} +bool WaylandPlatform::get_window_decorations(SRDWindow*) const { return decorations_enabled_; } + +// Private helpers (stubs) +bool WaylandPlatform::setup_wlroots_backend() { return true; } +bool WaylandPlatform::setup_compositor() { return true; } +bool WaylandPlatform::setup_shell_protocols() { return true; } +void WaylandPlatform::handle_registry_global(struct wl_registry*, uint32_t, const char*, uint32_t) {} +void WaylandPlatform::handle_registry_global_remove(struct wl_registry*, uint32_t) {} +void WaylandPlatform::handle_xdg_surface_new(struct wlr_xdg_surface*) {} +void WaylandPlatform::handle_xdg_surface_destroy(struct wlr_xdg_surface*) {} +void WaylandPlatform::handle_xdg_toplevel_new(struct wlr_xdg_toplevel*) {} +void WaylandPlatform::handle_xdg_toplevel_destroy(struct wlr_xdg_toplevel*) {} +void WaylandPlatform::handle_output_new(struct wlr_output*) {} +void WaylandPlatform::handle_output_destroy(struct wlr_output*) {} +void WaylandPlatform::handle_output_frame(struct wlr_output*) {} +void WaylandPlatform::handle_pointer_motion(struct wlr_pointer_motion_event*) {} +void WaylandPlatform::handle_pointer_button(struct wlr_pointer_button_event*) {} +void WaylandPlatform::handle_pointer_axis(struct wlr_pointer_axis_event*) {} +void WaylandPlatform::keyboard_key_handler(struct wl_listener*, void*) {} +void WaylandPlatform::pointer_motion_handler(struct wl_listener*, void*) {} +void WaylandPlatform::pointer_button_handler(struct wl_listener*, void*) {} +void WaylandPlatform::pointer_axis_handler(struct wl_listener*, void*) {} +void WaylandPlatform::output_new_handler(struct wl_listener*, void*) {} +void WaylandPlatform::output_destroy_handler(struct wl_listener*, void*) {} +void WaylandPlatform::output_frame_handler(struct wl_listener*, void*) {} +void WaylandPlatform::xdg_surface_new_handler(struct wl_listener*, void*) {} +void WaylandPlatform::xdg_surface_destroy_handler(struct wl_listener*, void*) {} +void WaylandPlatform::xdg_toplevel_new_handler(struct wl_listener*, void*) {} +void WaylandPlatform::xdg_toplevel_destroy_handler(struct wl_listener*, void*) {} +void WaylandPlatform::manage_xdg_window(struct wlr_xdg_surface*) {} +void WaylandPlatform::unmanage_window(SRDWindow*) {} +void WaylandPlatform::handle_output_mode(struct wlr_output*) {} +void WaylandPlatform::handle_output_scale(struct wlr_output*) {} +void WaylandPlatform::handle_key_event(uint32_t, bool) {} +void WaylandPlatform::handle_button_event(uint32_t, bool) {} +void WaylandPlatform::create_surface_window(struct wlr_surface*) {} +void WaylandPlatform::destroy_surface_window(struct wlr_surface*) {} +void WaylandPlatform::update_surface_window(struct wlr_surface*) {} +void WaylandPlatform::convert_wlroots_event_to_srdwm_event(void*, EventType) {} +void WaylandPlatform::handle_wlroots_error(const std::string&) {} +void WaylandPlatform::setup_decoration_manager() {} +void WaylandPlatform::handle_decoration_request(struct wlr_xdg_surface*, uint32_t) {} diff --git a/src/platform/windows_platform.cc b/src/platform/windows_platform.cc new file mode 100644 index 0000000..11cadca --- /dev/null +++ b/src/platform/windows_platform.cc @@ -0,0 +1,585 @@ +#include "windows_platform.h" +#include <iostream> +#include <windows.h> +#include <dwmapi.h> + +// Static member initialization +SRDWindowsPlatform* SRDWindowsPlatform::instance_ = nullptr; + +SRDWindowsPlatform::SRDWindowsPlatform() + : h_instance_(nullptr) + , keyboard_hook_(nullptr) + , mouse_hook_(nullptr) { + + instance_ = this; +} + +SRDWindowsPlatform::~SRDWindowsPlatform() { + shutdown(); + if (instance_ == this) { + instance_ = nullptr; + } +} + +bool SRDWindowsPlatform::initialize() { + std::cout << "Initializing SRDWindows platform..." << std::endl; + + // Get module handle + h_instance_ = GetModuleHandle(nullptr); + if (!h_instance_) { + std::cerr << "Failed to get module handle" << std::endl; + return false; + } + + // Register window class + if (!register_window_class()) { + std::cerr << "Failed to register window class" << std::endl; + return false; + } + + // Setup global hooks + setup_global_hooks(); + + std::cout << "SRDWindows platform initialized successfully" << std::endl; + return true; +} + +void SRDWindowsPlatform::shutdown() { + std::cout << "Shutting down SRDWindows platform..." << std::endl; + + // Unhook global hooks + if (keyboard_hook_) { + UnhookSRDWindowsHookEx(keyboard_hook_); + keyboard_hook_ = nullptr; + } + + if (mouse_hook_) { + UnhookSRDWindowsHookEx(mouse_hook_); + mouse_hook_ = nullptr; + } + + // Clean up windows + for (auto& pair : window_map_) { + if (pair.second) { + delete pair.second; + } + } + window_map_.clear(); + + std::cout << "SRDWindows platform shutdown complete" << std::endl; +} + +// SRDWindow decoration implementations +void SRDWindowsPlatform::set_window_decorations(SRDWindow* window, bool enabled) { + std::cout << "SRDWindowsPlatform: Set window decorations " << (enabled ? "enabled" : "disabled") << std::endl; + + if (!window) return; + + // Find the HWND for this window + HWND hwnd = nullptr; + for (const auto& pair : window_map_) { + if (pair.second == window) { + hwnd = pair.first; + break; + } + } + + if (!hwnd) return; + + decorations_enabled_ = enabled; + + if (enabled) { + // Enable native window decorations + LONG style = GetSRDWindowLong(hwnd, GWL_STYLE); + style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + SetSRDWindowLong(hwnd, GWL_STYLE, style); + } else { + // Disable native window decorations + LONG style = GetSRDWindowLong(hwnd, GWL_STYLE); + style &= ~(WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + SetSRDWindowLong(hwnd, GWL_STYLE, style); + } + + // Force window redraw + SetSRDWindowPos(hwnd, nullptr, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); +} + +void SRDWindowsPlatform::set_window_border_color(SRDWindow* window, int r, int g, int b) { + std::cout << "SRDWindowsPlatform: Set border color RGB(" << r << "," << g << "," << b << ")" << std::endl; + + if (!window) return; + + // Find the HWND for this window + HWND hwnd = nullptr; + for (const auto& pair : window_map_) { + if (pair.second == window) { + hwnd = pair.first; + break; + } + } + + if (!hwnd) return; + + COLORREF color = RGB(r, g, b); + apply_dwm_border_color(hwnd, r, g, b); +} + +void SRDWindowsPlatform::set_window_border_width(SRDWindow* window, int width) { + std::cout << "SRDWindowsPlatform: Set border width " << width << std::endl; + + if (!window) return; + + border_width_ = width; + + // SRDWindows doesn't support custom border widths via DWM + // This would need to be implemented with custom window frames +} + +bool SRDWindowsPlatform::get_window_decorations(SRDWindow* window) const { + if (!window) return false; + + return decorations_enabled_; +} + +void SRDWindowsPlatform::apply_dwm_border_color(HWND hwnd, int r, int g, int b) { + // Use DWM API to set border color (SRDWindows 11 feature) + COLORREF color = RGB(r, g, b); + + HRESULT result = DwmSetSRDWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color)); + if (FAILED(result)) { + std::cerr << "Failed to set DWM border color" << std::endl; + } +} + +void SRDWindowsPlatform::remove_dwm_border_color(HWND hwnd) { + // Remove custom border color + COLORREF color = DWMWA_COLOR_DEFAULT; + + HRESULT result = DwmSetSRDWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color)); + if (FAILED(result)) { + std::cerr << "Failed to remove DWM border color" << std::endl; + } +} + +bool SRDWindowsPlatform::register_window_class() { + WNDCLASSEX wc = {}; + wc.cbSize = sizeof(WNDCLASSEX); + wc.lpfnWndProc = window_proc; + wc.hInstance = h_instance_; + wc.lpszClassName = L"SRDWM_SRDWindow"; + wc.hCursor = LoadCursor(nullptr, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.style = CS_HREDRAW | CS_VREDRAW; + + return RegisterClassEx(&wc) != 0; +} + +void SRDWindowsPlatform::setup_global_hooks() { + std::cout << "Setting up global hooks..." << std::endl; + + // Global keyboard hook + keyboard_hook_ = SetSRDWindowsHookEx(WH_KEYBOARD_LL, + keyboard_proc, h_instance_, 0); + if (!keyboard_hook_) { + std::cerr << "Failed to set keyboard hook" << std::endl; + } + + // Global mouse hook + mouse_hook_ = SetSRDWindowsHookEx(WH_MOUSE_LL, + mouse_proc, h_instance_, 0); + if (!mouse_hook_) { + std::cerr << "Failed to set mouse hook" << std::endl; + } + + std::cout << "Global hooks setup complete" << std::endl; +} + +LRESULT CALLBACK SRDWindowsPlatform::window_proc(HWND hwnd, UINT msg, + WPARAM wparam, LPARAM lparam) { + switch (msg) { + case WM_CREATE: + std::cout << "SRDWindow created: " << hwnd << std::endl; + break; + + case WM_DESTROY: + std::cout << "SRDWindow destroyed: " << hwnd << std::endl; + break; + + case WM_SIZE: + // Handle window resizing + break; + + case WM_MOVE: + // Handle window moving + break; + + case WM_SETFOCUS: + // Handle window focus + break; + + case WM_KILLFOCUS: + // Handle window unfocus + break; + + case WM_CLOSE: + // Handle window close request + break; + + default: + return DefSRDWindowProc(hwnd, msg, wparam, lparam); + } + return 0; +} + +LRESULT CALLBACK SRDWindowsPlatform::keyboard_proc(int nCode, WPARAM wparam, LPARAM lparam) { + if (nCode >= 0) { + KBDLLHOOKSTRUCT* kbhs = (KBDLLHOOKSTRUCT*)lparam; + + if (wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN) { + std::cout << "Key pressed: " << kbhs->vkCode << std::endl; + } else if (wparam == WM_KEYUP || wparam == WM_SYSKEYUP) { + std::cout << "Key released: " << kbhs->vkCode << std::endl; + } + } + return CallNextHookEx(nullptr, nCode, wparam, lparam); +} + +LRESULT CALLBACK SRDWindowsPlatform::mouse_proc(int nCode, WPARAM wparam, LPARAM lparam) { + if (nCode >= 0) { + MSLLHOOKSTRUCT* mhs = (MSLLHOOKSTRUCT*)lparam; + + switch (wparam) { + case WM_LBUTTONDOWN: + std::cout << "Left mouse button down at (" << mhs->pt.x << ", " << mhs->pt.y << ")" << std::endl; + break; + + case WM_LBUTTONUP: + std::cout << "Left mouse button up at (" << mhs->pt.x << ", " << mhs->pt.y << ")" << std::endl; + break; + + case WM_RBUTTONDOWN: + std::cout << "Right mouse button down at (" << mhs->pt.x << ", " << mhs->pt.y << ")" << std::endl; + break; + + case WM_RBUTTONUP: + std::cout << "Right mouse button up at (" << mhs->pt.x << ", " << mhs->pt.y << ")" << std::endl; + break; + + case WM_MOUSEMOVE: + // Handle mouse movement + break; + } + } + return CallNextHookEx(nullptr, nCode, wparam, lparam); +} + +void SRDWindowsPlatform::convert_win32_message(UINT msg, WPARAM wparam, LPARAM lparam, std::vector<Event>& events) { + Event event; + + switch (msg) { + case WM_CREATE: + event.type = EventType::SRDWindowCreated; + break; + case WM_DESTROY: + event.type = EventType::SRDWindowDestroyed; + break; + case WM_MOVE: + event.type = EventType::SRDWindowMoved; + break; + case WM_SIZE: + event.type = EventType::SRDWindowResized; + break; + case WM_SETFOCUS: + event.type = EventType::SRDWindowFocused; + break; + case WM_KILLFOCUS: + event.type = EventType::SRDWindowUnfocused; + break; + case WM_KEYDOWN: + event.type = EventType::KeyPress; + break; + case WM_KEYUP: + event.type = EventType::KeyRelease; + break; + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + event.type = EventType::MouseButtonPress; + break; + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + event.type = EventType::MouseButtonRelease; + break; + case WM_MOUSEMOVE: + event.type = EventType::MouseMotion; + break; + default: + return; // Skip unknown messages + } + + event.data = nullptr; + event.data_size = 0; + events.push_back(event); +} + +bool SRDWindowsPlatform::poll_events(std::vector<Event>& events) { + if (!initialized_) return false; + + events.clear(); + + // Process SRDWindows messages + MSG msg; + while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + + // Convert SRDWindows message to SRDWM event + convert_win32_message(msg.message, msg.wParam, msg.lParam, events); + } + + return !events.empty(); +} + +void SRDWindowsPlatform::process_event(const Event& event) { + // TODO: Implement event processing +} + +std::unique_ptr<SRDWindow> SRDWindowsPlatform::create_window(const std::string& title, int x, int y, int width, int height) { + // Convert title to wide string + int title_len = MultiByteToWideChar(CP_UTF8, 0, title.c_str(), -1, nullptr, 0); + std::wstring wtitle(title_len, 0); + MultiByteToWideChar(CP_UTF8, 0, title.c_str(), -1, &wtitle[0], title_len); + + // Create window + HWND hwnd = CreateSRDWindowEx( + WS_EX_OVERLAPPEDWINDOW, + L"SRDWM_SRDWindow", + wtitle.c_str(), + WS_OVERLAPPEDWINDOW, + x, y, width, height, + nullptr, nullptr, h_instance_, nullptr + ); + + if (!hwnd) { + std::cerr << "Failed to create SRDWindows window" << std::endl; + return nullptr; + } + + // Create SRDWM window object + auto window = std::make_unique<SRDWindow>(); + // TODO: Set window properties + + // Store window mapping + window_map_[hwnd] = window.get(); + + std::cout << "Created SRDWindows window: " << hwnd << " (" << title << ")" << std::endl; + return window; +} + +void SRDWindowsPlatform::destroy_window(SRDWindow* window) { + // Find window handle + for (auto& pair : window_map_) { + if (pair.second == window) { + DestroySRDWindow(pair.first); + window_map_.erase(pair.first); + break; + } + } +} + +void SRDWindowsPlatform::set_window_position(SRDWindow* window, int x, int y) { + // Find window handle + for (auto& pair : window_map_) { + if (pair.second == window) { + SetSRDWindowPos(pair.first, nullptr, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + break; + } + } +} + +void SRDWindowsPlatform::set_window_size(SRDWindow* window, int width, int height) { + // Find window handle + for (auto& pair : window_map_) { + if (pair.second == window) { + SetSRDWindowPos(pair.first, nullptr, 0, 0, width, height, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + break; + } + } +} + +void SRDWindowsPlatform::set_window_title(SRDWindow* window, const std::string& title) { + // Find window handle + for (auto& pair : window_map_) { + if (pair.second == window) { + // Convert title to wide string + int title_len = MultiByteToWideChar(CP_UTF8, 0, title.c_str(), -1, nullptr, 0); + std::wstring wtitle(title_len, 0); + MultiByteToWideChar(CP_UTF8, 0, title.c_str(), -1, &wtitle[0], title_len); + + SetSRDWindowText(pair.first, wtitle.c_str()); + break; + } + } +} + +void SRDWindowsPlatform::focus_window(SRDWindow* window) { + // Find window handle + for (auto& pair : window_map_) { + if (pair.second == window) { + SetForegroundSRDWindow(pair.first); + SetFocus(pair.first); + break; + } + } +} + +void SRDWindowsPlatform::minimize_window(SRDWindow* window) { + // Find window handle + for (auto& pair : window_map_) { + if (pair.second == window) { + ShowSRDWindow(pair.first, SW_MINIMIZE); + break; + } + } +} + +void SRDWindowsPlatform::maximize_window(SRDWindow* window) { + // Find window handle + for (auto& pair : window_map_) { + if (pair.second == window) { + ShowSRDWindow(pair.first, SW_MAXIMIZE); + break; + } + } +} + +void SRDWindowsPlatform::close_window(SRDWindow* window) { + // Find window handle + for (auto& pair : window_map_) { + if (pair.second == window) { + PostMessage(pair.first, WM_CLOSE, 0, 0); + break; + } + } +} + +std::vector<Monitor> SRDWindowsPlatform::get_monitors() { + std::vector<Monitor> monitors; + + // Enumerate monitors using EnumDisplayMonitors + EnumDisplayMonitors(nullptr, nullptr, + [](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL { + auto* monitors = reinterpret_cast<std::vector<Monitor>*>(dwData); + + MONITORINFOEX monitorInfo; + monitorInfo.cbSize = sizeof(MONITORINFOEX); + GetMonitorInfo(hMonitor, &monitorInfo); + + Monitor monitor; + monitor.id = reinterpret_cast<int>(hMonitor); + monitor.name = std::string(monitorInfo.szDevice); + monitor.x = monitorInfo.rcMonitor.left; + monitor.y = monitorInfo.rcMonitor.top; + monitor.width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left; + monitor.height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top; + monitor.refresh_rate = 60; // TODO: Get actual refresh rate + + monitors->push_back(monitor); + + return TRUE; + }, reinterpret_cast<LPARAM>(&monitors)); + + return monitors; +} + +Monitor SRDWindowsPlatform::get_primary_monitor() { + auto monitors = get_monitors(); + if (!monitors.empty()) { + return monitors[0]; + } + + // Fallback to primary display + Monitor monitor; + monitor.id = 0; + monitor.name = "Primary Display"; + monitor.x = 0; + monitor.y = 0; + monitor.width = GetSystemMetrics(SM_CXSCREEN); + monitor.height = GetSystemMetrics(SM_CYSCREEN); + monitor.refresh_rate = 60; + + return monitor; +} + +void SRDWindowsPlatform::grab_keyboard() { + // TODO: Implement keyboard grabbing + std::cout << "Keyboard grabbing setup" << std::endl; +} + +void SRDWindowsPlatform::ungrab_keyboard() { + // TODO: Implement keyboard ungrab + std::cout << "Keyboard ungrab" << std::endl; +} + +void SRDWindowsPlatform::grab_pointer() { + // TODO: Implement pointer grabbing + std::cout << "Pointer grabbing setup" << std::endl; +} + +void SRDWindowsPlatform::ungrab_pointer() { + // TODO: Implement pointer ungrab + std::cout << "Pointer ungrab" << std::endl; +} + +void SRDWindowsPlatform::convert_windows_message_to_event(const MSG& msg, std::vector<Event>& events) { + // TODO: Convert SRDWindows messages to SRDWM events + switch (msg.message) { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + // Convert to key press event + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + // Convert to key release event + break; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + // Convert to button press event + break; + + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + // Convert to button release event + break; + + case WM_MOUSEMOVE: + // Convert to mouse motion event + break; + + case WM_SIZE: + // Convert to window resize event + break; + + case WM_MOVE: + // Convert to window move event + break; + } +} + +void SRDWindowsPlatform::handle_global_keyboard(WPARAM wparam, KBDLLHOOKSTRUCT* kbhs) { + // TODO: Implement global keyboard handling +} + +void SRDWindowsPlatform::handle_global_mouse(WPARAM wparam, MSLLHOOKSTRUCT* mhs) { + // TODO: Implement global mouse handling +} + + diff --git a/src/platform/windows_platform.h b/src/platform/windows_platform.h new file mode 100644 index 0000000..70b7d54 --- /dev/null +++ b/src/platform/windows_platform.h @@ -0,0 +1,140 @@ +#ifndef SRDWM_WINDOWS_PLATFORM_H +#define SRDWM_WINDOWS_PLATFORM_H + +#include "platform.h" +#include <windows.h> +#include <memory> +#include <string> +#include <map> + +class SRDWindowsPlatform : public Platform { +public: + SRDWindowsPlatform(); + ~SRDWindowsPlatform() override; + + // Platform interface implementation + bool initialize() override; + void shutdown() override; + + bool poll_events(std::vector<Event>& events) override; + void process_event(const Event& event) override; + + std::unique_ptr<SRDWindow> create_window(const std::string& title, int x, int y, int width, int height) override; + void destroy_window(SRDWindow* window) override; + void set_window_position(SRDWindow* window, int x, int y) override; + void set_window_size(SRDWindow* window, int width, int height) override; + void set_window_title(SRDWindow* window, const std::string& title) override; + void focus_window(SRDWindow* window) override; + void minimize_window(SRDWindow* window) override; + void maximize_window(SRDWindow* window) override; + void close_window(SRDWindow* window) override; + + std::vector<Monitor> get_monitors() override; + Monitor get_primary_monitor() override; + + void grab_keyboard() override; + void ungrab_keyboard() override; + void grab_pointer() override; + void ungrab_pointer() override; + + // SRDWindow decorations (SRDWindows implementation) + void set_window_decorations(SRDWindow* window, bool enabled) override; + void set_window_border_color(SRDWindow* window, int r, int g, int b) override; + void set_window_border_width(SRDWindow* window, int width) override; + bool get_window_decorations(SRDWindow* window) const override; + + // Windows-specific features + void enable_dwm_composition(bool enabled); + void set_dwm_window_attribute(HWND hwnd, DWORD attribute, DWORD value); + void set_dwm_window_thumbnail(HWND hwnd, HWND thumbnail_hwnd); + void set_dwm_window_peek(HWND hwnd, bool enabled); + + // Virtual Desktop support (Windows 10+) + void create_virtual_desktop(); + void remove_virtual_desktop(int desktop_id); + void switch_to_virtual_desktop(int desktop_id); + int get_current_virtual_desktop() const; + std::vector<int> get_virtual_desktops() const; + void move_window_to_desktop(SRDWindow* window, int desktop_id); + + // Taskbar integration + void set_taskbar_visible(bool visible); + void set_taskbar_position(int position); // 0=bottom, 1=top, 2=left, 3=right + void set_taskbar_auto_hide(bool enabled); + void update_taskbar_preview(HWND hwnd, const std::string& title); + + // Aero effects + void enable_aero_effects(bool enabled); + void set_window_transparency(HWND hwnd, BYTE alpha); + void set_window_blur(HWND hwnd, bool enabled); + void set_window_shadow(HWND hwnd, bool enabled); + + // System tray integration + void add_system_tray_icon(const std::string& tooltip, HICON icon); + void remove_system_tray_icon(); + void show_system_tray_menu(HMENU menu); + + std::string get_platform_name() const override; + bool is_wayland() const override; + bool is_x11() const override; + bool is_windows() const override; + bool is_macos() const override; + +private: + bool initialized_; + HINSTANCE h_instance_; + std::map<HWND, SRDWindow*> window_map_; + std::vector<Monitor> monitors_; + + // Decoration state + bool decorations_enabled_; + int border_width_; + COLORREF border_color_; + COLORREF focused_border_color_; + + // Windows-specific state + bool dwm_enabled_; + bool aero_enabled_; + bool taskbar_visible_; + bool taskbar_auto_hide_; + int taskbar_position_; + int current_virtual_desktop_; + std::vector<int> virtual_desktops_; + NOTIFYICONDATA system_tray_icon_; + + // SRDWindow class registration + bool register_window_class(); + void unregister_window_class(); + + // SRDWindow procedure + static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); + + // Event conversion + void convert_win32_message(UINT msg, WPARAM wparam, LPARAM lparam, std::vector<Event>& events); + + // Monitor enumeration + static BOOL CALLBACK enum_monitor_proc(HMONITOR hmonitor, HDC hdc_monitor, LPRECT lprc_monitor, LPARAM dw_data); + + // Utility methods + void update_monitors(); + SRDWindow* find_window_by_hwnd(HWND hwnd); + + // Decoration methods + void apply_dwm_border_color(HWND hwnd, int r, int g, int b); + void remove_dwm_border_color(HWND hwnd); + + // Virtual Desktop methods + void initialize_virtual_desktops(); + void cleanup_virtual_desktops(); + + // DWM methods + bool initialize_dwm(); + void cleanup_dwm(); + + // Taskbar methods + void initialize_taskbar(); + void update_taskbar(); +}; + +#endif // SRDWM_WINDOWS_PLATFORM_H + diff --git a/src/platform/x11_platform.cc b/src/platform/x11_platform.cc new file mode 100644 index 0000000..0d25369 --- /dev/null +++ b/src/platform/x11_platform.cc @@ -0,0 +1,1005 @@ +#include "x11_platform.h" +#include <iostream> +#include <cstring> + +X11Platform::X11Platform() { + std::cout << "X11Platform: Constructor called" << std::endl; +} + +X11Platform::~X11Platform() { + std::cout << "X11Platform: Destructor called" << std::endl; +} + +bool X11Platform::initialize() { + std::cout << "X11Platform: Initializing X11 backend..." << std::endl; + + // Open X11 display + display_ = XOpenDisplay(nullptr); + if (!display_) { + std::cerr << "Failed to open X11 display" << std::endl; + return false; + } + + // Get root window + root_ = DefaultRootWindow(display_); + + // Check for other window manager + if (!check_for_other_wm()) { + std::cerr << "Another window manager is already running" << std::endl; + return false; + } + + // Setup X11 environment + if (!setup_x11_environment()) { + std::cerr << "Failed to setup X11 environment" << std::endl; + return false; + } + + // Setup event masks + if (!setup_event_masks()) { + std::cerr << "Failed to setup event masks" << std::endl; + return false; + } + + // Setup atoms + setup_atoms(); + + // Setup extensions + setup_extensions(); + + // Initialize decoration state + decorations_enabled_ = true; + border_width_ = 2; + border_color_ = 0x2e3440; // Default border color + focused_border_color_ = 0x88c0d0; // Default focused border color + + std::cout << "X11Platform: Initialized successfully" << std::endl; + return true; +} + +void X11Platform::shutdown() { + std::cout << "X11Platform: Shutting down..." << std::endl; + + // Clean up windows + for (auto& pair : window_map_) { + if (pair.second) { + destroy_window(pair.second); + } + } + window_map_.clear(); + frame_window_map_.clear(); + + // Close X11 display + if (display_) { + XCloseDisplay(display_); + display_ = nullptr; + } + + std::cout << "X11Platform: Shutdown complete" << std::endl; +} + +bool X11Platform::poll_events(std::vector<Event>& events) { + if (!display_) return false; + + events.clear(); + + // Check for pending events + if (XPending(display_) > 0) { + XEvent xevent; + XNextEvent(display_, &xevent); + + // Handle the X11 event + handle_x11_event(xevent); + + // Convert to SRDWM events (simplified for now) + Event event; + event.type = EventType::WindowCreated; // Placeholder + event.data = nullptr; + event.data_size = 0; + events.push_back(event); + + return true; + } + + return false; +} + +void X11Platform::process_event(const Event& event) { + std::cout << "X11Platform: Process event called" << std::endl; +} + +std::unique_ptr<SRDWindow> X11Platform::create_window(const std::string& title, int x, int y, int width, int height) { + std::cout << "X11Platform: Create window called" << std::endl; + // TODO: Implement actual window creation when headers are available + return nullptr; +} + +void X11Platform::destroy_window(SRDWindow* window) { + std::cout << "X11Platform: Destroy window called" << std::endl; +} + +void X11Platform::set_window_position(SRDWindow* window, int x, int y) { + std::cout << "X11Platform: Set window position to (" << x << "," << y << ")" << std::endl; + if (!window || !display_) return; + X11Window x11_window = static_cast<X11Window>(window->getId()); + XMoveWindow(display_, to_x11_window(x11_window), x, y); + XFlush(display_); +} + +void X11Platform::set_window_size(SRDWindow* window, int width, int height) { + std::cout << "X11Platform: Set window size to (" << width << "x" << height << ")" << std::endl; + if (!window || !display_) return; + X11Window x11_window = static_cast<X11Window>(window->getId()); + XResizeWindow(display_, to_x11_window(x11_window), static_cast<unsigned int>(width), static_cast<unsigned int>(height)); + XFlush(display_); +} + +void X11Platform::set_window_title(SRDWindow* window, const std::string& title) { + std::cout << "X11Platform: Set window title to '" << title << "'" << std::endl; + if (!window || !display_) return; + X11Window x11_window = static_cast<X11Window>(window->getId()); + XStoreName(display_, to_x11_window(x11_window), title.c_str()); + XFlush(display_); +} + +void X11Platform::focus_window(SRDWindow* window) { + std::cout << "X11Platform: Focus window" << std::endl; + if (!window || !display_) return; + X11Window x11_window = static_cast<X11Window>(window->getId()); + XSetInputFocus(display_, to_x11_window(x11_window), RevertToParent, CurrentTime); + XFlush(display_); +} + +void X11Platform::minimize_window(SRDWindow* window) { + std::cout << "X11Platform: Minimize window called" << std::endl; +} + +void X11Platform::maximize_window(SRDWindow* window) { + std::cout << "X11Platform: Maximize window called" << std::endl; +} + +void X11Platform::close_window(SRDWindow* window) { + std::cout << "X11Platform: Close window" << std::endl; + if (!window || !display_) return; + X11Window x11_window = static_cast<X11Window>(window->getId()); + Atom wm_delete = XInternAtom(display_, "WM_DELETE_WINDOW", False); + if (wm_delete != None) { + XEvent ev{}; + ev.xclient.type = ClientMessage; + ev.xclient.message_type = XInternAtom(display_, "WM_PROTOCOLS", False); + ev.xclient.display = display_; + ev.xclient.window = to_x11_window(x11_window); + ev.xclient.format = 32; + ev.xclient.data.l[0] = wm_delete; + ev.xclient.data.l[1] = CurrentTime; + XSendEvent(display_, to_x11_window(x11_window), False, NoEventMask, &ev); + XFlush(display_); + } else { + XDestroyWindow(display_, to_x11_window(x11_window)); + XFlush(display_); + } +} + +// EWMH (Extended Window Manager Hints) support implementation +void X11Platform::set_ewmh_supported(bool supported) { + ewmh_supported_ = supported; + if (supported) { + setup_ewmh(); + } + std::cout << "X11Platform: EWMH support " << (supported ? "enabled" : "disabled") << std::endl; +} + +void X11Platform::set_window_type(SRDWindow* window, const std::string& type) { + if (!ewmh_supported_ || !window) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + Atom window_type_atom = None; + + if (type == "desktop") window_type_atom = _NET_WM_WINDOW_TYPE_DESKTOP_; + else if (type == "dock") window_type_atom = _NET_WM_WINDOW_TYPE_DOCK_; + else if (type == "toolbar") window_type_atom = _NET_WM_WINDOW_TYPE_TOOLBAR_; + else if (type == "menu") window_type_atom = _NET_WM_WINDOW_TYPE_MENU_; + else if (type == "utility") window_type_atom = _NET_WM_WINDOW_TYPE_UTILITY_; + else if (type == "splash") window_type_atom = _NET_WM_WINDOW_TYPE_SPLASH_; + else if (type == "dialog") window_type_atom = _NET_WM_WINDOW_TYPE_DIALOG_; + else if (type == "dropdown_menu") window_type_atom = _NET_WM_WINDOW_TYPE_DROPDOWN_MENU_; + else if (type == "popup_menu") window_type_atom = _NET_WM_WINDOW_TYPE_POPUP_MENU_; + else if (type == "tooltip") window_type_atom = _NET_WM_WINDOW_TYPE_TOOLTIP_; + else if (type == "notification") window_type_atom = _NET_WM_WINDOW_TYPE_NOTIFICATION_; + else if (type == "combo") window_type_atom = _NET_WM_WINDOW_TYPE_COMBO_; + else if (type == "dnd") window_type_atom = _NET_WM_WINDOW_TYPE_DND_; + else window_type_atom = _NET_WM_WINDOW_TYPE_NORMAL_; + + if (window_type_atom != None) { + XChangeProperty(display_, x11_window, _NET_WM_WINDOW_TYPE_, XA_ATOM, 32, + PropModeReplace, (unsigned char*)&window_type_atom, 1); + } +} + +void X11Platform::set_window_state(SRDWindow* window, const std::vector<std::string>& states) { + if (!ewmh_supported_ || !window) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + std::vector<Atom> state_atoms; + + for (const auto& state : states) { + Atom state_atom = None; + if (state == "maximized_vert") state_atom = _NET_WM_STATE_MAXIMIZED_VERT_; + else if (state == "maximized_horz") state_atom = _NET_WM_STATE_MAXIMIZED_HORZ_; + else if (state == "fullscreen") state_atom = _NET_WM_STATE_FULLSCREEN_; + else if (state == "above") state_atom = _NET_WM_STATE_ABOVE_; + else if (state == "below") state_atom = _NET_WM_STATE_BELOW_; + + if (state_atom != None) { + state_atoms.push_back(state_atom); + } + } + + if (!state_atoms.empty()) { + XChangeProperty(display_, x11_window, _NET_WM_STATE_, XA_ATOM, 32, + PropModeReplace, (unsigned char*)state_atoms.data(), state_atoms.size()); + } +} + +void X11Platform::set_window_strut(SRDWindow* window, int left, int right, int top, int bottom) { + if (!ewmh_supported_ || !window) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + long strut[12] = {left, right, top, bottom, 0, 0, 0, 0, 0, 0, 0, 0}; + + XChangeProperty(display_, x11_window, XInternAtom(display_, "_NET_WM_STRUT_PARTIAL", False), + XA_CARDINAL, 32, PropModeReplace, (unsigned char*)strut, 12); +} + +// Virtual Desktop support implementation +void X11Platform::create_virtual_desktop(const std::string& name) { + if (!ewmh_supported_) return; + + int desktop_id = virtual_desktops_.size(); + virtual_desktops_.push_back(desktop_id); + + // Update EWMH desktop info + update_ewmh_desktop_info(); + + std::cout << "X11Platform: Created virtual desktop " << desktop_id << " (" << name << ")" << std::endl; +} + +void X11Platform::remove_virtual_desktop(int desktop_id) { + if (!ewmh_supported_) return; + + auto it = std::find(virtual_desktops_.begin(), virtual_desktops_.end(), desktop_id); + if (it != virtual_desktops_.end()) { + virtual_desktops_.erase(it); + + // If removing current desktop, switch to first available + if (desktop_id == current_virtual_desktop_ && !virtual_desktops_.empty()) { + switch_to_virtual_desktop(virtual_desktops_[0]); + } + + update_ewmh_desktop_info(); + std::cout << "X11Platform: Removed virtual desktop " << desktop_id << std::endl; + } +} + +void X11Platform::switch_to_virtual_desktop(int desktop_id) { + if (!ewmh_supported_) return; + + auto it = std::find(virtual_desktops_.begin(), virtual_desktops_.end(), desktop_id); + if (it != virtual_desktops_.end()) { + current_virtual_desktop_ = desktop_id; + + // Update EWMH current desktop + XChangeProperty(display_, root_, _NET_CURRENT_DESKTOP_, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)¤t_virtual_desktop_, 1); + + std::cout << "X11Platform: Switched to virtual desktop " << desktop_id << std::endl; + } +} + +int X11Platform::get_current_virtual_desktop() const { + return current_virtual_desktop_; +} + +std::vector<int> X11Platform::get_virtual_desktops() const { + return virtual_desktops_; +} + +void X11Platform::move_window_to_desktop(SRDWindow* window, int desktop_id) { + if (!ewmh_supported_ || !window) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + XChangeProperty(display_, x11_window, _NET_WM_DESKTOP_, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)&desktop_id, 1); + + std::cout << "X11Platform: Moved window " << window->getId() << " to desktop " << desktop_id << std::endl; +} + +std::vector<Monitor> X11Platform::get_monitors() { + std::cout << "X11Platform: Get monitors called" << std::endl; + // Return a default monitor for now + return {Monitor{0, 0, 0, 1920, 1080}}; +} + +Monitor X11Platform::get_primary_monitor() { + std::cout << "X11Platform: Get primary monitor called" << std::endl; + return Monitor{0, 0, 0, 1920, 1080}; +} + +void X11Platform::grab_keyboard() { + std::cout << "X11Platform: Grab keyboard called" << std::endl; +} + +void X11Platform::ungrab_keyboard() { + std::cout << "X11Platform: Ungrab keyboard called" << std::endl; +} + +void X11Platform::grab_pointer() { + std::cout << "X11Platform: Grab pointer called" << std::endl; +} + +void X11Platform::ungrab_pointer() { + std::cout << "X11Platform: Ungrab pointer called" << std::endl; +} + +// Private method stubs removed - actual implementations exist below + +void X11Platform::setup_extensions() { + std::cout << "X11Platform: Setup extensions called" << std::endl; +} + +bool X11Platform::check_for_other_wm() { + // Try to select SubstructureRedirectMask on root window + // If another WM is running, this will fail + XSelectInput(display_, root_, SubstructureRedirectMask); + XSync(display_, False); + + // Check if the selection was successful + XErrorHandler old_handler = XSetErrorHandler([](Display*, XErrorEvent*) -> int { + return 0; // Ignore errors + }); + + XSync(display_, False); + XSetErrorHandler(old_handler); + + return true; // Simplified check +} + +bool X11Platform::setup_x11_environment() { + std::cout << "X11Platform: Setting up X11 environment..." << std::endl; + + // Set up error handling + XSetErrorHandler([](Display*, XErrorEvent* e) -> int { + if (e->error_code == BadWindow || + e->error_code == BadMatch || + e->error_code == BadAccess) { + return 0; // Ignore common errors + } + std::cerr << "X11 error: " << e->error_code << std::endl; + return 0; + }); + + return true; +} + +bool X11Platform::setup_event_masks() { + std::cout << "X11Platform: Setting up event masks..." << std::endl; + + // Set up root window event mask + long event_mask = SubstructureRedirectMask | SubstructureNotifyMask | + StructureNotifyMask | PropertyChangeMask | + ButtonPressMask | ButtonReleaseMask | + KeyPressMask | KeyReleaseMask | + PointerMotionMask | EnterWindowMask | LeaveWindowMask; + + XSelectInput(display_, root_, event_mask); + + return true; +} + +void X11Platform::setup_atoms() { + std::cout << "X11Platform: Setting up atoms..." << std::endl; + + // TODO: Implement atom setup for EWMH/ICCCM + // This would involve creating atoms for window manager protocols +} + +void X11Platform::handle_x11_event(XEvent& event) { + std::cout << "X11Platform: Handle X11 event called" << std::endl; + + switch (event.type) { + case MapRequest: + handle_map_request(event.xmaprequest); + break; + case ConfigureRequest: + handle_configure_request(event.xconfigurerequest); + break; + case DestroyNotify: + handle_destroy_notify(event.xdestroywindow); + break; + case UnmapNotify: + handle_unmap_notify(event.xunmap); + break; + case KeyPress: + handle_key_press(event.xkey); + break; + case ButtonPress: + handle_button_press(event.xbutton); + break; + case MotionNotify: + handle_motion_notify(event.xmotion); + break; + default: + break; + } +} + +void X11Platform::handle_map_request(XMapRequestEvent& event) { + std::cout << "X11Platform: Map request for window " << static_cast<unsigned long>(event.window) << std::endl; + + // Create a SRDWindow object for this X11 window + auto window = std::make_unique<SRDWindow>(static_cast<int>(static_cast<unsigned long>(event.window)), "X11 Window"); + + // Add to window map + window_map_[from_x11_window(event.window)] = window.get(); + window.release(); + + // Map the window + XMapWindow(display_, event.window); + + // Apply decorations if enabled + if (decorations_enabled_) { + create_frame_window(window_map_[from_x11_window(event.window)]); + } +} + +void X11Platform::handle_configure_request(XConfigureRequestEvent& event) { + std::cout << "X11Platform: Configure request for window " << static_cast<unsigned long>(event.window) << std::endl; + + XWindowChanges changes; + changes.x = event.x; + changes.y = event.y; + changes.width = event.width; + changes.height = event.height; + changes.border_width = event.border_width; + changes.sibling = static_cast<::Window>(event.above); + changes.stack_mode = event.detail; + + XConfigureWindow(display_, event.window, event.value_mask, &changes); +} + +void X11Platform::handle_destroy_notify(XDestroyWindowEvent& event) { + std::cout << "X11Platform: Destroy notify for window " << static_cast<unsigned long>(event.window) << std::endl; + + auto it = window_map_.find(from_x11_window(event.window)); + if (it != window_map_.end()) { + destroy_window(it->second); + window_map_.erase(it); + } +} + +void X11Platform::handle_unmap_notify(XUnmapEvent& event) { + std::cout << "X11Platform: Unmap notify for window " << static_cast<unsigned long>(event.window) << std::endl; + + // Handle window unmapping +} + +void X11Platform::handle_key_press(XKeyEvent& event) { + std::cout << "X11Platform: Key press event" << std::endl; + + // Convert X11 key event to SRDWM event + // TODO: Implement key event conversion +} + +void X11Platform::handle_button_press(XButtonEvent& event) { + std::cout << "X11Platform: Button press event" << std::endl; + + // Convert X11 button event to SRDWM event + // TODO: Implement button event conversion +} + +void X11Platform::handle_motion_notify(XMotionEvent& event) { + std::cout << "X11Platform: Motion notify event" << std::endl; + + // Convert X11 motion event to SRDWM event + // TODO: Implement motion event conversion +} + +// Window decoration implementations +void X11Platform::set_window_decorations(SRDWindow* window, bool enabled) { + std::cout << "X11Platform: Set window decorations " << (enabled ? "enabled" : "disabled") << std::endl; + + if (!window || !display_) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + + if (enabled) { + create_frame_window(window); + } else { + destroy_frame_window(window); + } + + decorations_enabled_ = enabled; +} + +void X11Platform::set_window_border_color(SRDWindow* window, int r, int g, int b) { + std::cout << "X11Platform: Set border color RGB(" << r << "," << g << "," << b << ")" << std::endl; + + if (!window || !display_) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + unsigned long color = (r << 16) | (g << 8) | b; + + XSetWindowBorder(display_, to_x11_window(x11_window), color); + + // Update decoration state + if (window == get_focused_window()) { + focused_border_color_ = color; + } else { + border_color_ = color; + } +} + +void X11Platform::set_window_border_width(SRDWindow* window, int width) { + std::cout << "X11Platform: Set border width " << width << std::endl; + + if (!window || !display_) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + XSetWindowBorderWidth(display_, to_x11_window(x11_window), width); + + border_width_ = width; +} + +bool X11Platform::get_window_decorations(SRDWindow* window) const { + if (!window) return false; + + // Check if window has a frame window + X11Window x11_window = static_cast<X11Window>(window->getId()); + auto it = frame_window_map_.find(x11_window); + + return it != frame_window_map_.end(); +} + +void X11Platform::create_frame_window(SRDWindow* window) { + std::cout << "X11Platform: Create frame window for window " << window->getId() << std::endl; + + if (!window || !display_) return; + + X11Window client_window = static_cast<X11Window>(window->getId()); + + // Check if frame already exists + if (frame_window_map_.find(client_window) != frame_window_map_.end()) { + return; + } + + // Get client window attributes + XWindowAttributes attr; + attr.x = 0; + attr.y = 0; + attr.width = 0; + attr.height = 0; + attr.border_width = 0; + attr.depth = 0; + attr.visual = nullptr; + attr.root = 0; + attr.c_class = 0; + attr.bit_gravity = 0; + attr.win_gravity = 0; + attr.backing_store = 0; + attr.backing_planes = 0; + attr.backing_pixel = 0; + attr.save_under = 0; + attr.colormap = 0; + attr.map_installed = 0; + attr.map_state = 0; + attr.all_event_masks = 0; + attr.your_event_mask = 0; + attr.do_not_propagate_mask = 0; + attr.override_redirect = 0; + if (XGetWindowAttributes(display_, to_x11_window(client_window), &attr) == 0) { + std::cerr << "Failed to get window attributes" << std::endl; + return; + } + + // Create frame window + X11Window frame_window = from_x11_window(XCreateSimpleWindow( + display_, to_x11_window(root_), + attr.x, attr.y, + attr.width + border_width_ * 2, + attr.height + border_width_ + 30, // Add titlebar height + border_width_, + border_color_, + 0x000000 // Background color + )); + + // Set frame window properties + XSetWindowAttributes frame_attr; + frame_attr.event_mask = ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | ExposureMask; + XChangeWindowAttributes(display_, to_x11_window(frame_window), CWEventMask, &frame_attr); + + // Reparent client window into frame + XReparentWindow(display_, to_x11_window(client_window), to_x11_window(frame_window), border_width_, 30); + + // Map frame window + XMapWindow(display_, to_x11_window(frame_window)); + + // Store frame window mapping + frame_window_map_[client_window] = frame_window; + + // Draw titlebar + draw_titlebar(window); + + std::cout << "X11Platform: Frame window created successfully" << std::endl; +} + +void X11Platform::destroy_frame_window(SRDWindow* window) { + std::cout << "X11Platform: Destroy frame window for window " << window->getId() << std::endl; + + if (!window || !display_) return; + + X11Window client_window = static_cast<X11Window>(window->getId()); + + // Find frame window + auto it = frame_window_map_.find(client_window); + if (it == frame_window_map_.end()) { + return; + } + + X11Window frame_window = it->second; + + // Reparent client window back to root + XReparentWindow(display_, to_x11_window(client_window), to_x11_window(root_), 0, 0); + + // Destroy frame window + XDestroyWindow(display_, to_x11_window(frame_window)); + + // Remove from mapping + frame_window_map_.erase(it); + + std::cout << "X11Platform: Frame window destroyed successfully" << std::endl; +} + +void X11Platform::draw_titlebar(SRDWindow* window) { + std::cout << "X11Platform: Draw titlebar for window " << window->getId() << std::endl; + + if (!window || !display_) return; + + X11Window client_window = static_cast<X11Window>(window->getId()); + + // Find frame window + auto it = frame_window_map_.find(client_window); + if (it == frame_window_map_.end()) { + return; + } + + X11Window frame_window = it->second; + + // Get window title + char* window_name = nullptr; + if (XFetchName(display_, to_x11_window(client_window), &window_name) && window_name) { + // Create GC for drawing + XGCValues gc_values; + gc_values.foreground = 0xFFFFFF; // White text + gc_values.background = 0x2E3440; // Dark background + gc_values.font = XLoadFont(display_, "fixed"); + + GC gc = XCreateGC(display_, to_x11_window(frame_window), + GCForeground | GCBackground | GCFont, &gc_values); + + // Draw titlebar background + XSetForeground(display_, gc, 0x2E3440); + XFillRectangle(display_, to_x11_window(frame_window), gc, 0, 0, 800, 30); // Placeholder size + + // Draw title text + XSetForeground(display_, gc, 0xFFFFFF); + XDrawString(display_, to_x11_window(frame_window), gc, 10, 20, window_name, strlen(window_name)); + + // Clean up + XFreeGC(display_, gc); + XFree(window_name); + } +} + +void X11Platform::update_frame_geometry(SRDWindow* window) { + std::cout << "X11Platform: Update frame geometry" << std::endl; + + // TODO: Implement when X11 headers are available + // Update frame window geometry when client window changes +} + +SRDWindow* X11Platform::get_focused_window() const { + if (!display_) return nullptr; + + typedef ::Window X11WindowType; + X11WindowType focused_window; + int revert_to; + XGetInputFocus(display_, &focused_window, &revert_to); + + auto it = window_map_.find(from_x11_window(focused_window)); + if (it != window_map_.end()) { + return it->second; + } + + return nullptr; +} + +// EWMH helper methods +void X11Platform::setup_ewmh() { + if (!display_ || !ewmh_supported_) return; + + // Set EWMH supported atoms + Atom supported[] = { + _NET_WM_STATE_, + _NET_WM_STATE_MAXIMIZED_VERT_, + _NET_WM_STATE_MAXIMIZED_HORZ_, + _NET_WM_STATE_FULLSCREEN_, + _NET_WM_STATE_ABOVE_, + _NET_WM_STATE_BELOW_, + _NET_WM_WINDOW_TYPE_, + _NET_WM_WINDOW_TYPE_DESKTOP_, + _NET_WM_WINDOW_TYPE_DOCK_, + _NET_WM_WINDOW_TYPE_TOOLBAR_, + _NET_WM_WINDOW_TYPE_MENU_, + _NET_WM_WINDOW_TYPE_UTILITY_, + _NET_WM_WINDOW_TYPE_SPLASH_, + _NET_WM_WINDOW_TYPE_DIALOG_, + _NET_WM_WINDOW_TYPE_DROPDOWN_MENU_, + _NET_WM_WINDOW_TYPE_POPUP_MENU_, + _NET_WM_WINDOW_TYPE_TOOLTIP_, + _NET_WM_WINDOW_TYPE_NOTIFICATION_, + _NET_WM_WINDOW_TYPE_COMBO_, + _NET_WM_WINDOW_TYPE_DND_, + _NET_WM_WINDOW_TYPE_NORMAL_, + _NET_WM_DESKTOP_, + _NET_NUMBER_OF_DESKTOPS_, + _NET_CURRENT_DESKTOP_, + _NET_DESKTOP_NAMES_ + }; + + XChangeProperty(display_, root_, XInternAtom(display_, "_NET_SUPPORTED", False), + XA_ATOM, 32, PropModeReplace, (unsigned char*)supported, + sizeof(supported) / sizeof(supported[0])); + + // Set initial desktop info + update_ewmh_desktop_info(); + + std::cout << "X11Platform: EWMH setup completed" << std::endl; +} + +void X11Platform::update_ewmh_desktop_info() { + if (!display_ || !ewmh_supported_) return; + + // Set number of desktops + int num_desktops = virtual_desktops_.size(); + XChangeProperty(display_, root_, _NET_NUMBER_OF_DESKTOPS_, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)&num_desktops, 1); + + // Set current desktop + XChangeProperty(display_, root_, _NET_CURRENT_DESKTOP_, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)¤t_virtual_desktop_, 1); + + // Set desktop names (simplified - just use numbers for now) + std::vector<std::string> desktop_names; + for (int i = 0; i < num_desktops; ++i) { + desktop_names.push_back("Desktop " + std::to_string(i + 1)); + } + + // Convert to X11 string format + std::string names_str; + for (const auto& name : desktop_names) { + names_str += name + '\0'; + } + + XChangeProperty(display_, root_, _NET_DESKTOP_NAMES_, XA_STRING, 8, + PropModeReplace, (unsigned char*)names_str.c_str(), names_str.length()); +} + +// Linux/X11-specific features implementation +void X11Platform::enable_compositor(bool enabled) { + compositor_enabled_ = enabled; + + if (enabled) { + // Try to enable compositor effects + // This is a simplified implementation - real compositors have more complex setup + std::cout << "X11Platform: Compositor effects enabled" << std::endl; + } else { + std::cout << "X11Platform: Compositor effects disabled" << std::endl; + } +} + +void X11Platform::set_window_opacity(SRDWindow* window, unsigned char opacity) { + if (!window) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + + // Set window opacity using _NET_WM_WINDOW_OPACITY atom + Atom opacity_atom = XInternAtom(display_, "_NET_WM_WINDOW_OPACITY", False); + if (opacity_atom != None) { + unsigned long opacity_value = (opacity << 24) | (opacity << 16) | (opacity << 8) | opacity; + XChangeProperty(display_, x11_window, opacity_atom, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)&opacity_value, 1); + } + + std::cout << "X11Platform: Set window " << window->getId() << " opacity to " << (int)opacity << std::endl; +} + +void X11Platform::set_window_blur(SRDWindow* window, bool enabled) { + if (!window) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + + // Set window blur using _NET_WM_WINDOW_BLUR atom (if supported) + Atom blur_atom = XInternAtom(display_, "_NET_WM_WINDOW_BLUR", False); + if (blur_atom != None) { + unsigned long blur_value = enabled ? 1 : 0; + XChangeProperty(display_, x11_window, blur_atom, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)&blur_value, 1); + } + + std::cout << "X11Platform: Set window " << window->getId() << " blur " << (enabled ? "enabled" : "disabled") << std::endl; +} + +void X11Platform::set_window_shadow(SRDWindow* window, bool enabled) { + if (!window) return; + + X11Window x11_window = static_cast<X11Window>(window->getId()); + + // Set window shadow using _NET_WM_WINDOW_SHADOW atom (if supported) + Atom shadow_atom = XInternAtom(display_, "_NET_WM_WINDOW_SHADOW", False); + if (shadow_atom != None) { + unsigned long shadow_value = enabled ? 1 : 0; + XChangeProperty(display_, x11_window, shadow_atom, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)&shadow_value, 1); + } + + std::cout << "X11Platform: Set window " << window->getId() << " shadow " << (enabled ? "enabled" : "disabled") << std::endl; +} + +// RandR (Resize and Rotate) support implementation +void X11Platform::enable_randr(bool enabled) { + randr_enabled_ = enabled; + + if (enabled) { + initialize_randr(); + } else { + cleanup_randr(); + } + + std::cout << "X11Platform: RandR support " << (enabled ? "enabled" : "disabled") << std::endl; +} + +void X11Platform::set_monitor_rotation(int monitor_id, int rotation) { + if (!randr_enabled_) return; + + // Rotation values: 0=0°, 1=90°, 2=180°, 3=270° + if (rotation < 0 || rotation > 3) return; + + // TODO: Implement actual RandR rotation + std::cout << "X11Platform: Set monitor " << monitor_id << " rotation to " << (rotation * 90) << "°" << std::endl; +} + +void X11Platform::set_monitor_refresh_rate(int monitor_id, int refresh_rate) { + if (!randr_enabled_) return; + + if (refresh_rate < 30 || refresh_rate > 240) return; + + // TODO: Implement actual RandR refresh rate setting + std::cout << "X11Platform: Set monitor " << monitor_id << " refresh rate to " << refresh_rate << " Hz" << std::endl; +} + +void X11Platform::set_monitor_scale(int monitor_id, float scale) { + if (!randr_enabled_) return; + + if (scale < 0.5f || scale > 3.0f) return; + + // TODO: Implement actual RandR scaling + std::cout << "X11Platform: Set monitor " << monitor_id << " scale to " << scale << "x" << std::endl; +} + +void X11Platform::initialize_randr() { + if (!display_) return; + + // Check if RandR extension is available + int event_base, error_base; + if (XRRQueryExtension(display_, &event_base, &error_base)) { + std::cout << "X11Platform: RandR extension available" << std::endl; + + // Get screen resources + Window root = DefaultRootWindow(display_); + int screen = DefaultScreen(display_); + XRRScreenResources* resources = XRRGetScreenResources(display_, root); + + if (resources) { + // Process monitor information + for (int i = 0; i < resources->noutput; ++i) { + XRROutputInfo* output_info = XRRGetOutputInfo(display_, resources, resources->outputs[i]); + if (output_info && output_info->connection == RR_Connected) { + // Add monitor to our list + Monitor monitor; + monitor.id = i; + monitor.x = 0; // TODO: Get actual position + monitor.y = 0; + monitor.width = output_info->mm_width; // Convert mm to pixels + monitor.height = output_info->mm_height; + monitor.name = output_info->name; + monitor.refresh_rate = 60; // Default + + monitors_.push_back(monitor); + } + if (output_info) XRRFreeOutputInfo(output_info); + } + XRRFreeScreenResources(resources); + } + } else { + std::cout << "X11Platform: RandR extension not available" << std::endl; + } +} + +void X11Platform::cleanup_randr() { + // Clean up RandR resources if needed + std::cout << "X11Platform: RandR cleanup completed" << std::endl; +} + +// Panel/Dock integration implementation +void X11Platform::set_panel_visible(bool visible) { + panel_visible_ = visible; + + // TODO: Implement actual panel visibility control + std::cout << "X11Platform: Panel visibility " << (visible ? "enabled" : "disabled") << std::endl; +} + +void X11Platform::set_panel_position(int position) { + if (position < 0 || position > 3) return; + + panel_position_ = position; + + // Position values: 0=bottom, 1=top, 2=left, 3=right + std::string position_str; + switch (position) { + case 0: position_str = "bottom"; break; + case 1: position_str = "top"; break; + case 2: position_str = "left"; break; + case 3: position_str = "right"; break; + default: position_str = "unknown"; break; + } + + std::cout << "X11Platform: Panel position set to " << position_str << std::endl; +} + +void X11Platform::set_panel_auto_hide(bool enabled) { + panel_auto_hide_ = enabled; + + // TODO: Implement actual panel auto-hide behavior + std::cout << "X11Platform: Panel auto-hide " << (enabled ? "enabled" : "disabled") << std::endl; +} + +void X11Platform::update_panel_workspace_list() { + if (!ewmh_supported_) return; + + // Update panel with current workspace information + // This would typically involve communicating with the panel application + std::cout << "X11Platform: Updated panel workspace list" << std::endl; +} + +// System tray integration implementation +void X11Platform::add_system_tray_icon(const std::string& tooltip, Pixmap icon) { + // TODO: Implement actual system tray icon addition + // This would involve using the _NET_SYSTEM_TRAY_S0 atom and related protocols + + system_tray_icon_ = 1; // Placeholder + std::cout << "X11Platform: Added system tray icon with tooltip: " << tooltip << std::endl; +} + +void X11Platform::remove_system_tray_icon() { + if (system_tray_icon_) { + // TODO: Implement actual system tray icon removal + system_tray_icon_ = 0; + std::cout << "X11Platform: Removed system tray icon" << std::endl; + } +} + +void X11Platform::show_system_tray_menu(Window menu) { + // TODO: Implement system tray menu display + std::cout << "X11Platform: Show system tray menu" << std::endl; +} diff --git a/src/platform/x11_platform.h b/src/platform/x11_platform.h new file mode 100644 index 0000000..095081e --- /dev/null +++ b/src/platform/x11_platform.h @@ -0,0 +1,210 @@ +#ifndef SRDWM_X11_PLATFORM_H +#define SRDWM_X11_PLATFORM_H + +#include "platform.h" +#include <string> +#include <vector> +#include <map> +#include <algorithm> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xrandr.h> +#include <X11/extensions/Xinerama.h> + +// X11 types are now properly included +// Use X11Window typedef to avoid collision with our SRDWindow class +typedef unsigned long X11Window; + +// Helper functions to convert between X11Window and X11's Window type +inline ::Window to_x11_window(X11Window w) { return static_cast<::Window>(w); } +inline X11Window from_x11_window(::Window w) { return static_cast<X11Window>(w); } + +class X11Platform : public Platform { +public: + X11Platform(); + ~X11Platform() override; + + // Platform interface implementation + bool initialize() override; + void shutdown() override; + bool poll_events(std::vector<Event>& events) override; + void process_event(const Event& event) override; + + // Window management + std::unique_ptr<SRDWindow> create_window(const std::string& title, int x, int y, int width, int height) override; + void destroy_window(SRDWindow* window) override; + void set_window_position(SRDWindow* window, int x, int y) override; + void set_window_size(SRDWindow* window, int width, int height) override; + void set_window_title(SRDWindow* window, const std::string& title) override; + void focus_window(SRDWindow* window) override; + void minimize_window(SRDWindow* window) override; + void maximize_window(SRDWindow* window) override; + void close_window(SRDWindow* window) override; + + // Monitor management + std::vector<Monitor> get_monitors() override; + Monitor get_primary_monitor() override; + + // Input handling + void grab_keyboard() override; + void ungrab_keyboard() override; + void grab_pointer() override; + void ungrab_pointer() override; + + // Window decorations (X11 implementation) + void set_window_decorations(SRDWindow* window, bool enabled) override; + void set_window_border_color(SRDWindow* window, int r, int g, int b) override; + void set_window_border_width(SRDWindow* window, int width) override; + bool get_window_decorations(SRDWindow* window) const override; + + // Linux/X11-specific features + void enable_compositor(bool enabled); + void set_window_opacity(SRDWindow* window, unsigned char opacity); + void set_window_blur(SRDWindow* window, bool enabled); + void set_window_shadow(SRDWindow* window, bool enabled); + + // EWMH (Extended Window Manager Hints) support + void set_ewmh_supported(bool supported); + void set_window_type(SRDWindow* window, const std::string& type); + void set_window_state(SRDWindow* window, const std::vector<std::string>& states); + void set_window_strut(SRDWindow* window, int left, int right, int top, int bottom); + + // Virtual Desktop support (X11 workspaces) + void create_virtual_desktop(const std::string& name); + void remove_virtual_desktop(int desktop_id); + void switch_to_virtual_desktop(int desktop_id); + int get_current_virtual_desktop() const; + std::vector<int> get_virtual_desktops() const; + void move_window_to_desktop(SRDWindow* window, int desktop_id); + + // Panel/Dock integration + void set_panel_visible(bool visible); + void set_panel_position(int position); // 0=bottom, 1=top, 2=left, 3=right + void set_panel_auto_hide(bool enabled); + void update_panel_workspace_list(); + + // System tray integration + void add_system_tray_icon(const std::string& tooltip, Pixmap icon); + void remove_system_tray_icon(); + void show_system_tray_menu(Window menu); + + // RandR (Resize and Rotate) support + void enable_randr(bool enabled); + void set_monitor_rotation(int monitor_id, int rotation); + void set_monitor_refresh_rate(int monitor_id, int refresh_rate); + void set_monitor_scale(int monitor_id, float scale); + + // Utility + std::string get_platform_name() const override { return "X11"; } + bool is_wayland() const override { return false; } + bool is_x11() const override { return true; } + bool is_windows() const override { return false; } + bool is_macos() const override { return false; } + +private: + // X11-specific members + Display* display_ = nullptr; + X11Window root_ = 0; + + // Window tracking + std::map<X11Window, ::SRDWindow*> window_map_; + std::map<X11Window, X11Window> frame_window_map_; // client -> frame + + // Monitor information + std::vector<Monitor> monitors_; + + // Decoration state + bool decorations_enabled_; + int border_width_; + unsigned long border_color_; + unsigned long focused_border_color_; + + // Linux/X11-specific state + bool compositor_enabled_; + bool ewmh_supported_; + bool randr_enabled_; + int current_virtual_desktop_; + std::vector<int> virtual_desktops_; + bool panel_visible_; + bool panel_auto_hide_; + int panel_position_; + Window system_tray_icon_; + + // EWMH atoms + Atom _NET_WM_STATE_; + Atom _NET_WM_STATE_MAXIMIZED_VERT_; + Atom _NET_WM_STATE_MAXIMIZED_HORZ_; + Atom _NET_WM_STATE_FULLSCREEN_; + Atom _NET_WM_STATE_ABOVE_; + Atom _NET_WM_STATE_BELOW_; + Atom _NET_WM_WINDOW_TYPE_; + Atom _NET_WM_WINDOW_TYPE_DESKTOP_; + Atom _NET_WM_WINDOW_TYPE_DOCK_; + Atom _NET_WM_WINDOW_TYPE_TOOLBAR_; + Atom _NET_WM_WINDOW_TYPE_MENU_; + Atom _NET_WM_WINDOW_TYPE_UTILITY_; + Atom _NET_WM_WINDOW_TYPE_SPLASH_; + Atom _NET_WM_WINDOW_TYPE_DIALOG_; + Atom _NET_WM_WINDOW_TYPE_DROPDOWN_MENU_; + Atom _NET_WM_WINDOW_TYPE_POPUP_MENU_; + Atom _NET_WM_WINDOW_TYPE_TOOLTIP_; + Atom _NET_WM_WINDOW_TYPE_NOTIFICATION_; + Atom _NET_WM_WINDOW_TYPE_COMBO_; + Atom _NET_WM_WINDOW_TYPE_DND_; + Atom _NET_WM_WINDOW_TYPE_NORMAL_; + Atom _NET_WM_DESKTOP_; + Atom _NET_NUMBER_OF_DESKTOPS_; + Atom _NET_CURRENT_DESKTOP_; + Atom _NET_DESKTOP_NAMES_; + Atom _NET_WM_STRUT_; + Atom _NET_WM_STRUT_PARTIAL_; + Atom _NET_WM_OPACITY_; + + // Helper methods + SRDWindow* get_focused_window() const; + + // Private methods + bool setup_x11_environment(); + bool setup_event_masks(); + void handle_x11_event(XEvent& event); + void setup_atoms(); + void setup_extensions(); + bool check_for_other_wm(); + + // Event handlers + void handle_map_request(XMapRequestEvent& event); + void handle_configure_request(XConfigureRequestEvent& event); + void handle_destroy_notify(XDestroyWindowEvent& event); + void handle_unmap_notify(XUnmapEvent& event); + void handle_key_press(XKeyEvent& event); + void handle_button_press(XButtonEvent& event); + void handle_motion_notify(XMotionEvent& event); + + // Decoration methods + void create_frame_window(SRDWindow* window); + void destroy_frame_window(SRDWindow* window); + void draw_titlebar(SRDWindow* window); + void update_frame_geometry(SRDWindow* window); + + // EWMH methods + void setup_ewmh(); + void update_ewmh_desktop_info(); + void handle_ewmh_message(XClientMessageEvent& event); + + // Virtual Desktop methods + void initialize_virtual_desktops(); + void cleanup_virtual_desktops(); + + // RandR methods + void initialize_randr(); + void cleanup_randr(); + + // Panel methods + void initialize_panel(); + void update_panel(); +}; + +#endif // SRDWM_X11_PLATFORM_H + |
