use a single window, with tabs
authorFrédéric Péters <fpeters@0d.be>
Sun, 19 Apr 2015 14:10:02 +0000 (16:10 +0200)
committerFrédéric Péters <fpeters@0d.be>
Fri, 1 May 2015 14:13:57 +0000 (16:13 +0200)
src/Makefile.am
src/empathy-chat-window.c
src/empathy-chat-window.h
src/empathy-chat-window.ui
src/empathy-chat.c
src/empathy-roster-window.c
src/empathy-roster-window.ui
src/empathy.c
src/polari-fixed-size-frame.c [new file with mode: 0644]
src/polari-fixed-size-frame.h [new file with mode: 0644]

index 8806ae4..c792dd5 100644 (file)
@@ -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 =                                                      \
index b496356..2f41d3d 100644 (file)
@@ -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;
index ae986cc..2e64b68 100644 (file)
@@ -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
index 4901978..7ac2403 100644 (file)
             <property name="stock_id">gtk-about</property>
             <property name="name">menu_help_about</property>
           </object>
+          <accelerator key="F2" modifiers=""/>
         </child>
       </object>
     </child>
         </menu>
         <menu action="menu_help">
           <menuitem action="menu_help_contents"/>
-          <menuitem action="menu_help_about"/>
         </menu>
       </menubar>
     </ui>
   </object>
+  <object class="GtkBox" id="main_box">
+    <property name="can_focus">False</property>
+    <property name="orientation">horizontal</property>
+    <property name="visible">True</property>
+
+<child>
   <object class="GtkVBox" id="chat_vbox">
     <property name="visible">True</property>
-    <child>
-      <object class="GtkMenuBar" constructor="ui_manager" id="chats_menubar">
-        <property name="visible">True</property>
-      </object>
-      <packing>
-        <property name="expand">False</property>
-        <property name="fill">False</property>
-      </packing>
-    </child>
     <child>
       <placeholder/>
     </child>
   </object>
+  <packing>
+    <property name="expand">True</property>
+    <property name="fill">True</property>
+    <property name="position">1</property>
+  </packing>
+
+</child>
+</object>
 </interface>
index f25acb6..b35480d 100644 (file)
@@ -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));
 }
index e584cdd..b70332d 100644 (file)
@@ -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);
index 937bae6..c595a61 100644 (file)
@@ -1,22 +1,35 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 2.12 -->
-  <object class="GtkVBox" id="main_vbox">
-    <property name="visible">True</property>
+  <object class="GtkBox" id="main_vbox">
     <property name="can_focus">False</property>
+    <property name="orientation">horizontal</property>
+    <property name="visible">True</property>
+
     <child>
-      <object class="GtkHBox" id="presence_toolbar">
-        <property name="visible">True</property>
+      <object class="GtkRevealer" id="revealer">
         <property name="can_focus">False</property>
-        <property name="spacing">3</property>
-        <property name="border-width">3</property>
-      </object>
-      <packing>
-        <property name="expand">False</property>
-        <property name="fill">False</property>
-        <property name="position">1</property>
-      </packing>
-    </child>
+        <property name="hexpand">False</property>
+        <property name="reveal_child">True</property>
+        <property name="transition_type">slide-right</property>
+        <property name="visible">True</property>
+        <child>
+          <object class="PolariFixedSizeFrame" id="sidebar_frame">
+            <property name="hexpand">False</property>
+            <property name="width">240</property>
+            <property name="visible">True</property>
+            <style>
+              <class name="sidebar"/>
+              <class name="chat-sidebar"/>
+            </style>
+            <child>
+              <object class="GtkGrid" id="grid0">
+                <property name="can_focus">False</property>
+                <property name="hexpand">False</property>
+                <property name="orientation">vertical</property>
+                <property name="visible">True</property>
+
+
     <child>
       <object class="GtkVBox" id="balance_vbox">
         <property name="can_focus">False</property>
         <property name="position">4</property>
       </packing>
     </child>
