1212
1313namespace nativeapi {
1414
15+ // Key to store/retrieve WindowId on GObjects
16+ static const char * kWindowIdKey = " NativeAPIWindowId" ;
17+
1518// Private implementation class
1619class Window ::Impl {
1720 public:
18- Impl (GdkWindow* window) : gdk_window_(window) {}
21+ Impl (GtkWidget* widget, GdkWindow* gdk_window) : widget_(widget), gdk_window_(gdk_window) {}
22+ GtkWidget* widget_;
1923 GdkWindow* gdk_window_;
2024};
2125
@@ -24,75 +28,87 @@ Window::Window() {
2428 GdkDisplay* display = gdk_display_get_default ();
2529 if (!display) {
2630 std::cerr << " No display available for window creation" << std::endl;
27- pimpl_ = std::make_unique<Impl>(nullptr );
31+ pimpl_ = std::make_unique<Impl>(nullptr , nullptr );
2832 return ;
2933 }
3034
31- // Create a new GTK window
32- GtkWidget* gtk_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
33- if (!gtk_window ) {
35+ // Create a new GTK toplevel window
36+ GtkWidget* widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
37+ if (!widget ) {
3438 std::cerr << " Failed to create GTK window" << std::endl;
35- pimpl_ = std::make_unique<Impl>(nullptr );
39+ pimpl_ = std::make_unique<Impl>(nullptr , nullptr );
3640 return ;
3741 }
3842
3943 // Realize to ensure GdkWindow exists
40- if (!gtk_widget_get_realized (gtk_window )) {
41- gtk_widget_realize (gtk_window );
44+ if (!gtk_widget_get_realized (widget )) {
45+ gtk_widget_realize (widget );
4246 }
4347
4448 // Obtain GdkWindow
45- GdkWindow* gdk_window = gtk_widget_get_window (gtk_window );
49+ GdkWindow* gdk_window = gtk_widget_get_window (widget );
4650 if (!gdk_window) {
4751 std::cerr << " Failed to get GdkWindow from GTK widget" << std::endl;
48- gtk_widget_destroy (gtk_window );
49- pimpl_ = std::make_unique<Impl>(nullptr );
52+ gtk_widget_destroy (widget );
53+ pimpl_ = std::make_unique<Impl>(nullptr , nullptr );
5054 return ;
5155 }
5256
57+ // Allocate and attach a stable WindowId to the native objects
58+ WindowId id = IdAllocator::Allocate<Window>();
59+ if (id != IdAllocator::kInvalidId ) {
60+ g_object_set_data (G_OBJECT (widget), kWindowIdKey , reinterpret_cast <gpointer>(static_cast <uintptr_t >(id)));
61+ g_object_set_data (G_OBJECT (gdk_window), kWindowIdKey , reinterpret_cast <gpointer>(static_cast <uintptr_t >(id)));
62+ }
63+
5364 // Only create the instance, don't show the window
54- pimpl_ = std::make_unique<Impl>(gdk_window);
65+ pimpl_ = std::make_unique<Impl>(widget, gdk_window);
5566}
5667
57- Window::Window (void * native_window) : pimpl_(std::make_unique<Impl>((GdkWindow*)native_window)) {}
58-
59- Window::~Window () {}
68+ Window::Window (void * native_window) {
69+ // Wrap existing GdkWindow or GtkWidget
70+ GtkWidget* widget = nullptr ;
71+ GdkWindow* gdk_window = nullptr ;
6072
61- WindowId Window::GetId () const {
62- // Use IdAllocator to generate unique IDs instead of casting pointers
63- if (!pimpl_->gdk_window_ ) {
64- return IdAllocator::kInvalidId ;
73+ // Heuristic: if this looks like a GtkWidget*, use it; otherwise treat as GdkWindow*
74+ // In our codebase, native Linux window handles should be GtkWidget* (GtkWindow)
75+ widget = static_cast <GtkWidget*>(native_window);
76+ if (widget && GTK_IS_WIDGET (widget)) {
77+ if (!gtk_widget_get_realized (widget)) {
78+ gtk_widget_realize (widget);
79+ }
80+ gdk_window = gtk_widget_get_window (widget);
81+ } else {
82+ // Fallback: assume GdkWindow*
83+ gdk_window = static_cast <GdkWindow*>(native_window);
6584 }
6685
67- // Store the allocated ID in a static map to ensure consistency
68- static std::unordered_map<GdkWindow*, WindowId> window_id_map;
69- static std::mutex map_mutex;
70-
71- std::lock_guard<std::mutex> lock (map_mutex);
72- auto it = window_id_map.find (pimpl_->gdk_window_ );
73- if (it != window_id_map.end ()) {
74- return it->second ;
75- }
86+ pimpl_ = std::make_unique<Impl>(widget, gdk_window);
87+ }
7688
77- // Allocate new ID using the IdAllocator
78- WindowId new_id = IdAllocator::Allocate<Window>();
79- if (new_id != IdAllocator::kInvalidId ) {
80- window_id_map[pimpl_->gdk_window_ ] = new_id;
89+ Window::~Window () {}
8190
82- // Register window in registry (delayed registration)
83- // This requires the Window to be managed by shared_ptr
84- try {
85- WindowRegistry::GetInstance ().Add (new_id, const_cast <Window*>(this )->shared_from_this ());
86- } catch (const std::bad_weak_ptr&) {
87- // Window not yet managed by shared_ptr, skip registration
88- // Registration will happen when window is properly managed by shared_ptr
91+ WindowId Window::GetId () const {
92+ // Prefer reading ID stored on the native objects
93+ if (pimpl_->gdk_window_ ) {
94+ gpointer data = g_object_get_data (G_OBJECT (pimpl_->gdk_window_ ), kWindowIdKey );
95+ if (data) {
96+ return static_cast <WindowId>(reinterpret_cast <uintptr_t >(data));
97+ }
98+ }
99+ if (pimpl_->widget_ ) {
100+ gpointer data = g_object_get_data (G_OBJECT (pimpl_->widget_ ), kWindowIdKey );
101+ if (data) {
102+ return static_cast <WindowId>(reinterpret_cast <uintptr_t >(data));
89103 }
90104 }
91- return new_id ;
105+ return IdAllocator:: kInvalidId ;
92106}
93107
94108void Window::Focus () {
95- if (pimpl_->gdk_window_ ) {
109+ if (pimpl_->widget_ ) {
110+ gtk_window_present (GTK_WINDOW (pimpl_->widget_ ));
111+ } else if (pimpl_->gdk_window_ ) {
96112 gdk_window_focus (pimpl_->gdk_window_ , GDK_CURRENT_TIME);
97113 }
98114}
@@ -120,27 +136,37 @@ bool Window::IsFocused() const {
120136}
121137
122138void Window::Show () {
123- if (pimpl_->gdk_window_ ) {
139+ if (pimpl_->widget_ ) {
140+ gtk_widget_show (pimpl_->widget_ );
141+ } else if (pimpl_->gdk_window_ ) {
124142 gdk_window_show (pimpl_->gdk_window_ );
125143 }
126144}
127145
128146void Window::ShowInactive () {
129- if (pimpl_->gdk_window_ ) {
147+ if (pimpl_->widget_ ) {
148+ gtk_widget_show (pimpl_->widget_ );
149+ } else if (pimpl_->gdk_window_ ) {
130150 gdk_window_show_unraised (pimpl_->gdk_window_ );
131151 }
132152}
133153
134154void Window::Hide () {
135- if (pimpl_->gdk_window_ ) {
155+ if (pimpl_->widget_ ) {
156+ gtk_widget_hide (pimpl_->widget_ );
157+ } else if (pimpl_->gdk_window_ ) {
136158 gdk_window_hide (pimpl_->gdk_window_ );
137159 }
138160}
139161
140162bool Window::IsVisible () const {
141- if (!pimpl_->gdk_window_ )
142- return false ;
143- return gdk_window_is_visible (pimpl_->gdk_window_ );
163+ if (pimpl_->widget_ ) {
164+ return gtk_widget_get_visible (pimpl_->widget_ );
165+ }
166+ if (pimpl_->gdk_window_ ) {
167+ return gdk_window_is_visible (pimpl_->gdk_window_ );
168+ }
169+ return false ;
144170}
145171
146172void Window::Maximize () {
@@ -388,13 +414,44 @@ void Window::Center() {
388414}
389415
390416void Window::SetTitle (std::string title) {
391- // GDK windows don't have titles directly - this would be set on the GTK
392- // widget For now, provide stub implementation
417+ // Prefer setting title via GtkWindow if available
418+ if (pimpl_->widget_ && GTK_IS_WINDOW (pimpl_->widget_ )) {
419+ gtk_window_set_title (GTK_WINDOW (pimpl_->widget_ ), title.c_str ());
420+ return ;
421+ }
422+
423+ // If only GdkWindow is available, try to get associated GtkWindow
424+ if (pimpl_->gdk_window_ ) {
425+ gpointer user_data = nullptr ;
426+ gdk_window_get_user_data (pimpl_->gdk_window_ , &user_data);
427+ if (user_data && GTK_IS_WINDOW (user_data)) {
428+ gtk_window_set_title (GTK_WINDOW (user_data), title.c_str ());
429+ return ;
430+ }
431+
432+ // Fallback: set title via GDK for toplevel windows
433+ gdk_window_set_title (pimpl_->gdk_window_ , title.c_str ());
434+ }
393435}
394436
395437std::string Window::GetTitle () const {
396- // GDK windows don't have titles directly - this would come from the GTK
397- // widget
438+ // Prefer reading title via GtkWindow if available
439+ if (pimpl_->widget_ && GTK_IS_WINDOW (pimpl_->widget_ )) {
440+ const gchar* t = gtk_window_get_title (GTK_WINDOW (pimpl_->widget_ ));
441+ return t ? std::string (t) : std::string ();
442+ }
443+
444+ // If only GdkWindow is available, try to get associated GtkWindow
445+ if (pimpl_->gdk_window_ ) {
446+ gpointer user_data = nullptr ;
447+ gdk_window_get_user_data (pimpl_->gdk_window_ , &user_data);
448+ if (user_data && GTK_IS_WINDOW (user_data)) {
449+ const gchar* t = gtk_window_get_title (GTK_WINDOW (user_data));
450+ return t ? std::string (t) : std::string ();
451+ }
452+ }
453+
454+ // No reliable way to get title directly from GdkWindow
398455 return std::string ();
399456}
400457
@@ -460,7 +517,8 @@ void Window::StartResizing() {
460517}
461518
462519void * Window::GetNativeObjectInternal () const {
463- return pimpl_ ? pimpl_->gdk_window_ : nullptr ;
520+ // Return the GtkWidget* (GtkWindow) as the native handle on Linux
521+ return pimpl_ ? static_cast <void *>(pimpl_->widget_ ? pimpl_->widget_ : nullptr ) : nullptr ;
464522}
465523
466524} // namespace nativeapi
0 commit comments