mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
f4f683a469
Make it more clear that the function is supposed to be called during the dispose sequence of a widget.
549 lines
17 KiB
C
549 lines
17 KiB
C
#include "config.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
typedef GtkApplication DemoApplication;
|
|
typedef GtkApplicationClass DemoApplicationClass;
|
|
|
|
static GType demo_application_get_type (void);
|
|
G_DEFINE_TYPE (DemoApplication, demo_application, GTK_TYPE_APPLICATION)
|
|
|
|
typedef struct {
|
|
GtkApplicationWindow parent_instance;
|
|
|
|
GtkWidget *message;
|
|
GtkWidget *infobar;
|
|
GtkWidget *status;
|
|
GtkWidget *menubutton;
|
|
GMenuModel *toolmenu;
|
|
GtkTextBuffer *buffer;
|
|
|
|
int width;
|
|
int height;
|
|
gboolean maximized;
|
|
gboolean fullscreen;
|
|
} DemoApplicationWindow;
|
|
typedef GtkApplicationWindowClass DemoApplicationWindowClass;
|
|
|
|
static GType demo_application_window_get_type (void);
|
|
G_DEFINE_TYPE (DemoApplicationWindow, demo_application_window, GTK_TYPE_APPLICATION_WINDOW)
|
|
|
|
static void create_window (GApplication *app, const char *contents);
|
|
|
|
static void
|
|
show_action_dialog (GSimpleAction *action)
|
|
{
|
|
const char *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_window_destroy), NULL);
|
|
|
|
gtk_widget_show (dialog);
|
|
}
|
|
|
|
static void
|
|
show_action_infobar (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer data)
|
|
{
|
|
DemoApplicationWindow *window = data;
|
|
char *text;
|
|
const char *name;
|
|
const char *value;
|
|
|
|
name = g_action_get_name (G_ACTION (action));
|
|
value = g_variant_get_string (parameter, NULL);
|
|
|
|
text = g_strdup_printf ("You activated radio action: \"%s\".\n"
|
|
"Current value: %s", name, value);
|
|
gtk_label_set_text (GTK_LABEL (window->message), text);
|
|
gtk_widget_show (window->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,
|
|
int 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_window_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 char *authors[] = {
|
|
"Peter Mattis",
|
|
"Spencer Kimball",
|
|
"Josh MacDonald",
|
|
"and many more...",
|
|
NULL
|
|
};
|
|
|
|
const char *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", "org.gtk.Demo4",
|
|
"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_window_destroy (GTK_WINDOW (win));
|
|
|
|
list = next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
update_statusbar (GtkTextBuffer *buffer,
|
|
DemoApplicationWindow *window)
|
|
{
|
|
char *msg;
|
|
int row, col;
|
|
int count;
|
|
GtkTextIter iter;
|
|
|
|
/* clear any previous message, underflow is allowed */
|
|
gtk_statusbar_pop (GTK_STATUSBAR (window->status), 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 (GTK_STATUSBAR (window->status), 0, msg);
|
|
|
|
g_free (msg);
|
|
}
|
|
|
|
static void
|
|
mark_set_callback (GtkTextBuffer *buffer,
|
|
const GtkTextIter *new_location,
|
|
GtkTextMark *mark,
|
|
DemoApplicationWindow *window)
|
|
{
|
|
update_statusbar (buffer, window);
|
|
}
|
|
|
|
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_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[] = {
|
|
{ "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, DemoApplicationWindow *window)
|
|
{
|
|
gtk_widget_hide (window->infobar);
|
|
}
|
|
|
|
static void
|
|
startup (GApplication *app)
|
|
{
|
|
GtkBuilder *builder;
|
|
|
|
G_APPLICATION_CLASS (demo_application_parent_class)->startup (app);
|
|
|
|
builder = gtk_builder_new ();
|
|
gtk_builder_add_from_resource (builder, "/application_demo/menus.ui", NULL);
|
|
|
|
gtk_application_set_menubar (GTK_APPLICATION (app),
|
|
G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
|
|
|
|
g_object_unref (builder);
|
|
}
|
|
|
|
static void
|
|
create_window (GApplication *app,
|
|
const char *content)
|
|
{
|
|
DemoApplicationWindow *window;
|
|
|
|
window = (DemoApplicationWindow *)g_object_new (demo_application_window_get_type (),
|
|
"application", app,
|
|
"show-menubar", TRUE,
|
|
NULL);
|
|
if (content)
|
|
gtk_text_buffer_set_text (window->buffer, content, -1);
|
|
|
|
gtk_window_present (GTK_WINDOW (window));
|
|
}
|
|
|
|
static void
|
|
activate (GApplication *app)
|
|
{
|
|
create_window (app, NULL);
|
|
}
|
|
|
|
static void
|
|
demo_application_init (DemoApplication *app)
|
|
{
|
|
GSettings *settings;
|
|
GAction *action;
|
|
|
|
settings = g_settings_new ("org.gtk.Demo4");
|
|
|
|
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_object_unref (settings);
|
|
}
|
|
|
|
static void
|
|
demo_application_class_init (DemoApplicationClass *class)
|
|
{
|
|
GApplicationClass *app_class = G_APPLICATION_CLASS (class);
|
|
|
|
app_class->startup = startup;
|
|
app_class->activate = activate;
|
|
}
|
|
|
|
static void
|
|
demo_application_window_store_state (DemoApplicationWindow *win)
|
|
{
|
|
GSettings *settings;
|
|
|
|
settings = g_settings_new ("org.gtk.Demo4");
|
|
g_settings_set (settings, "window-size", "(ii)", win->width, win->height);
|
|
g_settings_set_boolean (settings, "maximized", win->maximized);
|
|
g_settings_set_boolean (settings, "fullscreen", win->fullscreen);
|
|
g_object_unref (settings);
|
|
}
|
|
|
|
static void
|
|
demo_application_window_load_state (DemoApplicationWindow *win)
|
|
{
|
|
GSettings *settings;
|
|
|
|
settings = g_settings_new ("org.gtk.Demo4");
|
|
g_settings_get (settings, "window-size", "(ii)", &win->width, &win->height);
|
|
win->maximized = g_settings_get_boolean (settings, "maximized");
|
|
win->fullscreen = g_settings_get_boolean (settings, "fullscreen");
|
|
g_object_unref (settings);
|
|
}
|
|
|
|
static void
|
|
demo_application_window_init (DemoApplicationWindow *window)
|
|
{
|
|
GtkWidget *popover;
|
|
|
|
window->width = -1;
|
|
window->height = -1;
|
|
window->maximized = FALSE;
|
|
window->fullscreen = FALSE;
|
|
|
|
gtk_widget_init_template (GTK_WIDGET (window));
|
|
|
|
popover = gtk_popover_menu_new_from_model (window->toolmenu);
|
|
gtk_menu_button_set_popover (GTK_MENU_BUTTON (window->menubutton), popover);
|
|
|
|
g_action_map_add_action_entries (G_ACTION_MAP (window),
|
|
win_entries, G_N_ELEMENTS (win_entries),
|
|
window);
|
|
}
|
|
|
|
static void
|
|
demo_application_window_constructed (GObject *object)
|
|
{
|
|
DemoApplicationWindow *window = (DemoApplicationWindow *)object;
|
|
|
|
demo_application_window_load_state (window);
|
|
|
|
gtk_window_set_default_size (GTK_WINDOW (window), window->width, window->height);
|
|
|
|
if (window->maximized)
|
|
gtk_window_maximize (GTK_WINDOW (window));
|
|
|
|
if (window->fullscreen)
|
|
gtk_window_fullscreen (GTK_WINDOW (window));
|
|
|
|
G_OBJECT_CLASS (demo_application_window_parent_class)->constructed (object);
|
|
}
|
|
|
|
static void
|
|
demo_application_window_size_allocate (GtkWidget *widget,
|
|
int width,
|
|
int height,
|
|
int baseline)
|
|
{
|
|
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
|
|
|
|
GTK_WIDGET_CLASS (demo_application_window_parent_class)->size_allocate (widget,
|
|
width,
|
|
height,
|
|
baseline);
|
|
|
|
if (!window->maximized && !window->fullscreen)
|
|
gtk_window_get_default_size (GTK_WINDOW (window), &window->width, &window->height);
|
|
}
|
|
|
|
static void
|
|
surface_state_changed (GtkWidget *widget)
|
|
{
|
|
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
|
|
GdkToplevelState new_state;
|
|
|
|
new_state = gdk_toplevel_get_state (GDK_TOPLEVEL (gtk_native_get_surface (GTK_NATIVE (widget))));
|
|
window->maximized = (new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0;
|
|
window->fullscreen = (new_state & GDK_TOPLEVEL_STATE_FULLSCREEN) != 0;
|
|
}
|
|
|
|
static void
|
|
demo_application_window_realize (GtkWidget *widget)
|
|
{
|
|
GTK_WIDGET_CLASS (demo_application_window_parent_class)->realize (widget);
|
|
|
|
g_signal_connect_swapped (gtk_native_get_surface (GTK_NATIVE (widget)), "notify::state",
|
|
G_CALLBACK (surface_state_changed), widget);
|
|
}
|
|
|
|
static void
|
|
demo_application_window_unrealize (GtkWidget *widget)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (gtk_native_get_surface (GTK_NATIVE (widget)),
|
|
surface_state_changed, widget);
|
|
|
|
GTK_WIDGET_CLASS (demo_application_window_parent_class)->unrealize (widget);
|
|
}
|
|
|
|
static void
|
|
demo_application_window_dispose (GObject *object)
|
|
{
|
|
DemoApplicationWindow *window = (DemoApplicationWindow *)object;
|
|
|
|
demo_application_window_store_state (window);
|
|
|
|
gtk_widget_dispose_template (GTK_WIDGET (window), demo_application_window_get_type ());
|
|
|
|
G_OBJECT_CLASS (demo_application_window_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
demo_application_window_class_init (DemoApplicationWindowClass *class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
|
|
|
object_class->constructed = demo_application_window_constructed;
|
|
object_class->dispose = demo_application_window_dispose;
|
|
|
|
widget_class->size_allocate = demo_application_window_size_allocate;
|
|
widget_class->realize = demo_application_window_realize;
|
|
widget_class->unrealize = demo_application_window_unrealize;
|
|
|
|
gtk_widget_class_set_template_from_resource (widget_class, "/application_demo/application.ui");
|
|
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, message);
|
|
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, infobar);
|
|
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, status);
|
|
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, buffer);
|
|
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menubutton);
|
|
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, toolmenu);
|
|
gtk_widget_class_bind_template_callback (widget_class, clicked_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, update_statusbar);
|
|
gtk_widget_class_bind_template_callback (widget_class, mark_set_callback);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GtkApplication *app;
|
|
|
|
app = GTK_APPLICATION (g_object_new (demo_application_get_type (),
|
|
"application-id", "org.gtk.Demo4.App",
|
|
"flags", G_APPLICATION_HANDLES_OPEN,
|
|
NULL));
|
|
|
|
return g_application_run (G_APPLICATION (app), 0, NULL);
|
|
}
|