-    <child>
-      <object class="GtkVBox" id="search_vbox">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <child>
-          <placeholder/>
-        </child>
-      </object>
-      <packing>
-        <property name="expand">False</property>
-        <property name="fill">False</property>
-        <property name="position">5</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkNotebook" id="notebook">
+
+                <child>
+  <object class="GtkNotebook" id="notebook">
         <property name="visible">True</property>
         <property name="can_focus">True</property>
         <property name="show_tabs">False</property>
         <property name="show_border">False</property>
+        <property name="expand">True</property>
         <child>
           <object class="GtkScrolledWindow" id="roster_scrolledwindow">
             <property name="visible">True</property>
             <property name="position">1</property>
           </packing>
         </child>
+      </object>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="status_area">
+                    <property name="can_focus">False</property>
+                    <property name="visible">True</property>
+                    <style>
+                      <class name="chat-status-area"/>
+                    </style>
+                    <child>
+                      <object class="GtkGrid" id="status_area_grid0">
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="orientation">horizontal</property>
+                        <property name="vexpand">False</property>
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkGrid" id="status_area_grid1">
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="orientation">vertical</property>
+                            <property name="vexpand">False</property>
+                            <property name="visible">True</property>
+
+                           <child>
+                             <object class="GtkHBox" id="presence_toolbar">
+                               <property name="visible">True</property>
+                               <property name="can_focus">False</property>
+                               <property name="spacing">3</property>
+                               <property name="border-width">3</property>
+                                <property name="hexpand">True</property>
+                               </object>
+                       </child>
+
+                            <child>
+                              <object class="GtkLabel" id="status_area_nickname">
+                                <property name="can_focus">False</property>
+                                <property name="ellipsize">end</property>
+                                <property name="halign">start</property>
+                                <property name="hexpand">True</property>
+                                <property name="use_markup">True</property>
+                                <property name="valign">center</property>
+                                <property name="vexpand">True</property>
+                                <property name="visible">False</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkGrid" id="status_area_grid2">
+                                <property name="can_focus">False</property>
+                                <property name="column_spacing">3</property>
+                                <property name="hexpand">True</property>
+                                <property name="orientation">horizontal</property>
+                                <property name="vexpand">False</property>
+                                <property name="visible">False</property>
+                                <child>
+                                  <object class="GtkImage" id="status_area_presence_icon">
+                                    <property name="can_focus">False</property>
+                                    <property name="icon_size">1</property>
+                                    <property name="visible">False</property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="status_area_presence_message">
+                                    <property name="can_focus">False</property>
+                                    <property name="ellipsize">end</property>
+                                    <property name="halign">start</property>
+                                    <property name="hexpand">True</property>
+                                    <property name="valign">center</property>
+                                    <property name="vexpand">True</property>
+                                    <property name="visible">False</property>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
       </object>
       <packing>
-        <property name="expand">True</property>
-        <property name="fill">True</property>
-        <property name="position">6</property>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">0</property>
       </packing>
     </child>
+
+<child>
+  <object class="GtkVBox" id="chat_vbox">
+    <property name="visible">True</property>
+    <child>
+      <placeholder/>
+    </child>
+  </object>
+  <packing>
+    <property name="expand">True</property>
+    <property name="fill">True</property>
+    <property name="position">1</property>
+  </packing>
+
+</child>
+
   </object>
 </interface>
index 54b06a8..fa71d70 100644 (file)
@@ -317,6 +317,10 @@ empathy_app_activate (GApplication *app)
           "<Primary>h",
           "win." EMPATHY_PREFS_UI_SHOW_OFFLINE,
           NULL);
+      gtk_application_add_accelerator (GTK_APPLICATION (app),
+          "<Control>Page_Up", "win.tab_prev", NULL);
+      gtk_application_add_accelerator (GTK_APPLICATION (app),
+          "<Control>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 (file)
index 0000000..089f38f
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.";
+ */
+
+#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 (file)
index 0000000..6926eec
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.";
+ */
+
+#ifndef __POLARI_FIXED_SIZE_FRAME_H__
+#define __POLARI_FIXED_SIZE_FRAME_H__
+
+#include <gtk/gtk.h>
+
+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