[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
On Fri, 2010-07-02 at 10:54 +0200, Elias Pschernig wrote:
>
> The log window seems like a good idea though since also in OSX and Linux
> printfs aren't always visible. I can make the GTK version of it.
>
I made a quick GTK-only patch. Well, threading issues made it less quick
than I would have liked :P Anyway, the API is this:
window = al_open_native_log_window(title, flags)
al_close_native_log_window(window)
al_append_log(window, text)
al_extend_log(window, text)
append adds the text as a new line at the end of the log, extend just
extends the last line but doesn't at a new one. Not sure how to name
those two or whether there should be two functions. Could just as well
require use of "\n" at the end if you want a new line. Should probably
also make it take printf style parameters.
--
Elias Pschernig <elias.pschernig@xxxxxxxxxx>
diff --git a/addons/native_dialog/allegro5/allegro_native_dialog.h b/addons/native_dialog/allegro5/allegro_native_dialog.h
index 900591f..3aa25cb 100644
--- a/addons/native_dialog/allegro5/allegro_native_dialog.h
+++ b/addons/native_dialog/allegro5/allegro_native_dialog.h
@@ -53,6 +53,15 @@ ALLEGRO_DIALOG_FUNC(
ALLEGRO_DIALOG_FUNC(void, al_destroy_native_dialog, (ALLEGRO_NATIVE_DIALOG *fc));
ALLEGRO_DIALOG_FUNC(uint32_t, al_get_allegro_native_dialog_version, (void));
+ALLEGRO_DIALOG_FUNC(ALLEGRO_NATIVE_DIALOG *, al_open_native_log_window,
+ (char const *title, int flags));
+ALLEGRO_DIALOG_FUNC(void, al_close_native_log_window,
+ (ALLEGRO_NATIVE_DIALOG *textlog));
+ALLEGRO_DIALOG_FUNC(void, al_append_log,
+ (ALLEGRO_NATIVE_DIALOG *textlog, char const *text));
+ALLEGRO_DIALOG_FUNC(void, al_extend_log,
+ (ALLEGRO_NATIVE_DIALOG *textlog, char const *text));
+
#define ALLEGRO_FILECHOOSER_FILE_MUST_EXIST 1
#define ALLEGRO_FILECHOOSER_SAVE 2
#define ALLEGRO_FILECHOOSER_FOLDER 4
diff --git a/addons/native_dialog/allegro5/internal/aintern_native_dialog.h b/addons/native_dialog/allegro5/internal/aintern_native_dialog.h
index 8151fff..471b562 100644
--- a/addons/native_dialog/allegro5/internal/aintern_native_dialog.h
+++ b/addons/native_dialog/allegro5/internal/aintern_native_dialog.h
@@ -1,26 +1,44 @@
#ifndef __al_included_allegro_aintern_native_dialog_h
#define __al_included_allegro_aintern_native_dialog_h
+/* We could use different structs for the different dialogs. But why
+ * bother.
+ */
struct ALLEGRO_NATIVE_DIALOG
{
- ALLEGRO_PATH *initial_path;
ALLEGRO_USTR *title;
- ALLEGRO_USTR *heading;
ALLEGRO_USTR *text;
- ALLEGRO_USTR *patterns;
- ALLEGRO_USTR *buttons;
- ALLEGRO_PATH **paths;
-
int mode;
+
+ /* Only used by file chooser. */
+ ALLEGRO_PATH *initial_path;
size_t count;
+ ALLEGRO_PATH **paths;
+ ALLEGRO_USTR *patterns;
+
+ /* Only used by message box. */
+ ALLEGRO_USTR *heading;
+ ALLEGRO_USTR *buttons;
int pressed_button;
+
+ /* Only used by text log. */
+ ALLEGRO_THREAD *thread;
+ ALLEGRO_COND *text_cond;
+ ALLEGRO_MUTEX *text_mutex;
+ bool done;
+ int new_line;
/* Only used by platform implementations. */
bool is_active;
ALLEGRO_COND *cond;
+ void *window;
+ void *textview;
};
extern int _al_show_native_message_box(ALLEGRO_DISPLAY *display,
ALLEGRO_NATIVE_DIALOG *fd);
+extern void _al_open_native_log_window(ALLEGRO_NATIVE_DIALOG *textlog);
+extern void _al_close_native_log_window(ALLEGRO_NATIVE_DIALOG *textlog);
+void _al_append_to_textlog(ALLEGRO_NATIVE_DIALOG *textlog);
#endif
diff --git a/addons/native_dialog/dialog.c b/addons/native_dialog/dialog.c
index e841ad2..0bb49f4 100644
--- a/addons/native_dialog/dialog.c
+++ b/addons/native_dialog/dialog.c
@@ -109,3 +109,92 @@ void al_show_native_file_dialog(ALLEGRO_NATIVE_DIALOG *fd)
}
#endif
+
+/* This will only return when the text window is closed. */
+static void *textlog_proc(ALLEGRO_THREAD *thread, void *arg)
+{
+ ALLEGRO_NATIVE_DIALOG *textlog = arg;
+ _al_open_native_log_window(textlog);
+ return thread;
+}
+
+/* Function: al_show_native_textlog
+ */
+ALLEGRO_NATIVE_DIALOG *al_open_native_log_window(
+ char const *title, int flags)
+{
+ ALLEGRO_NATIVE_DIALOG *textlog = al_calloc(1, sizeof *textlog);
+ textlog->title = al_ustr_new(title);
+ textlog->mode = flags;
+ textlog->thread = al_create_thread(textlog_proc, textlog);
+ textlog->text_cond = al_create_cond();
+ textlog->text_mutex = al_create_mutex();
+
+ /* Unlike the other dialogs, this one never blocks as the intended
+ * use case is a log window running in the background for debugging
+ * purposes when no console can be used. Therefore we have it run
+ * in a separate thread.
+ */
+ al_start_thread(textlog->thread);
+ al_lock_mutex(textlog->text_mutex);
+ textlog->done = false;
+ while (!textlog->done) {
+ al_wait_cond(textlog->text_cond, textlog->text_mutex);
+ }
+ al_unlock_mutex(textlog->text_mutex);
+
+ return textlog;
+}
+
+void al_close_native_log_window(ALLEGRO_NATIVE_DIALOG *textlog)
+{
+ al_lock_mutex(textlog->text_mutex);
+ textlog->done = false;
+
+ _al_close_native_log_window(textlog);
+
+ while (!textlog->done) {
+ al_wait_cond(textlog->text_cond, textlog->text_mutex);
+ }
+
+ al_ustr_free(textlog->title);
+
+ al_unlock_mutex(textlog->text_mutex);
+
+ al_destroy_thread(textlog->thread);
+ al_destroy_cond(textlog->text_cond);
+ al_destroy_mutex(textlog->text_mutex);
+ al_free(textlog);
+}
+
+void al_append_or_extend_log(ALLEGRO_NATIVE_DIALOG *textlog,
+ char const *text, bool append)
+{
+ al_lock_mutex(textlog->text_mutex);
+ textlog->text = al_ustr_new(text);
+ textlog->new_line = append;
+ _al_append_to_textlog(textlog);
+
+ /* We wait until it is appended - that way we are sure it will
+ * work correctly even if 10 threads are calling us 60 times
+ * a second. (Of course calling us that often would be slow.)
+ */
+ textlog->done = false;
+ while (!textlog->done) {
+ al_wait_cond(textlog->text_cond, textlog->text_mutex);
+ }
+
+ al_ustr_free(textlog->text);
+
+ al_unlock_mutex(textlog->text_mutex);
+}
+
+void al_append_log(ALLEGRO_NATIVE_DIALOG *textlog, char const *text)
+{
+ al_append_or_extend_log(textlog, text, true);
+}
+
+void al_extend_log(ALLEGRO_NATIVE_DIALOG *textlog, char const *text)
+{
+ al_append_or_extend_log(textlog, text, false);
+}
diff --git a/addons/native_dialog/gtk_dialog.c b/addons/native_dialog/gtk_dialog.c
index 6631b21..7d91e7f 100644
--- a/addons/native_dialog/gtk_dialog.c
+++ b/addons/native_dialog/gtk_dialog.c
@@ -296,3 +296,96 @@ int _al_show_native_message_box(ALLEGRO_DISPLAY *display,
return fd->pressed_button;
}
+
+
+void _al_open_native_log_window(ALLEGRO_NATIVE_DIALOG *textlog)
+{
+ al_lock_mutex(textlog->text_mutex);
+
+ gtk_start_and_lock();
+
+ /* Create a new text log window. */
+ GtkWidget *top = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size(GTK_WINDOW(top), 640, 480);
+ gtk_window_set_title(GTK_WINDOW(top), al_cstr(textlog->title));
+ gtk_window_set_deletable(GTK_WINDOW(top), false);
+ g_signal_connect(G_OBJECT(top), "destroy", G_CALLBACK(destroy), textlog);
+ GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(top), scroll);
+ GtkWidget *view = gtk_text_view_new();
+ gtk_container_add(GTK_CONTAINER(scroll), view);
+ gtk_widget_show(view);
+ gtk_widget_show(scroll);
+ gtk_widget_show(top);
+ textlog->window = top;
+ textlog->textview = view;
+
+ /* Now notify al_show_native_textlog that the text log is ready. */
+ textlog->done = true;
+ al_signal_cond(textlog->text_cond);
+ al_unlock_mutex(textlog->text_mutex);
+
+ /* Keep running until the textlog is closed. */
+ gtk_unlock_and_wait(textlog);
+
+ /* Notify everyone that we're gone. */
+ al_lock_mutex(textlog->text_mutex);
+ textlog->done = true;
+ al_signal_cond(textlog->text_cond);
+ al_unlock_mutex(textlog->text_mutex);
+
+}
+
+static gboolean _al_append_to_textlog_called_in_gtk_thread(gpointer data)
+{
+ ALLEGRO_NATIVE_DIALOG *textlog = data;
+ al_lock_mutex(textlog->text_mutex);
+
+ GtkTextView *tv = GTK_TEXT_VIEW(textlog->textview);
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(tv);
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_end_iter(buffer, &iter);
+ if (!textlog->new_line)
+ gtk_text_iter_backward_chars(&iter, 1);
+
+ gtk_text_buffer_insert(buffer, &iter, al_cstr(textlog->text), -1);
+
+ if (textlog->new_line) {
+ gtk_text_buffer_get_end_iter(buffer, &iter);
+ gtk_text_buffer_insert(buffer, &iter, "\n", -1);
+
+ gtk_text_buffer_get_end_iter(buffer, &iter);
+ gtk_text_view_scroll_to_iter(tv, &iter, 0, false, 0, 0);
+ }
+
+ /* Notify the original caller that we are all done. */
+ textlog->done = true;
+ al_signal_cond(textlog->text_cond);
+ al_unlock_mutex(textlog->text_mutex);
+ return false;
+}
+
+void _al_append_to_textlog(ALLEGRO_NATIVE_DIALOG *textlog)
+{
+ gdk_threads_add_timeout(0, _al_append_to_textlog_called_in_gtk_thread, textlog);
+}
+
+static gboolean _al_close_native_log_window_called_in_gtk_thread(gpointer data)
+{
+ ALLEGRO_NATIVE_DIALOG *textlog = data;
+ /* This causes the GTK window as well as all of its children to
+ * be freed. Further it will call the destroy function which we
+ * connected to the destroy signal which in turn causes our
+ * gtk thread to quit.
+ */
+ gtk_widget_destroy(textlog->window);
+ return false;
+}
+
+void _al_close_native_log_window(ALLEGRO_NATIVE_DIALOG *textlog)
+{
+ gdk_threads_add_timeout(0, _al_close_native_log_window_called_in_gtk_thread, textlog);
+}
diff --git a/docs/src/refman/native_dialog.txt b/docs/src/refman/native_dialog.txt
index b76afdf..8d2d712 100644
--- a/docs/src/refman/native_dialog.txt
+++ b/docs/src/refman/native_dialog.txt
@@ -121,3 +121,26 @@ Example:
Returns the (compiled) version of the addon, in the same format as
[al_get_allegro_version].
+
+## API: al_open_native_log_window
+
+Shows a text window to which you can append log messages with
+[al_append_log]. This can be useful for debugging if you don't want
+to depend on a console being available.
+
+Use [al_close_native_log_window] to close the window again.
+
+## API: al_close_native_log_window
+
+Closes a message log window opened with [al_open_native_log_window]
+earlier.
+
+## API: al_append_log
+
+Appends a line of text to the message log window and scrolls to the
+bottom (if the line would not be visible otherwise).
+
+## API: al_extend_log
+
+Like [al_append_log] but instead of appending a new line, appends to
+the last existing line.
diff --git a/examples/ex_native_filechooser.c b/examples/ex_native_filechooser.c
index 494170c..dd983de 100644
--- a/examples/ex_native_filechooser.c
+++ b/examples/ex_native_filechooser.c
@@ -28,6 +28,31 @@ typedef struct
ALLEGRO_THREAD *thread;
} AsyncDialog;
+ALLEGRO_NATIVE_DIALOG *textlog;
+
+static void message(char const *format, ...)
+{
+ if (!textlog) return;
+ char str[1024];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(str, sizeof str, format, args);
+ va_end(args);
+
+ al_append_log(textlog, str);
+}
+
+static void message_ext(char const *format, ...)
+{
+ if (!textlog) return;
+ char str[1024];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(str, sizeof str, format, args);
+ va_end(args);
+
+ al_extend_log(textlog, str);
+}
/* Our thread to show the native file dialog. */
static void *async_file_dialog_thread_func(ALLEGRO_THREAD *thread, void *arg)
@@ -156,8 +181,13 @@ int main(void)
AsyncDialog *message_box = NULL;
bool redraw = false;
int button;
+ bool message_log = true;
al_init();
+
+ textlog = al_open_native_log_window("Log", 0);
+ message("Starting up log window.");
+
al_init_image_addon();
al_init_font_addon();
@@ -169,20 +199,28 @@ int main(void)
al_install_mouse();
al_install_keyboard();
+ message("Creating 640x480 window...");
+
display = al_create_display(640, 480);
if (!display) {
+ message_ext("failure.");
abort_example("Error creating display\n");
return 1;
}
+ message_ext("success.");
+ message("Loading font '%s'...", "data/fixed_font.tga");
font = al_load_font("data/fixed_font.tga", 0, 0);
if (!font) {
+ message_ext("failure.");
abort_example("Error loading data/fixed_font.tga\n");
return 1;
}
+ message_ext("success.");
timer = al_install_timer(1.0 / 30);
restart:
+ message("Starting main loop.");
queue = al_create_event_queue();
al_register_event_source(queue, al_get_keyboard_event_source());
al_register_event_source(queue, al_get_mouse_event_source());
@@ -191,6 +229,7 @@ restart:
al_start_timer(timer);
while (1) {
+ float h = al_get_display_height(display);
ALLEGRO_EVENT event;
al_wait_for_event(queue, &event);
@@ -206,8 +245,19 @@ restart:
* shown already, we show a new one.
*/
if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
+ message("Mouse clicked at %d,%d.", event.mouse.x, event.mouse.y);
if (event.mouse.y > 30) {
- if (!message_box) {
+ if (event.mouse.y > h - 30) {
+ message_log = !message_log;
+ if (message_log) {
+ textlog = al_open_native_log_window("Log", 0);
+ }
+ else {
+ al_close_native_log_window(textlog);
+ textlog = NULL;
+ }
+ }
+ else if (!message_box) {
message_box = spawn_async_message_dialog(display);
al_register_event_source(queue, &message_box->event_source);
}
@@ -261,11 +311,15 @@ restart:
al_clear_to_color(background);
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
al_draw_textf(font, cur_dialog ? inactive : active, x, y, ALLEGRO_ALIGN_CENTRE, "Open");
+ al_draw_textf(font, cur_dialog ? inactive : active, x, h - 30,
+ ALLEGRO_ALIGN_CENTRE, message_log ? "Close Message Log" : "Open Message Log");
if (old_dialog)
show_files_list(old_dialog->file_dialog, font, info);
al_flip_display();
}
}
+
+ message("Exiting.");
al_destroy_event_queue(queue);