From: Frédéric Péters Date: Sun, 19 Apr 2015 14:10:02 +0000 (+0200) Subject: use a single window, with tabs X-Git-Url: https://git.0d.be/?p=empathy.git;a=commitdiff_plain;h=15aa6a83ff96fad9f959762f2b57646f9e735cd1 use a single window, with tabs --- diff --git a/src/Makefile.am b/src/Makefile.am index 8806ae45..c792dd51 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,8 +58,7 @@ bin_PROGRAMS = \ libexec_PROGRAMS = \ empathy-auth-client \ - empathy-call \ - empathy-chat + empathy-call empathy_accounts_SOURCES = \ empathy-accounts.c empathy-accounts.h \ @@ -92,6 +91,7 @@ empathy_chat_SOURCES = \ empathy-chat-window.c empathy-chat-window.h \ empathy-invite-participant-dialog.c empathy-invite-participant-dialog.h \ empathy-chat.c \ + polari-fixed-size-frame.c polari-fixed-size-frame.h \ $(NULL) nodist_empathy_chat_SOURCES = \ @@ -151,6 +151,7 @@ empathy_handwritten_source = \ empathy-preferences.c empathy-preferences.h \ empathy-status-icon.c empathy-status-icon.h \ empathy-chat-manager.c empathy-chat-manager.h \ + polari-fixed-size-frame.c polari-fixed-size-frame.h \ empathy.c empathy_SOURCES = \ diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index b4963562..2f41d3d9 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -45,6 +45,7 @@ #include "empathy-sound-manager.h" #include "empathy-ui-utils.h" #include "empathy-utils.h" +#include "empathy-new-message-dialog.h" #define DEBUG_FLAG EMPATHY_DEBUG_CHAT #include "empathy-debug.h" @@ -170,7 +171,7 @@ static void empathy_chat_window_get_nb_chats (EmpathyChatWindow *self, guint *nb_rooms, guint *nb_private); -G_DEFINE_TYPE (EmpathyChatWindow, empathy_chat_window, GTK_TYPE_WINDOW) +G_DEFINE_TYPE (EmpathyChatWindow, empathy_chat_window, GTK_TYPE_BIN) static void chat_window_accel_cb (GtkAccelGroup *accelgroup, @@ -313,7 +314,7 @@ confirm_close (EmpathyChatWindow *self, } dialog = gtk_message_dialog_new ( - GTK_WINDOW (self), + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CANCEL, @@ -598,6 +599,9 @@ chat_window_contact_menu_update (EmpathyChatWindow *self) { GtkWidget *menu, *submenu, *orig_submenu; + if (self->priv->current_chat == NULL) + return; + if (self->priv->updating_menu) return; self->priv->updating_menu = TRUE; @@ -726,7 +730,7 @@ chat_window_title_update (EmpathyChatWindow *self) gchar *name; name = get_window_title_name (self); - gtk_window_set_title (GTK_WINDOW (self), name); + //gtk_window_set_title (GTK_WINDOW (self), name); g_free (name); } @@ -744,8 +748,8 @@ chat_window_icon_update (EmpathyChatWindow *self, /* Update window icon */ if (new_messages) { - gtk_window_set_icon_name (GTK_WINDOW (self), - EMPATHY_IMAGE_MESSAGE); + //gtk_window_set_icon_name (GTK_WINDOW (self), + // EMPATHY_IMAGE_MESSAGE); } else { @@ -757,14 +761,14 @@ chat_window_icon_update (EmpathyChatWindow *self, remote_contact = empathy_chat_get_remote_contact (self->priv->current_chat); icon = empathy_pixbuf_avatar_from_contact_scaled (remote_contact, 0, 0); - gtk_window_set_icon (GTK_WINDOW (self), icon); + //gtk_window_set_icon (GTK_WINDOW (self), icon); if (icon != NULL) g_object_unref (icon); } else { - gtk_window_set_icon_name (GTK_WINDOW (self), NULL); + //gtk_window_set_icon_name (GTK_WINDOW (self), NULL); } } } @@ -1253,7 +1257,7 @@ chat_window_invite_participant_activate_cb (GtkAction *action, tp_chat = empathy_chat_get_tp_chat (self->priv->current_chat); dialog = empathy_invite_participant_dialog_new ( - GTK_WINDOW (self), tp_chat); + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))), tp_chat); gtk_widget_show (dialog); @@ -1437,6 +1441,19 @@ chat_window_tabs_previous_activate_cb (GtkAction *action, gtk_notebook_prev_page (GTK_NOTEBOOK (self->priv->notebook)); } +void +empathy_chat_window_next_tab (EmpathyChatWindow *self) +{ + chat_window_tabs_next_activate_cb (NULL, self); +} + +void +empathy_chat_window_prev_tab (EmpathyChatWindow *self) +{ + chat_window_tabs_previous_activate_cb (NULL, self); +} + + static void chat_window_tabs_undo_close_tab_activate_cb (GtkAction *action, EmpathyChatWindow *self) @@ -1481,14 +1498,10 @@ chat_window_tabs_right_activate_cb (GtkAction *action, chat_window_menu_context_update (self, num_pages); } -static EmpathyChatWindow * +EmpathyChatWindow * empathy_chat_window_new (void) { return g_object_new (EMPATHY_TYPE_CHAT_WINDOW, - "default-width", 580, - "default-height", 480, - "title", _("Chat"), - "role", "chat", NULL); } @@ -1518,7 +1531,7 @@ static void chat_window_help_about_activate_cb (GtkAction *action, EmpathyChatWindow *self) { - empathy_about_dialog_new (GTK_WINDOW (self)); + empathy_about_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)))); } static gboolean @@ -1565,7 +1578,7 @@ static void chat_window_set_urgency_hint (EmpathyChatWindow *self, gboolean urgent) { - gtk_window_set_urgency_hint (GTK_WINDOW (self), urgent); + //gtk_window_set_urgency_hint (GTK_WINDOW (self), urgent); } static void @@ -1668,7 +1681,7 @@ empathy_chat_window_has_focus (EmpathyChatWindow *self) g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (self), FALSE); - g_object_get (self, "has-toplevel-focus", &has_focus, NULL); + g_object_get ( gtk_widget_get_toplevel (GTK_WIDGET (self)), "has-toplevel-focus", &has_focus, NULL); return has_focus; } @@ -1839,7 +1852,7 @@ notebook_create_window_cb (GtkNotebook *source, empathy_chat_window_move_chat (window, new_window, chat); gtk_widget_show (GTK_WIDGET (new_window)); - gtk_window_move (GTK_WINDOW (new_window), x, y); + //gtk_window_move (GTK_WINDOW (new_window), x, y); return NULL; } @@ -1965,6 +1978,9 @@ chat_window_focus_in_event_cb (GtkWidget *widget, GdkEvent *event, EmpathyChatWindow *self) { + if (self->priv->current_chat == NULL) { + return FALSE; + } empathy_chat_messages_read (self->priv->current_chat); chat_window_set_urgency_hint (self, FALSE); @@ -2396,6 +2412,17 @@ empathy_chat_window_class_init (EmpathyChatWindowClass *klass) g_type_class_add_private (object_class, sizeof (EmpathyChatWindowPriv)); } +static void +chat_window_chat_new_message_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + EmpathyChatWindow *self = user_data; + + //empathy_new_message_dialog_show (GTK_WINDOW (self)); +} + + static void empathy_chat_window_init (EmpathyChatWindow *self) { @@ -2406,6 +2433,7 @@ empathy_chat_window_init (EmpathyChatWindow *self) GtkWidget *submenu; guint i; GtkWidget *chat_vbox; + GtkWidget *main_box; gchar *filename; EmpathySmileyManager *smiley_manager; @@ -2415,6 +2443,7 @@ empathy_chat_window_init (EmpathyChatWindow *self) filename = empathy_file_lookup ("empathy-chat-window.ui", "src"); gui = tpaw_builder_get_file (filename, "chat_vbox", &chat_vbox, + "main_box", &main_box, "ui_manager", &self->priv->ui_manager, "menu_conv_insert_smiley", &self->priv->menu_conv_insert_smiley, "menu_conv_favorite", &self->priv->menu_conv_favorite, @@ -2470,11 +2499,12 @@ empathy_chat_window_init (EmpathyChatWindow *self) self->priv->sound_mgr = empathy_sound_manager_dup_singleton (); self->priv->notebook = gtk_notebook_new (); + //gtk_notebook_set_show_tabs (GTK_NOTEBOOK (self->priv->notebook), FALSE); g_signal_connect (self->priv->notebook, "create-window", G_CALLBACK (notebook_create_window_cb), self); - gtk_container_add (GTK_CONTAINER (self), chat_vbox); + gtk_container_add (GTK_CONTAINER (self), main_box); gtk_notebook_set_group_name (GTK_NOTEBOOK (self->priv->notebook), "EmpathyChatWindow"); @@ -2483,9 +2513,10 @@ empathy_chat_window_init (EmpathyChatWindow *self) gtk_box_pack_start (GTK_BOX (chat_vbox), self->priv->notebook, TRUE, TRUE, 0); gtk_widget_show (self->priv->notebook); +#if 0 /* no top level window yet at this point */ /* Set up accels */ accel_group = gtk_accel_group_new (); - gtk_window_add_accel_group (GTK_WINDOW (self), accel_group); + gtk_window_add_accel_group (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))), accel_group); for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) { @@ -2497,6 +2528,7 @@ empathy_chat_window_init (EmpathyChatWindow *self) } g_object_unref (accel_group); +#endif /* Set up drag target lists */ self->priv->contact_targets = gtk_target_list_new (drag_types_dest_contact, @@ -2580,6 +2612,7 @@ empathy_chat_window_get_default (gboolean room) separate_windows = g_settings_get_boolean (gsettings, EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS); + separate_windows = FALSE; g_object_unref (gsettings); @@ -2594,6 +2627,7 @@ empathy_chat_window_get_default (gboolean room) chat_window = l->data; +#if 0 empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private); /* Skip the window if there aren't any rooms in it */ @@ -2603,6 +2637,7 @@ empathy_chat_window_get_default (gboolean room) /* Skip the window if there aren't any 1-1 chats in it */ if (!room && nb_private == 0) continue; +#endif return chat_window; } @@ -2633,6 +2668,7 @@ empathy_chat_window_add_chat (EmpathyChatWindow *self, separate_windows = g_settings_get_boolean (self->priv->gsettings_ui, EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS); + separate_windows = FALSE; if (empathy_chat_is_room (chat)) name = "room-window"; @@ -2642,24 +2678,24 @@ empathy_chat_window_add_chat (EmpathyChatWindow *self, gint x, y; /* Save current position of the window */ - gtk_window_get_position (GTK_WINDOW (self), &x, &y); + //gtk_window_get_position (GTK_WINDOW (self), &x, &y); /* First bind to the 'generic' name. So new window for which we didn't * save a geometry yet will have the geometry of the last saved * window (bgo #601191). */ - empathy_geometry_bind (GTK_WINDOW (self), name); + //empathy_geometry_bind (GTK_WINDOW (self), name); /* Restore previous position of the window so the newly created window * won't be in the same position as the latest saved window and so * completely hide it. */ - gtk_window_move (GTK_WINDOW (self), x, y); + //gtk_window_move (GTK_WINDOW (self), x, y); /* Then bind it to the name of the contact/room so we'll save the * geometry specific to this window */ name = empathy_chat_get_id (chat); } - empathy_geometry_bind (GTK_WINDOW (self), name); + //empathy_geometry_bind (GTK_WINDOW (self), name); } child = GTK_WIDGET (chat); @@ -2814,6 +2850,13 @@ empathy_chat_window_present_chat (EmpathyChat *chat, EmpathyChatWindow *self; guint32 x_timestamp; + if (chat == NULL) { + /* initial window */ + self = empathy_chat_window_new (); + gtk_widget_show (GTK_WIDGET (self)); + return self; + } + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); self = chat_window_find_chat (chat); @@ -2859,7 +2902,7 @@ empathy_chat_window_present_chat (EmpathyChat *chat, * to our current desktop but move to the window's desktop instead. This is * more coherent with Shell's 'app is ready' notication which moves the view * to the app desktop rather than moving the app itself. */ - empathy_move_to_window_desktop (GTK_WINDOW (self), x_timestamp); + empathy_move_to_window_desktop (GTK_WINDOW (gtk_widget_get_toplevel(GTK_WIDGET(self))), x_timestamp); gtk_widget_grab_focus (chat->input_text_view); return self; diff --git a/src/empathy-chat-window.h b/src/empathy-chat-window.h index ae986cc7..2e64b680 100644 --- a/src/empathy-chat-window.h +++ b/src/empathy-chat-window.h @@ -63,13 +63,13 @@ typedef struct _EmpathyChatWindowPriv EmpathyChatWindowPriv; struct _EmpathyChatWindow { - GtkWindow parent; + GtkBin parent; EmpathyChatWindowPriv *priv; }; struct _EmpathyChatWindowClass { - GtkWindowClass parent_class; + GtkBinClass parent_class; }; GType empathy_chat_window_get_type (void); @@ -81,9 +81,14 @@ EmpathyChat * empathy_chat_window_find_chat (TpAccount *account, EmpathyChatWindow * empathy_chat_window_present_chat (EmpathyChat *chat, gint64 timestamp); +EmpathyChatWindow * empathy_chat_window_new (void); + EmpathyIndividualManager * empathy_chat_window_get_individual_manager ( EmpathyChatWindow *self); +void empathy_chat_window_next_tab (EmpathyChatWindow *self); +void empathy_chat_window_prev_tab (EmpathyChatWindow *self); + G_END_DECLS #endif diff --git a/src/empathy-chat-window.ui b/src/empathy-chat-window.ui index 4901978b..7ac2403a 100644 --- a/src/empathy-chat-window.ui +++ b/src/empathy-chat-window.ui @@ -176,6 +176,7 @@ gtk-about menu_help_about + @@ -213,24 +214,28 @@ - + + False + horizontal + True + + True - - - True - - - False - False - - + + True + True + 1 + + + + diff --git a/src/empathy-chat.c b/src/empathy-chat.c index f25acb65..b35480dc 100644 --- a/src/empathy-chat.c +++ b/src/empathy-chat.c @@ -76,6 +76,8 @@ activate_cb (GApplication *application) g_assert (chat_mgr == NULL); chat_mgr = empathy_chat_manager_dup_singleton (); + empathy_chat_window_present_chat(NULL, 0); + g_signal_connect (chat_mgr, "displayed-chats-changed", G_CALLBACK (displayed_chats_changed_cb), GUINT_TO_POINTER (1)); } diff --git a/src/empathy-roster-window.c b/src/empathy-roster-window.c index e584cdd3..b70332de 100644 --- a/src/empathy-roster-window.c +++ b/src/empathy-roster-window.c @@ -32,6 +32,7 @@ #include "empathy-accounts-dialog.h" #include "empathy-call-observer.h" #include "empathy-chat-manager.h" +#include "empathy-chat-window.h" #include "empathy-chatroom-manager.h" #include "empathy-chatrooms-window.h" #include "empathy-client-factory.h" @@ -55,6 +56,8 @@ #include "empathy-roster-model-manager.h" #include "empathy-roster-view.h" #include "empathy-status-presets.h" +#include "empathy-theme-manager.h" +#include "empathy-theme-manager.h" #include "empathy-ui-utils.h" #include "empathy-utils.h" @@ -90,6 +93,8 @@ G_DEFINE_TYPE (EmpathyRosterWindow, empathy_roster_window, GTK_TYPE_APPLICATION_ struct _EmpathyRosterWindowPriv { EmpathyRosterView *view; TpAccountManager *account_manager; + EmpathyChatManager *chat_manager; + EmpathyThemeManager *theme_manager; EmpathyChatroomManager *chatroom_manager; EmpathyEventManager *event_manager; EmpathySoundManager *sound_mgr; @@ -116,6 +121,7 @@ struct _EmpathyRosterWindowPriv { GtkWidget *button_add_contact; GtkWidget *spinner_loading; GtkWidget *tooltip_widget; + GtkWidget *chat_window; GMenu *menumodel; GMenu *rooms_section; @@ -1033,6 +1039,8 @@ empathy_roster_window_finalize (GObject *window) g_object_unref (self->priv->call_observer); g_object_unref (self->priv->event_manager); + g_object_unref (self->priv->chat_manager); + g_object_unref (self->priv->theme_manager); g_object_unref (self->priv->chatroom_manager); g_object_unref (self->priv->gsettings_ui); @@ -1540,6 +1548,25 @@ roster_window_help_contents_cb (GSimpleAction *action, empathy_url_show (GTK_WIDGET (self), "help:empathy"); } +static void +next_tab_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + EmpathyRosterWindow *self = user_data; + empathy_chat_window_next_tab (EMPATHY_CHAT_WINDOW (self->priv->chat_window)); +} + +static void +prev_tab_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + EmpathyRosterWindow *self = user_data; + empathy_chat_window_prev_tab (EMPATHY_CHAT_WINDOW (self->priv->chat_window)); +} + + static gboolean roster_window_throbber_button_press_event_cb (GtkWidget *throbber, GdkEventButton *event, @@ -1898,6 +1925,13 @@ static GActionEntry menubar_entries[] = { { "help_about", roster_window_help_about_cb, NULL, NULL, NULL }, }; +static GActionEntry app_entries[] = +{ + { "tab_next", next_tab_cb, NULL, NULL, NULL }, + { "tab_prev", prev_tab_cb, NULL, NULL, NULL } +}; + + static void empathy_roster_window_set_property (GObject *object, guint property_id, @@ -2285,10 +2319,10 @@ empathy_roster_window_init (EmpathyRosterWindow *self) GtkBuilder *gui; GtkWidget *sw; gchar *filename; - GtkWidget *search_vbox; GtkWidget *header_bar; GtkWidget *new_conversation_button; GtkWidget *image; + GtkWidget *chat_vbox; guint i; EmpathyRosterModel *model; @@ -2313,10 +2347,10 @@ empathy_roster_window_init (EmpathyRosterWindow *self) filename = empathy_file_lookup ("empathy-roster-window.ui", "src"); gui = tpaw_builder_get_file (filename, "main_vbox", &self->priv->main_vbox, + "chat_vbox", &chat_vbox, "balance_vbox", &self->priv->balance_vbox, "errors_vbox", &self->priv->errors_vbox, "auth_vbox", &self->priv->auth_vbox, - "search_vbox", &search_vbox, "presence_toolbar", &self->priv->presence_toolbar, "notebook", &self->priv->notebook, "no_entry_label", &self->priv->no_entry_label, @@ -2364,6 +2398,10 @@ empathy_roster_window_init (EmpathyRosterWindow *self) self->priv->status_changed_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); + /* set up accelerators */ + g_action_map_add_action_entries (G_ACTION_MAP (self), + app_entries, G_N_ELEMENTS (app_entries), self); + /* set up menus */ g_action_map_add_action_entries (G_ACTION_MAP (self), menubar_entries, G_N_ELEMENTS (menubar_entries), self); @@ -2416,6 +2454,7 @@ empathy_roster_window_init (EmpathyRosterWindow *self) self->priv->view = EMPATHY_ROSTER_VIEW ( empathy_roster_view_new (model)); + g_object_unref (model); gtk_widget_show (GTK_WIDGET (self->priv->view)); @@ -2454,8 +2493,6 @@ empathy_roster_window_init (EmpathyRosterWindow *self) GTK_WIDGET (self->priv->view)); empathy_roster_view_set_live_search (self->priv->view, TPAW_LIVE_SEARCH (self->priv->search_bar)); - gtk_box_pack_start (GTK_BOX (search_vbox), self->priv->search_bar, - FALSE, TRUE, 0); g_signal_connect_swapped (self, "map", G_CALLBACK (gtk_widget_grab_focus), self->priv->view); @@ -2467,9 +2504,16 @@ empathy_roster_window_init (EmpathyRosterWindow *self) /* Set window size. */ empathy_geometry_bind (GTK_WINDOW (self), GEOMETRY_NAME); + self->priv->chat_window = GTK_WIDGET (empathy_chat_window_new ()); + gtk_widget_show (GTK_WIDGET (self->priv->chat_window) ); + gtk_box_pack_start (GTK_BOX (chat_vbox), self->priv->chat_window, TRUE, TRUE, 0); + /* Enable event handling */ self->priv->call_observer = empathy_call_observer_dup_singleton (); self->priv->event_manager = empathy_event_manager_dup_singleton (); + self->priv->chat_manager = empathy_chat_manager_dup_singleton (); + + self->priv->theme_manager = empathy_theme_manager_dup_singleton (); tp_g_signal_connect_object (self->priv->event_manager, "event-added", G_CALLBACK (roster_window_event_added_cb), self, 0); diff --git a/src/empathy-roster-window.ui b/src/empathy-roster-window.ui index 937bae63..c595a61a 100644 --- a/src/empathy-roster-window.ui +++ b/src/empathy-roster-window.ui @@ -1,22 +1,35 @@ - - True + False + horizontal + True + - - True + False - 3 - 3 - - - False - False - 1 - - + False + True + slide-right + True + + + False + 240 + True + + + + False + False + vertical + True + + False @@ -57,26 +70,14 @@ 4 - - - True - False - - - - - - False - False - 5 - - - - + + + True True False False + True True @@ -248,12 +249,112 @@ 1 + + + + + False + True + + + + False + True + horizontal + False + True + + + False + True + vertical + False + True + + + + True + False + 3 + 3 + True + + + + + + False + end + start + True + True + center + True + False + + + + + False + 3 + True + horizontal + False + False + + + False + 1 + False + + + + + False + end + start + True + center + True + False + + + + + + + + + + + + + + - True - True - 6 + False + False + 0 + + + + True + + + + + + True + True + 1 + + + + diff --git a/src/empathy.c b/src/empathy.c index 54b06a83..fa71d706 100644 --- a/src/empathy.c +++ b/src/empathy.c @@ -317,6 +317,10 @@ empathy_app_activate (GApplication *app) "h", "win." EMPATHY_PREFS_UI_SHOW_OFFLINE, NULL); + gtk_application_add_accelerator (GTK_APPLICATION (app), + "Page_Up", "win.tab_prev", NULL); + gtk_application_add_accelerator (GTK_APPLICATION (app), + "Page_Down", "win.tab_next", NULL); /* check if Shell is running */ dbus = tp_dbus_daemon_dup (&error); @@ -836,7 +840,7 @@ main (int argc, char *argv[]) add_empathy_features (); app = g_object_new (EMPATHY_TYPE_APP, - "application-id", EMPATHY_BUS_NAME, + "application-id", EMPATHY_CHAT_BUS_NAME, NULL); retval = g_application_run (G_APPLICATION (app), argc, argv); diff --git a/src/polari-fixed-size-frame.c b/src/polari-fixed-size-frame.c new file mode 100644 index 00000000..089f38f6 --- /dev/null +++ b/src/polari-fixed-size-frame.c @@ -0,0 +1,209 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see ."; + */ + +#include "polari-fixed-size-frame.h" + +struct _PolariFixedSizeFramePrivate { + int width; + int height; +}; + +enum +{ + PROP_0, + + PROP_WIDTH, + PROP_HEIGHT, + + LAST_PROP +}; + +static GParamSpec *props[LAST_PROP]; + +static void +polari_fixed_size_frame_buildable_init (GtkBuildableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (PolariFixedSizeFrame, polari_fixed_size_frame, + GTK_TYPE_FRAME, + G_ADD_PRIVATE (PolariFixedSizeFrame) + G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, + polari_fixed_size_frame_buildable_init)) + +static void +polari_fixed_size_frame_buildable_init (GtkBuildableIface *iface) +{ +} + +static void +queue_redraw (PolariFixedSizeFrame *self) +{ + GtkWidget *child = gtk_bin_get_child (GTK_BIN (self)); + + if (child) + gtk_widget_queue_resize (child); + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +polari_fixed_size_frame_set_width (PolariFixedSizeFrame *self, + int width) +{ + if (self->priv->width != width) + { + self->priv->width = width; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_WIDTH]); + + queue_redraw (self); + } +} + +static void +polari_fixed_size_frame_set_height (PolariFixedSizeFrame *self, + int height) +{ + if (self->priv->height != height) + { + self->priv->height = height; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HEIGHT]); + + queue_redraw (self); + } +} + +static void +polari_fixed_size_frame_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PolariFixedSizeFrame *self = POLARI_FIXED_SIZE_FRAME (object); + + switch (prop_id) + { + case PROP_WIDTH: + polari_fixed_size_frame_set_width(self, g_value_get_int (value)); + break; + case PROP_HEIGHT: + polari_fixed_size_frame_set_height(self, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +polari_fixed_size_frame_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PolariFixedSizeFrame *self = POLARI_FIXED_SIZE_FRAME (object); + + switch (prop_id) + { + case PROP_WIDTH: + g_value_set_int (value, self->priv->width); + break; + case PROP_HEIGHT: + g_value_set_int (value, self->priv->height); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +polari_fixed_size_frame_get_preferred_width (GtkWidget *widget, + int *minimum_size, + int *natural_size) +{ + PolariFixedSizeFrame *self = POLARI_FIXED_SIZE_FRAME (widget); + + if (self->priv->width == -1) + { + GTK_WIDGET_CLASS (polari_fixed_size_frame_parent_class)->get_preferred_width (widget, minimum_size, natural_size); + } + else + { + *minimum_size = *natural_size = self->priv->width; + } +} + +static void +polari_fixed_size_frame_get_preferred_height (GtkWidget *widget, + int *minimum_size, + int *natural_size) +{ + PolariFixedSizeFrame *self = POLARI_FIXED_SIZE_FRAME (widget); + + if (self->priv->height == -1) + { + GTK_WIDGET_CLASS (polari_fixed_size_frame_parent_class)->get_preferred_height (widget, minimum_size, natural_size); + } + else + { + *minimum_size = *natural_size = self->priv->height; + } +} + +static void +polari_fixed_size_frame_class_init (PolariFixedSizeFrameClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + object_class->get_property = polari_fixed_size_frame_get_property; + object_class->set_property = polari_fixed_size_frame_set_property; + widget_class->get_preferred_width = + polari_fixed_size_frame_get_preferred_width; + widget_class->get_preferred_height = + polari_fixed_size_frame_get_preferred_height; + gtk_container_class_handle_border_width (container_class); + + props[PROP_WIDTH] = + g_param_spec_int ("width", + "Width", + "Fixed width of the widget, or -1 to use the child's " + "width", + -1, + G_MAXINT, + -1, + G_PARAM_READWRITE); + + props[PROP_HEIGHT] = + g_param_spec_int ("height", + "Height", + "Fixed height of the widget, or -1 to use the child's " + "height", + -1, + G_MAXINT, + -1, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, LAST_PROP, props); +} + +static void +polari_fixed_size_frame_init (PolariFixedSizeFrame *self) +{ + self->priv = polari_fixed_size_frame_get_instance_private (self), + self->priv->width = -1; + self->priv->height = -1; +} diff --git a/src/polari-fixed-size-frame.h b/src/polari-fixed-size-frame.h new file mode 100644 index 00000000..6926eec1 --- /dev/null +++ b/src/polari-fixed-size-frame.h @@ -0,0 +1,51 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see ."; + */ + +#ifndef __POLARI_FIXED_SIZE_FRAME_H__ +#define __POLARI_FIXED_SIZE_FRAME_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _PolariFixedSizeFrame PolariFixedSizeFrame; +typedef struct _PolariFixedSizeFrameClass PolariFixedSizeFrameClass; +typedef struct _PolariFixedSizeFramePrivate PolariFixedSizeFramePrivate; + +#define POLARI_TYPE_FIXED_SIZE_FRAME (polari_fixed_size_frame_get_type()) +#define POLARI_FIXED_SIZE_FRAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), POLARI_TYPE_FIXED_SIZE_FRAME, PolariFixedSizeFrame)) +#define POLARI_IS_FIXED_SIZE_FRAME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLARI_TYPE_FIXED_SIZE_FRAME)) +#define POLARI_FIXED_SIZE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POLARI_TYPE_FIXED_SIZE_FRAME, PolariFixedSizeFrameClass)) +#define POLARI_IS_FIXED_SIZE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POLARI_TYPE_FIXED_SIZE_FRAME)) +#define POLARI_FIXED_SIZE_FRAME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), POLARI_TYPE_FIXED_SIZE_FRAME, PolariFixedSizeFrameClass)) + +struct _PolariFixedSizeFrame { + GtkFrame parent_instance; + + PolariFixedSizeFramePrivate *priv; +}; + +struct _PolariFixedSizeFrameClass { + GtkFrameClass parent_class; +}; + +GType polari_fixed_size_frame_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif