Skip to content

Commit 420a6e1

Browse files
committed
Add Linux window management implementation
1 parent 0561c88 commit 420a6e1

File tree

4 files changed

+191
-8
lines changed

4 files changed

+191
-8
lines changed

src/menu.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "menu.h"
2+
#include <sstream>
3+
4+
namespace nativeapi {
5+
6+
std::string KeyboardAccelerator::ToString() const {
7+
std::ostringstream oss;
8+
bool first = true;
9+
if (modifiers & Ctrl) {
10+
oss << "Ctrl";
11+
first = false;
12+
}
13+
if (modifiers & Alt) {
14+
if (!first) oss << "+";
15+
oss << "Alt";
16+
first = false;
17+
}
18+
if (modifiers & Shift) {
19+
if (!first) oss << "+";
20+
oss << "Shift";
21+
first = false;
22+
}
23+
if (modifiers & Meta) {
24+
if (!first) oss << "+";
25+
oss << "Meta";
26+
first = false;
27+
}
28+
if (!key.empty()) {
29+
if (!first) oss << "+";
30+
oss << key;
31+
}
32+
return oss.str();
33+
}
34+
35+
} // namespace nativeapi
36+
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include <iostream>
2+
3+
#include "../../app_runner.h"
4+
#include "../../window.h"
5+
6+
// Import GTK headers
7+
#include <gtk/gtk.h>
8+
#include <gdk/gdk.h>
9+
10+
namespace nativeapi {
11+
12+
// Private implementation for Linux using GTK
13+
class AppRunner::Impl {
14+
public:
15+
Impl() {
16+
// GTK initialization is handled by WindowManager
17+
// No need to initialize again here
18+
}
19+
20+
~Impl() {
21+
// GTK cleanup is handled automatically
22+
}
23+
24+
int Run(std::shared_ptr<Window> window) {
25+
if (!window) {
26+
std::cerr << "Cannot run application with null window" << std::endl;
27+
return -1;
28+
}
29+
30+
// Check if GTK is available
31+
GdkDisplay* display = gdk_display_get_default();
32+
if (!display) {
33+
std::cerr << "No display available - cannot run application" << std::endl;
34+
return -1;
35+
}
36+
37+
std::cout << "Starting application with window ID: " << window->id << std::endl;
38+
39+
// Connect to the window destroy signal to quit the main loop
40+
// when the window is closed
41+
if (window->id != 0) {
42+
// Find the GTK window corresponding to our Window object
43+
GList* toplevels = gtk_window_list_toplevels();
44+
for (GList* l = toplevels; l != nullptr; l = l->next) {
45+
GtkWindow* gtk_window = GTK_WINDOW(l->data);
46+
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(gtk_window));
47+
48+
if (gdk_window && (WindowID)gdk_window == window->id) {
49+
// Connect destroy signal to quit the main loop
50+
g_signal_connect(gtk_window, "destroy", G_CALLBACK(gtk_main_quit), nullptr);
51+
break;
52+
}
53+
}
54+
g_list_free(toplevels);
55+
}
56+
57+
// Run the GTK main loop
58+
std::cout << "Starting GTK main loop..." << std::endl;
59+
gtk_main();
60+
61+
std::cout << "Application finished" << std::endl;
62+
return 0;
63+
}
64+
};
65+
66+
// AppRunner implementation
67+
AppRunner::AppRunner() : pimpl_(std::make_unique<Impl>()) {
68+
}
69+
70+
AppRunner::~AppRunner() = default;
71+
72+
int AppRunner::Run(std::shared_ptr<Window> window) {
73+
return pimpl_->Run(window);
74+
}
75+
76+
} // namespace nativeapi

src/platform/linux/window_linux.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ void Window::SetMinimumSize(Size size) {
182182
// For now, we'll provide a basic implementation that doesn't enforce constraints
183183
}
184184

