forked from AuroraMiddleware/gtk
51dc4873fd
Its very easy to get extra references to the NativeDialog so that when you release your last reference any visible dialog is not hidden. We handle this by adding a destroy method similar to how you destroy regular toplevels.
531 lines
15 KiB
C
531 lines
15 KiB
C
/* Application Class
|
|
*
|
|
* Demonstrates a simple application.
|
|
*
|
|
* This examples uses GtkApplication, GtkApplicationWindow, GtkBuilder
|
|
* as well as GMenu and GResource. Due to the way GtkApplication is structured,
|
|
* it is run as a separate process.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#ifdef STANDALONE
|
|
|
|
static void create_window (GApplication *app, const char *contents);
|
|
|
|
static void
|
|
show_action_dialog (GSimpleAction *action)
|
|
{
|
|
const gchar *name;
|
|
GtkWidget *dialog;
|
|
|
|
name = g_action_get_name (G_ACTION (action));
|
|
|
|
dialog = gtk_message_dialog_new (NULL,
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_INFO,
|
|
GTK_BUTTONS_CLOSE,
|
|
"You activated action: \"%s\"",
|
|
name);
|
|
|
|
g_signal_connect (dialog, "response",
|
|
G_CALLBACK (gtk_widget_destroy), NULL);
|
|
|
|
gtk_widget_show (dialog);
|
|
}
|
|
|
|
static void
|
|
show_action_infobar (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer window)
|
|
{
|
|
GtkWidget *infobar;
|
|
GtkWidget *message;
|
|
gchar *text;
|
|
const gchar *name;
|
|
const gchar *value;
|
|
|
|
name = g_action_get_name (G_ACTION (action));
|
|
value = g_variant_get_string (parameter, NULL);
|
|
|
|
message = g_object_get_data (G_OBJECT (window), "message");
|
|
infobar = g_object_get_data (G_OBJECT (window), "infobar");
|
|
text = g_strdup_printf ("You activated radio action: \"%s\".\n"
|
|
"Current value: %s", name, value);
|
|
gtk_label_set_text (GTK_LABEL (message), text);
|
|
gtk_widget_show (infobar);
|
|
g_free (text);
|
|
}
|
|
|
|
static void
|
|
activate_action (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
show_action_dialog (action);
|
|
}
|
|
|
|
static void
|
|
activate_new (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
GApplication *app = user_data;
|
|
|
|
create_window (app, NULL);
|
|
}
|
|
|
|
static void
|
|
open_response_cb (GtkNativeDialog *dialog,
|
|
gint response_id,
|
|
gpointer user_data)
|
|
{
|
|
GtkFileChooserNative *native = user_data;
|
|
GApplication *app = g_object_get_data (G_OBJECT (native), "app");
|
|
GtkWidget *message_dialog;
|
|
GFile *file;
|
|
char *contents;
|
|
GError *error = NULL;
|
|
|
|
if (response_id == GTK_RESPONSE_ACCEPT)
|
|
{
|
|
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
|
|
|
|
if (g_file_load_contents (file, NULL, &contents, NULL, NULL, &error))
|
|
{
|
|
create_window (app, contents);
|
|
g_free (contents);
|
|
}
|
|
else
|
|
{
|
|
message_dialog = gtk_message_dialog_new (NULL,
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_ERROR,
|
|
GTK_BUTTONS_CLOSE,
|
|
"Error loading file: \"%s\"",
|
|
error->message);
|
|
g_signal_connect (message_dialog, "response",
|
|
G_CALLBACK (gtk_widget_destroy), NULL);
|
|
gtk_widget_show (message_dialog);
|
|
g_error_free (error);
|
|
}
|
|
}
|
|
|
|
gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
|
|
g_object_unref (native);
|
|
}
|
|
|
|
|
|
static void
|
|
activate_open (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
GApplication *app = user_data;
|
|
GtkFileChooserNative *native;
|
|
|
|
native = gtk_file_chooser_native_new ("Open File",
|
|
NULL,
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
"_Open",
|
|
"_Cancel");
|
|
|
|
g_object_set_data_full (G_OBJECT (native), "app", g_object_ref (app), g_object_unref);
|
|
g_signal_connect (native,
|
|
"response",
|
|
G_CALLBACK (open_response_cb),
|
|
native);
|
|
|
|
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
|
|
}
|
|
|
|
static void
|
|
activate_toggle (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
GVariant *state;
|
|
|
|
show_action_dialog (action);
|
|
|
|
state = g_action_get_state (G_ACTION (action));
|
|
g_action_change_state (G_ACTION (action), g_variant_new_boolean (!g_variant_get_boolean (state)));
|
|
g_variant_unref (state);
|
|
}
|
|
|
|
static void
|
|
activate_radio (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
show_action_infobar (action, parameter, user_data);
|
|
|
|
g_action_change_state (G_ACTION (action), parameter);
|
|
}
|
|
|
|
static void
|
|
activate_about (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
GtkWidget *window = user_data;
|
|
|
|
const gchar *authors[] = {
|
|
"Peter Mattis",
|
|
"Spencer Kimball",
|
|
"Josh MacDonald",
|
|
"and many more...",
|
|
NULL
|
|
};
|
|
|
|
const gchar *documentors[] = {
|
|
"Owen Taylor",
|
|
"Tony Gale",
|
|
"Matthias Clasen <mclasen@redhat.com>",
|
|
"and many more...",
|
|
NULL
|
|
};
|
|
|
|
gtk_show_about_dialog (GTK_WINDOW (window),
|
|
"program-name", "GTK+ Code Demos",
|
|
"version", g_strdup_printf ("%s,\nRunning against GTK+ %d.%d.%d",
|
|
PACKAGE_VERSION,
|
|
gtk_get_major_version (),
|
|
gtk_get_minor_version (),
|
|
gtk_get_micro_version ()),
|
|
"copyright", "(C) 1997-2013 The GTK+ Team",
|
|
"license-type", GTK_LICENSE_LGPL_2_1,
|
|
"website", "http://www.gtk.org",
|
|
"comments", "Program to demonstrate GTK+ functions.",
|
|
"authors", authors,
|
|
"documenters", documentors,
|
|
"logo-icon-name", "gtk3-demo",
|
|
"title", "About GTK+ Code Demos",
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
activate_quit (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
GtkApplication *app = user_data;
|
|
GtkWidget *win;
|
|
GList *list, *next;
|
|
|
|
list = gtk_application_get_windows (app);
|
|
while (list)
|
|
{
|
|
win = list->data;
|
|
next = list->next;
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (win));
|
|
|
|
list = next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
update_statusbar (GtkTextBuffer *buffer,
|
|
GtkStatusbar *statusbar)
|
|
{
|
|
gchar *msg;
|
|
gint row, col;
|
|
gint count;
|
|
GtkTextIter iter;
|
|
|
|
/* clear any previous message, underflow is allowed */
|
|
gtk_statusbar_pop (statusbar, 0);
|
|
|
|
count = gtk_text_buffer_get_char_count (buffer);
|
|
|
|
gtk_text_buffer_get_iter_at_mark (buffer,
|
|
&iter,
|
|
gtk_text_buffer_get_insert (buffer));
|
|
|
|
row = gtk_text_iter_get_line (&iter);
|
|
col = gtk_text_iter_get_line_offset (&iter);
|
|
|
|
msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document",
|
|
row, col, count);
|
|
|
|
gtk_statusbar_push (statusbar, 0, msg);
|
|
|
|
g_free (msg);
|
|
}
|
|
|
|
static void
|
|
mark_set_callback (GtkTextBuffer *buffer,
|
|
const GtkTextIter *new_location,
|
|
GtkTextMark *mark,
|
|
gpointer data)
|
|
{
|
|
update_statusbar (buffer, GTK_STATUSBAR (data));
|
|
}
|
|
|
|
static void
|
|
change_theme_state (GSimpleAction *action,
|
|
GVariant *state,
|
|
gpointer user_data)
|
|
{
|
|
GtkSettings *settings = gtk_settings_get_default ();
|
|
|
|
g_object_set (G_OBJECT (settings),
|
|
"gtk-application-prefer-dark-theme",
|
|
g_variant_get_boolean (state),
|
|
NULL);
|
|
|
|
g_simple_action_set_state (action, state);
|
|
}
|
|
|
|
static void
|
|
change_titlebar_state (GSimpleAction *action,
|
|
GVariant *state,
|
|
gpointer user_data)
|
|
{
|
|
GtkWindow *window = user_data;
|
|
|
|
gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (window),
|
|
g_variant_get_boolean (state));
|
|
|
|
g_simple_action_set_state (action, state);
|
|
}
|
|
|
|
static void
|
|
change_radio_state (GSimpleAction *action,
|
|
GVariant *state,
|
|
gpointer user_data)
|
|
{
|
|
g_simple_action_set_state (action, state);
|
|
}
|
|
|
|
static GActionEntry app_entries[] = {
|
|
{ "new", activate_new, NULL, NULL, NULL },
|
|
{ "open", activate_open, NULL, NULL, NULL },
|
|
{ "save", activate_action, NULL, NULL, NULL },
|
|
{ "save-as", activate_action, NULL, NULL, NULL },
|
|
{ "quit", activate_quit, NULL, NULL, NULL },
|
|
{ "dark", activate_toggle, NULL, "false", change_theme_state }
|
|
};
|
|
|
|
static GActionEntry win_entries[] = {
|
|
{ "titlebar", activate_toggle, NULL, "false", change_titlebar_state },
|
|
{ "shape", activate_radio, "s", "'oval'", change_radio_state },
|
|
{ "bold", activate_toggle, NULL, "false", NULL },
|
|
{ "about", activate_about, NULL, NULL, NULL },
|
|
{ "file1", activate_action, NULL, NULL, NULL },
|
|
{ "logo", activate_action, NULL, NULL, NULL }
|
|
};
|
|
|
|
static void
|
|
clicked_cb (GtkWidget *widget, GtkWidget *info)
|
|
{
|
|
gtk_widget_hide (info);
|
|
}
|
|
|
|
static void
|
|
startup (GApplication *app)
|
|
{
|
|
GtkBuilder *builder;
|
|
GMenuModel *appmenu;
|
|
GMenuModel *menubar;
|
|
|
|
builder = gtk_builder_new ();
|
|
gtk_builder_add_from_resource (builder, "/application/menus.ui", NULL);
|
|
|
|
appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu");
|
|
menubar = (GMenuModel *)gtk_builder_get_object (builder, "menubar");
|
|
|
|
gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu);
|
|
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
|
|
|
g_object_unref (builder);
|
|
}
|
|
|
|
static void
|
|
create_window (GApplication *app,
|
|
const char *content_text)
|
|
{
|
|
GtkBuilder *builder;
|
|
GtkWidget *window;
|
|
GtkWidget *grid;
|
|
GtkWidget *contents;
|
|
GtkWidget *status;
|
|
GtkWidget *message;
|
|
GtkWidget *button;
|
|
GtkWidget *infobar;
|
|
GtkWidget *menutool;
|
|
GMenuModel *toolmenu;
|
|
GtkTextBuffer *buffer;
|
|
|
|
window = gtk_application_window_new (GTK_APPLICATION (app));
|
|
gtk_window_set_title (GTK_WINDOW (window), "Application Class");
|
|
gtk_window_set_icon_name (GTK_WINDOW (window), "document-open");
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
|
|
|
|
g_action_map_add_action_entries (G_ACTION_MAP (window),
|
|
win_entries, G_N_ELEMENTS (win_entries),
|
|
window);
|
|
|
|
builder = gtk_builder_new ();
|
|
gtk_builder_add_from_resource (builder, "/application/application.ui", NULL);
|
|
|
|
grid = (GtkWidget *)gtk_builder_get_object (builder, "grid");
|
|
contents = (GtkWidget *)gtk_builder_get_object (builder, "contents");
|
|
status = (GtkWidget *)gtk_builder_get_object (builder, "status");
|
|
message = (GtkWidget *)gtk_builder_get_object (builder, "message");
|
|
button = (GtkWidget *)gtk_builder_get_object (builder, "button");
|
|
infobar = (GtkWidget *)gtk_builder_get_object (builder, "infobar");
|
|
menutool = (GtkWidget *)gtk_builder_get_object (builder, "menutool");
|
|
toolmenu = (GMenuModel *)gtk_builder_get_object (builder, "toolmenu");
|
|
|
|
g_object_set_data (G_OBJECT (window), "message", message);
|
|
g_object_set_data (G_OBJECT (window), "infobar", infobar);
|
|
|
|
gtk_container_add (GTK_CONTAINER (window), grid);
|
|
|
|
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (menutool),
|
|
gtk_menu_new_from_model (toolmenu));
|
|
|
|
gtk_widget_grab_focus (contents);
|
|
g_signal_connect (button, "clicked", G_CALLBACK (clicked_cb), infobar);
|
|
|
|
/* Show text widget info in the statusbar */
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (contents));
|
|
if (content_text)
|
|
gtk_text_buffer_set_text (buffer, content_text, -1);
|
|
g_signal_connect_object (buffer, "changed",
|
|
G_CALLBACK (update_statusbar), status, 0);
|
|
g_signal_connect_object (buffer, "mark-set",
|
|
G_CALLBACK (mark_set_callback), status, 0);
|
|
|
|
update_statusbar (buffer, GTK_STATUSBAR (status));
|
|
|
|
gtk_widget_show_all (window);
|
|
|
|
g_object_unref (builder);
|
|
}
|
|
|
|
static void
|
|
activate (GApplication *app)
|
|
{
|
|
create_window (app, NULL);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GtkApplication *app;
|
|
GSettings *settings;
|
|
GAction *action;
|
|
|
|
gtk_init (NULL, NULL);
|
|
|
|
app = gtk_application_new ("org.gtk.Demo2", 0);
|
|
settings = g_settings_new ("org.gtk.Demo");
|
|
|
|
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
|
app_entries, G_N_ELEMENTS (app_entries),
|
|
app);
|
|
|
|
action = g_settings_create_action (settings, "color");
|
|
|
|
g_action_map_add_action (G_ACTION_MAP (app), action);
|
|
|
|
g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
|
|
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
|
|
|
g_application_run (G_APPLICATION (app), 0, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else /* !STANDALONE */
|
|
|
|
static gboolean name_seen;
|
|
static GtkWidget *placeholder;
|
|
|
|
static void
|
|
on_name_appeared (GDBusConnection *connection,
|
|
const gchar *name,
|
|
const gchar *name_owner,
|
|
gpointer user_data)
|
|
{
|
|
name_seen = TRUE;
|
|
}
|
|
|
|
static void
|
|
on_name_vanished (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer user_data)
|
|
{
|
|
if (!name_seen)
|
|
return;
|
|
|
|
if (placeholder)
|
|
{
|
|
gtk_widget_destroy (placeholder);
|
|
g_object_unref (placeholder);
|
|
placeholder = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef G_OS_WIN32
|
|
#define APP_EXTENSION ".exe"
|
|
#else
|
|
#define APP_EXTENSION
|
|
#endif
|
|
|
|
GtkWidget *
|
|
do_application (GtkWidget *toplevel)
|
|
{
|
|
static guint watch = 0;
|
|
|
|
if (watch == 0)
|
|
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
|
"org.gtk.Demo2",
|
|
0,
|
|
on_name_appeared,
|
|
on_name_vanished,
|
|
NULL, NULL);
|
|
|
|
if (placeholder == NULL)
|
|
{
|
|
const gchar *command;
|
|
GError *error = NULL;
|
|
|
|
if (g_file_test ("./gtk3-demo-application" APP_EXTENSION, G_FILE_TEST_IS_EXECUTABLE))
|
|
command = "./gtk3-demo-application" APP_EXTENSION;
|
|
else
|
|
command = "gtk3-demo-application";
|
|
|
|
if (!g_spawn_command_line_async (command, &error))
|
|
{
|
|
g_warning ("%s", error->message);
|
|
g_error_free (error);
|
|
}
|
|
|
|
placeholder = gtk_label_new ("");
|
|
g_object_ref_sink (placeholder);
|
|
}
|
|
else
|
|
{
|
|
g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
|
|
"org.gtk.Demo2",
|
|
"/org/gtk/Demo2",
|
|
"org.gtk.Actions",
|
|
"Activate",
|
|
g_variant_new ("(sava{sv})", "quit", NULL, NULL),
|
|
NULL,
|
|
0,
|
|
G_MAXINT,
|
|
NULL, NULL);
|
|
}
|
|
|
|
return placeholder;
|
|
}
|
|
|
|
#endif
|