11#include " ../../message_dialog.h"
22#include " ../../dialog.h"
33
4+ #include < gtk/gtk.h>
5+
46namespace nativeapi {
57
6- // Private implementation class for MessageDialog (Linux stub)
8+ // Private implementation class for MessageDialog
79class MessageDialog ::Impl {
810 public:
911 Impl (const std::string& title, const std::string& message)
10- : title_(title), message_(message) {
11- // TODO: Implement GTK message dialog (GtkMessageDialog or GtkDialog)
12+ : title_(title), message_(message), dialog_(nullptr ), is_open_(false ) {
13+ // Ensure GTK is initialized
14+ if (!gdk_display_get_default ()) {
15+ gtk_init_check (nullptr , nullptr );
16+ }
1217 }
1318
1419 ~Impl () {
15- // TODO: Cleanup if needed
20+ if (dialog_) {
21+ gtk_widget_destroy (dialog_);
22+ dialog_ = nullptr ;
23+ }
1624 }
1725
1826 void SetTitle (const std::string& title) {
1927 title_ = title;
28+ // Title will be applied when dialog is opened
2029 }
2130
2231 std::string GetTitle () const {
@@ -25,26 +34,126 @@ class MessageDialog::Impl {
2534
2635 void SetMessage (const std::string& message) {
2736 message_ = message;
37+ // Message will be applied when dialog is opened
2838 }
2939
3040 std::string GetMessage () const {
3141 return message_;
3242 }
3343
3444 bool Open (DialogModality modality) {
35- // TODO: Implement using gtk_message_dialog_new or gtk_dialog_new
36- // For now, return false (not implemented)
37- return false ;
45+ // Ensure GTK is initialized
46+ if (!gdk_display_get_default ()) {
47+ if (!gtk_init_check (nullptr , nullptr )) {
48+ return false ;
49+ }
50+ }
51+
52+ // For modal dialogs, always create a new dialog since gtk_dialog_run destroys it
53+ // For non-modal dialogs, close existing dialog if open before creating new one
54+ // This ensures title and message are always up to date
55+ if (dialog_ && GTK_IS_WIDGET (dialog_)) {
56+ // Destroy old dialog if exists
57+ gtk_widget_destroy (dialog_);
58+ dialog_ = nullptr ;
59+ is_open_ = false ;
60+ }
61+
62+ // Create a new message dialog
63+ dialog_ = gtk_message_dialog_new (
64+ nullptr , // No parent window
65+ GTK_DIALOG_MODAL, // Default to modal (will be overridden for non-modal)
66+ GTK_MESSAGE_INFO, // Message type
67+ GTK_BUTTONS_OK, // Buttons
68+ " %s" , // Format string
69+ message_.c_str ());
70+
71+ if (!dialog_) {
72+ return false ;
73+ }
74+
75+ // Set title
76+ gtk_window_set_title (GTK_WINDOW (dialog_), title_.c_str ());
77+
78+ // Connect destroy signal to track when dialog is closed by user
79+ g_signal_connect (dialog_, " response" , G_CALLBACK (OnResponse), this );
80+ g_signal_connect (dialog_, " destroy" , G_CALLBACK (OnDestroy), this );
81+
82+ // Handle modality
83+ switch (modality) {
84+ case DialogModality::None:
85+ // Non-modal: show the dialog without blocking
86+ gtk_window_set_modal (GTK_WINDOW (dialog_), FALSE );
87+ gtk_widget_show (dialog_);
88+ is_open_ = true ;
89+ break ;
90+
91+ case DialogModality::Application:
92+ case DialogModality::Window:
93+ // Modal: block until user responds
94+ gtk_window_set_modal (GTK_WINDOW (dialog_), TRUE );
95+ is_open_ = true ;
96+
97+ // Run the dialog modally - this blocks until user responds
98+ // Note: gtk_dialog_run automatically destroys the dialog when done
99+ gtk_dialog_run (GTK_DIALOG (dialog_));
100+
101+ // After gtk_dialog_run returns, the dialog has been dismissed and destroyed
102+ // The OnDestroy callback will set dialog_ to nullptr
103+ is_open_ = false ;
104+ break ;
105+ }
106+
107+ return true ;
38108 }
39109
40110 bool Close () {
41- // TODO: Implement closing logic using gtk_widget_destroy
42- return false ;
111+ if (!dialog_ || !is_open_) {
112+ return false ;
113+ }
114+
115+ // Close the dialog programmatically
116+ gtk_dialog_response (GTK_DIALOG (dialog_), GTK_RESPONSE_CLOSE);
117+
118+ // If it's a modal dialog, we need to destroy it manually
119+ // (gtk_dialog_run already destroyed it)
120+ if (dialog_) {
121+ gtk_widget_destroy (dialog_);
122+ dialog_ = nullptr ;
123+ }
124+
125+ is_open_ = false ;
126+ return true ;
43127 }
44128
45129 private:
46130 std::string title_;
47131 std::string message_;
132+ GtkWidget* dialog_;
133+ bool is_open_;
134+
135+ static void OnResponse (GtkDialog* dialog, gint response_id, gpointer user_data) {
136+ Impl* impl = static_cast <Impl*>(user_data);
137+
138+ // Mark as closed
139+ impl->is_open_ = false ;
140+
141+ // For non-modal dialogs, destroy the dialog when user responds
142+ if (!gtk_window_get_modal (GTK_WINDOW (dialog))) {
143+ gtk_widget_destroy (GTK_WIDGET (dialog));
144+ impl->dialog_ = nullptr ;
145+ }
146+ }
147+
148+ static void OnDestroy (GtkWidget* widget, gpointer user_data) {
149+ Impl* impl = static_cast <Impl*>(user_data);
150+
151+ // Clear the dialog pointer when it's destroyed
152+ if (impl->dialog_ == widget) {
153+ impl->dialog_ = nullptr ;
154+ impl->is_open_ = false ;
155+ }
156+ }
48157};
49158
50159// MessageDialog implementation
0 commit comments