185-
Size Window::GetMinimumSize() {
185+
Size Window::GetMinimumSize() const {
186186
return Size{0, 0};
187187
}
188188

@@ -191,7 +191,7 @@ void Window::SetMaximumSize(Size size) {
191191
// For now, we'll provide a basic implementation that doesn't enforce constraints
192192
}
193193

194-
Size Window::GetMaximumSize() {
194+
Size Window::GetMaximumSize() const {
195195
return Size{-1, -1}; // -1 indicates no maximum
196196
}
197197

@@ -254,7 +254,7 @@ void Window::SetAlwaysOnTop(bool is_always_on_top) {
254254
}
255255
}
256256

257-
bool Window::IsAlwaysOnTop() {
257+
bool Window::IsAlwaysOnTop() const {
258258
if (!pimpl_->gdk_window_) return false;
259259
GdkWindowState state = gdk_window_get_state(pimpl_->gdk_window_);
260260
return state & GDK_WINDOW_STATE_ABOVE;
@@ -266,7 +266,7 @@ void Window::SetPosition(Point point) {
266266
}
267267
}
268268

269-
Point Window::GetPosition() {
269+
Point Window::GetPosition() const {
270270
Point point = {0, 0};
271271
if (pimpl_->gdk_window_) {
272272
gint x, y;
@@ -282,7 +282,7 @@ void Window::SetTitle(std::string title) {
282282
// For now, provide stub implementation
283283
}
284284

285-
std::string Window::GetTitle() {
285+
std::string Window::GetTitle() const {
286286
// GDK windows don't have titles directly - this would come from the GTK widget
287287
return std::string();
288288
}

src/platform/linux/window_manager_linux.cpp

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,80 @@ std::shared_ptr<Window> WindowManager::GetCurrent() {
166166
}
167167

168168
std::shared_ptr<Window> WindowManager::Create(const WindowOptions& options) {
169-
// TODO: Implement Linux window creation using GTK
170-
// For now, return nullptr as this is a stub implementation
171-
return nullptr;
169+
// Check if GTK is available
170+
GdkDisplay* display = gdk_display_get_default();
171+
if (!display) {
172+
std::cerr << "No display available for window creation" << std::endl;
173+
return nullptr;
174+
}
175+
176+
// Create a new GTK window
177+
GtkWidget* gtk_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
178+
if (!gtk_window) {
179+
std::cerr << "Failed to create GTK window" << std::endl;
180+
return nullptr;
181+
}
182+
183+
// Set window properties from options
184+
if (!options.title.empty()) {
185+
gtk_window_set_title(GTK_WINDOW(gtk_window), options.title.c_str());
186+
}
187+
188+
// Set window size
189+
if (options.size.width > 0 && options.size.height > 0) {
190+
gtk_window_set_default_size(GTK_WINDOW(gtk_window),
191+
options.size.width,
192+
options.size.height);
193+
}
194+
195+
// Set minimum size if specified
196+
if (options.minimum_size.width > 0 && options.minimum_size.height > 0) {
197+
GdkGeometry geometry;
198+
geometry.min_width = options.minimum_size.width;
199+
geometry.min_height = options.minimum_size.height;
200+
gtk_window_set_geometry_hints(GTK_WINDOW(gtk_window), nullptr, &geometry, GDK_HINT_MIN_SIZE);
201+
}
202+
203+
// Set maximum size if specified
204+
if (options.maximum_size.width > 0 && options.maximum_size.height > 0) {
205+
GdkGeometry geometry;
206+
geometry.max_width = options.maximum_size.width;
207+
geometry.max_height = options.maximum_size.height;
208+
gtk_window_set_geometry_hints(GTK_WINDOW(gtk_window), nullptr, &geometry, GDK_HINT_MAX_SIZE);
209+
}
210+
211+
// Center the window if requested
212+
if (options.centered) {
213+
gtk_window_set_position(GTK_WINDOW(gtk_window), GTK_WIN_POS_CENTER);
214+
}
215+
216+
// Show the window
217+
gtk_widget_show(gtk_window);
218+
219+
// Get the GdkWindow after the widget is realized
220+
GdkWindow* gdk_window = gtk_widget_get_window(gtk_window);
221+
if (!gdk_window) {
222+
// If window is not yet realized, realize it first
223+
gtk_widget_realize(gtk_window);
224+
gdk_window = gtk_widget_get_window(gtk_window);
225+
}
226+
227+
if (!gdk_window) {
228+
std::cerr << "Failed to get GdkWindow from GTK widget" << std::endl;
229+
gtk_widget_destroy(gtk_window);
230+
return nullptr;
231+
}
232+
233+
// Create our Window wrapper
234+
auto window = std::make_shared<Window>((void*)gdk_window);
235+
WindowID window_id = (WindowID)gdk_window;
236+
237+
// Store in our cache
238+
windows_[window_id] = window;
239+
240+
std::cout << "Created window with ID: " << window_id << std::endl;
241+
242+
return window;
172243
}
173244

174245
bool WindowManager::Destroy(WindowID id) {

0 commit comments

Comments
 (0)